Compare commits

...

3 Commits

Author SHA1 Message Date
Ali Oezyetimoglu
c4e73cbdc5 RED-6807: adapted all RM rules 2023-10-16 20:14:55 +02:00
Ali Oezyetimoglu
7e9c6c8695 RED-6807: updated RM and DM rules
* changed typos
* added rules
* fixed bugs
2023-10-16 17:34:57 +02:00
Ali Oezyetimoglu
c26b4f3827 RED-6807: added all new customer rules 2023-10-16 17:34:57 +02:00
11 changed files with 309 additions and 173 deletions

View File

@ -132,6 +132,12 @@ public class RedactionSearchUtility {
return getTextRangesByPatternWithLineBreaks(textBlock, group, pattern); return getTextRangesByPatternWithLineBreaks(textBlock, group, pattern);
} }
public static List<TextRange> findTextRangesByRegexIgnoreCase(String regexPattern, TextBlock textBlock) {
Pattern pattern = Patterns.getCompiledPattern(regexPattern, true);
return getTextRangesByPattern(textBlock, 0, pattern);
}
public static List<TextRange> findTextRangesByRegexIgnoreCase(String regexPattern, int group, TextBlock textBlock) { public static List<TextRange> findTextRangesByRegexIgnoreCase(String regexPattern, int group, TextBlock textBlock) {

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRu
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*; import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
@ -73,7 +74,7 @@ query "getFileAttributes"
//------------------------------------ Local dictionary search rules ------------------------------------ //------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LocalDictionarySearch.0 // Rule unit: LocalDictionarySearch.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -63,7 +63,7 @@ class DroolsSyntaxValidationServiceTest {
void testAllRules() { void testAllRules() {
DroolsSyntaxValidationService droolsSyntaxValidationService = new DroolsSyntaxValidationService(new KieContainerCreationService(rulesClient)); DroolsSyntaxValidationService droolsSyntaxValidationService = new DroolsSyntaxValidationService(new KieContainerCreationService(rulesClient));
var rulesFile = new ClassPathResource("drools/all_rules.drl"); var rulesFile = new ClassPathResource("drools/all_redact_manager_rules.drl");
String rulesString = new String(rulesFile.getInputStream().readAllBytes()); String rulesString = new String(rulesFile.getInputStream().readAllBytes());
@ -216,8 +216,7 @@ class DroolsSyntaxValidationServiceTest {
DroolsSyntaxValidationService droolsSyntaxValidationService = new DroolsSyntaxValidationService(new KieContainerCreationService(rulesClient)); DroolsSyntaxValidationService droolsSyntaxValidationService = new DroolsSyntaxValidationService(new KieContainerCreationService(rulesClient));
List<String> ruleFiles = List.of("drools/rules.drl", List<String> ruleFiles = List.of("drools/rules.drl", "drools/all_redact_manager_rules.drl",
"drools/all_rules.drl",
"drools/documine_flora.drl", "drools/documine_flora.drl",
"drools/manual_redaction_rules.drl", "drools/manual_redaction_rules.drl",
"drools/acceptance_rules.drl", "drools/acceptance_rules.drl",

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRu
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*; import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
@ -752,7 +753,7 @@ rule "FA.1.0: remove duplicate FileAttributes"
//------------------------------------ Local dictionary search rules ------------------------------------ //------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -902,7 +902,7 @@ rule "FA.1.0: remove duplicate FileAttributes"
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRu
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*; import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
@ -94,25 +95,25 @@ rule "SYN.1.0: Recommend CTL/BL laboratory that start with BL or CTL"
//------------------------------------ CBI rules ------------------------------------ //------------------------------------ CBI rules ------------------------------------
// Rule unit: CBI.0 // Rule unit: CBI.0
rule "CBI.0.0: Redact CBI Authors (Non Vertebrate Study)" rule "CBI.0.0: Redact CBI Authors (non vertebrate Study)"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$entity: TextEntity(type == "CBI_author", dictionaryEntry) $entity: TextEntity(type == "CBI_author", dictionaryEntry)
then then
$entity.apply("CBI.0.0", "Author found", "Article 39(e)(3) of Regulation (EC) No 178/2002"); $entity.redact("CBI.0.0", "Author found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
end end
rule "CBI.0.1: Redact CBI Authors (Vertebrate Study)" rule "CBI.0.1: Redact CBI Authors (vertebrate Study)"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$entity: TextEntity(type == "CBI_author", dictionaryEntry) $entity: TextEntity(type == "CBI_author", dictionaryEntry)
then then
$entity.apply("CBI.0.1", "Author found", "Article 39(e)(2) of Regulation (EC) No 178/2002"); $entity.redact("CBI.0.1", "Author found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
end end
// Rule unit: CBI.1 // Rule unit: CBI.1
rule "CBI.1.0: Don't redact CBI Address (Non Vertebrate Study)" rule "CBI.1.0: Do not redact CBI Address (non vertebrate Study)"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$entity: TextEntity(type == "CBI_address", dictionaryEntry) $entity: TextEntity(type == "CBI_address", dictionaryEntry)
@ -120,17 +121,17 @@ rule "CBI.1.0: Don't redact CBI Address (Non Vertebrate Study)"
$entity.skip("CBI.1.0", "Address found for Non Vertebrate Study"); $entity.skip("CBI.1.0", "Address found for Non Vertebrate Study");
end end
rule "CBI.1.1: Redact CBI Address (Vertebrate Study)" rule "CBI.1.1: Redact CBI Address (vertebrate Study)"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$entity: TextEntity(type == "CBI_address", dictionaryEntry) $entity: TextEntity(type == "CBI_address", dictionaryEntry)
then then
$entity.apply("CBI.1.1", "Address found", "Article 39(e)(2) of Regulation (EC) No 178/2002"); $entity.redact("CBI.1.1", "Address found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
end end
// Rule unit: CBI.2 // Rule unit: CBI.2
rule "CBI.2.0: Don't redact genitive CBI_author" rule "CBI.2.0: Do not redact genitive CBI Author"
when when
$entity: TextEntity(type == "CBI_author", anyMatch(textAfter, "[''ʼˈ´`ʻ']s"), applied()) $entity: TextEntity(type == "CBI_author", anyMatch(textAfter, "[''ʼˈ´`ʻ']s"), applied())
then then
@ -140,7 +141,7 @@ rule "CBI.2.0: Don't redact genitive CBI_author"
// Rule unit: CBI.3 // Rule unit: CBI.3
rule "CBI.3.0: Redacted because Section contains Vertebrate" rule "CBI.3.0: Redacted because Section contains a vertebrate"
when when
$section: Section(!hasTables(), hasEntitiesOfType("vertebrate"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address"))) $section: Section(!hasTables(), hasEntitiesOfType("vertebrate"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address")))
then then
@ -155,7 +156,7 @@ rule "CBI.3.0: Redacted because Section contains Vertebrate"
}); });
end end
rule "CBI.3.1: Redacted because Table Row contains Vertebrate" rule "CBI.3.1: Redacted because table row contains a vertebrate"
when when
$table: Table(hasEntitiesOfType("vertebrate"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address"))) $table: Table(hasEntitiesOfType("vertebrate"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address")))
then then
@ -171,7 +172,7 @@ rule "CBI.3.1: Redacted because Table Row contains Vertebrate"
}); });
end end
rule "CBI.3.2: Don't redact because Section doesn't contain Vertebrate" rule "CBI.3.2: Do not redact because Section does not contain a vertebrate"
when when
$section: Section(!hasTables(), !hasEntitiesOfType("vertebrate"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address"))) $section: Section(!hasTables(), !hasEntitiesOfType("vertebrate"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address")))
then then
@ -179,7 +180,7 @@ rule "CBI.3.2: Don't redact because Section doesn't contain Vertebrate"
.forEach(entity -> entity.skip("CBI.3.2", "No vertebrate found")); .forEach(entity -> entity.skip("CBI.3.2", "No vertebrate found"));
end end
rule "CBI.3.3: Dont redact because Table Row doesn't contain Vertebrate" rule "CBI.3.3: Do not redact because table row does not contain a vertebrate"
when when
$table: Table(hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address")) $table: Table(hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address"))
then then
@ -190,7 +191,7 @@ rule "CBI.3.3: Dont redact because Table Row doesn't contain Vertebrate"
// Rule unit: CBI.4 // Rule unit: CBI.4
rule "CBI.4.0: Dont redact Names and Addresses if no_redaction_indicator is found in Section" rule "CBI.4.0: Do not redact Names and Addresses if no_redaction_indicator is found in Section"
when when
$section: Section(!hasTables(), $section: Section(!hasTables(),
hasEntitiesOfType("vertebrate"), hasEntitiesOfType("vertebrate"),
@ -207,7 +208,7 @@ rule "CBI.4.0: Dont redact Names and Addresses if no_redaction_indicator is foun
}); });
end end
rule "CBI.4.1: Dont redact Names and Addresses if no_redaction_indicator is found in Table Row" rule "CBI.4.1: Do not redact Names and Addresses if no_redaction_indicator is found in table row"
when when
$table: Table(hasEntitiesOfType("no_redaction_indicator"), $table: Table(hasEntitiesOfType("no_redaction_indicator"),
hasEntitiesOfType("vertebrate"), hasEntitiesOfType("vertebrate"),
@ -228,7 +229,7 @@ rule "CBI.4.1: Dont redact Names and Addresses if no_redaction_indicator is foun
// Rule unit: CBI.5 // Rule unit: CBI.5
rule "CBI.5.0: Redact Names and Addresses if no_redaction_indicator but also redaction_indicator is found in section" rule "CBI.5.0: Redact Names and Addresses if no_redaction_indicator but also redaction_indicator is found in Section"
when when
$section: Section(!hasTables(), $section: Section(!hasTables(),
hasEntitiesOfType("redaction_indicator"), hasEntitiesOfType("redaction_indicator"),
@ -248,7 +249,7 @@ rule "CBI.5.0: Redact Names and Addresses if no_redaction_indicator but also red
}); });
end end
rule "CBI.5.1: Redact Names and Addresses if no_redaction_indicator but also redaction_indicator is found in Table Row" rule "CBI.5.1: Redact Names and Addresses if no_redaction_indicator but also redaction_indicator is found in table row"
when when
$table: Table(hasEntitiesOfType("no_redaction_indicator"), $table: Table(hasEntitiesOfType("no_redaction_indicator"),
hasEntitiesOfType("redaction_indicator"), hasEntitiesOfType("redaction_indicator"),
@ -270,7 +271,7 @@ rule "CBI.5.1: Redact Names and Addresses if no_redaction_indicator but also red
// Rule unit: CBI.6 // Rule unit: CBI.6
rule "CBI.6.0: Don't redact Names and Addresses if vertebrate but also published_information is found in Section" rule "CBI.6.0: Do not redact Names and Addresses if vertebrate but also published_information is found in Section"
when when
$section: Section(!hasTables(), $section: Section(!hasTables(),
hasEntitiesOfType("vertebrate"), hasEntitiesOfType("vertebrate"),
@ -289,7 +290,7 @@ rule "CBI.6.0: Don't redact Names and Addresses if vertebrate but also published
}); });
end end
rule "CBI.6.1: Don't redact Names and Addresses if vertebrate but also published_information is found in Table Row" rule "CBI.6.1: Do not redact Names and Addresses if vertebrate but also published_information is found in table row"
when when
$table: Table(hasEntitiesOfType("vertebrate"), $table: Table(hasEntitiesOfType("vertebrate"),
hasEntitiesOfType("published_information"), hasEntitiesOfType("published_information"),
@ -310,7 +311,7 @@ rule "CBI.6.1: Don't redact Names and Addresses if vertebrate but also published
// Rule unit: CBI.7 // Rule unit: CBI.7
rule "CBI.7.0: Do not redact Names and Addresses if published information found in section without tables" rule "CBI.7.0: Do not redact Names and Addresses if published information found in Section without tables"
when when
$section: Section(!hasTables(), $section: Section(!hasTables(),
hasEntitiesOfType("published_information"), hasEntitiesOfType("published_information"),
@ -358,7 +359,7 @@ rule "CBI.8.0: Redacted because Section contains must_redact entity"
}); });
end end
rule "CBI.8.1: Redacted because Table Row contains must_redact entity" rule "CBI.8.1: Redacted because table row contains must_redact entity"
when when
$table: Table(hasEntitiesOfType("must_redact"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address"))) $table: Table(hasEntitiesOfType("must_redact"), (hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address")))
then then
@ -376,7 +377,7 @@ rule "CBI.8.1: Redacted because Table Row contains must_redact entity"
// Rule unit: CBI.9 // Rule unit: CBI.9
rule "CBI.9.0: Redact all Cell's with Header Author(s) as CBI_author (non vertebrate study)" rule "CBI.9.0: Redact all cells with Header Author(s) as CBI_author (non vertebrate study)"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
@ -386,10 +387,10 @@ rule "CBI.9.0: Redact all Cell's with Header Author(s) as CBI_author (non verteb
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY)) .map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.forEach(redactionEntity -> redactionEntity.apply("CBI.9.0", "Author(s) found", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(redactionEntity -> redactionEntity.redact("CBI.9.0", "Author(s) found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "CBI.9.1: Redact all Cell's with Header Author as CBI_author (non vertebrate study)" rule "CBI.9.1: Redact all cells with Header Author as CBI_author (non vertebrate study)"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
@ -399,12 +400,12 @@ rule "CBI.9.1: Redact all Cell's with Header Author as CBI_author (non vertebrat
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY)) .map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.forEach(redactionEntity -> redactionEntity.apply("CBI.9.1", "Author found", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(redactionEntity -> redactionEntity.redact("CBI.9.1", "Author found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
// Rule unit: CBI.10 // Rule unit: CBI.10
rule "CBI.10.0: Redact all Cell's with Header Author(s) as CBI_author (vertebrate study)" rule "CBI.10.0: Redact all cells with Header Author(s) as CBI_author (vertebrate study)"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
@ -414,10 +415,10 @@ rule "CBI.10.0: Redact all Cell's with Header Author(s) as CBI_author (vertebrat
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY)) .map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.forEach(redactionEntity -> redactionEntity.apply("CBI.10.0", "Author(s) found", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(redactionEntity -> redactionEntity.redact("CBI.10.0", "Author(s) found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
rule "CBI.10.1: Redact all Cell's with Header Author as CBI_author (vertebrate study)" rule "CBI.10.1: Redact all cells with Header Author as CBI_author (vertebrate study)"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
@ -427,7 +428,7 @@ rule "CBI.10.1: Redact all Cell's with Header Author as CBI_author (vertebrate s
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY)) .map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.forEach(redactionEntity -> redactionEntity.apply("CBI.10.1", "Author found", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(redactionEntity -> redactionEntity.redact("CBI.10.1", "Author found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
@ -443,7 +444,7 @@ rule "CBI.11.0: Recommend all CBI_author entities in Table with Vertebrate Study
// Rule unit: CBI.12 // Rule unit: CBI.12
rule "CBI.12.0: Add all Cell's with Header Author(s) as CBI_author" rule "CBI.12.0: Add all cells with Header Author(s) as CBI_author"
salience 1 salience 1
when when
$table: Table(hasHeader("Author(s)") || hasHeader("Author")) $table: Table(hasHeader("Author(s)") || hasHeader("Author"))
@ -458,7 +459,7 @@ rule "CBI.12.0: Add all Cell's with Header Author(s) as CBI_author"
.forEach(redactionEntity -> redactionEntity.skip("CBI.12.0", "Author(s) header found")); .forEach(redactionEntity -> redactionEntity.skip("CBI.12.0", "Author(s) header found"));
end end
rule "CBI.12.1: Dont redact CBI_author, if its row contains a cell with header \"Vertebrate study Y/N\" and value No" rule "CBI.12.1: Do not redact CBI_author, if its row contains a cell with header \"Vertebrate study Y/N\" and value No"
when when
$table: Table(hasRowWithHeaderAndValue("Vertebrate study Y/N", "N") || hasRowWithHeaderAndValue("Vertebrate study Y/N", "No")) $table: Table(hasRowWithHeaderAndValue("Vertebrate study Y/N", "N") || hasRowWithHeaderAndValue("Vertebrate study Y/N", "No"))
then then
@ -473,12 +474,12 @@ rule "CBI.12.2: Redact CBI_author, if its row contains a cell with header \"Vert
then then
$table.streamEntitiesWhereRowHasHeaderAndAnyValue("Vertebrate study Y/N", List.of("Y", "Yes")) $table.streamEntitiesWhereRowHasHeaderAndAnyValue("Vertebrate study Y/N", List.of("Y", "Yes"))
.filter(redactionEntity -> redactionEntity.isAnyType(List.of("CBI_author", "CBI_address"))) .filter(redactionEntity -> redactionEntity.isAnyType(List.of("CBI_author", "CBI_address")))
.forEach(authorEntity -> authorEntity.apply("CBI.12.2", "Redacted because it's row belongs to a vertebrate study", "Reg (EC) No 1107/2009 Art. 63 (2g)")); .forEach(authorEntity -> authorEntity.redact("CBI.12.2", "Redacted because it's row belongs to a vertebrate study", "Reg (EC) No 1107/2009 Art. 63 (2g)"));
end end
// Rule unit: CBI.13 // Rule unit: CBI.13
rule "CBI.13.0: Ignore CBI Address Recommendations" rule "CBI.13.0: Ignore CBI Address recommendations"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$entity: TextEntity(type == "CBI_address", entityType == EntityType.RECOMMENDATION) $entity: TextEntity(type == "CBI_address", entityType == EntityType.RECOMMENDATION)
@ -493,7 +494,7 @@ rule "CBI.14.0: Redact CBI_sponsor entities if preceded by \"batches produced at
when when
$sponsorEntity: TextEntity(type == "CBI_sponsor", textBefore.contains("batches produced at")) $sponsorEntity: TextEntity(type == "CBI_sponsor", textBefore.contains("batches produced at"))
then then
$sponsorEntity.apply("CBI.14.0", "Redacted because it represents a sponsor company", "Reg (EC) No 1107/2009 Art. 63 (2g)"); $sponsorEntity.redact("CBI.14.0", "Redacted because it represents a sponsor company", "Reg (EC) No 1107/2009 Art. 63 (2g)");
end end
@ -518,7 +519,7 @@ rule "CBI.15.0: Redact row if row contains \"determination of residues\" and liv
.toList(); .toList();
$section.getEntitiesOfType(List.of($keyword, $residueKeyword)) $section.getEntitiesOfType(List.of($keyword, $residueKeyword))
.forEach(redactionEntity -> redactionEntity.apply("CBI.15.0", "Determination of residues and keyword \"" + $keyword + "\" was found.", "Reg (EC) No 1107/2009 Art. 63 (2g)")); .forEach(redactionEntity -> redactionEntity.redact("CBI.15.0", "Determination of residues and keyword \"" + $keyword + "\" was found.", "Reg (EC) No 1107/2009 Art. 63 (2g)"));
end end
rule "CBI.15.1: Redact CBI_author and CBI_address if row contains \"determination of residues\" and livestock keyword" rule "CBI.15.1: Redact CBI_author and CBI_address if row contains \"determination of residues\" and livestock keyword"
@ -540,12 +541,12 @@ rule "CBI.15.1: Redact CBI_author and CBI_address if row contains \"determinatio
$table.streamEntitiesWhereRowContainsStringsIgnoreCase(List.of($keyword, $residueKeyword)) $table.streamEntitiesWhereRowContainsStringsIgnoreCase(List.of($keyword, $residueKeyword))
.filter(redactionEntity -> redactionEntity.isAnyType(List.of("CBI_author", "CBI_address"))) .filter(redactionEntity -> redactionEntity.isAnyType(List.of("CBI_author", "CBI_address")))
.forEach(redactionEntity -> redactionEntity.apply("CBI.15.1", "Determination of residues and keyword \"" + $keyword + "\" was found.", "Reg (EC) No 1107/2009 Art. 63 (2g)")); .forEach(redactionEntity -> redactionEntity.redact("CBI.15.1", "Determination of residues and keyword \"" + $keyword + "\" was found.", "Reg (EC) No 1107/2009 Art. 63 (2g)"));
end end
// Rule unit: CBI.16 // Rule unit: CBI.16
rule "CBI.16.0: Add CBI_author with \"et al.\" Regex (non vertebrate study)" rule "CBI.16.0: Add CBI_author with \"et al.\" RegEx (non vertebrate study)"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
@ -553,12 +554,12 @@ rule "CBI.16.0: Add CBI_author with \"et al.\" Regex (non vertebrate study)"
then then
entityCreationService.byRegex("\\b([A-ZÄÖÜ][^\\s\\.,]+( [A-ZÄÖÜ]{1,2}\\.?)?( ?[A-ZÄÖÜ]\\.?)?) et al\\.?", "CBI_author", EntityType.ENTITY, 1, $section) entityCreationService.byRegex("\\b([A-ZÄÖÜ][^\\s\\.,]+( [A-ZÄÖÜ]{1,2}\\.?)?( ?[A-ZÄÖÜ]\\.?)?) et al\\.?", "CBI_author", EntityType.ENTITY, 1, $section)
.forEach(entity -> { .forEach(entity -> {
entity.apply("CBI.16.0", "Author found by \"et al\" regex", "Article 39(e)(3) of Regulation (EC) No 178/2002"); entity.redact("CBI.16.0", "Author found by \"et al\" regex", "Article 39(e)(3) of Regulation (EC) No 178/2002");
dictionary.recommendEverywhere(entity); dictionary.recommendEverywhere(entity);
}); });
end end
rule "CBI.16.1: Add CBI_author with \"et al.\" Regex (vertebrate study)" rule "CBI.16.1: Add CBI_author with \"et al.\" RegEx (vertebrate study)"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
@ -566,7 +567,7 @@ rule "CBI.16.1: Add CBI_author with \"et al.\" Regex (vertebrate study)"
then then
entityCreationService.byRegex("\\b([A-ZÄÖÜ][^\\s\\.,]+( [A-ZÄÖÜ]{1,2}\\.?)?( ?[A-ZÄÖÜ]\\.?)?) et al\\.?", "CBI_author", EntityType.ENTITY, 1, $section) entityCreationService.byRegex("\\b([A-ZÄÖÜ][^\\s\\.,]+( [A-ZÄÖÜ]{1,2}\\.?)?( ?[A-ZÄÖÜ]\\.?)?) et al\\.?", "CBI_author", EntityType.ENTITY, 1, $section)
.forEach(entity -> { .forEach(entity -> {
entity.apply("CBI.16.1", "Author found by \"et al\" regex", "Article 39(e)(2) of Regulation (EC) No 178/2002"); entity.redact("CBI.16.1", "Author found by \"et al\" regex", "Article 39(e)(2) of Regulation (EC) No 178/2002");
dictionary.recommendEverywhere(entity); dictionary.recommendEverywhere(entity);
}); });
end end
@ -645,11 +646,48 @@ rule "CBI.20.1: Redact between \"PERFORMING LABORATORY\" and \"LABORATORY PROJEC
then then
entityCreationService.betweenStrings("PERFORMING LABORATORY:", "LABORATORY PROJECT ID:", "CBI_address", EntityType.ENTITY, $section) entityCreationService.betweenStrings("PERFORMING LABORATORY:", "LABORATORY PROJECT ID:", "CBI_address", EntityType.ENTITY, $section)
.forEach(laboratoryEntity -> { .forEach(laboratoryEntity -> {
laboratoryEntity.apply("CBI.20.1", "PERFORMING LABORATORY was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"); laboratoryEntity.redact("CBI.20.1", "PERFORMING LABORATORY was found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
dictionary.recommendEverywhere(laboratoryEntity); dictionary.recommendEverywhere(laboratoryEntity);
}); });
end end
// Rule unit: CBI.21
rule "CBI.21.0: Redact short Authors section (non vertebrate study)"
when
not FileAttribute(label == "Vertebrate Study", value == "Yes")
$section: Section(containsAnyStringIgnoreCase("author(s)", "author", "authors"), length() < 50, getTreeId().get(0) <= 20) //TODO: evaluate the reason of this rule
not TextEntity(type == "CBI_author", engines contains Engine.NER) from $section.getEntities()
then
entityCreationService.byRegexIgnoreCase("(?<=author\\(?s\\)?\\s\\n?)([\\p{Lu}\\p{L} ]{5,15}(,|\\n)?){1,3}", "CBI_author", EntityType.ENTITY, $section)
.forEach(entity -> {
entity.redact("CBI.21.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
});
end
rule "CBI.21.1: Redact short Authors section (vertebrate study)"
when
FileAttribute(label == "Vertebrate Study", value == "Yes")
$section: Section(containsAnyStringIgnoreCase("author(s)", "author", "authors"), length() < 50, getTreeId().get(0) <= 20) //TODO: evaluate the reason of this rule
not TextEntity(type == "CBI_author", engines contains Engine.NER) from $section.getEntities()
then
entityCreationService.byRegexIgnoreCase("(?<=author\\(?s\\)?\\s\\n?)([\\p{Lu}\\p{L} ]{5,15}(,|\\n)?){1,3}", "CBI_author", EntityType.ENTITY, $section)
.forEach(entity -> {
entity.redact("CBI.21.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
});
end
// Rule unit: CBI.22
rule "CBI.22.0: Redact Addresses in Reference Tables for vertebrate studies in non-vertebrate documents"
when
not FileAttribute(label == "Vertebrate Study", value == "Yes")
$table: Table(hasHeader("Vertebrate study Y/N"), hasRowWithHeaderAndValue("Vertebrate study Y/N", "Y") || hasRowWithHeaderAndValue("Vertebrate study Y/N", "Yes"))
then
$table.streamEntitiesWhereRowHasHeaderAndAnyValue("Vertebrate study Y/N", List.of("Y", "Yes"))
.filter(redactionEntity -> redactionEntity.isType("CBI_address"))
.forEach(authorEntity -> authorEntity.redact("CBI.22.0", "Redacted because row is a vertebrate study", "Reg (EC) No 1107/2009 Art. 63 (2g)"));
end
//------------------------------------ PII rules ------------------------------------ //------------------------------------ PII rules ------------------------------------
@ -659,7 +697,7 @@ rule "PII.0.0: Redact all PII (non vertebrate study)"
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$pii: TextEntity(type == "PII", dictionaryEntry) $pii: TextEntity(type == "PII", dictionaryEntry)
then then
$pii.apply("PII.0.0", "Personal Information found", "Article 39(e)(3) of Regulation (EC) No 178/2002"); $pii.redact("PII.0.0", "Personal Information found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
end end
rule "PII.0.1: Redact all PII (vertebrate study)" rule "PII.0.1: Redact all PII (vertebrate study)"
@ -667,7 +705,7 @@ rule "PII.0.1: Redact all PII (vertebrate study)"
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$pii: TextEntity(type == "PII", dictionaryEntry) $pii: TextEntity(type == "PII", dictionaryEntry)
then then
$pii.apply("PII.0.1", "Personal Information found", "Article 39(e)(2) of Regulation (EC) No 178/2002"); $pii.redact("PII.0.1", "Personal Information found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
end end
@ -678,7 +716,7 @@ rule "PII.1.0: Redact Emails by RegEx (Non vertebrate study)"
$section: Section(containsString("@")) $section: Section(containsString("@"))
then then
entityCreationService.byRegex("\\b([A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z\\-]{1,23}[A-Za-z])\\b", "PII", EntityType.ENTITY, 1, $section) entityCreationService.byRegex("\\b([A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z\\-]{1,23}[A-Za-z])\\b", "PII", EntityType.ENTITY, 1, $section)
.forEach(emailEntity -> emailEntity.apply("PII.1.0", "Found by Email Regex", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(emailEntity -> emailEntity.redact("PII.1.0", "Found by Email Regex", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "PII.1.1: Redact Emails by RegEx (vertebrate study)" rule "PII.1.1: Redact Emails by RegEx (vertebrate study)"
@ -687,7 +725,15 @@ rule "PII.1.1: Redact Emails by RegEx (vertebrate study)"
$section: Section(containsString("@")) $section: Section(containsString("@"))
then then
entityCreationService.byRegex("\\b([A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z\\-]{1,23}[A-Za-z])\\b", "PII", EntityType.ENTITY, 1, $section) entityCreationService.byRegex("\\b([A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z\\-]{1,23}[A-Za-z])\\b", "PII", EntityType.ENTITY, 1, $section)
.forEach(emailEntity -> emailEntity.apply("PII.1.1", "Found by Email Regex", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(emailEntity -> emailEntity.redact("PII.1.1", "Found by Email Regex", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end
rule "PII.1.2: Redact typoed Emails with indicator"
when
$section: Section(containsString("@") || containsStringIgnoreCase("mail"))
then
entityCreationService.byRegexIgnoreCase("mail[:\\.\\s]{1,2}([\\w\\/\\-\\{\\(\\. ]{3,20}(@|a|f)\\s?[\\w\\/\\-\\{\\(\\. ]{3,20}(\\. \\w{2,4}\\b|\\.\\B|\\.\\w{1,4}\\b))", "PII", EntityType.ENTITY, $section)
.forEach(emailEntity -> emailEntity.redact("PII.1.2", "Personal information found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
@ -707,7 +753,7 @@ rule "PII.2.0: Redact Phone and Fax by RegEx (non vertebrate study)"
containsString("Fer")) containsString("Fer"))
then then
entityCreationService.byRegexIgnoreCase("\\b(contact|telephone|phone|ph\\.|fax|tel|ter|mobile|fel|fer)[a-zA-Z\\s]{0,10}[:.\\s]{0,3}([\\+\\d\\(][\\s\\d\\(\\)\\-\\/\\.]{4,100}\\d)\\b", "PII", EntityType.ENTITY, 2, $section) entityCreationService.byRegexIgnoreCase("\\b(contact|telephone|phone|ph\\.|fax|tel|ter|mobile|fel|fer)[a-zA-Z\\s]{0,10}[:.\\s]{0,3}([\\+\\d\\(][\\s\\d\\(\\)\\-\\/\\.]{4,100}\\d)\\b", "PII", EntityType.ENTITY, 2, $section)
.forEach(contactEntity -> contactEntity.apply("PII.2.0", "Found by Phone and Fax Regex", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(contactEntity -> contactEntity.redact("PII.2.0", "Found by Phone and Fax Regex", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "PII.2.1: Redact Phone and Fax by RegEx (vertebrate study)" rule "PII.2.1: Redact Phone and Fax by RegEx (vertebrate study)"
@ -725,7 +771,15 @@ rule "PII.2.1: Redact Phone and Fax by RegEx (vertebrate study)"
containsString("Fer")) containsString("Fer"))
then then
entityCreationService.byRegexIgnoreCase("\\b(contact|telephone|phone|ph\\.|fax|tel|ter|mobile|fel|fer)[a-zA-Z\\s]{0,10}[:.\\s]{0,3}([\\+\\d\\(][\\s\\d\\(\\)\\-\\/\\.]{4,100}\\d)\\b", "PII", EntityType.ENTITY, 2, $section) entityCreationService.byRegexIgnoreCase("\\b(contact|telephone|phone|ph\\.|fax|tel|ter|mobile|fel|fer)[a-zA-Z\\s]{0,10}[:.\\s]{0,3}([\\+\\d\\(][\\s\\d\\(\\)\\-\\/\\.]{4,100}\\d)\\b", "PII", EntityType.ENTITY, 2, $section)
.forEach(contactEntity -> contactEntity.apply("PII.2.1", "Found by Phone and Fax Regex", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(contactEntity -> contactEntity.redact("PII.2.1", "Found by Phone and Fax Regex", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end
rule "PII.2.2: Redact phone numbers without indicators"
when
$section: Section(containsString("+"))
then
entityCreationService.byRegex("(\\+[\\dO]{1,2} )(\\([\\dO]{1,3}\\))?[\\d\\-O ]{8,15}", "PII", EntityType.ENTITY, $section)
.forEach(entity -> entity.redact("PII.2.2", "Personal information found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
@ -736,7 +790,7 @@ rule "PII.3.0: Redact telephone numbers by RegEx (Non vertebrate study)"
$section: Section(matchesRegex("[+]\\d{1,}")) $section: Section(matchesRegex("[+]\\d{1,}"))
then then
entityCreationService.byRegex("((([+]\\d{1,3} (\\d{7,12})\\b)|([+]\\d{1,3}(\\d{3,12})\\b|[+]\\d{1,3}([ -]\\(?\\d{1,6}\\)?){2,4})|[+]\\d{1,3} ?((\\d{2,6}\\)?)([ -]\\d{2,6}){1,4}))(-\\d{1,3})?\\b)", "PII", EntityType.ENTITY, 1, $section) entityCreationService.byRegex("((([+]\\d{1,3} (\\d{7,12})\\b)|([+]\\d{1,3}(\\d{3,12})\\b|[+]\\d{1,3}([ -]\\(?\\d{1,6}\\)?){2,4})|[+]\\d{1,3} ?((\\d{2,6}\\)?)([ -]\\d{2,6}){1,4}))(-\\d{1,3})?\\b)", "PII", EntityType.ENTITY, 1, $section)
.forEach(entity -> entity.apply("PII.3.0", "Telephone number found by regex", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(entity -> entity.redact("PII.3.0", "Telephone number found by regex", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "PII.3.1: Redact telephone numbers by RegEx (vertebrate study)" rule "PII.3.1: Redact telephone numbers by RegEx (vertebrate study)"
@ -745,10 +799,9 @@ rule "PII.3.1: Redact telephone numbers by RegEx (vertebrate study)"
$section: Section(matchesRegex("[+]\\d{1,}")) $section: Section(matchesRegex("[+]\\d{1,}"))
then then
entityCreationService.byRegex("((([+]\\d{1,3} (\\d{7,12})\\b)|([+]\\d{1,3}(\\d{3,12})\\b|[+]\\d{1,3}([ -]\\(?\\d{1,6}\\)?){2,4})|[+]\\d{1,3} ?((\\d{2,6}\\)?)([ -]\\d{2,6}){1,4}))(-\\d{1,3})?\\b)", "PII", EntityType.ENTITY, 1, $section) entityCreationService.byRegex("((([+]\\d{1,3} (\\d{7,12})\\b)|([+]\\d{1,3}(\\d{3,12})\\b|[+]\\d{1,3}([ -]\\(?\\d{1,6}\\)?){2,4})|[+]\\d{1,3} ?((\\d{2,6}\\)?)([ -]\\d{2,6}){1,4}))(-\\d{1,3})?\\b)", "PII", EntityType.ENTITY, 1, $section)
.forEach(entity -> entity.apply("PII.3.1", "Telephone number found by regex", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(entity -> entity.redact("PII.3.1", "Telephone number found by regex", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
// Rule unit: PII.4 // Rule unit: PII.4
rule "PII.4.0: Redact line after contact information keywords (non vertebrate study)" rule "PII.4.0: Redact line after contact information keywords (non vertebrate study)"
when when
@ -775,12 +828,12 @@ rule "PII.4.0: Redact line after contact information keywords (non vertebrate st
$section: Section(containsString($contactKeyword)) $section: Section(containsString($contactKeyword))
then then
entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section) entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section)
.forEach(contactEntity -> contactEntity.apply("PII.4.0", "Found after \"" + $contactKeyword + "\" contact keyword", "Reg (EC) No 1107/2009 Art. 63 (2e)")); .forEach(contactEntity -> contactEntity.redact("PII.4.0", "Found after \"" + $contactKeyword + "\" contact keyword", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
end end
rule "PII.4.1: Redact line after contact information keywords (non vertebrate study)" rule "PII.4.1: Redact line after contact information keywords (vertebrate study)"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$contactKeyword: String() from List.of("Contact point:", $contactKeyword: String() from List.of("Contact point:",
"Contact:", "Contact:",
"Alternative contact:", "Alternative contact:",
@ -803,7 +856,7 @@ rule "PII.4.1: Redact line after contact information keywords (non vertebrate st
$section: Section(containsString($contactKeyword)) $section: Section(containsString($contactKeyword))
then then
entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section) entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section)
.forEach(contactEntity -> contactEntity.apply("PII.4.1", "Found after \"" + $contactKeyword + "\" contact keyword", "Reg (EC) No 1107/2009 Art. 63 (2e)")); .forEach(contactEntity -> contactEntity.redact("PII.4.1", "Found after \"" + $contactKeyword + "\" contact keyword", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
end end
@ -818,7 +871,7 @@ rule "PII.5.0: Redact line after contact information keywords reduced (non verte
$section: Section(containsString($contactKeyword)) $section: Section(containsString($contactKeyword))
then then
entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section) entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section)
.forEach(contactEntity -> contactEntity.apply("PII.5.0", "Found after \"" + $contactKeyword + "\" contact keyword", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(contactEntity -> contactEntity.redact("PII.5.0", "Found after \"" + $contactKeyword + "\" contact keyword", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "PII.5.1: Redact line after contact information keywords reduced (Vertebrate study)" rule "PII.5.1: Redact line after contact information keywords reduced (Vertebrate study)"
@ -831,12 +884,12 @@ rule "PII.5.1: Redact line after contact information keywords reduced (Vertebrat
$section: Section(containsString($contactKeyword)) $section: Section(containsString($contactKeyword))
then then
entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section) entityCreationService.lineAfterString($contactKeyword, "PII", EntityType.ENTITY, $section)
.forEach(contactEntity -> contactEntity.apply("PII.5.1", "Found after \"" + $contactKeyword + "\" contact keyword", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(contactEntity -> contactEntity.redact("PII.5.1", "Found after \"" + $contactKeyword + "\" contact keyword", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
// Rule unit: PII.6 // Rule unit: PII.6
rule "PII.6.0: redact line between contact keywords (non vertebrate study)" rule "PII.6.0: Redact line between contact keywords (non vertebrate study)"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section((containsString("No:") && containsString("Fax")) || (containsString("Contact:") && containsString("Tel"))) $section: Section((containsString("No:") && containsString("Fax")) || (containsString("Contact:") && containsString("Tel")))
@ -845,10 +898,10 @@ rule "PII.6.0: redact line between contact keywords (non vertebrate study)"
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section), entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section) entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
) )
.forEach(contactEntity -> contactEntity.apply("PII.6.0", "Found between contact keywords", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(contactEntity -> contactEntity.redact("PII.6.0", "Found between contact keywords", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "PII.6.1: redact line between contact keywords" rule "PII.6.1: Redact line between contact keywords (vertebrate study)"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section((containsString("No:") && containsString("Fax")) || (containsString("Contact:") && containsString("Tel"))) $section: Section((containsString("No:") && containsString("Fax")) || (containsString("Contact:") && containsString("Tel")))
@ -857,7 +910,7 @@ rule "PII.6.1: redact line between contact keywords"
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section), entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section) entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
) )
.forEach(contactEntity -> contactEntity.apply("PII.6.1", "Found between contact keywords", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(contactEntity -> contactEntity.redact("PII.6.1", "Found between contact keywords", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
@ -877,10 +930,10 @@ rule "PII.7.0: Redact contact information if applicant is found (non vertebrate
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section), entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section) entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
)) ))
.forEach(entity -> entity.apply("PII.7.0", "Applicant information was found", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(entity -> entity.redact("PII.7.0", "Applicant information was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "PII.7.1: Redact contact information if applicant is found (non vertebrate study)" rule "PII.7.1: Redact contact information if applicant is found (vertebrate study)"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section(getHeadline().containsString("applicant") || $section: Section(getHeadline().containsString("applicant") ||
@ -895,12 +948,12 @@ rule "PII.7.1: Redact contact information if applicant is found (non vertebrate
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section), entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section) entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
)) ))
.forEach(entity -> entity.apply("PII.7.1", "Applicant information was found", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(entity -> entity.redact("PII.7.1", "Applicant information was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
// Rule unit: PII.8 // Rule unit: PII.8
rule "PII.8.0: Redact contact information if producer is found" rule "PII.8.0: Redact contact information if producer is found (non vertebrate study)"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section(containsStringIgnoreCase("producer of the plant protection") || $section: Section(containsStringIgnoreCase("producer of the plant protection") ||
@ -915,10 +968,10 @@ rule "PII.8.0: Redact contact information if producer is found"
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section), entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section) entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
)) ))
.forEach(entity -> entity.apply("PII.8.0", "Producer was found", "Reg (EC) No 1107/2009 Art. 63 (2e)")); .forEach(entity -> entity.redact("PII.8.0", "Producer was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
end end
rule "PII.8.1: Redact contact information if producer is found" rule "PII.8.1: Redact contact information if producer is found (vertebrate study)"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section(containsStringIgnoreCase("producer of the plant protection") || $section: Section(containsStringIgnoreCase("producer of the plant protection") ||
@ -933,54 +986,27 @@ rule "PII.8.1: Redact contact information if producer is found"
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section), entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section) entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
)) ))
.forEach(entity -> entity.apply("PII.8.1", "Producer was found", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(entity -> entity.redact("PII.8.1", "Producer was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
// Rule unit: PII.9 // Rule unit: PII.9
rule "PII.9.0: Redact between \"AUTHOR(S)\" and \"COMPLETION DATE\" (non vertebrate study)" rule "PII.9.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
when when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section(!hasTables(), containsString("AUTHOR(S):"), containsString("COMPLETION DATE:"), !containsString("STUDY COMPLETION DATE:")) $document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
then then
entityCreationService.betweenStrings("AUTHOR(S):", "COMPLETION DATE:", "PII", EntityType.ENTITY, $section) entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
.forEach(authorEntity -> authorEntity.apply("PII.9.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
rule "PII.9.1: Redact between \"AUTHOR(S)\" and \"STUDY COMPLETION DATE\" (non vertebrate study)" rule "PII.9.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
when when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes") FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section(!hasTables(), containsString("AUTHOR(S):"), containsString("COMPLETION DATE:"), !containsString("STUDY COMPLETION DATE:")) $document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
then then
entityCreationService.betweenStrings("AUTHOR(S):", "COMPLETION DATE:", "PII", EntityType.ENTITY, $section) entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
.forEach(authorEntity -> authorEntity.apply("PII.9.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002")); .forEach(authorEntity -> authorEntity.redact("PII.9.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end
rule "PII.9.2: Redact between \"AUTHOR(S)\" and \"COMPLETION DATE\" (non vertebrate study)"
when
not FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section(!hasTables(), containsString("AUTHOR(S):"), containsString("STUDY COMPLETION DATE:"))
then
entityCreationService.betweenStrings("AUTHOR(S):", "STUDY COMPLETION DATE:", "PII", EntityType.ENTITY, $section)
.forEach(authorEntity -> authorEntity.apply("PII.9.2", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"STUDY COMPLETION DATE\" (vertebrate study)"
when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$section: Section(!hasTables(), containsString("AUTHOR(S):"), containsString("STUDY COMPLETION DATE:"))
then
entityCreationService.betweenStrings("AUTHOR(S):", "STUDY COMPLETION DATE:", "PII", EntityType.ENTITY, $section)
.forEach(authorEntity -> authorEntity.apply("PII.9.3", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end
rule "PII.9.4: Redact between \"AUTHOR(S)\" and \"STUDY COMPLETION DATE\" (vertebrate study)"
when
FileAttribute(label == "Vertebrate Study", value.toLowerCase() == "yes")
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsStringIgnoreCase("STUDY COMPLETION DATE"))
then
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S):","AUTHOR(S)"), List.of("STUDY COMPLETION DATE:","STUDY COMPLETION DATE"), "PII", EntityType.ENTITY, $document)
.forEach(authorEntity -> authorEntity.apply("PII.9.4", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
end end
@ -990,7 +1016,7 @@ rule "PII.10.0: Redact study director abbreviation"
$section: Section(containsString("KATH") || containsString("BECH") || containsString("KML")) $section: Section(containsString("KATH") || containsString("BECH") || containsString("KML"))
then then
entityCreationService.byRegexIgnoreCase("((KATH)|(BECH)|(KML)) ?(\\d{4})","PII", EntityType.ENTITY, 1, $section) entityCreationService.byRegexIgnoreCase("((KATH)|(BECH)|(KML)) ?(\\d{4})","PII", EntityType.ENTITY, 1, $section)
.forEach(entity -> entity.apply("PII.10.0", "Personal information found", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(entity -> entity.redact("PII.10.0", "Personal information found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
@ -1000,7 +1026,7 @@ rule "PII.11.0: Redact On behalf of Sequani Ltd.:"
$section: Section(!hasTables(), containsString("On behalf of Sequani Ltd.: Name Title")) $section: Section(!hasTables(), containsString("On behalf of Sequani Ltd.: Name Title"))
then then
entityCreationService.betweenStrings("On behalf of Sequani Ltd.: Name Title", "On behalf of", "PII", EntityType.ENTITY, $section) entityCreationService.betweenStrings("On behalf of Sequani Ltd.: Name Title", "On behalf of", "PII", EntityType.ENTITY, $section)
.forEach(authorEntity -> authorEntity.apply("PII.11.0", "On behalf of Sequani Ltd.: Name Title was found", "Article 39(e)(3) of Regulation (EC) No 178/2002")); .forEach(authorEntity -> authorEntity.redact("PII.11.0", "On behalf of Sequani Ltd.: Name Title was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end end
@ -1013,6 +1039,24 @@ rule "PII.12.0: Expand PII entities with salutation prefix"
.ifPresent(expandedEntity -> expandedEntity.addMatchedRules($entityToExpand.getMatchedRuleList())); .ifPresent(expandedEntity -> expandedEntity.addMatchedRules($entityToExpand.getMatchedRuleList()));
end end
// Rule unit: PII.13
rule "PII.13.0: Add recommendation for PII after Contact Person"
when
$section: Section(containsString("contact person:"))
then
entityCreationService.lineAfterStringsIgnoreCase(List.of("Contact Person", "Contact Person:"), "PII", EntityType.RECOMMENDATION, $section)
.forEach(entity -> entity.skip("PII.13.0", "Line after \"Source:\" in Test Animals Section"));
end
// Rule unit: PII.14
rule "PII.14.0: Recommend title prefixed words as PII"
when
$section: Section(containsAnyString("Dr ", "PD Dr ", "Prof. Dr ", "Dr. med. vet ", "Dr. rer. nat ", "PhD ", "BSc ", "(FH) ", "Mr ", "Mrs ", "Ms ", "Miss ", "Dr.", "PD. Dr.", "Prof. Dr.", "Dr. med. vet.", "Dr. rer. nat.", "PhD.", "BSc.", "(FH).", "Mr.", "Mrs.", "Ms.", "Miss."))
then
entityCreationService.byRegex("((Dr|PD Dr|Prof. Dr|Dr. med. vet|Dr. rer. nat|PhD|BSc|\\\\(FH\\\\)|Mr|Mrs|Ms|Miss)[.\\\\s]{1,2})([\\\\p{Lu}][\\\\p{L}\\\\-.]{1,20}\\\\s[\\\\p{Lu}][\\\\p{L}\\\\-.]{1,20})", "PII", EntityType.ENTITY, 3, $section);
end
//------------------------------------ Other rules ------------------------------------ //------------------------------------ Other rules ------------------------------------
@ -1032,7 +1076,7 @@ rule "ETC.1.0: Redact Purity"
$section: Section(containsStringIgnoreCase("purity")) $section: Section(containsStringIgnoreCase("purity"))
then then
entityCreationService.byRegex("\\bPurity:\\s*(<?>?\\s*\\d{1,2}(?:\\.\\d{1,2})?\\s*%)", "purity", EntityType.ENTITY, 1, $section) entityCreationService.byRegex("\\bPurity:\\s*(<?>?\\s*\\d{1,2}(?:\\.\\d{1,2})?\\s*%)", "purity", EntityType.ENTITY, 1, $section)
.forEach(entity -> entity.apply("ETC.1.0", "Purity found", "Reg (EC) No 1107/2009 Art. 63 (2a)")); .forEach(entity -> entity.redact("ETC.1.0", "Purity found", "Reg (EC) No 1107/2009 Art. 63 (2a)"));
end end
@ -1042,7 +1086,7 @@ rule "ETC.2.0: Redact signatures (non vertebrate study)"
not FileAttribute(label == "Vertebrate Study", value == "Yes") not FileAttribute(label == "Vertebrate Study", value == "Yes")
$signature: Image(imageType == ImageType.SIGNATURE) $signature: Image(imageType == ImageType.SIGNATURE)
then then
$signature.apply("ETC.2.0", "Signature Found", "Article 39(e)(3) of Regulation (EC) No 178/2002"); $signature.redact("ETC.2.0", "Signature Found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
end end
rule "ETC.2.1: Redact signatures (vertebrate study)" rule "ETC.2.1: Redact signatures (vertebrate study)"
@ -1050,7 +1094,7 @@ rule "ETC.2.1: Redact signatures (vertebrate study)"
FileAttribute(label == "Vertebrate Study", value == "Yes") FileAttribute(label == "Vertebrate Study", value == "Yes")
$signature: Image(imageType == ImageType.SIGNATURE) $signature: Image(imageType == ImageType.SIGNATURE)
then then
$signature.apply("ETC.2.1", "Signature Found", "Article 39(e)(2) of Regulation (EC) No 178/2002"); $signature.redact("ETC.2.1", "Signature Found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
end end
@ -1060,7 +1104,7 @@ rule "ETC.3.0: Redact logos (vertebrate study)"
not FileAttribute(label == "Vertebrate Study", value == "Yes") not FileAttribute(label == "Vertebrate Study", value == "Yes")
$logo: Image(imageType == ImageType.LOGO) $logo: Image(imageType == ImageType.LOGO)
then then
$logo.apply("ETC.3.0", "Logo Found", "Article 39(e)(3) of Regulation (EC) No 178/2002"); $logo.redact("ETC.3.0", "Logo Found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
end end
rule "ETC.3.1: Redact logos (non vertebrate study)" rule "ETC.3.1: Redact logos (non vertebrate study)"
@ -1068,7 +1112,7 @@ rule "ETC.3.1: Redact logos (non vertebrate study)"
FileAttribute(label == "Vertebrate Study", value == "Yes") FileAttribute(label == "Vertebrate Study", value == "Yes")
$logo: Image(imageType == ImageType.LOGO) $logo: Image(imageType == ImageType.LOGO)
then then
$logo.apply("ETC.3.1", "Logo Found", "Article 39(e)(2) of Regulation (EC) No 178/2002"); $logo.redact("ETC.3.1", "Logo Found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
end end
@ -1077,7 +1121,21 @@ rule "ETC.4.0: Redact dossier dictionary entries"
when when
$dossierRedaction: TextEntity(type == "dossier_redaction") $dossierRedaction: TextEntity(type == "dossier_redaction")
then then
$dossierRedaction.apply("ETC.4.0", "Specification of impurity found", "Article 39(e)(3) of Regulation (EC) No 178/2002"); $dossierRedaction.redact("ETC.4.0", "Specification of impurity found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
end
rule "ETC.4.1: Redact dossier dictionary entries"
when
$dossierRedaction: TextEntity(type == "dossier_redaction")
then
$dossierRedaction.redact("ETC.4.1", "Dossier Redaction found", "Article 39(1)(2) of Regulation (EC) No 178/2002");
end
rule "ETC.4.2: Redact dossier dictionary entries"
when
$dossierRedaction: TextEntity(type == "dossier_redaction")
then
$dossierRedaction.redact("ETC.4.2", "Dossier redaction found", "Article 63(2)(a) of Regulation (EC) No 1107/2009 (making reference to Article 39 of Regulation EC No 178/2002)");
end end
@ -1101,14 +1159,14 @@ rule "ETC.6.0: Redact CAS Number"
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "PII", EntityType.ENTITY)) .map(tableCell -> entityCreationService.bySemanticNode(tableCell, "PII", EntityType.ENTITY))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.forEach(redactionEntity -> redactionEntity.apply("ETC.6.0", "Sample # found in Header", "Reg (EC) No 1107/2009 Art. 63 (2g)")); .forEach(redactionEntity -> redactionEntity.redact("ETC.6.0", "Sample # found in Header", "Reg (EC) No 1107/2009 Art. 63 (2g)"));
end end
// Rule unit: ETC.7 // Rule unit: ETC.7
rule "ETC.7.0: Guidelines FileAttributes" rule "ETC.7.0: Guidelines FileAttributes"
when when
$section: Section(!hasTables(), (containsString("DATA REQUIREMENT(S):") || containsString("TEST GUIDELINE(S):")) && (containsString("OECD") || containsString("EPA") || containsString("OPPTS"))) $section: Section(!hasTables(), containsAnyString("DATA REQUIREMENT(S):", "TEST GUIDELINE(S):") && containsAnyString("OECD", "EPA", "OPPTS"))
then then
RedactionSearchUtility.findTextRangesByRegex("OECD (No\\.? )?\\d{3}( \\(\\d{4}\\))?", $section.getTextBlock()).stream() RedactionSearchUtility.findTextRangesByRegex("OECD (No\\.? )?\\d{3}( \\(\\d{4}\\))?", $section.getTextBlock()).stream()
.map(boundary -> $section.getTextBlock().subSequence(boundary).toString()) .map(boundary -> $section.getTextBlock().subSequence(boundary).toString())
@ -1123,7 +1181,7 @@ rule "ETC.8.0: Redact formulas (vertebrate study)"
not FileAttribute(label == "Vertebrate Study", value == "Yes") not FileAttribute(label == "Vertebrate Study", value == "Yes")
$logo: Image(imageType == ImageType.FORMULA) $logo: Image(imageType == ImageType.FORMULA)
then then
$logo.apply("ETC.8.0", "Logo Found", "Article 39(e)(3) of Regulation (EC) No 178/2002"); $logo.redact("ETC.8.0", "Logo Found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
end end
rule "ETC.8.1: Redact formulas (non vertebrate study)" rule "ETC.8.1: Redact formulas (non vertebrate study)"
@ -1131,14 +1189,49 @@ rule "ETC.8.1: Redact formulas (non vertebrate study)"
FileAttribute(label == "Vertebrate Study", value == "Yes") FileAttribute(label == "Vertebrate Study", value == "Yes")
$logo: Image(imageType == ImageType.FORMULA) $logo: Image(imageType == ImageType.FORMULA)
then then
$logo.apply("ETC.8.1", "Logo Found", "Article 39(e)(2) of Regulation (EC) No 178/2002"); $logo.redact("ETC.8.1", "Logo Found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
end end
// Rule unit: ETC.9
rule "ETC.9.0: Redact skipped impurities"
when
FileAttribute(label == "Redact Skipped Impurities", value == "Yes")
$skippedImpurities: TextEntity(type == "skipped_impurities")
then
$skippedImpurities.redact("ETC.9.0", "Occasional Impurity found", "Article 63(2)(b) of Regulation (EC) No 1107/2009");
end
rule "ETC.9.1: Redact impurities"
when
FileAttribute(label == "Redact Impurities", value == "Yes")
$skippedImpurities: TextEntity(type == "impurities")
then
$skippedImpurities.redact("ETC.9.1", "Impurity found", "Article 63(2)(b) of Regulation (EC) No 1107/2009");
end
// Rule unit: ETC.10
rule "ETC.10.0: Redact Product Composition Information"
when
$compositionInformation: TextEntity(type == "product_composition")
then
$compositionInformation.redact("ETC.10.0", "Product Composition Information found", "Article 63(2)(d) of Regulation (EC) No 1107/2009");
end
// Rule unit: ETC.11
rule "ETC.11.0: Recommend first line in table cell with name and address of owner"
when
$table: Table(hasHeader("Name and Address of Owner / Tenant"), containsString("trial site"))
$header: TableCell(isHeader(), containsString("Name and Address of Owner / Tenant")) from $table.streamTableCells().toList()
$tableCell: TableCell(col == $header.col, row == 2) from $table.streamTableCells().toList()
then
entityCreationService.bySemanticNode($tableCell, "PII", EntityType.RECOMMENDATION)
.ifPresent(redactionEntity -> redactionEntity.redact("ETC.11.0", "Trial Site owner and address found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
end
//------------------------------------ AI rules ------------------------------------ //------------------------------------ AI rules ------------------------------------
// Rule unit: AI.0 // Rule unit: AI.0
rule "AI.0.0: add all NER Entities of type CBI_author" rule "AI.0.0: Add all NER Entities of type CBI_author"
salience 999 salience 999
when when
nerEntities: NerEntities(hasEntitiesOfType("CBI_author")) nerEntities: NerEntities(hasEntitiesOfType("CBI_author"))
@ -1149,7 +1242,7 @@ rule "AI.0.0: add all NER Entities of type CBI_author"
// Rule unit: AI.1 // Rule unit: AI.1
rule "AI.1.0: combine and add NER Entities as CBI_address" rule "AI.1.0: Combine and add NER Entities as CBI_address"
salience 999 salience 999
when when
nerEntities: NerEntities(hasEntitiesOfType("ORG") || hasEntitiesOfType("STREET") || hasEntitiesOfType("CITY")) nerEntities: NerEntities(hasEntitiesOfType("ORG") || hasEntitiesOfType("STREET") || hasEntitiesOfType("CITY"))
@ -1159,7 +1252,7 @@ rule "AI.1.0: combine and add NER Entities as CBI_address"
// Rule unit: AI.2 // Rule unit: AI.2
rule "AI.2.0: add all NER Entities of any type except CBI_author" rule "AI.2.0: Add all NER Entities of any type except CBI_author"
salience 999 salience 999
when when
nerEntities: NerEntities() nerEntities: NerEntities()
@ -1170,6 +1263,16 @@ rule "AI.2.0: add all NER Entities of any type except CBI_author"
end end
// Rule unit: AI.3
rule "AI.3.0: Recommend authors from AI as PII"
salience 999
when
nerEntities: NerEntities(hasEntitiesOfType("CBI_author"))
then
nerEntities.streamEntitiesOfType("CBI_author")
.forEach(nerEntity -> entityCreationService.byNerEntity(nerEntity, "PII", EntityType.RECOMMENDATION, document));
end
//------------------------------------ Manual redaction rules ------------------------------------ //------------------------------------ Manual redaction rules ------------------------------------
// Rule unit: MAN.0 // Rule unit: MAN.0
@ -1267,7 +1370,6 @@ rule "MAN.3.0: Apply entity recategorization"
retract($entityToBeRecategorized); retract($entityToBeRecategorized);
end end
rule "MAN.3.1: Apply entity recategorization of same type" rule "MAN.3.1: Apply entity recategorization of same type"
salience 128 salience 128
when when
@ -1279,7 +1381,6 @@ rule "MAN.3.1: Apply entity recategorization of same type"
retract($recategorization); retract($recategorization);
end end
rule "MAN.3.2: Apply image recategorization" rule "MAN.3.2: Apply image recategorization"
salience 128 salience 128
when when
@ -1317,7 +1418,7 @@ rule "MAN.4.1: Apply legal basis change"
//------------------------------------ Entity merging rules ------------------------------------ //------------------------------------ Entity merging rules ------------------------------------
// Rule unit: X.0 // Rule unit: X.0
rule "X.0.0: remove Entity contained by Entity of same type" rule "X.0.0: Remove Entity contained by Entity of same type"
salience 65 salience 65
when when
$larger: TextEntity($type: type, $entityType: entityType, active()) $larger: TextEntity($type: type, $entityType: entityType, active())
@ -1329,7 +1430,7 @@ rule "X.0.0: remove Entity contained by Entity of same type"
// Rule unit: X.1 // Rule unit: X.1
rule "X.1.0: merge intersecting Entities of same type" rule "X.1.0: Merge intersecting Entities of same type"
salience 64 salience 64
when when
$first: TextEntity($type: type, $entityType: entityType, !resized(), active()) $first: TextEntity($type: type, $entityType: entityType, !resized(), active())
@ -1345,7 +1446,7 @@ rule "X.1.0: merge intersecting Entities of same type"
// Rule unit: X.2 // Rule unit: X.2
rule "X.2.0: remove Entity of type ENTITY when contained by FALSE_POSITIVE" rule "X.2.0: Remove Entity of type ENTITY when contained by FALSE_POSITIVE"
salience 64 salience 64
when when
$falsePositive: TextEntity($type: type, entityType == EntityType.FALSE_POSITIVE, active()) $falsePositive: TextEntity($type: type, entityType == EntityType.FALSE_POSITIVE, active())
@ -1358,7 +1459,7 @@ rule "X.2.0: remove Entity of type ENTITY when contained by FALSE_POSITIVE"
// Rule unit: X.3 // Rule unit: X.3
rule "X.3.0: remove Entity of type RECOMMENDATION when contained by FALSE_RECOMMENDATION" rule "X.3.0: Remove Entity of type RECOMMENDATION when contained by FALSE_RECOMMENDATION"
salience 64 salience 64
when when
$falseRecommendation: TextEntity($type: type, entityType == EntityType.FALSE_RECOMMENDATION, active()) $falseRecommendation: TextEntity($type: type, entityType == EntityType.FALSE_RECOMMENDATION, active())
@ -1370,7 +1471,7 @@ rule "X.3.0: remove Entity of type RECOMMENDATION when contained by FALSE_RECOMM
// Rule unit: X.4 // Rule unit: X.4
rule "X.4.0: remove Entity of type RECOMMENDATION when intersected by ENTITY with same type" rule "X.4.0: Remove Entity of type RECOMMENDATION when intersected by ENTITY with same type"
salience 256 salience 256
when when
$entity: TextEntity($type: type, (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active()) $entity: TextEntity($type: type, (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
@ -1383,7 +1484,7 @@ rule "X.4.0: remove Entity of type RECOMMENDATION when intersected by ENTITY wit
// Rule unit: X.5 // Rule unit: X.5
rule "X.5.0: remove Entity of type RECOMMENDATION when contained by ENTITY" rule "X.5.0: Remove Entity of type RECOMMENDATION when contained by ENTITY"
salience 256 salience 256
when when
$entity: TextEntity((entityType == EntityType.ENTITY || entityType == EntityType.HINT), active()) $entity: TextEntity((entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
@ -1395,7 +1496,7 @@ rule "X.5.0: remove Entity of type RECOMMENDATION when contained by ENTITY"
// Rule unit: X.6 // Rule unit: X.6
rule "X.6.0: remove Entity of lower rank, when contained by by entity of type ENTITY" rule "X.6.0: Remove Entity of lower rank, when contained by by entity of type ENTITY"
salience 32 salience 32
when when
$higherRank: TextEntity($type: type, (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active()) $higherRank: TextEntity($type: type, (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
@ -1422,7 +1523,7 @@ rule "X.6.1: remove Entity of higher rank, when intersected by entity of type EN
//------------------------------------ File attributes rules ------------------------------------ //------------------------------------ File attributes rules ------------------------------------
// Rule unit: FA.1 // Rule unit: FA.1
rule "FA.1.0: remove duplicate FileAttributes" rule "FA.1.0: Remove duplicate FileAttributes"
salience 64 salience 64
when when
$fileAttribute: FileAttribute($label: label, $value: value) $fileAttribute: FileAttribute($label: label, $value: value)
@ -1435,7 +1536,7 @@ rule "FA.1.0: remove duplicate FileAttributes"
//------------------------------------ Local dictionary search rules ------------------------------------ //------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRu
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*; import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
@ -64,8 +65,10 @@ global Dictionary dictionary
query "getFileAttributes" query "getFileAttributes"
$fileAttribute: FileAttribute() $fileAttribute: FileAttribute()
end end
//---------------------------------------------------------------------------
//------------------------------------ H rules ------------------------------------
// Rule unit: H.0
rule "H.0.0: retract table of contents page" rule "H.0.0: retract table of contents page"
when when
$page: Page(getMainBodyTextBlock().getSearchText().contains("........") || (getMainBodyTextBlock().getSearchText().contains("APPENDICES") && getMainBodyTextBlock().getSearchText().contains("TABLES"))) $page: Page(getMainBodyTextBlock().getSearchText().contains("........") || (getMainBodyTextBlock().getSearchText().contains("APPENDICES") && getMainBodyTextBlock().getSearchText().contains("TABLES")))
@ -75,6 +78,7 @@ rule "H.0.0: retract table of contents page"
end end
// Rule unit: H.1
rule "H.1.0: Ignore Table of Contents" rule "H.1.0: Ignore Table of Contents"
salience 10 salience 10
when when
@ -86,7 +90,7 @@ rule "H.1.0: Ignore Table of Contents"
end end
// Rule unit: MAN.0 // Rule unit: H.2
rule "H.2.0: Show headlines" rule "H.2.0: Show headlines"
when when
$headline: Headline() $headline: Headline()
@ -95,6 +99,7 @@ rule "H.2.0: Show headlines"
end end
// Rule unit: H.3
rule "H.3.0: Study Type File Attribute" rule "H.3.0: Study Type File Attribute"
when when
not FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","438","439","471","487")) not FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","438","439","471","487"))
@ -112,6 +117,9 @@ rule "H.3.0: Study Type File Attribute"
end end
//------------------------------------ General documine rules ------------------------------------
// Rule unit: DOC.1
rule "DOC.1.0: Guidelines" rule "DOC.1.0: Guidelines"
when when
$section: Section( $section: Section(
@ -171,7 +179,6 @@ rule "DOC.1.0: Guidelines"
); );
end end
rule "DOC.1.2: Guidelines" rule "DOC.1.2: Guidelines"
when when
$section: Section( $section: Section(
@ -197,7 +204,6 @@ rule "DOC.1.2: Guidelines"
}); });
end end
rule "DOC.1.3: Guidelines" rule "DOC.1.3: Guidelines"
when when
$section: Section( $section: Section(
@ -227,6 +233,7 @@ rule "DOC.1.3: Guidelines"
end end
// Rule unit: DOC.2
rule "DOC.2.0: Report number" rule "DOC.2.0: Report number"
when when
$section: Section(containsString("LABORATORY PROJECT ID") , containsString("Report Number:")) $section: Section(containsString("LABORATORY PROJECT ID") , containsString("Report Number:"))
@ -237,6 +244,7 @@ rule "DOC.2.0: Report number"
end end
// Rule unit: DOC.3
rule "DOC.3.0: Experimental Starting Date" rule "DOC.3.0: Experimental Starting Date"
when when
$section: Section(containsString("Experimental I. Starting Date:") || containsString("Experimental II. Starting Date:") || containsStringIgnoreCase("experimental start date") || containsStringIgnoreCase("experimental starting date")) $section: Section(containsString("Experimental I. Starting Date:") || containsString("Experimental II. Starting Date:") || containsStringIgnoreCase("experimental start date") || containsStringIgnoreCase("experimental starting date"))
@ -257,6 +265,7 @@ rule "DOC.3.0: Experimental Starting Date"
end end
// Rule unit: DOC.4
rule "DOC.4.0: Experimental Completion Date" rule "DOC.4.0: Experimental Completion Date"
when when
$section: Section(containsStringIgnoreCase("experimental termination date") || containsStringIgnoreCase("experimental completion date")) $section: Section(containsStringIgnoreCase("experimental termination date") || containsStringIgnoreCase("experimental completion date"))
@ -275,7 +284,8 @@ rule "DOC.4.0: Experimental Completion Date"
end end
rule "DOC.5.0: Ignore species and strain in irrelevant study types" // Rule unit: DOC.5
rule "DOC.5.0: Ignore species and strain in irrelevant study types"
salience 1 salience 1
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("406","428","438","439","471","474","487")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("406","428","438","439","471","474","487"))
@ -287,8 +297,7 @@ rule "DOC.4.0: Experimental Completion Date"
}); });
end end
rule "DOC.5.1: Hide all skipped species and strains except in the relevant sections"
rule "DOC.5.1: Hide all skipped species and strains except in the relevant sections"
salience 1 salience 1
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436"))
@ -307,7 +316,6 @@ rule "DOC.4.0: Experimental Completion Date"
}); });
end end
rule "DOC.5.2: Species" rule "DOC.5.2: Species"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436"))
@ -319,7 +327,6 @@ rule "DOC.5.2: Species"
}); });
end end
rule "DOC.5.3: Strain" rule "DOC.5.3: Strain"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436"))
@ -339,20 +346,21 @@ rule "DOC.5.3: Strain"
end end
// Rule unit: DOC.6
rule "DOC.6.0: study title by document structure" rule "DOC.6.0: study title by document structure"
when when
$table: Table(onPage(1), $table: Table(onPage(1),
(containsString("Final Report") || containsString("SPL")), (containsString("Final Report") || containsString("SPL")),
numberOfRows == 1, numberOfRows == 1,
numberOfCols == 1) numberOfCols == 1)
$tableCell: TableCell(row == 1, col == 1) from $table.streamTableCells().toList()
$paragraph: Paragraph(previousSibling.isPresent(), nextSibling.isPresent()) from $tableCell.streamChildren().toList()
then then
entityCreationService.bySemanticNode($paragraph, "title", EntityType.ENTITY).ifPresent(entity -> {
entityCreationService.bySemanticNode($table.getCell(0, 0).streamChildren().toList().get(1), "title", EntityType.ENTITY).ifPresent(entity -> {
entity.apply("DOC.6.0", "Study title found", "n-a"); entity.apply("DOC.6.0", "Study title found", "n-a");
}); });
end end
rule "DOC.6.1: study title" rule "DOC.6.1: study title"
when when
$table: Table(onPage(1), (containsString("Final Report") || containsString("SPL"))) $table: Table(onPage(1), (containsString("Final Report") || containsString("SPL")))
@ -362,7 +370,6 @@ rule "DOC.6.1: study title"
}); });
end end
rule "DOC.6.2: study title" rule "DOC.6.2: study title"
when when
not Table(onPage(1), (containsString("Final Report") || containsString("SPL"))) not Table(onPage(1), (containsString("Final Report") || containsString("SPL")))
@ -374,7 +381,7 @@ rule "DOC.6.2: study title"
end end
// Rule unit: DOC.7
rule "DOC.7.0: Performing Laboratory (Name)" rule "DOC.7.0: Performing Laboratory (Name)"
when when
$section: Section(containsString("PERFORMING LABORATORY:")) $section: Section(containsString("PERFORMING LABORATORY:"))
@ -384,8 +391,7 @@ rule "DOC.7.0: Performing Laboratory (Name)"
}); });
end end
rule "DOC.7.1: Performing Laboratory (Country)"
rule "DOC.7.1: Performing Laboratory (Country)"
when when
nerEntities: NerEntities(hasEntitiesOfType("COUNTRY")) nerEntities: NerEntities(hasEntitiesOfType("COUNTRY"))
$section: Section(containsString("PERFORMING LABORATORY:")) $section: Section(containsString("PERFORMING LABORATORY:"))
@ -399,7 +405,6 @@ rule "DOC.7.0: Performing Laboratory (Name)"
}); });
end end
rule "DOC.7.2: Performing Laboratory (Country & Name) from dict" rule "DOC.7.2: Performing Laboratory (Country & Name) from dict"
when when
$section: Section( $section: Section(
@ -415,7 +420,6 @@ rule "DOC.7.2: Performing Laboratory (Country & Name) from dict"
}); });
end end
rule "DOC.7.3: Performing Laboratory (Country) from dict" rule "DOC.7.3: Performing Laboratory (Country) from dict"
when when
$section: Section( $section: Section(
@ -430,6 +434,7 @@ rule "DOC.7.3: Performing Laboratory (Country) from dict"
end end
// Rule unit: DOC.8
rule "DOC.8.0: GLP Study" rule "DOC.8.0: GLP Study"
when when
$headline: Headline(containsString("GOOD LABORATORY PRACTICE COMPLIANCE") $headline: Headline(containsString("GOOD LABORATORY PRACTICE COMPLIANCE")
@ -447,6 +452,7 @@ rule "DOC.8.0: GLP Study"
end end
// Rule unit: DOC.9
rule "DOC.9.0: Batch number from CoA" rule "DOC.9.0: Batch number from CoA"
when when
$section: Section( $section: Section(
@ -485,7 +491,6 @@ rule "DOC.9.0: Batch number from CoA"
}); });
end end
rule "DOC.9.1: Batch number" rule "DOC.9.1: Batch number"
when when
$section: Section( $section: Section(
@ -518,7 +523,6 @@ rule "DOC.9.1: Batch number"
}); });
end end
rule "DOC.9.2: Batch number" rule "DOC.9.2: Batch number"
when when
$section: Section( $section: Section(
@ -551,8 +555,7 @@ rule "DOC.9.2: Batch number"
end end
// Rule unit: DOC.10
rule "DOC.10.0: Conclusions - LD50, LC50, Confidence" rule "DOC.10.0: Conclusions - LD50, LC50, Confidence"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","425","436")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","425","436"))
@ -586,6 +589,7 @@ rule "DOC.10.0: Conclusions - LD50, LC50, Confidence"
end end
// Rule unit: DOC.11
rule "DOC.11.0: Guideline Deviation" rule "DOC.11.0: Guideline Deviation"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","471")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","471"))
@ -611,7 +615,6 @@ rule "DOC.11.0: Guideline Deviation"
}); });
end end
rule "DOC.11.1: Guideline Deviation in text" rule "DOC.11.1: Guideline Deviation in text"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","471")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","471"))
@ -626,6 +629,7 @@ rule "DOC.11.1: Guideline Deviation in text"
end end
// Rule unit: DOC.12
rule "DOC.12.0: Clinical Signs" rule "DOC.12.0: Clinical Signs"
when when
FileAttribute(label == "OECD Number", value == "425") FileAttribute(label == "OECD Number", value == "425")
@ -636,6 +640,7 @@ rule "DOC.12.0: Clinical Signs"
end end
// Rule unit: DOC.13
rule "DOC.13.0: Dosages" rule "DOC.13.0: Dosages"
when when
FileAttribute(label == "OECD Number", value == "425") FileAttribute(label == "OECD Number", value == "425")
@ -656,6 +661,7 @@ rule "DOC.13.0: Dosages"
end end
// Rule unit: DOC.14
rule "DOC.14.0: Mortality" rule "DOC.14.0: Mortality"
when when
$headline: Headline(containsString("Mortality") && !containsString("TABLE")) $headline: Headline(containsString("Mortality") && !containsString("TABLE"))
@ -666,6 +672,7 @@ rule "DOC.14.0: Mortality"
end end
// Rule unit: DOC.15
rule "DOC.15.0: Study Conclusion" rule "DOC.15.0: Study Conclusion"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","471")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","404","405","425","429","436","471"))
@ -678,6 +685,7 @@ rule "DOC.15.0: Study Conclusion"
end end
// Rule unit: DOC.16
rule "DOC.16.0: Weight Behavior Changes" rule "DOC.16.0: Weight Behavior Changes"
when when
FileAttribute(label == "OECD Number", value == "402") FileAttribute(label == "OECD Number", value == "402")
@ -696,6 +704,7 @@ rule "DOC.16.0: Weight Behavior Changes"
end end
// Rule unit: DOC.17
rule "DOC.17.0: Necropsy findings" rule "DOC.17.0: Necropsy findings"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","436")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","403","436"))
@ -715,6 +724,7 @@ rule "DOC.17.0: Necropsy findings"
end end
// Rule unit: DOC.18
rule "DOC.18.0: Clinical observations" rule "DOC.18.0: Clinical observations"
when when
FileAttribute(label == "OECD Number", value == "403") FileAttribute(label == "OECD Number", value == "403")
@ -735,6 +745,7 @@ rule "DOC.18.0: Clinical observations"
end end
// Rule unit: DOC.19
rule "DOC.19.0: Bodyweight changes" rule "DOC.19.0: Bodyweight changes"
when when
FileAttribute(label == "OECD Number", value == "403") FileAttribute(label == "OECD Number", value == "403")
@ -745,6 +756,7 @@ rule "DOC.19.0: Bodyweight changes"
end end
// Rule unit: DOC.20
rule "DOC.20.0: Study Design" rule "DOC.20.0: Study Design"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","404","405","406","428","429","438","439","474","487")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("402","404","405","406","428","429","438","439","474","487"))
@ -757,7 +769,6 @@ rule "DOC.20.0: Study Design"
.forEach(entity -> entity.apply("DOC.20.0", "Study design section found", "n-a")); .forEach(entity -> entity.apply("DOC.20.0", "Study design section found", "n-a"));
end end
rule "DOC.20.1: Study Design" rule "DOC.20.1: Study Design"
when when
Headline(containsStringIgnoreCase("Study Design"), $sectionIdentifier: getSectionIdentifier()) Headline(containsStringIgnoreCase("Study Design"), $sectionIdentifier: getSectionIdentifier())
@ -770,6 +781,7 @@ rule "DOC.20.1: Study Design"
end end
// Rule unit: DOC.21
rule "DOC.21.0: Results and Conclusion (406, 428, 438, 439, 474 & 487)" rule "DOC.21.0: Results and Conclusion (406, 428, 438, 439, 474 & 487)"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("406","428","438","439","474","487")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("406","428","438","439","474","487"))
@ -784,7 +796,6 @@ rule "DOC.21.0: Results and Conclusion (406, 428, 438, 439, 474 & 487)"
.forEach(entity -> entity.apply("DOC.21.0", "Results and Conclusion found", "n-a")); .forEach(entity -> entity.apply("DOC.21.0", "Results and Conclusion found", "n-a"));
end end
rule "DOC.21.1: Results and Conclusion (406, 428, 438, 439, 474 & 487)" rule "DOC.21.1: Results and Conclusion (406, 428, 438, 439, 474 & 487)"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("406","428","438","439","474","487")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("406","428","438","439","474","487"))
@ -800,6 +811,7 @@ rule "DOC.21.1: Results and Conclusion (406, 428, 438, 439, 474 & 487)"
end end
// Rule unit: DOC.22
rule "DOC.22.0: Detailing (404 & 405)" rule "DOC.22.0: Detailing (404 & 405)"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("404","405")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("404","405"))
@ -814,6 +826,7 @@ rule "DOC.22.0: Detailing (404 & 405)"
end end
// Rule unit: DOC.23
rule "DOC.23.0: Preliminary Test Results (429)" rule "DOC.23.0: Preliminary Test Results (429)"
when when
FileAttribute(label == "OECD Number", value == "429") FileAttribute(label == "OECD Number", value == "429")
@ -827,6 +840,7 @@ rule "DOC.23.0: Preliminary Test Results (429)"
end end
// Rule unit: DOC.24
rule "DOC.24.0: Test Results (429)" rule "DOC.24.0: Test Results (429)"
when when
FileAttribute(label == "OECD Number", value == "429") FileAttribute(label == "OECD Number", value == "429")
@ -836,7 +850,6 @@ rule "DOC.24.0: Test Results (429)"
.forEach(entity -> entity.apply("DOC.24.0", "Test Results found", "n-a")); .forEach(entity -> entity.apply("DOC.24.0", "Test Results found", "n-a"));
end end
rule "DOC.24.1: Test Results (429)" rule "DOC.24.1: Test Results (429)"
when when
Headline(containsStringIgnoreCase("RESULTS AND DISCUSSION"), $sectionIdentifierResultsAndDiscussion: getSectionIdentifier()) Headline(containsStringIgnoreCase("RESULTS AND DISCUSSION"), $sectionIdentifierResultsAndDiscussion: getSectionIdentifier())
@ -849,6 +862,7 @@ rule "DOC.24.1: Test Results (429)"
end end
// Rule unit: DOC.25
rule "DOC.25.0: Approach used (429)" rule "DOC.25.0: Approach used (429)"
when when
FileAttribute(label == "OECD Number", value == "429") FileAttribute(label == "OECD Number", value == "429")
@ -863,6 +877,7 @@ rule "DOC.25.0: Approach used (429)"
end end
// Rule unit: DOC.26
rule "DOC.26.0: Sex" rule "DOC.26.0: Sex"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("405","429")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("405","429"))
@ -885,6 +900,7 @@ rule "DOC.26.0: Sex"
end end
// Rule unit: DOC.27
rule "DOC.27.0: Animal Number 405" rule "DOC.27.0: Animal Number 405"
when when
FileAttribute(label == "OECD Number", value == "405") FileAttribute(label == "OECD Number", value == "405")
@ -910,6 +926,7 @@ rule "DOC.27.0: Animal Number 405"
end end
// Rule unit: DOC.28
rule "DOC.28.0: Animal Number 429" rule "DOC.28.0: Animal Number 429"
when when
FileAttribute(label == "OECD Number", value == "429") FileAttribute(label == "OECD Number", value == "429")
@ -935,7 +952,6 @@ rule "DOC.28.0: Animal Number 429"
}); });
end end
rule "DOC.28.1: No. Of animals - Fallback to appendix tables listing all individual animals for 429" rule "DOC.28.1: No. Of animals - Fallback to appendix tables listing all individual animals for 429"
when when
$keyword: String() from List.of("Animal Number", "Animal No.", "Animal number") $keyword: String() from List.of("Animal Number", "Animal No.", "Animal number")
@ -953,6 +969,7 @@ rule "DOC.28.1: No. Of animals - Fallback to appendix tables listing all individ
end end
// Rule unit: DOC.29
rule "DOC.29.0: 4h Exposure" rule "DOC.29.0: 4h Exposure"
when when
FileAttribute(label == "OECD Number", valueEqualsAnyOf("403","436")) FileAttribute(label == "OECD Number", valueEqualsAnyOf("403","436"))
@ -966,6 +983,7 @@ rule "DOC.29.0: 4h Exposure"
end end
// Rule unit: DOC.30
rule "DOC.30.0: Dilution of the test substance" rule "DOC.30.0: Dilution of the test substance"
when when
FileAttribute(label == "OECD Number", value == "404") FileAttribute(label == "OECD Number", value == "404")
@ -979,6 +997,7 @@ rule "DOC.30.0: Dilution of the test substance"
end end
// Rule unit: DOC.31
rule "DOC.31.0: Positive Control" rule "DOC.31.0: Positive Control"
when when
FileAttribute(label == "OECD Number", value == "429") FileAttribute(label == "OECD Number", value == "429")
@ -992,6 +1011,7 @@ rule "DOC.31.0: Positive Control"
end end
// Rule unit: DOC.32
rule "DOC.32.0: Mortality Statement" rule "DOC.32.0: Mortality Statement"
when when
FileAttribute(label == "OECD Number", value == "402") FileAttribute(label == "OECD Number", value == "402")
@ -1002,6 +1022,7 @@ rule "DOC.32.0: Mortality Statement"
end end
// Rule unit: DOC.33
rule "DOC.33.0: Dose Mortality" rule "DOC.33.0: Dose Mortality"
when when
FileAttribute(label == "OECD Number", value == "425") FileAttribute(label == "OECD Number", value == "425")
@ -1045,6 +1066,7 @@ rule "DOC.33.0: Dose Mortality"
end end
// Rule unit: DOC.34
rule "DOC.34.0: Results (Main Study)" rule "DOC.34.0: Results (Main Study)"
when when
FileAttribute(label == "OECD Number", value == "429") FileAttribute(label == "OECD Number", value == "429")
@ -1059,6 +1081,7 @@ rule "DOC.34.0: Results (Main Study)"
end end
// Rule unit: DOC.35
rule "DOC.35.0: Doses (mg/kg bodyweight)" rule "DOC.35.0: Doses (mg/kg bodyweight)"
when when
FileAttribute(label == "OECD Number", value == "402") FileAttribute(label == "OECD Number", value == "402")
@ -1070,6 +1093,7 @@ rule "DOC.35.0: Doses (mg/kg bodyweight)"
.forEach(entity -> entity.apply("DOC.35.0", "Doses per bodyweight information found", "n-a")); .forEach(entity -> entity.apply("DOC.35.0", "Doses per bodyweight information found", "n-a"));
end end
//------------------------------------ Manual redaction rules ------------------------------------ //------------------------------------ Manual redaction rules ------------------------------------
// Rule unit: MAN.0 // Rule unit: MAN.0
@ -1212,11 +1236,10 @@ rule "MAN.4.1: Apply legal basis change"
end end
//------------------------------------ Entity merging rules ------------------------------------ //------------------------------------ Entity merging rules ------------------------------------
// Rule unit: X.0 // Rule unit: X.0
rule "X.0.0: remove Entity contained by Entity of same type" rule "X.0.0: Remove Entity contained by Entity of same type"
salience 65 salience 65
when when
$larger: TextEntity($type: type, $entityType: entityType, active()) $larger: TextEntity($type: type, $entityType: entityType, active())
@ -1228,7 +1251,7 @@ rule "X.0.0: remove Entity contained by Entity of same type"
// Rule unit: X.2 // Rule unit: X.2
rule "X.2.0: remove Entity of type ENTITY when contained by FALSE_POSITIVE" rule "X.2.0: Remove Entity of type ENTITY when contained by FALSE_POSITIVE"
salience 64 salience 64
when when
$falsePositive: TextEntity($type: type, entityType == EntityType.FALSE_POSITIVE, active()) $falsePositive: TextEntity($type: type, entityType == EntityType.FALSE_POSITIVE, active())
@ -1241,7 +1264,7 @@ rule "X.2.0: remove Entity of type ENTITY when contained by FALSE_POSITIVE"
// Rule unit: X.3 // Rule unit: X.3
rule "X.3.0: remove Entity of type RECOMMENDATION when contained by FALSE_RECOMMENDATION" rule "X.3.0: Remove Entity of type RECOMMENDATION when contained by FALSE_RECOMMENDATION"
salience 64 salience 64
when when
$falseRecommendation: TextEntity($type: type, entityType == EntityType.FALSE_RECOMMENDATION, active()) $falseRecommendation: TextEntity($type: type, entityType == EntityType.FALSE_RECOMMENDATION, active())
@ -1253,7 +1276,7 @@ rule "X.3.0: remove Entity of type RECOMMENDATION when contained by FALSE_RECOMM
// Rule unit: X.4 // Rule unit: X.4
rule "X.4.0: remove Entity of type RECOMMENDATION when intersected by ENTITY with same type" rule "X.4.0: Remove Entity of type RECOMMENDATION when intersected by ENTITY with same type"
salience 256 salience 256
when when
$entity: TextEntity($type: type, (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active()) $entity: TextEntity($type: type, (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
@ -1266,7 +1289,7 @@ rule "X.4.0: remove Entity of type RECOMMENDATION when intersected by ENTITY wit
// Rule unit: X.5 // Rule unit: X.5
rule "X.5.0: remove Entity of type RECOMMENDATION when contained by ENTITY" rule "X.5.0: Remove Entity of type RECOMMENDATION when contained by ENTITY"
salience 256 salience 256
when when
$entity: TextEntity((entityType == EntityType.ENTITY || entityType == EntityType.HINT), active()) $entity: TextEntity((entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
@ -1291,8 +1314,7 @@ rule "X.7.0: remove all images"
//------------------------------------ File attributes rules ------------------------------------ //------------------------------------ File attributes rules ------------------------------------
// Rule unit: FA.1 // Rule unit: FA.1
rule "FA.1.0: remove duplicate FileAttributes" rule "FA.1.0: Remove duplicate FileAttributes"
salience 64 salience 64
when when
$fileAttribute: FileAttribute($label: label, $value: value) $fileAttribute: FileAttribute($label: label, $value: value)
@ -1302,8 +1324,10 @@ rule "FA.1.0: remove duplicate FileAttributes"
end end
//------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRu
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*; import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
@ -210,7 +211,7 @@ rule "MAN.4.1: Apply legal basis change"
//------------------------------------ Local dictionary search rules ------------------------------------ //------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRu
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*; import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
@ -1136,7 +1137,7 @@ rule "FA.1.0: remove duplicate FileAttributes"
//------------------------------------ Local dictionary search rules ------------------------------------ //------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRu
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*; import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
@ -349,7 +350,7 @@ rule "FA.1.0: remove duplicate FileAttributes"
//------------------------------------ Local dictionary search rules ------------------------------------ //------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when

View File

@ -16,6 +16,7 @@ import com.iqser.red.service.redaction.v1.server.document.graph.*;
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.*; import com.iqser.red.service.redaction.v1.server.document.graph.nodes.*;
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Section; import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Section;
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Table; import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Table;
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.TableCell;
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.document.graph.nodes.SemanticNode;
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Document; import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Document;
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.document.graph.nodes.Paragraph;
@ -724,7 +725,7 @@ rule "FA.1.0: remove duplicate FileAttributes"
//------------------------------------ Local dictionary search rules ------------------------------------ //------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LDS.0 // Rule unit: LDS.0
rule "LDS.0.0: run local dictionary search" rule "LDS.0.0: Run local dictionary search"
agenda-group "LOCAL_DICTIONARY_ADDS" agenda-group "LOCAL_DICTIONARY_ADDS"
salience -999 salience -999
when when