~ubuntu-branches/ubuntu/precise/arduino/precise

« back to all changes in this revision

Viewing changes to src/processing/xml/StdXMLParser.java

  • Committer: Bazaar Package Importer
  • Author(s): Scott Howard
  • Date: 2010-04-13 22:32:24 UTC
  • Revision ID: james.westby@ubuntu.com-20100413223224-jduxnd0xxnkkda02
Tags: upstream-0018+dfsg
ImportĀ upstreamĀ versionĀ 0018+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* StdXMLParser.java                                               NanoXML/Java
 
2
 *
 
3
 * $Revision: 1.5 $
 
4
 * $Date: 2002/03/24 11:37:00 $
 
5
 * $Name: RELEASE_2_2_1 $
 
6
 *
 
7
 * This file is part of NanoXML 2 for Java.
 
8
 * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
 
9
 *
 
10
 * This software is provided 'as-is', without any express or implied warranty.
 
11
 * In no event will the authors be held liable for any damages arising from the
 
12
 * use of this software.
 
13
 *
 
14
 * Permission is granted to anyone to use this software for any purpose,
 
15
 * including commercial applications, and to alter it and redistribute it
 
16
 * freely, subject to the following restrictions:
 
17
 *
 
18
 *  1. The origin of this software must not be misrepresented; you must not
 
19
 *     claim that you wrote the original software. If you use this software in
 
20
 *     a product, an acknowledgment in the product documentation would be
 
21
 *     appreciated but is not required.
 
22
 *
 
23
 *  2. Altered source versions must be plainly marked as such, and must not be
 
24
 *     misrepresented as being the original software.
 
25
 *
 
26
 *  3. This notice may not be removed or altered from any source distribution.
 
27
 */
 
28
 
 
29
package processing.xml;
 
30
 
 
31
 
 
32
import java.io.Reader;
 
33
import java.util.Enumeration;
 
34
import java.util.Properties;
 
35
import java.util.Vector;
 
36
 
 
37
 
 
38
/**
 
39
 * StdXMLParser is the core parser of NanoXML.
 
40
 *
 
41
 * @author Marc De Scheemaecker
 
42
 * @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
 
43
 */
 
