diff --git a/bob/pad/face/database/batl.py b/bob/pad/face/database/batl.py
index f310f62fbf5c77bdbc0f3bb4763e7fe9a072ed6f..8452baf74d4ee26f3845dcd7225ee4bb2333bf3f 100644
--- a/bob/pad/face/database/batl.py
+++ b/bob/pad/face/database/batl.py
@@ -202,6 +202,14 @@ class BatlPadDatabase(PadDatabase):
             infrared data only, use 50 frames, join train and dev sets forming
             a single large training set.
 
+            "grandtest-infrared-50-LOO_<unseen_attack>", for example "grandtest-infrared-50-LOO_fakehead"
+            - Leave One Out (LOO) protocol with fakehead attacks present only in the `test` set. The original partitioning
+            in the `grandtest` protocol is queried first and subselects the file list such
+            that the specified `unknown_attack` is removed from both `train` and `dev` sets. 
+            The `test` set will consist of only the selected `unknown_attack` and `bonafide` files.
+            This protocol is used to evaluate the robustness against attacks unseen in training. 
+            .
+
             "grandtest-color*infrared-50" - baseline protocol,
             load both "color" and "infrared" channels,
             use 50 frames.
@@ -286,6 +294,15 @@ class BatlPadDatabase(PadDatabase):
         self.append_color_face_roi_annot = append_color_face_roi_annot
 
 
+        #map file to identify attack grouping
+        map_file = pkg_resources.resource_filename('bob.pad.face', 'lists/batl/idiap_converter_v2.json')
+
+        with open(map_file, 'r') as fp:
+            map_dict=json.load(fp)
+
+        self.map_dict=map_dict
+
+
     @property
     def original_directory(self):
         return self.db.original_directory
@@ -295,6 +312,52 @@ class BatlPadDatabase(PadDatabase):
     def original_directory(self, value):
         self.db.original_directory = value
 
+    def unseen_attack_list_maker(self,files,unknown_attack,train=True):
+        """
+        Selects and returns a list of files for Leave One Out (LOO) protocols. 
+        This utilizes the original partitioning in the `grandtest` protocol and subselects 
+        the file list such that the specified `unknown_attack` is removed from both `train` and `dev` sets. 
+        The `test` set will consist of only the selected `unknown_attack` and `bonafide` files.
+
+        **Parameters:**
+
+        ``files`` : pyclass::list
+            A list of files, db.objects()
+        ``unknown_attack`` : str
+            The unknown attack protocol name example:'rigidmask' .
+        ``train`` : bool
+            Denotes whether files are from training or development partition
+
+        **Returns:**
+
+        ``mod_files`` : pyclass::list
+            A list of files selected for the protocol
+
+        """
+
+
+        mod_files=[]
+
+
+        for file in files:
+
+            attack_category=self.map_dict["_"+"_".join(os.path.split(file.path)[-1].split("_")[-2:])].split("_")[-1]
+
+            if train:
+                if  attack_category==unknown_attack:
+                    pass
+                else:
+                    mod_files.append(file) # everything except the attack specified is there 
+
+            if not train:
+
+                if  attack_category==unknown_attack or attack_category=='bonafide':
+                    mod_files.append(file) # only the attack mentioned and bonafides in testing
+                else:
+                    pass
+
+
+        return mod_files
 
     def parse_protocol(self, protocol):
         """
@@ -329,7 +392,7 @@ class BatlPadDatabase(PadDatabase):
             forming a single training set.
         """
 
-        possible_extras = ['join_train_dev']
+        possible_extras = ['join_train_dev','LOO_fakehead','LOO_flexiblemask','LOO_glasses','LOO_papermask','LOO_prints','LOO_replay','LOO_rigidmask','LOO_makeup']
 
         components = protocol.split("-")
 
@@ -490,10 +553,11 @@ class BatlPadDatabase(PadDatabase):
         protocol = 'nowig' if protocol == 'grandtest' else protocol
 
         # Convert group names to low-level group names here.
-        groups = self.convert_names_to_lowlevel(
-            groups, self.low_level_group_names, self.high_level_group_names)
+        groups = self.convert_names_to_lowlevel(groups, self.low_level_group_names, self.high_level_group_names)
 
