Valentina Presutti

222 papers A* 3A 3B 21C 3Misc 6Journal 64Unranked 90
YearRankTypeTitle / Venue / Authors
2026 J jnl
Knowl. Inf. Syst.
Aldo Gangemi, Arianna Graciotti, Antonello Meloni, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero, Alessandro Russo
2026 ed.
ESWC (Satellite Events)
Edward Curry, Valentina Presutti, John P. McCrae, Mehwish Alam, Pieter Colpaert, Josiane Xavier Parreira, Diego Collarana, Marta Sabou, Andreas Harth, Pasquale Lisena
2026 J jnl
CoRR
Nicolas Lazzari, Valentina Presutti, Antonio Vergari
2025 J jnl
CoRR
Anna Sofia Lippolis, Minh Davide Ragagni, Paolo Ciancarini, Andrea Giovanni Nuzzolese, Valentina Presutti
2025 conf
IC3K
Valentina Presutti
2025 ed.
EKAW (Companion)
Carlos Badenes-Olmedo, Inna Novalija, Enrico Daga, Lise Stork, Reshmi Gopalakrishna Pillai, Laurence Dierickx, Benno Kruit, Victoria Degeler, João Moreira, Bohui Zhang, Reham Alharbi, Yuan He, Arianna Graciotti, Alba Catalina Morales Tirado, Valentina Presutti, Enrico Motta
2025 conf
ACL (Findings)
Arianna Graciotti, Leonardo Piano, Nicolas Lazzari, Enrico Daga, Rocco Tripodi, Valentina Presutti, Livio Pompianu
2025 J jnl
CoRR
Arianna Graciotti, Nicolas Lazzari, Valentina Presutti, Rocco Tripodi
2025 J jnl
Artif. Intell. Rev.
Arianna Graciotti, Nicolas Lazzari, Valentina Presutti, Rocco Tripodi
2025 conf
SemDH
Jose Maldonado-Rodríguez, Arianna Graciotti, Valentina Presutti, Federico Pianzola
2025 J jnl
CoRR
Raia Abu Ahmad, Reham Alharbi, Roberto Barile, Martin Böckling, Francisco Bolanos, Sara Bonfitto, Oleksandra Bruns, Irene Celino, Yashrajsinh Chudasama, Martin Critelli, Claudia d'Amato, Giada D'Ippolito, Ioannis Dasoulas, Stefano De Giorgis, Vincenzo De Leo, Chiara Di Bonaventura, Marco Di Panfilo, Daniil Dobriy, John Domingue, Xuemin Duan, Michel Dumontier, Sefika Efeoglu, Ruben Eschauzier, Ginwa Fakih, Nicolas Ferranti, Arianna Graciotti, Philipp Hanisch, George Hannah, Golsa Heidari, Aidan Hogan, Hassan Hussein, Alexane Jouglar, Jan-Christoph Kalo, Manoé Kieffer, Antonis Klironomos, Inês Koch, Weronika Lajewska, Nicolas Lazzari, Mikael Lindekrans, Anna Sofia Lippolis, Majlinda Llugiqi, Eleonora Mancini, Eleonora Marzi, Laura Menotti, Daniela F. Milon-Flores, Soulakshmee D. Nagowah, Kerstin Neubert, Emetis Niazmand, Ebrahim Norouzi, Beatriz Olarte Martinez, Anouk Michelle Oudshoorn, Andrea Poltronieri, Valentina Presutti, Disha Purohit, Ensiyeh Raoufi, Célian Ringwald, Johanna Rockstroh, Sebastian Rudolph, Harald Sack, Zafar Saeed, Mohammad Javad Saeedizade, Aya Sahbi, Cristian Santini, Aleksandra Simic, Dennis Sommer, Rita T. Sousa, Mary Ann Tan, Vidyashree Tarikere, Tabea Tietz, Liam Tirpitz, Arnaldo Tomasino, Frank van Harmelen, Joao Vissoci, Caitlin Woods, Bohui Zhang, Xinyue Zhang, Heng Zheng
2025 ed.
ESWC Satellite Events (1)
Albert Meroño-Peñuela, Óscar Corcho, Paul Groth, Elena Simperl, Valentina Tamma, Andrea Giovanni Nuzzolese, María Poveda-Villalón, Marta Sabou, Valentina Presutti, Irene Celino, Artem Revenko, Joe Raad, Bruno Sartini, Pasquale Lisena
2025 ed.
ESWC Satellite Events (2)
Albert Meroño-Peñuela, Óscar Corcho, Paul Groth, Elena Simperl, Valentina Tamma, Andrea Giovanni Nuzzolese, María Poveda-Villalón, Marta Sabou, Valentina Presutti, Irene Celino, Artem Revenko, Joe Raad, Bruno Sartini, Pasquale Lisena
2025 conf
CLiC-it
Marco Cuccarini, Lia Draetta, Beatrice Fiumanò, Stefano Bistarelli, Rossana Damiano, Valentina Presutti
2025 conf
ESWC (2)
Aldo Gangemi, Arianna Graciotti, Antonello Meloni, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero, Alessandro Russo
2024 J jnl
Comput. Hum. Behav.
Fiorela Ciroku, Stefano De Giorgis, Aldo Gangemi, Delfina Sol Martinez Pandiani, Valentina Presutti
2024 J jnl
CoRR
Andrea Poltronieri, Valentina Presutti, Martín Rocamora
2024 conf
EKAW (Companion)
Nicolas Lazzari, Arianna Graciotti, Valentina Presutti
2024 J jnl
Intelligenza Artificiale
Francesco Alfieri, Luigi Asprino, Nicolas Lazzari, Valentina Presutti
2024 J jnl
Semantic Web
Valentina Anita Carriero, Paul Groth, Valentina Presutti
2024 conf
ESWC Satellite Events (2)
Nicolas Lazzari, Stefano De Giorgis, Aldo Gangemi, Valentina Presutti
2024 J jnl
CoRR
Nicolas Lazzari, Stefano De Giorgis, Aldo Gangemi, Valentina Presutti
2024 conf
LREC/COLING
Arianna Graciotti, Valentina Presutti, Rocco Tripodi
2024 conf
ESWC Satellite Events (1)
Aldo Gangemi, Arianna Graciotti, Antonello Meloni, Eleonora Marzi, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero, Alessandro Russo, Rocco Tripodi
2024 ed.
CREAI@ECAI
Allegra De Filippo, François Pachet, Valentina Presutti, Luc Steels
2024 J jnl
J. Web Semant.
Fiorela Ciroku, Jacopo de Berardinis, Jongmo Kim, Albert Meroño-Peñuela, Valentina Presutti, Elena Simperl
2024 J jnl
CoRR
Nicolas Lazzari, Stefano De Giorgis, Aldo Gangemi, Valentina Presutti
2024 J jnl
CoRR
Delfina Sol Martinez Pandiani, Valentina Presutti
2024 Misc conf
SEMANTICS
Delfina Sol Martinez Pandiani, Nicolas Lazzari, Valentina Presutti
2024 J jnl
CoRR
Delfina Sol Martinez Pandiani, Nicolas Lazzari, Valentina Presutti
2024 conf
CREAI@ECAI
Nicolas Lazzari, Valentina Presutti
2023 conf
WWW (Companion Volume)
Marieke van Erp, Raphaël Troncy, Valentina Presutti, Albert Meroño-Peñuela, Sara Tonelli, Enrico Daga
2023 conf
ICAART
Valentina Presutti
2023 B conf
ESWC
Nicolas Lazzari, Andrea Poltronieri, Valentina Presutti
2023 J jnl
CoRR
Nicolas Lazzari, Andrea Poltronieri, Valentina Presutti
2023 conf
CREAI@AI*IA
Francesco Alfieri, Luigi Asprino, Nicolas Lazzari, Valentina Presutti
2023 conf
HT
Giulia Renda, Marilena Daquino, Valentina Presutti
2023 J jnl
CoRR
Giulia Renda, Marilena Daquino, Valentina Presutti
2023 J jnl
IEEE Access
Luigi Asprino, Valentina Presutti
2023 J jnl
CoRR
Nicolas Lazzari, Andrea Poltronieri, Valentina Presutti
2023 ed.
CREAI@AI*IA
Allegra De Filippo, Michela Milano, Valentina Presutti, Alessandro Saffiotti
2023 J jnl
CoRR
Delfina Sol Martinez Pandiani, Valentina Presutti
2023 conf
ISWC (Posters/Demos/Industry)
Aldo Gangemi, Arianna Graciotti, Antonello Meloni, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero, Alessandro Russo, Rocco Tripodi
2023 A* conf
WWW
Jacopo de Berardinis, Albert Meroño-Peñuela, Andrea Poltronieri, Valentina Presutti
2023 J jnl
CoRR
Jacopo de Berardinis, Albert Meroño-Peñuela, Andrea Poltronieri, Valentina Presutti
2023 conf
ISMIR
Jacopo de Berardinis, Valentina Anita Carriero, Albert Meroño-Peñuela, Andrea Poltronieri, Valentina Presutti
2023 J jnl
CoRR
Jacopo de Berardinis, Valentina Anita Carriero, Albert Meroño-Peñuela, Andrea Poltronieri, Valentina Presutti
2023 Misc conf
ISWC
Jacopo de Berardinis, Valentina Anita Carriero, Nitisha Jain, Nicolas Lazzari, Albert Meroño-Peñuela, Andrea Poltronieri, Valentina Presutti
2023 Misc ed.
ISWC
Terry R. Payne, Valentina Presutti, Guilin Qi, María Poveda-Villalón, Giorgos Stoilos, Laura Hollink, Zoi Kaoudi, Gong Cheng, Juanzi Li
2023 Misc ed.
ISWC
Terry R. Payne, Valentina Presutti, Guilin Qi, María Poveda-Villalón, Giorgos Stoilos, Laura Hollink, Zoi Kaoudi, Gong Cheng, Juanzi Li
2023 J jnl
ACM Trans. Multim. Comput. Commun. Appl.
Federico Becattini, Pietro Bongini, Luana Bulla, Alberto Del Bimbo, Ludovica Marinucci, Misael Mongiovì, Valentina Presutti
2022 J jnl
J. Web Semant.
Luigi Asprino, Paolo Ciancarini, Andrea Giovanni Nuzzolese, Valentina Presutti, Alessandro Russo
2022 J jnl
XRDS
Matthew Studley, Valentina Presutti, Daniele Nardi, Sarah Carter
2022 conf
ADBIS (Short Papers)
Luana Bulla, Maria Chiara Frangipane, Maria Letizia Mancinelli, Ludovica Marinucci, Misael Mongiovì, Margherita Porena, Valentina Presutti, Chiara Veninata
2022 B conf
RO-MAN
Emanuele Antonioni, Cristiana Sanalitro, Olga Capirci, Alessio Di Renzo, Maria Beatrice D'Aversa, Domenico Bloisi, Lun Wang, Ermanno Bartoli, Lorenzo Diaco, Valentina Presutti, Daniele Nardi
2022 conf
CREAI@AI*IA
Nicolas Lazzari, Andrea Poltronieri, Valentina Presutti
2022 ed.
CREAI@AI*IA
Allegra De Filippo, Michela Milano, Valentina Presutti, Alessandro Saffiotti
2022 conf
TEXT2KG/MK@ESWC
Fiorela Ciroku, Valentina Presutti
2022 conf
WOP@ISWC
Jacopo de Berardinis, Albert Meroño-Peñuela, Andrea Poltronieri, Valentina Presutti
2022 Misc ed.
ISWC
Ulrike Sattler, Aidan Hogan, C. Maria Keet, Valentina Presutti, João Paulo A. Almeida, Hideaki Takeda, Pierre Monnin, Giuseppe Pirrò, Claudia d'Amato
2022 conf
Wikidata@ISWC
Valentina Anita Carriero, Paul Groth, Valentina Presutti
2021 conf
LOD
Luigi Asprino, Luana Bulla, Ludovica Marinucci, Misael Mongiovì, Valentina Presutti
2021 conf
WOP (Book)
Valentina Anita Carriero, Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti
2021 J jnl
CoRR
Valentina Anita Carriero, Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti
2021 J jnl
CoRR
Delfina Sol Martinez Pandiani, Valentina Presutti
2021 B conf
K-CAP
Luigi Asprino, Valentina Anita Carriero, Valentina Presutti
2021 J jnl
CoRR
Luigi Asprino, Valentina Anita Carriero, Valentina Presutti
2021 conf
WOP@ISWC
Luigi Asprino, Valentina Anita Carriero, Christian Colonna, Valentina Presutti
2021 J jnl
CoRR
Luigi Asprino, Christian Colonna, Misael Mongiovì, Margherita Porena, Valentina Presutti
2021 J jnl
Semantic Web
Valentina Anita Carriero, Aldo Gangemi, Maria Letizia Mancinelli, Andrea Giovanni Nuzzolese, Valentina Presutti, Chiara Veninata
2021 J jnl
Prog. Artif. Intell.
Mehwish Alam, Aldo Gangemi, Valentina Presutti, Diego Reforgiato Recupero
2021 J jnl
Scientometrics
Erik Boetto, Maria Pia Fantini, Aldo Gangemi, Davide Golinelli, Manfredi Greco, Andrea Giovanni Nuzzolese, Valentina Presutti, Flavia Rallo
2020 J jnl
CoRR
Luigi Asprino, Paolo Ciancarini, Andrea Giovanni Nuzzolese, Valentina Presutti, Alessandro Russo
2020 J jnl
CoRR
Nacira Abbas, Kholoud Alghamdi, Mortaza Alinam, Francesca Alloatti, Glenda C. M. Amaral, Claudia d'Amato, Luigi Asprino, Martin Beno, Felix Bensmann, Russa Biswas, Ling Cai, Riley Capshaw, Valentina Anita Carriero, Irene Celino, Amine Dadoun, Stefano De Giorgis, Harm Delva, John Domingue, Michel Dumontier, Vincent Emonet, Marieke van Erp, Paola Espinoza-Arias, Omaima Fallatah, Sebastián Ferrada, Marc Gallofré Ocaña, Michalis Georgiou, Genet Asefa Gesese, Frances Gillis-Webber, Francesca Giovannetti, María Granados Buey, Ismail Harrando, Ivan Heibi, Vitor A. C. Horta, Laurine Huber, Federico Igne, Mohamad Yaser Jaradeh, Neha Keshan, Aneta Koleva, Bilal Koteich, Kabul Kurniawan, Mengya Liu, Chuangtao Ma, Lientje Maas, Martin Mansfield, Fabio Mariani, Eleonora Marzi, Sepideh Mesbah, Maheshkumar Mistry, Alba Catalina Morales Tirado, Anna Nguyen, Viet Bach Nguyen, Allard Oelen, Valentina Pasqual, Heiko Paulheim, Axel Polleres, Margherita Porena, Jan Portisch, Valentina Presutti, Kader Pustu-Iren, Ariam Rivas Mendez, Soheil Roshankish, Sebastian Rudolph, Harald Sack, Ahmad Sakor, Jaime Salas, Thomas Schleider, Meilin Shi, Gianmarco Spinaci, Chang Sun, Tabea Tietz, Molka Tounsi Dhouib, Alessandro Umbrico, Wouter van den Berg, Weiqin Xu
2020 ed.
SBD@SIGMOD
Sven Groppe, Le Gruenwald, Valentina Presutti
2020 J jnl
Semantic Web
Paolo Ciancarini, Andrea Giovanni Nuzzolese, Valentina Presutti, Daniel Russo
2020 J jnl
CoRR
Valentina Anita Carriero, Marilena Daquino, Aldo Gangemi, Andrea Giovanni Nuzzolese, Silvio Peroni, Valentina Presutti, Francesca Tomasi
2020 ch.
Applications and Practices in Ontology Design, Extraction, and Reasoning
Valentina Anita Carriero, Marilena Daquino, Aldo Gangemi, Andrea Giovanni Nuzzolese, Silvio Peroni, Valentina Presutti, Francesca Tomasi
2020 ed.
ESWC (Satellite Events)
Andreas Harth, Valentina Presutti, Raphaël Troncy, Maribel Acosta, Axel Polleres, Javier D. Fernández, Josiane Xavier Parreira, Olaf Hartig, Katja Hose, Michael Cochez
2020 J jnl
Scientometrics
Silvio Peroni, Paolo Ciancarini, Aldo Gangemi, Andrea Giovanni Nuzzolese, Francesco Poggi, Valentina Presutti
2020 J jnl
CoRR
Erik Boetto, Maria Pia Fantini, Aldo Gangemi, Davide Golinelli, Manfredi Greco, Andrea Giovanni Nuzzolese, Valentina Presutti, Flavia Rallo
2019 conf
ISWC (Satellites)
Valentina Anita Carriero, Fabio Mariani, Andrea Giovanni Nuzzolese, Valentina Pasqual, Valentina Presutti
2019 conf
WOP@ISWC
Valentina Anita Carriero, Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti
2019 conf
ODOCH@CAiSE
Valentina Anita Carriero, Aldo Gangemi, Maria Letizia Mancinelli, Ludovica Marinucci, Andrea Giovanni Nuzzolese, Valentina Presutti, Chiara Veninata
2019 conf
ISWC (2)
Valentina Anita Carriero, Aldo Gangemi, Maria Letizia Mancinelli, Ludovica Marinucci, Andrea Giovanni Nuzzolese, Valentina Presutti, Chiara Veninata
2019 J jnl
CoRR
Valentina Anita Carriero, Aldo Gangemi, Maria Letizia Mancinelli, Ludovica Marinucci, Andrea Giovanni Nuzzolese, Valentina Presutti, Chiara Veninata
2019 conf
ISWC (Satellites)
Luigi Asprino, Valentina Anita Carriero, Aldo Gangemi, Ludovica Marinucci, Andrea Giovanni Nuzzolese, Valentina Presutti
2019 J jnl
Scientometrics
Andrea Giovanni Nuzzolese, Paolo Ciancarini, Aldo Gangemi, Silvio Peroni, Francesco Poggi, Valentina Presutti
2019 J jnl
CoRR
Tayeb Abderrahmani Ghor, Esha Agrawal, Mehwish Alam, Omar Alqawasmeh, Claudia d'Amato, Amina Annane, Amr Azzam, Andrew Berezovskyi, Russa Biswas, Mathias Bonduel, Quentin Brabant, Cristina-Iulia Bucur, Elena Camossi, Valentina Anita Carriero, Shruthi Chari, David Chaves-Fraga, Fiorela Ciroku, Michael Cochez, Hubert Curien, Vincenzo Cutrona, Rahma Dandan, Danilo Dessì, Valerio Di Carlo, Ahmed El Amine Djebri, Marieke van Erp, Faiq Miftakhul Falakh, Alba Fernndez Izquierdo, Giuseppe Futia, Aldo Gangemi, Simone Gasperoni, Arnaud Grall, Lars Heling, Pierre Henri, Noura Herradi, Subhi Issa, Samaneh Jozashoori, Nyoman Juniarta, Lucie-Aimée Kaffee, Ilkcan Keles, Prashant Khare, Viktor Kovtun, Valentina Leone, Siying Li, Sven Lieber, Pasquale Lisena, Tatiana Makhalova, Ludovica Marinucci, Thomas Minier, Benjamin Moreau, Alberto Moya Loustaunau, Durgesh Nandini, Sylwia Ozdowska, Amanda Pacini de Moura, Swati Padhee, Guillermo Palma, Pedro Del Pozo Jimnez, Valentina Presutti, Roberto Reda, Ettore Rizza, Henry Rosales-Méndez, Sebastian Rudolph, Harald Sack, Luca Sciullo, Humasak Simanjuntak, Carlo Stomeo, Thiviyan Thanapalasingam, Tabea Tietz, Dalia Varanka, Maria-Esther Vidal, Michael Wolowyk, Maximilian Zocholl
2019 conf
ISWC (1)
Luigi Asprino, Wouter Beek, Paolo Ciancarini, Frank van Harmelen, Valentina Presutti
2019 ch.
Data Science for Healthcare
Luigi Asprino, Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero, Alessandro Russo
2019 J jnl
CoRR
Valentina Anita Carriero, Aldo Gangemi, Maria Letizia Mancinelli, Andrea Giovanni Nuzzolese, Valentina Presutti, Chiara Veninata
2019 J jnl
PeerJ Comput. Sci.
Francesco Poggi, Paolo Ciancarini, Aldo Gangemi, Andrea Giovanni Nuzzolese, Silvio Peroni, Valentina Presutti
2019 J jnl
PeerJ Prepr.
Francesco Poggi, Paolo Ciancarini, Aldo Gangemi, Andrea Giovanni Nuzzolese, Silvio Peroni, Valentina Presutti
2019 J jnl
CoRR
Paolo Ciancarini, Andrea Giovanni Nuzzolese, Valentina Presutti, Daniel Russo
2019 J jnl
CoRR
Luigi Asprino, Wouter Beek, Paolo Ciancarini, Frank van Harmelen, Valentina Presutti
2019 J jnl
CoRR
Silvio Peroni, Paolo Ciancarini, Aldo Gangemi, Andrea Giovanni Nuzzolese, Francesco Poggi, Valentina Presutti
2019 conf
ISWC (Satellites)
Luigi Asprino, Wouter Beek, Paolo Ciancarini, Frank van Harmelen, Valentina Presutti
2018 C conf
FOIS
Aldo Gangemi, Mehwish Alam, Valentina Presutti
2018 J jnl
CoRR
Aldo Gangemi, Mehwish Alam, Valentina Presutti
2018 J jnl
CoRR
Andrea Giovanni Nuzzolese, Paolo Ciancarini, Aldo Gangemi, Silvio Peroni, Francesco Poggi, Valentina Presutti
2018 A* conf
IJCAI
Luigi Asprino, Valerio Basile, Paolo Ciancarini, Valentina Presutti
2018 J jnl
CoRR
Luigi Asprino, Valerio Basile, Paolo Ciancarini, Valentina Presutti
2018 conf
SAVE-SD@WWW
Andrea Giovanni Nuzzolese, Valentina Presutti, Aldo Gangemi, Paolo Ciancarini
2018 J jnl
Dagstuhl Reports
Piero Andrea Bonatti, Stefan Decker, Axel Polleres, Valentina Presutti
2018 conf
ISWC (P&D/Industry/BlueSky)
Aldo Gangemi, Mehwish Alam, Valentina Presutti
2018 conf
ForItAAL
Grazia D'Onofrio, Daniele Sancarlo, Massimiliano Raciti, Alessandro Russo, Francesco Ricciardi, Valentina Presutti, Thomas Messervey, Filippo Cavallo, Francesco Giuliani, Antonio Greco
2018 ed.
SWAT4LS
Adrian Paschke, Albert Burger, Andrea Splendiani, M. Scott Marshall, Paolo Romano, Valentina Presutti
2018 J jnl
CoRR
Mehwish Alam, Aldo Gangemi, Valentina Presutti, Diego Reforgiato Recupero
2018 ed.
ISWC (1)
Denny Vrandecic, Kalina Bontcheva, Mari Carmen Suárez-Figueroa, Valentina Presutti, Irene Celino, Marta Sabou, Lucie-Aimée Kaffee, Elena Simperl
2018 ed.
ISWC (2)
Denny Vrandecic, Kalina Bontcheva, Mari Carmen Suárez-Figueroa, Valentina Presutti, Irene Celino, Marta Sabou, Lucie-Aimée Kaffee, Elena Simperl
2017 conf
AnSWeR@ESWC
Luigi Asprino, Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti, Alessandro Russo
2017 conf
WOP@ISWC
Aldo Gangemi, Raffaele Lillo, Giorgia Lodi, Andrea Giovanni Nuzzolese, Valentina Presutti
2017 J jnl
Semantic Web
Andrea Giovanni Nuzzolese, Valentina Presutti, Aldo Gangemi, Silvio Peroni, Paolo Ciancarini
2017 conf
AnSWeR@ESWC
Luigi Asprino, Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero, Alessandro Russo
2017 conf
ISWC (Posters, Demos & Industry Tracks)
Diego Reforgiato Recupero, Mehwish Alam, Aldo Gangemi, Valentina Presutti
2017 A* conf
AAAI
Luigi Asprino, Valentina Presutti, Aldo Gangemi, Paolo Ciancarini
2017 ed.
EKAW (Satellite Events)
Paolo Ciancarini, Francesco Poggi, Matthew Horridge, Jun Zhao, Tudor Groza, Mari Carmen Suárez-Figueroa, Mathieu d'Aquin, Valentina Presutti
2017 conf
AnSWeR@ESWC
Luigi Asprino, Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti, Alessandro Russo
2017 conf
ForItAAL
Grazia D'Onofrio, Daniele Sancarlo, Massimiliano Raciti, Diego Reforgiato Recupero, Antonio Mangiacotti, Alessandro Russo, Francesco Ricciardi, Alessandra Vitanza, Filippo Cantucci, Valentina Presutti, Thomas Messervey, Stefano Nolfi, Filippo Cavallo, Eva Barrett, Sally Whelan, Dympna Casey, Francesco Giuliani, Antonio Greco
2017 J jnl
Big Data Res.
Sergio Consoli, Valentina Presutti, Diego Reforgiato Recupero, Andrea Giovanni Nuzzolese, Silvio Peroni, Misael Mongiovì, Aldo Gangemi
2017 J jnl
Semantic Web
Aldo Gangemi, Valentina Presutti, Diego Reforgiato Recupero, Andrea Giovanni Nuzzolese, Francesco Draicchio, Misael Mongiovì
2017 conf
WOP@ISWC
Pascal Hitzler, Aldo Gangemi, Krzysztof Janowicz, Adila Alfa Krisnadhi, Valentina Presutti
2016 C conf
FOIS
Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero
2016 J jnl
CoRR
Diego Reforgiato Recupero, Mario Castronovo, Sergio Consoli, Tarcisio Costanzo, Aldo Gangemi, Luigi Grasso, Giorgia Lodi, Gianluca Merendino, Misael Mongiovì, Valentina Presutti, Salvatore Davide Rapisarda, Salvo Rosa, Emanuele Spampinato
2016 conf
WOP@ISWC
Luigi Asprino, Andrea Giovanni Nuzzolese, Alessandro Russo, Aldo Gangemi, Valentina Presutti, Stefano Nolfi
2016 conf
ISWC (2)
Andrea Giovanni Nuzzolese, Anna Lisa Gentile, Valentina Presutti, Aldo Gangemi
2016 ch.
Ontology Engineering with Ontology Design Patterns
Valentina Presutti, Aldo Gangemi
2016 ch.
Ontology Engineering with Ontology Design Patterns
Eva Blomqvist, Karl Hammar, Valentina Presutti
2016 conf
ISWC (2)
Silvio Peroni, Giorgia Lodi, Luigi Asprino, Aldo Gangemi, Valentina Presutti
2016 B conf
EKAW
Aldo Gangemi, Mehwish Alam, Luigi Asprino, Valentina Presutti, Diego Reforgiato Recupero
2016 J jnl
Semantic Web
Valentina Presutti, Andrea Giovanni Nuzzolese, Sergio Consoli, Aldo Gangemi, Diego Reforgiato Recupero
2016 conf
ISWC (Posters & Demos)
Andrea Giovanni Nuzzolese, Anna Lisa Gentile, Valentina Presutti, Aldo Gangemi
2016 J jnl
Knowl. Based Syst.
Aldo Gangemi, Diego Reforgiato Recupero, Misael Mongiovì, Andrea Giovanni Nuzzolese, Valentina Presutti
2016 conf
EKAW (Satellite Events)
Luigi Asprino, Valentina Presutti, Aldo Gangemi
2016 J jnl
Knowl. Based Syst.
Misael Mongiovì, Diego Reforgiato Recupero, Aldo Gangemi, Valentina Presutti, Sergio Consoli
2016 ch.
Ontology Engineering with Ontology Design Patterns
Aldo Gangemi, Valentina Presutti
2016 book
Pascal Hitzler, Aldo Gangemi, Krzysztof Janowicz, Adila Krisnadhi, Valentina Presutti
2016 conf
ESWC (Satellite Events)
Andrea Giovanni Nuzzolese, Anna Lisa Gentile, Valentina Presutti, Aldo Gangemi
2016 conf
WOP@ISWC
Karl Hammar, Valentina Presutti
2016 A conf
ER
Valentina Presutti, Giorgia Lodi, Andrea Giovanni Nuzzolese, Aldo Gangemi, Silvio Peroni, Luigi Asprino
2016 conf
SemWebEval@ESWC
Andrea Giovanni Nuzzolese, Anna Lisa Gentile, Valentina Presutti, Aldo Gangemi, Robert Meusel, Heiko Paulheim
2016 conf
LD4IE@ISWC
Aldo Gangemi, Mehwish Alam, Valentina Presutti
2015 conf
WWW (Companion Volume)
Sergio Consoli, Misael Mongiovì, Andrea Giovanni Nuzzolese, Silvio Peroni, Valentina Presutti, Diego Reforgiato Recupero, Daria Spampinato
2015 conf
WWW (Companion Volume)
Sergio Consoli, Diego Reforgiato Recupero, Misael Mongiovì, Valentina Presutti, Gianni Cataldi, Wladimiro Patatu
2015 conf
WWW (Companion Volume)
Anna Lisa Gentile, Maribel Acosta, Luca Costabello, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero
2015 conf
SemWebEval@ESWC
Diego Reforgiato Recupero, Mauro Dragoni, Valentina Presutti
2015 conf
WWW (Companion Volume)
Diego Reforgiato Recupero, Andrea Giovanni Nuzzolese, Sergio Consoli, Valentina Presutti, Misael Mongiovì, Silvio Peroni
2015 ed.
EKAW (Satellite Events)
Patrick Lambrix, Eero Hyvönen, Eva Blomqvist, Valentina Presutti, Guilin Qi, Uli Sattler, Ying Ding, Chiara Ghidini
2015 conf
SemWebEval@ESWC
Andrea Giovanni Nuzzolese, Anna Lisa Gentile, Valentina Presutti, Aldo Gangemi, Darío Garigliotti, Roberto Navigli
2015 B conf
K-CAP
Misael Mongiovì, Diego Reforgiato Recupero, Aldo Gangemi, Valentina Presutti, Andrea Giovanni Nuzzolese, Sergio Consoli
2015 J jnl
Cogn. Comput.
Diego Reforgiato Recupero, Valentina Presutti, Sergio Consoli, Aldo Gangemi, Andrea Giovanni Nuzzolese
2014 J jnl
IEEE Comput. Intell. Mag.
Aldo Gangemi, Valentina Presutti, Diego Reforgiato Recupero
2014 conf
WOP
Valentina Presutti
2014 conf
WIMS
Sergio Consoli, Aldo Gangemi, Andrea Giovanni Nuzzolese, Silvio Peroni, Valentina Presutti, Diego Reforgiato Recupero, Daria Spampinato
2014 conf
EKAW (Satellite Events)
Sergio Consoli, Andrea Giovanni Nuzzolese, Valentina Presutti, Diego Reforgiato Recupero, Aldo Gangemi
2014 ed.
WOP
Aldo Gangemi, Michael Gruninger, Karl Hammar, Laurent Lefort, Valentina Presutti, Ansgar Scherp
2014 conf
EKAW (Satellite Events)
Diego Reforgiato Recupero, Andrea Giovanni Nuzzolese, Sergio Consoli, Aldo Gangemi, Valentina Presutti
2014 ed.
SemWebEval@ESWC
Valentina Presutti, Milan Stankovic, Erik Cambria, Iván Cantador, Angelo Di Iorio, Tommaso Di Noia, Christoph Lange, Diego Reforgiato Recupero, Anna Tordai
2014 conf
SSA-SMILE@ESWC
Diego Reforgiato Recupero, Aldo Gangemi, Andrea Giovanni Nuzzolese, Sergio Consoli, Daria Spampinato, Valentina Presutti
2014 ed.
ESWC (Satellite Events)
Valentina Presutti, Eva Blomqvist, Raphaël Troncy, Harald Sack, Ioannis Papadakis, Anna Tordai
2014 B ed.
ESWC
Valentina Presutti, Claudia d'Amato, Fabien Gandon, Mathieu d'Aquin, Steffen Staab, Anna Tordai
2014 conf
SSA-SMILE@ESWC
Sergio Consoli, Aldo Gangemi, Andrea Giovanni Nuzzolese, Silvio Peroni, Valentina Presutti, Diego Reforgiato Recupero, Daria Spampinato
2014 B conf
EKAW
Valentina Presutti, Sergio Consoli, Andrea Giovanni Nuzzolese, Diego Reforgiato Recupero, Aldo Gangemi, Ines Bannour, Haïfa Zargayouna
2013 conf
ISWC (Posters & Demos)
Aldo Gangemi, Francesco Draicchio, Valentina Presutti, Andrea Giovanni Nuzzolese, Diego Reforgiato Recupero
2013 B conf
SOFSEM
Aldo Gangemi, Valentina Presutti
2013 conf
WebSci
Andrea Giovanni Nuzzolese, Valentina Presutti, Aldo Gangemi, Alberto Musetti, Paolo Ciancarini
2013 B conf
K-CAP
Andreas Scheuermann, Enrico Motta, Paul Mulholland, Aldo Gangemi, Valentina Presutti
2013 conf
DeRiVE@ISWC
Aldo Gangemi, Ehab Hassan, Valentina Presutti, Diego Reforgiato Recupero
2013 conf
ESWC (Satellite Events)
Francesco Draicchio, Aldo Gangemi, Valentina Presutti, Andrea Giovanni Nuzzolese
2013 conf
WOP
Ricardo de Almeida Falbo, Giancarlo Guizzardi, Aldo Gangemi, Valentina Presutti
2013 B ed.
ESWC
Philipp Cimiano, Óscar Corcho, Valentina Presutti, Laura Hollink, Sebastian Rudolph
2013 conf
I-SEMANTICS
Alessandro Adamou, Paolo Ciancarini, Aldo Gangemi, Valentina Presutti
2013 conf
ISWC (Posters & Demos)
Andrea Giovanni Nuzzolese, Aldo Gangemi, Valentina Presutti, Paolo Ciancarini
2013 conf
ESWC (Satellite Events)
Andrea Giovanni Nuzzolese, Aldo Gangemi, Valentina Presutti, Francesco Draicchio, Alberto Musetti, Paolo Ciancarini
2012 conf
ISWC (1)
Aldo Gangemi, Andrea Giovanni Nuzzolese, Valentina Presutti, Francesco Draicchio, Alberto Musetti, Paolo Ciancarini
2012 ch.
Ontology Engineering in a Networked World
Alessandro Adamou, Valentina Presutti
2012 ch.
Semantic Technologies in Content Management Systems
Valentina Presutti
2012 ed.
I-SEMANTICS
Valentina Presutti, Helena Sofia Pinto
2012 B conf
EKAW
Valentina Presutti, Francesco Draicchio, Aldo Gangemi
2012 B conf
EKAW
Eva Blomqvist, Azam Seil Sepour, Valentina Presutti
2012 ch.
Ontology Engineering in a Networked World
Valentina Presutti, Eva Blomqvist, Enrico Daga, Aldo Gangemi
2012 B ed.
ESWC
Elena Simperl, Philipp Cimiano, Axel Polleres, Óscar Corcho, Valentina Presutti
2012 conf
LDOW
Andrea Giovanni Nuzzolese, Aldo Gangemi, Valentina Presutti, Paolo Ciancarini
2011 B conf
K-CAP
Valentina Presutti, Lora Aroyo, Aldo Gangemi, Alessandro Adamou, Balthasar A. C. Schopman, Guus Schreiber
2011 conf
ISWC (1)
Andrea Giovanni Nuzzolese, Aldo Gangemi, Valentina Presutti, Paolo Ciancarini
2011 conf
COLD
Valentina Presutti, Lora Aroyo, Alessandro Adamou, Balthasar A. C. Schopman, Aldo Gangemi, Guus Schreiber
2011 B conf
K-CAP
Andrea Giovanni Nuzzolese, Aldo Gangemi, Valentina Presutti
2011 ch.
Approaches to Legal Ontologies
Aldo Gangemi, Valentina Presutti, Eva Blomqvist
2011 J jnl
Appl. Ontology
Harry Halpin, Valentina Presutti
2011 conf
SPIM
Alessandro Adamou, Paolo Ciancarini, Aldo Gangemi, Valentina Presutti
2010 B conf
EKAW
Eva Blomqvist, Valentina Presutti, Enrico Daga, Aldo Gangemi
2010 B conf
EKAW
Alessandro Adamou, Valentina Presutti, Aldo Gangemi
2010 ed.
WOP
Eva Blomqvist, Vinay K. Chaudhri, Óscar Corcho, Valentina Presutti, Kurt Sandkuhl
2010 conf
EKAW (Posters and Demos)
Andrea Giovanni Nuzzolese, Aldo Gangemi, Valentina Presutti, Paolo Ciancarini
2010 J jnl
Semantic Web
Aldo Gangemi, Valentina Presutti
2010 A conf
IUI
Siegfried Handschuh, Tom Heath, VinhTuan Thai, Ian Dickinson, Lora Aroyo, Valentina Presutti
2009 conf
LDOW
Harry Halpin, Valentina Presutti
2009 B conf
ESWC
Harry Halpin, Valentina Presutti
2009 B conf
K-CAP
Eva Blomqvist, Aldo Gangemi, Valentina Presutti
2009 B conf
ESWC
Bonaventura Coppola, Aldo Gangemi, Alfio Massimiliano Gliozzo, Davide Picca, Valentina Presutti
2009 ch.
Handbook on Ontologies
Aldo Gangemi, Valentina Presutti
2009 conf
WOP
Vojtech Svátek, Ondrej Sváb-Zamazal, Valentina Presutti
2009 conf
WOP
Valentina Presutti, Enrico Daga, Aldo Gangemi, Eva Blomqvist
2008 A conf
ER
Valentina Presutti, Aldo Gangemi
2008 J jnl
Int. J. Semantic Web Inf. Syst.
Valentina Presutti, Aldo Gangemi
2008 ed.
SWAP
Aldo Gangemi, Johannes Keizer, Valentina Presutti, Heiko Stoermer
2008 conf
SWAP
Enrico Daga, Valentina Presutti, Alberto Salvati
2008 conf
ISWC (Posters & Demos)
Valentina Presutti, Enrico Daga, Aldo Gangemi, Alberto Salvati
2007 conf
ISWC/ASWC
Alfio Massimiliano Gliozzo, Aldo Gangemi, Valentina Presutti, Elena Cardillo, Enrico Daga, Alberto Salvati, Gianluca Troiani
2007 conf
I3
Aldo Gangemi, Valentina Presutti
2007 conf
CKC
Aldo Gangemi, Jos Lehmann, Valentina Presutti, Malvina Nissim, Carola Catenacci
2006 conf
SemWiki
Angelo Di Iorio, Marco Fabbri, Valentina Presutti, Fabio Vitali
2006
Valentina Presutti
2006 conf
SWAP
Aldo Gangemi, Valentina Presutti
2006 B conf
ESWC
Angelo Di Iorio, Valentina Presutti, Fabio Vitali
2005 Misc conf
SAC
Laura Bocchi, Paolo Ciancarini, Rocco Moretti, Valentina Presutti, Davide Rossi
2005 conf
SemAnnot@ISWC
Valentina Presutti, Lars Marius Garshol, Fabio Vitali, Steve Pepper, Nicola Gessa
2004 conf
CBSE
Massimo Tivoli, Paola Inverardi, Valentina Presutti, Alessandro Forghieri, Maurizio Sebastianis
2003 C conf
SEKE
Paolo Ciancarini, Valentina Presutti, Luca Abeti
2003 conf
Extreme Markup Languages®
Paolo Ciancarini, Riccardo Gentilucci, Marco Pirruccio, Valentina Presutti, Fabio Vitali
2002 conf
RISSEF
Paolo Ciancarini, Valentina Presutti
redb/extractors/js_extractors/js_features.py
← Index redb/extractors/js_extractors/js_features.py python
import inspect
from datetime import datetime, timezone
from typing import Any

