xref: /AOO42X/main/qadevOOo/runner/helper/StreamSimulator.java (revision b0efeae40e43e6d4ccd561d22ec612d42773857b)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package helper;
25 
26 import com.sun.star.uno.UnoRuntime;
27 
28 
29 import com.sun.star.lang.XMultiServiceFactory;
30 import com.sun.star.ucb.XSimpleFileAccess;
31 
32 /**
33  * It simulates an input and output stream and
34  * implements the interfaces XInputStream, XOutputStream.
35  * So it can be used for testing loading/saving of documents
36  * using streams instead of URLs.
37  *
38  */
39 public class StreamSimulator implements com.sun.star.io.XInputStream    ,
40                                         com.sun.star.io.XOutputStream   ,
41                                         com.sun.star.io.XSeekable
42 {
43     //_________________________________
44     /**
45      * @member  m_sFileName     name of the corresponding file on disk
46      * @member  m_xInStream     the internal input stream for reading
47      * @member  m_xOutStream    the internal input stream for writing
48      * @member  m_xSeek         points at runtime to m_xInStream or m_xOutStream and make it seekable
49      *
50      * @member  //m_aProtocol     the external set protocol object for logging messages
51      * @member  m_bInWasUsed    indicates, that the input stream interface was used
52      * @member  m_bOutWasUsed   indicates, that the output stream interface was used
53      */
54 
55     private String                          m_sFileName     ;
56     private com.sun.star.io.XInputStream    m_xInStream     ;
57     private com.sun.star.io.XOutputStream   m_xOutStream    ;
58     private com.sun.star.io.XSeekable       m_xSeek         ;
59 
60     //public  ComplexTestEnvironment          //m_aProtocol     ;
61     public  boolean                         m_bInWasUsed    ;
62     public  boolean                         m_bOutWasUsed   ;
63 
64     //_________________________________
65     /**
66      * construct a new instance of this class
67      * It set the name of the correspojnding file on disk, which
68      * should be source or target for the following operations on
69      * this object. And it regulate if it should function as
70      * input or output stream.
71      *
72      * @param   sFileName
73      *              name of the file on disk
74      *              Will be used as source (if param bInput==true)
75      *              or as target (if param bInput==false).
76      *
77      * @param   bInput
78      *              it specify, which interface should work at this object.
79      *              <TRUE/>  => we simulate an input stream
80      *              <FALSE/> => we simulate an output stream
81      *
82      * @throw   com.sun.star.io.NotConnectedException
83      *              in case the internal streams to the file on disk couldn't established.
84      *              They are necessary. Otherwise this simulator can't really work.
85      */
86 <<<<<<< HEAD:main/qadevOOo/runner/helper/StreamSimulator.java
87     public StreamSimulator( String  sFileName , boolean bInput ,
88         lib.TestParameters param   ) throws com.sun.star.io.NotConnectedException
89 =======
90     public StreamSimulator( String  sFileName , boolean bInput ,
91         XMultiServiceFactory xMSF   ) throws com.sun.star.io.NotConnectedException
92 >>>>>>> 3309286857 (pre-commit auto remove trailing whitespace from java files (#382)):main/qadevOOo/java/OOoRunner/src/main/java/helper/StreamSimulator.java
93     {
94         ////m_aProtocol = new ComplexTestEnvironment();
95         m_sFileName     = sFileName ;
96         m_bInWasUsed    = false     ;
97         m_bOutWasUsed   = false     ;
98 
99         try
100         {
101 <<<<<<< HEAD:main/qadevOOo/runner/helper/StreamSimulator.java
102             XSimpleFileAccess xHelper = (XSimpleFileAccess)
103                 UnoRuntime.queryInterface(XSimpleFileAccess.class,
104                     ((XMultiServiceFactory)param.getMSF()).createInstance("com.sun.star.ucb.SimpleFileAccess"));
105 =======
106             XSimpleFileAccess xHelper = (XSimpleFileAccess)
107                 UnoRuntime.queryInterface(XSimpleFileAccess.class,
108                     xMSF.createInstance("com.sun.star.ucb.SimpleFileAccess"));
109 >>>>>>> 3309286857 (pre-commit auto remove trailing whitespace from java files (#382)):main/qadevOOo/java/OOoRunner/src/main/java/helper/StreamSimulator.java
110 /*            com.sun.star.ucb.XSimpleFileAccess xHelper = (com.sun.star.ucb.XSimpleFileAccess)OfficeConnect.createRemoteInstance(
111                 com.sun.star.ucb.XSimpleFileAccess.class,
112                 "com.sun.star.ucb.SimpleFileAccess");*/
113 
114             if (xHelper == null)
115                 throw new com.sun.star.io.NotConnectedException("ucb helper not available. Can't create streams.");
116 
117             if (bInput)
118             {
119                 m_xInStream = xHelper.openFileRead(m_sFileName);
120                 m_xSeek = (com.sun.star.io.XSeekable)UnoRuntime.queryInterface(
121                             com.sun.star.io.XSeekable.class,
122                             m_xInStream);
123             }
124             else
125             {
126                 m_xOutStream = xHelper.openFileWrite(m_sFileName);
127                 m_xSeek = (com.sun.star.io.XSeekable)UnoRuntime.queryInterface(
128                             com.sun.star.io.XSeekable.class,
129                             m_xOutStream);
130             }
131         }
132         catch(com.sun.star.uno.Exception exUno)
133         {
134             ////m_aProtocol.log("\tstream not open. throw NotConnectedException\n\n\tfailed\n}\n");
135             throw new com.sun.star.io.NotConnectedException("Could not open the file.");
136         }
137     }
138 
139 /*    public void finalize()
140     {
141         ////m_aProtocol.log("finalize was called. Please check if it was right or not.\n");
142     } */
143 
144     //_________________________________
145     /**
146      * following methods simulates the XInputStream.
147      * The notice all actions inside the internal protocol
148      * and try to map all necessary functions to the internal
149      * open in-stream.
150      */
151     public int readBytes( /*OUT*/ byte[][] lData        ,
152                           /*IN*/  int      nBytesToRead ) throws com.sun.star.io.NotConnectedException      ,
153                                                                  com.sun.star.io.BufferSizeExceededException,
154                                                                  com.sun.star.io.IOException
155     {
156         //m_aProtocol.log("readBytes(lData["+lData.length+"]["+lData[0]+"],"+nBytesToRead+")\n{\n");
157         m_bInWasUsed = true;
158 
159         if (m_xInStream == null)
160         {
161             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\n\tfailed\n}\n");
162             throw new com.sun.star.io.NotConnectedException("stream not open");
163         }
164 
165         int nRead = 0;
166         try
167         {
168             nRead = m_xInStream.readBytes(lData,nBytesToRead);
169         }
170         catch (com.sun.star.io.NotConnectedException       exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"      ); throw exConnect;
171         }
172         catch (com.sun.star.io.BufferSizeExceededException exBuffer ) { //m_aProtocol.log("\tgot BufferSizeExceededException\n\tfailed\n}\n"); throw exBuffer;
173         }
174         catch (com.sun.star.io.IOException                 exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"                ); throw exIO;
175         }
176         catch (com.sun.star.uno.RuntimeException           exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"           ); throw exRuntime;
177         }
178         catch (com.sun.star.uno.Exception                  exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"                  );
179         }
180 
181         //m_aProtocol.log("\treads "+nRead+" bytes\n\tOK\n}\n");
182 
183         //if (nRead != nBytesToRead)
184             //m_aProtocol.log("there are some missing bytes for reading!\n");
185 
186         return nRead;
187     }
188 
189     //_________________________________
190 
191     public int readSomeBytes( /*OUT*/ byte[][] lData           ,
192                               /*IN*/  int      nMaxBytesToRead ) throws com.sun.star.io.NotConnectedException       ,
193                                                                         com.sun.star.io.BufferSizeExceededException ,
194                                                                         com.sun.star.io.IOException
195     {
196         //m_aProtocol.log("readSomeBytes(lData["+lData.length+"]["+lData[0]+"],"+nMaxBytesToRead+")\n{\n");
197         m_bInWasUsed = true;
198 
199         if (m_xInStream == null)
200         {
201             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\tfailed\n}\n");
202             throw new com.sun.star.io.NotConnectedException("stream not open");
203         }
204 
205         int nRead = 0;
206         try
207         {
208             nRead = m_xInStream.readSomeBytes(lData,nMaxBytesToRead);
209         }
210         catch (com.sun.star.io.NotConnectedException       exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"      ); throw exConnect;
211         }
212         catch (com.sun.star.io.BufferSizeExceededException exBuffer ) { //m_aProtocol.log("\tgot BufferSizeExceededException\n\tfailed\n}\n"); throw exBuffer;
213         }
214         catch (com.sun.star.io.IOException                 exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"                ); throw exIO;
215         }
216         catch (com.sun.star.uno.RuntimeException           exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"           ); throw exRuntime;
217         }
218         catch (com.sun.star.uno.Exception                  exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"                  );
219         }
220 
221         //m_aProtocol.log("\treads "+nRead+" bytes\n\tOK\n}\n");
222 
223         //if (nRead != nMaxBytesToRead)
224             //m_aProtocol.log("there are some missing bytes for reading!");
225 
226         return nRead;
227     }
228 
229     //_________________________________
230 
231     public void skipBytes( /*IN*/ int nBytesToSkip ) throws com.sun.star.io.NotConnectedException       ,
232                                                             com.sun.star.io.BufferSizeExceededException ,
233                                                             com.sun.star.io.IOException
234     {
235         //m_aProtocol.log("skipBytes("+nBytesToSkip+")\n{\n");
236         m_bInWasUsed = true;
237 
238         if (m_xInStream == null)
239         {
240             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\tfailed\n}\n");
241             throw new com.sun.star.io.NotConnectedException("stream not open");
242         }
243 
244         try
245         {
246             m_xInStream.skipBytes(nBytesToSkip);
247         }
248         catch (com.sun.star.io.NotConnectedException       exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"      ); throw exConnect;
249         }
250         catch (com.sun.star.io.BufferSizeExceededException exBuffer ) { //m_aProtocol.log("\tgot BufferSizeExceededException\n\tfailed\n}\n"); throw exBuffer;
251         }
252         catch (com.sun.star.io.IOException                 exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"                ); throw exIO;
253         }
254         catch (com.sun.star.uno.RuntimeException           exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"           ); throw exRuntime;
255         }
256         catch (com.sun.star.uno.Exception                  exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"                  );
257         }
258 
259         //m_aProtocol.log("\tOK\n}\n");
260     }
261 
262     //_________________________________
263 
264     public int available() throws com.sun.star.io.NotConnectedException,
265                                   com.sun.star.io.IOException
266     {
267         //m_aProtocol.log("available()\n{\n");
268         m_bInWasUsed = true;
269 
270         if (m_xInStream == null)
271         {
272             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\tfailed\n}\n");
273             throw new com.sun.star.io.NotConnectedException("stream not open");
274         }
275 
276         int nAvailable = 0;
277         try
278         {
279             nAvailable = m_xInStream.available();
280         }
281         catch (com.sun.star.io.NotConnectedException exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"); throw exConnect;
282         }
283         catch (com.sun.star.io.IOException           exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"          ); throw exIO;
284         }
285         catch (com.sun.star.uno.RuntimeException     exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"     ); throw exRuntime;
286         }
287         catch (com.sun.star.uno.Exception            exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"            );
288         }
289 
290         //m_aProtocol.log("\treturns "+nAvailable+" bytes\n\tOK\n}\n");
291         return nAvailable;
292     }
293 
294     //_________________________________
295 
296     public void closeInput() throws com.sun.star.io.NotConnectedException,
297                                     com.sun.star.io.IOException
298     {
299         //m_aProtocol.log("closeInput()\n{\n");
300         m_bInWasUsed = true;
301 
302         if (m_xInStream == null)
303         {
304             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\tfailed\n}\n");
305             throw new com.sun.star.io.NotConnectedException("stream not open");
306         }
307 
308         try
309         {
310             m_xInStream.closeInput();
311         }
312         catch (com.sun.star.io.NotConnectedException exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"); throw exConnect;
313         }
314         catch (com.sun.star.io.IOException           exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"          ); throw exIO;
315         }
316         catch (com.sun.star.uno.RuntimeException     exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"     ); throw exRuntime;
317         }
318         catch (com.sun.star.uno.Exception            exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"            );
319         }
320 
321         //m_aProtocol.log("\tOK\n}\n");
322     }
323 
324     //_________________________________
325     /**
326      * following methods simulates the XOutputStream.
327      * The notice all actions inside the internal protocol
328      * and try to map all necessary functions to the internal
329      * open out-stream.
330      */
331     public void writeBytes( /*IN*/byte[] lData ) throws com.sun.star.io.NotConnectedException       ,
332                                                         com.sun.star.io.BufferSizeExceededException ,
333                                                         com.sun.star.io.IOException
334     {
335         //m_aProtocol.log("writeBytes(lData["+lData.length+"])\n{\n");
336         m_bOutWasUsed = true;
337 
338         if (m_xOutStream == null)
339         {
340             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\tfailed\n}\n");
341             throw new com.sun.star.io.NotConnectedException("stream not open");
342         }
343 
344         try
345         {
346             m_xOutStream.writeBytes(lData);
347         }
348         catch (com.sun.star.io.NotConnectedException       exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"      ); throw exConnect;
349         }
350         catch (com.sun.star.io.BufferSizeExceededException exBuffer ) { //m_aProtocol.log("\tgot BufferSizeExceededException\n\tfailed\n}\n"); throw exBuffer;
351         }
352         catch (com.sun.star.io.IOException                 exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"                ); throw exIO;
353         }
354         catch (com.sun.star.uno.RuntimeException           exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"           ); throw exRuntime;
355         }
356         catch (com.sun.star.uno.Exception                  exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"                  );
357         }
358 
359         //m_aProtocol.log("\tOK\n}\n");
360     }
361 
362     //_________________________________
363 
364     public void flush() throws com.sun.star.io.NotConnectedException        ,
365                                com.sun.star.io.BufferSizeExceededException  ,
366                                com.sun.star.io.IOException
367     {
368         //m_aProtocol.log("flush()\n{\n");
369         m_bOutWasUsed = true;
370 
371         if (m_xOutStream == null)
372         {
373             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\tfailed\n}\n");
374             throw new com.sun.star.io.NotConnectedException("stream not open");
375         }
376 
377         try
378         {
379             m_xOutStream.flush();
380         }
381         catch (com.sun.star.io.NotConnectedException       exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"      ); throw exConnect;
382         }
383         catch (com.sun.star.io.BufferSizeExceededException exBuffer ) { //m_aProtocol.log("\tgot BufferSizeExceededException\n\tfailed\n}\n"); throw exBuffer;
384         }
385         catch (com.sun.star.io.IOException                 exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"                ); throw exIO;
386         }
387         catch (com.sun.star.uno.RuntimeException           exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"           ); throw exRuntime;
388         }
389         catch (com.sun.star.uno.Exception                  exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"                  );
390         }
391         //m_aProtocol.log("\tOK\n}\n");
392     }
393 
394     //_________________________________
395 
396     public void closeOutput() throws com.sun.star.io.NotConnectedException      ,
397                                      com.sun.star.io.BufferSizeExceededException,
398                                      com.sun.star.io.IOException
399     {
400         //m_aProtocol.log("closeOutput()\n{\n");
401         m_bOutWasUsed = true;
402 
403         if (m_xOutStream == null)
404         {
405             //m_aProtocol.log("\tstream not open. throw NotConnectedException\n\tfailed\n}\n");
406             throw new com.sun.star.io.NotConnectedException("stream not open");
407         }
408 
409         try
410         {
411             m_xOutStream.closeOutput();
412         }
413         catch (com.sun.star.io.NotConnectedException       exConnect) { //m_aProtocol.log("\tgot NotConnectedException\n\tfailed\n}\n"      ); throw exConnect;
414         }
415         catch (com.sun.star.io.BufferSizeExceededException exBuffer ) { //m_aProtocol.log("\tgot BufferSizeExceededException\n\tfailed\n}\n"); throw exBuffer;
416         }
417         catch (com.sun.star.io.IOException                 exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"                ); throw exIO;
418         }
419         catch (com.sun.star.uno.RuntimeException           exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"           ); throw exRuntime;
420         }
421         catch (com.sun.star.uno.Exception                  exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"                  );
422         }
423 
424         //m_aProtocol.log("\tOK\n}\n");
425     }
426 
427     //_________________________________
428     /**
429      * following methods simulates the XSeekable.
430      * The notice all actions inside the internal protocol
431      * and try to map all necessary functions to the internal
432      * open stream.
433      */
434     public void seek( /*IN*/long nLocation ) throws com.sun.star.lang.IllegalArgumentException,
435                                                     com.sun.star.io.IOException
436     {
437         //m_aProtocol.log("seek("+nLocation+")\n{\n");
438 
439         if (m_xInStream != null)
440             m_bInWasUsed = true;
441         else
442         if (m_xOutStream != null)
443             m_bOutWasUsed = true;
444         else
445             //m_aProtocol.log("\tno stream open!\n");
446 
447         if (m_xSeek == null)
448         {
449             //m_aProtocol.log("\tstream not seekable. throw IOException\n\tfailed\n}\n");
450             throw new com.sun.star.io.IOException("stream not seekable");
451         }
452 
453         try
454         {
455             m_xSeek.seek(nLocation);
456         }
457         catch (com.sun.star.lang.IllegalArgumentException exArg    ) { //m_aProtocol.log("\tgot IllegalArgumentException\n\tfailed\n}\n" ); throw exArg;
458         }
459         catch (com.sun.star.io.IOException                exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"              ); throw exIO;
460         }
461         catch (com.sun.star.uno.RuntimeException          exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"         ); throw exRuntime;
462         }
463         catch (com.sun.star.uno.Exception                 exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"                );
464         }
465 
466         //m_aProtocol.log("\tOK\n}\n");
467     }
468 
469     //_________________________________
470 
471     public long getPosition() throws com.sun.star.io.IOException
472     {
473         //m_aProtocol.log("getPosition()\n{\n");
474 
475         if (m_xInStream != null)
476             m_bInWasUsed = true;
477         else
478         if (m_xOutStream != null)
479             m_bOutWasUsed = true;
480         else
481             //m_aProtocol.log("\tno stream open!\n");
482 
483         if (m_xSeek == null)
484         {
485             //m_aProtocol.log("\tstream not seekable. throw IOException\n\tfailed\n}\n");
486             throw new com.sun.star.io.IOException("stream not seekable");
487         }
488 
489         long nPos = 0;
490         try
491         {
492             nPos = m_xSeek.getPosition();
493         }
494         catch (com.sun.star.io.IOException       exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"     ); throw exIO;
495         }
496         catch (com.sun.star.uno.RuntimeException exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"); throw exRuntime;
497         }
498         catch (com.sun.star.uno.Exception        exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"       );
499         }
500 
501         //m_aProtocol.log("\treturns pos="+nPos+"\n\tOK\n}\n");
502         return nPos;
503     }
504 
505     //_________________________________
506 
507     public long getLength() throws com.sun.star.io.IOException
508     {
509         //m_aProtocol.log("getLength()\n{\n");
510 
511         if (m_xInStream != null)
512             m_bInWasUsed = true;
513         else
514         if (m_xOutStream != null)
515             m_bOutWasUsed = true;
516         else
517             //m_aProtocol.log("\tno stream open!\n");
518 
519         if (m_xSeek == null)
520         {
521             //m_aProtocol.log("\tstream not seekable. throw IOException\n\tfailed\n}\n");
522             throw new com.sun.star.io.IOException("stream not seekable");
523         }
524 
525         long nLen = 0;
526         try
527         {
528             nLen = m_xSeek.getLength();
529         }
530         catch (com.sun.star.io.IOException       exIO     ) { //m_aProtocol.log("\tgot IOException\n\tfailed\n}\n"     ); throw exIO;
531         }
532         catch (com.sun.star.uno.RuntimeException exRuntime) { //m_aProtocol.log("\tgot RuntimeException\n\tfailed\n}\n"); throw exRuntime;
533         }
534         catch (com.sun.star.uno.Exception        exUno    ) { //m_aProtocol.log("\tgot Exception\n\tfailed\n}\n"       );
535         }
536 
537         //m_aProtocol.log("\treturns len="+nLen+"\n\tOK\n}\n");
538         return nLen;
539     }
540 }
541