-        if not isinstance(groups, list) and groups is not None:  # if a single group is given make it a list
+            
+
+        if not isinstance(groups, list) and groups is not None and not isinstance(groups,str):  # if a single group is given make it a list
             groups = list(groups)
 
         if extra is not None and "join_train_dev" in extra:
@@ -515,6 +579,48 @@ class BatlPadDatabase(PadDatabase):
                                         groups=['test'],
                                         purposes=purposes, **kwargs)
 
+
+        # for the LOO protocols
+        elif extra is not None and "LOO_" in extra:
+
+            batl_files=[]
+
+            unknown_attack=extra.split("_")[-1]
+
+            if 'train' in groups:
+                tbatl_files = self.db.objects(protocol=protocol,
+                                        groups=['train'],
+                                        purposes=purposes, **kwargs)
+
+                tbatl_files=self.unseen_attack_list_maker(tbatl_files,unknown_attack,train=True)
+
+                batl_files=batl_files+tbatl_files
+
+
+            if 'validation' in groups: 
+                tbatl_files = self.db.objects(protocol=protocol,
+                                        groups=['validation'],
+                                        purposes=purposes, **kwargs)
+
+                tbatl_files=self.unseen_attack_list_maker(tbatl_files,unknown_attack,train=True)
+
+
+                batl_files=batl_files+tbatl_files
+
+            if 'test' in groups:
+                tbatl_files = self.db.objects(protocol=protocol,
+                                        groups=['test'],
+                                        purposes=purposes, **kwargs)
+
+                tbatl_files=self.unseen_attack_list_maker(tbatl_files,unknown_attack,train=False)
+
+                batl_files=batl_files+tbatl_files
+
+
+            files=batl_files
+
+
+
         else:
 #            files = self._fix_funny_eyes_in_objects(protocol=protocol,
 #                                                    groups=groups,