from redb.extractors.enum import Tag
from redb.extractors.js_extractor import JSExtractor
from redb.extractors.js_extractors.js_patterns import FEATURE_PATTERNS
from redb.models.dataclasses import JSFeatures


_LONG_STRING_THRESHOLD = 256

# Comments still need a separate scan because the obfuscation metrics consume
# the matched text (to sum its length for comment_ratio), not just its count.
_COMMENT_RE = FEATURE_PATTERNS["comment"]


class JSFeaturesExtractor(JSExtractor):

    def __init__(
        self, filepath, log, exporters=None, index_prefix=None,
        known_benign=False, known_malicious=False, source=None, context=None,
    ):
        super().__init__(
            filepath, log, exporters, index_prefix,
            known_benign, known_malicious, source, context=context,
        )
        self.js_features = None
        self.log.debug(inspect.currentframe().f_code.co_name)

    def tag(self):
        return Tag.JS_FEATURES.value

    @staticmethod
    def _count(scan, name):
        entry = scan.get(name)
        return entry["count"] if entry else 0

    # Score tiers — see docs/js_analysis.md for the rationale behind each
    # threshold. Strong signals are ones that are unambiguous evidence of
    # obfuscation on their own (high encoding density, single-line packers,
    # 1-2 char identifiers). Weak signals are commonly seen in legitimate
    # code (eval, fromCharCode, mid-band entropy) and only count toward the
    # verdict when corroborated.
    _SCORE_STRONG_HEX_DENSITY = 0.05    # >5% of source is \xHH / \uHHHH escapes
    _SCORE_STRONG_MAX_LINE = 5000       # single line ≥5K chars (packer output)
    _SCORE_STRONG_MIN_ID = 2.0          # avg identifier length <2 chars
    _SCORE_STRONG_HIGH_ENTROPY = 5.0    # entropy >5.0 — encoded payload range
    _SCORE_STRONG_NON_ASCII = 0.30      # >30% non-ASCII codepoints in source
    _SCORE_STRONG_UNIQUE_LINES = 0.10   # <10% unique lines (with line_count >100)
    _MIN_LINES_FOR_REPETITION = 100     # below this, repetition isn't meaningful
    # Threshold is paired with the strong-signal gate in the verdict — a high
    # score alone is no longer enough, so the threshold serves as a noise
    # floor, not the false-positive prevention. The gate stops the original
    # "60/100 from weak ticks in clean code" failure mode regardless of where
    # this number sits; 40 keeps the score meaningful without re-banning
    # genuine obfuscation that lacks AST-derived signals (e.g. when
    # pyjsparser isn't installed and avg_identifier_length isn't available).
    _OBFUSCATED_THRESHOLD = 40

    def _score_obfuscation(self, metrics, scan):
        """Return `(score, strong_count, weak_count)` for the obfuscation
        heuristic. The verdict requires `score >= _OBFUSCATED_THRESHOLD` AND
        `strong_count >= 1` (or a js-x-ray hit, handled in the caller); a pile
        of weak signals alone is not enough.
        """
        score = 0
        strong = 0
        weak = 0

        src_len = len(self.js_source) if self.js_source else 1
        line_count = metrics.get('line_count', 1) or 1

        # --- Encoding density (strong / weak split by 1% vs 5%). The old
        # heuristic awarded the same +15 to a sample with 6 hex escapes in
        # 142 KB and to one that was 30% \xHH soup; this fixes that.
        hex_density = (metrics.get('hex_string_count', 0) * 4) / src_len
        unicode_density = (metrics.get('unicode_escape_count', 0) * 6) / src_len
        encoding_density = hex_density + unicode_density
        if encoding_density > self._SCORE_STRONG_HEX_DENSITY:
            score += 20
            strong += 1
        elif encoding_density > 0.01:
            score += 8
            weak += 1

        # --- Identifier length (strong: <2, weak: <3). Obfuscators rename
        # everything to `_0xNNNN` or single chars; legitimate code averages 6+.
        avg_id_len = metrics.get('avg_identifier_length', 10) or 10
        if 0 < avg_id_len < self._SCORE_STRONG_MIN_ID:
            score += 15
            strong += 1
        elif 0 < avg_id_len < 3.0:
            score += 6
            weak += 1

        # --- Single-line packers (strong: >10K, weak: >5K).
        max_line = metrics.get('max_line_length', 0)
        if max_line > 10000:
            score += 15
            strong += 1
        elif max_line > self._SCORE_STRONG_MAX_LINE:
            score += 8
            weak += 1

        # --- Text entropy (strong: >5.0). The old 4.5–5.0 weak band caught
        # jQuery/lodash and is dropped entirely.
        text_entropy = metrics.get('text_entropy', 0)
        if text_entropy > self._SCORE_STRONG_HIGH_ENTROPY:
            score += 15
            strong += 1

        # --- eval (weak; capped at +12). One eval is normal in templating,
        # AngularJS, and polyfills — it can no longer drive 30% of the verdict.
        eval_count = metrics.get('eval_count', 0)
        if eval_count > 0:
            score += min(eval_count * 4, 12)
            weak += 1

        # --- fromCharCode (weak). Common in legacy escapers but worth a tick.
        if metrics.get('fromcharcode_count', 0) > 0:
            score += 6
            weak += 1

        # --- String concatenation density (weak). >20 chains per 100 lines.
        concat_density = self._count(scan, "string_concat") / (line_count / 100)
        if concat_density > 20:
            score += 8
            weak += 1

        # --- Comment-stripped + few-line + large file (weak). Minifier tell.
        comment_ratio = metrics.get('comment_ratio', 0)
        if comment_ratio < 0.01 and line_count < 5 and src_len > 1000:
            score += 5
            weak += 1

        # --- Non-ASCII codepoint density (strong: >30%, weak: >10%). Real-world
        # JS averages <5% non-ASCII (mostly emoji or i18n string literals);
        # ≥30% almost always means a Unicode-codepoint payload (e.g. WSH
        # droppers that build a long string of non-ASCII chars and decode
        # them at runtime). Heavy localization files might cross 30% but
        # typically only score on this signal alone, which can't reach the
        # threshold by itself — the strong-signal gate prevents that
        # false-positive class while still surfacing the case where it
        # corroborates other signals.
        non_ascii_density = metrics.get('non_ascii_density', 0)
        if non_ascii_density > self._SCORE_STRONG_NON_ASCII:
            score += 20
            strong += 1
        elif non_ascii_density > 0.10:
            score += 8
            weak += 1

        # --- Line-uniqueness ratio (strong: <10%, weak: <30%, with
        # line_count >100). Hand-written or even minified code has near-1
        # line uniqueness; <10% means thousands of duplicate lines, which
        # is junk-padding / dead-code-injection used to bloat samples and
        # bury the actual payload. The line-count floor avoids
        # false-positives on tiny files that happen to repeat a few lines.
        unique_line_ratio = metrics.get('unique_line_ratio', 1.0)
        if line_count > self._MIN_LINES_FOR_REPETITION:
            if unique_line_ratio < self._SCORE_STRONG_UNIQUE_LINES:
                score += 15
                strong += 1
            elif unique_line_ratio < 0.30:
                score += 6
                weak += 1

        return min(score, 100), strong, weak

    def _detect_obfuscation_techniques(self, scan, src_len, metrics):
        """Tag the obfuscation techniques present in the source. Densities are
        computed against `src_len` so a handful of escapes in a large file
        does not get the same `hex_encoding` tag as a packed payload.

        Tags mirror the score's signals so the displayed reasoning matches
        the verdict. Three structural tags (`short_identifiers`,
        `packed_single_line`, `high_entropy`) cover the archetypes — minified
        single-line packers, renamed-identifier obfuscators, encoded-payload
        bodies — that the per-API tags below would otherwise miss entirely.
        """
        techniques = []
        if not self.js_source:
            return techniques

        if "eval" in scan:
            techniques.append("eval_usage")
        if "Function constructor" in scan:
            techniques.append("function_constructor")

        # hex_encoding / unicode_encoding by density — match the score's bar
        # so the displayed tags reflect what the score actually credited.
        hex_count = self._count(scan, "hex_escape")
        if hex_count > 5 and (hex_count * 4) / max(src_len, 1) > 0.001:
            techniques.append("hex_encoding")
        unicode_count = self._count(scan, "unicode_escape")
        if unicode_count > 5 and (unicode_count * 6) / max(src_len, 1) > 0.001:
            techniques.append("unicode_encoding")

        # charcode_encoding now requires a real cluster of calls, not one.
        if self._count(scan, "String.fromCharCode") > 3:
            techniques.append("charcode_encoding")
        if self._count(scan, "string_concat") > 10:
            techniques.append("string_concatenation")
        if "atob" in scan:
            techniques.append("base64_decoding")
        if "unescape" in scan:
            techniques.append("unescape_usage")
        if "array_function_call" in scan:
            techniques.append("array_function_calls")

        # Structural tags — surface the score's strong/weak signals so a
        # `is_likely_obfuscated: true` verdict never lands with an empty
        # techniques array (which is what happens on minified packer bodies
        # that don't match any per-API tag above).
        avg_id = metrics.get('avg_identifier_length', 0) or 0
        # Use the weak-tier bar (<3) so both strong (<2) and weak cases
        # surface — `0` means AST was unavailable from both pyjsparser and
        # js-x-ray, so we can't claim anything either way.
        if 0 < avg_id < 3.0:
            techniques.append("short_identifiers")

        # Use the weak-tier bar (>5000) so single-line packers surface even
        # below the strong 10K threshold — both cases credit the score, both
        # deserve a label.
        if metrics.get('max_line_length', 0) > 5000:
            techniques.append("packed_single_line")

        # Mirror the strong-tier entropy bar (>5.0) — the score's only
        # entropy band, since the old 4.5–4.8 weak band was dropped.
        if metrics.get('text_entropy', 0) > 5.0:
            techniques.append("high_entropy")

        # Non-ASCII codepoint payload — Unicode-character buffers that
        # decode at runtime (WSH dropper pattern). Tag at the weak bar
        # (>0.1) so any meaningful presence shows up in the techniques
        # list, even when it's not strong enough on its own.
        if metrics.get('non_ascii_density', 0) > 0.10:
            techniques.append("non_ascii_payload")

        # Repetitive padding — junk-filled bulk that buries the payload
        # under thousands of duplicate lines. Tag at the weak bar (<0.30
        # unique lines) provided the file has enough lines to make the
        # ratio meaningful.
        if (metrics.get('line_count', 0) > self._MIN_LINES_FOR_REPETITION
                and metrics.get('unique_line_ratio', 1.0) < 0.30):
            techniques.append("repetitive_padding")

        return techniques

    def _compute_ast_metrics(self, scan):
        """Compute AST-based metrics: function count, nesting depth, identifiers.

        Falls back to counts from the shared scan dict (function_decl / var_decl
        entries) when pyjsparser is unavailable.
        """
        ast = self._parse_ast()
        if not ast:
            return {
                'total_function_count': self._count(scan, "function_decl"),
                'total_variable_count': self._count(scan, "var_decl"),
                'max_nesting_depth': 0,
                'avg_identifier_length': 0.0,
            }

        counters = {'functions': 0, 'variables': 0}
        identifiers = []
        max_depth = [0]

        def walk(node, depth=0):
            if not isinstance(node, dict):
                return
            node_type = node.get('type', '')
            if node_type in ('FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'):
                counters['functions'] += 1
            if node_type == 'VariableDeclaration':
                counters['variables'] += len(node.get('declarations', []))
            if node_type == 'Identifier':
                name = node.get('name', '')
                if name:
                    identifiers.append(name)

            # Track nesting depth for blocks/functions
            new_depth = depth
            if node_type in ('BlockStatement', 'FunctionDeclaration', 'FunctionExpression'):
                new_depth = depth + 1
                if new_depth > max_depth[0]:
                    max_depth[0] = new_depth

            for key, value in node.items():
                if key == 'type':
                    continue
                if isinstance(value, dict):
                    walk(value, new_depth)
                elif isinstance(value, list):
                    for item in value:
                        if isinstance(item, dict):
                            walk(item, new_depth)

        try:
            walk(ast)
        except RecursionError:
            self.log.warning(f"AST too deep for {self.hash.sha256}")

        avg_id = 0.0
        if identifiers:
            avg_id = round(sum(len(i) for i in identifiers) / len(identifiers), 2)

        return {
            'total_function_count': counters['functions'],
            'total_variable_count': counters['variables'],
            'max_nesting_depth': max_depth[0],
            'avg_identifier_length': avg_id,
        }

    def extract(self):
        src = self.js_source
        if not src:
            self.log.error(f"Empty JS source for {self.hash.sha256}")
            return None

        lines = self.lines
        line_count = len(lines)
        char_count = len(src)
        # text_entropy is over decoded characters (distinct from BasicProperties.file_entropy
        # over raw bytes); needed for non-ASCII sources where byte entropy is depressed by
        # encoding artefacts (e.g. UTF-16 nulls).
        text_entropy = self._calculate_text_entropy(src)

        line_lengths = [len(l) for l in lines] if lines else [0]
        max_line_length = max(line_lengths)
        avg_line_length = round(sum(line_lengths) / len(line_lengths), 2) if line_lengths else 0.0

        # Minification heuristic: few lines but large file, or very long average lines
        is_minified = (line_count < 5 and char_count > 500) or avg_line_length > 500

        # The shared per-sample scan dict (built once on the JSContext); every
        # count below reads from it, including _detect_obfuscation_techniques()
        # and _score_obfuscation().
        scan = self._context.scan
        # js-x-ray output is also cached on the context — same subprocess runs
        # at most once per sample regardless of how many extractors consult it.
        xray = self._context.xray

        eval_count = self._count(scan, "eval")
        function_constructor_count = self._count(scan, "Function constructor")
        settimeout_setinterval_count = self._count(scan, "settimeout_setinterval")
        document_write_count = self._count(scan, "document.write")
        innerhtml_count = self._count(scan, "innerHTML assignment")
        unescape_count = self._count(scan, "unescape")
        fromcharcode_count = self._count(scan, "String.fromCharCode")
        atob_count = self._count(scan, "atob")
        decodeuri_count = self._count(scan, "decodeURI")

        hex_string_count = self._count(scan, "hex_escape")
        unicode_escape_count = self._count(scan, "unicode_escape")
        long_string_count = self._count(scan, "long_string")
        base64_string_count = self._count(scan, "base64_string")

        # Comment ratio still needs the matched text (to sum its length), so
        # the comment regex is the one pattern we run separately.
        comments = _COMMENT_RE.findall(src)
        comment_chars = sum(len(c) for c in comments)
        comment_ratio = round(comment_chars / char_count, 4) if char_count else 0.0

        # Non-ASCII codepoint density and line-uniqueness ratio — both target
        # patterns the per-API/per-encoding signals miss: Unicode-codepoint
        # payloads (WSH droppers building runtime strings out of >0x7f chars)
        # and junk-padded bulk (thousands of duplicate lines hiding the actual
        # logic). Computed here so they ride alongside the existing metrics.
        non_ascii_count = sum(1 for c in src if ord(c) > 127)
        non_ascii_density = non_ascii_count / char_count if char_count else 0.0
        unique_lines = len({l for l in lines if l.strip()})
        unique_line_ratio = unique_lines / line_count if line_count else 1.0

        ast_metrics = self._compute_ast_metrics(scan)

        # pyjsparser is ES5.1-only — anything with destructuring, classes,
        # optional chaining, etc. fails parse and the AST path returns 0.0
        # for avg_identifier_length, which is exactly the strong signal the
        # heuristic needs to catch obfuscator.io's `_0xNNNN` renaming. js-x-ray
        # parses ES2015+ internally and reports the same statistic, so we use
        # it as the fallback when our own AST is missing.
        avg_id_length = ast_metrics['avg_identifier_length']
        if avg_id_length == 0.0 and xray.avg_identifier_length is not None:
            avg_id_length = xray.avg_identifier_length
            ast_metrics['avg_identifier_length'] = avg_id_length

        metrics = {
            'text_entropy': text_entropy,
            'eval_count': eval_count,
            'hex_string_count': hex_string_count,
            'unicode_escape_count': unicode_escape_count,
            'fromcharcode_count': fromcharcode_count,
            'line_count': line_count,
            'max_line_length': max_line_length,
            'comment_ratio': comment_ratio,
            'avg_identifier_length': avg_id_length,
            'non_ascii_density': non_ascii_density,
            'unique_line_ratio': unique_line_ratio,
        }

        obfuscation_techniques = self._detect_obfuscation_techniques(
            scan, char_count, metrics
        )
        obfuscation_score, strong_signals, _weak = self._score_obfuscation(metrics, scan)

        # Verdict: js-x-ray's recognised obfuscator family is authoritative.
        # Otherwise the heuristic must clear the threshold AND have at least
        # one strong signal — three weak ticks alone are no longer enough.
        obfuscator_name = xray.obfuscator
        is_likely_obfuscated = (
            obfuscator_name is not None
            or (obfuscation_score >= self._OBFUSCATED_THRESHOLD and strong_signals >= 1)
        )

        script_type = self._detect_script_type()
        detected_environment = self._detect_environment()

        self.js_features = JSFeatures(
            line_count=line_count,
            char_count=char_count,
            text_entropy=text_entropy,
            max_line_length=max_line_length,
            avg_line_length=avg_line_length,
            is_minified=is_minified,
            is_likely_obfuscated=is_likely_obfuscated,
            obfuscator_name=obfuscator_name,
            obfuscation_score=obfuscation_score,
            obfuscation_techniques=obfuscation_techniques,
            eval_count=eval_count,
            function_constructor_count=function_constructor_count,
            settimeout_setinterval_count=settimeout_setinterval_count,
            document_write_count=document_write_count,
            innerhtml_count=innerhtml_count,
            unescape_count=unescape_count,
            fromcharcode_count=fromcharcode_count,
            atob_count=atob_count,
            decodeuri_count=decodeuri_count,
            total_function_count=ast_metrics['total_function_count'],
            total_variable_count=ast_metrics['total_variable_count'],
            max_nesting_depth=ast_metrics['max_nesting_depth'],
            avg_identifier_length=ast_metrics['avg_identifier_length'],
            hex_string_count=hex_string_count,
            unicode_escape_count=unicode_escape_count,
            long_string_count=long_string_count,
            base64_string_count=base64_string_count,
            comment_ratio=comment_ratio,
            script_type=script_type,
            detected_environment=detected_environment,
        )
        return self.js_features

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            if not self.js_features:
                return None

            f = self.js_features
            current_time = datetime.now(timezone.utc)
            data = [[
                self.sha256,
                f.line_count,
                f.char_count,
                f.text_entropy,
                f.max_line_length,
                f.avg_line_length,
                int(f.is_minified),
                int(f.is_likely_obfuscated),
                f.obfuscator_name or "",
                f.obfuscation_score,
                f.obfuscation_techniques,
                f.eval_count,
                f.function_constructor_count,
                f.settimeout_setinterval_count,
                f.document_write_count,
                f.innerhtml_count,
                f.unescape_count,
                f.fromcharcode_count,
                f.atob_count,
                f.decodeuri_count,
                f.total_function_count,
                f.total_variable_count,
                f.max_nesting_depth,
                f.avg_identifier_length,
                f.hex_string_count,
                f.unicode_escape_count,
                f.long_string_count,
                f.base64_string_count,
                f.comment_ratio,
                f.script_type,
                f.detected_environment,
                current_time,
            ]]

            column_names = [
                "sha256",
                "line_count", "char_count", "text_entropy",
                "max_line_length", "avg_line_length",
                "is_minified", "is_likely_obfuscated", "obfuscator_name",
                "obfuscation_score", "obfuscation_techniques",
                "eval_count", "function_constructor_count",
                "settimeout_setinterval_count", "document_write_count",
                "innerhtml_count", "unescape_count", "fromcharcode_count",
                "atob_count", "decodeuri_count",
                "total_function_count", "total_variable_count",
                "max_nesting_depth", "avg_identifier_length",
                "hex_string_count", "unicode_escape_count",
                "long_string_count", "base64_string_count",
                "comment_ratio",
                "script_type", "detected_environment",
                "analysis_date",
            ]

            column_type_names = [
                "FixedString(64)",
                "UInt32", "UInt64", "Float64",
                "UInt32", "Float64",
                "UInt8", "UInt8", "LowCardinality(String)",
                "UInt8", "Array(String)",
                "UInt32", "UInt32",
                "UInt32", "UInt32",
                "UInt32", "UInt32", "UInt32",
                "UInt32", "UInt32",
                "UInt32", "UInt32",
                "UInt16", "Float64",
                "UInt32", "UInt32",
                "UInt32", "UInt32",
                "Float64",
                "LowCardinality(String)", "LowCardinality(String)",
                "DateTime64(3, 'UTC')",
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_js_features"