Commit b32327fe authored by Gerrit Hübbers's avatar Gerrit Hübbers 🃏
Browse files

Finalize spreadsheet parsing.

parent 53da494e
......@@ -56,70 +56,78 @@ public abstract class AbstractTemplateExcelSheetBundlesSource implements Bundles
protected abstract Logger getLog();
protected void extractMetadatumFromCellAndAddToMetadataSetBuilder(String key, Cell cell, ImmutableSet.Builder<Metadatum> metadataBuilder) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
Metadatum metadatum = new SimpleMetadatum(key, rawValue);
metadataBuilder.add(metadatum);
if (null != cell) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
Metadatum metadatum = new SimpleMetadatum(key, rawValue);
metadataBuilder.add(metadatum);
}
}
}
protected void extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder(String key, Cell cell, ImmutableSet.Builder<Metadatum> metadataBuilder) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
String sanitizedValue = rawValue.replace("\n", " ").replace("\r", " ").trim();
Metadatum metadatum = new SimpleMetadatum(key, sanitizedValue);
metadataBuilder.add(metadatum);
if (null != cell) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
String sanitizedValue = sanitizeString(rawValue);
Metadatum metadatum = new SimpleMetadatum(key, sanitizedValue);
metadataBuilder.add(metadatum);
}
}
}
protected void extractMetadataFromCellAndAddToMetadataSetBuilder(String key, Cell cell, String delimiterRegex, ImmutableSet.Builder<Metadatum> metadataBuilder) {
String rawValues = cell.toString();
if (isNotBlank(rawValues) ) {
Arrays.stream( rawValues.split(delimiterRegex) )
.filter(StringUtils::isNotBlank)
.map(validValue -> new SimpleMetadatum(key, validValue) )
.forEach( metadataBuilder::add );
if (null != cell) {
String rawValues = cell.toString();
if (isNotBlank(rawValues) ) {
Arrays.stream( rawValues.split(delimiterRegex) )
.filter(StringUtils::isNotBlank)
.map(AbstractTemplateExcelSheetBundlesSource::sanitizeString)
.map(validValue -> new SimpleMetadatum(key, validValue) )
.forEach( metadataBuilder::add );
}
}
}
protected void extractDcDateKindMetadatumFromCellAndAddToMetadataSetBuilder(String key, Cell cell, ImmutableSet.Builder<Metadatum> metadataBuilder) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
String sanitizedValue;
if ( rawValue.endsWith(".0") ) {
sanitizedValue = rawValue.replace(".0", "");
}
else {
sanitizedValue = rawValue;
if (null != cell) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
String sanitizedValue;
if ( rawValue.endsWith(".0") ) {
sanitizedValue = rawValue.replace(".0", "");
}
else {
sanitizedValue = rawValue;
}
Metadatum metadatum = new SimpleMetadatum(key, sanitizedValue);
metadataBuilder.add(metadatum);
}
Metadatum metadatum = new SimpleMetadatum(key, sanitizedValue);
metadataBuilder.add(metadatum);
}
}
protected void extractControlledVocabularyFromCell(String key, Cell cell, ImmutableSet.Builder<Metadatum> metadataBuilder) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
// sanitizing identifier in case Apache POI returns a float-like string instead of integer-like string
String sanitizedValue = rawValue.replace(".0", "");
if ( containsIdentifier(key, sanitizedValue) ) {
String valueDe = getValue(key, sanitizedValue, DE);
Metadatum deMetadatum = new SimpleMetadatum(key, "de", valueDe);
metadataBuilder.add(deMetadatum);
String valueEn = getValue(key, sanitizedValue, EN);
Metadatum enMetadatum = new SimpleMetadatum(key, "en", valueEn);
metadataBuilder.add(enMetadatum);
}
else {
getLog().warn("controlled vocabulary for {} does not contain identifier {}. Adding this identifier verbatim as metadatum.", key, rawValue);
Metadatum metadatum = new SimpleMetadatum(key, rawValue);
metadataBuilder.add(metadatum);
if (null != cell) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
// sanitizing identifier in case Apache POI returns a float-like string instead of integer-like string
String sanitizedValue = rawValue.replace(".0", "");
if ( containsIdentifier(key, sanitizedValue) ) {
String valueDe = getValue(key, sanitizedValue, DE);
Metadatum deMetadatum = new SimpleMetadatum(key, "de", valueDe);
metadataBuilder.add(deMetadatum);
String valueEn = getValue(key, sanitizedValue, EN);
Metadatum enMetadatum = new SimpleMetadatum(key, "en", valueEn);
metadataBuilder.add(enMetadatum);
}
else {
getLog().warn("controlled vocabulary for {} does not contain identifier {}. Adding this identifier verbatim as metadatum.", key, rawValue);
Metadatum metadatum = new SimpleMetadatum(key, rawValue);
metadataBuilder.add(metadatum);
}
}
}
}
......@@ -132,35 +140,51 @@ public abstract class AbstractTemplateExcelSheetBundlesSource implements Bundles
* @param metadataBuilder
*/
protected void extractBinaryMetadatumFromCellAndAddToMetadatumSetBuilder(String key, Cell cell, String iffCellHasTextThenSetValue, String iffCellHasNoTextThenSetValue, Builder<Metadatum> metadataBuilder) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
Metadatum metadatum = new SimpleMetadatum(key, iffCellHasTextThenSetValue);
metadataBuilder.add(metadatum);
}
else if (null != iffCellHasNoTextThenSetValue) {
Metadatum metadatum = new SimpleMetadatum(key, iffCellHasNoTextThenSetValue);
metadataBuilder.add(metadatum);
if (null != cell) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
Metadatum metadatum = new SimpleMetadatum(key, iffCellHasTextThenSetValue);
metadataBuilder.add(metadatum);
}
else if (null != iffCellHasNoTextThenSetValue) {
Metadatum metadatum = new SimpleMetadatum(key, iffCellHasNoTextThenSetValue);
metadataBuilder.add(metadatum);
}
}
}
protected void extractOpenAireMetadatumFromCellAndAddToMetadatumSetBuilder(Cell cell, ImmutableSet.Builder<Metadatum> metadataBuilder) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
String openAireString = "info:eu-repo/grantAgreement/EC/" + rawValue;
Metadatum metadatum = new SimpleMetadatum("dc.relation", openAireString);
metadataBuilder.add(metadatum);
if (null != cell) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
String openAireString = "info:eu-repo/grantAgreement/EC/" + rawValue;
Metadatum metadatum = new SimpleMetadatum("dc.relation", openAireString);
metadataBuilder.add(metadatum);
}
}
}
protected void extractIntegerMetadatumFromCellAndAddToMetadataSetBuilder(String key, Cell cell, ImmutableSet.Builder<Metadatum> metadataBuilder) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
int intValue = (int) Double.parseDouble(rawValue);
String intString = Integer.toString(intValue);
Metadatum metadatum = new SimpleMetadatum(key, intString);
metadataBuilder.add(metadatum);
if (null != cell) {
String rawValue = cell.toString();
if ( isNotBlank(rawValue) ) {
int intValue = (int) Double.parseDouble(rawValue);
String intString = Integer.toString(intValue);
Metadatum metadatum = new SimpleMetadatum(key, intString);
metadataBuilder.add(metadatum);
}
}
}
private static String sanitizeString(String rawValue) {
String sanitizedResult;
if (null != rawValue) {
sanitizedResult = rawValue.replace("\n", " ").replace("\r", " ").replace(" ", " ").trim();
}
else {
sanitizedResult = "";
}
return sanitizedResult;
}
}
package org.gesis.dda.publishing.domain.impl;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.gesis.dda.publishing.domain.Metadatum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableSet.Builder;
public class CollectionSheetBundlesSource extends AbstractTemplateExcelSheetBundlesSource {
private final static Logger log = LoggerFactory.getLogger(CollectionSheetBundlesSource.class);
protected CollectionSheetBundlesSource(Sheet journalArticleSheet) {
super(journalArticleSheet);
}
@Override
protected void doGetBundles(Row row, Builder<Metadatum> metadataBuilder) {
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.editor", row.getCell(1), "@@", metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.corporateeditor", row.getCell(2), "@@", metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title", row.getCell(3), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title.alternative", row.getCell(4), metadataBuilder );
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.source.series", row.getCell(5), metadataBuilder );
extractControlledVocabularyFromCell( "dc.language", row.getCell(6), metadataBuilder );
extractIntegerMetadatumFromCellAndAddToMetadataSetBuilder( "dc.source.volume", row.getCell(7), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.issn", row.getCell(8), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.isbn", row.getCell(9), metadataBuilder );
extractDcDateKindMetadatumFromCellAndAddToMetadataSetBuilder("dc.date.issued", row.getCell(10), metadataBuilder);
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.source.pageinfo", row.getCell(11), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.publisher", row.getCell(12), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.publisher.city", row.getCell(13), metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.description.abstract", row.getCell(14), "@@", metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.subject.other", row.getCell(15), "; ", metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.urn", row.getCell(16), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.doi", row.getCell(17), metadataBuilder );
extractControlledVocabularyFromCell( "dc.rights.licence", row.getCell(18), metadataBuilder );
extractControlledVocabularyFromCell( "dc.type.document", row.getCell(19), metadataBuilder );
extractBinaryMetadatumFromCellAndAddToMetadatumSetBuilder( "ssoar.wgl.collection", row.getCell(20), "true", null, metadataBuilder );
extractBinaryMetadatumFromCellAndAddToMetadatumSetBuilder( "ssoar.licence.dfg", row.getCell(21), "true", null, metadataBuilder );
extractOpenAireMetadatumFromCellAndAddToMetadatumSetBuilder(row.getCell(22), metadataBuilder);
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "ssoar.contributor.institution", row.getCell(23), metadataBuilder );
extractControlledVocabularyFromCell( "dc.description.pubstatus", row.getCell(24), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "internal.embargo.liftdate", row.getCell(25), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.url", row.getCell(26), metadataBuilder );
}
@Override
protected Logger getLog() {
return log;
}
}
package org.gesis.dda.publishing.domain.impl;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.gesis.dda.publishing.domain.Metadatum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableSet.Builder;
public class InCollectionSheetBundlesSource extends AbstractTemplateExcelSheetBundlesSource {
private final static Logger log = LoggerFactory.getLogger(InCollectionSheetBundlesSource.class);
protected InCollectionSheetBundlesSource(Sheet journalArticleSheet) {
super(journalArticleSheet);
}
@Override
protected void doGetBundles(Row row, Builder<Metadatum> metadataBuilder) {
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.author", row.getCell(1), "@@", metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.editor", row.getCell(2), "@@", metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.corporateeditor", row.getCell(3), "@@", metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title", row.getCell(4), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title.alternative", row.getCell(5), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.source.collection", row.getCell(6), metadataBuilder );
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.source.series", row.getCell(7), metadataBuilder );
extractControlledVocabularyFromCell( "dc.language", row.getCell(8), metadataBuilder );
extractIntegerMetadatumFromCellAndAddToMetadataSetBuilder( "dc.source.volume", row.getCell(9), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.issn", row.getCell(10), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.isbn", row.getCell(11), metadataBuilder );
extractDcDateKindMetadatumFromCellAndAddToMetadataSetBuilder("dc.date.issued", row.getCell(12), metadataBuilder);
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.source.pageinfo", row.getCell(13), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.publisher", row.getCell(14), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.publisher.city", row.getCell(15), metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.description.abstract", row.getCell(16), "@@", metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.subject.other", row.getCell(17), "; ", metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.urn", row.getCell(18), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.doi", row.getCell(19), metadataBuilder );
extractControlledVocabularyFromCell( "dc.rights.licence", row.getCell(20), metadataBuilder );
extractControlledVocabularyFromCell( "dc.type.document", row.getCell(21), metadataBuilder );
extractBinaryMetadatumFromCellAndAddToMetadatumSetBuilder( "ssoar.wgl.collection", row.getCell(22), "true", null, metadataBuilder );
extractBinaryMetadatumFromCellAndAddToMetadatumSetBuilder( "ssoar.licence.dfg", row.getCell(23), "true", null, metadataBuilder );
extractOpenAireMetadatumFromCellAndAddToMetadatumSetBuilder(row.getCell(24), metadataBuilder);
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "ssoar.contributor.institution", row.getCell(25), metadataBuilder );
extractControlledVocabularyFromCell( "dc.description.pubstatus", row.getCell(26), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "internal.embargo.liftdate", row.getCell(27), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.identifier.url", row.getCell(28), metadataBuilder );
}
@Override
protected Logger getLog() {
return log;
}
}
......@@ -19,8 +19,8 @@ public class JournalArticleSheetBundlesSource extends AbstractTemplateExcelSheet
@Override
protected void doGetBundles(Row row, Builder<Metadatum> metadataBuilder) {
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.author", row.getCell(1), "@@", metadataBuilder );
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.title", row.getCell(2), metadataBuilder );
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.title.alternative", row.getCell(3), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title", row.getCell(2), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title.alternative", row.getCell(3), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.source.journal", row.getCell(4), metadataBuilder );
extractControlledVocabularyFromCell( "dc.language", row.getCell(5), metadataBuilder );
extractIntegerMetadatumFromCellAndAddToMetadataSetBuilder( "dc.source.volume", row.getCell(6), metadataBuilder );
......
......@@ -22,8 +22,8 @@ public class MonographSheetBundlesSource extends AbstractTemplateExcelSheetBundl
protected void doGetBundles(Row row, Builder<Metadatum> metadataBuilder) {
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.author", row.getCell(1), "@@", metadataBuilder );
extractMetadataFromCellAndAddToMetadataSetBuilder( "dc.contributor.corporateeditor", row.getCell(2), "@@", metadataBuilder );
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.title", row.getCell(3), metadataBuilder );
extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.title.alternative", row.getCell(4), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title", row.getCell(3), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.title.alternative", row.getCell(4), metadataBuilder );
extractMetadatumFromCellAndSanitizeAndAddToMetadataSetBuilder( "dc.source.series", row.getCell(5), metadataBuilder );
//extractMetadatumFromCellAndAddToMetadataSetBuilder( "dc.language", row.getCell(6), metadataBuilder );
extractControlledVocabularyFromCell( "dc.language", row.getCell(6), metadataBuilder );
......
......@@ -32,7 +32,6 @@ import org.gesis.dda.feeder.ssoar.domain.Item;
import org.gesis.dda.feeder.ssoar.domain.MetadataEntry;
import org.gesis.dda.feeder.ssoar.domain.Status;
import org.gesis.dda.feeder.ssoar.domain.XmlWorkflowItem;
import org.gesis.dda.feeder.ssoar.impl.SpringRestTemplateSsoarRestService;
import org.gesis.dda.wizard.Application;
import org.junit.Before;
import org.junit.Test;
......
package org.gesis.dda.publishing.domain.impl;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.gesis.dda.publishing.domain.Bundle;
import org.gesis.dda.publishing.domain.BundlesSource;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CollectionSheetBundlesSourceTest {
private final static Logger log = LoggerFactory.getLogger(CollectionSheetBundlesSourceTest.class);
@Test
public void testCollectionSheetNewExcel() throws EncryptedDocumentException, InvalidFormatException, IOException {
File exampleXlsFile = new File("src/test/resources/2016_08_Beispieldaten ARL.xlsx");
try (Workbook wb = WorkbookFactory.create(exampleXlsFile)) {
for (Sheet sheet : wb) {
if ( sheet.getSheetName().equals("collection") ) {
BundlesSource bundlesSource = new CollectionSheetBundlesSource(sheet);
Set<Bundle> bundles = bundlesSource.getBundles();
bundles.stream().forEach(bundle -> log.info( bundle.toString() ) );
}
}
}
}
@Test
public void testCollectionSheetOldExcel() throws EncryptedDocumentException, InvalidFormatException, IOException {
File exampleXlsFile = new File("src/test/resources/csv_muster_import_dda_Beispieldokumente.xls");
try (Workbook wb = WorkbookFactory.create(exampleXlsFile)) {
for (Sheet sheet : wb) {
if ( sheet.getSheetName().equals("collection") ) {
BundlesSource bundlesSource = new CollectionSheetBundlesSource(sheet);
Set<Bundle> bundles = bundlesSource.getBundles();
bundles.stream().forEach(bundle -> log.info( bundle.toString() ) );
}
}
}
}
}
package org.gesis.dda.publishing.domain.impl;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.gesis.dda.publishing.domain.Bundle;
import org.gesis.dda.publishing.domain.BundlesSource;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InCollectionSheetBundlesSourceTest {
private final static Logger log = LoggerFactory.getLogger(InCollectionSheetBundlesSourceTest.class);
@Test
public void testInCollectionSheetNewExcel() throws EncryptedDocumentException, InvalidFormatException, IOException {
File exampleXlsFile = new File("src/test/resources/2016_08_Beispieldaten ARL.xlsx");
try (Workbook wb = WorkbookFactory.create(exampleXlsFile)) {
for (Sheet sheet : wb) {
if ( sheet.getSheetName().equals("incollection") ) {
BundlesSource bundlesSource = new InCollectionSheetBundlesSource(sheet);
Set<Bundle> bundles = bundlesSource.getBundles();
bundles.stream().forEach(bundle -> log.info( bundle.toString() ) );
}
}
}
}
@Test
public void testInCollectionSheetOldExcel() throws EncryptedDocumentException, InvalidFormatException, IOException {
File exampleXlsFile = new File("src/test/resources/csv_muster_import_dda_Beispieldokumente.xls");
try (Workbook wb = WorkbookFactory.create(exampleXlsFile)) {
for (Sheet sheet : wb) {
if ( sheet.getSheetName().equals("incollection") ) {
BundlesSource bundlesSource = new InCollectionSheetBundlesSource(sheet);
Set<Bundle> bundles = bundlesSource.getBundles();
bundles.stream().forEach(bundle -> log.info( bundle.toString() ) );
}
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment