prepare document as late as possible

This commit is contained in:
Jochen Stärk
2017-11-30 14:58:29 +01:00
parent 50f9fe5f65
commit 4b4450410d
7 changed files with 197 additions and 180 deletions

View File

@@ -1,22 +1,26 @@
1.5.0
=====
<date>
Now using factory. Export is now also possible on OutputStream.
Further dev improvements: no more need to call PDFattachZugferdFile(null) or exporter close();
toecount now has options to combine documents and upgrade xml file from ZF1 to ZF2
More unit tests, e.g. for custom xml export, PDF/A Schema extensions.
Toecount is now integrated and the main class so "java -jar mustang-1.5.0.jar" should suffice
2017-11-30
Support for ZUGFeRD 2.0 "public review" part 1.
Now using factories to create/configure ZUGFeRDExporter.
Export is now also possible on OutputStream.
Removed need to call PDFattachZugferdFile(null) or exporter close();
More unit tests, e.g. for custom xml export, PDF/A Schema extensions.
The command line utility "toecount" is now integrated and the main class so "java -jar mustang-1.5.0.jar" should suffice.
It now also features options to combine PDF with XML and upgrade XML files from ZF1 to ZF2.
First attempts be able to start with a PDF/A-3 in the first place and better error messages for non-PDF/A-conformance.
Further changes:
be able to specify profile #50
close pdf files automatically after export #49
ZUGFeRDimporter does not close #48
command line option -e does not work on all-in-one jar #47
invoices have wrong namespaces #45
invalid a3 #44
warn on export #39
* be able to specify profile #50
* close pdf files automatically after export #49
* ZUGFeRDimporter does not close #48
* command line option -e does not work on all-in-one jar #47
* invoices have wrong namespaces #45
* invalid a3 #44
* warn on export #39
1.4.0

Binary file not shown.

Binary file not shown.

View File

@@ -3,7 +3,6 @@ package org.mustangproject.ZUGFeRD;
import java.io.IOException;
import java.io.InputStream;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.xmpbox.XMPMetadata;
public interface IExporterFactory {
@@ -25,8 +24,6 @@ public interface IExporterFactory {
* @throws IOException
*/
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException;
public void prepareDocument(PDDocument doc) throws IOException;
public void addXMP(XMPMetadata metadata);
public IExporterFactory setCreator(String creator);
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel);
@@ -34,6 +31,5 @@ public interface IExporterFactory {
public IExporterFactory setZUGFeRDVersion(int version);
public IExporterFactory ignorePDFAErrors();
public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel);
public IExporterFactory setAttachZUGFeRDHeaders(final boolean attachZugferdHeaders);
}

View File

