You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2011/08/04 10:53:22 UTC
svn commit: r1153788 - in
/pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser:
NSMapping.java PDFAExtentionSchemaPreprocessor.java XMPDocumentBuilder.java
XMPDocumentPreprocessor.java XMPSchemaFactory.java
Author: leleueri
Date: Thu Aug 4 08:53:21 2011
New Revision: 1153788
URL: http://svn.apache.org/viewvc?rev=1153788&view=rev
Log:
Update XMPBox with last changes of the GitHub repository.
Added:
pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/PDFAExtentionSchemaPreprocessor.java
pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentPreprocessor.java
Modified:
pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/NSMapping.java
pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentBuilder.java
pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPSchemaFactory.java
Modified: pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/NSMapping.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/NSMapping.java?rev=1153788&r1=1153787&r2=1153788&view=diff
==============================================================================
--- pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/NSMapping.java (original)
+++ pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/NSMapping.java Thu Aug 4 08:53:21 2011
@@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import javax.xml.namespace.QName;
@@ -99,6 +100,52 @@ public class NSMapping {
}
+
+ /**
+ * Import an NSMapping content.
+ * @param imp
+ */
+ public void importNSMapping(NSMapping imp) throws XmpSchemaException {
+ mergeNSMap(imp.nsMaps);
+ mergeComplexBasicTypesDeclarationEntireXMPLevel(imp.complexBasicTypesDeclarationEntireXMPLevel);
+ mergeComplexBasicTypesDeclarationSchemaLevel(imp.complexBasicTypesDeclarationSchemaLevel);
+ mergeComplexBasicTypesDeclarationPropertyLevel(imp.complexBasicTypesDeclarationPropertyLevel);
+ }
+
+ protected void mergeNSMap(Map<String, XMPSchemaFactory> map) throws XmpSchemaException {
+ for (Entry<String, XMPSchemaFactory> entry : map.entrySet() ) {
+ if (this.nsMaps.containsKey(entry.getKey())) {
+ this.nsMaps.get(entry.getKey()).importXMPSchemaFactory(entry.getValue());
+ } else {
+ this.nsMaps.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ private void mergeComplexBasicTypesDeclarationEntireXMPLevel(Map<String, String> external) {
+ for (Entry<String, String> entry : external.entrySet()) {
+ if(!complexBasicTypesDeclarationEntireXMPLevel.containsKey(entry.getKey())) {
+ complexBasicTypesDeclarationEntireXMPLevel.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ private void mergeComplexBasicTypesDeclarationSchemaLevel(Map<String, String> external) {
+ for (Entry<String, String> entry : external.entrySet()) {
+ if(!complexBasicTypesDeclarationSchemaLevel.containsKey(entry.getKey())) {
+ complexBasicTypesDeclarationSchemaLevel.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ private void mergeComplexBasicTypesDeclarationPropertyLevel(Map<String, String> external) {
+ for (Entry<String, String> entry : external.entrySet()) {
+ if(!complexBasicTypesDeclarationPropertyLevel.containsKey(entry.getKey())) {
+ complexBasicTypesDeclarationPropertyLevel.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
/**
* Add mapping of common schemas
*
Added: pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/PDFAExtentionSchemaPreprocessor.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/PDFAExtentionSchemaPreprocessor.java?rev=1153788&view=auto
==============================================================================
--- pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/PDFAExtentionSchemaPreprocessor.java (added)
+++ pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/PDFAExtentionSchemaPreprocessor.java Thu Aug 4 08:53:21 2011
@@ -0,0 +1,97 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+package org.apache.padaf.xmpbox.parser;
+
+import java.util.HashMap;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.padaf.xmpbox.XMPMetadata;
+import org.apache.padaf.xmpbox.schema.PDFAExtensionSchema;
+import org.apache.padaf.xmpbox.type.BadFieldValueException;
+
+public class PDFAExtentionSchemaPreprocessor extends XMPDocumentBuilder implements XMPDocumentPreprocessor {
+
+ public PDFAExtentionSchemaPreprocessor() throws XmpSchemaException {
+ super();
+ }
+
+ public NSMapping process(byte[] xmp) throws XmpParsingException, XmpSchemaException,
+ XmpUnknownValueTypeException, XmpExpectedRdfAboutAttribute, XmpXpacketEndException, BadFieldValueException {
+ parse(xmp);
+ return this.nsMap;
+ }
+
+ protected void parseDescription(XMPMetadata metadata)
+ throws XmpParsingException, XMLStreamException, XmpSchemaException,
+ XmpUnknownValueTypeException, XmpExpectedRdfAboutAttribute,
+ BadFieldValueException {
+
+ nsMap.resetComplexBasicTypesDeclarationInSchemaLevel();
+ int cptNS = reader.get().getNamespaceCount();
+ HashMap<String, String> namespaces = new HashMap<String, String>();
+ for (int i = 0; i < cptNS; i++) {
+ namespaces.put(reader.get().getNamespacePrefix(i), reader.get().getNamespaceURI(i));
+ if (nsMap.isComplexBasicTypes(reader.get().getNamespaceURI(i))) {
+ nsMap.setComplexBasicTypesDeclarationForLevelSchema(reader
+ .get().getNamespaceURI(i), reader.get()
+ .getNamespacePrefix(i));
+ }
+ }
+
+ // Different treatment for PDF/A Extension schema
+ if (namespaces.containsKey(PDFAExtensionSchema.PDFAEXTENSION)) {
+
+ if (namespaces.containsKey(PDFAExtensionSchema.PDFAPROPERTY)
+ && namespaces.containsKey(PDFAExtensionSchema.PDFASCHEMA)) {
+
+ if (namespaces.containsValue(PDFAExtensionSchema.PDFAEXTENSIONURI)
+ && namespaces.containsValue(PDFAExtensionSchema.PDFAPROPERTYURI)
+ && namespaces.containsValue(PDFAExtensionSchema.PDFASCHEMAURI)) {
+ PDFAExtensionSchema schema = metadata.createAndAddPDFAExtensionSchemaWithNS(namespaces);
+ treatDescriptionAttributes(metadata, schema);
+ parseExtensionSchema(schema, metadata);
+ } else {
+ throw new XmpUnexpectedNamespaceURIException("Unexpected namespaceURI in PDFA Extension Schema encountered");
+ }
+
+ } else {
+ throw new XmpUnexpectedNamespacePrefixException("Unexpected namespace Prefix in PDFA Extension Schema");
+ }
+
+ } else {
+ int openedTag = 0;
+ while (reader.get().nextTag() == XMLStreamReader.START_ELEMENT) {
+ openedTag=1;
+ do {
+ int tag = reader.get().next();
+ if (tag == XMLStreamReader.START_ELEMENT) {
+ openedTag++;
+ } else if (tag == XMLStreamReader.END_ELEMENT) {
+ openedTag--;
+ }
+ } while (openedTag>0);
+ }
+ }
+ }
+}
Modified: pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentBuilder.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentBuilder.java?rev=1153788&r1=1153787&r2=1153788&view=diff
==============================================================================
--- pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentBuilder.java (original)
+++ pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentBuilder.java Thu Aug 4 08:53:21 2011
@@ -22,6 +22,8 @@
package org.apache.padaf.xmpbox.parser;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
@@ -35,6 +37,7 @@ import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import org.apache.commons.io.IOUtils;
import org.apache.padaf.xmpbox.CreateXMPMetadataException;
import org.apache.padaf.xmpbox.XMPMetadata;
import org.apache.padaf.xmpbox.schema.PDFAExtensionSchema;
@@ -64,6 +67,8 @@ public class XMPDocumentBuilder {
protected NSMapping nsMap;
protected ThreadLocal<XMLStreamReader> reader = new ThreadLocal<XMLStreamReader>();
+
+ protected List<XMPDocumentPreprocessor> preprocessors = new ArrayList<XMPDocumentPreprocessor>();
/**
* Constructor of a XMPDocumentBuilder
@@ -104,55 +109,32 @@ public class XMPDocumentBuilder {
XmpSchemaException, XmpUnknownValueTypeException,
XmpExpectedRdfAboutAttribute, XmpXpacketEndException,
BadFieldValueException {
- return parse(new ByteArrayInputStream(xmp));
- }
- /**
- * Parsing method using serialized xmp read from a stream
- *
- * @param is
- * The stream to read
- * @return Metadata with all information read
- * @throws XmpParsingException
- * When element expected not found When element expected not
- * found
- * @throws XmpSchemaException
- * When instancing schema object failed or in PDF/A Extension
- * case, if its namespace miss
- * @throws XmpUnknownValueTypeException
- * When ValueType found not correspond to basic type and not has
- * been declared in current schema
- * @throws XmpExpectedRdfAboutAttribute
- * When rdf:Description not contains rdf:about attribute
- * @throws XmpXpacketEndException
- * When xpacket end Processing Instruction is missing or is
- * incorrect
- * @throws BadFieldValueException
- * When treat a Schema associed to a schema Description in PDF/A
- * Extension schema
- */
- public XMPMetadata parse(InputStream is) throws XmpParsingException,
- XmpSchemaException, XmpUnknownValueTypeException,
- XmpExpectedRdfAboutAttribute, XmpXpacketEndException,
- BadFieldValueException {
+ if (!(this instanceof XMPDocumentPreprocessor)) {
+ for (XMPDocumentPreprocessor processor : preprocessors) {
+ NSMapping additionalNSMapping = processor.process(xmp);
+ this.nsMap.importNSMapping(additionalNSMapping);
+ }
+ }
+ ByteArrayInputStream is = new ByteArrayInputStream(xmp);
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
reader.set(factory.createXMLStreamReader(is));
// expect xpacket processing instruction
expectNext(XMLStreamReader.PROCESSING_INSTRUCTION,
- "Did not find initial xpacket processing instruction");
+ "Did not find initial xpacket processing instruction");
XMPMetadata metadata = parseInitialXpacket(reader.get().getPIData());
// expect x:xmpmeta
expectNextTag(XMLStreamReader.START_ELEMENT,
- "Did not find initial x:xmpmeta");
+ "Did not find initial x:xmpmeta");
expectName("adobe:ns:meta/", "xmpmeta");
// expect rdf:RDF
expectNextTag(XMLStreamReader.START_ELEMENT,
- "Did not find initial rdf:RDF");
+ "Did not find initial rdf:RDF");
expectName("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF");
nsMap.resetComplexBasicTypesDeclarationInEntireXMPLevel();
@@ -161,14 +143,12 @@ public class XMPDocumentBuilder {
int nsCount = reader.get().getNamespaceCount();
for (int i = 0; i < nsCount; i++) {
if (nsMap.isComplexBasicTypes(reader.get().getNamespaceURI(i))) {
- System.out.println("in method parse: prefix:"
- + reader.get().getAttributeLocalName(i)
- + "; nsURI:" + reader.get().getAttributeValue(i));
- nsMap.setComplexBasicTypesDeclarationForLevelXMP(reader
- .get().getNamespaceURI(i), reader.get()
- .getNamespacePrefix(i));
+ nsMap.setComplexBasicTypesDeclarationForLevelXMP(
+ reader.get().getNamespaceURI(i),
+ reader.get().getNamespacePrefix(i));
}
}
+
// now work on each rdf:Description
int type = reader.get().nextTag();
while (type == XMLStreamReader.START_ELEMENT) {
@@ -179,17 +159,17 @@ public class XMPDocumentBuilder {
// all description are finished
// expect end of rdf:RDF
expectType(XMLStreamReader.END_ELEMENT,
- "Expected end of descriptions");
+ "Expected end of descriptions");
expectName("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF");
// expect ending xmpmeta
expectNextTag(XMLStreamReader.END_ELEMENT,
- "Did not find initial x:xmpmeta");
+ "Did not find initial x:xmpmeta");
expectName("adobe:ns:meta/", "xmpmeta");
// expect final processing instruction
expectNext(XMLStreamReader.PROCESSING_INSTRUCTION,
- "Did not find final xpacket processing instruction");
+ "Did not find final xpacket processing instruction");
// treats xpacket end
if (!reader.get().getPITarget().equals("xpacket")) {
throw new XmpXpacketEndException("Excepted PI xpacket");
@@ -199,30 +179,79 @@ public class XMPDocumentBuilder {
// xmp spec says Other unrecognized attributes can follow, but
// should be ignored
if (xpackData.startsWith("end=")) {
- // check value (5 for end='X')
- if (xpackData.charAt(5)!='r' && xpackData.charAt(5)!='w') {
- throw new XmpXpacketEndException(
- "Excepted xpacket 'end' attribute with value 'r' or 'w' ");
- }
+ // check value (5 for end='X')
+ if (xpackData.charAt(5)!='r' && xpackData.charAt(5)!='w') {
+ throw new XmpXpacketEndException(
+ "Excepted xpacket 'end' attribute with value 'r' or 'w' ");
+ }
} else {
- // should find end='r/w'
- throw new XmpXpacketEndException(
- "Excepted xpacket 'end' attribute (must be present and placed in first)");
+ // should find end='r/w'
+ throw new XmpXpacketEndException(
+ "Excepted xpacket 'end' attribute (must be present and placed in first)");
}
-
+
metadata.setEndXPacket(xpackData);
// return constructed object
return metadata;
} catch (XMLStreamException e) {
- throw new XmpParsingException(
- "An error has occured when processing the underlying XMP source",
- e);
+ throw new XmpParsingException("An error has occured when processing the underlying XMP source", e);
} finally {
reader.remove();
+ IOUtils.closeQuietly(is);
}
}
/**
+ * Parsing method using serialized xmp read from a stream
+ *
+ * @param is
+ * The stream to read
+ * @return Metadata with all information read
+ * @throws XmpParsingException
+ * When element expected not found When element expected not
+ * found
+ * @throws XmpSchemaException
+ * When instancing schema object failed or in PDF/A Extension
+ * case, if its namespace miss
+ * @throws XmpUnknownValueTypeException
+ * When ValueType found not correspond to basic type and not has
+ * been declared in current schema
+ * @throws XmpExpectedRdfAboutAttribute
+ * When rdf:Description not contains rdf:about attribute
+ * @throws XmpXpacketEndException
+ * When xpacket end Processing Instruction is missing or is
+ * incorrect
+ * @throws BadFieldValueException
+ * When treat a Schema associed to a schema Description in PDF/A
+ * Extension schema
+ */
+ public XMPMetadata parse(InputStream input) throws XmpParsingException,
+ XmpSchemaException, XmpUnknownValueTypeException,
+ XmpExpectedRdfAboutAttribute, XmpXpacketEndException,
+ BadFieldValueException {
+
+ byte[] bos = getStreamAsByteArray(input);
+ return parse(bos);
+ }
+
+ private byte[] getStreamAsByteArray(InputStream input) throws XmpParsingException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try {
+ IOUtils.copyLarge(input, bos);
+ } catch (IOException e) {
+ throw new XmpParsingException("An error has occured when processing the underlying XMP source", e);
+ } finally {
+ IOUtils.closeQuietly(bos);
+ IOUtils.closeQuietly(input);
+ }
+ return bos.toByteArray();
+ }
+
+ public void addPreprocessor(XMPDocumentPreprocessor processor) {
+ this.preprocessors.add(processor);
+ }
+
+ /**
* Check InitialXPacket and build metadata object with these information
*
* @param data
@@ -390,7 +419,7 @@ public class XMPDocumentBuilder {
* @throws XmpExpectedRdfAboutAttribute
* When rdf:Description not contains rdf:about attribute
*/
- private void treatDescriptionAttributes(XMPMetadata metadata,
+ protected final void treatDescriptionAttributes(XMPMetadata metadata,
XMPSchema schema) throws XmpExpectedRdfAboutAttribute {
int cptAtt = reader.get().getAttributeCount();
if (cptAtt < 1) {
@@ -578,7 +607,7 @@ public class XMPDocumentBuilder {
* When one of a field property include to describe a property
* in Schema Description contain an incorrect value
*/
- private void parseExtensionSchema(PDFAExtensionSchema schema,
+ protected final void parseExtensionSchema(PDFAExtensionSchema schema,
XMPMetadata metadata) throws XmpParsingException,
XMLStreamException, XmpUnknownValueTypeException,
BadFieldValueException {
Added: pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentPreprocessor.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentPreprocessor.java?rev=1153788&view=auto
==============================================================================
--- pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentPreprocessor.java (added)
+++ pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPDocumentPreprocessor.java Thu Aug 4 08:53:21 2011
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+package org.apache.padaf.xmpbox.parser;
+
+import org.apache.padaf.xmpbox.type.BadFieldValueException;
+
+public interface XMPDocumentPreprocessor {
+
+ NSMapping process(byte[] xmp) throws XmpParsingException,
+ XmpSchemaException, XmpUnknownValueTypeException,
+ XmpExpectedRdfAboutAttribute, XmpXpacketEndException,
+ BadFieldValueException;
+}
Modified: pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPSchemaFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPSchemaFactory.java?rev=1153788&r1=1153787&r2=1153788&view=diff
==============================================================================
--- pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPSchemaFactory.java (original)
+++ pdfbox/trunk/xmpbox/src/main/java/org/apache/padaf/xmpbox/parser/XMPSchemaFactory.java Thu Aug 4 08:53:21 2011
@@ -22,6 +22,7 @@
package org.apache.padaf.xmpbox.parser;
import java.lang.reflect.Constructor;
+import java.util.ArrayList;
import java.util.List;
import org.apache.padaf.xmpbox.XMPMetadata;
@@ -41,7 +42,9 @@ public class XMPSchemaFactory {
protected PropMapping propDef;
protected String nsName;
protected boolean isDeclarative;
-
+
+ protected List<PropMapping> importedPropertyMapping = new ArrayList<PropMapping>();
+
/**
* Factory Constructor for basic known schemas
*
@@ -81,6 +84,15 @@ public class XMPSchemaFactory {
this.nsName = nsName;
}
+ public void importXMPSchemaFactory(XMPSchemaFactory externalFactory)
+ throws XmpSchemaException {
+ if (!this.namespace.equals(externalFactory.namespace)) {
+ throw new XmpSchemaException("Unable to import a XMPSchemaFactory if the namespace is different." +
+ " - expected : " + this.namespace + " - import : " + externalFactory.namespace);
+ }
+ this.importedPropertyMapping.add(externalFactory.propDef);
+ }
+
/**
* Get namespace URI treated by this factory
*
@@ -98,7 +110,16 @@ public class XMPSchemaFactory {
* @return null if propery name is unknown
*/
public String getPropertyType(String name) {
- return propDef.getPropertyType(name);
+ String result = propDef.getPropertyType(name);
+ if (result == null) {
+ for (PropMapping mapping : importedPropertyMapping) {
+ result = mapping.getPropertyType(name);
+ if (result != null) {
+ break;
+ }
+ }
+ }
+ return result;
}
/**
@@ -109,7 +130,16 @@ public class XMPSchemaFactory {
* @return List of all attributes defined for this property
*/
public List<String> getPropertyAttributes(String name) {
- return propDef.getPropertyAttributes(name);
+ List<String> result = propDef.getPropertyAttributes(name);
+ if (result == null) {
+ for (PropMapping mapping : importedPropertyMapping) {
+ result = mapping.getPropertyAttributes(name);
+ if (result != null) {
+ break;
+ }
+ }
+ }
+ return result;
}
/**