Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ab0ff5f50 | ||
|
|
64cc23a883 | ||
|
|
76bf6773db | ||
|
|
e3992f169a | ||
|
|
bcd469bb65 | ||
|
|
0b3298e6e2 | ||
|
|
078dc2c3c3 | ||
|
|
4dda7ae543 | ||
|
|
4d514d0e5e | ||
|
|
1f12f9571f | ||
|
|
5312d5ffdf | ||
|
|
e43e8bccbf | ||
|
|
54250583b1 | ||
|
|
bb80b7ae75 | ||
|
|
25264f1450 | ||
|
|
e8a4ef172c |
@@ -93,11 +93,6 @@ public class PlanSpec {
|
||||
.description("Resultparser")
|
||||
.resultDirectories("**/test-reports/*.xml, **/target/surefire-reports/*.xml, **/target/failsafe-reports/*.xml")
|
||||
.enabled(true),
|
||||
new ScriptTask()
|
||||
.description("Sonar")
|
||||
.location(Location.FILE)
|
||||
.fileFromPath("bamboo-specs/src/main/resources/scripts/sonar-java.sh")
|
||||
.argument(SERVICE_NAME),
|
||||
new InjectVariablesTask()
|
||||
.description("Inject git Tag")
|
||||
.path("git.tag")
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SERVICE_NAME=$1
|
||||
|
||||
echo "dependency-check:aggregate"
|
||||
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
|
||||
--no-transfer-progress \
|
||||
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
|
||||
org.owasp:dependency-check-maven:aggregate
|
||||
|
||||
if [[ -z "${bamboo_repository_pr_key}" ]]
|
||||
then
|
||||
echo "Sonar Scan for branch: ${bamboo_planRepository_1_branch}"
|
||||
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
|
||||
--no-transfer-progress \
|
||||
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
|
||||
sonar:sonar \
|
||||
-Dsonar.projectKey=RED_$SERVICE_NAME \
|
||||
-Dsonar.host.url=https://sonarqube.iqser.com \
|
||||
-Dsonar.login=${bamboo_sonarqube_api_token_secret} \
|
||||
-Dsonar.branch.name=${bamboo_planRepository_1_branch} \
|
||||
-Dsonar.dependencyCheck.jsonReportPath=target/dependency-check-report.json \
|
||||
-Dsonar.dependencyCheck.xmlReportPath=target/dependency-check-report.xml \
|
||||
-Dsonar.dependencyCheck.htmlReportPath=target/dependency-check-report.html
|
||||
|
||||
else
|
||||
echo "Sonar Scan for PR with key1: ${bamboo_repository_pr_key}"
|
||||
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
|
||||
--no-transfer-progress \
|
||||
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
|
||||
sonar:sonar \
|
||||
-Dsonar.projectKey=RED_$SERVICE_NAME \
|
||||
-Dsonar.host.url=https://sonarqube.iqser.com \
|
||||
-Dsonar.login=${bamboo_sonarqube_api_token_secret} \
|
||||
-Dsonar.pullrequest.key=${bamboo_repository_pr_key} \
|
||||
-Dsonar.pullrequest.branch=${bamboo_repository_pr_sourceBranch} \
|
||||
-Dsonar.pullrequest.base=${bamboo_repository_pr_targetBranch} \
|
||||
-Dsonar.dependencyCheck.jsonReportPath=target/dependency-check-report.json \
|
||||
-Dsonar.dependencyCheck.xmlReportPath=target/dependency-check-report.xml \
|
||||
-Dsonar.dependencyCheck.htmlReportPath=target/dependency-check-report.html
|
||||
fi
|
||||
@@ -13,7 +13,6 @@ RUN apt-get update \
|
||||
wget cabextract xfonts-utils fonts-liberation \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl http://ftp.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.8_all.deb -o /tmp/ttf-mscorefonts-installer_3.8_all.deb \
|
||||
RUN curl http://ftp.br.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.8_all.deb -o /tmp/ttf-mscorefonts-installer_3.8_all.deb \
|
||||
&& dpkg -i /tmp/ttf-mscorefonts-installer_3.8_all.deb \
|
||||
&& rm /tmp/ttf-mscorefonts-installer_3.8_all.deb \
|
||||
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.iqser.red.service.redaction.v1.model;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Change {
|
||||
|
||||
private ChangeType type;
|
||||
private OffsetDateTime dateTime;
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
package com.iqser.red.service.redaction.v1.model;
|
||||
|
||||
public enum ChangeType {
|
||||
ADDED, REMOVED
|
||||
ADDED, REMOVED, CHANGED
|
||||
}
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ public class ManualLegalBasisChange {
|
||||
private String user;
|
||||
private Status status;
|
||||
private String legalBasis;
|
||||
private String section;
|
||||
|
||||
private OffsetDateTime requestDate;
|
||||
private OffsetDateTime processedDate;
|
||||
|
||||
-1
@@ -23,7 +23,6 @@ public class ManualRedactionEntry {
|
||||
private String legalBasis;
|
||||
private List<Rectangle> positions = new ArrayList<>();
|
||||
private Status status;
|
||||
private String section;
|
||||
|
||||
private boolean addToDictionary;
|
||||
private boolean addToDossierDictionary;
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package com.iqser.red.service.redaction.v1.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RedactionChangeLog {
|
||||
|
||||
private List<RedactionChangeLogEntry> redactionLogEntry = new ArrayList<>();
|
||||
|
||||
private long dictionaryVersion = -1;
|
||||
private long dossierDictionaryVersion = -1;
|
||||
private long rulesVersion = -1;
|
||||
private long legalBasisVersion = -1;
|
||||
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
package com.iqser.red.service.redaction.v1.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RedactionChangeLogEntry {
|
||||
|
||||
private String id;
|
||||
private String type;
|
||||
private String value;
|
||||
private String reason;
|
||||
private int matchedRule;
|
||||
private String legalBasis;
|
||||
private boolean redacted;
|
||||
private boolean isHint;
|
||||
private boolean isRecommendation;
|
||||
private String section;
|
||||
private float[] color;
|
||||
|
||||
@Builder.Default
|
||||
private List<Rectangle> positions = new ArrayList<>();
|
||||
private int sectionNumber;
|
||||
private boolean manual;
|
||||
private Status status;
|
||||
private ManualRedactionType manualRedactionType;
|
||||
private boolean isDictionaryEntry;
|
||||
|
||||
private String textBefore;
|
||||
private String textAfter;
|
||||
|
||||
@Builder.Default
|
||||
private List<Comment> comments = new ArrayList<>();
|
||||
|
||||
private ChangeType changeType;
|
||||
|
||||
private boolean isDossierDictionaryEntry;
|
||||
|
||||
private boolean excluded;
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.iqser.red.service.redaction.v1.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RedactionLogChanges {
|
||||
|
||||
private RedactionLog redactionLog;
|
||||
private boolean hasChanges;
|
||||
|
||||
}
|
||||
+4
@@ -58,4 +58,8 @@ public class RedactionLogEntry {
|
||||
private String recategorizationType;
|
||||
private String legalBasisChangeValue;
|
||||
|
||||
@EqualsAndHashCode.Exclude
|
||||
@Builder.Default
|
||||
private List<Change> changes = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
||||
-2
@@ -20,6 +20,4 @@ public class RedactionRequest {
|
||||
private ManualRedactions manualRedactions;
|
||||
@Builder.Default
|
||||
private Set<Integer> excludedPages = new HashSet<>();
|
||||
|
||||
private boolean withSectionDataForManualRedactions;
|
||||
}
|
||||
|
||||
+1
-5
@@ -27,11 +27,7 @@ public class SectionArea {
|
||||
private String header;
|
||||
|
||||
public boolean contains(Rectangle other) {
|
||||
return page == other.getPage()
|
||||
&& topLeft.getX() <= other.getTopLeft().getX()
|
||||
&& topLeft.getX() + getWidth() >= other.getTopLeft().getX() + other.getWidth()
|
||||
&& getTopLeft().getY() <= other.getTopLeft().getY()
|
||||
&& getTopLeft().getY() + getHeight() >= other.getTopLeft().getY() + other.getHeight();
|
||||
return page == other.getPage() && this.topLeft.getX() <= other.getTopLeft().getX() && this.topLeft.getX() + this.getWidth() >= other.getTopLeft().getX() + other.getWidth() && this.getTopLeft().getY() <= other.getTopLeft().getY() && this.getTopLeft().getY() + this.getHeight() >= other.getTopLeft().getY() + other.getHeight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-14
@@ -3,9 +3,10 @@ package com.iqser.red.service.redaction.v1.model;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@@ -14,16 +15,4 @@ public class SectionGrid {
|
||||
|
||||
private Map<Integer, List<SectionRectangle>> rectanglesPerPage = new HashMap<>();
|
||||
|
||||
private List<SectionGridSection> sections = new ArrayList<>();
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
public static class SectionGridSection {
|
||||
|
||||
private final int sectionNumber;
|
||||
private final String headline;
|
||||
private final Set<Integer> pages;
|
||||
private final List<SectionArea> sectionAreas;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+5
-8
@@ -1,6 +1,10 @@
|
||||
package com.iqser.red.service.redaction.v1.model;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,11 +31,4 @@ public class SectionRectangle {
|
||||
|
||||
private List<CellRectangle> tableCells;
|
||||
|
||||
public boolean contains(Rectangle other) {
|
||||
return topLeft.getX() <= other.getTopLeft().getX()
|
||||
&& topLeft.getX() + getWidth() >= other.getTopLeft().getX() + other.getWidth()
|
||||
&& getTopLeft().getY() <= other.getTopLeft().getY()
|
||||
&& getTopLeft().getY() + getHeight() >= other.getTopLeft().getY() + other.getHeight();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<dependency>
|
||||
<groupId>com.iqser.red.service</groupId>
|
||||
<artifactId>file-management-service-api-v1</artifactId>
|
||||
<version>2.80.15</version>
|
||||
<version>2.25.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.iqser.red.service</groupId>
|
||||
|
||||
+18
-56
@@ -1,7 +1,5 @@
|
||||
package com.iqser.red.service.redaction.v1.server.classification.service;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.FloatFrequencyCounter;
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.Orientation;
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.Page;
|
||||
@@ -18,7 +16,6 @@ import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -28,12 +25,9 @@ public class BlockificationService {
|
||||
|
||||
static final float THRESHOLD = 1f;
|
||||
|
||||
|
||||
public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines,
|
||||
List<Ruling> verticalRulingLines) {
|
||||
|
||||
sortRotatedSequences(textPositions);
|
||||
|
||||
List<TextPositionSequence> chunkWords = new ArrayList<>();
|
||||
List<AbstractTextContainer> chunkBlockList1 = new ArrayList<>();
|
||||
|
||||
@@ -56,7 +50,7 @@ public class BlockificationService {
|
||||
if (prev != null && (lineSeparation || startFromTop || splitByX || newLineAfterSplit || splittedByRuling)) {
|
||||
|
||||
Orientation prevOrientation = null;
|
||||
if (!chunkBlockList1.isEmpty()) {
|
||||
if(!chunkBlockList1.isEmpty()) {
|
||||
prevOrientation = chunkBlockList1.get(chunkBlockList1.size() - 1).getOrientation();
|
||||
}
|
||||
|
||||
@@ -68,11 +62,15 @@ public class BlockificationService {
|
||||
wasSplitted = true;
|
||||
cb1.setOrientation(Orientation.LEFT);
|
||||
splitX1 = word.getX1();
|
||||
} else if (newLineAfterSplit && !splittedByRuling) {
|
||||
} else
|
||||
|
||||
if (newLineAfterSplit && !splittedByRuling) {
|
||||
wasSplitted = false;
|
||||
cb1.setOrientation(Orientation.RIGHT);
|
||||
splitX1 = null;
|
||||
} else if (prevOrientation != null && prevOrientation.equals(Orientation.RIGHT) && (lineSeparation || !startFromTop || !splitByX || !newLineAfterSplit || !splittedByRuling)) {
|
||||
} else
|
||||
|
||||
if(prevOrientation != null && prevOrientation.equals(Orientation.RIGHT) && (lineSeparation || !startFromTop || !splitByX || !newLineAfterSplit || !splittedByRuling)){
|
||||
cb1.setOrientation(Orientation.LEFT);
|
||||
}
|
||||
|
||||
@@ -112,18 +110,16 @@ public class BlockificationService {
|
||||
while (itty.hasNext()) {
|
||||
TextBlock block = (TextBlock) itty.next();
|
||||
|
||||
if (previousLeft != null && block.getOrientation().equals(Orientation.LEFT)) {
|
||||
if (previousLeft.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousLeft
|
||||
.getMinY()) {
|
||||
if(previousLeft != null && block.getOrientation().equals(Orientation.LEFT)){
|
||||
if (previousLeft.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousLeft.getMinY()){
|
||||
previousLeft.add(block);
|
||||
itty.remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (previousRight != null && block.getOrientation().equals(Orientation.RIGHT)) {
|
||||
if (previousRight.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousRight
|
||||
.getMinY()) {
|
||||
if(previousRight != null && block.getOrientation().equals(Orientation.RIGHT)){
|
||||
if (previousRight.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousRight.getMinY()){
|
||||
previousRight.add(block);
|
||||
itty.remove();
|
||||
continue;
|
||||
@@ -137,16 +133,16 @@ public class BlockificationService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
itty = chunkBlockList1.iterator();
|
||||
TextBlock previous = null;
|
||||
while (itty.hasNext()) {
|
||||
TextBlock block = (TextBlock) itty.next();
|
||||
|
||||
if (previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation()
|
||||
.equals(Orientation.LEFT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY()) || previous != null && previous
|
||||
.getOrientation()
|
||||
.equals(Orientation.LEFT) && block.getOrientation()
|
||||
.equals(Orientation.RIGHT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY())) {
|
||||
if(previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation().equals(Orientation.LEFT) && equalsWithThreshold(block.getMaxY(), previous
|
||||
.getMaxY())||
|
||||
previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation().equals(Orientation.RIGHT) && equalsWithThreshold(block.getMaxY(), previous
|
||||
.getMaxY())){
|
||||
previous.add(block);
|
||||
itty.remove();
|
||||
continue;
|
||||
@@ -155,12 +151,11 @@ public class BlockificationService {
|
||||
previous = block;
|
||||
}
|
||||
|
||||
|
||||
return new Page(chunkBlockList1);
|
||||
}
|
||||
|
||||
|
||||
private boolean equalsWithThreshold(float f1, float f2) {
|
||||
|
||||
private boolean equalsWithThreshold(float f1, float f2){
|
||||
return Math.abs(f1 - f2) < THRESHOLD;
|
||||
}
|
||||
|
||||
@@ -202,13 +197,6 @@ public class BlockificationService {
|
||||
textBlock.setHighestFontSize(fontSizeFrequencyCounter.getHighest());
|
||||
}
|
||||
|
||||
if (textBlock != null && textBlock.getSequences() != null && textBlock.getSequences()
|
||||
.stream()
|
||||
.map(t -> round(t.getY1(), 3))
|
||||
.collect(toSet())
|
||||
.size() == 1) {
|
||||
textBlock.getSequences().sort(Comparator.comparing(TextPositionSequence::getX1));
|
||||
}
|
||||
return textBlock;
|
||||
}
|
||||
|
||||
@@ -303,30 +291,4 @@ public class BlockificationService {
|
||||
return new Rectangle(minY, minX, maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
|
||||
private void sortRotatedSequences(List<TextPositionSequence> sequences) {
|
||||
|
||||
List<TextPositionSequence> rotatedWords = new ArrayList<>();
|
||||
Iterator<TextPositionSequence> itty = sequences.iterator();
|
||||
while (itty.hasNext()) {
|
||||
var pos = itty.next();
|
||||
if (pos.getTextPositions().get(0).getDir() == 270) {
|
||||
rotatedWords.add(pos);
|
||||
itty.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (!rotatedWords.isEmpty() && !sequences.isEmpty()) {
|
||||
rotatedWords.sort(Comparator.comparing(TextPositionSequence::getX1));
|
||||
}
|
||||
sequences.addAll(rotatedWords);
|
||||
}
|
||||
|
||||
|
||||
private double round(float value, int decimalPoints) {
|
||||
|
||||
var d = Math.pow(10, decimalPoints);
|
||||
return Math.round(value * d) / d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-5
@@ -73,10 +73,8 @@ public class ClassificationService {
|
||||
}
|
||||
} else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock) && textBlock.getMostPopularWordFontSize() > document
|
||||
.getFontSizeCounter()
|
||||
.getMostPopular() && PositionUtils.getApproxLineCount(textBlock) < 4.9 && (textBlock.getMostPopularWordStyle()
|
||||
.equals("bold") || !document.getFontStyleCounter().getCountPerValue().containsKey("bold") && textBlock.getMostPopularWordFontSize() > document
|
||||
.getFontSizeCounter()
|
||||
.getMostPopular() + 1) && textBlock.getSequences().get(0).getTextPositions().get(0).getFontSizeInPt() >= textBlock.getMostPopularWordFontSize()) {
|
||||
.getMostPopular() && PositionUtils.getApproxLineCount(textBlock) < 4.9 && textBlock.getMostPopularWordStyle()
|
||||
.equals("bold")) {
|
||||
|
||||
for (int i = 1; i <= headlineFontSizes.size(); i++) {
|
||||
if (textBlock.getMostPopularWordFontSize() == headlineFontSizes.get(i - 1)) {
|
||||
@@ -88,7 +86,7 @@ public class ClassificationService {
|
||||
.startsWith("Figure ") && PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock) && textBlock.getMostPopularWordStyle()
|
||||
.equals("bold") && !document.getFontStyleCounter()
|
||||
.getMostPopular()
|
||||
.equals("bold") && PositionUtils.getApproxLineCount(textBlock) < 2.9 && textBlock.getSequences().get(0).getTextPositions().get(0).getFontSizeInPt() >= textBlock.getMostPopularWordFontSize()) {
|
||||
.equals("bold") && PositionUtils.getApproxLineCount(textBlock) < 2.9) {
|
||||
textBlock.setClassification("H " + (headlineFontSizes.size() + 1));
|
||||
document.setHeadlines(true);
|
||||
} else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock) && textBlock.getMostPopularWordFontSize() == document
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.iqser.red.service.redaction.v1.server.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.server.client.model.EntityRecogintionEntity;
|
||||
import com.iqser.red.service.redaction.v1.server.client.model.EntityRecognitionRequest;
|
||||
|
||||
@FeignClient(name = "EntityRecognitionClient", url = "${entity-recognition-service.url}")
|
||||
public interface EntityRecognitionClient {
|
||||
|
||||
@PostMapping(value = "/find_authors", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
Map<String, Map<String, List<EntityRecogintionEntity>>> findAuthors(EntityRecognitionRequest entityRecognitionRequest);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.iqser.red.service.redaction.v1.server.client.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EntityRecogintionEntity {
|
||||
|
||||
private String value;
|
||||
private int startOffset;
|
||||
private int endOffset;
|
||||
private String type;
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.iqser.red.service.redaction.v1.server.client.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EntityRecognitionRequest {
|
||||
|
||||
private List<EntityRecognitionSection> data;
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.iqser.red.service.redaction.v1.server.client.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EntityRecognitionResponse {
|
||||
|
||||
@Builder.Default
|
||||
private Map<String, List<EntityRecogintionEntity>> result = new HashMap<>();
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.iqser.red.service.redaction.v1.server.client.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EntityRecognitionResult {
|
||||
|
||||
@Builder.Default
|
||||
private Map<Integer, List<EntityRecogintionEntity>> entities = new HashMap<>();
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.iqser.red.service.redaction.v1.server.client.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EntityRecognitionSection {
|
||||
|
||||
private int sectionNumber;
|
||||
private String text;
|
||||
}
|
||||
-8
@@ -1,7 +1,6 @@
|
||||
package com.iqser.red.service.redaction.v1.server.controller;
|
||||
|
||||
import com.iqser.red.commons.spring.ErrorMessage;
|
||||
import com.iqser.red.service.redaction.v1.server.exception.RedactionLogNotFoundException;
|
||||
import com.iqser.red.service.redaction.v1.server.exception.RulesValidationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -18,13 +17,6 @@ public class ControllerAdvice {
|
||||
|
||||
/* error handling */
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(value = RedactionLogNotFoundException.class)
|
||||
public ErrorMessage handleRedactionLogNotFoundException(RedactionLogNotFoundException e) {
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@ExceptionHandler(value = NullPointerException.class)
|
||||
|
||||
+4
-29
@@ -6,12 +6,12 @@ import com.iqser.red.service.redaction.v1.resources.RedactionResource;
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.Document;
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.Page;
|
||||
import com.iqser.red.service.redaction.v1.server.exception.RedactionException;
|
||||
import com.iqser.red.service.redaction.v1.server.exception.RedactionLogNotFoundException;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.service.AnnotationService;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.service.DictionaryService;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.service.DroolsExecutionService;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.service.RedactionLogMergeService;
|
||||
import com.iqser.red.service.redaction.v1.server.segmentation.PdfSegmentationService;
|
||||
import com.iqser.red.service.redaction.v1.server.settings.RedactionServiceSettings;
|
||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
|
||||
@@ -20,12 +20,12 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.pdfbox.io.MemoryUsageSetting;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@@ -147,44 +147,19 @@ public class RedactionController implements RedactionResource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedactionLog getRedactionLog(@RequestBody RedactionRequest redactionRequest) {
|
||||
public RedactionLog getRedactionLog(RedactionRequest redactionRequest) {
|
||||
|
||||
log.info("Requested preview for: {}", redactionRequest);
|
||||
dictionaryService.updateDictionary(redactionRequest.getDossierTemplateId(), redactionRequest.getDossierId());
|
||||
|
||||
SectionGrid sectionGrid = null;
|
||||
var redactionLog = redactionStorageService.getRedactionLog(redactionRequest.getDossierId(), redactionRequest.getFileId());
|
||||
|
||||
if (redactionLog == null) {
|
||||
throw new RedactionLogNotFoundException();
|
||||
}
|
||||
|
||||
|
||||
if (redactionRequest.isWithSectionDataForManualRedactions()) {
|
||||
sectionGrid = redactionStorageService.getSectionGrid(redactionRequest.getDossierId(), redactionRequest.getFileId());
|
||||
if (sectionGrid.getSections().isEmpty()) {
|
||||
|
||||
log.info("SectionGrid does not have headlines set. Computing headlines now!");
|
||||
var text = redactionStorageService.getText(redactionRequest.getDossierId(), redactionRequest.getFileId());
|
||||
|
||||
// enhance section grid with headline data
|
||||
for (var sectionText : text.getSectionTexts()) {
|
||||
sectionGrid.getSections().add(new SectionGrid.SectionGridSection(sectionText.getSectionNumber(),
|
||||
sectionText.getHeadline(),
|
||||
sectionText.getSectionAreas().stream().map(SectionArea::getPage).collect(Collectors.toSet()),
|
||||
sectionText.getSectionAreas()));
|
||||
}
|
||||
redactionStorageService.storeObject(redactionRequest.getDossierId(), redactionRequest.getFileId(), FileType.SECTION_GRID, sectionGrid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log.info("Loaded redaction log with computationalVersion: {}", redactionLog.getAnalysisVersion());
|
||||
if (redactionLog.getAnalysisVersion() == 0) {
|
||||
// old redaction logs are returned directly
|
||||
return redactionLog;
|
||||
} else {
|
||||
return redactionLogMergeService.mergeRedactionLogData(redactionLog, sectionGrid, redactionRequest.getDossierTemplateId(), redactionRequest.getManualRedactions(), redactionRequest.getExcludedPages());
|
||||
return redactionLogMergeService.mergeRedactionLogData(redactionLog, redactionRequest.getDossierTemplateId(), redactionRequest.getManualRedactions(), redactionRequest.getExcludedPages());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package com.iqser.red.service.redaction.v1.server.exception;
|
||||
|
||||
public class RedactionLogNotFoundException extends RuntimeException {
|
||||
|
||||
public RedactionLogNotFoundException() {
|
||||
super("RedactionLog not found!");
|
||||
}
|
||||
|
||||
}
|
||||
+32
-82
@@ -1,33 +1,16 @@
|
||||
package com.iqser.red.service.redaction.v1.server.parsing;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.model.PdfImage;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.apache.pdfbox.contentstream.operator.Operator;
|
||||
import org.apache.pdfbox.contentstream.operator.OperatorName;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingColor;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingColorN;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingColorSpace;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingDeviceCMYKColor;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingDeviceGrayColor;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingDeviceRGBColor;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetStrokingColor;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetStrokingColorN;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetStrokingColorSpace;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetStrokingDeviceCMYKColor;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetStrokingDeviceGrayColor;
|
||||
import org.apache.pdfbox.contentstream.operator.color.SetStrokingDeviceRGBColor;
|
||||
import org.apache.pdfbox.contentstream.operator.state.SetFlatness;
|
||||
import org.apache.pdfbox.contentstream.operator.state.SetLineCapStyle;
|
||||
import org.apache.pdfbox.contentstream.operator.state.SetLineDashPattern;
|
||||
import org.apache.pdfbox.contentstream.operator.state.SetLineJoinStyle;
|
||||
import org.apache.pdfbox.contentstream.operator.state.SetLineMiterLimit;
|
||||
import org.apache.pdfbox.contentstream.operator.state.SetLineWidth;
|
||||
import org.apache.pdfbox.contentstream.operator.state.SetRenderingIntent;
|
||||
import org.apache.pdfbox.contentstream.operator.color.*;
|
||||
import org.apache.pdfbox.contentstream.operator.state.*;
|
||||
import org.apache.pdfbox.contentstream.operator.text.SetFontAndSize;
|
||||
import org.apache.pdfbox.cos.COSBase;
|
||||
import org.apache.pdfbox.cos.COSName;
|
||||
@@ -40,14 +23,12 @@ import org.apache.pdfbox.text.PDFTextStripper;
|
||||
import org.apache.pdfbox.text.TextPosition;
|
||||
import org.apache.pdfbox.util.Matrix;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.server.parsing.model.RedTextPosition;
|
||||
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.model.PdfImage;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
@@ -208,19 +189,16 @@ public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
COSName objectName = (COSName) arguments.get(0);
|
||||
PDXObject xobject = getResources().getXObject(objectName);
|
||||
if (xobject instanceof PDImageXObject) {
|
||||
PDImageXObject image = (PDImageXObject) xobject;
|
||||
PDImageXObject image = (PDImageXObject)xobject;
|
||||
Matrix ctmNew = getGraphicsState().getCurrentTransformationMatrix();
|
||||
|
||||
Rectangle2D rect = new Rectangle2D.Float(ctmNew.getTranslateX(), ctmNew.getTranslateY(), ctmNew.getScaleX(), ctmNew
|
||||
.getScaleY());
|
||||
Rectangle2D rect = new Rectangle2D.Float(ctmNew.getTranslateX(), ctmNew.getTranslateY(), ctmNew.getScaleX(), ctmNew.getScaleY());
|
||||
|
||||
// Memory Hack - sofReference kills me
|
||||
FieldUtils.writeField(image, "cachedImageSubsampling", -1, true);
|
||||
|
||||
if (rect.getHeight() > 2 && rect.getWidth() > 2) {
|
||||
this.images.add(new PdfImage(image.getImage(), rect, pageNumber, image.getImage()
|
||||
.getColorModel()
|
||||
.hasAlpha()));
|
||||
this.images.add(new PdfImage(image.getImage(), rect, pageNumber, image.getImage().getColorModel().hasAlpha()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -229,6 +207,8 @@ public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private float floatValue(COSBase value) {
|
||||
|
||||
if (value instanceof COSNumber) {
|
||||
@@ -267,16 +247,8 @@ public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
public void writeString(String text, List<TextPosition> textPositions) throws IOException {
|
||||
|
||||
int startIndex = 0;
|
||||
RedTextPosition previous = null;
|
||||
|
||||
for (int i = 0; i <= textPositions.size() - 1; i++) {
|
||||
|
||||
if (!textPositionSequences.isEmpty()) {
|
||||
previous = textPositionSequences.get(textPositionSequences.size() - 1)
|
||||
.getTextPositions()
|
||||
.get(textPositionSequences.get(textPositionSequences.size() - 1).getTextPositions().size() - 1);
|
||||
}
|
||||
|
||||
int charWidth = (int) textPositions.get(i).getWidthDirAdj();
|
||||
if (charWidth < minCharWidth) {
|
||||
minCharWidth = charWidth;
|
||||
@@ -295,54 +267,42 @@ public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
|
||||
if (i == 0 && (textPositions.get(i).getUnicode().equals(" ") || textPositions.get(i)
|
||||
.getUnicode()
|
||||
.equals("\u00A0") || textPositions.get(i)
|
||||
.getUnicode()
|
||||
.equals("\t"))) {
|
||||
.equals("\u00A0"))) {
|
||||
startIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Strange but sometimes this is happening, for example: Metolachlor2.pdf
|
||||
if (i > 0 && textPositions.get(i).getXDirAdj() < textPositions.get(i - 1).getXDirAdj()) {
|
||||
if (i > 0 && textPositions.get(i).getX() < textPositions.get(i - 1).getX()) {
|
||||
List<TextPosition> sublist = textPositions.subList(startIndex, i);
|
||||
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0)
|
||||
.getUnicode()
|
||||
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0") || sublist.get(0).getUnicode().equals("\t")))) {
|
||||
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) {
|
||||
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
|
||||
}
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
if (textPositions.get(i).getRotation() == 0 && i > 0 && textPositions.get(i)
|
||||
.getX() > textPositions.get(i - 1).getEndX() + 1) {
|
||||
|
||||
if (textPositions.get(i).getRotation() == 0 && i > 0 && textPositions.get(i).getX() > textPositions.get(i - 1).getEndX() + 1) {
|
||||
List<TextPosition> sublist = textPositions.subList(startIndex, i);
|
||||
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0)
|
||||
.getUnicode()
|
||||
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0") || sublist.get(0).getUnicode().equals("\t")))) {
|
||||
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) {
|
||||
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
|
||||
}
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
|
||||
if (i > 0 && (textPositions.get(i).getUnicode().equals(" ") || textPositions.get(i)
|
||||
.getUnicode()
|
||||
.equals("\u00A0") || textPositions.get(i)
|
||||
.getUnicode()
|
||||
.equals("\t")) && i <= textPositions.size() - 2) {
|
||||
.equals("\u00A0")) && i <= textPositions.size() - 2) {
|
||||
List<TextPosition> sublist = textPositions.subList(startIndex, i);
|
||||
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0)
|
||||
.getUnicode()
|
||||
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0") || sublist.get(0).getUnicode().equals("\t")))) {
|
||||
|
||||
// Remove false sequence ends (whitespaces)
|
||||
if (previous != null && sublist.get(0).getYDirAdj() == previous.getYDirAdj() && sublist.get(0)
|
||||
.getXDirAdj() - (previous.getXDirAdj() + previous.getWidthDirAdj()) < 0.01) {
|
||||
for (TextPosition t : sublist) {
|
||||
textPositionSequences.get(textPositionSequences.size() - 1).add(t);
|
||||
}
|
||||
} else {
|
||||
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
|
||||
}
|
||||
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) {
|
||||
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
|
||||
}
|
||||
startIndex = i + 1;
|
||||
}
|
||||
@@ -351,23 +311,13 @@ public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
List<TextPosition> sublist = textPositions.subList(startIndex, textPositions.size());
|
||||
if (!sublist.isEmpty() && (sublist.get(sublist.size() - 1)
|
||||
.getUnicode()
|
||||
.equals(" ") || sublist.get(sublist.size() - 1).getUnicode().equals("\u00A0") || sublist.get(sublist.size() - 1).getUnicode().equals("\t"))) {
|
||||
.equals(" ") || sublist.get(sublist.size() - 1).getUnicode().equals("\u00A0"))) {
|
||||
sublist = sublist.subList(0, sublist.size() - 1);
|
||||
}
|
||||
|
||||
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0).getUnicode().equals(" ") || sublist.get(0)
|
||||
.getUnicode()
|
||||
.equals("\u00A0") || sublist.get(0)
|
||||
.getUnicode()
|
||||
.equals("\t")))) {
|
||||
if (previous != null && sublist.get(0).getYDirAdj() == previous.getYDirAdj() && sublist.get(0)
|
||||
.getXDirAdj() - (previous.getXDirAdj() + previous.getWidthDirAdj()) < 0.01) {
|
||||
for (TextPosition t : sublist) {
|
||||
textPositionSequences.get(textPositionSequences.size() - 1).add(t);
|
||||
}
|
||||
} else {
|
||||
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
|
||||
}
|
||||
.equals("\u00A0")))) {
|
||||
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
|
||||
}
|
||||
super.writeString(text);
|
||||
}
|
||||
|
||||
-2
@@ -21,8 +21,6 @@ public class RedTextPosition {
|
||||
private float YDirAdj;
|
||||
private float width;
|
||||
private float heightDir;
|
||||
private float widthDirAdj;
|
||||
private float dir;
|
||||
|
||||
// not used in reanalysis
|
||||
@JsonIgnore
|
||||
|
||||
+3
-34
@@ -1,7 +1,5 @@
|
||||
package com.iqser.red.service.redaction.v1.server.parsing.model;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.iqser.red.service.redaction.v1.model.Point;
|
||||
@@ -138,13 +136,6 @@ public class TextPositionSequence implements CharSequence {
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnore
|
||||
public float getRotationAdjustedX() {
|
||||
|
||||
return textPositions.get(0).getXDirAdj();
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnore
|
||||
public float getY1() {
|
||||
|
||||
@@ -242,7 +233,7 @@ public class TextPositionSequence implements CharSequence {
|
||||
float posYInit;
|
||||
float posYEnd;
|
||||
|
||||
if (textPositions.get(0).getRotation() == 90 && textPositions.get(0).getDir() != 0.0f) {
|
||||
if (textPositions.get(0).getRotation() == 90) {
|
||||
posXEnd = textPositions.get(0).getYDirAdj() + 2;
|
||||
posYInit = getY1();
|
||||
posYEnd = textPositions.get(textPositions.size() - 1).getXDirAdj() - height + 4;
|
||||
@@ -253,31 +244,9 @@ public class TextPositionSequence implements CharSequence {
|
||||
posXInit = textPositions.get(0).getPageWidth() - textPositions.get(0).getYDirAdj() - 2;
|
||||
posXEnd = textPositions.get(0).getPageWidth() - textPositions.get(textPositions.size() - 1)
|
||||
.getYDirAdj() + height;
|
||||
} else if(textPositions.get(0).getRotation() == 0 && textPositions.get(0).getDir() == 270f) {
|
||||
posYInit = textPositions.get(0).getPageHeight() - getX1();
|
||||
posYEnd = textPositions.get(0).getPageHeight() - getX2() - textPositions.get(0)
|
||||
.getWidthDirAdj() - textPositions.get(textPositions.size() - 1).getWidthDirAdj() - 3;
|
||||
posXInit = textPositions.get(0).getPageWidth() - textPositions.get(0).getYDirAdj() - 2;
|
||||
posXEnd = textPositions.get(0).getPageWidth() - textPositions.get(textPositions.size() - 1)
|
||||
.getYDirAdj() + height;
|
||||
} else if(textPositions.get(0).getRotation() == 90 && textPositions.get(0).getDir() == 0.0f){
|
||||
posXInit = textPositions.get(textPositions.size() - 1)
|
||||
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getHeightDir();
|
||||
posXEnd = textPositions.get(0).getXDirAdj();
|
||||
posYInit = textPositions.get(0).getPageHeight() - textPositions.get(0).getYDirAdj() - 2;
|
||||
posYEnd = textPositions.get(0).getPageHeight() - textPositions.get(textPositions.size() - 1)
|
||||
.getYDirAdj() + 2;
|
||||
} else if(textPositions.get(0).getRotation() == 0 && textPositions.get(0).getDir() == 90f){
|
||||
posYInit = getX1();
|
||||
posYEnd = getX2() + textPositions.get(0)
|
||||
.getWidthDirAdj() - textPositions.get(textPositions.size() - 1).getWidthDirAdj() - 3;
|
||||
posXInit = textPositions.get(0).getYDirAdj() + 2;
|
||||
posXEnd = textPositions.get(textPositions.size() - 1)
|
||||
.getYDirAdj() - height;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
posXEnd = textPositions.get(textPositions.size() - 1)
|
||||
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidthDirAdj() + 1;
|
||||
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidth() + 1;
|
||||
posYInit = textPositions.get(0).getPageHeight() - textPositions.get(0).getYDirAdj() - 2;
|
||||
posYEnd = textPositions.get(0).getPageHeight() - textPositions.get(textPositions.size() - 1)
|
||||
.getYDirAdj() + 2;
|
||||
|
||||
+2
-10
@@ -1,12 +1,10 @@
|
||||
package com.iqser.red.service.redaction.v1.server.redaction.service;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.model.AnalyzeResult;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionChangeLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.server.settings.RedactionServiceSettings;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -17,15 +15,9 @@ public class AnalyzeResponseService {
|
||||
private final RedactionServiceSettings redactionServiceSettings;
|
||||
|
||||
public AnalyzeResult createAnalyzeResponse(String dossierId, String fileId, long duration, int pageCount,
|
||||
RedactionLog redactionLog, RedactionChangeLog redactionChangeLog) {
|
||||
RedactionLog redactionLog, boolean hasUpdates) {
|
||||
|
||||
|
||||
boolean hasUpdates = redactionChangeLog != null && redactionChangeLog.getRedactionLogEntry() != null && !redactionChangeLog
|
||||
.getRedactionLogEntry()
|
||||
.isEmpty() && redactionChangeLog.getRedactionLogEntry()
|
||||
.stream()
|
||||
.anyMatch(entry -> !entry.getType().equals("false_positive"));
|
||||
|
||||
return AnalyzeResult.builder()
|
||||
.dossierId(dossierId)
|
||||
.fileId(fileId)
|
||||
|
||||
+49
-8
@@ -2,14 +2,22 @@ package com.iqser.red.service.redaction.v1.server.redaction.service;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.model.*;
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.*;
|
||||
import com.iqser.red.service.redaction.v1.server.client.EntityRecognitionClient;
|
||||
import com.iqser.red.service.redaction.v1.server.client.model.EntityRecogintionEntity;
|
||||
import com.iqser.red.service.redaction.v1.server.client.model.EntityRecognitionRequest;
|
||||
import com.iqser.red.service.redaction.v1.server.client.model.EntityRecognitionResponse;
|
||||
import com.iqser.red.service.redaction.v1.server.client.model.EntityRecognitionSection;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.model.Dictionary;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.model.*;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.utils.EntitySearchUtils;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.utils.IdBuilder;
|
||||
import com.iqser.red.service.redaction.v1.server.settings.RedactionServiceSettings;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
@@ -28,6 +36,8 @@ public class EntityRedactionService {
|
||||
private final DictionaryService dictionaryService;
|
||||
private final DroolsExecutionService droolsExecutionService;
|
||||
private final SurroundingWordsService surroundingWordsService;
|
||||
private final EntityRecognitionClient entityRecognitionClient;
|
||||
private final RedactionServiceSettings redactionServiceSettings;
|
||||
|
||||
|
||||
public void processDocument(Document classifiedDoc, String dossierTemplateId, ManualRedactions manualRedactions,
|
||||
@@ -58,7 +68,8 @@ public class EntityRedactionService {
|
||||
}
|
||||
|
||||
|
||||
public Map<Integer, List<Entity>> convertToEnititesPerPage(Set<Entity> entities){
|
||||
public Map<Integer, List<Entity>> convertToEnititesPerPage(Set<Entity> entities) {
|
||||
|
||||
Map<Integer, List<Entity>> entitiesPerPage = new HashMap<>();
|
||||
for (Entity entity : entities) {
|
||||
Map<Integer, List<EntityPositionSequence>> sequenceOnPage = new HashMap<>();
|
||||
@@ -68,8 +79,7 @@ public class EntityRedactionService {
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, List<EntityPositionSequence>> entry : sequenceOnPage.entrySet()) {
|
||||
entitiesPerPage
|
||||
.computeIfAbsent(entry.getKey(), (x) -> new ArrayList<>())
|
||||
entitiesPerPage.computeIfAbsent(entry.getKey(), (x) -> new ArrayList<>())
|
||||
.add(new Entity(entity.getWord(), entity.getType(), entity.isRedaction(), entity.getRedactionReason(), entry
|
||||
.getValue(), entity.getHeadline(), entity.getMatchedRule(), entity.getSectionNumber(), entity
|
||||
.getLegalBasis(), entity.isDictionaryEntry(), entity.getTextBefore(), entity.getTextAfter(), entity
|
||||
@@ -80,17 +90,18 @@ public class EntityRedactionService {
|
||||
}
|
||||
|
||||
|
||||
public Map<Integer, Set<Entity>> getHintsPerSection(Set<Entity> entities, Dictionary dictionary){
|
||||
public Map<Integer, Set<Entity>> getHintsPerSection(Set<Entity> entities, Dictionary dictionary) {
|
||||
|
||||
Map<Integer, Set<Entity>> hintsPerSectionNumber = new HashMap<>();
|
||||
entities.stream().forEach(entity -> {
|
||||
if (dictionary.isHint(entity.getType()) && entity.isDictionaryEntry()) {
|
||||
hintsPerSectionNumber.computeIfAbsent(entity.getSectionNumber(), (x) -> new HashSet<>())
|
||||
.add(entity);
|
||||
hintsPerSectionNumber.computeIfAbsent(entity.getSectionNumber(), (x) -> new HashSet<>()).add(entity);
|
||||
}
|
||||
});
|
||||
return hintsPerSectionNumber;
|
||||
}
|
||||
|
||||
|
||||
private Set<Entity> findEntities(Document classifiedDoc, KieContainer kieContainer,
|
||||
ManualRedactions manualRedactions, Dictionary dictionary, boolean local,
|
||||
Map<Integer, Set<Entity>> hintsPerSectionNumber,
|
||||
@@ -148,7 +159,8 @@ public class EntityRedactionService {
|
||||
}
|
||||
|
||||
|
||||
public void addLocalValuesToDictionary(Section analysedSection, Dictionary dictionary){
|
||||
public void addLocalValuesToDictionary(Section analysedSection, Dictionary dictionary) {
|
||||
|
||||
analysedSection.getLocalDictionaryAdds().keySet().forEach(key -> {
|
||||
if (dictionary.isRecommendation(key)) {
|
||||
analysedSection.getLocalDictionaryAdds().get(key).forEach(value -> {
|
||||
@@ -393,11 +405,16 @@ public class EntityRedactionService {
|
||||
}
|
||||
}
|
||||
|
||||
if (redactionServiceSettings.isEnableEntityRecognition() && !local) {
|
||||
found.addAll(getAiEntities(sectionNumber, searchableString, headline));
|
||||
}
|
||||
|
||||
return EntitySearchUtils.clearAndFindPositions(found, searchableText, dictionary);
|
||||
}
|
||||
|
||||
|
||||
private Image convertAndRecategorize(PdfImage pdfImage, int sectionNumber, String headline, ManualRedactions manualRedactions) {
|
||||
private Image convertAndRecategorize(PdfImage pdfImage, int sectionNumber, String headline,
|
||||
ManualRedactions manualRedactions) {
|
||||
|
||||
Image image = Image.builder()
|
||||
.type(pdfImage.getImageType().equals(ImageType.OTHER) ? "image" : pdfImage.getImageType()
|
||||
@@ -423,4 +440,28 @@ public class EntityRedactionService {
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
private Set<Entity> getAiEntities(int sectionNumber, String searchableString, String headline) {
|
||||
|
||||
Set<Entity> found = new HashSet<>();
|
||||
|
||||
Map<String, Map<String, List<EntityRecogintionEntity>>> response = entityRecognitionClient.findAuthors(EntityRecognitionRequest
|
||||
.builder()
|
||||
.data(List.of(EntityRecognitionSection.builder()
|
||||
.sectionNumber(sectionNumber)
|
||||
.text(searchableString)
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
EntityRecognitionResponse entityRecognitionResponse = new EntityRecognitionResponse(response.get("result:"));
|
||||
|
||||
if (entityRecognitionResponse.getResult() != null && entityRecognitionResponse.getResult()
|
||||
.containsKey(String.valueOf(sectionNumber))) {
|
||||
entityRecognitionResponse.getResult().get(String.valueOf(sectionNumber)).forEach(res -> {
|
||||
found.add(new Entity(res.getValue(), res.getType(), res.getStartOffset(), res.getEndOffset(), headline, sectionNumber, false, false));
|
||||
});
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-28
@@ -14,9 +14,11 @@ import com.iqser.red.service.redaction.v1.server.redaction.utils.IdBuilder;
|
||||
import com.iqser.red.service.redaction.v1.server.segmentation.PdfSegmentationService;
|
||||
import com.iqser.red.service.redaction.v1.server.settings.RedactionServiceSettings;
|
||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -76,26 +78,17 @@ public class ReanalyzeService {
|
||||
log.info("Analyzed with rules {} and dictionary {} for dossierTemplate: {}", classifiedDoc.getRulesVersion(), classifiedDoc
|
||||
.getDictionaryVersion(), analyzeRequest.getDossierTemplateId());
|
||||
|
||||
// first create changelog - this only happens when we migrate files analyzed via the old process and we don't want to loose changeLog data
|
||||
var changeLog = redactionChangeLogService.createAndStoreChangeLog(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
|
||||
// store redactionLog
|
||||
var redactionLogChange = redactionChangeLogService.computeChanges(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
|
||||
redactionLog = redactionLogChange.getRedactionLog();
|
||||
|
||||
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.REDACTION_LOG, redactionLog);
|
||||
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.TEXT, new Text(pageCount, classifiedDoc
|
||||
.getSectionText()));
|
||||
|
||||
// enhance section grid with headline data
|
||||
classifiedDoc.getSectionText().forEach(sectionText -> {
|
||||
classifiedDoc
|
||||
.getSectionGrid().getSections().add(new SectionGrid.SectionGridSection(sectionText.getSectionNumber(),
|
||||
sectionText.getHeadline(),
|
||||
sectionText.getSectionAreas().stream().map(SectionArea::getPage).collect(Collectors.toSet()),
|
||||
sectionText.getSectionAreas()));
|
||||
});
|
||||
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.SECTION_GRID, classifiedDoc
|
||||
.getSectionGrid());
|
||||
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
return analyzeResponseService.createAnalyzeResponse(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), duration, pageCount, redactionLog, changeLog);
|
||||
return analyzeResponseService.createAnalyzeResponse(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), duration, pageCount, redactionLog, redactionLogChange.isHasChanges());
|
||||
}
|
||||
|
||||
|
||||
@@ -273,13 +266,13 @@ public class ReanalyzeService {
|
||||
|
||||
excludeExcludedPages(redactionLog, analyzeRequest.getExcludedPages());
|
||||
|
||||
var changeLog = redactionChangeLogService.createAndStoreChangeLog(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
|
||||
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.REDACTION_LOG, redactionLog);
|
||||
var redactionLogChange = redactionChangeLogService.computeChanges(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
|
||||
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.REDACTION_LOG, redactionLogChange.getRedactionLog());
|
||||
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
|
||||
return analyzeResponseService.createAnalyzeResponse(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), duration, text
|
||||
.getNumberOfPages(), redactionLog, changeLog);
|
||||
.getNumberOfPages(), redactionLogChange.getRedactionLog(), redactionLogChange.isHasChanges());
|
||||
}
|
||||
|
||||
|
||||
@@ -290,12 +283,12 @@ public class ReanalyzeService {
|
||||
}
|
||||
|
||||
return Stream.concat(manualRedactions.getManualLegalBasisChanges()
|
||||
.stream()
|
||||
.map(ManualLegalBasisChange::getId), Stream.concat(manualRedactions.getImageRecategorizations()
|
||||
.stream()
|
||||
.map(ManualImageRecategorization::getId), Stream.concat(manualRedactions.getIdsToRemove()
|
||||
.stream()
|
||||
.map(IdRemoval::getId), manualRedactions.getForceRedacts().stream().map(ManualForceRedact::getId))))
|
||||
.stream()
|
||||
.map(ManualLegalBasisChange::getId), Stream.concat(manualRedactions.getImageRecategorizations()
|
||||
.stream()
|
||||
.map(ManualImageRecategorization::getId), Stream.concat(manualRedactions.getIdsToRemove()
|
||||
.stream()
|
||||
.map(IdRemoval::getId), manualRedactions.getForceRedacts().stream().map(ManualForceRedact::getId))))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@@ -318,12 +311,10 @@ public class ReanalyzeService {
|
||||
|
||||
private void excludeExcludedPages(RedactionLog redactionLog, Set<Integer> excludedPages) {
|
||||
|
||||
if (excludedPages != null && !excludedPages.isEmpty()) {
|
||||
redactionLog.getRedactionLogEntry().forEach(entry -> entry.getPositions().forEach(pos -> {
|
||||
if (excludedPages.contains(pos.getPage())) {
|
||||
entry.setExcluded(true);
|
||||
}
|
||||
}));
|
||||
if(excludedPages != null && !excludedPages.isEmpty()) {
|
||||
redactionLog.getRedactionLogEntry().forEach(entry -> entry.getPositions().forEach(pos -> { if (excludedPages.contains(pos.getPage())) {
|
||||
entry.setExcluded(true);
|
||||
}}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+76
-69
@@ -1,19 +1,25 @@
|
||||
package com.iqser.red.service.redaction.v1.server.redaction.service;
|
||||
|
||||
import com.iqser.red.service.file.management.v1.api.model.FileType;
|
||||
import com.iqser.red.service.redaction.v1.model.ChangeType;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionChangeLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionChangeLogEntry;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
|
||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import com.iqser.red.service.redaction.v1.model.Change;
|
||||
import com.iqser.red.service.redaction.v1.model.ChangeType;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLogChanges;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
|
||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -22,76 +28,77 @@ public class RedactionChangeLogService {
|
||||
|
||||
private final RedactionStorageService redactionStorageService;
|
||||
|
||||
public RedactionChangeLog createAndStoreChangeLog(String dossierId, String fileId, RedactionLog currentRedactionLog) {
|
||||
|
||||
try {
|
||||
RedactionLog previousRedactionLog = redactionStorageService.getRedactionLog(dossierId, fileId);
|
||||
var changeLog = createChangeLog(currentRedactionLog, previousRedactionLog);
|
||||
redactionStorageService.storeObject(dossierId, fileId, FileType.REDACTION_CHANGELOG, changeLog);
|
||||
return changeLog;
|
||||
} catch (Exception e) {
|
||||
log.debug("Previous redaction log not available");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private RedactionChangeLog createChangeLog(RedactionLog currentRedactionLog, RedactionLog previousRedactionLog) {
|
||||
public RedactionLogChanges computeChanges(String dossierId, String fileId, RedactionLog currentRedactionLog) {
|
||||
|
||||
RedactionLog previousRedactionLog = redactionStorageService.getRedactionLog(dossierId, fileId);
|
||||
|
||||
if (previousRedactionLog == null) {
|
||||
return null;
|
||||
currentRedactionLog.getRedactionLogEntry().forEach(entry -> {
|
||||
entry.getChanges().add(new Change(ChangeType.ADDED, OffsetDateTime.now()));
|
||||
});
|
||||
return new RedactionLogChanges(currentRedactionLog, false);
|
||||
}
|
||||
|
||||
List<RedactionLogEntry> added = new ArrayList<>(currentRedactionLog.getRedactionLogEntry());
|
||||
added.removeAll(previousRedactionLog.getRedactionLogEntry());
|
||||
List<RedactionLogEntry> notRemovedPreviousEntries = previousRedactionLog.getRedactionLogEntry()
|
||||
.stream()
|
||||
.filter(entry -> !entry.getChanges()
|
||||
.get(entry.getChanges().size() - 1)
|
||||
.getType()
|
||||
.equals(ChangeType.REMOVED))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<RedactionLogEntry> removed = new ArrayList<>(previousRedactionLog.getRedactionLogEntry());
|
||||
Set<RedactionLogEntry> added = new HashSet<>(currentRedactionLog.getRedactionLogEntry());
|
||||
added.removeAll(notRemovedPreviousEntries);
|
||||
|
||||
Set<RedactionLogEntry> removed = new HashSet<>(notRemovedPreviousEntries);
|
||||
removed.removeAll(currentRedactionLog.getRedactionLogEntry());
|
||||
|
||||
List<RedactionChangeLogEntry> changeLogEntries = added.stream()
|
||||
.map(entry -> convert(entry, ChangeType.ADDED))
|
||||
.collect(Collectors.toList());
|
||||
changeLogEntries.addAll(removed.stream()
|
||||
.map(entry -> convert(entry, ChangeType.REMOVED))
|
||||
.collect(Collectors.toList()));
|
||||
Map<String, RedactionLogEntry> addedIds = new HashMap<>();
|
||||
added.forEach(entry -> {
|
||||
addedIds.put(entry.getId(), entry);
|
||||
});
|
||||
|
||||
return new RedactionChangeLog(changeLogEntries,
|
||||
currentRedactionLog.getDictionaryVersion(),
|
||||
currentRedactionLog.getDossierDictionaryVersion(),
|
||||
currentRedactionLog.getRulesVersion(),
|
||||
currentRedactionLog.getLegalBasisVersion());
|
||||
}
|
||||
Set<String> removedIds = new HashSet<>();
|
||||
removed.forEach(entry -> {
|
||||
removedIds.add(entry.getId());
|
||||
});
|
||||
|
||||
List<RedactionLogEntry> newRedactionLogEntries = previousRedactionLog.getRedactionLogEntry();
|
||||
|
||||
private RedactionChangeLogEntry convert(RedactionLogEntry entry, ChangeType changeType) {
|
||||
List<RedactionLogEntry> toRemove = new ArrayList<>();
|
||||
newRedactionLogEntries.forEach(entry -> {
|
||||
if (removedIds.contains(entry.getId()) && addedIds.containsKey(entry.getId())) {
|
||||
List<Change> changes = entry.getChanges();
|
||||
changes.add(new Change(ChangeType.CHANGED, OffsetDateTime.now()));
|
||||
var newEntry = addedIds.get(entry.getId());
|
||||
newEntry.setChanges(changes);
|
||||
addedIds.put(entry.getId(), newEntry);
|
||||
toRemove.add(entry);
|
||||
} else if (removedIds.contains(entry.getId())) {
|
||||
entry.getChanges().add(new Change(ChangeType.REMOVED, OffsetDateTime.now()));
|
||||
} else if (addedIds.containsKey(entry.getId())) {
|
||||
List<Change> changes = entry.getChanges();
|
||||
changes.add(new Change(ChangeType.ADDED, OffsetDateTime.now()));
|
||||
var newEntry = addedIds.get(entry.getId());
|
||||
newEntry.setChanges(changes);
|
||||
addedIds.put(entry.getId(), newEntry);
|
||||
toRemove.add(entry);
|
||||
}
|
||||
});
|
||||
|
||||
return RedactionChangeLogEntry.builder()
|
||||
.id(entry.getId())
|
||||
.type(entry.getType())
|
||||
.value(entry.getValue())
|
||||
.reason(entry.getReason())
|
||||
.matchedRule(entry.getMatchedRule())
|
||||
.legalBasis(entry.getLegalBasis())
|
||||
.redacted(entry.isRedacted())
|
||||
.isHint(entry.isHint())
|
||||
.isRecommendation(entry.isRecommendation())
|
||||
.section(entry.getSection())
|
||||
.color(entry.getColor())
|
||||
.positions(entry.getPositions())
|
||||
.sectionNumber(entry.getSectionNumber())
|
||||
.manual(entry.isManual())
|
||||
.status(entry.getStatus())
|
||||
.manualRedactionType(entry.getManualRedactionType())
|
||||
.isDictionaryEntry(entry.isDictionaryEntry())
|
||||
.textBefore(entry.getTextBefore())
|
||||
.textAfter(entry.getTextAfter())
|
||||
.comments(entry.getComments())
|
||||
.changeType(changeType)
|
||||
.isDossierDictionaryEntry(entry.isDossierDictionaryEntry())
|
||||
.excluded(entry.isExcluded())
|
||||
.build();
|
||||
newRedactionLogEntries.removeAll(toRemove);
|
||||
|
||||
addedIds.forEach((k, v) -> {
|
||||
if(v.getChanges().isEmpty()) {
|
||||
v.getChanges().add(new Change(ChangeType.ADDED, OffsetDateTime.now()));
|
||||
}
|
||||
newRedactionLogEntries.add(v);
|
||||
});
|
||||
|
||||
currentRedactionLog.setRedactionLogEntry(newRedactionLogEntries);
|
||||
|
||||
return new RedactionLogChanges(currentRedactionLog, !addedIds.isEmpty() || !removedIds.isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-9
@@ -79,9 +79,7 @@ public class RedactionLogCreatorService {
|
||||
.getX(), (float) image.getPosition().getY()), (float) image.getPosition()
|
||||
.getWidth(), (float) image.getPosition().getHeight(), pageNumber)))
|
||||
.sectionNumber(image.getSectionNumber())
|
||||
//.section(image.getSection())
|
||||
// RED-2622
|
||||
.section("Image:"+image.getType())
|
||||
.section(image.getSection())
|
||||
.imageHasTransparency(image.isHasTransparency())
|
||||
.build();
|
||||
|
||||
@@ -150,7 +148,7 @@ public class RedactionLogCreatorService {
|
||||
int startIndex = 0;
|
||||
for (int i = 1; i < textPositions.size(); i++) {
|
||||
float yDirAdj = textPositions.get(i).getYDirAdj();
|
||||
if (round(yDirAdj,3) != round(y, 3)) {
|
||||
if (yDirAdj != y) {
|
||||
rectangles.add(TextPositionSequence.fromData(textPositions.subList(startIndex, i), page)
|
||||
.getRectangle());
|
||||
y = yDirAdj;
|
||||
@@ -166,11 +164,6 @@ public class RedactionLogCreatorService {
|
||||
return rectangles;
|
||||
}
|
||||
|
||||
private double round(float value, int decimalPoints) {
|
||||
var d = Math.pow(10, decimalPoints);
|
||||
return Math.round(value * d) / d;
|
||||
}
|
||||
|
||||
|
||||
private RedactionLogEntry createRedactionLogEntry(Entity entity, String dossierTemplateId) {
|
||||
|
||||
|
||||
+28
-33
@@ -1,15 +1,31 @@
|
||||
package com.iqser.red.service.redaction.v1.server.redaction.service;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.model.*;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.model.Comment;
|
||||
import com.iqser.red.service.redaction.v1.model.IdRemoval;
|
||||
import com.iqser.red.service.redaction.v1.model.ManualForceRedact;
|
||||
import com.iqser.red.service.redaction.v1.model.ManualImageRecategorization;
|
||||
import com.iqser.red.service.redaction.v1.model.ManualLegalBasisChange;
|
||||
import com.iqser.red.service.redaction.v1.model.ManualRedactionEntry;
|
||||
import com.iqser.red.service.redaction.v1.model.ManualRedactionType;
|
||||
import com.iqser.red.service.redaction.v1.model.ManualRedactions;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
|
||||
import com.iqser.red.service.redaction.v1.model.Status;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -17,15 +33,15 @@ import java.util.stream.Collectors;
|
||||
public class RedactionLogMergeService {
|
||||
|
||||
private final DictionaryService dictionaryService;
|
||||
private final SectionTextService sectionTextService;
|
||||
|
||||
public RedactionLog mergeRedactionLogData(RedactionLog redactionLog, SectionGrid sectionGrid, String dossierTemplateId,
|
||||
|
||||
public RedactionLog mergeRedactionLogData(RedactionLog redactionLog, String dossierTemplateId,
|
||||
ManualRedactions manualRedactions, Set<Integer> excludedPages) {
|
||||
|
||||
log.info("Merging Redaction log with manual redactions {}", manualRedactions);
|
||||
if (manualRedactions != null) {
|
||||
|
||||
var manualRedactionLogEntries = addManualAddEntries(sectionGrid, manualRedactions.getEntriesToAdd(), manualRedactions.getComments(), dossierTemplateId);
|
||||
var manualRedactionLogEntries = addManualAddEntries(manualRedactions.getEntriesToAdd(), manualRedactions.getComments(), dossierTemplateId);
|
||||
|
||||
redactionLog.getRedactionLogEntry().addAll(manualRedactionLogEntries);
|
||||
|
||||
@@ -50,14 +66,6 @@ public class RedactionLogMergeService {
|
||||
|
||||
}
|
||||
|
||||
Set<String> processedIds = new HashSet<>();
|
||||
redactionLog.getRedactionLogEntry().removeIf(entry -> {
|
||||
if(processedIds.contains(entry.getId())){
|
||||
return true;
|
||||
}
|
||||
processedIds.add(entry.getId());
|
||||
return false;
|
||||
});
|
||||
return redactionLog;
|
||||
}
|
||||
|
||||
@@ -107,8 +115,6 @@ public class RedactionLogMergeService {
|
||||
if (imageRecategorization.getStatus().equals(Status.APPROVED)) {
|
||||
redactionLogEntry.setStatus(Status.APPROVED);
|
||||
redactionLogEntry.setType(imageRecategorization.getType());
|
||||
// RED-2622
|
||||
redactionLogEntry.setSection("Image:" + redactionLogEntry.getType());
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", recategorized by manual override");
|
||||
} else if (imageRecategorization.getStatus().equals(Status.REQUESTED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to recategorize");
|
||||
@@ -184,12 +190,8 @@ public class RedactionLogMergeService {
|
||||
String manualOverrideReason = null;
|
||||
if (manualLegalBasisChange.getStatus().equals(Status.APPROVED)) {
|
||||
redactionLogEntry.setStatus(Status.APPROVED);
|
||||
redactionLogEntry.setRedacted(true);
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis was manually changed");
|
||||
redactionLogEntry.setLegalBasis(manualLegalBasisChange.getLegalBasis());
|
||||
if (manualLegalBasisChange.getSection() != null) {
|
||||
redactionLogEntry.setSection(manualLegalBasisChange.getSection());
|
||||
}
|
||||
} else if (manualLegalBasisChange.getStatus().equals(Status.REQUESTED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis change requested");
|
||||
redactionLogEntry.setStatus(Status.REQUESTED);
|
||||
@@ -200,7 +202,6 @@ public class RedactionLogMergeService {
|
||||
redactionLogEntry.setStatus(Status.DECLINED);
|
||||
}
|
||||
|
||||
|
||||
redactionLogEntry.setManualRedactionUserId(manualLegalBasisChange.getUser());
|
||||
redactionLogEntry.setReason(manualOverrideReason);
|
||||
redactionLogEntry.setManual(true);
|
||||
@@ -225,8 +226,7 @@ public class RedactionLogMergeService {
|
||||
}
|
||||
|
||||
|
||||
private List<RedactionLogEntry> addManualAddEntries(SectionGrid sectionGrid,
|
||||
Set<ManualRedactionEntry> manualAdds,
|
||||
public List<RedactionLogEntry> addManualAddEntries(Set<ManualRedactionEntry> manualAdds,
|
||||
Map<String, List<Comment>> comments, String dossierTemplateId) {
|
||||
|
||||
List<RedactionLogEntry> redactionLogEntries = new ArrayList<>();
|
||||
@@ -234,15 +234,11 @@ public class RedactionLogMergeService {
|
||||
for (ManualRedactionEntry manualRedactionEntry : manualAdds) {
|
||||
|
||||
if (!approvedAndShouldBeInDictionary(manualRedactionEntry)) {
|
||||
|
||||
RedactionLogEntry redactionLogEntry = createRedactionLogEntry(manualRedactionEntry, manualRedactionEntry
|
||||
.getId(), dossierTemplateId);
|
||||
redactionLogEntry.setPositions(manualRedactionEntry.getPositions());
|
||||
redactionLogEntry.setComments(comments.get(manualRedactionEntry.getId()));
|
||||
|
||||
sectionTextService.handleSectionText(sectionGrid, redactionLogEntry);
|
||||
|
||||
redactionLogEntries.add(redactionLogEntry);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,15 +264,14 @@ public class RedactionLogMergeService {
|
||||
.isDossierDictionaryEntry(manualRedactionEntry.isAddToDossierDictionary())
|
||||
.legalBasis(manualRedactionEntry.getLegalBasis())
|
||||
.value(manualRedactionEntry.getValue())
|
||||
.section(manualRedactionEntry.getSection())
|
||||
.type(manualRedactionEntry.getType())
|
||||
.redacted(true)
|
||||
.isHint(false)
|
||||
.section(null)
|
||||
.sectionNumber(-1)
|
||||
.manual(true)
|
||||
.status(manualRedactionEntry.getStatus())
|
||||
.manualRedactionType(ManualRedactionType.ADD)
|
||||
.positions(manualRedactionEntry.getPositions())
|
||||
.manualRedactionUserId(manualRedactionEntry.getUser())
|
||||
.build();
|
||||
}
|
||||
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
package com.iqser.red.service.redaction.v1.server.redaction.service;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
|
||||
import com.iqser.red.service.redaction.v1.model.SectionGrid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SectionTextService {
|
||||
|
||||
|
||||
public void handleSectionText(SectionGrid sectionGrid, RedactionLogEntry redactionLogEntry) {
|
||||
|
||||
log.info("Handling manual redaction match for sections: {} and entry section: {}, positions: {}",
|
||||
sectionGrid != null ? sectionGrid.getSections().size() : "null", redactionLogEntry.getSection(), redactionLogEntry.getPositions());
|
||||
|
||||
if (redactionLogEntry.getSection() != null) {
|
||||
// set by UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (sectionGrid != null) {
|
||||
var firstPosition = !redactionLogEntry.getPositions().isEmpty() ? redactionLogEntry.getPositions().iterator().next() : null;
|
||||
|
||||
if (firstPosition != null) {
|
||||
|
||||
for (var section : sectionGrid.getSections()) {
|
||||
if (section.getPages().contains(firstPosition.getPage())) {
|
||||
for (var sectionArea : section.getSectionAreas()) {
|
||||
if (sectionArea.contains(firstPosition)) {
|
||||
redactionLogEntry.setSection(section.getHeadline());
|
||||
redactionLogEntry.setSectionNumber(section.getSectionNumber());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -17,4 +17,6 @@ public class RedactionServiceSettings {
|
||||
|
||||
private int analysisVersion = 1;
|
||||
|
||||
private boolean enableEntityRecognition = true;
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -83,6 +83,7 @@ public class RedactionStorageService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum StorageType {
|
||||
PARSED_DOCUMENT(".json");
|
||||
|
||||
@@ -4,6 +4,7 @@ info:
|
||||
configuration-service.url: "http://configuration-service-v1:8080"
|
||||
file-management-service.url: "http://file-management-service-v1:8080"
|
||||
image-service.url: "http://image-service-v1:8080"
|
||||
entity-recognition-service.url: "http://entity-recognition-service-v1:8080"
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
+18
-1
@@ -656,7 +656,7 @@ public class RedactionIntegrationTest {
|
||||
public void redactionTest() throws IOException {
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
ClassPathResource pdfFileResource = new ClassPathResource("files/new/VV-919901.pdf");
|
||||
ClassPathResource pdfFileResource = new ClassPathResource("files/new/Single Study - Oral (Gavage) Mouse.pdf");
|
||||
AnalyzeRequest request = prepareStorage(pdfFileResource.getInputStream());
|
||||
request.setExcludedPages(Set.of(1));
|
||||
|
||||
@@ -714,10 +714,13 @@ public class RedactionIntegrationTest {
|
||||
reanlysisVersions.put("physical", 2L);
|
||||
|
||||
deleted.add("David Chubb");
|
||||
deleted.add("mouse");
|
||||
|
||||
dictionary.get(FALSE_POSITIVE).add("David Chubb");
|
||||
reanlysisVersions.put("David Chubb", 3L);
|
||||
|
||||
reanlysisVersions.put("mouse", 3L);
|
||||
|
||||
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER)).thenReturn(3L);
|
||||
|
||||
when(dictionaryClient.getDictionaryForType(VERTEBRATE, TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER))
|
||||
@@ -754,6 +757,20 @@ public class RedactionIntegrationTest {
|
||||
fileOutputStream.write(annotateResponse.getDocument());
|
||||
}
|
||||
|
||||
|
||||
deleted.remove("mouse");
|
||||
reanlysisVersions.put("mouse", 4L);
|
||||
|
||||
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER)).thenReturn(4L);
|
||||
|
||||
when(dictionaryClient.getDictionaryForType(VERTEBRATE, TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER))
|
||||
.thenReturn(getDictionaryResponse(VERTEBRATE, false));
|
||||
|
||||
reanalyzeService.reanalyze(request);
|
||||
|
||||
redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID);
|
||||
|
||||
System.out.println("hi");
|
||||
}
|
||||
|
||||
|
||||
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
package com.iqser.red.service.redaction.v1.server.redaction.utils;
|
||||
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.iqser.red.service.redaction.v1.model.ManualRedactions;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLog;
|
||||
import com.iqser.red.service.redaction.v1.model.SectionGrid;
|
||||
import com.iqser.red.service.redaction.v1.server.Application;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.service.DictionaryService;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.service.RedactionLogMergeService;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.service.SectionTextService;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.compress.utils.Lists;
|
||||
import org.assertj.core.util.Sets;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
|
||||
@Import(SectionTextServiceTest.TestConfiguration.class)
|
||||
public class SectionTextServiceTest {
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private SectionTextService service;
|
||||
|
||||
@Autowired
|
||||
private RedactionLogMergeService redactionLogMergeService;
|
||||
|
||||
@MockBean
|
||||
private DictionaryService dictionaryService;
|
||||
|
||||
@MockBean
|
||||
private AmazonS3 amazonS3;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = {RabbitAutoConfiguration.class})
|
||||
public static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void testMerge() {
|
||||
|
||||
when(dictionaryService.getColor(Mockito.anyString(), Mockito.anyString())).thenReturn(new float[]{0, 0, 0});
|
||||
|
||||
ManualRedactions manualRedactions = objectMapper.readValue(new ClassPathResource("contains/manual-redactions.json").getInputStream(), ManualRedactions.class);
|
||||
|
||||
RedactionLog redactionLog = new RedactionLog(1, Lists.newArrayList(), Lists.newArrayList(), 1, 1, 1, 1);
|
||||
SectionGrid sectionGrid = objectMapper.readValue(new ClassPathResource("contains/sections.json").getInputStream(), SectionGrid.class);
|
||||
RedactionLog merged = redactionLogMergeService.mergeRedactionLogData(redactionLog, sectionGrid, "1", manualRedactions, Sets.newHashSet());
|
||||
|
||||
assertThat(merged.getRedactionLogEntry().isEmpty()).isFalse();
|
||||
|
||||
assertThat(merged.getRedactionLogEntry().iterator().next().getSection()).isEqualTo("NOTIFICATION OF AN ACTIVE\n" +
|
||||
"SUBSTANCE UNDER COMMISSION\n" +
|
||||
"REGULATION (EU) 844/2012");
|
||||
assertThat(merged.getRedactionLogEntry().iterator().next().getSectionNumber()).isEqualTo(7);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
configuration-service.url: "http://configuration-service-v1:8080"
|
||||
image-service.url: "http://image-service-v1:8080"
|
||||
file-management-service.url: "http://file-management-service-v1:8080"
|
||||
entity-recognition-service.url: "http://entity-recognition-service-v1:8080"
|
||||
|
||||
ribbon:
|
||||
ConnectTimeout: 600000
|
||||
@@ -17,3 +18,4 @@ platform.multi-tenancy:
|
||||
|
||||
redaction-service:
|
||||
enable-image-classification: false
|
||||
enable-entity-recognition: false
|
||||
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"idsToRemove": [],
|
||||
"entriesToAdd": [
|
||||
{
|
||||
"id": "d5fd9fd9690557703a22d8ab22832c7f",
|
||||
"user": "7adf30b4-a0d8-4abb-adbb-760b1211098f",
|
||||
"type": "manual",
|
||||
"value": "DOCUMENT M-CA, Section 10\nSupplement",
|
||||
"reason": "names and addresses of persons involved in testing on vertebrate animals",
|
||||
"legalBasis": "[Reg (EC) No 1107/2009 Art. 63 (2g)]",
|
||||
"section": null,
|
||||
"positions": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 190.92,
|
||||
"y": 376.7999
|
||||
},
|
||||
"width": 227.49368,
|
||||
"height": 14.974969,
|
||||
"page": 1
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 258.96,
|
||||
"y": 358.31992
|
||||
},
|
||||
"width": 91.47408,
|
||||
"height": 14.974969,
|
||||
"page": 1
|
||||
}
|
||||
],
|
||||
"status": "APPROVED",
|
||||
"addToDictionary": false,
|
||||
"addToDossierDictionary": false,
|
||||
"requestDate": "2021-11-03T15:01:45Z",
|
||||
"processedDate": "2021-11-03T15:01:45Z",
|
||||
"softDeletedTime": null
|
||||
}
|
||||
],
|
||||
"forceRedactions": [],
|
||||
"imageRecategorization": [],
|
||||
"legalBasisChanges": [],
|
||||
"comments": {
|
||||
"d5fd9fd9690557703a22d8ab22832c7f": [
|
||||
{
|
||||
"id": "56c1a675-0d64-4190-b76c-6af9d0b361a9",
|
||||
"date": "2021-11-03T15:01:45Z",
|
||||
"text": "test",
|
||||
"user": "7adf30b4-a0d8-4abb-adbb-760b1211098f",
|
||||
"softDeletedTime": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-877
@@ -1,877 +0,0 @@
|
||||
{
|
||||
"rectanglesPerPage": {
|
||||
"1": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 251.4,
|
||||
"y": 550.32
|
||||
},
|
||||
"width": 107.763336,
|
||||
"height": 12.02002,
|
||||
"part": 1,
|
||||
"numberOfParts": 1,
|
||||
"tableCells": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 159.24,
|
||||
"y": 280.92004
|
||||
},
|
||||
"width": 291.92004,
|
||||
"height": 212.29996,
|
||||
"part": 1,
|
||||
"numberOfParts": 3,
|
||||
"tableCells": null
|
||||
}
|
||||
],
|
||||
"2": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 735.36
|
||||
},
|
||||
"width": 105.64288,
|
||||
"height": 9.02002,
|
||||
"part": 2,
|
||||
"numberOfParts": 3,
|
||||
"tableCells": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.56436,
|
||||
"y": 719.9557
|
||||
},
|
||||
"width": 478.4686,
|
||||
"height": -110.91278,
|
||||
"part": 3,
|
||||
"numberOfParts": 3,
|
||||
"tableCells": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.56436,
|
||||
"y": 684.47955
|
||||
},
|
||||
"width": 83.35573,
|
||||
"height": 35.476135
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 148.92009,
|
||||
"y": 684.47955
|
||||
},
|
||||
"width": 255.12016,
|
||||
"height": 35.476135
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 404.04025,
|
||||
"y": 684.47955
|
||||
},
|
||||
"width": 139.9927,
|
||||
"height": 35.476135
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.56436,
|
||||
"y": 659.27954
|
||||
},
|
||||
"width": 83.35573,
|
||||
"height": 25.200012
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 148.92009,
|
||||
"y": 659.27954
|
||||
},
|
||||
"width": 255.12016,
|
||||
"height": 25.200012
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 404.04025,
|
||||
"y": 659.27954
|
||||
},
|
||||
"width": 139.9927,
|
||||
"height": 25.200012
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.56436,
|
||||
"y": 634.20074
|
||||
},
|
||||
"width": 83.35573,
|
||||
"height": 25.078796
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 148.92009,
|
||||
"y": 634.20074
|
||||
},
|
||||
"width": 255.12016,
|
||||
"height": 25.078796
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 404.04025,
|
||||
"y": 634.20074
|
||||
},
|
||||
"width": 139.9927,
|
||||
"height": 25.078796
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.56436,
|
||||
"y": 609.0429
|
||||
},
|
||||
"width": 83.35573,
|
||||
"height": 25.157837
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 148.92009,
|
||||
"y": 609.0429
|
||||
},
|
||||
"width": 255.12016,
|
||||
"height": 25.157837
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 404.04025,
|
||||
"y": 609.0429
|
||||
},
|
||||
"width": 139.9927,
|
||||
"height": 25.157837
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"3": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 691.2
|
||||
},
|
||||
"width": 468.76624,
|
||||
"height": 53.179993,
|
||||
"part": 1,
|
||||
"numberOfParts": 3,
|
||||
"tableCells": null
|
||||
}
|
||||
],
|
||||
"4": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 71.04,
|
||||
"y": 555.48
|
||||
},
|
||||
"width": 461.24002,
|
||||
"height": 188.78003,
|
||||
"part": 2,
|
||||
"numberOfParts": 3,
|
||||
"tableCells": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 540.55756
|
||||
},
|
||||
"width": 478.58698,
|
||||
"height": -365.55508,
|
||||
"part": 3,
|
||||
"numberOfParts": 3,
|
||||
"tableCells": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 515.4003
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 25.157227
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 515.4003
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 25.157227
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 404.75992
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 110.64041
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 404.75992
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 110.64041
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 379.68002
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 25.079895
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 379.68002
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 25.079895
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 335.8798
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 43.800232
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 335.8798
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 43.800232
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 310.68
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 25.199799
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 310.68
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 25.199799
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 281.2798
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 29.400208
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 281.2798
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 29.400208
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 218.76001
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 62.519775
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 218.76001
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 62.519775
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 175.00247
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 43.757538
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 175.00247
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 43.757538
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"sections": [
|
||||
{
|
||||
"sectionNumber": 1,
|
||||
"headline": "",
|
||||
"pages": [
|
||||
1
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 251.4,
|
||||
"y": 550.32
|
||||
},
|
||||
"width": 107.763336,
|
||||
"height": 12.02002,
|
||||
"page": 1,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 2,
|
||||
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
|
||||
"pages": [
|
||||
2
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.56436,
|
||||
"y": 684.47955
|
||||
},
|
||||
"width": 83.35573,
|
||||
"height": 35.476135,
|
||||
"page": 2,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 148.92009,
|
||||
"y": 684.47955
|
||||
},
|
||||
"width": 255.12016,
|
||||
"height": 35.476135,
|
||||
"page": 2,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 404.04025,
|
||||
"y": 684.47955
|
||||
},
|
||||
"width": 139.9927,
|
||||
"height": 35.476135,
|
||||
"page": 2,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 3,
|
||||
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
|
||||
"pages": [],
|
||||
"sectionAreas": []
|
||||
},
|
||||
{
|
||||
"sectionNumber": 4,
|
||||
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
|
||||
"pages": [],
|
||||
"sectionAreas": []
|
||||
},
|
||||
{
|
||||
"sectionNumber": 5,
|
||||
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
|
||||
"pages": [
|
||||
2
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.56436,
|
||||
"y": 609.0429
|
||||
},
|
||||
"width": 83.35573,
|
||||
"height": 25.157837,
|
||||
"page": 2,
|
||||
"header": "Date"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 7,
|
||||
"headline": "NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
|
||||
"pages": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 159.24,
|
||||
"y": 280.92004
|
||||
},
|
||||
"width": 291.92004,
|
||||
"height": 212.29996,
|
||||
"page": 1,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 735.36
|
||||
},
|
||||
"width": 105.64288,
|
||||
"height": 9.02002,
|
||||
"page": 2,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 8,
|
||||
"headline": "Table in: Table of Contents",
|
||||
"pages": [
|
||||
4
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 515.4003
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 25.157227,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 515.4003
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 25.157227,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 404.75992
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 110.64041,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 379.68002
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 25.079895,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 379.68002
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 25.079895,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 335.8798
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 43.800232,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 335.8798
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 43.800232,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 310.68
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 25.199799,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 310.68
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 25.199799,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 281.2798
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 29.400208,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 281.2798
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 29.400208,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 218.76001
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 62.519775,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 218.76001
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 62.519775,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 65.68587,
|
||||
"y": 175.00247
|
||||
},
|
||||
"width": 125.808716,
|
||||
"height": 43.757538,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 191.49458,
|
||||
"y": 175.00247
|
||||
},
|
||||
"width": 352.77826,
|
||||
"height": 43.757538,
|
||||
"page": 4,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 9,
|
||||
"headline": "Table of Contents",
|
||||
"pages": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 691.2
|
||||
},
|
||||
"width": 468.76624,
|
||||
"height": 53.179993,
|
||||
"page": 3,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 71.04,
|
||||
"y": 555.48
|
||||
},
|
||||
"width": 461.24002,
|
||||
"height": 188.78003,
|
||||
"page": 4,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 10,
|
||||
"headline": "Header",
|
||||
"pages": [
|
||||
1
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 799.08
|
||||
},
|
||||
"width": 469.31543,
|
||||
"height": 6.799988,
|
||||
"page": 1,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 534.72,
|
||||
"y": 783.84
|
||||
},
|
||||
"width": 5.470215,
|
||||
"height": 6.0200195,
|
||||
"page": 1,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 11,
|
||||
"headline": "Header",
|
||||
"pages": [
|
||||
2
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 799.08
|
||||
},
|
||||
"width": 469.31543,
|
||||
"height": 6.799988,
|
||||
"page": 2,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 534.72,
|
||||
"y": 783.84
|
||||
},
|
||||
"width": 5.470215,
|
||||
"height": 6.0200195,
|
||||
"page": 2,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 12,
|
||||
"headline": "Header",
|
||||
"pages": [
|
||||
3
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 799.08
|
||||
},
|
||||
"width": 469.31543,
|
||||
"height": 6.799988,
|
||||
"page": 3,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 534.72,
|
||||
"y": 783.84
|
||||
},
|
||||
"width": 5.470215,
|
||||
"height": 6.0200195,
|
||||
"page": 3,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 13,
|
||||
"headline": "Header",
|
||||
"pages": [
|
||||
4
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 71.04,
|
||||
"y": 798.96
|
||||
},
|
||||
"width": 469.70926,
|
||||
"height": 6.799988,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 534.84,
|
||||
"y": 783.72
|
||||
},
|
||||
"width": 5.488098,
|
||||
"height": 6.036072,
|
||||
"page": 4,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 14,
|
||||
"headline": "Footer",
|
||||
"pages": [
|
||||
1
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 37.080017
|
||||
},
|
||||
"width": 93.19173,
|
||||
"height": 6.0200005,
|
||||
"page": 1,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 468.0,
|
||||
"y": 37.080017
|
||||
},
|
||||
"width": 71.701416,
|
||||
"height": 6.0200005,
|
||||
"page": 1,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 15,
|
||||
"headline": "Footer",
|
||||
"pages": [
|
||||
2
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 37.440002
|
||||
},
|
||||
"width": 93.19173,
|
||||
"height": 6.0200005,
|
||||
"page": 2,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 468.0,
|
||||
"y": 37.440002
|
||||
},
|
||||
"width": 71.701416,
|
||||
"height": 6.0200005,
|
||||
"page": 2,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 16,
|
||||
"headline": "Footer",
|
||||
"pages": [
|
||||
3
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 70.92,
|
||||
"y": 37.440002
|
||||
},
|
||||
"width": 468.78143,
|
||||
"height": 6.0200005,
|
||||
"page": 3,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionNumber": 17,
|
||||
"headline": "Footer",
|
||||
"pages": [
|
||||
4
|
||||
],
|
||||
"sectionAreas": [
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 71.04,
|
||||
"y": 37.320007
|
||||
},
|
||||
"width": 93.3805,
|
||||
"height": 6.0360794,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 468.12,
|
||||
"y": 37.320007
|
||||
},
|
||||
"width": 71.984375,
|
||||
"height": 6.0360794,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 71.04,
|
||||
"y": 140.16003
|
||||
},
|
||||
"width": 254.69507,
|
||||
"height": 7.5200043,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 71.04,
|
||||
"y": 115.56
|
||||
},
|
||||
"width": 65.564415,
|
||||
"height": 7.5199966,
|
||||
"page": 4,
|
||||
"header": null
|
||||
},
|
||||
{
|
||||
"topLeft": {
|
||||
"x": 71.04,
|
||||
"y": 90.599976
|
||||
},
|
||||
"width": 424.84805,
|
||||
"height": 7.5199966,
|
||||
"page": 4,
|
||||
"header": null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
Amendment 1
|
||||
Report Number: 33168
|
||||
Page
|
||||
Report Number: BFI0714
|
||||
Tesh Consultants International
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user