Skip to content

Commit

Permalink
MODSOURCE-506: remove rawRecord field from source record
Browse files Browse the repository at this point in the history
  • Loading branch information
yaroslav-epam committed Nov 6, 2023
1 parent b4f17f6 commit 80140a0
Show file tree
Hide file tree
Showing 35 changed files with 93 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ public static SourceRecord toSourceRecord(Record record) {
}
return sourceRecord
.withOrder(record.getOrder())
.withRawRecord(record.getRawRecord())
.withParsedRecord(record.getParsedRecord())
.withAdditionalInfo(record.getAdditionalInfo())
.withExternalIdsHolder(record.getExternalIdsHolder())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,21 @@
public class TestMocks {

private static final String SOURCE_RECORDS_FOLDER_PATH = "src/test/resources/mock/sourceRecords";

private static final String SNAPSHOT_PATH_TEMPLATE = "src/test/resources/mock/snapshots/%s.json";
private static final String RECORD_PATH_TEMPLATE = "src/test/resources/mock/records/%s.json";
private static final String RAW_RECORD_PATH_TEMPLATE = "src/test/resources/mock/rawRecords/%s.json";
private static final String ERROR_RECORD_PATH_TEMPLATE = "src/test/resources/mock/errorRecords/%s.json";

private static List<Snapshot> snapshots;

private static List<Record> records;

private static List<RawRecord> rawRecords;

private static List<ParsedRecord> parsedRecords;

private static List<ErrorRecord> errorRecords;

static {
List<SourceRecord> sourceRecords = readSourceRecords();
rawRecords = sourceRecords.stream().map(TestMocks::toRawRecord).collect(Collectors.toList());
parsedRecords = sourceRecords.stream().map(TestMocks::toParsedRecord).collect(Collectors.toList());
errorRecords = readErrorRecords(sourceRecords);
records = readRecords(sourceRecords);
Expand Down Expand Up @@ -102,14 +99,6 @@ public static ErrorRecord getErrorRecord(int index) {
return clone(errorRecords.get(index));
}

public static List<RawRecord> getRawRecords() {
return new ArrayList<>(rawRecords.stream().map(TestMocks::clone).collect(Collectors.toList()));
}

public static RawRecord getRawRecord(int index) {
return clone(rawRecords.get(index));
}

public static List<ParsedRecord> getParsedRecords() {
return new ArrayList<>(parsedRecords.stream().map(TestMocks::clone).collect(Collectors.toList()));
}
Expand All @@ -130,10 +119,6 @@ public static Optional<ErrorRecord> getErrorRecord(String id) {
return errorRecords.stream().map(TestMocks::clone).filter(er -> er.getId().equals(id)).findAny();
}

public static Optional<RawRecord> getRawRecord(String id) {
return rawRecords.stream().map(TestMocks::clone).filter(rr -> rr.getId().equals(id)).findAny();
}

public static Optional<ParsedRecord> getParsedRecord(String id) {
return parsedRecords.stream().map(TestMocks::clone).filter(pr -> pr.getId().equals(id)).findAny();
}
Expand All @@ -145,18 +130,13 @@ public static ParsedRecord normalizeContent(ParsedRecord parsedRecord) {
return parsedRecord;
}

private static RawRecord toRawRecord(SourceRecord sourceRecord) {
return sourceRecord.getRawRecord();
}

private static ParsedRecord toParsedRecord(SourceRecord sourceRecord) {
return sourceRecord.getParsedRecord();
}

private static List<SourceRecord> readSourceRecords() {
File sourceRecordsDirectory = new File(SOURCE_RECORDS_FOLDER_PATH);
String[] extensions = new String[]{ "json" };
return FileUtils.listFiles(sourceRecordsDirectory, extensions, false).stream()
return FileUtils.listFiles(sourceRecordsDirectory, new String[]{"json"}, false).stream()
.map(TestMocks::readSourceRecord)
.filter(sr -> sr.isPresent())
.map(sr -> sr.get())
Expand Down Expand Up @@ -209,18 +189,15 @@ private static Optional<Record> readRecord(SourceRecord sourceRecord) {
if (file.exists()) {
try {
Record record = new ObjectMapper().readValue(file, Record.class)
.withRawRecord(sourceRecord.getRawRecord())
.withRawRecord(readRawRecord(sourceRecord.getRecordId()))
.withParsedRecord(sourceRecord.getParsedRecord())
.withExternalIdsHolder(sourceRecord.getExternalIdsHolder())
.withAdditionalInfo(sourceRecord.getAdditionalInfo());
if (Objects.nonNull(sourceRecord.getMetadata())) {
record.withMetadata(sourceRecord.getMetadata());
}
Optional<ErrorRecord> errorRecord = errorRecords.stream()
.filter(er -> er.getId().equals(record.getId())).findAny();
if (errorRecord.isPresent()) {
record.withErrorRecord(errorRecord.get());
}
errorRecords.stream()
.filter(er -> er.getId().equals(record.getId())).findAny().ifPresent(record::withErrorRecord);
return Optional.of(record);
} catch (IOException e) {
e.printStackTrace();
Expand All @@ -229,6 +206,10 @@ private static Optional<Record> readRecord(SourceRecord sourceRecord) {
return Optional.empty();
}

private static RawRecord readRawRecord(String recordId) throws IOException {
return new ObjectMapper().readValue(new File(format(RAW_RECORD_PATH_TEMPLATE, recordId)), RawRecord.class);
}

private static List<ErrorRecord> readErrorRecords(List<SourceRecord> sourceRecords) {
return sourceRecords.stream()
.map(TestMocks::readErrorRecord)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package org.folio.dao.util;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.xlate.edi.stream.EDIStreamException;
import org.folio.TestUtil;
import org.folio.rest.jaxrs.model.SourceRecord;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -21,6 +20,7 @@ public class EdifactUtilTest {

private static final String SOURCE_RECORD_PATH = "src/test/resources/mock/sourceRecords/e4cfe577-4015-46d8-a54d-7c9b34796955.json";
private static final String SOURCE_RECORD_WITH_IGNORED_CODES_PATH = "src/test/resources/mock/sourceRecords/4ca9d8ac-9de5-432a-83ee-15832f09e868.json";
private static final String RAW_EDIFACT_RECORD_CONTENT_SAMPLE_PATH = "src/test/resources/rawEdifactRecordContent.sample";

private static final String INVALID_RAW_EDIFACT_RECORD =
"UNA:+.? '" +
Expand Down Expand Up @@ -51,14 +51,15 @@ public class EdifactUtilTest {
private SourceRecord sourceRecord;

@Before
public void readSourceRecord() throws JsonParseException, JsonMappingException, IOException {
public void readSourceRecord() throws IOException {
File file = new File(SOURCE_RECORD_PATH);
sourceRecord = new ObjectMapper().readValue(file, SourceRecord.class);
}

@Test
public void shouldFormatEdifact() throws IOException, EDIStreamException {
String rawEdifact = sourceRecord.getRawRecord().getContent();
String rawEdifact = new ObjectMapper().readValue(
TestUtil.readFileFromPath(RAW_EDIFACT_RECORD_CONTENT_SAMPLE_PATH), String.class);
String formattedEdifact = EdifactUtil.formatEdifact(rawEdifact);
assertNotNull(formattedEdifact);
assertEquals(sourceRecord.getParsedRecord().getFormattedContent(), formattedEdifact);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,38 @@
package org.folio.dao.util;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.tomakehurst.wiremock.common.Json;

import org.folio.rest.jaxrs.model.RawRecord;
import org.folio.rest.jaxrs.model.SourceRecord;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.marc4j.MarcException;

import java.io.File;
import java.io.IOException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@RunWith(BlockJUnit4ClassRunner.class)
public class MarcUtilTest {

private static final String SOURCE_RECORD_PATH = "src/test/resources/mock/sourceRecords/d3cd3e1e-a18c-4f7c-b053-9aa50343394e.json";
private static final String RAW_RECORD_PATH = "src/test/resources/mock/rawRecords/d3cd3e1e-a18c-4f7c-b053-9aa50343394e.json";

private SourceRecord sourceRecord;

@Before
public void readSourceRecord() throws JsonParseException, JsonMappingException, IOException {
public void readSourceRecord() throws IOException {
File file = new File(SOURCE_RECORD_PATH);
sourceRecord = new ObjectMapper().readValue(file, SourceRecord.class);
}

@Test
public void shouldConvertRawMarcToMarcJson() throws IOException, MarcException {
String rawMarc = sourceRecord.getRawRecord().getContent();
String rawMarc = new ObjectMapper().readValue(new File(RAW_RECORD_PATH), RawRecord.class).getContent();
String marcJson = MarcUtil.rawMarcToMarcJson(rawMarc);
assertNotNull(marcJson);
assertEquals(rawMarc, MarcUtil.marcJsonToRawMarc(marcJson));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
package org.folio.rest.impl;

import java.util.Collections;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.restassured.RestAssured;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import org.apache.http.HttpStatus;
import org.folio.TestMocks;
import org.folio.TestUtil;
import org.folio.rest.jaxrs.model.RawRecord;
import org.folio.rest.jaxrs.model.TestMarcRecordsCollection;
import org.junit.Test;
import org.junit.runner.RunWith;

import io.restassured.RestAssured;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

@RunWith(VertxUnitRunner.class)
public class TestMarcRecordsApiTest extends AbstractRestVerticleTest {

private static final String POPULATE_TEST_MARK_RECORDS_PATH = "/source-storage/populate-test-marc-records";

@Test
public void shouldReturnNoContentOnPostRecordCollectionPassedInBody() {
public void shouldReturnNoContentOnPostRecordCollectionPassedInBody() throws IOException {
RawRecord rawRecord = new RawRecord().withContent(
new ObjectMapper().readValue(TestUtil.readFileFromPath(RAW_MARC_RECORD_CONTENT_SAMPLE_PATH), String.class));

RestAssured.given()
.spec(spec)
.body(new TestMarcRecordsCollection()
.withRawRecords(TestMocks.getRawRecords()))
.withRawRecords(List.of(rawRecord)))
.when()
.post(POPULATE_TEST_MARK_RECORDS_PATH)
.then()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,6 @@ private void getMarcSourceRecordById(TestContext context, Record expected) {
context.fail(get.cause());
}
context.assertTrue(get.result().isPresent());
context.assertNotNull(get.result().get().getRawRecord());
context.assertNotNull(get.result().get().getParsedRecord());
compareSourceRecords(context, RecordDaoUtil.toSourceRecord(expected), get.result().get());
async.complete();
Expand Down Expand Up @@ -1794,15 +1793,8 @@ private void compareSourceRecords(TestContext context, SourceRecord expected, So
context.assertEquals(expected.getSnapshotId(), actual.getSnapshotId());
context.assertEquals(expected.getRecordType(), actual.getRecordType());
context.assertEquals(expected.getOrder(), actual.getOrder());
if (Objects.nonNull(expected.getRawRecord())) {
compareRawRecords(context, expected.getRawRecord(), actual.getRawRecord());
} else {
context.assertNull(actual.getRawRecord());
}
if (Objects.nonNull(expected.getParsedRecord())) {
compareParsedRecords(context, expected.getParsedRecord(), actual.getParsedRecord());
} else {
context.assertNull(actual.getRawRecord());
}
if (Objects.nonNull(expected.getAdditionalInfo())) {
compareAdditionalInfo(context, expected.getAdditionalInfo(), actual.getAdditionalInfo());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"id": "0f0fe962-d502-4a4f-9e74-7732bec94ee8",
"content": "{\"leader\":\"02042nma a2200349 c 4500\",\"fields\":[{\"001\":\"inst000000000019\"},{\"003\":\"DE-601\"},{\"005\":\"20180122150003.0\"},{\"007\":\"cu\\\\uuu---uuuuu\"},{\"008\":\"180122s2017\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\000\\\\0\\\\eng\\\\d\"},{\"020\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"9781450351430\"},{\"9\":\"978-1-4503-5143-0\"}]}},{\"035\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"(DE-599)GBV1011273942\"}]}},{\"035\":\"1011273942\"},{\"040\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"b\":\"ger\"},{\"c\":\"GBVCP\"},{\"e\":\"rda\"}]}},{\"041\":{\"ind1\":\"0\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"eng\"}]}},{\"110\":{\"ind1\":\"2\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"ACM Workshop on Millimeter Wave Networks and Sensing Systems\"},{\"n\":\"1.\"},{\"d\":\"2017\"},{\"c\":\"Snowbird, Utah\"},{\"e\":\"VerfasserIn\"},{\"4\":\"aut\"}]}},{\"245\":{\"ind1\":\"0\",\"ind2\":\"0\",\"subfields\":[{\"a\":\"MobiCom'17\"},{\"n\":\"5\"},{\"p\":\"mmNets'17, October 16, 2017, Snowbird, UT, USA / general chairs: Haitham Hassanieh (University of Illinois at Urbana Champaign, USA), Xinyu Zhang (University of California San Diego, USA)\"}]}},{\"246\":{\"ind1\":\"3\",\"ind2\":\"0\",\"subfields\":[{\"a\":\"1st First ACM Workshop Millimeter Wave Networks Sensing Systems\"}]}},{\"336\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Text\"},{\"b\":\"txt\"},{\"2\":\"rdacontent\"}]}},{\"337\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Computermedien\"},{\"b\":\"c\"},{\"2\":\"rdamedia\"}]}},{\"338\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Computerdisk\"},{\"b\":\"cd\"},{\"2\":\"rdacarrier\"}]}},{\"700\":{\"ind1\":\"1\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Hassanieh, Haitham\"},{\"e\":\"VeranstalterIn\"},{\"4\":\"orm\"}]}},{\"700\":{\"ind1\":\"1\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Zhang, Xinyu\"},{\"e\":\"VeranstalterIn\"},{\"4\":\"orm\"}]}},{\"710\":{\"ind1\":\"2\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"MobiCom\"},{\"n\":\"23.\"},{\"d\":\"2017\"},{\"c\":\"Snowbird, Utah\"},{\"e\":\"VeranstalterIn\"},{\"4\":\"orm\"}]}},{\"710\":{\"ind1\":\"2\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Association for Computing Machinery\"},{\"b\":\"Special Interest Group on Mobility of Systems Users, Data, and Computing\"},{\"e\":\"SponsorIn\"},{\"4\":\"spn\"},{\"0\":\"(DE-601)499677137\"},{\"0\":\"(DE-588)10113390-X\"}]}},{\"711\":{\"ind1\":\"2\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"ACM Workshop on Millimeter Wave Networks and Sensing Systems\"},{\"n\":\"1\"},{\"d\":\"2017.10.16\"},{\"c\":\"Snowbird, Utah\"}]}},{\"711\":{\"ind1\":\"2\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"mmNets\"},{\"n\":\"1\"},{\"d\":\"2017.10.16\"},{\"c\":\"Snowbird, Utah\"}]}},{\"711\":{\"ind1\":\"2\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Annual International Conference on Mobile Computing and Networking (ACM MobiCom)\"},{\"n\":\"23\"},{\"d\":\"2017.10.16-20\"},{\"c\":\"Snowbird, Utah\"}]}},{\"773\":{\"ind1\":\"0\",\"ind2\":\"\\\\\",\"subfields\":[{\"w\":\"(DE-601)1011270897\"},{\"t\":\"MobiCom'17, MobiCom'17, proceedings and co-located workshops of the 23rd Annual International Conference on Mobile Computing and Networking : October 16-20, 2017, Snowbird, UT, USA, MobiCom, Snowbird, Utah. - New York, NY : ACM, Association for Computing Machinery\"}]}},{\"900\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"GBV\"},{\"b\":\"TIB/UB Hannover <89>\"}]}},{\"954\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"0\":\"TIB/UB Hannover <89>\"},{\"a\":\"70\"},{\"b\":\"1743063695\"},{\"c\":\"01\"},{\"x\":\"0089\"}]}},{\"999\":{\"ind1\":\"f\",\"ind2\":\"f\",\"subfields\":[{\"s\":\"0f0fe962-d502-4a4f-9e74-7732bec94ee8\"},{\"i\":\"6b4ae089-e1ee-431f-af83-e1133f8e3da0\"}]}}]}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"id": "3187432f-9434-40a8-8782-35a111a1491e",
"content": "{\"leader\":\"01463nja a2200313 c 4500\",\"fields\":[{\"001\":\"inst000000000007\"},{\"003\":\"DE-601\"},{\"005\":\"20180118183625.0\"},{\"007\":\"su\\\\uuuuuuuuuuu\"},{\"008\":\"180118s2017\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\000\\\\0\\\\ger\\\\d\"},{\"035\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"(DE-599)GBV1011162431\"}]}},{\"035\":\"1011162431\"},{\"040\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"b\":\"ger\"},{\"c\":\"GBVCP\"},{\"e\":\"rda\"}]}},{\"041\":{\"ind1\":\"0\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"ger\"}]}},{\"100\":{\"ind1\":\"1\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Bach, Johann Sebastian\"},{\"e\":\"KomponistIn\"},{\"4\":\"cmp\"},{\"0\":\"(DE-601)134579348\"},{\"0\":\"(DE-588)11850553X\"}]}},{\"240\":{\"ind1\":\"1\",\"ind2\":\"0\",\"subfields\":[{\"0\":\"(DE-601)701589477\"},{\"0\":\"(DE-588)300007736\"},{\"a\":\"Ich habe genung\"}]}},{\"245\":{\"ind1\":\"1\",\"ind2\":\"0\",\"subfields\":[{\"a\":\"Cantatas for bass\"},{\"n\":\"4\"},{\"p\":\"Ich habe genug : BWV 82 / Johann Sebastian Bach ; Matthias Goerne, baritone ; Freiburger Barockorchester, Gottfried von der Goltz, violin and conductor\"}]}},{\"246\":{\"ind1\":\"1\",\"ind2\":\"3\",\"subfields\":[{\"i\":\"Abweichender Titel\"},{\"a\":\"Ich habe genung\"}]}},{\"300\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Track 10-14\"}]}},{\"336\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"aufgeführte Musik\"},{\"b\":\"prm\"},{\"2\":\"rdacontent\"}]}},{\"337\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"audio\"},{\"b\":\"s\"},{\"2\":\"rdamedia\"}]}},{\"338\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Audiodisk\"},{\"b\":\"sd\"},{\"2\":\"rdacarrier\"}]}},{\"700\":{\"ind1\":\"1\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Arfken, Katharina\"},{\"e\":\"InstrumentalmusikerIn\"},{\"4\":\"itr\"},{\"0\":\"(DE-601)576364940\"},{\"0\":\"(DE-588)135158265\"}]}},{\"700\":{\"ind1\":\"1\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Goltz, Gottfried von der\"},{\"e\":\"DirigentIn\"},{\"4\":\"cnd\"},{\"0\":\"(DE-601)081724969\"},{\"0\":\"(DE-588)122080912\"}]}},{\"710\":{\"ind1\":\"2\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"Freiburger Barockorchester\"},{\"e\":\"InstrumentalmusikerIn\"},{\"4\":\"itr\"},{\"0\":\"(DE-601)12121060X\"},{\"0\":\"(DE-588)5066798-1\"}]}},{\"773\":{\"ind1\":\"0\",\"ind2\":\"\\\\\",\"subfields\":[{\"w\":\"(DE-601)895161729\"},{\"t\":\"Cantatas for bass, Bach, Johann Sebastian. - Arles : Harmonia Mundi\"}]}},{\"900\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"a\":\"GBV\"},{\"b\":\"SBB-PK Berlin <1+1A>\"}]}},{\"954\":{\"ind1\":\"\\\\\",\"ind2\":\"\\\\\",\"subfields\":[{\"0\":\"SBB-PK Berlin <1+1A>\"},{\"a\":\"11\"},{\"b\":\"1742288871\"},{\"c\":\"01\"},{\"x\":\"0001\"}]}},{\"999\":{\"ind1\":\"f\",\"ind2\":\"f\",\"subfields\":[{\"s\":\"3187432f-9434-40a8-8782-35a111a1491e\"},{\"i\":\"ce00bca2-9270-4c6b-b096-b83a2e56e8e9\"}]}}]}"
}
Loading

0 comments on commit 80140a0

Please sign in to comment.