44
public class StdXMLParser {
 
45
 
 
46
   /**
 
47
    * The builder which creates the logical structure of the XML data.
 
48
    */
 
49
   private StdXMLBuilder builder;
 
50
 
 
51
 
 
52
   /**
 
53
    * The reader from which the parser retrieves its data.
 
54
    */
 
55
   private StdXMLReader reader;
 
56
 
 
57
 
 
58
   /**
 
59
    * The entity resolver.
 
60
    */
 
61
   private XMLEntityResolver entityResolver;
 
62
 
 
63
 
 
64
   /**
 
65
    * The validator that will process entity references and validate the XML
 
66
    * data.
 
67
    */
 
68
   private XMLValidator validator;
 
69
 
 
70
 
 
71
   /**
 
72
    * Creates a new parser.
 
73
    */
 
74
   public StdXMLParser()
 
75
   {
 
76
      this.builder = null;
 
77
      this.validator = null;
 
78
      this.reader = null;
 
79
      this.entityResolver = new XMLEntityResolver();
 
80
   }
 
81
 
 
82
 
 
83
   /**
 
84
    * Cleans up the object when it's destroyed.
 
85
    */
 
86
   protected void finalize()
 
87
      throws Throwable
 
88
   {
 
89
      this.builder = null;
 
90
      this.reader = null;
 
91
      this.entityResolver = null;
 
92
      this.validator = null;
 
93
      super.finalize();
 
94
   }
 
95
 
 
96
 
 
97
   /**
 
98
    * Sets the builder which creates the logical structure of the XML data.
 
99
    *
 
100
    * @param builder the non-null builder
 
101
    */
 
102
   public void setBuilder(StdXMLBuilder builder)
 
103
   {
 
104
      this.builder = builder;
 
105
   }
 
106
 
 
107
 
 
108
   /**
 
109
    * Returns the builder which creates the logical structure of the XML data.
 
110
    *
 
111
    * @return the builder
 
112
    */
 
113
   public StdXMLBuilder getBuilder()
 
114
   {
 
115
      return this.builder;
 
116
   }
 
117
 
 
118
 
 
119
   /**
 
120
    * Sets the validator that validates the XML data.
 
121
    *
 
122
    * @param validator the non-null validator
 
123
    */
 
124
   public void setValidator(XMLValidator validator)
 
125
   {
 
126
      this.validator = validator;
 
127
   }
 
128
 
 
129
 
 
130
   /**
 
131
    * Returns the validator that validates the XML data.
 
132
    *
 
133
    * @return the validator
 
134
    */
 
135
   public XMLValidator getValidator()
 
136
   {
 
137
      return this.validator;
 
138
   }
 
139
 
 
140
 
 
141
   /**
 
142
    * Sets the entity resolver.
 
143
    *
 
144
    * @param resolver the non-null resolver
 
145
    */
 
146
   public void setResolver(XMLEntityResolver resolver)
 
147
   {
 
148
      this.entityResolver = resolver;
 
149
   }
 
150
 
 
151
 
 
152
   /**
 
153
    * Returns the entity resolver.
 
154
    *
 
155
    * @return the non-null resolver
 
156
    */
 
157
   public XMLEntityResolver getResolver()
 
158
   {
 
159
      return this.entityResolver;
 
160
   }
 
161
 
 
162
 
 
163
   /**
 
164
    * Sets the reader from which the parser retrieves its data.
 
165
    *
 
166
    * @param reader the reader
 
167
    */
 
168
   public void setReader(StdXMLReader reader)
 
169
   {
 
170
      this.reader = reader;
 
171
   }
 
172
 
 
173
 
 
174
   /**
 
175
    * Returns the reader from which the parser retrieves its data.
 
176
    *
 
177
    * @return the reader
 
178
    */
 
179
   public StdXMLReader getReader()
 
180
   {
 
181
      return this.reader;
 
182
   }
 
183
 
 
184
 
 
185
   /**
 
186
    * Parses the data and lets the builder create the logical data structure.
 
187
    *
 
188
    * @return the logical structure built by the builder
 
189
    *
 
190
    * @throws net.n3.nanoxml.XMLException
 
191
    *           if an error occurred reading or parsing the data
 
192
    */
 
193
   public Object parse()
 
194
      throws XMLException
 
195
   {
 
196
      try {
 
197
         this.builder.startBuilding(this.reader.getSystemID(),
 
198
                                    this.reader.getLineNr());
 
199
         this.scanData();
 
200
         return this.builder.getResult();
 
201
      } catch (XMLException e) {
 
202
         throw e;
 
203
      } catch (Exception e) {
 
204
         throw new XMLException(e);
 
205
      }
 
206
   }
 
207
 
 
208
 
 
209
   /**
 
210
    * Scans the XML data for elements.
 
211
    *
 
212
    * @throws java.lang.Exception
 
213
    *     if something went wrong
 
214
    */
 
215
   protected void scanData() throws Exception {
 
216
      while ((! this.reader.atEOF()) && (this.builder.getResult() == null)) {
 
217
         String str = XMLUtil.read(this.reader, '&');
 
218
         char ch = str.charAt(0);
 
219
         if (ch == '&') {
 
220
            XMLUtil.processEntity(str, this.reader, this.entityResolver);
 
221
            continue;
 
222
         }
 
223
 
 
224
         switch (ch) {
 
225
            case '<':
 
226
               this.scanSomeTag(false, // don't allow CDATA
 
227
                                null,  // no default namespace
 
228
                                new Properties());
 
229
               break;
 
230
 
 
231
            case ' ':
 
232
            case '\t':
 
233
            case '\r':
 
234
            case '\n':
 
235
               // skip whitespace
 
236
               break;
 
237
 
 
238
            default:
 
239
               XMLUtil.errorInvalidInput(reader.getSystemID(),
 
240
                                         reader.getLineNr(),
 
241
                                         "`" + ch + "' (0x"
 
242
                                         + Integer.toHexString((int) ch)
 
243
                                         + ')');
 
244
         }
 
245
      }
 
246
   }
 
247
 
 
248
 
 
249
   /**
 
250
    * Scans an XML tag.
 
251
    *
 
252
    * @param allowCDATA true if CDATA sections are allowed at this point
 
253
    * @param defaultNamespace the default namespace URI (or null)
 
254
    * @param namespaces list of defined namespaces
 
255
    *
 
256
    * @throws java.lang.Exception
 
257
    *     if something went wrong
 
258
    */
 
259
   protected void scanSomeTag(boolean allowCDATA,
 
260
                              String defaultNamespace,
 
261
                              Properties namespaces)
 
262
      throws Exception
 
263
   {
 
264
      String str = XMLUtil.read(this.reader, '&');
 
265
      char ch = str.charAt(0);
 
266
 
 
267
      if (ch == '&') {
 
268
         XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
 
269
                                       reader.getLineNr(),
 
270
                                       str);
 
271
      }
 
272
 
 
273
      switch (ch) {
 
274
         case '?':
 
275
            this.processPI();
 
276
            break;
 
277
 
 
278
         case '!':
 
279
            this.processSpecialTag(allowCDATA);
 
280
            break;
 
281
 
 
282
         default:
 
283
            this.reader.unread(ch);
 
284
            this.processElement(defaultNamespace, namespaces);
 
285
      }
 
286
   }
 
287
 
 
288
 
 
289
   /**
 
290
    * Processes a "processing instruction".
 
291
    *
 
292
    * @throws java.lang.Exception
 
293
    *     if something went wrong
 
294
    */
 
295
   protected void processPI()
 
296
      throws Exception
 
297
   {
 
298
      XMLUtil.skipWhitespace(this.reader, null);
 
299
      String target = XMLUtil.scanIdentifier(this.reader);
 
300
      XMLUtil.skipWhitespace(this.reader, null);
 
301
      Reader r = new PIReader(this.reader);
 
302
      
 
303
      if (!target.equalsIgnoreCase("xml")) {
 
304
         this.builder.newProcessingInstruction(target, r);
 
305
      }
 
306
 
 
307
      r.close();
 
308
   }
 
309
 
 
310
 
 
311
   /**
 
312
    * Processes a tag that starts with a bang (&lt;!...&gt;).
 
313
    *
 
314
    * @param allowCDATA true if CDATA sections are allowed at this point
 
315
    *
 
316
    * @throws java.lang.Exception
 
317
    *     if something went wrong
 
318
    */
 
319
   protected void processSpecialTag(boolean allowCDATA)
 
320
      throws Exception
 
321
   {
 
322
      String str = XMLUtil.read(this.reader, '&');
 
323
      char ch = str.charAt(0);
 
324
 
 
325
      if (ch == '&') {
 
326
         XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
 
327
                                       reader.getLineNr(),
 
328
                                       str);
 
329
      }
 
330
 
 
331
      switch (ch) {
 
332
         case '[':
 
333
            if (allowCDATA) {
 
334
               this.processCDATA();
 
335
            } else {
 
336
               XMLUtil.errorUnexpectedCDATA(reader.getSystemID(),
 
337
                                            reader.getLineNr());
 
338
            }
 
339
 
 
340
            return;
 
341
 
 
342
         case 'D':
 
343
            this.processDocType();
 
344
            return;
 
345
 
 
346
         case '-':
 
347
            XMLUtil.skipComment(this.reader);
 
348
            return;
 
349
      }
 
350
   }
 
351
 
 
352
 
 
353
   /**
 
354
    * Processes a CDATA section.
 
355
    *
 
356
    * @throws java.lang.Exception
 
357
    *     if something went wrong
 
358
    */
 
359
   protected void processCDATA() throws Exception {
 
360
      if (! XMLUtil.checkLiteral(this.reader, "CDATA[")) {
 
361
         XMLUtil.errorExpectedInput(reader.getSystemID(),
 
362
                                    reader.getLineNr(),
 
363
                                    "<![[CDATA[");
 
364
      }
 
365
 
 
366
      this.validator.PCDataAdded(this.reader.getSystemID(),
 
367
                                 this.reader.getLineNr());
 
368
      Reader r = new CDATAReader(this.reader);
 
369
      this.builder.addPCData(r, this.reader.getSystemID(),
 
370
                             this.reader.getLineNr());
 
371
      r.close();
 
372
   }
 
373
 
 
374
 
 
375
   /**
 
376
    * Processes a document type declaration.
 
377
    *
 
378
    * @throws java.lang.Exception
 
379
    *           if an error occurred reading or parsing the data
 
380
    */
 
381
   protected void processDocType() throws Exception {
 
382
      if (! XMLUtil.checkLiteral(this.reader, "OCTYPE")) {
 
383
         XMLUtil.errorExpectedInput(reader.getSystemID(),
 
384
                                    reader.getLineNr(),
 
385
                                    "<!DOCTYPE");
 
386
         return;
 
387
      }
 
388
 
 
389
      XMLUtil.skipWhitespace(this.reader, null);
 
390
      String systemID = null;
 
391
      StringBuffer publicID = new StringBuffer();
 
392
      /*String rootElement =*/ XMLUtil.scanIdentifier(this.reader);
 
393
      //System.out.println("rootElement is " + rootElement);
 
394
      XMLUtil.skipWhitespace(this.reader, null);
 
395
      char ch = this.reader.read();
 
396
 
 
397
      if (ch == 'P') {
 
398
         systemID = XMLUtil.scanPublicID(publicID, reader);
 
399
         XMLUtil.skipWhitespace(this.reader, null);
 
400
         ch = this.reader.read();
 
401
      } else if (ch == 'S') {
 
402
         systemID = XMLUtil.scanSystemID(reader);
 
403
         XMLUtil.skipWhitespace(this.reader, null);
 
404
         ch = this.reader.read();
 
405
      }
 
406
 
 
407
      if (ch == '[') {
 
408
         this.validator.parseDTD(publicID.toString(),
 
409
                                 this.reader,
 
410
                                 this.entityResolver,
 
411
                                 false);
 
412
         XMLUtil.skipWhitespace(this.reader, null);
 
413
         ch = this.reader.read();
 
414
      }
 
415
 
 
416
      if (ch != '>') {
 
417
         XMLUtil.errorExpectedInput(reader.getSystemID(),
 
418
                                    reader.getLineNr(),
 
419
                                    "`>'");
 
420
      }
 
421
 
 
422
      // TODO DTD checking is currently disabled, because it breaks 
 
423
      //      applications that don't have access to a net connection 
 
424
      //      (since it insists on going and checking out the DTD).
 
425
      if (false) {
 
426
          if (systemID != null) {
 
427
                  Reader r = this.reader.openStream(publicID.toString(), systemID);
 
428
                  this.reader.startNewStream(r);
 
429
                  this.reader.setSystemID(systemID);
 
430
                  this.reader.setPublicID(publicID.toString());
 
431
                  this.validator.parseDTD(publicID.toString(),
 
432
                                                              this.reader,      
 
433
                                                              this.entityResolver,
 
434
                                                              true);
 
435
          }
 
436
      }
 
437
   }
 
438
 
 
439
 
 
440
   /**
 
441
    * Processes a regular element.
 
442
    *
 
443
    * @param defaultNamespace the default namespace URI (or null)
 
444
    * @param namespaces list of defined namespaces
 
445
    *
 
446
    * @throws java.lang.Exception
 
447
    *     if something went wrong
 
448
    */
 
449
   protected void processElement(String defaultNamespace,
 
450
                                 Properties namespaces)
 
451
      throws Exception
 
452
   {
 
453
      String fullName = XMLUtil.scanIdentifier(this.reader);
 
454
      String name = fullName;
 
455
      XMLUtil.skipWhitespace(this.reader, null);
 
456
      String prefix = null;
 
457
      int colonIndex = name.indexOf(':');
 
458
 
 
459
      if (colonIndex > 0) {
 
460
         prefix = name.substring(0, colonIndex);
 
461
         name = name.substring(colonIndex + 1);
 
462
      }
 
463
 
 
464
      Vector<String> attrNames = new Vector<String>();
 
465
      Vector<String> attrValues = new Vector<String>();
 
466
      Vector<String> attrTypes = new Vector<String>();
 
467
 
 
468
      this.validator.elementStarted(fullName,
 
469
                                    this.reader.getSystemID(),
 
470
                                    this.reader.getLineNr());
 
471
      char ch;
 
472
 
 
473
      for (;;) {
 
474
         ch = this.reader.read();
 
475
 
 
476
         if ((ch == '/') || (ch == '>')) {
 
477
            break;
 
478
         }
 
479
 
 
480
         this.reader.unread(ch);
 
481
         this.processAttribute(attrNames, attrValues, attrTypes);
 
482
         XMLUtil.skipWhitespace(this.reader, null);
 
483
      }
 
484
 
 
485
      Properties extraAttributes = new Properties();
 
486
      this.validator.elementAttributesProcessed(fullName,
 
487
                                                extraAttributes,
 
488
                                                this.reader.getSystemID(),
 
489
                                                this.reader.getLineNr());
 
490
      Enumeration<?> en = extraAttributes.keys();
 
491
 
 
492
      while (en.hasMoreElements()) {
 
493
         String key = (String) en.nextElement();
 
494
         String value = extraAttributes.getProperty(key);
 
495
         attrNames.addElement(key);
 
496
         attrValues.addElement(value);
 
497
         attrTypes.addElement("CDATA");
 
498
      }
 
499
 
 
500
      for (int i = 0; i < attrNames.size(); i++) {
 
501
         String key = (String) attrNames.elementAt(i);
 
502
         String value = (String) attrValues.elementAt(i);
 
503
         //String type = (String) attrTypes.elementAt(i);
 
504
 
 
505
         if (key.equals("xmlns")) {
 
506
            defaultNamespace = value;
 
507
         } else if (key.startsWith("xmlns:")) {
 
508
            namespaces.put(key.substring(6), value);
 
509
         }
 
510
      }
 
511
 
 
512
      if (prefix == null) {
 
513
         this.builder.startElement(name, prefix, defaultNamespace,
 
514
                                   this.reader.getSystemID(),
 
515
                                   this.reader.getLineNr());
 
516
      } else {
 
517
         this.builder.startElement(name, prefix,
 
518
                                   namespaces.getProperty(prefix),
 
519
                                   this.reader.getSystemID(),
 
520
                                   this.reader.getLineNr());
 
521
      }
 
522
 
 
523
      for (int i = 0; i < attrNames.size(); i++) {
 
524
         String key = (String) attrNames.elementAt(i);
 
525
 
 
526
         if (key.startsWith("xmlns")) {
 
527
            continue;
 
528
         }
 
529
 
 
530
         String value = (String) attrValues.elementAt(i);
 
531
         String type = (String) attrTypes.elementAt(i);
 
532
         colonIndex = key.indexOf(':');
 
533
 
 
534
         if (colonIndex > 0) {
 
535
            String attPrefix = key.substring(0, colonIndex);
 
536
            key = key.substring(colonIndex + 1);
 
537
            this.builder.addAttribute(key, attPrefix,
 
538
                                      namespaces.getProperty(attPrefix),
 
539
                                      value, type);
 
540
         } else {
 
541
            this.builder.addAttribute(key, null, null, value, type);
 
542
         }
 
543
      }
 
544
 
 
545
      if (prefix == null) {
 
546
         this.builder.elementAttributesProcessed(name, prefix,
 
547
                                                 defaultNamespace);
 
548
      } else {
 
549
         this.builder.elementAttributesProcessed(name, prefix,
 
550
                                                 namespaces
 
551
                                                   .getProperty(prefix));
 
552
      }
 
553
 
 
554
      if (ch == '/') {
 
555
         if (this.reader.read() != '>') {
 
556
            XMLUtil.errorExpectedInput(reader.getSystemID(),
 
557
                                       reader.getLineNr(),
 
558
                                       "`>'");
 
559
         }
 
560
 
 
561
         this.validator.elementEnded(name,
 
562
                                     this.reader.getSystemID(),
 
563
                                     this.reader.getLineNr());
 
564
 
 
565
         if (prefix == null) {
 
566
            this.builder.endElement(name, prefix, defaultNamespace);
 
567
         } else {
 
568
            this.builder.endElement(name, prefix,
 
569
                                    namespaces.getProperty(prefix));
 
570
         }
 
571
 
 
572
         return;
 
573
      }
 
574
 
 
575
      StringBuffer buffer = new StringBuffer(16);
 
576
 
 
577
      for (;;) {
 
578
         buffer.setLength(0);
 
579
         String str;
 
580
 
 
581
         for (;;) {
 
582
            XMLUtil.skipWhitespace(this.reader, buffer);
 
583
            str = XMLUtil.read(this.reader, '&');
 
584
 
 
585
            if ((str.charAt(0) == '&') && (str.charAt(1) != '#')) {
 
586
               XMLUtil.processEntity(str, this.reader,
 
587
                                     this.entityResolver);
 
588
            } else {
 
589
               break;
 
590
            }
 
591
         }
 
592
 
 
593
         if (str.charAt(0) == '<') {
 
594
            str = XMLUtil.read(this.reader, '\0');
 
595
 
 
596
            if (str.charAt(0) == '/') {
 
597
               XMLUtil.skipWhitespace(this.reader, null);
 
598
               str = XMLUtil.scanIdentifier(this.reader);
 
599
 
 
600
               if (! str.equals(fullName)) {
 
601
                  XMLUtil.errorWrongClosingTag(reader.getSystemID(),
 
602
                                               reader.getLineNr(),
 
603
                                               name, str);
 
604
               }
 
605
 
 
606
               XMLUtil.skipWhitespace(this.reader, null);
 
607
 
 
608
               if (this.reader.read() != '>') {
 
609
                  XMLUtil.errorClosingTagNotEmpty(reader.getSystemID(),
 
610
                                                  reader.getLineNr());
 
611
               }
 
612
 
 
613
               this.validator.elementEnded(fullName,
 
614
                                           this.reader.getSystemID(),
 
615
                                           this.reader.getLineNr());
 
616
               if (prefix == null) {
 
617
                   this.builder.endElement(name, prefix, defaultNamespace);
 
618
               } else {
 
619
                   this.builder.endElement(name, prefix,
 
620
                                           namespaces.getProperty(prefix));
 
621
               }
 
622
               break;
 
623
            } else { // <[^/]
 
624
               this.reader.unread(str.charAt(0));
 
625
               this.scanSomeTag(true, //CDATA allowed
 
626
                                defaultNamespace,
 
627
                                (Properties) namespaces.clone());
 
628
            }
 
629
         } else { // [^<]
 
630
            if (str.charAt(0) == '&') {
 
631
               ch = XMLUtil.processCharLiteral(str);
 
632
               buffer.append(ch);
 
633
            } else {
 
634
               reader.unread(str.charAt(0));
 
635
            }
 
636
            this.validator.PCDataAdded(this.reader.getSystemID(),
 
637
                                       this.reader.getLineNr());
 
638
            Reader r = new ContentReader(this.reader,
 
639
                                         this.entityResolver,
 
640
                                         buffer.toString());
 
641
            this.builder.addPCData(r, this.reader.getSystemID(),
 
642
                                   this.reader.getLineNr());
 
643
            r.close();
 
644
         }
 
645
      }
 
646
   }
 
647
 
 
648
 
 
649
   /**
 
650
    * Processes an attribute of an element.
 
651
    *
 
652
    * @param attrNames contains the names of the attributes.
 
653
    * @param attrValues contains the values of the attributes.
 
654
    * @param attrTypes contains the types of the attributes.
 
655
    *
 
656
    * @throws java.lang.Exception
 
657
    *     if something went wrong
 
658
    */
 
659
   protected void processAttribute(Vector<String> attrNames,
 
660
                                   Vector<String> attrValues,
 
661
                                   Vector<String> attrTypes)
 
662
      throws Exception
 
663
   {
 
664
      String key = XMLUtil.scanIdentifier(this.reader);
 
665
      XMLUtil.skipWhitespace(this.reader, null);
 
666
 
 
667
      if (! XMLUtil.read(this.reader, '&').equals("=")) {
 
668
         XMLUtil.errorExpectedInput(reader.getSystemID(),
 
669
                                    reader.getLineNr(),
 
670
                                    "`='");
 
671
      }
 
672
 
 
673
      XMLUtil.skipWhitespace(this.reader, null);
 
674
      String value = XMLUtil.scanString(this.reader, '&',
 
675
                                        this.entityResolver);
 
676
      attrNames.addElement(key);
 
677
      attrValues.addElement(value);
 
678
      attrTypes.addElement("CDATA");
 
679
      this.validator.attributeAdded(key, value,
 
680
                                    this.reader.getSystemID(),
 
681
                                    this.reader.getLineNr());
 
682
   }
 
683
 
 
684
}