diff --git a/bob/pad/face/lists/batl/idiap_converter_v2.json b/bob/pad/face/lists/batl/idiap_converter_v2.json
new file mode 100644
index 0000000000000000000000000000000000000000..795f3af67de17aaf22fbc1d5d52e284947b8f8b7
--- /dev/null
+++ b/bob/pad/face/lists/batl/idiap_converter_v2.json
@@ -0,0 +1 @@
+{"_0_00": "Unknown_bonafide", "_0_01": "Clientownmedicalglasse_bonafide", "_0_02": "UnisexglassesG01_bonafide", "_1_01": "FunnyeyesglassesG02_glasses", "_1_02": "PlastichalloweenmaskB082200_rigidmask", "_1_03": "unassigne_glasses", "_1_04": "FunnyeyesglassesG03_glasses", "_1_05": "FunnyeyesglassesG04_glasses", "_1_06": "FunnyeyesglassesG05_glasses", "_1_07": "FunnyeyesglassesG06_glasses", "_1_13": "ExoticfemailtransparentmaskB0853200_rigidmask", "_1_14": "ExoticfemailtransparentmaskwithmakeupB082301_rigidmask", "_1_15": "PaperglassesG10_glasses", "_1_16": "PaperglassesG11_glasses", "_2_01": "MannequinMq07_fakehead", "_2_02": "MannequinMq01_fakehead", "_2_03": "MannequinMq02_fakehead", "_2_04": "MannequinMq03_fakehead", "_2_05": "MannequinMq04_fakehead", "_2_06": "MannequinMq05_fakehead", "_2_07": "MannequinMq06_fakehead", "_2_08": "PapercraftmaskB030100_papermask", "_2_09": "PapercraftmaskB030300_papermask", "_2_10": "PapercraftmaskB031100_papermask", "_2_11": "PapercraftmaskB031200_papermask", "_2_12": "CustomwearablemaskB050100_rigidmask", "_2_13": "CustomwearablemaskB050200_rigidmask", "_2_14": "CustomwearablemaskB051200_rigidmask", "_2_15": "CustomwearablemaskB051600_rigidmask", "_2_16": "CustomwearablemaskB051800_rigidmask", "_2_17": "CustomwearablemaskB051900_rigidmask", "_2_18": "FlexiblesiliconmaskB072100_flexiblemask", "_2_75": "FlexiblesiliconmaskB063000_flexiblemask", "_2_76": "FlexiblesiliconmaskB063100_flexiblemask", "_2_77": "FlexiblesiliconmaskB073200_flexiblemask", "_2_78": "FlexiblesiliconmaskB073300_flexiblemask", "_2_79": "FlexiblesiliconmaskB073400_flexiblemask", "_2_80": "FlexiblesiliconmaskB060100_flexiblemask", "_2_81": "FlexiblesiliconmaskB060200_flexiblemask", "_2_82": "FlexiblesiliconmaskB060202_flexiblemask", "_2_83": "FlexiblesiliconmaskB061200_flexiblemask", "_2_84": "FlexiblesiliconmaskB062400_flexiblemask", "_2_85": "FlexiblesiliconmaskB061600_flexiblemask", "_2_86": "FlexiblesiliconmaskB061800_flexiblemask", "_2_87": "FlexiblesiliconmaskB061900_flexiblemask", "_2_88": "FlexiblesiliconmaskB070100_flexiblemask", "_2_89": "FlexiblesiliconmaskB071200_flexiblemask", "_2_90": "FlexiblesiliconmaskB071900_flexiblemask", "_2_91": "FlexiblesiliconmaskB062500_flexiblemask", "_2_92": "FlexiblesiliconmaskB062601_flexiblemask", "_2_93": "FlexiblesiliconmaskB072701_flexiblemask", "_2_94": "FlexiblesiliconmaskB072801_flexiblemask", "_2_95": "FlexiblesiliconmaskB072901_flexiblemask", "_2_96": "FlexiblesiliconmaskB062600_flexiblemask", "_2_97": "FlexiblesiliconmaskB072700_flexiblemask", "_2_98": "FlexiblesiliconmaskB072800_flexiblemask", "_2_99": "FlexiblesiliconmaskB072900_flexiblemask", "_3_01": "PrintedP0000100_prints", "_3_02": "PrintedP0000101_prints", "_3_03": "PrintedP0000102_prints", "_3_04": "PrintedP0000103_prints", "_3_05": "ElectronicP0100100_replay", "_3_06": "PrintedP0001800_prints", "_3_07": "PrintedP0001801_prints", "_3_08": "PrintedP0001802_prints", "_3_09": "PrintedP0001803_prints", "_3_10": "ElectronicP0101800_replay", "_3_11": "PrintedP0009800_prints", "_3_12": "PrintedP0009801_prints", "_3_13": "PrintedP0009802_prints", "_3_14": "PrintedP0009803_prints", "_3_15": "ElectronicP0109800_replay", "_4_01": "VideoplayV0001900_replay", "_4_02": "VideopauseV0101900_replay", "_4_03": "VideoplayV0001200_replay", "_4_04": "VideopauseV0101200_replay", "_4_05": "VideoplayV0009800_replay", "_4_06": "VideopauseV0109800_replay", "_4_07": "VideoplayV0001901_replay", "_4_08": "VideopauseV0101901_replay", "_4_09": "VideoplayV0000501_replay", "_4_10": "VideopauseV0100501_replay", "_4_11": "VideoplayV0009801_replay", "_4_12": "VideopauseV0109801_replay", "_4_13": "VideoplayV0101902_replay", "_4_14": "VideopauseV0101902_replay", "_4_15": "VideoplayV0101202_replay", "_4_16": "VideopauseV0101202_replay", "_4_17": "VideoplayV0109802_replay", "_4_18": "VideopauseV0109802_replay", "_5_01": "Makeup_makeup", "_5_02": "Makeup_makeup", "_5_03": "Makeup_makeup", "_5_04": "Makeup_makeup", "_5_05": "Makeup_makeup", "_5_06": "Makeup_makeup", "_5_07": "Makeup_makeup", "_5_08": "Makeup_makeup", "_5_09": "Makeup_makeup", "_5_10": "Makeup_makeup", "_5_100": "Makeup_makeup", "_5_101": "Makeup_makeup", "_5_102": "Makeup_makeup", "_5_103": "Makeup_makeup", "_5_104": "Makeup_makeup", "_5_105": "Makeup_makeup", "_5_106": "Makeup_makeup", "_5_107": "Makeup_makeup", "_5_108": "Makeup_makeup", "_5_109": "Makeup_makeup", "_5_11": "Makeup_makeup", "_5_110": "Makeup_makeup", "_5_111": "Makeup_makeup", "_5_112": "Makeup_makeup", "_5_113": "Makeup_makeup", "_5_114": "Makeup_makeup", "_5_115": "Makeup_makeup", "_5_116": "Makeup_makeup", "_5_117": "Makeup_makeup", "_5_118": "Makeup_makeup", "_5_119": "Makeup_makeup", "_5_12": "Makeup_makeup", "_5_120": "Makeup_makeup", "_5_121": "Makeup_makeup", "_5_122": "Makeup_makeup", "_5_123": "Makeup_makeup", "_5_124": "Makeup_makeup", "_5_125": "Makeup_makeup", "_5_126": "Makeup_makeup", "_5_127": "Makeup_makeup", "_5_128": "Makeup_makeup", "_5_129": "Makeup_makeup", "_5_13": "Makeup_makeup", "_5_130": "Makeup_makeup", "_5_131": "Makeup_makeup", "_5_132": "Makeup_makeup", "_5_133": "Makeup_makeup", "_5_134": "Makeup_makeup", "_5_135": "Makeup_makeup", "_5_136": "Makeup_makeup", "_5_137": "Makeup_makeup", "_5_138": "Makeup_makeup", "_5_139": "Makeup_makeup", "_5_14": "Makeup_makeup", "_5_15": "Makeup_makeup", "_5_16": "Makeup_makeup", "_5_17": "Makeup_makeup", "_5_18": "Makeup_makeup", "_5_19": "Makeup_makeup", "_5_20": "Makeup_makeup", "_5_21": "Makeup_makeup", "_5_22": "Makeup_makeup", "_5_23": "Makeup_makeup", "_5_24": "Makeup_makeup", "_5_25": "Makeup_makeup", "_5_26": "Makeup_makeup", "_5_27": "Makeup_makeup", "_5_28": "Makeup_makeup", "_5_29": "Makeup_makeup", "_5_30": "Makeup_makeup", "_5_31": "Makeup_makeup", "_5_32": "Makeup_makeup", "_5_33": "Makeup_makeup", "_5_34": "Makeup_makeup", "_5_35": "Makeup_makeup", "_5_36": "Makeup_makeup", "_5_37": "Makeup_makeup", "_5_38": "Makeup_makeup", "_5_39": "Makeup_makeup", "_5_40": "Makeup_makeup", "_5_41": "Makeup_makeup", "_5_42": "Makeup_makeup", "_5_43": "Makeup_makeup", "_5_44": "Makeup_makeup", "_5_45": "Makeup_makeup", "_5_46": "Makeup_makeup", "_5_47": "Makeup_makeup", "_5_48": "Makeup_makeup", "_5_49": "Makeup_makeup", "_5_50": "Makeup_makeup", "_5_51": "Makeup_makeup", "_5_52": "Makeup_makeup", "_5_53": "Makeup_makeup", "_5_54": "Makeup_makeup", "_5_55": "Makeup_makeup", "_5_56": "Makeup_makeup", "_5_57": "Makeup_makeup", "_5_58": "Makeup_makeup", "_5_59": "Makeup_makeup", "_5_60": "Makeup_makeup", "_5_61": "Makeup_makeup", "_5_62": "Makeup_makeup", "_5_63": "Makeup_makeup", "_5_64": "Makeup_makeup", "_5_65": "Makeup_makeup", "_5_66": "Makeup_makeup", "_5_67": "Makeup_makeup", "_5_68": "Makeup_makeup", "_5_69": "Makeup_makeup", "_5_70": "Makeup_makeup", "_5_71": "Makeup_makeup", "_5_72": "Makeup_makeup", "_5_73": "Makeup_makeup", "_5_74": "Makeup_makeup", "_5_75": "Makeup_makeup", "_5_76": "Makeup_makeup", "_5_77": "Makeup_makeup", "_5_78": "Makeup_makeup", "_5_79": "Makeup_makeup", "_5_80": "Makeup_makeup", "_5_81": "Makeup_makeup", "_5_82": "Makeup_makeup", "_5_83": "Makeup_makeup", "_5_84": "Makeup_makeup", "_5_85": "Makeup_makeup", "_5_86": "Makeup_makeup", "_5_87": "Makeup_makeup", "_5_88": "Makeup_makeup", "_5_89": "Makeup_makeup", "_5_90": "Makeup_makeup", "_5_91": "Makeup_makeup", "_5_92": "Makeup_makeup", "_5_93": "Makeup_makeup", "_5_94": "Makeup_makeup", "_5_95": "Makeup_makeup", "_5_96": "Makeup_makeup", "_5_97": "Makeup_makeup", "_5_98": "Makeup_makeup", "_5_99": "Makeup_makeup", "_1_08": "Wig", "_1_09": "Wig", "_1_10": "Wig", "_1_11": "Wig", "_1_12": "Wig"}
\ No newline at end of file
diff --git a/bob/pad/face/test/test_databases.py b/bob/pad/face/test/test_databases.py
index 3ed9051075549159ce82de3f51c8ffe3ab4f2289..215110cc2e30c8bf28e0737a1559db0011c2a14a 100644
--- a/bob/pad/face/test/test_databases.py
+++ b/bob/pad/face/test/test_databases.py
@@ -219,3 +219,136 @@ def test_casiasurf():
         raise SkipTest(
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e)
+
+# # Test the BATL database
+# @db_available('batl-db')
+# def test_aggregated_db():
+#     batl_db = bob.bio.base.load_resource(
+#         'batl-db',
+#         'database',
+#         preferred_package='bob.pad.face',
+#         package_prefix='bob.pad.')
+#     try:
+
+#         assert len(
+#             batl_db.objects(groups=['train', 'dev', 'eval'])) == 1679
+#         assert len(batl_db.objects(groups=['train', 'dev'])) == 1122
+#         assert len(batl_db.objects(groups=['train'])) == 565
+
+#         assert len(batl_db.objects(groups='train')) == 565
+#         assert len(batl_db.objects(groups='dev')) == 557
+#         assert len(batl_db.objects(groups='eval')) == 557
+
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'], protocol='grandtest')) == 1679
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest',
+#                 purposes='real')) == 347
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest',
+#                 purposes='attack')) == 1332
+#         #tests for join_train_dev protocols
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-join_train_dev')) == 1679
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-join_train_dev')) == 1679
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-join_train_dev')) == 557
+#         # test for LOO_fakehead
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-LOO_fakehead')) == 1149
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_fakehead')) == 1017
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-LOO_fakehead')) == 132
+
+#         # test for LOO_flexiblemask
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-LOO_flexiblemask')) == 1132
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_flexiblemask')) == 880
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-LOO_flexiblemask')) == 252
+
+#         # test for LOO_glasses
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-LOO_glasses')) == 1206
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_glasses')) == 1069
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-LOO_glasses')) == 137
+
+#         # test for LOO_papermask
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-LOO_papermask')) == 1308
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_papermask')) == 1122
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-LOO_papermask')) == 186
+
+#         # test for LOO_prints
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-LOO_prints')) == 1169
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_prints')) == 988
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-LOO_prints')) == 181
+
+#         # test for LOO_replay
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-LOO_replay')) == 1049
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_replay')) == 854
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-LOO_replay')) == 195
+
+#         # test for LOO_rigidmask
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev', 'eval'],
+#                 protocol='grandtest-color-50-LOO_rigidmask')) == 1198
+#         assert len(
+#             batl_db.objects(
+#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_rigidmask')) == 1034
+#         assert len(
+#             batl_db.objects(groups='eval',
+#                                   protocol='grandtest-color-50-LOO_rigidmask')) == 164
+
+
+#     except IOError as e:
+#         raise SkipTest(
+#             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
+#             % e)
\ No newline at end of file