diff --git a/Tp6/associations.zip b/Tp6/associations.zip
new file mode 100644
index 0000000000000000000000000000000000000000..d0bdeb1d8c6796026cdf8a32e602d3c46f493c16
Binary files /dev/null and b/Tp6/associations.zip differ
diff --git a/Tp6/associations/ap_decorators.py b/Tp6/associations/ap_decorators.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f4adc9129d3d7ffef9d7dc68b59e4d6643d419d
--- /dev/null
+++ b/Tp6/associations/ap_decorators.py
@@ -0,0 +1,135 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:module: ap_decorators  
+:author: FIL - Faculté des Sciences et Technologies -  Univ. Lille <http://portail.fil.univ-lille1.fr>_
+:date: 2018, september
+
+"""
+
+from functools import wraps
+
+
+def trace(fct):
+    '''
+    Decorator for tracing every call to fct.
+    Recursive calls are indented.
+
+    :Example:
+
+    >>> @trace
+    ... def fact(n):
+    ...     if n == 0:
+    ...         return 1
+    ...     else:
+    ...         return n * fact(n - 1)
+    
+    >>> fact(5)
+     -> fact((5,), {})
+    ... -> fact((4,), {})
+    ...... -> fact((3,), {})
+    ......... -> fact((2,), {})
+    ............ -> fact((1,), {})
+    ............... -> fact((0,), {})
+    ............... <- 1
+    ............ <- 1
+    ......... <- 2
+    ...... <- 6
+    ... <- 24
+    <- 120
+    120
+    '''
+    @wraps(fct)
+    def wrapper(*args, **kwargs):
+        dots = '...' * wrapper.__depth
+        print('{:s} -> {:s}{:s}'.format(dots, wrapper.__name__, repr((args, kwargs))))
+        wrapper.__depth += 1
+        y = fct(*args, **kwargs)
+        wrapper.__depth -= 1
+        print('{:s} <- {:s}'.format(dots, repr(y)))
+        return y
+    wrapper.__depth = 0
+    return wrapper
+
+def count(fct):
+    '''
+    decorator for counting  calls to  function fct
+    
+    :Example:
+
+    >>> @count
+    ... def fact(n):
+    ...     if n == 0:
+    ...         return 1
+    ...     else:
+    ...         return n * fact(n - 1)
+    
+    >>> fact.counter
+    0
+    >>> fact(5)
+    120
+    >>> fact.counter
+    6
+    '''
+    @wraps(fct) 
+    def wrapper(*args, **kwargs):
+        y = fct(*args, **kwargs)
+        wrapper.counter += 1
+        return y
+    wrapper.counter = 0
+    return wrapper
+
+
+def memoize(fct):
+    '''
+    decorator for memoizing computed values of  function fct
+    
+    :Example:
+
+    >>> @count
+    ... @memoize
+    ... def fact(n):
+    ...     if n == 0:
+    ...         return 1
+    ...     else:
+    ...         return n * fact(n - 1)
+    
+    >>> fact.counter
+    0
+    >>> fact(5)
+    120
+    >>> fact.counter
+    6
+    >>> fact.counter = 0
+    >>> fact(5)
+    120
+    >>> fact.counter
+    1
+    '''
+    cache = dict()
+    @wraps(fct)
+    def wrapper(*args, **kwargs):
+        key = repr((args, kwargs))
+        if key in cache:
+            return cache[key]
+        else:
+            y = fct(*args, **kwargs)
+            cache[key] = y
+            return y
+    return wrapper
+
+
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS, verbose=False)
+    
+    
+
+
+
+
+
+
+
diff --git a/Tp6/associations/apl1test.py b/Tp6/associations/apl1test.py
new file mode 100644
index 0000000000000000000000000000000000000000..8533ccaca5d99e7cfb83d6d86aa9334bb6a73a40
--- /dev/null
+++ b/Tp6/associations/apl1test.py
@@ -0,0 +1,89 @@
+import thonnycontrib
+from thonnycontrib.backend.evaluator import Evaluator
+import thonnycontrib.backend.l1test_backend
+from thonny.plugins.cpython_backend.cp_back import MainCPythonBackend
+import thonnycontrib.backend.doctest_parser 
+from thonnycontrib.backend.doctest_parser import ExampleWithExpected, ExampleWithoutExpected
+import thonnycontrib.backend.ast_parser
+from thonnycontrib.backend.ast_parser import L1DocTest
+import thonnycontrib.backend.verdicts
+from thonnycontrib.backend.verdicts.ExceptionVerdict import ExceptionVerdict 
+
+import inspect
+import tempfile
+import os
+import sys
+        
+class MockBackend(MainCPythonBackend):
+    """
+    Fake backend.
+    """
+    def __init__(self):
+        ...
+
+    def send_message(self, msg) -> None:
+        ...
+
+# register backend
+thonnycontrib.backend.l1test_backend.BACKEND = MockBackend()
+
+def l1test_to_org(filename: str, source: str=""):
+    """
+    Return an org abstract of the tests presents in `filename` file.
+    """
+    abstract = {'total': 0,
+                'success': 0,
+                'failures': 0,
+                'errors': 0,
+                'empty': 0}
+
+    if source == "":
+        with open(filename, 'rt') as fin:
+            source = fin.read()
+    evaluator = Evaluator(filename=filename,
+                          source=source)
+    tests = evaluator.evaluate()
+    n = len(tests)
+    abstract['total'] = n
+    res = ""
+    for test in tests:
+        examples = test.get_examples()
+        res_examples = ""
+        nb_test, nb_test_ok = 0, 0
+        empty = True
+        for example in examples:
+            verdict = test.get_verdict_from_example(example)
+            if isinstance(example, ExampleWithExpected):
+                nb_test += 1
+                if verdict.isSuccess():
+                    nb_test_ok += 1
+                    abstract['success'] += 1
+                else:
+                    abstract['failures'] += 1
+                empty = False
+            if isinstance(verdict, ExceptionVerdict):
+                abstract['errors'] += 1
+                empty = False
+            res_examples += f"** {verdict}\n\n"
+            if not verdict.isSuccess():
+                res_examples += f"   {verdict.get_details()}\n\n"
+        if not empty: 
+            res += f"* {test.get_name()} ~ {nb_test_ok}/{nb_test} réussis\n\n"
+        else:
+            abstract['empty'] += 1
+            res += f"* {test.get_name()}\n\n Aucun test trouvé !\n\n"
+        res += res_examples
+    res = f"Tests exécutés : {abstract['total']}\nSuccès: {abstract['success']}, \
+Echecs: {abstract['failures']}, Erreurs: {abstract['errors']}, \
+Vide: {abstract['empty']}\n\n" + res
+    return res
+
+
+def testmod(modulename: str):
+    """
+    mimic the doctest.testmod function
+    for `modulename` module
+    """
+    print(l1test_to_org(modulename))
+
+
diff --git a/Tp6/associations/association.py b/Tp6/associations/association.py
new file mode 100755
index 0000000000000000000000000000000000000000..179219eeb0048df0ac72aa96dfbb63baf9ad1b74
--- /dev/null
+++ b/Tp6/associations/association.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`association` module : un module pour les associations clé-valeur
+
+:author: `FIL - Faculté des Sciences et Technologies - 
+          Univ. Lille <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2024 février
+
+"""
+from ap_decorators import count
+from typing import TypeVar
+
+# On définit deux types génériques :
+# - C pour le type des clés
+# - V pour le type des valeurs
+
+C = TypeVar('C')
+V = TypeVar('V')
+
+class Association:
+    """Classe d'une association clé-valeur
+    """
+
+    def __init__(self, cle: C, valeur: V):
+        """
+        $$$ asso1 = Association('a', 1)
+        $$$ asso1.cle
+        'a'
+        $$$ asso1.valeur
+        1
+        """
+        self.cle=cle
+        self.valeur=valeur
+
+    def __repr__(self) -> str:
+        """
+        $$$ repr(Association(2, 3))
+        'Association(2, 3)'
+        $$$ repr(Association('a', 1))
+        "Association('a', 1)"
+        $$$ repr(Association((1, True), [1, 2, 3]))
+        'Association((1, True), [1, 2, 3])'
+        """
+        return f"Association{(self.cle,self.valeur)}"
+
+    def __eq__(self, autre) -> bool:
+        """
+        $$$ Association('a', 1) == Association('a', 1)
+        True
+        $$$ Association('a', 1) == Association('a', 2)
+        False
+        $$$ Association('a', 1) == Association(1, 'a')
+        False
+        $$$ AssertionError('a', 1) == ('a', 1)
+        False
+        """
+        if isinstance(autre,Association):
+            return self.cle==autre.cle and self.valeur==autre.valeur
+        return False
+
+@count
+def comp_asso(a1: Association, a2: Association) -> int:
+    """Renvoie 0 si les clés de a1 et a2 sont identiques
+               -1 si la clé de a1 < la clé de a2
+               1 si la clé de a1 > la clé de a2
+
+    Precondition : les clés de a1 et a2 sont comparables
+
+    $$$ comp_asso(Association(1, 'a'), Association(1, 'c'))
+    0
+    $$$ comp_asso(Association(1, 'a'), Association(2, 'a'))
+    -1
+    $$$ comp_asso(Association(1, 'd'), Association(0, 'c'))
+    1
+    """
+    if a1.cle==a2.cle:
+        return 0
+    elif a1.cle< a2.cle:
+        return -1
+    else:
+        return 1
+
+if __name__ == '__main__':
+    import apl1test
+    apl1test.testmod('association.py')
+
diff --git a/Tp6/associations/dicotrie.py b/Tp6/associations/dicotrie.py
new file mode 100755
index 0000000000000000000000000000000000000000..b863fbbe9ed5fb6a7a277ad1cb226cf0794cfdc5
--- /dev/null
+++ b/Tp6/associations/dicotrie.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`dicotrie` module : un module pour les ensembles d'associations
+
+:author: `FIL - Faculté des Sciences et Technologies - 
+          Univ. Lille <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2024 février
+
+"""
+
+from association import Association, C, V, comp_asso
+from recherches import indice_dicho, inserer
+from types import NoneType
+
+
+class DicoTrie:
+    """Classe d'une association clé-valeur
+    """
+
+    def __init__(self, liste_assos: list[Association]):
+        """
+        """
+        self.liste_assos=liste_assos
+
+    def __repr__(self) -> str:
+        """
+        $$$ repr(DicoTrie([Association('a', 1)]))
+        "DicoTrie([Association('a', 1)])"
+        $$$ repr(DicoTrie([Association('a', 1), Association('b', 2)]))
+        "DicoTrie([Association('a', 1), Association('b', 2)])"
+        $$$ repr(DicoTrie([Association('c', 3), Association('a', 2), Association('b', 1)]))
+        "DicoTrie([Association('a', 2), Association('b', 1), Association('c', 3)])"
+        """
+        ...
+
+    def __eq__(self, autre) -> bool:
+        """
+        $$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
+        $$$ d2 = DicoTrie([Association("b", 2), Association("a", 1)])
+        $$$ d3 = DicoTrie([Association("a", 1), Association("b", 2), Association("c", 3)])
+        $$$ d1 == d2
+        True
+        $$$ d1 == d3
+        False
+        $$$ d1 == {"a": 1, "b": 2}
+        False
+        """
+        ...
+
+    def __setitem__(self, cle: C, valeur: V) -> NoneType:
+        """
+        $$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
+        $$$ d1["c"] = 3
+        $$$ d1
+        DicoTrie([Association("a", 1), Association("b", 2), Association("c", 3)])
+        """
+        ...
+
+    def __getitem__(self, cle: C) -> V:
+        """
+        $$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
+        $$$ d1['a']
+        1
+        $$$ d1['b']
+        2
+        $$e d1['c']
+        KeyError
+        """
+        ...
+
+    def __delitem__(self, cle: C) -> NoneType:
+        """ 
+        $$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)]) 
+        $$$ del d1['a'] 
+        $$$ d1 
+        DicoTrie([Association("b", 2)]) 
+        $$e del d1['c'] 
+        KeyError 
+        """
+        ...
+
+    def __contains__(self, cle: C) -> bool:
+        """ 
+        $$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)]) 
+        $$$ 'a' in d1
+        True
+        $$$ 'c' in d1
+        False
+        """
+        ...
+
+if __name__ == '__main__':
+    import apl1test
+    apl1test.testmod('dicotrie.py')
+
diff --git a/Tp6/associations/mesures.py b/Tp6/associations/mesures.py
new file mode 100644
index 0000000000000000000000000000000000000000..ae603e74002c835e970db392564c61f211ba57c5
--- /dev/null
+++ b/Tp6/associations/mesures.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`mesures` module : un module pour les mesures de temps
+
+:author: `FIL - Faculté des Sciences et Technologies - 
+          Univ. Lille <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2024 février
+
+"""
+from dicotrie import DicoTrie
+from association import Association
+from types import NoneType
+from timeit import timeit
+from random import randrange
+import matplotlib.pyplot as plt
+
+def generation_dict(tailles: list[int]) -> list[dict[str, NoneType]]:
+    """Renvoie une liste de dictionnaires dont les clés sont les
+    représentations des n entiers compris entre 0 et n-1 et les valeurs
+    associées None pour chaque entier n dans la liste tailles.
+
+    Précondition : tous les entiers de tailles sont positifs ou nuls
+
+    $$$ generation_dict([0, 2, 4])
+    [{}, {'0': None, '1':None}, {'0': None, '1': None, '2': None, '3': None}]
+    """
+    ...
+
+def generation_dicotrie(tailles: list[int]) -> list[DicoTrie]:
+    """Renvoie une liste de DicoTrie dont les clés sont les représentations
+    des n entiers compris entre 0 et n-1 et les valeurs associées None pour
+    chaque entier n dans la liste tailles.
+
+    Précondition : tous les entiers de tailles sont positifs ou nuls
+
+    $$$ generation_dicotrie([0, 2])
+    [DicoTrie([]), DicoTrie([Association('0', None), Association('1', None)])]
+    """
+    ...
+
+def mesure_temps_acces(taille : int, d: dict[str, NoneType] | DicoTrie) -> float:
+    """Renvoie le temps moyen mis pour accéder à 1000 éléments quelconques
+    du dictionnaire d.
+
+    Précondition : les clés de d sont les représentations des entiers
+    compris entre 0 et taille - 1.
+    """
+    cles_a_tester = [str(randrange(taille)) for _ in range(1000)]
+    stmt = "all(d[cle] == None for cle in cles_a_tester)"
+    return timeit(stmt = stmt, globals = locals(), number = 1) / 1000
+
+def mesures_temps_acces_dict(tailles: list[int]) -> list[float]:
+    """Renvoie les listes des temps moyens pour accéder à 1000 éléments quelconques
+    de chacun des dictionnaires dont les clés sont les remprésentations des
+    n entiers compris entre 1 et n-1 pour chaque entier n dans la liste
+    tailles.
+    
+    Précondition : tous les entiers de tailles sont positifs ou nuls
+    """
+    ...
+
+def mesures_temps_acces_dicotrie(tailles: list[int]) -> list[float]:
+    """Renvoie les listes des temps moyens pour accéder à 1000 éléments quelconques
+    de chacun des DicoTrie dont les clés sont les remprésentations des
+    n entiers compris entre 1 et n-1 pour chaque entier n dans la liste
+    tailles.
+    
+    Précondition : tous les entiers de tailles sont positifs ou nuls
+    """
+    ...
+
+
+if __name__ == '__main__':
+    import apl1test
+    apl1test.testmod('mesures.py')
+
+    # Écrivez ici le code permettant de faire des hypothèses sur la
+    # vitesse d'accès aux dictionnaires.
+
+    # linéaire
+    # tailles = list(range(0, 100000, 1000)
+    # temps_dict = mesures_temps_acces_dict(tailles)
+    # temps_dicotrie = mesures_temps_acces_dicotrie(tailles)
+    # plt.plot(tailles, temps_dict, '+')
+    # plt.plot(tailles, temps_dicotrie, '.')
+    # plt.show()
+    # log
+    # tailles = [2**n for n in range(16)]
+    # temps_dict = mesures_temps_acces_dict(tailles)
+    # temps_dicotrie = mesures_temps_acces_dicotrie(tailles)
+    # plt.plot(range(16), temps_dict, '+')
+    # plt.plot(range(16), temps_dicotrie, '.')
+    # plt.show()
+    
+
diff --git a/Tp6/associations/recherches.py b/Tp6/associations/recherches.py
new file mode 100755
index 0000000000000000000000000000000000000000..fa01a60edb5f127fa4c6fc39cec77b295811ac45
--- /dev/null
+++ b/Tp6/associations/recherches.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`recherches` module : un module pour les recherches
+
+:author: `FIL - Faculté des Sciences et Technologies - 
+          Univ. Lille <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2024 février
+
+"""
+from typing import TypeVar, Callable
+from types import NoneType
+
+# On définit un type générique :
+C = TypeVar('C')
+
+def indice_seq(elem: C, liste: list[C], comp: Callable[[C, C], int]) \
+                                  -> tuple[bool, int]:
+    """Renvoie un couple (trouve, i) tel que:
+        - si elem est un élément de liste,
+             * trouve = True
+             * i est l'indice de première occurence de elem dans liste
+        - si elem n'est pas un élément de la liste : * trouve = False
+                                                     * i = len(liste)
+
+    Précondition : comp est une fonction de comparaison sur C
+
+    $$$ def compare(x, y): return 0 if x == y else 1 if x > y else -1
+    $$$ indice_seq(0, [1, 3, 5], compare)
+    (False, 3)
+    $$$ indice_seq(3, [1, 3, 5], compare)
+    (True, 1)
+    $$$ indice_seq(4, [1, 3, 5], compare)
+    (False, 3)
+    $$$ indice_seq(5, [1, 3, 5], compare)
+    (True, 2)
+    $$$ indice_seq(6, [1, 3, 5], compare)
+    (False, 3)
+    $$$ indice_seq(42, [], compare)
+    (False, 0)
+    """
+    trouve=False
+    i=len(liste)
+    
+    for index, element in enumerate(liste):
+        if comp(elem,element)==0:
+            trouve=True
+            i=index
+            
+    return trouve,i
+# 
+# def indice_dicho(elem: C, liste: list[C], comp: Callable[[C, C], int]) \
+#                                     -> tuple[bool, int]:
+#     """Renvoie un couple (trouve, i) tel que:
+#         - si elem est un élément de liste,
+#              * trouve = True
+#              * i est l'indice de première occurence de elem dans liste
+#         - si elem n'est pas un élément de la liste :
+#              * trouve = False
+#              * pour tout j < i, liste[j] < liste[i]
+#              * pour tout j > i, liste[j] > liste[i]
+# 
+#     Précondition : comp est une fonction de comparaison et liste est triée pour comp
+# 
+#     $$$ def compare(x, y): return 0 if x == y else 1 if x > y else -1
+#     $$$ indice_dicho(0, [1, 3, 5], compare)
+#     (False, 0)
+#     $$$ indice_dicho(3, [1, 3, 5], compare)
+#     (True, 1)
+#     $$$ indice_dicho(4, [1, 3, 5], compare)
+#     (False, 2)
+#     $$$ indice_dicho(5, [1, 3, 5], compare)
+#     (True, 2)
+#     $$$ indice_dicho(6, [1, 3, 5], compare)
+#     (False, 3)
+#     $$$ indice_dicho(42, [], compare)
+#     (False, 0)
+#     """
+#    
+
+
+
+def inserer(indice: int, elem: C, liste: list[C]) -> NoneType:
+    """Insère l'élément elem à l'indice indice de la liste liste.
+
+    Précondition : 0 ≤ indice ≤ len(liste)
+
+    $$$ l = [1, 3, 5]
+    $$$ inserer(0, 0, l)
+    $$$ l
+    [0, 1, 3, 5]
+    $$$ inserer(4, 6, l)
+    $$$ l
+    [0, 1, 3, 5, 6]
+    $$$ inserer(3, 4, l)
+    $$$ l
+    [0, 1, 3, 4, 5, 6]
+    $$$ vide = []
+    $$$ inserer(0, 42, vide)
+    $$$ vide
+    [42]
+    """
+    if indice==len(liste):
+        liste.append(elem)
+    else:
+        liste.append(None)
+        for i in range (len(liste)-1, indice, -1):
+            liste[i]=liste[i-1]
+        liste[indice]=elem
+
+        
+if __name__ == '__main__':
+    import apl1test
+    apl1test.testmod('recherches.py')
+