userdata for SAX parsing with schema validation

Lara Blatchford <[email protected]> Thu, 23 Dec 2021 19:14:26 +0000
Newsgroups gmane.comp.gnome.lib.xml.general
Message-ID <BN2P110MB1011417243976AD22E5FED7A9C7E9@BN2P110MB1011.NAMP110.PROD.OUTLOOK.COM>
--===============6863418100272890163==
Content-Language: en-US
Content-Type: multipart/related;
	boundary="_004_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_";
	type="multipart/alternative"

--_004_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_
Content-Type: multipart/alternative;
	boundary="_000_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_"

--_000_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

Hi - I have a simple SAX handler set up, and schema validation errors are b=
eing caught by my structured error handler.  So far so good.

It appears that the userdata argument to xmlSAXUserParseMemory must be the =
xmlSchemaSAXPlugPtr returned by the call to xmlSchemaSAXPlug, and that this=
 pointer is passed as the ctx pointer to the SAX handler callbacks.

Is there any way for me to make a userdata pointer of my choosing available=
 to my SAX handler callbacks while still getting schema validation?

My code is below, thanks for any suggestions!
Lara

#include <iostream>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <memory.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/xmlschemas.h>
#include <string>

std::string getFileContents( std::string filename )
{
  std::ifstream file ( filename );
  std::string line;
  std::ostringstream fileContents;
  while ( std::getline ( file,
                         line ) )
  {
    fileContents << line << "\n";
  }

  file.close ( );
  return fileContents.str ( );
}

void startElementNs( void * ctx, const xmlChar * localname, const xmlChar *=
 prefix, const xmlChar * URI,
                     int nb_namespaces, const xmlChar ** namespaces, int nb=
_attributes, int nb_defaulted,
                      const xmlChar ** attributes)
{
  fprintf(stderr, "startElementNs: ctx =3D %p\n", (unsigned long)ctx );
  fprintf(stderr, "startElementNs: %s %s %s\n", (char*)prefix, (char*)local=
name, (char*)URI );
}

void endElementNs( void * ctx, const xmlChar * localname, const xmlChar * p=
refix, const xmlChar * URI)
{
  fprintf(stderr, "endElementNs: ctx =3D %p\n", (unsigned long)ctx );
  fprintf(stderr, "endElementNs: %s %s %s\n", (char*)prefix, (char*)localna=
me, (char*)URI );
}

void structuredErrors(void *userdata, xmlErrorPtr error)
{
  fprintf(stderr, "Structured error userdata=3D%p\n", userdata );
  fprintf(stderr, "Structured error (%s, line %d): %s\n", error->file, erro=
r->line, error->message);
}

int main(int argc, const char * argv[])
{
   if ( argc !=3D 3 )
   {
     fprintf( stderr, "Usage: %s <xml file> <schema file>\n", argv[0] );
     exit(1);
   }

   const char* filename =3D argv[1];
   const char* schema =3D argv[2];

   std::string xmlIn =3D getFileContents( filename );

   xmlSAXHandler *schemaValHandler =3D new xmlSAXHandler;
   memset( schemaValHandler, 0, sizeof(xmlSAXHandler) );
   schemaValHandler->initialized =3D XML_SAX2_MAGIC;
   schemaValHandler->error =3D NULL;
   schemaValHandler->warning =3D warning;
   schemaValHandler->startElementNs =3D startElementNs;
   schemaValHandler->endElementNs =3D endElementNs;
   schemaValHandler->startElement =3D NULL;
   schemaValHandler->endElement =3D NULL;

   xmlSchemaParserCtxtPtr parseCtxt =3D xmlSchemaNewParserCtxt(schema);
   xmlSchemaPtr xsdSchemas =3D xmlSchemaParse(parseCtxt);
   xmlSchemaValidCtxtPtr xsdValidCtxt =3D xmlSchemaNewValidCtxt(xsdSchemas)=
;
   xmlSchemaSetValidStructuredErrors(xsdValidCtxt, structuredErrors, NULL )=
;

   // userdata arg is set to the pointer to the original SAX user data poin=
ter
   xmlSchemaValidCtxtPtr oldXsdValidCtxt =3D NULL;;
   void *ctxptr =3D &oldXsdValidCtxt;
   xmlSchemaSAXPlugPtr saxPlug =3D xmlSchemaSAXPlug(xsdValidCtxt, &schemaVa=
lHandler, &ctxptr );

   // !!!!!!!! the userdata in the second argument MUST be the xmlSchemaSAX=
PlugPtr, the pointer value is in
   // !!!!!!!! both saxPlug and ctxptr
   // !!!!!!!! This pointer is passed to functions such as startElementNsSp=
lit that are configured in
   // !!!!!!!! the call to xmlSchemaSAXPlug, which cast the pointer to a xm=
lSchemaSAXPlugPtr, so if you
   // !!!!!!!! try to pass ANY other pointer, you'll get a crash
   int result =3D xmlSAXUserParseMemory( schemaValHandler, ctxptr, xmlIn.c_=
str(), xmlIn.length() );

   if ( result !=3D 0 )
   {
      fprintf(stderr, "Failed to parse document.\n" );
   }

   xmlCleanupParser();
   xmlSchemaSAXUnplug( saxPlug );
   xmlSchemaFreeValidCtxt(xsdValidCtxt);
   xmlSchemaFree(xsdSchemas);
   xmlSchemaFreeParserCtxt(parseCtxt);
   delete schemaValHandler;

   return 0;
}