@@ -16,18 +16,29 @@ import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.type.BadFieldValueException;
import org.apache.xmpbox.xml.XmpSerializer;
import javax.xml.transform.TransformerException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
@@ -59,7 +70,7 @@ public class ZUGFeRDExporter implements Closeable {
// BASIC, COMFORT etc - may be set from outside.
@Deprecated
private ZUGFeRDConformanceLevel zUGFeRDConformanceLevel = ZUGFeRDConformanceLevel.EXTENDED;
private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EXTENDED;
/**
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
@@ -68,14 +79,22 @@ public class ZUGFeRDExporter implements Closeable {
* IZUGFeRDExportableTransaction for the XML to be populated.
*/
IXMLProvider xmlProvider;
protected PDMetadata metadata = null;
protected PDFAIdentificationSchema pdfaid = null;
protected XMPMetadata xmp = null;
protected String producer = "mustangproject";
protected String creator = "mustangproject";
@Deprecated
private boolean ignoreA1Errors;
protected boolean ensurePDFisUpgraded = true;
private PDDocument doc;
int ZFVersion;
private boolean disableAutoClose;
private boolean fileAttached=false;
private boolean fileAttached = false;
protected boolean attachZUGFeRDHeaders = true;
public ZUGFeRDExporter() {
init();
@@ -116,7 +135,7 @@ public class ZUGFeRDExporter implements Closeable {
}
}
@Deprecated
@Deprecated
public void setZUGFeRDVersion(int ver) {
if (ver == 1) {
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
@@ -233,8 +252,7 @@ public class ZUGFeRDExporter implements Closeable {
public PDDocumentCatalog PDFmakeA3compliant(String filename, String producer, String creator,
boolean attachZugferdHeaders) throws IOException, TransformerException {
doc = createPDFA1Factory().setProducer(producer).setCreator(creator)
.setAttachZUGFeRDHeaders(attachZugferdHeaders).load(filename).doc;
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(filename).doc;
return doc.getDocumentCatalog();
}
@@ -246,8 +264,7 @@ public class ZUGFeRDExporter implements Closeable {
public PDDocumentCatalog PDFmakeA3compliant(InputStream file, String producer, String creator,
boolean attachZugferdHeaders) throws IOException, TransformerException {
doc = createPDFA1Factory().setProducer(producer).setCreator(creator)
.setAttachZUGFeRDHeaders(attachZugferdHeaders).load(file).doc;
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(file).doc;
return doc.getDocumentCatalog();
}
@@ -257,7 +274,7 @@ public class ZUGFeRDExporter implements Closeable {
if (ignoreA1Errors) {
factory.ignorePDFAErrors();
}
return factory.setZUGFeRDConformanceLevel(zUGFeRDConformanceLevel).setConformanceLevel(conformanceLevel);
return factory.setZUGFeRDConformanceLevel(profile).setConformanceLevel(conformanceLevel);
}
@Override
@@ -277,6 +294,8 @@ public class ZUGFeRDExporter implements Closeable {
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
*/
public void PDFattachZugferdFile(IZUGFeRDExportableTransaction trans) throws IOException {
prepareDocument(doc);
xmlProvider.generateXML(trans);
String filename = getFilenameForVersion(ZFVersion);
PDFAttachGenericFile(doc, filename, "Alternative",
@@ -286,7 +305,8 @@ public class ZUGFeRDExporter implements Closeable {
public void export(String ZUGFeRDfilename) throws IOException {
if (!fileAttached) {
throw new IOException("File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
throw new IOException(
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
}
doc.save(ZUGFeRDfilename);
if (!disableAutoClose) {
@@ -296,7 +316,8 @@ public class ZUGFeRDExporter implements Closeable {
public void export(OutputStream output) throws IOException {
if (!fileAttached) {
throw new IOException("File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
throw new IOException(
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
}
doc.save(output);
if (!disableAutoClose) {
@@ -304,7 +325,6 @@ public class ZUGFeRDExporter implements Closeable {
}
}
/**
* Embeds an external file (generic - any type allowed) in the PDF.
*
@@ -324,7 +344,7 @@ public class ZUGFeRDExporter implements Closeable {
*/
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
String subType, byte[] data) throws IOException {
fileAttached=true;
fileAttached = true;
PDComplexFileSpecification fs = new PDComplexFileSpecification();
fs.setFile(filename);
@@ -412,7 +432,7 @@ public class ZUGFeRDExporter implements Closeable {
if (zUGFeRDConformanceLevel == null) {
throw new NullPointerException("ZUGFeRD conformance level");
}
this.zUGFeRDConformanceLevel = zUGFeRDConformanceLevel;
this.profile = zUGFeRDConformanceLevel;
}
/**
@@ -425,7 +445,7 @@ public class ZUGFeRDExporter implements Closeable {
*/
@Deprecated
public void setZUGFeRDConformanceLevel(String zUGFeRDConformanceLevel) {
this.zUGFeRDConformanceLevel = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel);
this.profile = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel);
}
/****
@@ -437,6 +457,107 @@ public class ZUGFeRDExporter implements Closeable {
return doc;
}
/**
* This will add both the RDF-indication which embedded file is Zugferd and the
* neccessary PDF/A schema extension description to be able to add this
* information to RDF
*
* @param metadata
*/
protected void addXMP(XMPMetadata metadata) {
if (attachZUGFeRDHeaders) {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile,
ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion),
ZUGFeRDExporter.getFilenameForVersion(ZFVersion));
metadata.addSchema(zf);
}
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZUGFeRDHeaders);
pdfaex.setZUGFeRDVersion(ZFVersion);
metadata.addSchema(pdfaex);
}
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
XmpSerializer serializer = new XmpSerializer();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
String prefix = "<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
String suffix = "<?xpacket end=\"w\"?>";
try {
buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44
serializer.serialize(xmpMetadata, buffer, false);
buffer.write(suffix.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return buffer.toByteArray();
}
protected void prepareDocument(PDDocument doc) throws IOException {
String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")";
PDDocumentCatalog cat = doc.getDocumentCatalog();
metadata = new PDMetadata(doc);
cat.setMetadata(metadata);
xmp = XMPMetadata.createXMPMetadata();
pdfaid = new PDFAIdentificationSchema(xmp);
xmp.addSchema(pdfaid);
DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema();
dc.addCreator(creator);
XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema();
xsb.setCreatorTool(creator);
xsb.setCreateDate(GregorianCalendar.getInstance());
// PDDocumentInformation pdi=doc.getDocumentInformation();
PDDocumentInformation pdi = new PDDocumentInformation();
pdi.setProducer(fullProducer);
pdi.setAuthor(creator);
doc.setDocumentInformation(pdi);
AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema();
pdf.setProducer(fullProducer);
if (ensurePDFisUpgraded) {
try {
pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$
} catch (BadFieldValueException ex) {
// This should be impossible, because it would occur only if an illegal
// conformance level is supplied,
// however the enum enforces that the conformance level is valid.
throw new Error(ex);
}
pdfaid.setPart(3);
}
if (attachZUGFeRDHeaders) {
addXMP(xmp); /*
* this is the only line where we do something Zugferd-specific, i.e. add PDF
* metadata specifically for Zugferd, not generically for a embedded file
*/
}
try {
metadata.importXMPMetadata(serializeXmpMetadata(xmp));
} catch (TransformerException e) {
throw new ZUGFeRDExportException("Could not export XmpMetadata", e);
}
}
public boolean isAutoCloseDisabled() {
return disableAutoClose;
}
@@ -445,4 +566,22 @@ public class ZUGFeRDExporter implements Closeable {
this.disableAutoClose = disableAutoClose;
}
@Deprecated
public void setCreator(String creator) {
this.creator = creator;
}
@Deprecated
public void setProducer(String producer) {
this.producer = producer;
}
public void setPDFA3(boolean ensurePDFisUpgraded) {
this.ensurePDFisUpgraded = ensurePDFisUpgraded;
}
public void setAttachZUGFeRDHeaders(boolean attachZUGFeRDHeaders) {
this.attachZUGFeRDHeaders=attachZUGFeRDHeaders;
}
}

View File

@@ -1,55 +1,10 @@
package org.mustangproject.ZUGFeRD;
import java.io.IOException;
import javax.xml.transform.TransformerException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.xmpbox.type.BadFieldValueException;
public class ZUGFeRDExporterFromA1Factory extends ZUGFeRDExporterFromA3Factory implements IExporterFactory {
public ZUGFeRDExporterFromA1Factory() {
ensurePDFisUpgraded=true;
/**
* Make a PDF A/3 from the PDF A/1
*/
public void prepareDocument(PDDocument doc) throws IOException {
super.prepareDocument(doc);
/*
* // Mandatory: PDF/A3-a is tagged PDF which has to be expressed using a //
* MarkInfo dictionary (PDF A/3 Standard sec. 6.7.2.2) PDMarkInfo markinfo = new
* PDMarkInfo(); markinfo.setMarked(true);
* doc.getDocumentCatalog().setMarkInfo(markinfo);
*/
/*
*
* To be on the safe side, we use level B without Markinfo because we can not
* guarantee that the user correctly tagged the templates for the PDF.
*/
try {
pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$
} catch (BadFieldValueException ex) {
// This should be impossible, because it would occur only if an illegal
// conformance level is supplied,
// however the enum enforces that the conformance level is valid.
throw new Error(ex);
}
pdfaid.setPart(3);
if (attachZugferdHeaders) {
addXMP(xmp); /*
* this is the only line where we do something Zugferd-specific, i.e. add PDF
* metadata specifically for Zugferd, not generically for a embedded file
*/
}
try {
metadata.importXMPMetadata(serializeXmpMetadata(xmp));
} catch (TransformerException e) {
throw new ZUGFeRDExportException("Could not export XmpMetadata", e);
}
}
}

View File

@@ -2,31 +2,19 @@ package org.mustangproject.ZUGFeRD;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.xml.XmpSerializer;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.xml.transform.TransformerException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.GregorianCalendar;
import java.util.zip.ZipFile;
public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
protected boolean ignorePDFAErrors = false;
@@ -34,13 +22,10 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
protected String producer = "mustangproject";
protected String creator = "mustangproject";
protected boolean attachZugferdHeaders = true;
protected PDMetadata metadata = null;
protected PDFAIdentificationSchema pdfaid = null;
protected XMPMetadata xmp = null;
protected int ZFVersion=ZUGFeRDExporter.DefaultZUGFeRDVersion;
protected boolean ensurePDFisUpgraded=false;
private boolean attachZUGFeRDHeaders=true;
/**
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
* metadata level, this will not e.g. convert graphics to JPG-2000)
@@ -53,47 +38,19 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
ensurePDFIsValidPDFA(new FileDataSource(pdfFilename));
ZUGFeRDExporter zugFeRDExporter;
PDDocument doc = PDDocument.load(new File(pdfFilename));
prepareDocument(doc);
zugFeRDExporter = new ZUGFeRDExporter(doc);
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
zugFeRDExporter.setCreator(creator);
zugFeRDExporter.setProducer(producer);
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
return zugFeRDExporter;
}
public void prepareDocument(PDDocument doc) throws IOException {
String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")";
PDDocumentCatalog cat = doc.getDocumentCatalog();
metadata = new PDMetadata(doc);
cat.setMetadata(metadata);
xmp = XMPMetadata.createXMPMetadata();
pdfaid = new PDFAIdentificationSchema(xmp);
xmp.addSchema(pdfaid);
DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema();
dc.addCreator(creator);
XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema();
xsb.setCreatorTool(creator);
xsb.setCreateDate(GregorianCalendar.getInstance());
// PDDocumentInformation pdi=doc.getDocumentInformation();
PDDocumentInformation pdi = new PDDocumentInformation();
pdi.setProducer(fullProducer);
pdi.setAuthor(creator);
doc.setDocumentInformation(pdi);
AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema();
pdf.setProducer(fullProducer);
}
/**
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
@@ -106,13 +63,22 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
ZUGFeRDExporter zugFeRDExporter;
PDDocument doc = PDDocument.load(pdfBinary);
prepareDocument(doc);
zugFeRDExporter = new ZUGFeRDExporter(doc);
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
zugFeRDExporter.setCreator(creator);
zugFeRDExporter.setProducer(producer);
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
return zugFeRDExporter;
}
public ZUGFeRDExporterFromA3Factory () {
ensurePDFisUpgraded=false;
}
/**
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
* metadata level, this will not e.g. convert graphics to JPG-2000)
@@ -135,53 +101,10 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
IOUtils.copy(in, buffer);
return buffer.toByteArray();
}
public byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
XmpSerializer serializer = new XmpSerializer();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
String prefix="<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
String suffix="<?xpacket end=\"w\"?>";
try {
buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44
serializer.serialize(xmpMetadata, buffer, false);
buffer.write(suffix.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return buffer.toByteArray();
}
private static boolean isValidA1(DataSource dataSource) throws IOException {
private static boolean isValidA1(DataSource dataSource) throws IOException {
return getPDFAParserValidationResult(new PreflightParser(dataSource));
}
/**
* This will add both the RDF-indication which embedded file is Zugferd and the
* neccessary PDF/A schema extension description to be able to add this
* information to RDF
*
* @param metadata
*/
public void addXMP(XMPMetadata metadata) {
if (attachZugferdHeaders) {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, zugferdConformanceLevel, ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion), ZUGFeRDExporter.getFilenameForVersion(ZFVersion) );
metadata.addSchema(zf);
}
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZugferdHeaders);
pdfaex.setZUGFeRDVersion(ZFVersion);
metadata.addSchema(pdfaex);
}
/**
* Sets the ZUGFeRD conformance level (override).
*
@@ -246,10 +169,6 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
return this;
}
public IExporterFactory setAttachZUGFeRDHeaders(final boolean attachZugferdHeaders) {
this.attachZugferdHeaders = attachZugferdHeaders;
return this;
}
public IExporterFactory setCreator(String creator) {
this.creator = creator;
@@ -260,6 +179,10 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
this.producer = producer;
return this;
}
public IExporterFactory setAttachZUGFeRDHeaders(boolean attachHeaders) {
this.attachZUGFeRDHeaders = attachHeaders;
return this;
}
@Override