xref: /aosp_15_r20/external/cronet/third_party/libxml/src/testparser.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker /*
2*6777b538SAndroid Build Coastguard Worker  * testparser.c: Additional parser tests
3*6777b538SAndroid Build Coastguard Worker  *
4*6777b538SAndroid Build Coastguard Worker  * See Copyright for the status of this software.
5*6777b538SAndroid Build Coastguard Worker  */
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <libxml/parser.h>
8*6777b538SAndroid Build Coastguard Worker #include <libxml/xmlreader.h>
9*6777b538SAndroid Build Coastguard Worker #include <libxml/xmlwriter.h>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include <string.h>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker static int
testStandaloneWithEncoding(void)14*6777b538SAndroid Build Coastguard Worker testStandaloneWithEncoding(void) {
15*6777b538SAndroid Build Coastguard Worker     xmlDocPtr doc;
16*6777b538SAndroid Build Coastguard Worker     const char *str =
17*6777b538SAndroid Build Coastguard Worker         "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
18*6777b538SAndroid Build Coastguard Worker         "<doc></doc>\n";
19*6777b538SAndroid Build Coastguard Worker     int err = 0;
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker     xmlResetLastError();
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker     doc = xmlReadDoc(BAD_CAST str, NULL, "UTF-8", 0);
24*6777b538SAndroid Build Coastguard Worker     if (doc == NULL) {
25*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "xmlReadDoc failed\n");
26*6777b538SAndroid Build Coastguard Worker         err = 1;
27*6777b538SAndroid Build Coastguard Worker     }
28*6777b538SAndroid Build Coastguard Worker     xmlFreeDoc(doc);
29*6777b538SAndroid Build Coastguard Worker 
30*6777b538SAndroid Build Coastguard Worker     return err;
31*6777b538SAndroid Build Coastguard Worker }
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker static int
testUnsupportedEncoding(void)34*6777b538SAndroid Build Coastguard Worker testUnsupportedEncoding(void) {
35*6777b538SAndroid Build Coastguard Worker     xmlDocPtr doc;
36*6777b538SAndroid Build Coastguard Worker     const xmlError *error;
37*6777b538SAndroid Build Coastguard Worker     int err = 0;
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker     xmlResetLastError();
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker     doc = xmlReadDoc(BAD_CAST "<doc/>", NULL, "#unsupported",
42*6777b538SAndroid Build Coastguard Worker                      XML_PARSE_NOWARNING);
43*6777b538SAndroid Build Coastguard Worker     if (doc == NULL) {
44*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "xmlReadDoc failed with unsupported encoding\n");
45*6777b538SAndroid Build Coastguard Worker         err = 1;
46*6777b538SAndroid Build Coastguard Worker     }
47*6777b538SAndroid Build Coastguard Worker     xmlFreeDoc(doc);
48*6777b538SAndroid Build Coastguard Worker 
49*6777b538SAndroid Build Coastguard Worker     error = xmlGetLastError();
50*6777b538SAndroid Build Coastguard Worker     if (error->code != XML_ERR_UNSUPPORTED_ENCODING ||
51*6777b538SAndroid Build Coastguard Worker         error->level != XML_ERR_WARNING ||
52*6777b538SAndroid Build Coastguard Worker         strcmp(error->message, "Unsupported encoding: #unsupported\n") != 0)
53*6777b538SAndroid Build Coastguard Worker     {
54*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "xmlReadDoc failed to raise correct error\n");
55*6777b538SAndroid Build Coastguard Worker         err = 1;
56*6777b538SAndroid Build Coastguard Worker     }
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker     return err;
59*6777b538SAndroid Build Coastguard Worker }
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker #ifdef LIBXML_SAX1_ENABLED
62*6777b538SAndroid Build Coastguard Worker static int
testBalancedChunk(void)63*6777b538SAndroid Build Coastguard Worker testBalancedChunk(void) {
64*6777b538SAndroid Build Coastguard Worker     xmlNodePtr list;
65*6777b538SAndroid Build Coastguard Worker     xmlNodePtr elem;
66*6777b538SAndroid Build Coastguard Worker     int ret;
67*6777b538SAndroid Build Coastguard Worker     int err = 0;
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker     ret = xmlParseBalancedChunkMemory(NULL, NULL, NULL, 0,
70*6777b538SAndroid Build Coastguard Worker             BAD_CAST "start <node xml:lang='en'>abc</node> end", &list);
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker     if ((ret != XML_ERR_OK) ||
73*6777b538SAndroid Build Coastguard Worker         (list == NULL) ||
74*6777b538SAndroid Build Coastguard Worker         ((elem = list->next) == NULL) ||
75*6777b538SAndroid Build Coastguard Worker         (elem->type != XML_ELEMENT_NODE) ||
76*6777b538SAndroid Build Coastguard Worker         (elem->nsDef == NULL) ||
77*6777b538SAndroid Build Coastguard Worker         (!xmlStrEqual(elem->nsDef->href, XML_XML_NAMESPACE))) {
78*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "xmlParseBalancedChunkMemory failed\n");
79*6777b538SAndroid Build Coastguard Worker         err = 1;
80*6777b538SAndroid Build Coastguard Worker     }
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker     xmlFreeNodeList(list);
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker     return(err);
85*6777b538SAndroid Build Coastguard Worker }
86*6777b538SAndroid Build Coastguard Worker #endif
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker #ifdef LIBXML_PUSH_ENABLED
89*6777b538SAndroid Build Coastguard Worker static int
testHugePush(void)90*6777b538SAndroid Build Coastguard Worker testHugePush(void) {
91*6777b538SAndroid Build Coastguard Worker     xmlParserCtxtPtr ctxt;
92*6777b538SAndroid Build Coastguard Worker     int err, i;
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker     ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker     /*
97*6777b538SAndroid Build Coastguard Worker      * Push parse a document larger than XML_MAX_LOOKUP_LIMIT
98*6777b538SAndroid Build Coastguard Worker      * (10,000,000 bytes). This mainly tests whether shrinking the
99*6777b538SAndroid Build Coastguard Worker      * buffer works when push parsing.
100*6777b538SAndroid Build Coastguard Worker      */
101*6777b538SAndroid Build Coastguard Worker     xmlParseChunk(ctxt, "<doc>", 5, 0);
102*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < 1000000; i++)
103*6777b538SAndroid Build Coastguard Worker         xmlParseChunk(ctxt, "<elem>text</elem>", 17, 0);
104*6777b538SAndroid Build Coastguard Worker     xmlParseChunk(ctxt, "</doc>", 6, 1);
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker     err = ctxt->wellFormed ? 0 : 1;
107*6777b538SAndroid Build Coastguard Worker     xmlFreeDoc(ctxt->myDoc);
108*6777b538SAndroid Build Coastguard Worker     xmlFreeParserCtxt(ctxt);
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker     return err;
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker 
113*6777b538SAndroid Build Coastguard Worker static int
testHugeEncodedChunk(void)114*6777b538SAndroid Build Coastguard Worker testHugeEncodedChunk(void) {
115*6777b538SAndroid Build Coastguard Worker     xmlBufferPtr buf;
116*6777b538SAndroid Build Coastguard Worker     xmlChar *chunk;
117*6777b538SAndroid Build Coastguard Worker     xmlParserCtxtPtr ctxt;
118*6777b538SAndroid Build Coastguard Worker     int err, i;
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker     /*
121*6777b538SAndroid Build Coastguard Worker      * Test the push parser with a built-in encoding handler like ISO-8859-1
122*6777b538SAndroid Build Coastguard Worker      * and a chunk larger than the initial decoded buffer (currently 4 KB).
123*6777b538SAndroid Build Coastguard Worker      */
124*6777b538SAndroid Build Coastguard Worker     buf = xmlBufferCreate();
125*6777b538SAndroid Build Coastguard Worker     xmlBufferCat(buf,
126*6777b538SAndroid Build Coastguard Worker             BAD_CAST "<?xml version='1.0' encoding='ISO-8859-1'?>\n");
127*6777b538SAndroid Build Coastguard Worker     xmlBufferCat(buf, BAD_CAST "<doc><!-- ");
128*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < 2000; i++)
129*6777b538SAndroid Build Coastguard Worker         xmlBufferCat(buf, BAD_CAST "0123456789");
130*6777b538SAndroid Build Coastguard Worker     xmlBufferCat(buf, BAD_CAST " --></doc>");
131*6777b538SAndroid Build Coastguard Worker     chunk = xmlBufferDetach(buf);
132*6777b538SAndroid Build Coastguard Worker     xmlBufferFree(buf);
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker     ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker     xmlParseChunk(ctxt, (char *) chunk, xmlStrlen(chunk), 0);
137*6777b538SAndroid Build Coastguard Worker     xmlParseChunk(ctxt, NULL, 0, 1);
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker     err = ctxt->wellFormed ? 0 : 1;
140*6777b538SAndroid Build Coastguard Worker     xmlFreeDoc(ctxt->myDoc);
141*6777b538SAndroid Build Coastguard Worker     xmlFreeParserCtxt(ctxt);
142*6777b538SAndroid Build Coastguard Worker     xmlFree(chunk);
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker     return err;
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker #endif
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker #if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
149*6777b538SAndroid Build Coastguard Worker typedef struct {
150*6777b538SAndroid Build Coastguard Worker     char *message;
151*6777b538SAndroid Build Coastguard Worker     int code;
152*6777b538SAndroid Build Coastguard Worker } testReaderErrorCtxt;
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker static void
testReaderError(void * arg,const char * msg,xmlParserSeverities severity ATTRIBUTE_UNUSED,xmlTextReaderLocatorPtr locator ATTRIBUTE_UNUSED)155*6777b538SAndroid Build Coastguard Worker testReaderError(void *arg, const char *msg,
156*6777b538SAndroid Build Coastguard Worker                 xmlParserSeverities severity ATTRIBUTE_UNUSED,
157*6777b538SAndroid Build Coastguard Worker                 xmlTextReaderLocatorPtr locator ATTRIBUTE_UNUSED) {
158*6777b538SAndroid Build Coastguard Worker     testReaderErrorCtxt *ctxt = arg;
159*6777b538SAndroid Build Coastguard Worker 
160*6777b538SAndroid Build Coastguard Worker     if (ctxt->message != NULL)
161*6777b538SAndroid Build Coastguard Worker         xmlFree(ctxt->message);
162*6777b538SAndroid Build Coastguard Worker     ctxt->message = xmlMemStrdup(msg);
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker static void
testStructuredReaderError(void * arg,const xmlError * error)166*6777b538SAndroid Build Coastguard Worker testStructuredReaderError(void *arg, const xmlError *error) {
167*6777b538SAndroid Build Coastguard Worker     testReaderErrorCtxt *ctxt = arg;
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker     if (ctxt->message != NULL)
170*6777b538SAndroid Build Coastguard Worker         xmlFree(ctxt->message);
171*6777b538SAndroid Build Coastguard Worker     ctxt->message = xmlMemStrdup(error->message);
172*6777b538SAndroid Build Coastguard Worker     ctxt->code = error->code;
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker static int
testReaderXIncludeError(void)176*6777b538SAndroid Build Coastguard Worker testReaderXIncludeError(void) {
177*6777b538SAndroid Build Coastguard Worker     /*
178*6777b538SAndroid Build Coastguard Worker      * Test whether XInclude errors are reported to the custom error
179*6777b538SAndroid Build Coastguard Worker      * handler of a reader.
180*6777b538SAndroid Build Coastguard Worker      */
181*6777b538SAndroid Build Coastguard Worker     const char *doc =
182*6777b538SAndroid Build Coastguard Worker         "<doc xmlns:xi='http://www.w3.org/2001/XInclude'>\n"
183*6777b538SAndroid Build Coastguard Worker         "  <xi:include/>\n"
184*6777b538SAndroid Build Coastguard Worker         "</doc>\n";
185*6777b538SAndroid Build Coastguard Worker     xmlTextReader *reader;
186*6777b538SAndroid Build Coastguard Worker     testReaderErrorCtxt errorCtxt;
187*6777b538SAndroid Build Coastguard Worker     int err = 0;
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker     reader = xmlReaderForDoc(BAD_CAST doc, NULL, NULL, XML_PARSE_XINCLUDE);
190*6777b538SAndroid Build Coastguard Worker     xmlTextReaderSetErrorHandler(reader, testReaderError, &errorCtxt);
191*6777b538SAndroid Build Coastguard Worker     errorCtxt.message = NULL;
192*6777b538SAndroid Build Coastguard Worker     errorCtxt.code = 0;
193*6777b538SAndroid Build Coastguard Worker     while (xmlTextReaderRead(reader) > 0)
194*6777b538SAndroid Build Coastguard Worker         ;
195*6777b538SAndroid Build Coastguard Worker 
196*6777b538SAndroid Build Coastguard Worker     if (errorCtxt.message == NULL ||
197*6777b538SAndroid Build Coastguard Worker         strstr(errorCtxt.message, "href or xpointer") == NULL) {
198*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "xmlTextReaderSetErrorHandler failed\n");
199*6777b538SAndroid Build Coastguard Worker         err = 1;
200*6777b538SAndroid Build Coastguard Worker     }
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker     xmlFree(errorCtxt.message);
203*6777b538SAndroid Build Coastguard Worker     xmlFreeTextReader(reader);
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker     reader = xmlReaderForDoc(BAD_CAST doc, NULL, NULL, XML_PARSE_XINCLUDE);
206*6777b538SAndroid Build Coastguard Worker     xmlTextReaderSetStructuredErrorHandler(reader, testStructuredReaderError,
207*6777b538SAndroid Build Coastguard Worker                                            &errorCtxt);
208*6777b538SAndroid Build Coastguard Worker     errorCtxt.message = NULL;
209*6777b538SAndroid Build Coastguard Worker     errorCtxt.code = 0;
210*6777b538SAndroid Build Coastguard Worker     while (xmlTextReaderRead(reader) > 0)
211*6777b538SAndroid Build Coastguard Worker         ;
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker     if (errorCtxt.code != XML_XINCLUDE_NO_HREF ||
214*6777b538SAndroid Build Coastguard Worker         errorCtxt.message == NULL ||
215*6777b538SAndroid Build Coastguard Worker         strstr(errorCtxt.message, "href or xpointer") == NULL) {
216*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "xmlTextReaderSetStructuredErrorHandler failed\n");
217*6777b538SAndroid Build Coastguard Worker         err = 1;
218*6777b538SAndroid Build Coastguard Worker     }
219*6777b538SAndroid Build Coastguard Worker 
220*6777b538SAndroid Build Coastguard Worker     xmlFree(errorCtxt.message);
221*6777b538SAndroid Build Coastguard Worker     xmlFreeTextReader(reader);
222*6777b538SAndroid Build Coastguard Worker 
223*6777b538SAndroid Build Coastguard Worker     return err;
224*6777b538SAndroid Build Coastguard Worker }
225*6777b538SAndroid Build Coastguard Worker #endif
226*6777b538SAndroid Build Coastguard Worker 
227*6777b538SAndroid Build Coastguard Worker #ifdef LIBXML_WRITER_ENABLED
228*6777b538SAndroid Build Coastguard Worker static int
testWriterIOWrite(void * ctxt,const char * data,int len)229*6777b538SAndroid Build Coastguard Worker testWriterIOWrite(void *ctxt, const char *data, int len) {
230*6777b538SAndroid Build Coastguard Worker     (void) ctxt;
231*6777b538SAndroid Build Coastguard Worker     (void) data;
232*6777b538SAndroid Build Coastguard Worker 
233*6777b538SAndroid Build Coastguard Worker     return len;
234*6777b538SAndroid Build Coastguard Worker }
235*6777b538SAndroid Build Coastguard Worker 
236*6777b538SAndroid Build Coastguard Worker static int
testWriterIOClose(void * ctxt)237*6777b538SAndroid Build Coastguard Worker testWriterIOClose(void *ctxt) {
238*6777b538SAndroid Build Coastguard Worker     (void) ctxt;
239*6777b538SAndroid Build Coastguard Worker 
240*6777b538SAndroid Build Coastguard Worker     return XML_IO_ENAMETOOLONG;
241*6777b538SAndroid Build Coastguard Worker }
242*6777b538SAndroid Build Coastguard Worker 
243*6777b538SAndroid Build Coastguard Worker static int
testWriterClose(void)244*6777b538SAndroid Build Coastguard Worker testWriterClose(void){
245*6777b538SAndroid Build Coastguard Worker     xmlOutputBufferPtr out;
246*6777b538SAndroid Build Coastguard Worker     xmlTextWriterPtr writer;
247*6777b538SAndroid Build Coastguard Worker     int err = 0;
248*6777b538SAndroid Build Coastguard Worker     int result;
249*6777b538SAndroid Build Coastguard Worker 
250*6777b538SAndroid Build Coastguard Worker     out = xmlOutputBufferCreateIO(testWriterIOWrite, testWriterIOClose,
251*6777b538SAndroid Build Coastguard Worker                                   NULL, NULL);
252*6777b538SAndroid Build Coastguard Worker     writer = xmlNewTextWriter(out);
253*6777b538SAndroid Build Coastguard Worker     xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
254*6777b538SAndroid Build Coastguard Worker     xmlTextWriterStartElement(writer, BAD_CAST "elem");
255*6777b538SAndroid Build Coastguard Worker     xmlTextWriterEndElement(writer);
256*6777b538SAndroid Build Coastguard Worker     xmlTextWriterEndDocument(writer);
257*6777b538SAndroid Build Coastguard Worker     result = xmlTextWriterClose(writer);
258*6777b538SAndroid Build Coastguard Worker 
259*6777b538SAndroid Build Coastguard Worker     if (result != XML_IO_ENAMETOOLONG) {
260*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "xmlTextWriterClose reported wrong error %d\n",
261*6777b538SAndroid Build Coastguard Worker                 result);
262*6777b538SAndroid Build Coastguard Worker         err = 1;
263*6777b538SAndroid Build Coastguard Worker     }
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker     xmlFreeTextWriter(writer);
266*6777b538SAndroid Build Coastguard Worker     return err;
267*6777b538SAndroid Build Coastguard Worker }
268*6777b538SAndroid Build Coastguard Worker #endif
269*6777b538SAndroid Build Coastguard Worker 
270*6777b538SAndroid Build Coastguard Worker int
main(void)271*6777b538SAndroid Build Coastguard Worker main(void) {
272*6777b538SAndroid Build Coastguard Worker     int err = 0;
273*6777b538SAndroid Build Coastguard Worker 
274*6777b538SAndroid Build Coastguard Worker     err |= testStandaloneWithEncoding();
275*6777b538SAndroid Build Coastguard Worker     err |= testUnsupportedEncoding();
276*6777b538SAndroid Build Coastguard Worker #ifdef LIBXML_SAX1_ENABLED
277*6777b538SAndroid Build Coastguard Worker     err |= testBalancedChunk();
278*6777b538SAndroid Build Coastguard Worker #endif
279*6777b538SAndroid Build Coastguard Worker #ifdef LIBXML_PUSH_ENABLED
280*6777b538SAndroid Build Coastguard Worker     err |= testHugePush();
281*6777b538SAndroid Build Coastguard Worker     err |= testHugeEncodedChunk();
282*6777b538SAndroid Build Coastguard Worker #endif
283*6777b538SAndroid Build Coastguard Worker #if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
284*6777b538SAndroid Build Coastguard Worker     err |= testReaderXIncludeError();
285*6777b538SAndroid Build Coastguard Worker #endif
286*6777b538SAndroid Build Coastguard Worker #ifdef LIBXML_WRITER_ENABLED
287*6777b538SAndroid Build Coastguard Worker     err |= testWriterClose();
288*6777b538SAndroid Build Coastguard Worker #endif
289*6777b538SAndroid Build Coastguard Worker 
290*6777b538SAndroid Build Coastguard Worker     return err;
291*6777b538SAndroid Build Coastguard Worker }
292*6777b538SAndroid Build Coastguard Worker 
293