Lara Blatchford
Principal Engineer
Nteligen, LLC
[email protected]
(443) 864-5042 x110

[cid:[email protected]]


--_000_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_
Content-Type: text/html; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

<html xmlns:v=3D"urn:schemas-microsoft-com:vml" xmlns:o=3D"urn:schemas-micr=
osoft-com:office:office" xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" xmlns=3D"http:=
//www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dus-ascii"=
>
<meta name=3D"Generator" content=3D"Microsoft Word 15 (filtered medium)">
<!--[if !mso]><style>v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style><![endif]--><style><!--
/* Font Definitions */
@font-face
	{font-family:"Cambria Math";
	panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
	{font-family:Calibri;
	panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0in;
	font-size:11.0pt;
	font-family:"Calibri",sans-serif;}
span.EmailStyle17
	{mso-style-type:personal-compose;
	font-family:"Calibri",sans-serif;
	color:windowtext;}
.MsoChpDefault
	{mso-style-type:export-only;
	font-family:"Calibri",sans-serif;}
@page WordSection1
	{size:8.5in 11.0in;
	margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
	{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext=3D"edit" spidmax=3D"1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext=3D"edit">
<o:idmap v:ext=3D"edit" data=3D"1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang=3D"EN-US" link=3D"#0563C1" vlink=3D"#954F72" style=3D"word-wrap:=
break-word">
<div class=3D"WordSection1">
<p class=3D"MsoNormal">Hi - I have a simple SAX handler set up, and schema =
validation errors are being caught by my structured error handler.&nbsp; So=
 far so good.<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">It appears that the userdata argument to xmlSAXUserP=
arseMemory
<i>must</i> be the xmlSchemaSAXPlugPtr returned by the call to xmlSchemaSAX=
Plug, and that this pointer is passed as the ctx pointer to the SAX handler=
 callbacks.<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">Is there any way for me to make a userdata pointer o=
f my choosing available to my SAX handler callbacks while still getting sch=
ema validation?<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">My code is below, thanks for any suggestions!<o:p></=
o:p></p>
<p class=3D"MsoNormal">Lara<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">#include &lt;iostream&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;fstream&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;sstream&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;stdio.h&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;memory.h&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;libxml/xmlmemory.h&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;libxml/parser.h&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;libxml/xmlschemas.h&gt;<o:p></o:p></p>
<p class=3D"MsoNormal">#include &lt;string&gt;<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">std::string getFileContents( std::string filename )<=
o:p></o:p></p>
<p class=3D"MsoNormal">{<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; std::ifstream file ( filename );<o:p></o:p></=
p>
<p class=3D"MsoNormal">&nbsp; std::string line;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; std::ostringstream fileContents;<o:p></o:p></=
p>
<p class=3D"MsoNormal">&nbsp; while ( std::getline ( file,<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp; line ) )<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; {<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp;&nbsp; fileContents &lt;&lt; line &lt;&l=
t; &quot;\n&quot;;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; }<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp; file.close ( );<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; return fileContents.str ( );<o:p></o:p></p>
<p class=3D"MsoNormal">}<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">void startElementNs( void * ctx, const xmlChar * loc=
alname, const xmlChar * prefix, const xmlChar * URI,<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nb=
_namespaces, const xmlChar ** namespaces, int nb_attributes, int nb_default=
ed,<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =
const xmlChar ** attributes)<o:p></o:p></p>
<p class=3D"MsoNormal">{<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; fprintf(stderr, &quot;startElementNs: ctx =3D=
 %p\n&quot;, (unsigned long)ctx );<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; fprintf(stderr, &quot;startElementNs: %s %s %=
s\n&quot;, (char*)prefix, (char*)localname, (char*)URI );<o:p></o:p></p>
<p class=3D"MsoNormal">}<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">void endElementNs( void * ctx, const xmlChar * local=
name, const xmlChar * prefix, const xmlChar * URI)<o:p></o:p></p>
<p class=3D"MsoNormal">{<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; fprintf(stderr, &quot;endElementNs: ctx =3D %=
p\n&quot;, (unsigned long)ctx );<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; fprintf(stderr, &quot;endElementNs: %s %s %s\=
n&quot;, (char*)prefix, (char*)localname, (char*)URI );<o:p></o:p></p>
<p class=3D"MsoNormal">}<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">void structuredErrors(void *userdata, xmlErrorPtr er=
ror)<o:p></o:p></p>
<p class=3D"MsoNormal">{<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; fprintf(stderr, &quot;Structured error userda=
ta=3D%p\n&quot;, userdata );<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp; fprintf(stderr, &quot;Structured error (%s, l=
ine %d): %s\n&quot;, error-&gt;file, error-&gt;line, error-&gt;message);<o:=
p></o:p></p>
<p class=3D"MsoNormal">}<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">int main(int argc, const char * argv[])<o:p></o:p></=
p>
<p class=3D"MsoNormal">{<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; if ( argc !=3D 3 )<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; {<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp;&nbsp;&nbsp; fprintf( stderr, &quot;Usag=
e: %s &lt;xml file&gt; &lt;schema file&gt;\n&quot;, argv[0] );<o:p></o:p></=
p>
<p class=3D"MsoNormal">&nbsp;&nbsp;&nbsp;&nbsp; exit(1);<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; }<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; const char* filename =3D argv[1];<o:p><=
/o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; const char* schema =3D argv[2];<o:p></o=
:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; std::string xmlIn =3D getFileContents( =
filename );<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSAXHandler *schemaValHandler =3D new=
 xmlSAXHandler;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; memset( schemaValHandler, 0, sizeof(xml=
SAXHandler) );<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; schemaValHandler-&gt;initialized =3D XM=
L_SAX2_MAGIC;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; schemaValHandler-&gt;error =3D NULL;<o:=
p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; schemaValHandler-&gt;warning =3D warnin=
g;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; schemaValHandler-&gt;startElementNs =3D=
 startElementNs;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; schemaValHandler-&gt;endElementNs =3D e=
ndElementNs;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; schemaValHandler-&gt;startElement =3D N=
ULL;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; schemaValHandler-&gt;endElement =3D NUL=
L;<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaParserCtxtPtr parseCtxt =3D xm=
lSchemaNewParserCtxt(schema);<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaPtr xsdSchemas =3D xmlSchemaPa=
rse(parseCtxt);<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaValidCtxtPtr xsdValidCtxt =3D =
xmlSchemaNewValidCtxt(xsdSchemas);<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaSetValidStructuredErrors(xsdVa=
lidCtxt, structuredErrors, NULL );<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; // userdata arg is set to the pointer t=
o the original SAX user data pointer<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaValidCtxtPtr oldXsdValidCtxt =
=3D NULL;;<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; void *ctxptr =3D &amp;oldXsdValidCtxt;<=
o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaSAXPlugPtr saxPlug =3D xmlSche=
maSAXPlug(xsdValidCtxt, &amp;schemaValHandler, &amp;ctxptr );<o:p></o:p></p=
>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; // !!!!!!!! the userdata in the second =
argument MUST be the xmlSchemaSAXPlugPtr, the pointer value is in<o:p></o:p=
></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; // !!!!!!!! both saxPlug and ctxptr<o:p=
></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; // !!!!!!!! This pointer is passed to f=
unctions such as startElementNsSplit that are configured in<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; // !!!!!!!! the call to xmlSchemaSAXPlu=
g, which cast the pointer to a xmlSchemaSAXPlugPtr, so if you<o:p></o:p></p=
>
<p class=3D"MsoNormal">&nbsp;&nbsp; // !!!!!!!! try to pass ANY other point=
er, you'll get a crash<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; int result =3D xmlSAXUserParseMemory( s=
chemaValHandler, ctxptr, xmlIn.c_str(), xmlIn.length() );<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; if ( result !=3D 0 )<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; {<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, &quot=
;Failed to parse document.\n&quot; );<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; }<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlCleanupParser();<o:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaSAXUnplug( saxPlug );<o:p></o:=
p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaFreeValidCtxt(xsdValidCtxt);<o=
:p></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaFree(xsdSchemas);<o:p></o:p></=
p>
<p class=3D"MsoNormal">&nbsp;&nbsp; xmlSchemaFreeParserCtxt(parseCtxt);<o:p=
></o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; delete schemaValHandler;<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">&nbsp;&nbsp; return 0;<o:p></o:p></p>
<p class=3D"MsoNormal">}<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal">Lara Blatchford<o:p></o:p></p>
<p class=3D"MsoNormal">Principal Engineer<o:p></o:p></p>
<p class=3D"MsoNormal">Nteligen, LLC<o:p></o:p></p>
<p class=3D"MsoNormal">[email protected]<o:p></o:p></p>
<p class=3D"MsoNormal">(443) 864-5042 x110<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
<p class=3D"MsoNormal"><img width=3D"118" height=3D"24" style=3D"width:1.23=
33in;height:.25in" id=3D"Picture_x0020_1" src=3D"cid:image001.jpg@01D7F807.=
64086410"><o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>&nbsp;</o:p></p>
</div>
</body>
</html>

