From 2f68b0ba71451a9c143f942debce6a7e756598df Mon Sep 17 00:00:00 2001 From: Steven Malmgren <4smalmgren@gmail.com> Date: Thu, 7 Nov 2024 10:54:34 -0700 Subject: [PATCH] [2.29.x] Forward port transforms exports 2.26 (#6809) Forward Ports Provide better transform failure message 390db3f #6771 DDF-6386 Add support for source id and metacard type for csv metacard transforms 367e426 #6387 Adds Gmd QueryResponseTransformer 89877a4 #6781 Use UTC dates when exporting metacards in CSV format 27ed601 #6501 Fix CSV transformer output when no columnOrder given fef3cb1 #6653 Updated the CsvTransformer to remove attributes that have empty or null fbb2b4d #6738 Xlsx column filtering 0335485 #6747 updated RTF transformer formatting and now omits null attributes from 64f8e5d #6744 fix npe in rtf 41fe113 #6750 Updated CSV and XLSX transformers to maintain the order specified in the columnOrder argument 506791d #6757 Dynamic rtf 83bcf56 #6762 Fix multi-value exports for RTF dd7bc91 #6767 --------- Co-authored-by: derekwilhelm --- .../rest/service/AbstractCatalogService.java | 13 + .../transformer/AbstractGmdTransformer.java | 17 +- .../catalog/transformer/GmdTransformer.java | 3 - .../OSGI-INF/blueprint/blueprint.xml | 15 + .../catalog-transformer-csv-common/pom.xml | 2 +- .../CsvAttributeDescriptorComparator.java | 1 + .../csv/common/CsvTransformer.java | 48 +- .../csv/common/MetacardIterator.java | 14 +- .../CsvAttributeDescriptorComparatorTest.java | 2 +- .../csv/common/CsvTransformerTest.java | 47 +- .../csv/CsvTransformerSupport.java | 4 +- .../csv/CsvMetacardTransformerTest.java | 193 +-- .../csv/CsvQueryResponseTransformerTest.java | 43 +- .../catalog-transformer-rtf/pom.xml | 4 +- ...tfQueryResponseAndMetacardTransformer.java | 62 +- .../transformer/output/rtf/RtfTemplate.java | 92 +- .../output/rtf/model/ExportCategory.java | 56 +- .../output/rtf/BaseTestConfiguration.java | 97 +- ...eryResponseAndMetacardTransformerTest.java | 104 ++ .../output/rtf/RtfTemplateTest.java | 47 + .../reference-metacard-with-args.rtf | 26 + ...eference-metacard-with-empty-thumbnail.rtf | 358 ++--- .../resources/reference-metacard-with-gif.rtf | 216 +++ .../src/test/resources/reference-metacard.rtf | 358 ++--- .../reference-source-response-with-args.rtf | 98 ++ .../resources/reference-source-response.rtf | 1426 +++++------------ .../test/resources/test-gif-image-string.txt | 1 + .../catalog-transformer-xlsx/pom.xml | 20 +- .../xlsx/XlsxMetacardTransformer.java | 22 +- .../transformer/xlsx/XlsxMetacardUtility.java | 105 +- .../xlsx/XlsxQueryResponseTransformer.java | 13 +- .../xlsx/XlsxMetacardUtilityTest.java | 69 +- .../_endpoints/catalog-rest-endpoint.adoc | 4 +- .../test/itests/catalog/TestFederation.java | 2 +- 34 files changed, 1774 insertions(+), 1808 deletions(-) create mode 100644 catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-args.rtf create mode 100644 catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-gif.rtf create mode 100644 catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response-with-args.rtf create mode 100644 catalog/transformer/catalog-transformer-rtf/src/test/resources/test-gif-image-string.txt diff --git a/catalog/rest/catalog-rest-service/src/main/java/org/codice/ddf/rest/service/AbstractCatalogService.java b/catalog/rest/catalog-rest-service/src/main/java/org/codice/ddf/rest/service/AbstractCatalogService.java index 6ce4d12f44b2..551f58029c3c 100644 --- a/catalog/rest/catalog-rest-service/src/main/java/org/codice/ddf/rest/service/AbstractCatalogService.java +++ b/catalog/rest/catalog-rest-service/src/main/java/org/codice/ddf/rest/service/AbstractCatalogService.java @@ -55,6 +55,7 @@ import ddf.catalog.operation.impl.UpdateRequestImpl; import ddf.catalog.plugin.OAuthPluginException; import ddf.catalog.resource.DataUsageLimitExceededException; +import ddf.catalog.resource.ResourceNotFoundException; import ddf.catalog.source.IngestException; import ddf.catalog.source.InternalIngestException; import ddf.catalog.source.SourceUnavailableException; @@ -263,6 +264,12 @@ public BinaryContent getHeaders( throw new InternalServerErrorException(exceptionMessage); } catch (CatalogTransformerException e) { String exceptionMessage = "Unable to transform Metacard. Try different transformer: "; + Throwable cause = e.getCause(); + if (cause instanceof ResourceNotFoundException) { + exceptionMessage = "Resource file is not available"; + } else if (cause instanceof IOException) { + exceptionMessage = "Unable to read resource file"; + } LOGGER.info(exceptionMessage, e); throw new InternalServerErrorException(exceptionMessage); } catch (SourceUnavailableException e) { @@ -462,6 +469,12 @@ public BinaryContent getDocument( throw new InternalServerErrorException(exceptionMessage); } catch (CatalogTransformerException e) { String exceptionMessage = "Unable to transform Metacard. Try different transformer: "; + Throwable cause = e.getCause(); + if (cause instanceof ResourceNotFoundException) { + exceptionMessage = "Resource file is not available"; + } else if (cause instanceof IOException) { + exceptionMessage = "Unable to read resource file"; + } LOGGER.info(exceptionMessage, e); throw new InternalServerErrorException(exceptionMessage); } catch (SourceUnavailableException e) { diff --git a/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/AbstractGmdTransformer.java b/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/AbstractGmdTransformer.java index a0df9ad4348d..95e7cb2f6f59 100644 --- a/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/AbstractGmdTransformer.java +++ b/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/AbstractGmdTransformer.java @@ -23,8 +23,10 @@ import ddf.catalog.data.BinaryContent; import ddf.catalog.data.Metacard; import ddf.catalog.data.impl.BinaryContentImpl; +import ddf.catalog.operation.SourceResponse; import ddf.catalog.transform.CatalogTransformerException; import ddf.catalog.transform.MetacardTransformer; +import ddf.catalog.transform.QueryResponseTransformer; import java.io.ByteArrayInputStream; import java.io.Serializable; import java.io.StringWriter; @@ -36,7 +38,7 @@ import org.codice.ddf.spatial.ogc.csw.catalog.common.GmdConstants; import org.codice.ddf.spatial.ogc.csw.catalog.converter.CswRecordConverter; -public class AbstractGmdTransformer implements MetacardTransformer { +public class AbstractGmdTransformer implements MetacardTransformer, QueryResponseTransformer { public static final String GML_PREFIX = "gml:"; @@ -44,12 +46,25 @@ public class AbstractGmdTransformer implements MetacardTransformer { private Supplier converterSupplier; + protected static final String TRANSFORM_EXCEPTION_MSG = + "Unable to transform from GMD Metadata to Metacard"; + /** @param converterSupplier must be non-null */ public AbstractGmdTransformer(Supplier converterSupplier) { notNull(converterSupplier, "converterSupplier must be non-null"); this.converterSupplier = converterSupplier; } + @Override + public BinaryContent transform(SourceResponse sourceResponse, Map map) + throws CatalogTransformerException { + if (sourceResponse.getResults() != null && sourceResponse.getResults().size() == 1) { + return transform(sourceResponse.getResults().get(0).getMetacard(), map); + } else { + throw new CatalogTransformerException(TRANSFORM_EXCEPTION_MSG); + } + } + @Override public BinaryContent transform(Metacard metacard, Map arguments) throws CatalogTransformerException { diff --git a/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/GmdTransformer.java b/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/GmdTransformer.java index c6e110ad471d..8e043bff3d25 100644 --- a/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/GmdTransformer.java +++ b/catalog/spatial/csw/spatial-csw-transformer/src/main/java/org/codice/ddf/spatial/ogc/csw/catalog/transformer/GmdTransformer.java @@ -85,9 +85,6 @@ public class GmdTransformer extends AbstractGmdTransformer implements InputTrans private static final Logger LOGGER = LoggerFactory.getLogger(GmdTransformer.class); - private static final String TRANSFORM_EXCEPTION_MSG = - "Unable to transform from GMD Metadata to Metacard"; - private static final Pattern WHITE_SPACE_PATTER = Pattern.compile("(\\s)+"); private static final Pattern NEW_LINE_PATTERN = Pattern.compile("(\\n)+"); diff --git a/catalog/spatial/csw/spatial-csw-transformer/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/catalog/spatial/csw/spatial-csw-transformer/src/main/resources/OSGI-INF/blueprint/blueprint.xml index c50c7243f8c9..999af84aefb8 100644 --- a/catalog/spatial/csw/spatial-csw-transformer/src/main/resources/OSGI-INF/blueprint/blueprint.xml +++ b/catalog/spatial/csw/spatial-csw-transformer/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -211,5 +211,20 @@ + + + + + + text/xml + application/xml + + + + + + + diff --git a/catalog/transformer/catalog-transformer-csv-common/pom.xml b/catalog/transformer/catalog-transformer-csv-common/pom.xml index b5e01c5c31fc..cb460cce69c6 100644 --- a/catalog/transformer/catalog-transformer-csv-common/pom.xml +++ b/catalog/transformer/catalog-transformer-csv-common/pom.xml @@ -81,7 +81,7 @@ COMPLEXITY COVEREDRATIO - 0.83 + 0.81 diff --git a/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparator.java b/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparator.java index fd358aefa0d1..5dbd9cddda33 100644 --- a/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparator.java +++ b/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparator.java @@ -62,6 +62,7 @@ public int compare(AttributeDescriptor descriptor1, AttributeDescriptor descript return new CompareToBuilder() .append(getAttributeIndex(descriptorName1), getAttributeIndex(descriptorName2)) + .append(descriptorName1, descriptorName2) .toComparison(); } diff --git a/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvTransformer.java b/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvTransformer.java index 404fad6b7448..5b2cfec6ee10 100644 --- a/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvTransformer.java +++ b/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/CsvTransformer.java @@ -16,18 +16,23 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; +import ddf.catalog.data.Attribute; import ddf.catalog.data.AttributeDescriptor; import ddf.catalog.data.AttributeType; import ddf.catalog.data.BinaryContent; import ddf.catalog.data.Metacard; import ddf.catalog.data.MetacardType; import ddf.catalog.data.impl.BinaryContentImpl; +import ddf.catalog.operation.QueryResponse; import ddf.catalog.transform.CatalogTransformerException; +import ddf.catalog.transform.MetacardTransformer; +import ddf.catalog.transform.QueryResponseTransformer; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.nio.charset.StandardCharsets; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -37,6 +42,7 @@ import javax.activation.MimeTypeParseException; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -170,11 +176,51 @@ public static Set getAllCsvAttributeDescriptors( */ public static Set getOnlyRequestedAttributes( final List metacards, final Set requestedAttributes) { - final Set attributes = getAllCsvAttributeDescriptors(metacards); + final Set attributes = getNonEmptyValueAttributes(metacards); // Filter out attributes not requested. attributes.removeIf(attrDesc -> !requestedAttributes.contains(attrDesc.getName())); return attributes; } + + /** + * Given a list of {@link Metacard}s, return only the attribute descriptors that have a non-empty + * value. Returns a set of {@link AttributeDescriptor}s containing the attributes with non-empty + * values. + */ + public static Set getNonEmptyValueAttributes( + final List metacards) { + final Set attributes = getAllCsvAttributeDescriptors(metacards); + final Set nonEmptyAttributes = new HashSet<>(); + + for (final AttributeDescriptor attribute : attributes) { + final boolean hasNonEmptyValue = + metacards.stream().anyMatch(metacard -> isNonEmptyValue(metacard, attribute)); + if (hasNonEmptyValue) { + nonEmptyAttributes.add(attribute); + } + } + return nonEmptyAttributes; + } + + private static boolean isNonEmptyValue(Metacard metacard, AttributeDescriptor descriptor) { + final Attribute attribute = metacard.getAttribute(descriptor.getName()); + switch (descriptor.getType().getAttributeFormat()) { + case STRING: + case XML: + case GEOMETRY: + return attribute != null && StringUtils.isNotEmpty((String) attribute.getValue()); + case INTEGER: + case LONG: + case DOUBLE: + case FLOAT: + case SHORT: + case DATE: + case BOOLEAN: + return attribute != null && attribute.getValue() != null; + default: + return false; + } + } } diff --git a/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/MetacardIterator.java b/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/MetacardIterator.java index 39aa715124c6..a0d56b97a3ef 100644 --- a/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/MetacardIterator.java +++ b/catalog/transformer/catalog-transformer-csv-common/src/main/java/ddf/catalog/transformer/csv/common/MetacardIterator.java @@ -23,6 +23,9 @@ import ddf.catalog.data.types.Core; import java.io.Serializable; import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Collections; import java.util.Date; import java.util.Iterator; @@ -39,10 +42,9 @@ * * @see java.util.Iterator */ -class MetacardIterator implements Iterator { +public class MetacardIterator implements Iterator { private static final Logger LOGGER = LoggerFactory.getLogger(MetacardIterator.class); - private static final String MULTIVALUE_DELIMITER = "\n"; private final List attributeDescriptorList; @@ -51,12 +53,14 @@ class MetacardIterator implements Iterator { private int index; + private DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + /** * @param metacard the metacard to be iterated over. * @param attributeDescriptorList the list of attributeDescriptors used to determine which * metacard attributes to return. */ - MetacardIterator( + public MetacardIterator( final Metacard metacard, final List attributeDescriptorList) { this.metacard = metacard; this.attributeDescriptorList = Collections.unmodifiableList(attributeDescriptorList); @@ -118,7 +122,9 @@ private Serializable convertValue( return null; } Instant instant = ((Date) value).toInstant(); - return instant.toString(); + ZoneId zoneId = ZoneId.of("UTC"); + ZonedDateTime zonedDateTime = instant.atZone(zoneId); + return zonedDateTime.format(formatter); case BINARY: byte[] bytes = (byte[]) value; return DatatypeConverter.printBase64Binary(bytes); diff --git a/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparatorTest.java b/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparatorTest.java index d054cd5e8d56..ddbe8c12052b 100644 --- a/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparatorTest.java +++ b/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvAttributeDescriptorComparatorTest.java @@ -63,7 +63,7 @@ public void testDescriptorComparator() { assertThat(comparison, is(1)); comparison = comparator.compare(nonExistendAttribute1, nonExistendAttribute2); - assertThat(comparison, is(0)); + assertThat(comparison, is(-1)); comparison = comparator.compare(nonExistendAttribute1, null); assertThat(comparison, is(1)); diff --git a/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvTransformerTest.java b/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvTransformerTest.java index cf3c9996cf12..b769eeeca324 100644 --- a/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvTransformerTest.java +++ b/catalog/transformer/catalog-transformer-csv-common/src/test/java/ddf/catalog/transformer/csv/common/CsvTransformerTest.java @@ -14,8 +14,10 @@ package ddf.catalog.transformer.csv.common; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -51,15 +53,8 @@ public class CsvTransformerTest { private static final List ATTRIBUTE_DESCRIPTOR_LIST = new ArrayList<>(); - - private static Map metacardDataMap = new HashMap<>(); - - private static List metacardList = new ArrayList<>(); - private static final int METACARD_COUNT = 2; - private static final String CSV_ITEM_SEPARATOR_REGEX = "[\\n\\r,]"; - private static final List> ATTRIBUTE_DATA = Arrays.asList( new ImmutableTriple( @@ -76,7 +71,10 @@ public class CsvTransformerTest { new ImmutableTriple( "attribute7", "OBJECT", BasicTypes.OBJECT_TYPE), new ImmutableTriple( - "attribute8", "BINARY", BasicTypes.BINARY_TYPE)); + "attribute8", "BINARY", BasicTypes.BINARY_TYPE), + new ImmutableTriple("attribute9", "", BasicTypes.STRING_TYPE)); + private static Map metacardDataMap = new HashMap<>(); + private static List metacardList = new ArrayList<>(); @Before public void setup() { @@ -89,13 +87,19 @@ public void setup() { public void getAllCsvAttributeDescriptors() { Set allAttributes = CsvTransformer.getAllCsvAttributeDescriptors(metacardList); - assertThat(allAttributes, hasSize(6)); + assertThat(allAttributes, hasSize(7)); Set allAttributeNames = allAttributes.stream().map(AttributeDescriptor::getName).collect(Collectors.toSet()); // Binary and Object types are filtered final Set expectedAttributes = Sets.newHashSet( - "attribute1", "attribute2", "attribute3", "attribute4", "attribute5", "attribute6"); + "attribute1", + "attribute2", + "attribute3", + "attribute4", + "attribute5", + "attribute6", + "attribute9"); assertThat(allAttributeNames, is(expectedAttributes)); } @@ -175,6 +179,29 @@ public void writeSearchResultsToCsvWithAliasMap() throws CatalogTransformerExcep assertThat(scanner.hasNext(), is(false)); } + @Test + public void filterEmptyValueAttributes() { + AttributeDescriptor attr9 = buildAttributeDescriptor("attribute9", BasicTypes.STRING_TYPE); + Set attributeDescriptors = new HashSet<>(ATTRIBUTE_DESCRIPTOR_LIST); + attributeDescriptors.add(attr9); + MetacardType metacardType = new MetacardTypeImpl("", attributeDescriptors); + Metacard metacard = new MetacardImpl(metacardType); + for (Attribute a : metacardDataMap.values()) { + metacard.setAttribute(a); + } + metacard.setAttribute(new AttributeImpl("attribute9", "")); + List metacards = new ArrayList<>(metacardList); + metacards.add(metacard); + Set nonEmptyValues = CsvTransformer.getNonEmptyValueAttributes(metacards); + + assertThat(nonEmptyValues, hasSize(6)); + Set nonEmptyAttributes = + nonEmptyValues.stream().map(AttributeDescriptor::getName).collect(Collectors.toSet()); + assertThat(nonEmptyAttributes, not(hasItem("attribute7"))); + assertThat(nonEmptyAttributes, not(hasItem("attribute8"))); + assertThat(nonEmptyAttributes, not(hasItem("attribute9"))); + } + private Metacard buildMetacard() { MetacardType metacardType = new MetacardTypeImpl("", new HashSet<>(ATTRIBUTE_DESCRIPTOR_LIST)); Metacard metacard = new MetacardImpl(metacardType); diff --git a/catalog/transformer/catalog-transformer-csv-queryresponse/src/main/java/ddf/catalog/transformer/csv/CsvTransformerSupport.java b/catalog/transformer/catalog-transformer-csv-queryresponse/src/main/java/ddf/catalog/transformer/csv/CsvTransformerSupport.java index 004a58f3e3bd..e006e88ec0f8 100644 --- a/catalog/transformer/catalog-transformer-csv-queryresponse/src/main/java/ddf/catalog/transformer/csv/CsvTransformerSupport.java +++ b/catalog/transformer/catalog-transformer-csv-queryresponse/src/main/java/ddf/catalog/transformer/csv/CsvTransformerSupport.java @@ -14,7 +14,7 @@ package ddf.catalog.transformer.csv; import static ddf.catalog.transformer.csv.common.CsvTransformer.createResponse; -import static ddf.catalog.transformer.csv.common.CsvTransformer.getAllCsvAttributeDescriptors; +import static ddf.catalog.transformer.csv.common.CsvTransformer.getNonEmptyValueAttributes; import static ddf.catalog.transformer.csv.common.CsvTransformer.getOnlyRequestedAttributes; import static ddf.catalog.transformer.csv.common.CsvTransformer.sortAttributes; import static ddf.catalog.transformer.csv.common.CsvTransformer.writeMetacardsToCsv; @@ -66,7 +66,7 @@ static BinaryContent transformWithArguments( final Set requestedAttributeDescriptors = requestedFields.isEmpty() - ? getAllCsvAttributeDescriptors(metacards) + ? getNonEmptyValueAttributes(metacards) : getOnlyRequestedAttributes(metacards, requestedFields); if (shouldInjectMetacardType(requestedFields)) { diff --git a/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvMetacardTransformerTest.java b/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvMetacardTransformerTest.java index 2cd4ffce0343..6af02097577a 100644 --- a/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvMetacardTransformerTest.java +++ b/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvMetacardTransformerTest.java @@ -14,23 +14,11 @@ package ddf.catalog.transformer.csv; -import static ddf.catalog.data.impl.BasicTypes.BINARY_TYPE; -import static ddf.catalog.data.impl.BasicTypes.DOUBLE_TYPE; -import static ddf.catalog.data.impl.BasicTypes.INTEGER_TYPE; -import static ddf.catalog.data.impl.BasicTypes.OBJECT_TYPE; -import static ddf.catalog.data.impl.BasicTypes.STRING_TYPE; -import static ddf.catalog.transformer.csv.CsvTransformerSupport.COLUMN_ORDER_KEY; -import static java.util.Collections.singletonMap; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import ddf.catalog.data.Attribute; import ddf.catalog.data.AttributeDescriptor; import ddf.catalog.data.AttributeType; @@ -39,167 +27,96 @@ import ddf.catalog.data.MetacardType; import ddf.catalog.data.impl.AttributeDescriptorImpl; import ddf.catalog.data.impl.AttributeImpl; +import ddf.catalog.data.impl.BasicTypes; import ddf.catalog.data.impl.MetacardImpl; import ddf.catalog.data.impl.MetacardTypeImpl; import ddf.catalog.transform.CatalogTransformerException; import java.io.IOException; +import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import org.junit.Before; import org.junit.Test; public class CsvMetacardTransformerTest { - private final CsvMetacardTransformer transformer = new CsvMetacardTransformer(); + private Map arguments; - private static final String METACARD_TYPE_NAME = "test-type"; + private CsvMetacardTransformer transformer; - @Test(expected = CatalogTransformerException.class) - public void testTransformerWithNullMetacard() throws CatalogTransformerException { - transformer.transform(null, new HashMap<>()); - } + private Metacard normalMC, nullMC; - @Test - public void testCsvMetacardTransformerNoArguments() - throws CatalogTransformerException, IOException { - String stringAtt = "stringAtt"; - String intAtt = "intAtt"; - String doubleAtt = "doubleAtt"; - Metacard metacard = - buildMetacard( - Sets.newHashSet( - buildAttributeDescriptor(stringAtt, STRING_TYPE), - buildAttributeDescriptor(intAtt, INTEGER_TYPE), - buildAttributeDescriptor(doubleAtt, DOUBLE_TYPE)), - new AttributeImpl(stringAtt, "stringVal"), - new AttributeImpl(intAtt, 101), - new AttributeImpl(doubleAtt, 3.14159)); - BinaryContent binaryContent = transformer.transform(metacard, new HashMap<>()); - assertThat(binaryContent.getMimeType().toString(), is("text/csv")); + private static final Set ATTRIBUTE_DESCRIPTORS = + ImmutableSet.of( + buildAttributeDescriptor("stringAtt", BasicTypes.STRING_TYPE), + buildAttributeDescriptor("intAtt", BasicTypes.INTEGER_TYPE), + buildAttributeDescriptor("doubleAtt", BasicTypes.DOUBLE_TYPE)); - List lines = Arrays.asList(new String(binaryContent.getByteArray()).split("\r\n")); - assertThat("The CSV didn't contain exactly two lines.", lines, hasSize(2)); + private static final List VALUES = ImmutableList.of("stringVal", "101", "3.14159"); - List attNames = Arrays.asList(lines.get(0).split(",")); - List attValues = Arrays.asList(lines.get(1).split(",")); - assertThat( - "The headers and values had different lengths.", attNames, hasSize(attValues.size())); + private static final List ATTRIBUTES = + ImmutableList.of( + new AttributeImpl("stringAtt", "stringVal"), + new AttributeImpl("intAtt", 101), + new AttributeImpl("doubleAtt", 3.14159)); - final Map headersToValues = new HashMap<>(); - for (int i = 0; i < attNames.size(); ++i) { - headersToValues.put(attNames.get(i), attValues.get(i)); - } - assertThat( - headersToValues, - allOf( - hasEntry(stringAtt, "stringVal"), - hasEntry(intAtt, "101"), - hasEntry(doubleAtt, "3.14159"))); - } + private static final List COLUMN_ORDER = + Arrays.asList("doubleAtt", "stringAtt", "intAtt"); - @Test - public void testCsvMetacardTransformerSupportsColumnOrder() - throws CatalogTransformerException, IOException { - String stringAtt = "stringAtt"; - String intAtt = "intAtt"; - String doubleAtt = "doubleAtt"; - Metacard metacard = - buildMetacard( - Sets.newHashSet( - buildAttributeDescriptor(stringAtt, STRING_TYPE), - buildAttributeDescriptor(intAtt, INTEGER_TYPE), - buildAttributeDescriptor(doubleAtt, DOUBLE_TYPE)), - new AttributeImpl(stringAtt, "stringVal"), - new AttributeImpl(intAtt, 101), - new AttributeImpl(doubleAtt, 3.14159)); - BinaryContent binaryContent = - transformer.transform( - metacard, singletonMap(COLUMN_ORDER_KEY, "doubleAtt,stringAtt,intAtt")); - assertThat(binaryContent.getMimeType().toString(), is("text/csv")); - - List lines = Arrays.asList(new String(binaryContent.getByteArray()).split("\r\n")); - assertThat("The CSV didn't contain exactly two lines.", lines, hasSize(2)); + @Before + public void setUp() { + this.transformer = new CsvMetacardTransformer(); + this.arguments = new HashMap<>(); + arguments.put("columnOrder", COLUMN_ORDER.stream().collect(Collectors.joining(","))); + normalMC = buildMetacard(); + } - List attNames = Arrays.asList(lines.get(0).split(",")); - List attValues = Arrays.asList(lines.get(1).split(",")); + private static AttributeDescriptor buildAttributeDescriptor(String name, AttributeType type) { + return new AttributeDescriptorImpl(name, true, true, true, true, type); + } - assertThat(attNames, contains(doubleAtt, stringAtt, intAtt)); - assertThat(attValues, contains("3.14159", "stringVal", "101")); + @Test(expected = CatalogTransformerException.class) + public void testTransformerWithNullMetacard() throws CatalogTransformerException { + transformer.transform(nullMC, arguments); } @Test - public void testFieldsNotRequestedAreExcluded() throws CatalogTransformerException, IOException { - String stringAtt = "stringAtt"; - String intAtt = "intAtt"; - String doubleAtt = "doubleAtt"; - Metacard metacard = - buildMetacard( - Sets.newHashSet( - buildAttributeDescriptor(stringAtt, STRING_TYPE), - buildAttributeDescriptor(intAtt, INTEGER_TYPE), - buildAttributeDescriptor(doubleAtt, DOUBLE_TYPE)), - new AttributeImpl(stringAtt, "stringVal"), - new AttributeImpl(intAtt, 101), - new AttributeImpl(doubleAtt, 3.14159)); - BinaryContent binaryContent = - transformer.transform( - metacard, singletonMap(COLUMN_ORDER_KEY, Lists.newArrayList(stringAtt))); + public void testCsvMetacardTransformer() throws CatalogTransformerException, IOException { + BinaryContent binaryContent = transformer.transform(normalMC, arguments); assertThat(binaryContent.getMimeType().toString(), is("text/csv")); - List lines = Arrays.asList(new String(binaryContent.getByteArray()).split("\r\n")); - assertThat("The CSV didn't contain exactly two lines.", lines, hasSize(2)); + List attributes = Arrays.asList(new String(binaryContent.getByteArray()).split("\r\n")); + List attNames = Arrays.asList(attributes.get(0).split(",")); + List attValues = Arrays.asList(attributes.get(1).split(",")); - List attNames = Arrays.asList(lines.get(0).split(",")); - List attValues = Arrays.asList(lines.get(1).split(",")); + assertThat(attNames, is(COLUMN_ORDER)); - assertThat(attNames, contains(stringAtt)); - assertThat(attValues, contains("stringVal")); + for (int i = 0; i < attNames.size(); i++) { + String attributeValue = attValues.get(i); + assertThat(VALUES.contains(attributeValue), is(true)); + } } @Test - public void testBinaryAndObjectFieldsAreExcluded() - throws CatalogTransformerException, IOException { - String stringAtt = "stringAtt"; - String binaryAtt = "binaryAtt"; - String objectAtt = "objectAtt"; - Metacard metacard = - buildMetacard( - Sets.newHashSet( - buildAttributeDescriptor(stringAtt, STRING_TYPE), - buildAttributeDescriptor(binaryAtt, BINARY_TYPE), - buildAttributeDescriptor(objectAtt, OBJECT_TYPE)), - new AttributeImpl(stringAtt, "stringVal"), - new AttributeImpl(binaryAtt, new byte[] {1, 0, 1}), - new AttributeImpl(objectAtt, new HashMap<>())); - BinaryContent binaryContent = transformer.transform(metacard, new HashMap<>()); + public void testNoColumnInfo() throws Exception { + BinaryContent binaryContent = transformer.transform(normalMC, new HashMap<>()); assertThat(binaryContent.getMimeType().toString(), is("text/csv")); - List lines = Arrays.asList(new String(binaryContent.getByteArray()).split("\r\n")); - assertThat("The CSV didn't contain exactly two lines.", lines, hasSize(2)); - - List attNames = Arrays.asList(lines.get(0).split(",")); - List attValues = Arrays.asList(lines.get(1).split(",")); - - assertThat(attNames, containsInAnyOrder(stringAtt, MetacardType.METACARD_TYPE)); - assertThat(attValues, hasSize(2)); - - int stringAttIndex = attNames.indexOf(stringAtt); - int typeIndex = attNames.indexOf(MetacardType.METACARD_TYPE); - assertThat(attValues.get(stringAttIndex), is("stringVal")); - assertThat(attValues.get(typeIndex), is(metacard.getMetacardType().getName())); - } - - private static AttributeDescriptor buildAttributeDescriptor(String name, AttributeType type) { - return new AttributeDescriptorImpl(name, true, true, true, true, type); + List attributes = Arrays.asList(new String(binaryContent.getByteArray()).split("\r\n")); + List attNames = Arrays.asList(attributes.get(0).split(",")); + List attValues = Arrays.asList(attributes.get(1).split(",")); + assertThat(attNames.size(), is(4)); + assertThat(attValues.size(), is(4)); } - private Metacard buildMetacard( - final Set attributeDescriptors, final Attribute... attributes) { - MetacardType metacardType = new MetacardTypeImpl(METACARD_TYPE_NAME, attributeDescriptors); + private Metacard buildMetacard() { + MetacardType metacardType = new MetacardTypeImpl("test", ATTRIBUTE_DESCRIPTORS); Metacard metacard = new MetacardImpl(metacardType); - for (Attribute attribute : attributes) { + for (Attribute attribute : ATTRIBUTES) { metacard.setAttribute(attribute); } return metacard; diff --git a/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvQueryResponseTransformerTest.java b/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvQueryResponseTransformerTest.java index 9041e64f9f8a..dbafaa1ba2e2 100644 --- a/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvQueryResponseTransformerTest.java +++ b/catalog/transformer/catalog-transformer-csv-queryresponse/src/test/java/ddf/catalog/transformer/csv/CsvQueryResponseTransformerTest.java @@ -49,9 +49,10 @@ public class CsvQueryResponseTransformerTest { {"attribute2", new Integer(101), BasicTypes.INTEGER_TYPE}, {"attribute3", new Double(3.14159), BasicTypes.DOUBLE_TYPE}, {"attribute4", "value,4", BasicTypes.STRING_TYPE}, - {"attribute5", "value5", BasicTypes.STRING_TYPE}, + {"attribute5", "POINT(1,1)", BasicTypes.GEO_TYPE}, {"attribute6", "OBJECT", BasicTypes.OBJECT_TYPE}, - {"attribute7", "BINARY", BasicTypes.BINARY_TYPE} + {"attribute7", "BINARY", BasicTypes.BINARY_TYPE}, + {"attribute8", "", BasicTypes.STRING_TYPE} }; private static final String METACARD_TYPE_NAME = "test-type"; @@ -87,7 +88,7 @@ public void testCsvQueryResponseTransformer() throws CatalogTransformerException String[] hiddenFieldsArray = {"attribute3", "attribute5"}; argumentsMap.put("hiddenFields", buildSet(hiddenFieldsArray)); - String[] columnOrderArray = {"attribute3", "attribute4", "attribute2"}; + String[] columnOrderArray = {"attribute3", "attribute4", "attribute2", "attribute8"}; argumentsMap.put("columnOrder", buildList(columnOrderArray)); String[][] aliases = {{"attribute1", "column1"}, {"attribute2", "column2"}}; @@ -164,6 +165,42 @@ public void testCsvQueryResponseTransformerWithMetacardType() throws CatalogTran assertThat(scanner.hasNext(), is(false)); } + @Test + public void testCsvQueryResponseTransformerWithNoArgs() throws CatalogTransformerException { + Map argumentsMap = new HashMap<>(); + + assertThat(ATTRIBUTE_DESCRIPTOR_LIST.size(), is(ATTRIBUTE_DATA.length)); + + BinaryContent bc = transformer.transform(sourceResponse, argumentsMap); + Scanner scanner = new Scanner(bc.getInputStream()); + scanner.useDelimiter("\\n|\\r|,"); + + /* + * OBJECT types, BINARY types, empty values, and hidden attributes will be filtered out + * We want to ensure that the only output data matches the explicitly requested headers + */ + + String[] expectedHeaders = { + "attribute1", "attribute2", "attribute3", "attribute4", "attribute5", "metacard-type" + }; + validate(scanner, expectedHeaders); + + // The scanner will split "value,4" into two tokens even though the CSVPrinter will + // handle it correctly. + String[] expectedValues = { + "", "value1", "101", "3.14159", "\"value", "4\"", "\"POINT(1", "1)\"", "test-type" + }; + + for (int i = 0; i < METACARD_COUNT; i++) { + validate(scanner, expectedValues); + } + + // final new line causes an extra "" value at end of file + assertThat(scanner.hasNext(), is(true)); + assertThat(scanner.next(), is("")); + assertThat(scanner.hasNext(), is(false)); + } + private void validate(Scanner scanner, String[] expectedValues) { for (int i = 0; i < expectedValues.length; i++) { assertThat(scanner.hasNext(), is(true)); diff --git a/catalog/transformer/catalog-transformer-rtf/pom.xml b/catalog/transformer/catalog-transformer-rtf/pom.xml index c4953f9f9369..421a1431afbe 100644 --- a/catalog/transformer/catalog-transformer-rtf/pom.xml +++ b/catalog/transformer/catalog-transformer-rtf/pom.xml @@ -169,12 +169,12 @@ BRANCH COVEREDRATIO - 0.81 + 0.72 COMPLEXITY COVEREDRATIO - 0.90 + 0.85 diff --git a/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformer.java b/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformer.java index 66c029cc64f0..ccac6035cb08 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformer.java +++ b/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformer.java @@ -25,27 +25,36 @@ import ddf.catalog.transform.CatalogTransformerException; import ddf.catalog.transform.MetacardTransformer; import ddf.catalog.transform.QueryResponseTransformer; +import ddf.catalog.transformer.output.rtf.model.ExportCategory; import ddf.catalog.transformer.output.rtf.model.RtfCategory; import java.io.ByteArrayInputStream; import java.io.Serializable; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import javax.activation.MimeType; import javax.activation.MimeTypeParseException; +import org.apache.commons.lang.StringUtils; public class RtfQueryResponseAndMetacardTransformer implements MetacardTransformer, QueryResponseTransformer { private final MimeType mimeType; - private final List categories; + private final List defaultCategories; + + public static final String COLUMN_ORDER_KEY = "columnOrder"; + + public static final String COLUMN_ALIAS_KEY = "aliases"; public RtfQueryResponseAndMetacardTransformer(List categories) throws MimeTypeParseException { - this.categories = categories; + this.defaultCategories = categories; this.mimeType = new MimeType("application/rtf"); } @@ -56,9 +65,24 @@ public BinaryContent transform(Metacard metacard, Map argu throw new CatalogTransformerException("Null metacard cannot be transformed into RTF"); } + String aliasesArg = (String) arguments.getOrDefault("aliases", ""); + Map aliases = + (StringUtils.isNotBlank(aliasesArg)) + ? Arrays.stream(aliasesArg.split(",")) + .map(s -> s.split("=")) + .collect(Collectors.toMap(k -> k[0], k -> k[1])) + : Collections.EMPTY_MAP; + String attributeString = (String) arguments.getOrDefault(COLUMN_ORDER_KEY, ""); + List attributes = + Arrays.stream(attributeString.split(",")) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); + final List categories = + attributes.isEmpty() ? defaultCategories : createCategory("Details", attributes, aliases); + ByteArrayInputStream rtfStream = Optional.of(metacard) - .map(this::toRtf) + .map(m -> toRtf(metacard, categories)) .map(this::rtfStringToInputStream) .orElseThrow(this::emptyRtfException); @@ -73,11 +97,24 @@ public BinaryContent transform( throw new CatalogTransformerException("Null result set cannot be transformed to RTF"); } + List attributeOrder = + Optional.ofNullable((List) arguments.get(COLUMN_ORDER_KEY)) + .orElse(Collections.emptyList()); + + Map columnAliasMap = + Optional.ofNullable((Map) arguments.get(COLUMN_ALIAS_KEY)) + .orElse(Collections.emptyMap()); + + final List categories = + attributeOrder.isEmpty() + ? defaultCategories + : createCategory("Details", attributeOrder, columnAliasMap); + Rtf doc = createRtfDoc(); upstreamResponse.getResults().stream() .map(Result::getMetacard) - .forEach(metacard -> toRtf(doc, metacard)); + .forEach(metacard -> toRtf(doc, metacard, categories)); ByteArrayInputStream templateStream = Optional.ofNullable(doc) @@ -106,18 +143,27 @@ private Rtf createRtfDoc() { return doc; } - private String toRtf(Metacard metacard) { - return Optional.ofNullable(toRtf(createRtfDoc(), metacard)) + private String toRtf(Metacard metacard, List categories) { + return Optional.ofNullable(toRtf(createRtfDoc(), metacard, categories)) .map(Rtf::out) .map(Object::toString) .orElse(""); } - private Rtf toRtf(Rtf doc, Metacard metacard) { + private Rtf toRtf(Rtf doc, Metacard metacard, List categories) { return new RtfTemplate.Builder() - .withCategories(this.categories) + .withCategories(categories) .withMetacard(metacard) .build() .rtf(doc); } + + private List createCategory( + String title, List attributes, Map aliases) { + ExportCategory dynamicCategory = new ExportCategory(); + dynamicCategory.setTitle(title); + dynamicCategory.setAttributes(attributes); + dynamicCategory.setAliases(aliases); + return Collections.singletonList(dynamicCategory); + } } diff --git a/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfTemplate.java b/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfTemplate.java index d9b9eab6a05f..04f66bb7e6c0 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfTemplate.java +++ b/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/RtfTemplate.java @@ -22,9 +22,11 @@ import static ddf.catalog.transformer.output.rtf.model.ExportCategory.EMPTY_VALUE; import com.tutego.jrtf.Rtf; +import com.tutego.jrtf.RtfException; import com.tutego.jrtf.RtfPara; import com.tutego.jrtf.RtfPicture; import com.tutego.jrtf.RtfRow; +import com.tutego.jrtf.RtfSectionFormatAndHeaderFooter; import com.tutego.jrtf.RtfText; import ddf.catalog.data.Metacard; import ddf.catalog.transformer.output.rtf.model.ExportCategory; @@ -51,30 +53,12 @@ public class RtfTemplate { private static final Logger LOGGER = LoggerFactory.getLogger(RtfTemplate.class); private static final int MINIMUM_VALID_IMAGE_DATA_SIZE = 10; - - static class Builder { - private List categories; - private Metacard metacard; - - public Builder withCategories(List categories) { - this.categories = categories; - - return this; - } - - public Builder withMetacard(Metacard metacard) { - this.metacard = metacard; - - return this; - } - - public RtfTemplate build() { - return new RtfTemplate(this.categories, this.metacard); - } - } - private final List categories; private final Metacard metacard; + private Function> memoizeForImageData = + metacardId -> data -> fromBytes(metacardId, data); + private Function> memoizeForRowData = + metacardId -> entry -> appendProperty(metacardId, entry); private RtfTemplate(List categories, Metacard metacard) { this.categories = categories; @@ -82,31 +66,29 @@ private RtfTemplate(List categories, Metacard metacard) { } public Rtf rtf(Rtf doc) { - doc.section(p(), p(), p(font(1, bold(this.metacard.getTitle()))).alignCentered()); + doc.section( + RtfSectionFormatAndHeaderFooter.noBreak(), + p(font(1, bold(this.metacard.getTitle()))).alignCentered()); this.categories.forEach(exportCategory -> appendSection(doc, exportCategory, this.metacard)); - + doc.p(); return doc; } - private Function> memoizeForRowData = - metacardId -> entry -> appendProperty(metacardId, entry); - - private Function> memoizeForImageData = - metacardId -> data -> fromBytes(metacardId, data); - private void appendSection(Rtf rtf, RtfCategory category, Metacard metacard) { - rtf.p(); - rtf.p(bold(category.getTitle())); - Function appendPropertyFunction = memoizeForRowData.apply(metacard.getId()); - Collection rows = category.toExportMap(metacard).entrySet().stream() .map(appendPropertyFunction) + .filter(r -> r != null) .collect(Collectors.toList()); - rtf.section(rows); + if (rows.isEmpty()) { + return; + } + rtf.p(); + rtf.p(bold(category.getTitle())); + rtf.section(RtfSectionFormatAndHeaderFooter.noBreak(), rows.toArray(new RtfPara[rows.size()])); } private RtfRow appendProperty( @@ -122,10 +104,24 @@ private RtfRow appendProperty( .map(this::imageFromStream) .orElse(text(EMPTY_VALUE)); - return row(entry.getKey(), picture); + try { + return row(entry.getKey(), picture) + .topCellBorder() + .rightCellBorder() + .leftCellBorder() + .bottomCellBorder(); + } catch (RtfException e) { + // Failed likely due to the fact this thumbnail is not a JPG or PNG + // return null and skip + return null; + } } - return row(entry.getKey(), entry.getValue().getValue()); + return row(entry.getKey(), entry.getValue().getValue()) + .bottomCellBorder() + .leftCellBorder() + .rightCellBorder() + .topCellBorder(); } private RtfText imageFromStream(InputStream stream) { @@ -142,4 +138,26 @@ private InputStream fromBytes(String metacardId, byte[] data) { return new ByteArrayInputStream(data); } + + static class Builder { + + private List categories; + private Metacard metacard; + + public Builder withCategories(List categories) { + this.categories = categories; + + return this; + } + + public Builder withMetacard(Metacard metacard) { + this.metacard = metacard; + + return this; + } + + public RtfTemplate build() { + return new RtfTemplate(this.categories, this.metacard); + } + } } diff --git a/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/model/ExportCategory.java b/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/model/ExportCategory.java index 21c11549937b..65b6eeee97df 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/model/ExportCategory.java +++ b/catalog/transformer/catalog-transformer-rtf/src/main/java/ddf/catalog/transformer/output/rtf/model/ExportCategory.java @@ -14,14 +14,18 @@ package ddf.catalog.transformer.output.rtf.model; import ddf.catalog.data.Attribute; +import ddf.catalog.data.AttributeDescriptor; import ddf.catalog.data.Metacard; import ddf.catalog.data.types.Core; import java.util.AbstractMap; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.WordUtils; public class ExportCategory implements RtfCategory { @@ -32,6 +36,7 @@ public class ExportCategory implements RtfCategory { private String title; private List attributes; + private Map aliases = Collections.EMPTY_MAP; public interface ExportValue { T getValue(); @@ -89,16 +94,25 @@ public void setAttributes(List attributes) { @Override public Map toExportMap(Metacard metacard) { return attributes.stream() + .filter(a -> isNonEmptyValue(metacard, a)) .map( key -> new AbstractMap.SimpleEntry<>( attributeKeyFrom(key), attributeExportValueFrom(key, metacard.getAttribute(key)))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + .collect( + Collectors.toMap( + Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new)); + } + + public void setAliases(Map aliases) { + this.aliases = aliases; } private String attributeKeyFrom(String key) { - if (key.startsWith(EXTENDED_ATTRIBUTE_PREFIX)) { + if (aliases.containsKey(key)) { + return aliases.get(key); + } else if (key.startsWith(EXTENDED_ATTRIBUTE_PREFIX)) { key = key.replaceFirst(EXTENDED_ATTRIBUTE_PREFIX, ""); } @@ -111,10 +125,6 @@ private String attributeKeyFrom(String key) { } private ExportValue attributeExportValueFrom(String attributeKey, Attribute attribute) { - if (attributeKey == null || attribute == null) { - return emptyValue(); - } - if (attributeKey.equals(Core.THUMBNAIL)) { byte[] image = (byte[]) attribute.getValue(); @@ -134,7 +144,39 @@ private ExportValue emptyValue() { private ExportValue simpleValue(Attribute attribute) { return new JustValue( - Optional.ofNullable(attribute.getValue()).map(Object::toString).orElse(null), + Optional.ofNullable( + attribute.getValues().stream() + .map(Object::toString) + .collect(Collectors.joining(", "))) + .orElse(null), ValueType.SIMPLE); } + + private static boolean isNonEmptyValue(Metacard metacard, String attrName) { + AttributeDescriptor descriptor = metacard.getMetacardType().getAttributeDescriptor(attrName); + final Attribute attribute = metacard.getAttribute(attrName); + if (descriptor == null) { + return attribute != null + && attribute.getValue() != null + && StringUtils.isNotEmpty(attribute.getValue().toString()); + } + + switch (descriptor.getType().getAttributeFormat()) { + case STRING: + case XML: + case GEOMETRY: + return attribute != null && StringUtils.isNotEmpty((String) attribute.getValue()); + case INTEGER: + case LONG: + case DOUBLE: + case FLOAT: + case SHORT: + case DATE: + case BOOLEAN: + case BINARY: + return attribute != null && attribute.getValue() != null; + default: + return false; + } + } } diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/BaseTestConfiguration.java b/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/BaseTestConfiguration.java index de0c79f37313..57cb65d4f8f5 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/BaseTestConfiguration.java +++ b/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/BaseTestConfiguration.java @@ -17,7 +17,11 @@ import static org.mockito.Mockito.when; import ddf.catalog.data.Attribute; +import ddf.catalog.data.AttributeDescriptor; +import ddf.catalog.data.AttributeType; import ddf.catalog.data.Metacard; +import ddf.catalog.data.MetacardType; +import ddf.catalog.data.impl.BasicTypes; import ddf.catalog.data.types.Core; import ddf.catalog.transformer.output.rtf.model.ExportCategory; import ddf.catalog.transformer.output.rtf.model.RtfCategory; @@ -26,7 +30,10 @@ import java.nio.charset.Charset; import java.util.Arrays; import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.io.IOUtils; @@ -34,10 +41,15 @@ public abstract class BaseTestConfiguration { static final String REFERENCE_IMAGE_STRING_FILE = "test-image-string.txt"; + static final String REFERENCE_GIF_STRING_FILE = "test-gif-image-string.txt"; static final String REFERENCE_METACARD_RTF_FILE = "reference-metacard.rtf"; + static final String REFERENCE_METACARD_WITH_ARGS_RTF_FILE = "reference-metacard-with-args.rtf"; + static final String REFERENCE_METACARD_WITH_GIF_RTF_FILE = "reference-metacard-with-gif.rtf"; static final String REFERENCE_METACARD_RTF_WITH_EMPTY_THUMBNAIL_FILE = "reference-metacard-with-empty-thumbnail.rtf"; static final String REFERENCE_SOURCE_RESPONSE_RTF_FILE = "reference-source-response.rtf"; + static final String REFERENCE_SOURCE_RESPONSE_WITH_ARGS_RTF_FILE = + "reference-source-response-with-args.rtf"; static final String EMPTY_ATTRIBUTE = "Empty"; static final String SIMPLE_ATTRIBUTE = "Simple"; @@ -45,6 +57,20 @@ public abstract class BaseTestConfiguration { private static final String UNKNOWN_ATTRIBUTE = "Unknown"; + static final List COLUMN_ORDER = + Arrays.asList(UNKNOWN_ATTRIBUTE, EXTENDED_ATTRIBUTE, SIMPLE_ATTRIBUTE, EMPTY_ATTRIBUTE); + + static final Map COLUMN_ALIASES; + + static { + Map map = new HashMap<>(); + map.put(EMPTY_ATTRIBUTE, "nothing"); + map.put(SIMPLE_ATTRIBUTE, "easy"); + map.put(EXTENDED_ATTRIBUTE, "extended"); + map.put(UNKNOWN_ATTRIBUTE, "not_Known"); + COLUMN_ALIASES = Collections.unmodifiableMap(map); + } + public static final List MOCK_CATEGORY = Stream.of( "Associations", @@ -97,6 +123,28 @@ String getReferenceImageString() throws IOException { getClass().getClassLoader().getResourceAsStream(REFERENCE_IMAGE_STRING_FILE)); } + String getReferenceGifString() throws IOException { + return inputStreamToString( + getClass().getClassLoader().getResourceAsStream(REFERENCE_GIF_STRING_FILE)); + } + + String getReferenceMetacardWithArgsRtfFile() throws IOException { + return inputStreamToString( + getClass().getClassLoader().getResourceAsStream(REFERENCE_METACARD_WITH_ARGS_RTF_FILE)); + } + + String getReferenceMetacardWithGifRtfFile() throws IOException { + return inputStreamToString( + getClass().getClassLoader().getResourceAsStream(REFERENCE_METACARD_WITH_GIF_RTF_FILE)); + } + + String getReferenceSourceResponseWithArgsRtfFile() throws IOException { + return inputStreamToString( + getClass() + .getClassLoader() + .getResourceAsStream(REFERENCE_SOURCE_RESPONSE_WITH_ARGS_RTF_FILE)); + } + String inputStreamToString(InputStream inputStream) throws IOException { return IOUtils.toString(inputStream, Charset.forName("UTF-8")).replaceAll("[\\r\\n]", ""); } @@ -110,6 +158,15 @@ Metacard createMockMetacardWithBadImageData(String title) { } } + Metacard createMockMetacardWithGifImageData(String title) { + try { + return createMockMetacard(title, createGifThumbnailAttribute()); + } catch (IOException e) { + // Will be caught in the test as missing attribute + return null; + } + } + Metacard createMockMetacard(String title) { try { return createMockMetacard(title, createMediaAttribute()); @@ -121,6 +178,8 @@ Metacard createMockMetacard(String title) { Metacard createMockMetacard(String title, Attribute mediaAttribute) { Metacard metacard = mock(Metacard.class); + MetacardType mockMetacardType = createMockMetacardType(); + when(metacard.getMetacardType()).thenReturn(mockMetacardType); when(metacard.getTitle()).thenReturn(title); when(metacard.getId()).thenReturn("mock-id"); @@ -155,17 +214,51 @@ Attribute createInvalidMediaAttribute() throws IOException { return mockAttribute; } + Attribute createGifThumbnailAttribute() throws IOException { + Attribute mockAttribute = mock(Attribute.class); + byte[] image = Base64.getDecoder().decode(getReferenceGifString()); + when(mockAttribute.getValue()).thenReturn(image); + + return mockAttribute; + } + Attribute createExtendedAttribute() { Attribute mockAttribute = mock(Attribute.class); when(mockAttribute.getValue()).thenReturn("Extended Value"); - + when(mockAttribute.getValues()).thenReturn(Collections.singletonList("Extended Value")); return mockAttribute; } Attribute createSimpleAttribute() { Attribute mockAttribute = mock(Attribute.class); when(mockAttribute.getValue()).thenReturn("Simple value"); - + when(mockAttribute.getValues()).thenReturn(Collections.singletonList("Simple value")); return mockAttribute; } + + MetacardType createMockMetacardType() { + MetacardType mockType = mock(MetacardType.class); + AttributeDescriptor mockThumbnailDesc = + createMockAttributeDescriptor(Core.THUMBNAIL, BasicTypes.BINARY_TYPE); + when(mockType.getAttributeDescriptor(Core.THUMBNAIL)).thenReturn(mockThumbnailDesc); + AttributeDescriptor mockEmptyDesc = + createMockAttributeDescriptor(EMPTY_ATTRIBUTE, BasicTypes.STRING_TYPE); + when(mockType.getAttributeDescriptor(EMPTY_ATTRIBUTE)).thenReturn(mockEmptyDesc); + AttributeDescriptor mockSimpleDesc = + createMockAttributeDescriptor(SIMPLE_ATTRIBUTE, BasicTypes.STRING_TYPE); + when(mockType.getAttributeDescriptor(SIMPLE_ATTRIBUTE)).thenReturn(mockSimpleDesc); + AttributeDescriptor mockExtendedDesc = + createMockAttributeDescriptor(EXTENDED_ATTRIBUTE, BasicTypes.STRING_TYPE); + when(mockType.getAttributeDescriptor(EXTENDED_ATTRIBUTE)).thenReturn(mockExtendedDesc); + AttributeDescriptor mockUnknownDesc = + createMockAttributeDescriptor(UNKNOWN_ATTRIBUTE, BasicTypes.INTEGER_TYPE); + when(mockType.getAttributeDescriptor(UNKNOWN_ATTRIBUTE)).thenReturn(mockUnknownDesc); + return mockType; + } + + AttributeDescriptor createMockAttributeDescriptor(String name, AttributeType type) { + AttributeDescriptor mockDescriptor = mock(AttributeDescriptor.class); + when(mockDescriptor.getType()).thenReturn(type); + return mockDescriptor; + } } diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformerTest.java b/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformerTest.java index f2a81c70837e..9401412b73f6 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformerTest.java +++ b/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfQueryResponseAndMetacardTransformerTest.java @@ -15,6 +15,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.equalToIgnoringWhiteSpace; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isEmptyOrNullString; import static org.hamcrest.Matchers.not; @@ -28,8 +29,12 @@ import ddf.catalog.operation.SourceResponse; import ddf.catalog.transform.CatalogTransformerException; import java.io.IOException; +import java.io.Serializable; import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.activation.MimeTypeParseException; @@ -108,6 +113,33 @@ public void testTransformMetacardWithMalformedImageData() equalTo(referenceRtfWithEmptyThumbnail.length())); } + @Test + public void testTransformMetacardWithGifThumbnail() + throws MimeTypeParseException, CatalogTransformerException, IOException { + RtfQueryResponseAndMetacardTransformer transformer = createTransformer(); + + Metacard mockMetacard = createMockMetacardWithGifImageData("Test Metacard With Gif Thumbnail"); + + BinaryContent content = transformer.transform(mockMetacard, Collections.emptyMap()); + + assertThat("Transformed content cannot be null", content, notNullValue()); + assertThat( + "Content mime type must be 'application/rtf'", + content.getMimeType().toString(), + equalTo("application/rtf")); + + String rtfResult = inputStreamToString(content.getInputStream()); + + assertThat("Content must not be empty", rtfResult, is(not(isEmptyOrNullString()))); + + String referenceRtfWithEmptyThumbnail = getReferenceMetacardWithGifRtfFile(); + + assertThat( + "Produced RTF document must match reference", + rtfResult, + equalToIgnoringWhiteSpace(referenceRtfWithEmptyThumbnail)); + } + @Test(expected = CatalogTransformerException.class) public void testTransformNullSourceResponse() throws CatalogTransformerException, MimeTypeParseException { @@ -147,6 +179,78 @@ public void testTransformSourceResponse() equalTo(referenceRtf.length())); } + @Test + public void testTransformMetacardWithArgs() + throws CatalogTransformerException, IOException, MimeTypeParseException { + RtfQueryResponseAndMetacardTransformer transformer = createTransformer(); + + Metacard mockMetacard = createMockMetacard("Test Metacard Title"); + + Map arguments = new HashMap<>(); + arguments.put( + RtfQueryResponseAndMetacardTransformer.COLUMN_ORDER_KEY, + COLUMN_ORDER.stream().collect(Collectors.joining(","))); + arguments.put( + RtfQueryResponseAndMetacardTransformer.COLUMN_ALIAS_KEY, + COLUMN_ALIASES.entrySet().stream() + .map(e -> String.format("%s=%s", e.getKey(), e.getValue())) + .collect(Collectors.joining(","))); + + BinaryContent content = transformer.transform(mockMetacard, arguments); + + assertThat("Transformed content cannot be null", content, notNullValue()); + assertThat( + "Content mime type must be 'application/rtf'", + content.getMimeType().toString(), + equalTo("application/rtf")); + + String rtfResult = inputStreamToString(content.getInputStream()); + + assertThat("Content must not be empty", rtfResult, is(not(isEmptyOrNullString()))); + + String referenceRtf = getReferenceMetacardWithArgsRtfFile(); + + assertThat( + "Produced RTF document must match reference", + rtfResult, + equalToIgnoringWhiteSpace(referenceRtf)); + } + + @Test + public void testTransformSourceResponseWithArgs() + throws CatalogTransformerException, IOException, MimeTypeParseException { + RtfQueryResponseAndMetacardTransformer transformer = createTransformer(); + + SourceResponse mockSourceResponse = mock(SourceResponse.class); + + List results = createMockResults(); + when(mockSourceResponse.getResults()).thenReturn(results); + Map arguments = new HashMap<>(); + arguments.put( + RtfQueryResponseAndMetacardTransformer.COLUMN_ORDER_KEY, new LinkedList<>(COLUMN_ORDER)); + arguments.put( + RtfQueryResponseAndMetacardTransformer.COLUMN_ALIAS_KEY, new HashMap<>(COLUMN_ALIASES)); + + BinaryContent content = transformer.transform(mockSourceResponse, arguments); + + assertThat("Transformed content cannot be null", content, notNullValue()); + assertThat( + "Content mime type must be 'application/rtf'", + content.getMimeType().toString(), + equalTo("application/rtf")); + + String rtfResult = inputStreamToString(content.getInputStream()); + + assertThat("Content must not be empty", rtfResult, is(not(isEmptyOrNullString()))); + + String referenceRtf = getReferenceSourceResponseWithArgsRtfFile(); + + assertThat( + "Produced RTF document must match reference", + rtfResult, + equalToIgnoringWhiteSpace(referenceRtf)); + } + private RtfQueryResponseAndMetacardTransformer createTransformer() throws MimeTypeParseException { return new RtfQueryResponseAndMetacardTransformer(MOCK_CATEGORY); } diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfTemplateTest.java b/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfTemplateTest.java index d1058b79da6b..a4c35826ba55 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfTemplateTest.java +++ b/catalog/transformer/catalog-transformer-rtf/src/test/java/ddf/catalog/transformer/output/rtf/RtfTemplateTest.java @@ -15,12 +15,15 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; import com.tutego.jrtf.Rtf; import ddf.catalog.data.Metacard; +import ddf.catalog.data.types.Core; import org.junit.Before; import org.junit.Test; @@ -57,4 +60,48 @@ public void testBuildingRtfFromTemplate() { finishedDoc, containsString(METACARD_TITLE)); } + + @Test + public void testBuildingRtfWithEmptyCategoryFromTemplate() { + when(mockMetacard.getAttribute(Core.THUMBNAIL)).thenReturn(null); + when(mockMetacard.getAttribute(EMPTY_ATTRIBUTE)).thenReturn(null); + when(mockMetacard.getAttribute(SIMPLE_ATTRIBUTE)).thenReturn(null); + when(mockMetacard.getAttribute(EXTENDED_ATTRIBUTE)).thenReturn(null); + RtfTemplate template = + new RtfTemplate.Builder().withMetacard(mockMetacard).withCategories(MOCK_CATEGORY).build(); + + assertThat("Template cannot be null", template, notNullValue()); + assertThat("There should be 5 categories", MOCK_CATEGORY.get(0).getAttributes(), hasSize(5)); + + Rtf doc = Rtf.rtf(); + + Rtf generatedTemplate = template.rtf(doc); + + assertThat("Rtf template instance cannot be null", generatedTemplate, notNullValue()); + + String finishedDoc = generatedTemplate.out().toString(); + + assertThat("RTF output cannot be null", finishedDoc, notNullValue()); + assertThat("RTF document must start with {\\rtf1", finishedDoc, startsWith("{\\rtf1")); + assertThat( + String.format("RTF document must contain section with title: %s", METACARD_TITLE), + finishedDoc, + containsString(METACARD_TITLE)); + assertThat( + String.format("RTF document must NOT contain section with title: %s", Core.THUMBNAIL), + finishedDoc, + not(containsString(Core.THUMBNAIL))); + assertThat( + String.format("RTF document must NOT contain section with title: %s", EMPTY_ATTRIBUTE), + finishedDoc, + not(containsString(EMPTY_ATTRIBUTE))); + assertThat( + String.format("RTF document must NOT contain section with title: %s", SIMPLE_ATTRIBUTE), + finishedDoc, + not(containsString(SIMPLE_ATTRIBUTE))); + assertThat( + String.format("RTF document must NOT contain section with title: %s", EXTENDED_ATTRIBUTE), + finishedDoc, + not(containsString(EXTENDED_ATTRIBUTE))); + } } diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-args.rtf b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-args.rtf new file mode 100644 index 000000000000..d2071e86e65c --- /dev/null +++ b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-args.rtf @@ -0,0 +1,26 @@ +{\rtf1\ansi\deff0 +{\fonttbl{\f0\fmodern\fcharset0 Arial;}{\f1\fnil\fcharset0 Times New Roman;}} +\sbknone{\qc +{\f1 {\b Test Metacard Title}}\par} +\sect +{\par} +\sect +{{\b Details}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{extended} +\cell +{Extended Value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{easy} +\cell +{Simple value} +\cell +\row}\sect +{\par} +} \ No newline at end of file diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-empty-thumbnail.rtf b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-empty-thumbnail.rtf index dc03f6f1b627..7dcfca5d0ace 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-empty-thumbnail.rtf +++ b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-empty-thumbnail.rtf @@ -1,445 +1,293 @@ {\rtf1\ansi\deff0 {\fonttbl{\f0\fmodern\fcharset0 Arial;}{\f1\fnil\fcharset0 Times New Roman;}} -\par\par{\qc +\sbknone{\qc {\f1 {\b Test Metacard With Bad Image}}\par} \sect {\par} \sect {{\b Associations}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Contact}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Core}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b DateTime}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Extended}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Location}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Media}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Security}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Topic}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Validation}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Version}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {--} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell -\row}} \ No newline at end of file +\row}\sect +{\par} +} \ No newline at end of file diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-gif.rtf b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-gif.rtf new file mode 100644 index 000000000000..34e118d7f41c --- /dev/null +++ b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard-with-gif.rtf @@ -0,0 +1,216 @@ +{\rtf1\ansi\deff0 +{\fonttbl{\f0\fmodern\fcharset0 Arial;}{\f1\fnil\fcharset0 Times New Roman;}} +\sbknone{\qc +{\f1 {\b Test Metacard With Gif Thumbnail}}\par} +\sect +{\par} +\sect +{{\b Associations}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Contact}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Core}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b DateTime}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Extended}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Location}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Media}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Security}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Topic}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Validation}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +\sect +{{\b Version}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} +\cell +{Simple value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Extended Attribute} +\cell +{Extended Value} +\cell +\row}\sect +{\par} +} \ No newline at end of file diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard.rtf b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard.rtf index 3e2e6e8436c5..773acfae8eb9 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard.rtf +++ b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-metacard.rtf @@ -1,29 +1,22 @@ {\rtf1\ansi\deff0 {\fonttbl{\f0\fmodern\fcharset0 Arial;}{\f1\fnil\fcharset0 Times New Roman;}} -\par\par{\qc +\sbknone{\qc {\f1 {\b Test Metacard Title}}\par} \sect {\par} \sect {{\b Associations}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -290,41 +283,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Contact}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -591,41 +570,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Core}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -892,41 +857,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b DateTime}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -1193,41 +1144,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Extended}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -1494,41 +1431,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Location}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -1795,41 +1718,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Media}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2096,41 +2005,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Security}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2397,41 +2292,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Topic}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2698,41 +2579,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Validation}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2999,41 +2866,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Version}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -3300,17 +3153,12 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell -\row}} \ No newline at end of file +\row}\sect +{\par} +} \ No newline at end of file diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response-with-args.rtf b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response-with-args.rtf new file mode 100644 index 000000000000..10f0d9f05110 --- /dev/null +++ b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response-with-args.rtf @@ -0,0 +1,98 @@ +{\rtf1\ansi\deff0 +{\fonttbl{\f0\fmodern\fcharset0 Arial;}{\f1\fnil\fcharset0 Times New Roman;}} +\sbknone{\qc +{\f1 {\b Metacard 1}}\par} +\sect +{\par} +\sect +{{\b Details}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{extended} +\cell +{Extended Value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{easy} +\cell +{Simple value} +\cell +\row}\sect +{\par} +\sect +\sbknone{\qc +{\f1 {\b Metacard 2}}\par} +\sect +{\par} +\sect +{{\b Details}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{extended} +\cell +{Extended Value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{easy} +\cell +{Simple value} +\cell +\row}\sect +{\par} +\sect +\sbknone{\qc +{\f1 {\b Metacard 3}}\par} +\sect +{\par} +\sect +{{\b Details}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{extended} +\cell +{Extended Value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{easy} +\cell +{Simple value} +\cell +\row}\sect +{\par} +\sect +\sbknone{\qc +{\f1 {\b Metacard 4}}\par} +\sect +{\par} +\sect +{{\b Details}\par} +\sect +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{extended} +\cell +{Extended Value} +\cell +\row}{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{easy} +\cell +{Simple value} +\cell +\row}\sect +{\par} +} \ No newline at end of file diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response.rtf b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response.rtf index 1bcdce5b218f..ab143625cb9d 100644 --- a/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response.rtf +++ b/catalog/transformer/catalog-transformer-rtf/src/test/resources/reference-source-response.rtf @@ -1,29 +1,22 @@ {\rtf1\ansi\deff0 {\fonttbl{\f0\fmodern\fcharset0 Arial;}{\f1\fnil\fcharset0 Times New Roman;}} -\par\par{\qc +\sbknone{\qc {\f1 {\b Metacard 1}}\par} \sect {\par} \sect {{\b Associations}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -290,41 +283,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Contact}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -591,41 +570,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Core}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -892,41 +857,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b DateTime}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -1193,41 +1144,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Extended}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -1494,41 +1431,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Location}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -1795,41 +1718,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Media}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2096,41 +2005,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Security}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2397,41 +2292,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Topic}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2698,41 +2579,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Validation}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -2999,41 +2866,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Version}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -3300,44 +3153,32 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect -\par\par{\qc +{\par} +\sect +\sbknone{\qc {\f1 {\b Metacard 2}}\par} \sect {\par} \sect {{\b Associations}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -3604,41 +3445,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Contact}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -3905,41 +3732,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Core}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -4206,41 +4019,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b DateTime}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -4507,41 +4306,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Extended}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -4808,41 +4593,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Location}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -5109,41 +4880,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Media}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -5410,41 +5167,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Security}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -5711,41 +5454,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Topic}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -6012,41 +5741,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Validation}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -6313,41 +6028,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Version}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -6614,44 +6315,32 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect -\par\par{\qc +{\par} +\sect +\sbknone{\qc {\f1 {\b Metacard 3}}\par} \sect {\par} \sect {{\b Associations}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -6918,41 +6607,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Contact}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -7219,41 +6894,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Core}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -7520,41 +7181,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b DateTime}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -7821,41 +7468,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Extended}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -8122,41 +7755,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Location}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -8423,41 +8042,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Media}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -8724,41 +8329,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Security}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -9025,41 +8616,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Topic}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -9326,41 +8903,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Validation}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -9627,41 +9190,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Version}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -9928,44 +9477,32 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect -\par\par{\qc +{\par} +\sect +\sbknone{\qc {\f1 {\b Metacard 4}}\par} \sect {\par} \sect {{\b Associations}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -10232,41 +9769,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Contact}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -10533,41 +10056,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Core}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -10834,41 +10343,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b DateTime}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -11135,41 +10630,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Extended}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -11436,41 +10917,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Location}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -11737,41 +11204,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Media}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -12038,41 +11491,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Security}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -12339,41 +11778,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Topic}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -12640,41 +12065,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Validation}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -12941,41 +12352,27 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell \row}\sect {\par} \sect {{\b Version}\par} \sect -{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Empty} -\cell -{} -\cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Unknown} +\sbknone{\trowd\trautofit1\intbl +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 +{Simple} \cell -{--} +{Simple value} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx1 +\clbrdrt\brdrs\clbrdrr\brdrs\clbrdrl\brdrs\clbrdrb\brdrs\cellx2 {Thumbnail} \cell {{\pict\jpegblip @@ -13242,17 +12639,12 @@ c914283de6da9ef3334a4e4eed9a145455912a412100080040020010008004002001000800400200 d9}} \cell \row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx1 +\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\clbrdrt\brdrs\cellx2 {Extended Attribute} \cell {Extended Value} \cell -\row}{\trowd\trautofit1\intbl -\cellx1 -\cellx2 -{Simple} -\cell -{Simple value} -\cell -\row}} \ No newline at end of file +\row}\sect +{\par} +} \ No newline at end of file diff --git a/catalog/transformer/catalog-transformer-rtf/src/test/resources/test-gif-image-string.txt b/catalog/transformer/catalog-transformer-rtf/src/test/resources/test-gif-image-string.txt new file mode 100644 index 000000000000..877d938aed98 --- /dev/null +++ b/catalog/transformer/catalog-transformer-rtf/src/test/resources/test-gif-image-string.txt @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/catalog/transformer/catalog-transformer-xlsx/pom.xml b/catalog/transformer/catalog-transformer-xlsx/pom.xml index 5e5a1e81f41e..b8fab7ce4558 100644 --- a/catalog/transformer/catalog-transformer-xlsx/pom.xml +++ b/catalog/transformer/catalog-transformer-xlsx/pom.xml @@ -64,6 +64,16 @@ catalog-core-api-impl ${project.version} + + ddf.catalog.transformer + catalog-transformer-csv-common + ${project.version} + + + org.apache.commons + commons-csv + ${commons-csv.version} + @@ -74,7 +84,9 @@ - catalog-core-api-impl + catalog-core-api-impl, + commons-csv, + catalog-transformer-csv-common ${project.artifactId} @@ -98,17 +110,17 @@ INSTRUCTION COVEREDRATIO - 0.95 + 0.83 BRANCH COVEREDRATIO - 1.0 + .80 COMPLEXITY COVEREDRATIO - 1.0 + .69 diff --git a/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardTransformer.java b/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardTransformer.java index bfcc2da4d0a7..27adce6c75eb 100644 --- a/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardTransformer.java +++ b/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardTransformer.java @@ -18,9 +18,12 @@ import ddf.catalog.transform.CatalogTransformerException; import ddf.catalog.transform.MetacardTransformer; import java.io.Serializable; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,8 +40,25 @@ public BinaryContent transform(Metacard metacard, Map argu throw new CatalogTransformerException("Null metacard cannot be transformed to XLSX"); } + String aliasesArg = (String) arguments.getOrDefault("aliases", new String()); + Map aliases = + (StringUtils.isNotBlank(aliasesArg)) + ? Arrays.stream(aliasesArg.split(",")) + .map(s -> s.split("=")) + .collect(Collectors.toMap(k -> k[0], k -> k[1])) + : Collections.EMPTY_MAP; + String attributeString = + arguments.get(XlsxMetacardUtility.COLUMN_ORDER_KEY) != null + ? (String) arguments.get(XlsxMetacardUtility.COLUMN_ORDER_KEY) + : ""; + + List attributes = + Arrays.asList((attributeString).split(",")).stream() + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); + List metacards = Collections.singletonList(metacard); - return XlsxMetacardUtility.buildSpreadSheet(metacards); + return XlsxMetacardUtility.buildSpreadSheet(metacards, aliases, attributes); } } diff --git a/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtility.java b/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtility.java index 3cac881f7cf5..5bcf4a26bfc9 100644 --- a/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtility.java +++ b/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtility.java @@ -15,23 +15,29 @@ import static com.google.common.net.MediaType.OOXML_SHEET; -import ddf.catalog.data.Attribute; import ddf.catalog.data.AttributeDescriptor; import ddf.catalog.data.BinaryContent; import ddf.catalog.data.Metacard; import ddf.catalog.data.impl.BinaryContentImpl; +import ddf.catalog.transformer.csv.common.CsvTransformer; +import ddf.catalog.transformer.csv.common.MetacardIterator; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.ArrayList; +import java.io.Serializable; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import javax.activation.MimeType; import javax.activation.MimeTypeParseException; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; @@ -43,6 +49,10 @@ class XlsxMetacardUtility { private static final Logger LOGGER = LoggerFactory.getLogger(XlsxMetacardUtility.class); + public static final String COLUMN_ORDER_KEY = "columnOrder"; + + public static final String COLUMN_ALIAS_KEY = "aliases"; + private static MimeType mimeType = new MimeType(); static { @@ -56,45 +66,73 @@ class XlsxMetacardUtility { private XlsxMetacardUtility() {} - public static BinaryContent buildSpreadSheet(List metacards) { + public static BinaryContent buildSpreadSheet( + List metacards, Map aliases, List attributeOrder) { if (metacards.isEmpty()) { return null; } Set attributeDescriptors = - metacards.get(0).getMetacardType().getAttributeDescriptors(); + CsvTransformer.getNonEmptyValueAttributes(metacards); - int rowIndex = 0; - int cellIndex = 0; + Set descriptors = + CollectionUtils.isEmpty(attributeOrder) + ? attributeDescriptors + : attributeDescriptors.stream() + .filter(attr -> attributeOrder.contains(attr.getName())) + .collect(Collectors.toSet()); Workbook workbook = new XSSFWorkbook(); - Sheet sheet = workbook.createSheet(); - Row row = sheet.createRow(rowIndex++); + List sortedAttributeDescriptors = + CsvTransformer.sortAttributes(descriptors, attributeOrder); + + Sheet sheet = writeHeaderRow(sortedAttributeDescriptors, aliases, workbook); + + writeMetacardValues(metacards, sortedAttributeDescriptors, sheet); + + return writeWorkbook(workbook); + } + + static Sheet writeHeaderRow( + List orderedAttributeDescriptors, + Map columnAliasMap, + Workbook workbook) { CellStyle style = workbook.createCellStyle(); Font font = workbook.createFont(); font.setBold(true); style.setFont(font); - - // Write header row. - for (AttributeDescriptor attributeDescriptor : attributeDescriptors) { + style.setAlignment(HorizontalAlignment.CENTER); + Sheet sheet = workbook.createSheet(); + Row row = sheet.createRow(0); + int cellIndex = 0; + for (AttributeDescriptor attributeDescriptor : orderedAttributeDescriptors) { String attributeName = attributeDescriptor.getName(); Cell cell = row.createCell(cellIndex++); - cell.setCellValue(attributeName); + cell.setCellValue( + Optional.ofNullable(columnAliasMap.get(attributeName)).orElse(attributeName)); cell.setCellStyle(style); } + return sheet; + } + private static void writeMetacardValues( + List metacards, + List orderedAttributeDescriptors, + Sheet sheet) { + int rowIndex = 1; // start at 1 since the header is row 0 for (Metacard metacard : metacards) { - List values = getMetacardValues(metacard); - row = sheet.createRow(rowIndex++); - - cellIndex = 0; - for (String value : values) { - row.createCell(cellIndex++).setCellValue(value); + Row row = sheet.createRow(rowIndex++); + int cellIndex = 0; + Iterator metacardIterator = + new MetacardIterator(metacard, orderedAttributeDescriptors); + while (metacardIterator.hasNext()) { + row.createCell(cellIndex++).setCellValue(String.valueOf(metacardIterator.next())); } } - - return writeWorkbook(workbook); + for (int i = 0; i < sheet.getRow(0).getPhysicalNumberOfCells(); i++) { + sheet.autoSizeColumn(i); + } } private static BinaryContent writeWorkbook(Workbook workbook) { @@ -109,29 +147,4 @@ private static BinaryContent writeWorkbook(Workbook workbook) { return new BinaryContentImpl( new ByteArrayInputStream(byteArrayOutputStream.toByteArray()), mimeType); } - - private static List getMetacardValues(Metacard metacard) { - List values = new ArrayList<>(); - - Set attributeDescriptors = - metacard.getMetacardType().getAttributeDescriptors(); - - for (AttributeDescriptor attributeDescriptor : attributeDescriptors) { - String attributeName = attributeDescriptor.getName(); - Attribute attribute = metacard.getAttribute(attributeName); - - if (attribute != null) { - if (attributeDescriptor.isMultiValued()) { - String value = StringUtils.join(attribute.getValues(), ", "); - values.add(value); - } else { - values.add(attribute.getValue().toString()); - } - } else { - values.add(""); - } - } - - return values; - } } diff --git a/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxQueryResponseTransformer.java b/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxQueryResponseTransformer.java index 6cc072258759..1157acd3f5f8 100644 --- a/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxQueryResponseTransformer.java +++ b/catalog/transformer/catalog-transformer-xlsx/src/main/java/ddf/catalog/transformer/xlsx/XlsxQueryResponseTransformer.java @@ -20,8 +20,10 @@ import ddf.catalog.transform.CatalogTransformerException; import ddf.catalog.transform.QueryResponseTransformer; import java.io.Serializable; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,9 +41,18 @@ public BinaryContent transform(SourceResponse sourceResponse, Map attributeOrder = + Optional.ofNullable((List) arguments.get(XlsxMetacardUtility.COLUMN_ORDER_KEY)) + .orElse(Collections.emptyList()); + + Map columnAliasMap = + Optional.ofNullable( + (Map) arguments.get(XlsxMetacardUtility.COLUMN_ALIAS_KEY)) + .orElse(Collections.emptyMap()); + List metacards = sourceResponse.getResults().stream().map(Result::getMetacard).collect(Collectors.toList()); - return XlsxMetacardUtility.buildSpreadSheet(metacards); + return XlsxMetacardUtility.buildSpreadSheet(metacards, columnAliasMap, attributeOrder); } } diff --git a/catalog/transformer/catalog-transformer-xlsx/src/test/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtilityTest.java b/catalog/transformer/catalog-transformer-xlsx/src/test/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtilityTest.java index d22e7e384a02..c0f0c801e62e 100644 --- a/catalog/transformer/catalog-transformer-xlsx/src/test/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtilityTest.java +++ b/catalog/transformer/catalog-transformer-xlsx/src/test/java/ddf/catalog/transformer/xlsx/XlsxMetacardUtilityTest.java @@ -19,23 +19,34 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; +import ddf.catalog.data.AttributeDescriptor; import ddf.catalog.data.BinaryContent; import ddf.catalog.data.Metacard; import ddf.catalog.data.impl.AttributeImpl; import ddf.catalog.data.impl.MetacardImpl; import ddf.catalog.data.types.Core; import java.io.Serializable; +import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import javax.activation.MimeType; import javax.activation.MimeTypeParseException; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.Test; public class XlsxMetacardUtilityTest { @Test public void testEmptyMetacardList() { - BinaryContent binaryContent = XlsxMetacardUtility.buildSpreadSheet(Collections.emptyList()); + BinaryContent binaryContent = + XlsxMetacardUtility.buildSpreadSheet( + Collections.emptyList(), Collections.emptyMap(), Collections.emptyList()); assertThat(binaryContent, nullValue()); } @@ -45,7 +56,8 @@ public void testContentReturnType() { Metacard metacard = new MetacardImpl(); BinaryContent binaryContent = - XlsxMetacardUtility.buildSpreadSheet(Collections.singletonList(metacard)); + XlsxMetacardUtility.buildSpreadSheet( + Collections.singletonList(metacard), Collections.emptyMap(), Collections.emptyList()); MimeType mimeType = new MimeType(); try { @@ -66,7 +78,8 @@ public void testNullMetacardAttribute() { metacard.setAttribute(new AttributeImpl(Metacard.CONTENT_TYPE, (Serializable) null)); BinaryContent binaryContent = - XlsxMetacardUtility.buildSpreadSheet(Collections.singletonList(metacard)); + XlsxMetacardUtility.buildSpreadSheet( + Collections.singletonList(metacard), Collections.emptyMap(), Collections.emptyList()); assertThat(binaryContent, notNullValue()); } @@ -74,10 +87,11 @@ public void testNullMetacardAttribute() { @Test public void testNonNullMetacardAttribute() { Metacard metacard = new MetacardImpl(); - metacard.setAttribute(new AttributeImpl(Metacard.ID, UUID.randomUUID())); + metacard.setAttribute(new AttributeImpl(Metacard.ID, UUID.randomUUID().toString())); BinaryContent binaryContent = - XlsxMetacardUtility.buildSpreadSheet(Collections.singletonList(metacard)); + XlsxMetacardUtility.buildSpreadSheet( + Collections.singletonList(metacard), Collections.emptyMap(), Collections.emptyList()); assertThat(binaryContent, notNullValue()); } @@ -85,11 +99,52 @@ public void testNonNullMetacardAttribute() { @Test public void testMultiValueMetacardAttribute() { Metacard metacard = new MetacardImpl(); - metacard.setAttribute(new AttributeImpl(Core.LANGUAGE, new String[] {"english", "spanish"})); + + metacard.setAttribute( + AttributeImpl.fromMultipleValues(Core.LANGUAGE, Arrays.asList("english", "spanish"))); BinaryContent binaryContent = - XlsxMetacardUtility.buildSpreadSheet(Collections.singletonList(metacard)); + XlsxMetacardUtility.buildSpreadSheet( + Collections.singletonList(metacard), Collections.emptyMap(), Collections.emptyList()); assertThat(binaryContent, notNullValue()); } + + @Test + public void testAliasMapping() { + Metacard metacard = new MetacardImpl(); + + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = + XlsxMetacardUtility.writeHeaderRow( + metacard.getMetacardType().getAttributeDescriptors().stream() + .filter(desc -> "id".equalsIgnoreCase(desc.getName())) + .collect(Collectors.toList()), + Collections.singletonMap("id", "ALIAS"), + workbook); + + Row header = sheet.getRow(0); + assertThat(header, notNullValue()); + Cell id = header.getCell(0); + assertThat(id.getStringCellValue(), is("ALIAS")); + } + + @Test + public void testColumnOrder() { + Metacard metacard = new MetacardImpl(); + + Workbook workbook = new XSSFWorkbook(); + List orderedDescriptors = + metacard.getMetacardType().getAttributeDescriptors().stream() + .sorted((desc1, desc2) -> desc1.getName().compareTo(desc2.getName())) + .collect(Collectors.toList()); + Sheet sheet = + XlsxMetacardUtility.writeHeaderRow(orderedDescriptors, Collections.emptyMap(), workbook); + + Row header = sheet.getRow(0); + assertThat(header, notNullValue()); + for (int i = 0; i < orderedDescriptors.size(); i++) { + assertThat(header.getCell(i).getStringCellValue(), is(orderedDescriptors.get(i).getName())); + } + } } diff --git a/distribution/docs/src/main/resources/content/_integrating/_endpoints/catalog-rest-endpoint.adoc b/distribution/docs/src/main/resources/content/_integrating/_endpoints/catalog-rest-endpoint.adoc index 45910db886c8..fed5fb6b3999 100644 --- a/distribution/docs/src/main/resources/content/_integrating/_endpoints/catalog-rest-endpoint.adoc +++ b/distribution/docs/src/main/resources/content/_integrating/_endpoints/catalog-rest-endpoint.adoc @@ -221,11 +221,13 @@ If the metacard or resource is not returned successfully, check for these errors |`
Unable to retrieve requested metacard.
` |Invalid Metacard ID -.3+.^|`500 Server Error` +.4+.^|`500 Server Error` |`
Unknown error occurred while processing request.
` |Transformer is invalid, unsupported, or not configured. |`
Unable to transform Metacard.  Try different transformer: 
` |Metacard does not have an associated resource (is metadata only). +|`
Resource file is not available
` +|The resource file/data is not accessible or doesn't exist |`
READ failed due to unexpected exception: 
` |Invalid source ID, or source unavailable. diff --git a/distribution/test/itests/test-itests-ddf/src/test/java/ddf/test/itests/catalog/TestFederation.java b/distribution/test/itests/test-itests-ddf/src/test/java/ddf/test/itests/catalog/TestFederation.java index 4c552dfb16f0..778b8825a382 100644 --- a/distribution/test/itests/test-itests-ddf/src/test/java/ddf/test/itests/catalog/TestFederation.java +++ b/distribution/test/itests/test-itests-ddf/src/test/java/ddf/test/itests/catalog/TestFederation.java @@ -637,7 +637,7 @@ public void testFederatedRetrieveProductInvalidResourceUrl() throws Exception { .assertThat() .contentType("text/html") .statusCode(equalTo(500)) - .body(containsString("Unable to transform Metacard.")); + .body(containsString("Resource file is not available")); } @Test