Rami Langar

142 papers B 46C 3Misc 1Journal 39Unranked 53
YearRankTypeTitle / Venue / Authors
2026 J jnl
Eng. Appl. Artif. Intell.
Sonda Fourati, Wael Jaafar, Noura Baccar, Safwan Alfattani, Rami Langar
2025 conf
NoF
Abdelwahab Boualouache, Vinicius F. Silva, Qiang Tang, Enric Pardo, Sylvain Cherrier, Badre Bousalem, Sébastien Faye, Rami Langar
2025 conf
ICC
Joseph Antoun, Wael Jaafar, Rami Langar
2025 conf
GIIS
Badre Bousalem, Vinicius F. Silva, Selsabil-Belkis Bakhouche, Rami Langar, Sylvain Cherrier
2025 B conf
WiMob
David Kule Mukuhi, Léo Mendiboure, Rami Langar, Rodrigue Fargeon, Sylvain Cherrier, Marion Berbineau, Pierre-Yves Petton
2025 conf
ICC
Abir Laouadi, Rami Langar
2025 B conf
WiMob
Massamaesso Narouwa, Léo Mendiboure, Sassi Maaloul, Hakim Badis, Dereje Mechal Molla, Marion Berbineau, Rami Langar
2025 J jnl
IEEE Commun. Mag.
Damos Ayobo Abongo, Wael Jaafar, Rami Langar
2025 C conf
ISORC
Massamaesso Narouwa, Léo Mendiboure, Sassi Maaloul, Ndeye Birame Dia, Hakim Badis, Dereje Mechal Molla, Marion Berbineau, Rami Langar
2025 J jnl
IEEE Access
Damos Ayobo Abongo, Wael Jaafar, Rami Langar
2025 conf
NoF
Amina Boudjelida, Ali Lemouari, Wael Jaafar, Rami Langar
2025 conf
GIIS
Mohamed Aziz Aboud, Nawel Zangar, Rami Langar, Marion Berbineau, Jerome Madec
2025 J jnl
CoRR
Mohamed Aziz Aboud, Nawel Zangar, Rami Langar, Marion Berbineau, Jerome Madec
2025 conf
ICC
Mohamed Anis Sakka, Wael Jaafar, Rami Langar
2025 J jnl
IEEE Open J. Commun. Soc.
Fahdah Alalyan, Mirna Awad, Wael Jaafar, Rami Langar
2024 J jnl
IEEE Access
Massamaesso Narouwa, Léo Mendiboure, Hakim Badis, Sassi Maaloul, Dereje Mechal Molla, Marion Berbineau, Rami Langar
2024 B conf
IWCMC
Tanmay Badageri, Bechir Hamdaoui, Rami Langar
2024 conf
CIoT
Messaoud Ait Yahia, Mouhamadou Mouctar Gueye, Wael Jaafar, Rami Langar
2024 conf
CIoT
Khalil Snoussi, Wael Jaafar, Rami Langar
2024 conf
ICC
Fahdah Alalyan, Badre Bousalem, Wael Jaafar, Rami Langar
2024 conf
CIoT
Mirna Awad, Adam Ait Hamid, Yeogeuch Ranganathan, Nizar Choubik, Rami Langar, Wael Jaafar
2023 J jnl
IEEE Internet Things Mag.
Abdelwahab Boualouache, Bouziane Brik, Qiang Tang, Abdelaziz Amara Korba, Sylvain Cherrier, Sidi-Mohammed Senouci, Enric Pardo, Yacine Ghamri-Doudane, Rami Langar, Thomas Engel
2023 B conf
CNSM
Badre Bousalem, Mohamed Anis Sakka, Vinicius F. Silva, Wael Jaafar, Asma Ben Letaifa, Rami Langar
2023 B conf
GLOBECOM
Badre Bousalem, Vinicius F. Silva, Abdelwahab Boualouache, Rami Langar, Sylvain Cherrier
2023 B conf
GLOBECOM
Roumaissa Bekkouche, Mawloud Omar, Rami Langar
2023 Misc conf
ICMLC
Muluken Regas Eressa, Hakim Badis, Rami Langar, Dorian Grosso
2023 J jnl
IEEE Trans. Netw. Serv. Manag.
Salma Matoussi, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar
2022 B conf
GLOBECOM
Badre Bousalem, Vinicius F. Silva, Rami Langar, Sylvain Cherrier
2022 B conf
NetSoft
Badre Bousalem, Vinicius F. Silva, Rami Langar, Sylvain Cherrier
2022 J jnl
Comput. Networks
E. L. Hocine Bouzidi, Abdelkader Outtagarts, Rami Langar, Raouf Boutaba
2022 B conf
GLOBECOM
Mohand Ouamer Nait Belaid, Vincent Audebert, Boris Deneuville, Rami Langar
2022 conf
SmartGridComm
Mohand Ouamer Nait Belaid, Vincent Audebert, Boris Deneuville, Rami Langar
2022 conf
ICC
Roumaissa Bekkouche, Mawloud Omar, Rami Langar, Bechir Hamdaoui
2021 J jnl
Comput. Networks
Nazih Salhab, Rami Langar, Rana Rahim
2021 J jnl
IEEE Commun. Mag.
Nazih Salhab, Rami Langar, Rana Rahim, Sylvain Cherrier, Abdelkader Outtagarts
2021 J jnl
J. Netw. Comput. Appl.
EL Hocine Bouzidi, Abdelkader Outtagarts, Rami Langar, Raouf Boutaba
2021 J jnl
Trans. Emerg. Telecommun. Technol.
Deze Zeng, Ruidong Li, Zhi Zhou, Ruiting Zhou, Rami Langar, Md. Zakirul Alam Bhuiyan
2021 J jnl
IEEE Access
Jarallah Alqahtani, Bechir Hamdaoui, Rami Langar
2020 J jnl
IEEE J. Sel. Areas Commun.
Salma Matoussi, Ilhem Fajjari, Salvatore Costanzo, Nadjib Aitsaadi, Rami Langar
2020 J jnl
IEEE Trans. Mob. Comput.
Shuai Yu, Boutheina Dab, Zeinab Movahedi, Rami Langar, Li Wang
2020 B conf
Networking
Nazih Salhab, Rana Rahim, Rami Langar
2020 B conf
LCN
Salma Matoussi, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar
2020 B conf
Networking
Nazih Salhab, Rana Rahim, Rami Langar, Raouf Boutaba
2020 conf
GIIS
Hager Ben Hafaiedh, Inès El Korbi, Rami Langar, Leïla Azouz Saïdane, Abdellatif Kobbane
2020 conf
ICC
Nazih Salhab, Rana Rahim, Rami Langar, Raouf Boutaba
2020 conf
ICC
EL Hocine Bouzidi, Abdelkader Outtagarts, Abdelkrim Hebbar, Rami Langar, Raouf Boutaba
2020 J jnl
IEEE Trans. Netw. Serv. Manag.
Nazih Salhab, Rana Rahim, Rami Langar
2020 conf
GIIS
Sylvain Cherrier, Rami Langar
2020 B conf
WCNC
Salma Matoussi, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar
2020 C conf
PEMWN
Hager Ben Hafaiedh, Inès El Korbi, Rami Langar, Leïla Azouz Saïdane
2019 conf
CCNC
Boutheina Dab, Nadjib Aitsaadi, Rami Langar
2019 B conf
IWCMC
Hager Ben Hafaiedh, Inès El Korbi, Rami Langar, Leïla Azouz Saïdane, Abdellatif Kobbane
2019 B conf
IM
Shuai Yu, Rami Langar
2019 B conf
GLOBECOM
EL Hocine Bouzidi, Abdelkader Outtagarts, Rami Langar
2019 conf
ICC
Salma Matoussi, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar, Salvatore Costanzo
2019 B conf
WCNC
Boutheina Dab, Nadjib Aitsaadi, Rami Langar
2019 B conf
GLOBECOM
Nazih Salhab, Rana Rahim, Rami Langar, Raouf Boutaba
2019 conf
INFOCOM Workshops
Nazih Salhab, Rana Rahim, Rami Langar
2019 conf
INFOCOM Workshops
Salvatore Costanzo, Sylvain Cherrier, Rami Langar
2019 B conf
IM
Boutheina Dab, Nadjib Aitsaadi, Rami Langar
2018 conf
ICC
Salma Matoussi, Ilhem Fajjari, Salvatore Costanzo, Nadjib Aitsaadi, Rami Langar
2018 J jnl
Comput. Networks
Mohammed Yazid Lyazidi, Nadjib Aitsaadi, Rami Langar
2018 conf
CCNC
Salvatore Costanzo, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar
2018 J jnl
IEEE Trans. Veh. Technol.
Shuai Yu, Rami Langar, Xiaoming Fu, Li Wang, Zhu Han
2018 conf
CCNC
Salvatore Costanzo, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar
2018 conf
CIoT
Salvatore Costanzo, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar
2018 B conf
IWCMC
Amira Bezzina, Mouna Ayari, Rami Langar, Leïla Azouz Saïdane
2018 B conf
GLOBECOM
EL Hocine Bouzidi, Duc-Hung Luong, Abdelkader Outtagarts, Abdelkrim Hebbar, Rami Langar
2018 conf
MENACOMM
Nazih Salhab, Salah El Falou, Rana Rahim, Salah Eddine El Ayoubi, Rami Langar
2018 conf
GIIS
Sylvain Cherrier, Rami Langar
2018 conf
GIIS
Nazih Salhab, Rana Rahim, Rami Langar
2018 J jnl
IEEE Trans. Mob. Comput.
Jose Leal Domingues Neto, Se-Young Yu, Daniel F. Macedo, José Marcos S. Nogueira, Rami Langar, Stefano Secci
2017 conf
VTC Fall
Mohammed Yazid Lyazidi, Lorenza Giupponi, Josep Mangues-Bafalluy, Nadjib Aitsaadi, Rami Langar
2017 J jnl
J. Netw. Comput. Appl.
Fahimeh Dabaghi, Zeinab Movahedi, Rami Langar
2017 conf
INFOCOM Workshops
Alessandro Zanni, Se-Young Yu, Stefano Secci, Rami Langar, Paolo Bellavista, Daniel F. Macedo
2017 B conf
CNSM
Alessandro Zanni, Se-Young Yu, Paolo Bellavista, Rami Langar, Stefano Secci
2017 B conf
PIMRC
Shuai Yu, Xin Wang, Rami Langar
2016 B conf
GLOBECOM
Shuai Yu, Rami Langar, Xin Wang
2016 conf
GIIS
Amira Bezzina, Mouna Ayari, Rami Langar, Leïla Azouz Saïdane
2016 conf
ICC
Shuai Yu, Rami Langar, Wenzhong Li, Xu Chen
2016 J jnl
IEEE Access
Mouna Hajir, Rami Langar, François Gagnon
2016 conf
ICC
Mohammed Yazid Lyazidi, Nadjib Aitsaadi, Rami Langar
2016 J jnl
Veh. Commun.
Rami Langar, Bechir Hamdaoui, Mario Gerla, Raouf Boutaba
2016 B conf
IWCMC
Ahlam Ben Cheikh, Mouna Ayari, Rami Langar, Leïla Azouz Saïdane
2016 conf
ISC2
Naourez Mejri, Mouna Ayari, Rami Langar, Leïla Azouz Saïdane
2016 B conf
GLOBECOM
Mohammed Yazid Lyazidi, Nadjib Aitsaadi, Rami Langar
2016 conf
ICC
Mouna Hajir, Rami Langar, François Gagnon
2015 B conf
Networking
Zakia Khalfallah, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar, Guy Pujolle
2015 J jnl
IEEE Trans. Mob. Comput.
Rami Langar, Stefano Secci, Raouf Boutaba, Guy Pujolle
2015 J jnl
IEEE Trans. Netw. Serv. Manag.
Ahmed Amokrane, Rami Langar, Raouf Boutaba, Guy Pujolle
2015 J jnl
IEEE Trans. Netw. Serv. Manag.
Ahmed Amokrane, Rami Langar, Mohamed Faten Zhani, Raouf Boutaba, Guy Pujolle
2015 conf
ICC
Ahlam Ben Cheikh, Mouna Ayari, Rami Langar, Guy Pujolle, Leïla Azouz Saïdane
2014 J jnl
IEEE Trans. Veh. Technol.
Abbas Antoun Hatoum, Rami Langar, Nadjib Aitsaadi, Raouf Boutaba, Guy Pujolle
2014 conf
ICC
Naourez Mejri, Mouna Ayari, Rami Langar, Farouk Kamoun, Guy Pujolle, Leïla Azouz Saïdane
2014 J jnl
Comput. Networks
Ahmed Amokrane, Rami Langar, Raouf Boutaba, Guy Pujolle
2014 conf
Wireless Days
Amira Bezzina, Mouna Ayari, Rami Langar, Guy Pujolle, Leïla Azouz Saïdane
2014 B conf
CNSM
Ahmed Amokrane, Mohamed Faten Zhani, Qi Zhang, Rami Langar, Raouf Boutaba, Guy Pujolle
2014 conf
NOF
Zakia Khalfallah, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar, Guy Pujolle
2013 J jnl
IEEE Trans. Mob. Comput.
Sahar Hoteit, Stefano Secci, Rami Langar, Guy Pujolle
2013 B conf
GLOBECOM
Zakia Khalfallah, Ilhem Fajjari, Nadjib Aitsaadi, Rami Langar, Guy Pujolle
2013 conf
ICC
Mouna Hkimi, Rami Langar, Stefano Secci, Raouf Boutaba, Guy Pujolle
2013 J jnl
IEEE Trans. Cloud Comput.
Ahmed Amokrane, Mohamed Faten Zhani, Rami Langar, Raouf Boutaba, Guy Pujolle
2013 B conf
GLOBECOM
Ahmed Amokrane, Rami Langar, Raouf Boutaba, Guy Pujolle
2013 B conf
WiMob
Ahlam Ben Cheikh, Mouna Ayari, Rami Langar, Guy Pujolle, Leïla Azouz Saïdane
2013 conf
Med-Hoc-Net
Rami Langar, Guy Pujolle
2012 J jnl
IEEE Commun. Surv. Tutorials
Zeinab Movahedi, Mouna Ayari, Rami Langar, Guy Pujolle
2012 B conf
GLOBECOM
Sahar Hoteit, Stefano Secci, Rami Langar, Guy Pujolle, Raouf Boutaba
2012 B conf
CNSM
Ahmed Amokrane, Rami Langar, Raouf Boutaba, Guy Pujolle
2012 B conf
WiMob
Amira Bezzina, Mouna Ayari, Rami Langar, Farouk Kamoun
2012 conf
ICC
Abbas Antoun Hatoum, Rami Langar, Nadjib Aitsaadi, Guy Pujolle
2012 B conf
GLOBECOM
Abbas Antoun Hatoum, Rami Langar, Nadjib Aitsaadi, Raouf Boutaba, Guy Pujolle
2012 conf
ICC
Sahar Hoteit, Stefano Secci, Rami Langar, Guy Pujolle
2011 conf
ICC
Sofiane Moad, Mario E. Rivero-Angeles, Nizar Bouabdallah, Rami Langar
2011 conf
Wireless Days
Sofiane Moad, Mohammad Abdul Azim, Nizar Bouabdallah, Rami Langar
2011 conf
ICC
Abbas Antoun Hatoum, Nadjib Aitsaadi, Rami Langar, Raouf Boutaba, Guy Pujolle
2011 J jnl
IEEE Trans. Veh. Technol.
Hanan Saleet, Rami Langar, Kshirasagar Naik, Raouf Boutaba, Amiya Nayak, Nishith Goel
2011 B conf
GLOBECOM
Hanan Saleet, Sagar Naik, Rami Langar, Raouf Boutaba, Amiya Nayak, Vineet Srivastava
2010 conf
Med-Hoc-Net
Wafa Berrayana, Habib Youssef, Rami Langar, Guy Pujolle
2010 J jnl
IEEE/ACM Trans. Netw.
Nizar Bouabdallah, Rami Langar, Raouf Boutaba
2010 conf
ICC
Rami Langar, Nizar Bouabdallah, Raouf Boutaba, Guy Pujolle
2010 B conf
GLOBECOM
Hanan Saleet, Rami Langar, Sagar Naik, Raouf Boutaba, Amiya Nayak, Nishith Goel
2010 J jnl
IEEE Trans. Veh. Technol.
Hanan Saleet, Otman Basir, Rami Langar, Raouf Boutaba
2010 conf
CNSR
Abdeljalil Karouia, Rami Langar, Thi Mai Trang Nguyen, Guy Pujolle
2010 B conf
GLOBECOM
Rami Langar, Salsabil Njima, Nizar Bouabdallah, Raouf Boutaba, Guy Pujolle
2009 conf
ICC
Hanan Saleet, Rami Langar, Otman Basir, Raouf Boutaba
2009 B conf
GLOBECOM
Hanan Saleet, Rami Langar, Otman Basir, Raouf Boutaba
2009 J jnl
Comput. Networks
Rami Langar, Nizar Bouabdallah, Raouf Boutaba
2009 J jnl
IEEE Trans. Wirel. Commun.
Rami Langar, Nizar Bouabdallah, Raouf Boutaba, Bruno Sericola
2008 J jnl
IEEE/ACM Trans. Netw.
Rami Langar, Nizar Bouabdallah, Raouf Boutaba
2008 B conf
GLOBECOM
Hanan Saleet, Rami Langar, Otman Basir, Raouf Boutaba
2007 B conf
GLOBECOM
Rami Langar, Nizar Bouabdallah, Raouf Boutaba
2006 conf
ICC
Rami Langar, Nizar Bouabdallah, Samir Tohmé
2006 B conf
NOMS
Rami Langar, Samir Tohmé, Nizar Bouabdallah
2006 B conf
PIMRC
Rami Langar, Nizar Bouabdallah, Samir Tohmé
2006 B conf
WCNC
Rami Langar, Nizar Bouabdallah, Samir Tohmé
2006 B conf
GLOBECOM
Rami Langar, Nizar Bouabdallah, Samir Tohmé, Raouf Boutaba
2006 J jnl
Int. J. Netw. Manag.
Rami Langar, Samir Tohmé, Nizar Bouabdallah
2006 J jnl
J. Commun.
Rami Langar, Nizar Bouabdallah, Samir Tohmé
2006 conf
CCNC
Rami Langar, Samir Tohmé, Nizar Bouabdallah, Guy Pujolle
2005 conf
WONS
Rami Langar, Gwendal Le Grand, Samir Tohmé
2005 C conf
ISCC
Rami Langar, Samir Tohmé, Gwendal Le Grand
2005 B conf
PIMRC
Rami Langar, Samir Tohmé, Nizar Bouabdallah, Guy Pujolle
start.py
← Index start.py python
"""
# By repository (existing behavior, now uses repository_upload_sessions)
python start.py --s3 --repo bazaar --index_prefix redb

# By repository with notes filter
python start.py --s3 --repo vx-itw --s3-notes "ITW.0138" --index_prefix redb

# By single date (all repo samples first seen on Jan 15, 2025)
python start.py --date 2025-01-15 --index_prefix redb

# By date with repository filter
python start.py --date 2025-01-15 --repo bazaar --index_prefix redb

# By date range (inclusive)
python start.py --range 2025-01-01 2025-01-31 --index_prefix redb

# By date range with repository and notes filters
python start.py --range 2025-01-01 2025-01-31 --repo malshare --s3-notes "batch1" --index_prefix redb

# By filetype (magika) standalone - process all ELF samples across all repos
python start.py --s3 --magika elf --index_prefix redb

# By filetype with repository filter
python start.py --s3 --repo bazaar --magika elf --index_prefix redb

# By filetype with date range - process only PE samples in date range
python start.py --range 2025-01-01 2025-01-31 --magika pebin --index_prefix redb
"""

import argparse
import os
import sys
from datetime import datetime, timedelta
from redb.ingestor import *

"""
        # General modules
        'BasicPropertiesExtractor': BasicPropertiesExtractor,
        'HashExtractor': HashExtractor,
        'DIEExtractor': DIEExtractor,
        'CAPAExtractor': CAPAExtractor,
        'StringsExtractor': StringsExtractor,
        # PE modules
        'PEFeaturesExtractor': PEFeaturesExtractor,
        'PEImportExtractor': PEImportExtractor,
        'PEResourceExtractor': PEResourceExtractor,
        'PEOverlayExtractor': PEOverlayExtractor,
        'PESectionExtractor': PESectionExtractor,
        'PESignatureExtractor': PESignatureExtractor,
        'PEExtraFindings': PEExtraFindings,
        'PEInconstistencyTestsExtractor': PEInconstistencyTestsExtractor,
        'PEDotNetExtractor': PEDotNetExtractor,
"""


def main():
    # # path = "/mnt/samples/consilience/malware/test/test-unzipped/0242d90dc48a8931bad72ddbdba34bdd568fd30610dfe049c84968d425088c71/"
    # path = "/Users/p4c0/_samples/test-unzipped/0242d90dc48a8931bad72ddbdba34bdd568fd30610dfe049c84968d425088c71" #Stuxnet
    # # path = "/Volumes/backup/consilience/malware/test/test-unzipped/rhpv-673f91a2085358e3266f466845366f30cf741060edeb31e9a93e2c92033bba28"
    # # path = "/mnt/samples/consilience/malware/test/test-redb/"
    # # path = "/mnt/samples/consilience/malware/malpedia-pe/9bc81280113473de9ebfe54f689b4440287c37fff562e070d3a28f5269cadcf0_dump7_0x00400000"
    # # path = "/mnt/samples/consilience/malware/test/test-unzipped/379251974ebcd5c397f92ca45bb9620d"
    # path = "0242d90dc48a8931bad72ddbdba34bdd568fd30610dfe049c84968d425088c71" # rich header, UPX packer
    # # #path = "d8637bdbcfc9112fcb1f0167b398e771" #dotnet
    # path = "/Users/p4c0/_samples/test-unzipped/sig-8e035beb02a411f8a9e92d4cf184ad34f52bbd0a81a50c222cdd4706e4e45104" #code signed, protector use case for sections
    # path = "/Users/p4c0/_samples/test-unzipped/vsinfo-39d8ad95b0323c37bd3134ab93ac4af44c66a1a8443a41c1ac02cec19bb2816a"
    # # path = "/Volumes/backup/consilience/malware/_sorted_samples/vx-apt/pebin/69e679daaaff3832c39671bf2b813b5530a70fb763d381f9a6e22e3bc493c8a9.7z"
    # # path = "test_files/hello"
    # path = "/Volumes/backup/consilience/malware/test/test-re2db/"
    # # path = "/Users/p4c0/_samples/HEUR-Trojan-PSW.MSIL.Maslog.gen-0c9ae5cd740c1da7060b92ddb33f3a3893e361aad45a2accc64d43bd9a1a4106"
    # # path = "/Users/p4c0/_samples/test-unzipped/"
    # # # path = "/Volumes/backup/consilience/malware/_sorted_samples/vx-apt/pebin/7156bd8056c4b6b4e179a64370067d3f7a7cce0044f1352d41f3c2c73038d273.7z"
    # decompile = False
    # repo = "test-fixing"
    # index_prefix = "test4"
    # selected_modules = "all"
    # exporter_types = ['ClickHouse']

    # parser = argparse.ArgumentParser(
    #     description="Process binary files in a given path."
    # )
    # parser.add_argument("path", 
    #     help="File path, directory path, or path to a .txt file containing a list of files to process (one per line)")
    # parser.add_argument(
    #     "--repo", help="Repository name for sample source, used for loggfile name"
    # )
    # parser.add_argument("--index_prefix", help="Index prefix for ElasticSearch")
    # parser.add_argument(
    #     "-d",
    #     "--decompile",
    #     action="store_true",
    #     help="Optional flag, if set it will run ONLY the decompiler on the binary files",
    # )
    # parser.add_argument(
    #     "-m",
    #     "--modules",
    #     help="Comma-separated list of modules to run (e.g., 'BasicPropertiesExtractor,HashExtractor') or 'all' for all modules",
    #     default="all",
    # )
    # args = parser.parse_args()
    # path = args.path
    # index_prefix = args.index_prefix
    # decompile = args.decompile
    # repo = args.repo
    # selected_modules = args.modules

    # print(f"Decompile flag: {decompile}")
    # print(f"Repo: {repo}")
    # print(f"Selected modules: {selected_modules}")
    
    # if path.endswith('.txt'):
    #     print(f"Reading file list from: {path}")

    # Ingestor(path, decompile, repo, index_prefix, selected_modules).ingest()

    parser = argparse.ArgumentParser(
        description="Process binary files from local paths or S3 storage."
    )
    
    # Create a mutually exclusive group for input sources
    # Not required because --analyzed can be used standalone
    input_group = parser.add_mutually_exclusive_group(required=False)
    input_group.add_argument(
        "--path", 
        help="File path, directory path, or path to a .txt file containing a list of files to process (one per line)")
    input_group.add_argument(
        "--s3",
        action="store_true",
        help="Use S3 mode to fetch files from repository specified by --repo")
    input_group.add_argument(
        "--s3-solo",
        metavar="S3_KEY",
        help="Process a single S3 file by providing the S3 key (e.g., 09/f7/09f7d02a....zip)")
    input_group.add_argument(
        "--nomad-job",
        action="store_true",
        help="Run as Nomad job using environment variables for job parameters")
    input_group.add_argument(
        "--date",
        metavar="YYYY-MM-DD",
        help="Process samples first seen on a specific date (from repository_upload_sessions only)")
    input_group.add_argument(
        "--range",
        nargs=2,
        metavar=("START_DATE", "END_DATE"),
        help="Process samples first seen in a date range (inclusive, from repository_upload_sessions only). Format: YYYY-MM-DD YYYY-MM-DD")
    parser.add_argument(
        "--analyzed",
        action="store_true",
        help="Filter to samples already in the database (from basic_properties). "
             "Can be used standalone or combined with --range/--date to partition large runs")

    parser.add_argument(
        "--repo",
        required=False,
        help="Repository name for sample source, used for logging and S3 filtering (optional for --date/--range modes)")
    
    parser.add_argument(
        "--s3-notes",
        help="Optional filter for S3 files based on notes field (S3 mode only)")

    parser.add_argument(
        "--magika",
        help="Filter by filetype_magika (e.g., 'elf', 'pebin'). Overrides SUPPORTED_FORMATS env var. Can combine with --repo, --date, --range")

    parser.add_argument(
        "--index_prefix", default="redb",
        help="Index prefix for database (default: redb)")
    
    parser.add_argument(
        "-d",
        "--decompile",
        action="store_true",
        help="Optional flag, if set it will run ONLY the decompiler on the binary files",
    )

    parser.add_argument(
        "-y",
        "--yara",
        action="store_true",
        help="Optional flag, if set it will run ONLY the YARA scanner on the binary files",
    )

    parser.add_argument(
        "--with-yara",
        action="store_true",
        help="Add YARA scanning to feature extraction (runs both features and YARA)",
    )

    parser.add_argument(
        "-m",
        "--modules",
        help="Comma-separated list of modules to run (e.g., 'BasicPropertiesExtractor,HashExtractor') or 'all' for all modules",
        default="all",
    )

    parser.add_argument(
        "--decompile-modules",
        help="Comma-separated list of decompiler sub-modules to run when using -d/--decompile. "
             "Available: decompilation, disassembly, cfg, llil, strings, or 'all' (default: all)",
        default="all",
    )
    
    parser.add_argument(
        "--force",
        action="store_true",
        help="Force reprocessing of samples already in the database (bypasses deduplication check)",
    )

    parser.add_argument(
        "--rerun",
        action="store_true",
        help="Re-run decompiler modules on already-disassembled samples only. "
             "Queries code_binja_disassembled_functions_references instead of basic_properties. "
             "Requires --analyzed and --decompile.",
    )

    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Print results instead of uploading to database (useful for testing)",
    )
    
    args = parser.parse_args()

    # Extract arguments
    path = args.path
    index_prefix = args.index_prefix
    decompile = args.decompile
    yara_scan = args.yara
    with_yara = args.with_yara
    repo = args.repo
    selected_modules = args.modules
    decompile_modules = args.decompile_modules
    s3_mode = args.s3
    s3_notes = args.s3_notes
    magika_filter = args.magika
    dry_run = args.dry_run
    force = args.force
    rerun = args.rerun
    s3_solo = args.s3_solo
    s3_key = args.s3_solo if args.s3_solo else None
    nomad_job = args.nomad_job
    analyzed = args.analyzed
    date_filter = args.date
    date_range = args.range

    # Validate that at least one input source is provided
    has_input = any([path, s3_mode, s3_solo, nomad_job, date_filter, date_range, analyzed])
    if not has_input:
        print("ERROR: Must specify an input source: --path, --s3, --s3-solo, --nomad-job, --date, --range, or --analyzed")
        sys.exit(1)

    # Validate --analyzed combinations
    if analyzed and any([path, s3_mode, s3_solo, nomad_job]):
        print("ERROR: --analyzed cannot be combined with --path, --s3, --s3-solo, or --nomad-job")
        sys.exit(1)

    # Validate flag combinations
    if yara_scan and with_yara:
        print("ERROR: Cannot use both --yara and --with-yara")
        sys.exit(1)
    if decompile and with_yara:
        print("ERROR: --with-yara only works with feature extraction, not decompile")
        sys.exit(1)

    # Parse and validate --decompile-modules
    VALID_DECOMPILE_MODULES = {"all", "decompilation", "disassembly", "cfg", "llil", "strings"}
    if decompile_modules == "all":
        decompile_modules_set = {"all"}
    else:
        decompile_modules_set = {m.strip() for m in decompile_modules.split(",")}
        invalid = decompile_modules_set - VALID_DECOMPILE_MODULES
        if invalid:
            print(f"ERROR: Invalid decompile module(s): {', '.join(sorted(invalid))}")
            print(f"Available: {', '.join(sorted(VALID_DECOMPILE_MODULES - {'all'}))}")
            sys.exit(1)

    if not decompile and decompile_modules != "all":
        print("ERROR: --decompile-modules requires -d/--decompile flag")
        sys.exit(1)

    if rerun and not analyzed:
        print("ERROR: --rerun requires --analyzed flag")
        sys.exit(1)
    if rerun and not decompile:
        print("ERROR: --rerun requires -d/--decompile flag")
        sys.exit(1)

    if rerun and force:
        print("ERROR: --rerun and --force are mutually exclusive. "
              "--rerun targets already-disassembled samples, --force targets all analyzed samples.")
        sys.exit(1)

    # Validate and parse date arguments
    start_date = None
    end_date = None

    if date_filter:
        # Single date mode: process samples from that day
        try:
            parsed_date = datetime.strptime(date_filter, "%Y-%m-%d")
            start_date = date_filter
            # End date is the next day (exclusive)
            end_date = (parsed_date + timedelta(days=1)).strftime("%Y-%m-%d")
        except ValueError:
            print(f"ERROR: Invalid date format '{date_filter}'. Use YYYY-MM-DD")
            sys.exit(1)

    if date_range:
        # Date range mode: process samples between start and end dates
        try:
            start_date = date_range[0]
            datetime.strptime(start_date, "%Y-%m-%d")  # Validate format
            parsed_end = datetime.strptime(date_range[1], "%Y-%m-%d")
            # End date is the day after the provided end date (to make it inclusive)
            end_date = (parsed_end + timedelta(days=1)).strftime("%Y-%m-%d")
        except ValueError:
            print(f"ERROR: Invalid date format in range '{date_range}'. Use YYYY-MM-DD YYYY-MM-DD")
            sys.exit(1)

    # Validate required parameters based on mode
    if nomad_job or s3_solo:
        # For nomad job and s3-solo modes, set default repo if not provided (used for log filename)
        if not repo:
            repo = "s3-solo" if s3_solo else "nomad-worker"
    elif analyzed:
        # For analyzed mode, repo is optional (used for logging only)
        if not repo:
            repo = "analyzed"
    elif date_filter or date_range:
        # For date/range modes, repo is optional (used for filtering within date range)
        # Set a default repo name for logging if not provided
        if not repo:
            repo = "date-range"
    elif s3_mode and magika_filter and not repo:
        # For S3 mode with magika filter, repo is optional (query all repos for that filetype)
        repo = "all-repos"
    elif not s3_mode and path:
        # For local mode, repo is required
        if not repo:
            print("ERROR: --repo is required for local mode")
            sys.exit(1)
    elif s3_mode and not repo:
        # For S3 mode without magika filter, repo is required
        print("ERROR: --repo is required for S3 catalog mode (or use --magika to query all repos)")
        sys.exit(1)

    print(f"Decompile flag: {decompile}")
    if decompile and decompile_modules != "all":
        print(f"Decompile modules: {', '.join(sorted(decompile_modules_set))}")
    print(f"YARA scan flag: {yara_scan}")
    print(f"With YARA flag: {with_yara}")
    print(f"Repo: {repo}")
    print(f"Selected modules: {selected_modules}")
    print(f"Dry run mode: {dry_run}")
    print(f"Force reprocessing: {force}")
    print(f"S3 solo mode: {s3_solo}")
    print(f"Nomad job mode: {nomad_job}")
    if magika_filter:
        print(f"Magika filter: {magika_filter}")
    if start_date:
        print(f"Date filter: {start_date} to {end_date}")
    if rerun:
        print(f"Rerun mode: targeting already-disassembled samples from code_binja_disassembled_functions_references")
    if analyzed:
        print(f"Analyzed mode: processing already-analyzed samples from basic_properties")

    if analyzed and not (date_filter or date_range):
        # Analyzed mode (standalone): process samples already in basic_properties via S3
        print(f"Processing already-analyzed samples from {index_prefix}_basic_properties")
        if magika_filter:
            print(f"Filetype filter: {magika_filter}")
        Ingestor(
            path=None,
            decompile=decompile,
            yara_scan=yara_scan,
            with_yara=with_yara,
            repository=repo or "analyzed",
            index_prefix=index_prefix,
            selected_modules=selected_modules,
            s3_mode=True,
            magika_filter=magika_filter,
            dry_run=dry_run,
            force=force,
            analyzed=True,
            decompile_modules=decompile_modules_set,
            rerun=rerun,
        ).ingest()

    elif date_filter or date_range:
        # Date-based S3 mode
        print(f"Date-based S3 mode enabled")
        if analyzed:
            print(f"Filtered to already-analyzed samples in {index_prefix}_basic_properties")
        if repo and repo != "date-range":
            print(f"Repository filter: {repo}")
        if s3_notes:
            print(f"Notes filter: {s3_notes}")
        Ingestor(
            path=None,
            decompile=decompile,
            yara_scan=yara_scan,
            with_yara=with_yara,
            repository=repo,
            index_prefix=index_prefix,
            selected_modules=selected_modules,
            s3_mode=True,
            s3_notes=s3_notes,
            magika_filter=magika_filter,
            dry_run=dry_run,
            force=force,
            start_date=start_date,
            end_date=end_date,
            analyzed=analyzed,
            decompile_modules=decompile_modules_set,
        ).ingest()

    elif s3_solo:
        # Process a single S3 file using S3 key provided as argument
        print(f"Starting S3 solo mode with S3 key: {s3_key}")

        # Override with environment variables if not provided via command line
        if not index_prefix:
            index_prefix = os.getenv('INDEX_PREFIX', 'redb')
        if not repo:
            repo = os.getenv('REPO', 's3-solo')

        # Validate required parameters
        if not s3_key:
            print("ERROR: S3 key is required for S3-solo mode")
            sys.exit(1)

        # Extract hash from S3 key by splitting and taking the last chunk
        # S3 key format examples:
        # - 09/f7/09f7d02a3c2382199458c98a62b045145ee54ab6aba86166aecf3d10c3c1444c.zip
        # - private/ab/cd/abcd1234567890abcdef1234567890abcdef1234567890abcdef123456.zip
        try:
            # Remove .zip extension and split by '/'
            sample_hash = s3_key.replace('.zip', '').split('/')[-1]
        except Exception as e:
            print(f"ERROR: Failed to extract hash from S3 key {s3_key}: {e}")
            sys.exit(1)

        print(f"S3 Key: {s3_key}")
        print(f"Extracted hash: {sample_hash}")
        print(f"Using index_prefix: {index_prefix}")
        print(f"Using repo: {repo}")
        print(f"Dry run mode: {dry_run}")
        print(f"Selected modules: {selected_modules}")

        # Use ingestor with S3-solo mode
        Ingestor(
            path=None,
            decompile=decompile,
            yara_scan=yara_scan,
            with_yara=with_yara,
            repository=repo,
            index_prefix=index_prefix or "s3_solo",
            selected_modules=selected_modules,
            s3_mode=True,
            s3_solo=True,
            s3_solo_hash=sample_hash,
            s3_solo_key=s3_key,
            dry_run=dry_run,
            force=force,
            decompile_modules=decompile_modules_set,
        ).ingest()

    elif nomad_job:
        # Run as Nomad job using environment variables - convert to S3-solo mode
        print("Starting Nomad job processor...")
        
        # Process Nomad environment variables
        job_id = os.getenv('JOB_ID')
        s3_key = os.getenv('S3_KEY')
        worker_type = os.getenv('WORKER_TYPE')
        callback_url = os.getenv('CALLBACK_URL')
        modules = os.getenv('ANALYSIS_MODULES', 'all')
        
        # Validate required parameters
        if not all([job_id, s3_key, worker_type, callback_url]):
            print("ERROR: Missing required Nomad job parameters")
            print("Required: JOB_ID, S3_KEY, WORKER_TYPE, CALLBACK_URL")
            sys.exit(1)
        
        print(f"Job ID: {job_id}")
        print(f"S3 Key: {s3_key}")
        print(f"Worker Type: {worker_type}")
        print(f"Callback URL: {callback_url}")
        print(f"Analysis Modules: {modules}")
        
        # Extract hash from S3 key (remove sharding structure and .zip extension)
        # S3 key format: 09/f7/09f7d02a3c2382199458c98a62b045145ee54ab6aba86166aecf3d10c3c1444c.zip
        # Extract: 09f7d02a3c2382199458c98a62b045145ee54ab6aba86166aecf3d10c3c1444c
        try:
            parts = s3_key.split('/')
            if len(parts) == 3:
                sample_hash = parts[2].replace('.zip', '')
            else:
                # Fallback for non-sharded keys
                sample_hash = s3_key.replace('.zip', '')
        except Exception as e:
            print(f"ERROR: Failed to extract hash from S3 key {s3_key}: {e}")
            sys.exit(1)
        
        print(f"Extracted hash: {sample_hash}")
        
        # Set decompile flag based on worker type
        decompile = worker_type == 'decompilation'
        
        # Override modules if specified
        if modules != 'all':
            selected_modules = modules
        
        # Use S3-solo mode with extracted hash
        Ingestor(
            path=None,
            decompile=decompile,
            yara_scan=yara_scan,
            with_yara=with_yara,
            repository=repo,
            index_prefix=index_prefix or "nomad",
            selected_modules=selected_modules,
            s3_mode=False,  # Not bulk S3 mode
            s3_solo=True,   # Use S3-solo mode
            s3_solo_hash=sample_hash,
            dry_run=dry_run,
            force=force,
            decompile_modules=decompile_modules_set,
        ).ingest()

        # TODO: Add callback to send results to callback_url
        print(f"[INFO] Nomad job {job_id} completed. Callback URL: {callback_url}")
    
    elif s3_mode:
        print(f"S3 mode enabled")
        if s3_notes:
            print(f"S3 notes filter: {s3_notes}")
        Ingestor(
            path=None,
            decompile=decompile,
            yara_scan=yara_scan,
            with_yara=with_yara,
            repository=repo,
            index_prefix=index_prefix,
            selected_modules=selected_modules,
            s3_mode=True,
            s3_notes=s3_notes,
            magika_filter=magika_filter,
            dry_run=dry_run,
            force=force,
            decompile_modules=decompile_modules_set,
        ).ingest()
    else:
        print(f"Local mode with path: {path}")
        if path.endswith('.txt'):
            print(f"Reading file list from: {path}")

        Ingestor(
            path=path,
            decompile=decompile,
            yara_scan=yara_scan,
            with_yara=with_yara,
            repository=repo,
            index_prefix=index_prefix,
            selected_modules=selected_modules,
            dry_run=dry_run,
            force=force,
            decompile_modules=decompile_modules_set,
        ).ingest()

if __name__ == "__main__":
    main()