Project

Profile

Help

How to connect?
Download (26.7 KB) Statistics
| Branch: | Tag: | Revision:

he / latest9.9 / hen / csource / api / Saxon.Api / Errors.cs @ a2e6e9df

1
using System;
2
using System.Collections.Generic;
3
using XPathException = net.sf.saxon.trans.XPathException;
4
using JException = java.lang.Exception;
5
using JInvalidityHandler = net.sf.saxon.lib.InvalidityHandler;
6
using JInvalidity = net.sf.saxon.lib.Invalidity;
7
using JValidationFailure = net.sf.saxon.type.ValidationFailure;
8
using JValidationException = net.sf.saxon.type.ValidationException;
9
using JSequence = net.sf.saxon.om.Sequence;
10
using JTransformerException = javax.xml.transform.TransformerException;
11
using JSourceLocator = javax.xml.transform.SourceLocator;
12
using JSaxonApiException = net.sf.saxon.s9api.SaxonApiException;
13

    
14
namespace Saxon.Api
15
{
16

    
17
    /// <summary>
18
	/// The <c>StaticError</c> class contains information about a static error detected during
19
    /// compilation of a stylesheet, query, or XPath expression.
20
    /// </summary>
21

    
22
    [Serializable]
23
    public class StaticError : Exception
24
    {
25

    
26
        private XPathException exception;
27
        internal bool isWarning;
28

    
29
        // internal constructor: Create a new StaticError, wrapping a Saxon XPathException
30

    
31
        internal StaticError(JException err)
32
        {
33
            if (err is XPathException)
34
            {
35
                this.exception = (XPathException)err;
36
            }
37
            else
38
            {
39
                this.exception = XPathException.makeXPathException(err);
40
            }
41
        }
42

    
43
        /// <summary>
44
		/// The error code, as a <c>QName</c>. May be null if no error code has been assigned.
45
        /// </summary>
46

    
47
        public QName ErrorCode
48
        {
49
            get
50
            {
51
                if (exception.getErrorCodeLocalPart() != null) {
52
                    return new QName("err",
53
                        exception.getErrorCodeNamespace(),
54
                        exception.getErrorCodeLocalPart());
55
                } else {
56
                    return null;
57
                }
58
            }
59
        }
60

    
61
        /// <summary>
62
        /// Return the message associated with this error
63
        /// </summary>
64

    
65
        public override String Message
66
        {
67
            get
68
            {
69
                return exception.getMessage();
70
            }
71
        }
72

    
73

    
74
        /// <summary>
75
        /// Return the message associated with this error concatenated with the message from the causing exception
76
        /// </summary> 
77
        public String InnerMessage
78
        {
79
            get {
80

    
81
                return exception.getMessage() + ": " + exception.getCause().Message;
82
            }
83

    
84
        }
85

    
86

    
87

    
88

    
89
        /// <summary>
90
        /// The URI of the query or stylesheet module in which the error was detected
91
        /// (as a string).
92
        /// </summary>
93
        /// <remarks>
94
        /// May be null if the location of the error is unknown, or if the error is not
95
        /// localized to a specific module, or if the module in question has no known URI
96
		/// (for example, if it was supplied as an anonymous <c>Stream</c>).
97
        /// </remarks>
98

    
99
        public String ModuleUri
100
        {
101
            get
102
            {
103
                if (exception.getLocator() == null)
104
                {
105
                    return null;
106
                }
107
                return exception.getLocator().getSystemId();
108
            }
109
        }
110

    
111
        /// <summary>
112
        /// The line number locating the error within a query or stylesheet module.
113
        /// </summary>
114
        /// <remarks>
115
        /// May be set to -1 if the location of the error is unknown.
116
        /// </remarks>        
117

    
118
        public int LineNumber
119
        {
120
            get
121
            {
122
                JSourceLocator loc = exception.getLocator();
123
                if (loc == null)
124
                {
125
                    if (exception.getException() is JTransformerException)
126
                    {
127
                        loc = ((JTransformerException)exception.getException()).getLocator();
128
                        if (loc != null)
129
                        {
130
                            return loc.getLineNumber();
131
                        }
132
                    }
133
                    return -1;
134
                }
135
                return loc.getLineNumber();
136
            }
137
        }
138

    
139

    
140
        /// <summary>
141
        /// The line number locating the error within a query or stylesheet module.
142
        /// </summary>
143
        /// <remarks>
144
        /// May be set to -1 if the location of the error is unknown.
145
        /// </remarks>        
146

    
147
        public int ColumnNumber
148
        {
149
            get
150
            {
151
                JSourceLocator loc = exception.getLocator();
152
                if (loc == null)
153
                {
154
                    if (exception.getException() is JTransformerException)
155
                    {
156
                        loc = ((JTransformerException)exception.getException()).getLocator();
157
                        if (loc != null)
158
                        {
159
                            return loc.getColumnNumber();
160
                        }
161
                    }
162
                    return -1;
163
                }
164
                return loc.getColumnNumber();
165
            }
166
        }
167

    
168
        /// <summary>
169
        /// Indicate whether this error is being reported as a warning condition. If so, applications
170
        /// may ignore the condition, though the results may not be as intended.
171
        /// </summary>
172

    
173
        public bool IsWarning
174
        {
175
            get
176
            {
177
                return isWarning;
178
            }
179
            set
180
            {
181
                isWarning = value;
182
            }
183
        }
184

    
185
        /// <summary>
186
        /// Indicate whether this condition is a type error.
187
        /// </summary>
188

    
189
        public bool IsTypeError
190
        {
191
            get
192
            {
193
                return exception.isTypeError();
194
            }
195
        }
196

    
197
        /// <summary>
198
        /// Return the underlying exception. This is unstable as this is an internal object.
199
        /// </summary>
200
		/// <returns>The underlying <c>XPathException</c></returns>
201
        
202
		public XPathException UnderlyingException
203
        {
204
            get
205
            {
206
                return exception;
207
            }
208
        }
209

    
210
        /// <summary>
211
        /// Return the error message.
212
        /// </summary>
213

    
214
        public override String ToString()
215
        {
216
            return exception.getMessage();
217
        }
218
    }
219

    
220
    /// <summary>
221
	/// The <c>DynamicError</c> class contains information about a dynamic error detected during
222
    /// execution of a stylesheet, query, or XPath expression.
223
    /// </summary>
224

    
225
    [Serializable]
226
    public class DynamicError : Exception
227
    {
228

    
229
        private XPathException exception;
230
        internal bool isWarning;
231

    
232
        /// <summary>
233
		/// Create a new <c>DynamicError</c>, specifying the error message
234
        /// </summary>
235
        /// <param name="message">The error message</param>
236

    
237
        public DynamicError(String message)
238
        {
239
            exception = new XPathException(message);
240
        }
241

    
242
        // internal constructor: Create a new DynamicError, wrapping a Saxon XPathException
243

    
244
        internal DynamicError(JTransformerException err)
245
        {
246
            if (err is XPathException)
247
            {
248
                this.exception = (XPathException)err;
249
            }
250
            else
251
            {
252
                this.exception = XPathException.makeXPathException(err);
253
            }
254
        }
255

    
256
        // internal constructor: Create a new DynamicError, wrapping an SaxonApiException
257

    
258
        internal DynamicError(JSaxonApiException err)
259
        {
260
            if (err.getCause() is XPathException)
261
            {   
262
                this.exception = (XPathException)err.getCause();
263
            }
264
            else
265
            {
266
                this.exception = XPathException.makeXPathException(err);
267
            }
268
        }
269

    
270
        /// <summary>
271
		/// The error code, as a <c>QName</c>. May be null if no error code has been assigned.
272
        /// </summary>
273

    
274
        public QName ErrorCode
275
        {
276
            get
277
            {
278

    
279
                String errorCode = exception.getErrorCodeLocalPart();
280
                if (errorCode == null) {
281
                    return null;
282
                }
283
                return new QName("err",
284
                        exception.getErrorCodeNamespace(),
285
                        errorCode);
286
            }
287
        }
288

    
289
        /// <summary>
290
        /// Return the message associated with this error
291
        /// </summary>
292

    
293
        public override String Message
294
        {
295
            get
296
            {
297
                return exception.getMessage();
298
            }
299
        }
300

    
301
        /// <summary>
302
        /// The URI of the query or stylesheet module in which the error was detected
303
        /// (as a string).
304
        /// </summary>
305
        /// <remarks>
306
        /// May be null if the location of the error is unknown, or if the error is not
307
        /// localized to a specific module, or if the module in question has no known URI
308
		/// (for example, if it was supplied as an anonymous <c>Stream</c>).
309
        /// </remarks>
310

    
311
        public String ModuleUri
312
        {
313
            get
314
            {
315
                if (exception.getLocator() == null)
316
                {
317
                    return null;
318
                }
319
                return exception.getLocator().getSystemId();
320
            }
321
        }
322

    
323
        /// <summary>
324
        /// The line number locating the error within a query or stylesheet module.
325
        /// </summary>
326
        /// <remarks>
327
        /// May be set to -1 if the location of the error is unknown.
328
        /// </remarks>        
329

    
330
        public int LineNumber
331
        {
332
            get
333
            {
334
                JSourceLocator loc = exception.getLocator();
335
                if (loc == null)
336
                {
337
                    if (exception.getException() is JTransformerException)
338
                    {
339
                        loc = ((JTransformerException)exception.getException()).getLocator();
340
                        if (loc != null)
341
                        {
342
                            return loc.getLineNumber();
343
                        }
344
                    }
345
                    return -1;
346
                }
347
                return loc.getLineNumber();
348
            }
349
        }
350

    
351
        /// <summary>
352
        /// Indicate whether this error is being reported as a warning condition. If so, applications
353
        /// may ignore the condition, though the results may not be as intended.
354
        /// </summary>
355

    
356
        public bool IsWarning
357
        {
358
            get
359
            {
360
                return isWarning;
361
            }
362
            set
363
            {
364
                isWarning = value;
365
            }
366
        }
367

    
368
        /// <summary>
369
        /// Indicate whether this condition is a type error.
370
        /// </summary>
371

    
372
        public bool IsTypeError
373
        {
374
            get
375
            {
376
                return exception.isTypeError();
377
            }
378
        }
379

    
380
        /// <summary>
381
        /// Return the error message.
382
        /// </summary>
383

    
384
        public override String ToString()
385
        {
386
            return exception.getMessage();
387
        }
388

    
389
        /// <summary>
390
        /// Return the underlying exception. This is unstable as this is an internal object.
391
        /// </summary>
392
		/// <returns>The underlying <c>XPathException</c></returns>
393
        
394
		public XPathException UnderlyingException
395
        {
396
            get
397
            {
398
                return exception;
399
            }
400
        }
401

    
402

    
403

    
404
    }
405

    
406

    
407
    /// <summary>
408
    /// This exception indicates a failure when validating an instance against a type
409
    ///  defined in a schema.
410
    ///  <p>This class holds the same information as a ValidationException, except that it is not an exception,
411
    ///  and does not carry system overheads such as a stack trace.It is used because operations such as "castable",
412
    ///  and validation of values in a union, cause validation failures on a success path and it is costly to throw,
413
    ///  or even to create, exception objects on a success path.</p>
414
    /// </summary>
415
    public class ValidationFailure
416
    {
417
        private JValidationFailure failure;
418

    
419
        internal ValidationFailure(JValidationFailure failure) {
420
            this.failure = failure; 
421
        }
422

    
423
        /// <summary>
424
        /// Return the character position where the current document event ends.
425
        /// </summary>
426
        /// <returns>the column number, or -1 if none is available</returns>
427
        public int GetColumnNumber()
428
        {
429
            return failure.getColumnNumber();
430
        }
431

    
432
        /// <summary>
433
        /// Get the constraint clause number
434
        /// </summary>
435
        /// <returns>the section number of the clause containing the constraint that has been violated.
436
        /// Generally a decimal number in the form n.n.n; possibly a sequence of such numbers separated
437
        ///  by semicolons.Or null if the information is not available.</returns>
438
        public String GetConstraintClauseNumber()
439
        {
440
            return failure.getConstraintClauseNumber();
441
        }
442

    
443

    
444
        /// <summary>
445
        /// Get the constraint name
446
        /// </summary>
447
        /// <returns>the name of the violated constraint, in the form of a fragment identifier within
448
        ///  the published XML Schema specification; or null if the information is not available.</returns>
449
        public String GetConstraintName()
450
        {
451
            return failure.getConstraintName();
452
        }
453

    
454
        /// <summary>
455
        /// Get the constraint name and clause in the format defined in XML Schema Part C (Outcome Tabulations).
456
        /// This mandates the format validation-rule-name.clause-number
457
        /// </summary>
458
        /// <returns>the constraint reference, for example "cos-ct-extends.1.2"; or null if the reference
459
        ///  is not known.</returns>
460
        public String getConstraintReference()
461
        {
462
            return failure.getConstraintReference();
463
        }
464

    
465
        /// <summary>
466
        /// Get additional location text, if any.
467
        /// </summary>
468
        /// <returns>additional information about the location of the error, designed to be output
469
        /// as a prefix to the error message if desired</returns>
470
        public String GetContextPath()
471
        {
472
            return failure.getContextPath().toString();
473
        }
474

    
475

    
476
        /// <summary>
477
        /// Get the error code associated with the validity error. This is relevant only when validation
478
        /// is run from within XSLT or XQuery, which define different error codes for validition errors
479
        /// </summary>
480
        /// <returns>the error code associated with the error, if any. The error is returned as a simple
481
        /// string if it is in the standard error namespace, or as an EQName(that is Q{ uri}
482
        /// local) otherwise.</returns>
483
        public String GetErrorCode()
484
        {
485
            return failure.getErrorCode();
486
        }
487

    
488
        /// <summary>
489
        /// Return the line number where the current document event ends.
490
        /// </summary>
491
        /// <returns>The line number, or -1 if none is available.</returns>
492
        public int GetLineNumber()
493
        {
494
            return failure.getLineNumber();
495
        }
496

    
497
        /// <summary>
498
        /// Get the text of a message explaing what is wrong
499
        /// </summary>
500
        /// <returns>a human-readable message explaining the validity error</returns>
501
        public String GetMessage()
502
        {
503
            return failure.getMessage();
504
        }
505

    
506
        /// <summary>
507
        /// Get a hierarchic path giving the logical position in the instance document where the
508
        /// validation error was found
509
        /// </summary>
510
        /// <returns>a path to the location in the document</returns>
511
        public String GetPath()
512
        {
513
            return failure.getPath().toString();
514
        }
515

    
516

    
517
        /// <summary>
518
        /// Return the public identifier for the current document event.
519
        /// </summary>
520
        /// <returns>A string containing the public identifier, or null if none is available</returns>
521
        public String GetPublicId()
522
        {
523
            return failure.getPublicId();
524
        }
525

    
526
        /// <summary>
527
        /// Get the "schema part" component of the constraint reference
528
        /// </summary>
529
        /// <returns>1 or 2 depending on whether the violated constraint is in XML Schema Part 1 or Part 2;
530
        /// or -1 if there is no constraint reference</returns>
531
        public int GetSchemaPart()
532
        {
533
            return failure.getSchemaPart();
534
        }
535

    
536
        /// <summary>
537
        /// Return the system identifier for the current document event
538
        /// </summary>
539
        /// <returns>A string containing the system identifier, or null if none is available</returns>
540
        public String GetSystemId()
541
        {
542
            return failure.getSystemId();
543
        }
544
    }
545

    
546
    /// <summary>
547
    /// Error gatherer. This class is used to provide customized error handling. </summary>
548
    /// <remarks><para>If an application does <em>not</em> register its own custom
549
    /// <code>ErrorListener</code>, the default <code>ErrorGatherer</code>
550
    /// is used which keeps track of all warnings and errors in a list.
551
    /// and does not throw any <code>Exception</code>s.
552
    /// Applications are <em>strongly</em> encouraged to register and use
553
    /// <code>ErrorListener</code>s that insure proper behavior for warnings and
554
    /// errors.</para>
555
    /// </remarks>
556
    [Serializable]
557
    internal class ErrorGatherer : javax.xml.transform.ErrorListener
558
    {
559

    
560
        private IList<StaticError> errorList;
561

    
562

    
563
        /// <summary>
564
        /// Initializes a new instance of the <see cref="Saxon.Api.ErrorGatherer"/> class.
565
        /// </summary>
566
        /// <param name="errorList">Error list.</param>
567
        public ErrorGatherer(IList<StaticError> errorList)
568
        {
569
            this.errorList = errorList;
570
        }
571

    
572
        /// <summary>
573
        /// Warning the specified exception.
574
        /// </summary>
575
        /// <param name="exception">TransformerException.</param>
576
        public void warning(JTransformerException exception)
577
        {
578
            StaticError se = new StaticError(exception);
579
            // if(exception)
580
            se.isWarning = true;
581
            //Console.WriteLine("(Adding warning " + exception.getMessage() + ")");
582
            errorList.Add(se);
583
        }
584

    
585
        /// <summary>
586
        /// Report a Transformer exception thrown.
587
        /// </summary>
588
        /// <param name="error">Error.</param>
589
        public void error(JTransformerException error)
590
        {
591
            StaticError se = new StaticError(error);
592
            se.isWarning = false;
593
            //Console.WriteLine("(Adding error " + error.getMessage() + ")");
594
            errorList.Add(se);
595
        }
596

    
597
        /// <summary>
598
        /// Report a fatal exception thrown.
599
        /// </summary>
600
        /// <param name="error">TransformerException.</param>
601
        public void fatalError(JTransformerException error)
602
        {
603
            StaticError se = new StaticError(error);
604
            se.isWarning = false;
605
            errorList.Add(se);
606
            //Console.WriteLine("(Adding fatal error " + error.getMessage() + ")");
607
        }
608

    
609

    
610
        /// <summary>
611
        /// Gets the error list.
612
        /// </summary>
613
        /// <returns>Returns the error list</returns>
614
        public IList<StaticError> ErrorList {
615

    
616
            get
617
            {
618
                return errorList;
619

    
620
            }
621
        }
622
    }
623

    
624

    
625
	/// <summary>
626
	/// Interface for reporting validation errors found during validation of an instance document
627
	/// against a schema.
628
	/// </summary>
629
	public interface IInvalidityHandler {
630

    
631
        /// <summary>
632
        /// At the start of a validation episode, initialize the handler
633
        /// </summary>
634
        /// <param name="systemId">optional; may be used to represent the destination of any
635
        /// report produced</param>
636
		/**public**/ void startReporting(String systemId);
637

    
638

    
639
		/// <summary>
640
		/// Report a validation error found during validation of an instance document
641
		/// against a schema
642
		/// </summary>
643
		/// <param name="i">details of the validation error</param>
644
		/**public**/ void reportInvalidity (ValidationFailure i);
645
		
646

    
647
		/// <summary>
648
		/// At the end of a validation episode, do any closedown actions, and optionally return
649
		/// information collected in the course of validation (for example a list of error messages).
650
		/// </summary>
651
		/// <returns>A value to be associated with a validation exception. May be the empty sequence.
652
		/// In the case of the <c>InvalidityReportGenerator</c>, this returns the XML document
653
		/// containing the validation report. This will be the value returned as the value of
654
		/// the variable <c>$err:value</c> during try/catch processing.</returns>
655
		/**public**/ XdmValue endReporting(); 
656
		
657

    
658

    
659

    
660
	}
661

    
662

    
663
    /// <summary>
664
	/// This class <c>InvalidityHandlerWrapper</c> extends the standard error handler for errors found during
665
    /// validation of an instance document against a schema, used if a user specifies the -report option on validate.
666
    /// Its effect is to output the validation errors found into the filename specified, in an XML format.
667
	/// This is a wrapper class to wrap a .NET <c>InvalidityHandler</c> class for interfacing within Java.
668
    /// </summary>
669
	public class InvalidityHandlerWrapper : JInvalidityHandler
670
    {
671

    
672
        private IInvalidityHandler inHandler;
673

    
674
        /// <summary>
675
        /// Create a standard Invalidity Handler
676
        /// </summary>
677
		/// <param name="inHandler">The .NET <c>IInvalidityHandler</c></param>
678
        public InvalidityHandlerWrapper(IInvalidityHandler inHandler) {
679
            this.inHandler = inHandler;
680
        }
681

    
682

    
683
        /// <summary>
684
        /// Get the value to be associated with a validation exception. May return null.
685
		/// In the case of the <c>InvalidityGenerator</c>, this returns the XML document
686
        /// containing the validation report.
687
        /// </summary>
688
        /// <returns>A value (or null). This will be the value returned as the value of the variable
689
		/// <c>$err:value</c> during try/catch processor.</returns>
690
        public JSequence endReporting()
691
        {
692
            XdmValue value = inHandler.endReporting();
693

    
694
            if (value != null)
695
            {
696
                return inHandler.endReporting().Unwrap();
697
            }
698
            return null;
699

    
700
        }
701

    
702
        /// <summary>
703
        /// Receive notification of a validity error.
704
        /// </summary>
705
        /// <param name="i">Information about the nature of the invalidity</param>
706
        public void reportInvalidity(JInvalidity i)
707
        {
708
            if (i is JValidationFailure) { 
709
                ValidationFailure error = new ValidationFailure((JValidationFailure)i);
710
                inHandler.reportInvalidity(error);
711
            }
712

    
713
            
714
        }
715

    
716

    
717
        /// <summary>
718
        /// At the start of a validation episode, initialize the handler
719
        /// </summary>
720
        /// <param name="systemId">optional; may be used to represent the destination of any report produced</param>
721
        public void startReporting(string systemId)
722
        {
723
            inHandler.startReporting(systemId);
724
        }
725

    
726
        
727
	}
728

    
729

    
730

    
731

    
732

    
733

    
734
	/// <summary>
735
	/// <para>If an application does <em>not</em> register its own custom
736
	/// <code>InvalidityHandler</code>, the default <code>InvalidityGatherer</code>
737
	/// is used which keeps track of all warnings and errors in a list.
738
	/// and does not throw any <code>Exception</code>s.
739
	/// Applications are <em>strongly</em> encouraged to register and use
740
	/// <code>InvalidityHandler</code>s that insure proper behavior for warnings and
741
	/// errors.</para>
742
	/// </summary>
743
	[Serializable]
744
	internal class InvalidityGatherer : JInvalidityHandler
745
	{
746

    
747

    
748
		private IList<ValidationFailure> errorList;
749

    
750

    
751

    
752
		/// <summary>
753
		/// Initializes a new instance of the <see cref="Saxon.Api.InvalidityGatherer"/> class.
754
		/// </summary>
755

    
756
		public InvalidityGatherer(IList<ValidationFailure> errorList)
757
		{
758
            this.errorList = errorList;
759
		}
760

    
761
		public void startReporting(String systemId) {
762
			//invalidityHandler.startReporting (systemId);
763
		}
764

    
765
		public JSequence endReporting() {
766
            //return invalidityHandler.endReporting ();
767
            return null;
768
		}
769

    
770
        /// <summary>
771
		/// List of errors. The caller may supply an empty list before calling <c>Compile</c>;
772
        /// the processor will then populate the list with error information obtained during
773
		/// the schema compilation. Each error will be included as an object of type <c>StaticError</c>.
774
        /// If no error list is supplied by the caller, error information will be written to
775
        /// the standard error stream.
776
        /// </summary>
777
        /// <remarks>
778
		/// <para>By supplying a custom <c>List</c> with a user-written <c>add()</c> method, it is possible to
779
        /// intercept error conditions as they occur.</para>
780
        /// <para>Note that this error list is used only for errors detected while 
781
        /// using the schema to validate a source document. It is not used to report errors
782
        /// in the schema itself.</para>
783
        /// </remarks>
784

    
785
        public IList<ValidationFailure> ErrorList
786
        {
787
            set
788
            {
789
                errorList = value;
790
            }
791
            get
792
            {
793
                return errorList;
794
            }
795
        }
796

    
797

    
798

    
799
        /// <summary>
800
        /// 
801
        /// </summary>
802
        /// <param name="failure">net.sf.saxon.type.ValidationFailure.</param>
803
        public void reportInvalidity(JInvalidity failure)
804
		{
805
            ValidationFailure se = new ValidationFailure((JValidationFailure)failure);
806
            errorList.Add(se);
807

    
808
			//invalidityHandler.reportInvalidity (se);
809
		}
810

    
811

    
812
	}
813

    
814

    
815

    
816

    
817
}
818

    
819
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
820
// Copyright (c) 2018 Saxonica Limited.
821
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
822
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
823
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
824
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(3-3/13)