--_000_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_--

--_004_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_
Content-Type: image/jpeg; name="image001.jpg"
Content-Description: image001.jpg
Content-Disposition: inline; filename="image001.jpg"; size=2374;
	creation-date="Thu, 23 Dec 2021 19:14:26 GMT";
	modification-date="Thu, 23 Dec 2021 19:14:26 GMT"
Content-ID: <[email protected]>
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQEAeAB4AAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK
CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAeAJQDASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD7D/bo
0PR/EHwTuLTXdbXQbIzD/SpK8a8I+OPiL8E/2e/BA+FOmaX428J2thNNfaxdyOCuHrmfFP7Wn/DQ
nwd8RHxh8Jft9lps3yad5z/vq81+LXx+1/wF8Ifhjofgi1j8DeGfEGlXSXGg+X55j+f+/VnuUcPP
k5JRPVvhf/wU01C80rxJqXjnQ9OsUs122FrpzvJNcyf/ABFeTa5/wUV+LOsai93bw2OlQfwWsL5S
vIv2e/hD/wALu+L+keDftH2GC4he6muo/wC4lez/ALZX7Ielfs8aLpOveHb6a6sribyLmC4/g/26
D0vZYOFXk5PfPo39kT9ut/jJ4g/4Q3xnY2+keImXNpPA/wAlz7f79e7+Gf2hPDnir4ueIfh/AlzD
qmhQ+dcXUwUQMD/cavx6+E8kM/xU8LpveRHvER5IH2Psevr/AOGv7MvgTxL+1X488J3Vvqf9jafZ
pPbpHqLq+9+u9qDxsww8KM/cP0Vgvrad9kdxE7/3Ueo7zVrHTx/pV5b2/wD18SqleHeD/wBnT4d/
APWr3xJ4aW9TXYrCbZBe6k829P8Aceviz4a+I/hv4/ttX8T/ABds/GnijxXealcp5mm+d9lhhR/k
RNj1B5R+olrrFhfNsgv7ed/7kUyvXz9+138X/Enwpuvh0vh+dII9Y1n7Fd+Z/EmK+RviFJ8JdK8P
yar8L9H8f6F41sHSawn2TOjv/cdHevVf2oPEGq+Lvhz+zxq+u2zWmr32qpPcxv8AJsk2JQB9Q+Mr
L4i33xI8HXPh/UtPtfCMb/8AE4tZ/wDXzJ/sV6XdXUNrHvnmSGP+877a+Q/2hb68g/a8+BEMV5cQ
QPN88Ec2xH/30rD8R+GV/aa/bA8Q+EvFt/e/8Il4Vsv3OlWNy8PnSP8AxvsoA+y4/EelTTKkWqWr
u3REmQ1fjkSb7rq/+5XznJ+wT8Ko8SWlrq1peR/6maPVJsxN7c14n+zP4m1/wD8I/jneS6tcarqm
gT3UNpdXT787B8lAH3Zda3pti2ye/tbd/wC5LMiVJZ6taakP9Gu4J/8Ari4evy9+E8/wa1zwHpet
/ELTfHnijxdqqfar++g87yN7/wACbH+5T/H/AIg8E+AH0TxP8D9H8dab4vsLxP8AQbpJntbyF32O
j73oA/Ub7QkfysypJ/dZ6ot4k0hG2HVbFH9PtCV8T/tK6FrHxI/aq+EvhtNbvtCtdY8PSf2rHaTO
nnJ5nzpXrP8Aw79+D3k+U2m6s42bNx1SbP8AOgD6QhkSeMPGyyKejL0or8dviV+0x8Sf2QfHGsfD
Lwj4hnvPDumTs9m2o7p5kRznaWPJxj9aKAP0R/aY8B+LJvhfPbfCvR9LTxA8owkkKImyvnb4h6Pp
OifBHQbD41eHrq7+JNtpVz9mn0q0320P/A0+5X6BV8Xft2/tcN8F9St/AQ0P7eviPTZl+1eZjyuM
dKs78PWnN8h8sf8ABO//AJOn0j/sG3VfVP8AwU6/5JLoLv8A6j+0k87/AHP46+Wf+Cd6bP2p9I/6
8Lr/ANAr6n/4Kg/8kb03/r8pHpVf99gfM/xA1z4Pal4o+FyfDGGSPVodTh/tHcmz938nWvprxd4V
+IvwO/aM1T4j+GfCy+MfDfiGxSG5gjm2T201fnX8Nf8AkpfhT/r8Sv3Xsf8Ajxtv9xKqZnmcOTkP
k/wXpXxI+Onx20/xh4l8MTeCvCmlaRdaZ5Elzve8eQ/f2Vxvw0X4tfsw2Oq+DLr4YQeMtAW+nvLD
WbeZN7o779jpX3dRWZ4R8aeIPi98bPHGkvpfgr4QWvh7W7n5E1TUnTy7ZP79af7Snwl8eeLvDPwd
tIoYvEOr6PqaTaxdJ8ifwfPX1xTKAPl/42/C/wAVeI/2nPg/4k03TftGiaPN/p91v/1Nch8RPCvi
Pwb+1Nf+LfhJc6d4g8SXln/xOvCt9cpBvT/ntvr7Srwf42fsp+HPjB4nsfFMerav4T8WWkHlx6ro
dx5LvH/ck/vCgDlpPiN+01qkf2RPhZoOivcfJ9u/tlJvs3+3s/jryX9jfwTdeOvhd8bPDN/fJf3u
pXt5az6in3HuX/8As69Ok/Yf1O9PkX3xc8YvZSDbMkOoOjP+Ne4fB/4QeGvgp4Ph8O+GLZ4bCN9z
yTvvmmk/vO3c0AfKXwr8afGD4E+CdL8D6/8ACG38Q/2In2W21W0mT/SYR9x63tb+IPx1+KX9naP4
N+HFl4F33CNea5f7H8mH/YSvsyigD5c+Inwv8Wat+158MvFVtZpd6JpejvbX99/02319QU+mUAfk
D+2V+yH8YvH3x/8AEOt6B4US/wBKuNhiuPO+9waK/YGigD//2Q==

--_004_BN2P110MB1011417243976AD22E5FED7A9C7E9BN2P110MB1011NAMP_--

--===============6863418100272890163==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
xml mailing list, project page  http://xmlsoft.org/
[email protected]
https://mail.gnome.org/mailman/listinfo/xml

--===============6863418100272890163==--