|
TestPR |
|
1 /* 2 * TestPR.java 3 * 4 * Copyright (c) 1998-2001, The University of Sheffield. 5 * 6 * This file is part of GATE (see http://gate.ac.uk/), and is free 7 * software, licenced under the GNU Library General Public License, 8 * Version 2, June 1991 (in the distribution as file licence.html, 9 * and also available at http://gate.ac.uk/gate/licence.html). 10 * 11 * Oana Hamza, 12 * 13 * $Id: TestPR.java,v 1.33 2002/04/23 13:30:44 oana Exp $ 14 */ 15 16 package gate.creole; 17 18 import java.util.*; 19 import java.io.*; 20 import java.net.*; 21 import junit.framework.*; 22 import gnu.regexp.*; 23 24 import gate.*; 25 import gate.util.*; 26 import gate.corpora.TestDocument; 27 import gate.creole.tokeniser.*; 28 import gate.creole.gazetteer.*; 29 import gate.creole.splitter.*; 30 import gate.creole.orthomatcher.*; 31 import gate.persist.*; 32 import gate.annotation.*; 33 import gate.creole.ANNIEConstants; 34 35 /** Test the PRs on three documents */ 36 public class TestPR extends TestCase 37 { 38 /** Debug flag */ 39 private static final boolean DEBUG = false; 40 41 protected static Document doc1; 42 protected static Document doc2; 43 protected static Document doc3; 44 45 protected static List annotationTypes = new ArrayList(10); 46 47 /** Construction */ 48 public TestPR(String name) { super(name); } 49 50 /** Fixture set up */ 51 public void setUp() throws Exception { 52 //get 3 documents 53 if (doc1 == null) 54 doc1 = Factory.newDocument( 55 new URL(TestDocument.getTestServerName() + 56 "tests/ft-bt-03-aug-2001.html") 57 ); 58 59 if (doc2 == null) 60 doc2 = Factory.newDocument( 61 new URL(TestDocument.getTestServerName() + 62 "tests/gu-Am-Brit-4-aug-2001.html") 63 ); 64 65 if (doc3 == null) 66 doc3 = Factory.newDocument( 67 new URL(TestDocument.getTestServerName() + 68 "tests/in-outlook-09-aug-2001.html") 69 ); 70 71 annotationTypes.add(ANNIEConstants.SENTENCE_ANNOTATION_TYPE); 72 annotationTypes.add(ANNIEConstants.ORGANIZATION_ANNOTATION_TYPE); 73 annotationTypes.add(ANNIEConstants.LOCATION_ANNOTATION_TYPE); 74 annotationTypes.add(ANNIEConstants.PERSON_ANNOTATION_TYPE); 75 annotationTypes.add(ANNIEConstants.DATE_ANNOTATION_TYPE); 76 annotationTypes.add(ANNIEConstants.MONEY_ANNOTATION_TYPE); 77 annotationTypes.add(ANNIEConstants.LOOKUP_ANNOTATION_TYPE); 78 annotationTypes.add(ANNIEConstants.TOKEN_ANNOTATION_TYPE); 79 } // setUp 80 81 /** Put things back as they should be after running tests. 82 */ 83 public void tearDown() throws Exception { 84 } // tearDown 85 86 public void testTokenizer() throws Exception { 87 FeatureMap params = Factory.newFeatureMap(); 88 DefaultTokeniser tokeniser = (DefaultTokeniser) Factory.createResource( 89 "gate.creole.tokeniser.DefaultTokeniser", params); 90 91 92 //run the tokeniser for doc1 93 tokeniser.setDocument(doc1); 94 tokeniser.execute(); 95 assertTrue("Found in "+doc1.getSourceUrl().getFile()+ " "+ 96 doc1.getAnnotations().size() + 97 " Token annotations, instead of the expected 1284.", 98 doc1.getAnnotations().size()== 1284); 99 100 101 //run the tokeniser for doc2 102 tokeniser.setDocument(doc2); 103 tokeniser.execute(); 104 assertTrue("Found in "+ doc2.getSourceUrl().getFile()+ " "+ 105 doc2.getAnnotations().size() + 106 " Token annotations, instead of the expected 2138.", 107 doc2.getAnnotations().size()== 2138); 108 109 110 //run the tokeniser for doc3 111 tokeniser.setDocument(doc3); 112 tokeniser.execute(); 113 assertTrue("Found in "+ doc3.getSourceUrl().getFile()+ " "+ 114 doc3.getAnnotations().size() + 115 " Token annotations, instead of the expected 2806.", 116 doc3.getAnnotations().size()== 2806); 117 118 Factory.deleteResource(tokeniser); 119 }// testTokenizer 120 121 public void testGazetteer() throws Exception { 122 FeatureMap params = Factory.newFeatureMap(); 123 DefaultGazetteer gaz = (DefaultGazetteer) Factory.createResource( 124 "gate.creole.gazetteer.DefaultGazetteer", params); 125 126 //run gazetteer for doc1 127 gaz.setDocument(doc1); 128 gaz.execute(); 129 assertTrue("Found in "+ doc1.getSourceUrl().getFile()+ " "+ 130 doc1.getAnnotations().get(ANNIEConstants.LOOKUP_ANNOTATION_TYPE).size() + 131 " Lookup annotations, instead of the expected 46.", 132 doc1.getAnnotations().get(ANNIEConstants.LOOKUP_ANNOTATION_TYPE).size()== 46); 133 134 //run gazetteer for doc2 135 gaz.setDocument(doc2); 136 gaz.execute(); 137 assertTrue("Found in "+ doc2.getSourceUrl().getFile()+ " "+ 138 doc2.getAnnotations().get(ANNIEConstants.LOOKUP_ANNOTATION_TYPE).size() + 139 " Lookup annotations, instead of the expected 98.", 140 doc2.getAnnotations().get(ANNIEConstants.LOOKUP_ANNOTATION_TYPE).size()== 98); 141 142 //run gazetteer for doc3 143 gaz.setDocument(doc3); 144 gaz.execute(); 145 assertTrue("Found in "+ doc3.getSourceUrl().getFile()+ " "+ 146 doc3.getAnnotations().get(ANNIEConstants.LOOKUP_ANNOTATION_TYPE).size() + 147 " Lookup annotations, instead of the expected 112.", 148 doc3.getAnnotations().get(ANNIEConstants.LOOKUP_ANNOTATION_TYPE).size()== 112); 149 Factory.deleteResource(gaz); 150 }//testGazetteer 151 152 public void testSplitter() throws Exception { 153 FeatureMap params = Factory.newFeatureMap(); 154 SentenceSplitter splitter = (SentenceSplitter) Factory.createResource( 155 "gate.creole.splitter.SentenceSplitter", params); 156 157 //run splitter for doc1 158 splitter.setDocument(doc1); 159 splitter.execute(); 160 assertTrue("Found in "+ doc1.getSourceUrl().getFile()+ " "+ 161 doc1.getAnnotations().get(ANNIEConstants.SENTENCE_ANNOTATION_TYPE).size() + 162 " Sentence annotations, instead of the expected 22.", 163 doc1.getAnnotations().get(ANNIEConstants.SENTENCE_ANNOTATION_TYPE).size()== 22); 164 165 assertTrue("Found in "+ doc1.getSourceUrl().getFile()+ " "+ 166 doc1.getAnnotations().get("Split").size() + 167 " Split annotations, instead of the expected 36.", 168 doc1.getAnnotations().get("Split").size()== 36); 169 170 171 //run splitter for doc2 172 splitter.setDocument(doc2); 173 splitter.execute(); 174 assertTrue("Found in "+ doc2.getSourceUrl().getFile()+ " "+ 175 doc2.getAnnotations().get(ANNIEConstants.SENTENCE_ANNOTATION_TYPE).size() + 176 " Sentence annotations, instead of the expected 52.", 177 doc2.getAnnotations().get(ANNIEConstants.SENTENCE_ANNOTATION_TYPE).size()== 52); 178 179 assertTrue("Found in "+ doc2.getSourceUrl().getFile()+ " "+ 180 doc2.getAnnotations().get("Split").size() + 181 " Split annotations, instead of the expected 71.", 182 doc2.getAnnotations().get("Split").size()== 71); 183 184 //run splitter for doc3 185 splitter.setDocument(doc3); 186 splitter.execute(); 187 188 assertTrue("Found in "+ doc3.getSourceUrl().getFile()+ " "+ 189 doc3.getAnnotations().get(ANNIEConstants.SENTENCE_ANNOTATION_TYPE).size() + 190 " Sentence annotations, instead of the expected 66.", 191 doc3.getAnnotations().get(ANNIEConstants.SENTENCE_ANNOTATION_TYPE).size()== 66); 192 193 assertTrue("Found in "+ doc3.getSourceUrl().getFile()+ " "+ 194 doc3.getAnnotations().get("Split").size() + 195 " Split annotations, instead of the expected 84.", 196 doc3.getAnnotations().get("Split").size()== 84); 197 Factory.deleteResource(splitter); 198 }//testSplitter 199 200 public void testTagger() throws Exception { 201 FeatureMap params = Factory.newFeatureMap(); 202 POSTagger tagger = (POSTagger) Factory.createResource( 203 "gate.creole.POSTagger", params); 204 205 206 //run the tagger for doc1 207 tagger.setDocument(doc1); 208 tagger.execute(); 209 210 HashSet fType = new HashSet(); 211 fType.add(ANNIEConstants.TOKEN_CATEGORY_FEATURE_NAME); 212 AnnotationSet annots = 213 doc1.getAnnotations().get(ANNIEConstants.TOKEN_ANNOTATION_TYPE, fType); 214 215 assertTrue("Found in "+ doc1.getSourceUrl().getFile()+ " "+ annots.size() + 216 " Token annotations with category feature, instead of the expected 675.", 217 annots.size() == 675); 218 219 //run the tagger for doc2 220 tagger.setDocument(doc2); 221 tagger.execute(); 222 annots = doc2.getAnnotations().get(ANNIEConstants.TOKEN_ANNOTATION_TYPE, fType); 223 assertTrue("Found in "+ doc2.getSourceUrl().getFile()+ " "+annots.size() + 224 " Token annotations with category feature, instead of the expected 1131.", 225 annots.size() == 1131); 226 227 //run the tagger for doc3 228 tagger.setDocument(doc3); 229 tagger.execute(); 230 annots = doc3.getAnnotations().get(ANNIEConstants.TOKEN_ANNOTATION_TYPE, fType); 231 assertTrue("Found in "+ doc3.getSourceUrl().getFile()+ " "+ annots.size() + 232 " Token annotations with category feature, instead of the expected 1443.", 233 annots.size() == 1443); 234 Factory.deleteResource(tagger); 235 }//testTagger() 236 237 public void testTransducer() throws Exception { 238 FeatureMap params = Factory.newFeatureMap(); 239 ANNIETransducer transducer = (ANNIETransducer) Factory.createResource( 240 "gate.creole.ANNIETransducer", params); 241 242 //run the transducer for doc1 243 transducer.setDocument(doc1); 244 transducer.execute(); 245 assertTrue("Found in "+ doc1.getSourceUrl().getFile()+ " "+ 246 doc1.getAnnotations().get(ANNIEConstants.ORGANIZATION_ANNOTATION_TYPE).size() + 247 " Organization annotations, instead of the expected 17", 248 doc1.getAnnotations().get(ANNIEConstants.ORGANIZATION_ANNOTATION_TYPE).size()== 17); 249 assertTrue("Found in "+doc1.getSourceUrl().getFile()+ " "+ 250 doc1.getAnnotations().get(ANNIEConstants.LOCATION_ANNOTATION_TYPE).size() + 251 " Location annotations, instead of the expected 3", 252 doc1.getAnnotations().get(ANNIEConstants.LOCATION_ANNOTATION_TYPE).size()== 3); 253 assertTrue("Found in "+doc1.getSourceUrl().getFile()+ " "+ 254 doc1.getAnnotations().get(ANNIEConstants.PERSON_ANNOTATION_TYPE).size() + 255 " Person annotations, instead of the expected 3", 256 doc1.getAnnotations().get(ANNIEConstants.PERSON_ANNOTATION_TYPE).size()== 3); 257 assertTrue("Found in "+doc1.getSourceUrl().getFile()+ " "+ 258 doc1.getAnnotations().get(ANNIEConstants.DATE_ANNOTATION_TYPE).size() + 259 " Date annotations, instead of the expected 6", 260 doc1.getAnnotations().get(ANNIEConstants.DATE_ANNOTATION_TYPE).size()== 6); 261 assertTrue("Found in "+doc1.getSourceUrl().getFile()+ " "+ 262 doc1.getAnnotations().get(ANNIEConstants.MONEY_ANNOTATION_TYPE).size() + 263 " Money annotations, instead of the expected 1", 264 doc1.getAnnotations().get(ANNIEConstants.MONEY_ANNOTATION_TYPE).size()== 1); 265 266 //run the transducer for doc2 267 transducer.setDocument(doc2); 268 transducer.execute(); 269 assertTrue("Found in "+doc2.getSourceUrl().getFile()+ " "+ 270 doc2.getAnnotations().get(ANNIEConstants.ORGANIZATION_ANNOTATION_TYPE).size() + 271 " Organization annotations, instead of the expected 18", 272 doc2.getAnnotations().get(ANNIEConstants.ORGANIZATION_ANNOTATION_TYPE).size()== 18); 273 assertTrue("Found in "+doc2.getSourceUrl().getFile()+ " "+ 274 doc2.getAnnotations().get(ANNIEConstants.LOCATION_ANNOTATION_TYPE).size() + 275 " Location annotations, instead of the expected 9", 276 doc2.getAnnotations().get(ANNIEConstants.LOCATION_ANNOTATION_TYPE).size()== 9); 277 assertTrue("Found in "+doc2.getSourceUrl().getFile()+ " "+ 278 doc2.getAnnotations().get(ANNIEConstants.PERSON_ANNOTATION_TYPE).size() + 279 " Person annotations, instead of the expected 1", 280 doc2.getAnnotations().get(ANNIEConstants.PERSON_ANNOTATION_TYPE).size()== 1); 281 assertTrue("Found in "+doc2.getSourceUrl().getFile()+ " "+ 282 doc2.getAnnotations().get(ANNIEConstants.DATE_ANNOTATION_TYPE).size() + 283 " Date annotations, instead of the expected 6", 284 doc2.getAnnotations().get(ANNIEConstants.DATE_ANNOTATION_TYPE).size()== 6); 285 assertTrue("Found in "+doc2.getSourceUrl().getFile()+ " "+ 286 doc2.getAnnotations().get(ANNIEConstants.MONEY_ANNOTATION_TYPE).size() + 287 " Money annotations, instead of the expected 3", 288 doc2.getAnnotations().get(ANNIEConstants.MONEY_ANNOTATION_TYPE).size()== 3); 289 290 //run the transducer for doc3 291 transducer.setDocument(doc3); 292 transducer.execute(); 293 assertTrue("Found in "+doc3.getSourceUrl().getFile()+ " "+ 294 doc3.getAnnotations().get(ANNIEConstants.ORGANIZATION_ANNOTATION_TYPE).size() + 295 " Organization annotations, instead of the expected 9", 296 doc3.getAnnotations().get(ANNIEConstants.ORGANIZATION_ANNOTATION_TYPE).size()== 9); 297 assertTrue("Found in "+doc3.getSourceUrl().getFile()+ " "+ 298 doc3.getAnnotations().get(ANNIEConstants.LOCATION_ANNOTATION_TYPE).size() + 299 " Location annotations, instead of the expected 12", 300 doc3.getAnnotations().get(ANNIEConstants.LOCATION_ANNOTATION_TYPE).size()== 12); 301 assertTrue("Found in "+doc3.getSourceUrl().getFile()+ " "+ 302 doc3.getAnnotations().get(ANNIEConstants.PERSON_ANNOTATION_TYPE).size() + 303 " Person annotations, instead of the expected 8", 304 doc3.getAnnotations().get(ANNIEConstants.PERSON_ANNOTATION_TYPE).size()== 8); 305 assertTrue("Found in "+doc3.getSourceUrl().getFile()+ " "+ 306 doc3.getAnnotations().get(ANNIEConstants.DATE_ANNOTATION_TYPE).size() + 307 " Date annotations, instead of the expected 7", 308 doc3.getAnnotations().get(ANNIEConstants.DATE_ANNOTATION_TYPE).size()== 7); 309 assertTrue("Found in "+doc3.getSourceUrl().getFile()+ " "+ 310 doc3.getAnnotations().get(ANNIEConstants.MONEY_ANNOTATION_TYPE).size() + 311 " Money annotations, instead of the expected 4", 312 doc3.getAnnotations().get(ANNIEConstants.MONEY_ANNOTATION_TYPE).size()== 4); 313 314 Factory.deleteResource(transducer); 315 }//testTransducer 316 317 public void testOrthomatcher() throws Exception { 318 FeatureMap params = Factory.newFeatureMap(); 319 320 OrthoMatcher orthomatcher = (OrthoMatcher) Factory.createResource( 321 "gate.creole.orthomatcher.OrthoMatcher", params); 322 323 324 // run the orthomatcher for doc1 325 orthomatcher.setDocument(doc1); 326 orthomatcher.execute(); 327 328 HashSet fType = new HashSet(); 329 fType.add(ANNIEConstants.ANNOTATION_COREF_FEATURE_NAME); 330 AnnotationSet annots = 331 doc1.getAnnotations().get(null,fType); 332 333 assertTrue("Found in "+doc1.getSourceUrl().getFile()+ " "+ annots.size() + 334 " annotations with matches feature, instead of the expected 30.", 335 annots.size() == 30); 336 337 //run the orthomatcher for doc2 338 orthomatcher.setDocument(doc2); 339 orthomatcher.execute(); 340 annots = doc2.getAnnotations().get(null,fType); 341 assertTrue("Found in "+doc2.getSourceUrl().getFile()+ " "+ annots.size() + 342 " annotations with matches feature, instead of the expected 35.", 343 annots.size() == 33); 344 345 //run the orthomatcher for doc3 346 orthomatcher.setDocument(doc3); 347 orthomatcher.execute(); 348 349 annots = doc3.getAnnotations().get(null,fType); 350 assertTrue("Found in "+doc3.getSourceUrl().getFile()+ " "+ annots.size() + 351 " annotations with matches feature, instead of the expected 22.", 352 annots.size() == 22); 353 Factory.deleteResource(orthomatcher); 354 }//testOrthomatcher 355 356 /** A test for comparing the annotation sets*/ 357 public void testAllPR() throws Exception { 358 359 // verify if the saved data store is the same with the just processed file 360 // first document 361 String urlBaseName = Gate.locateGateFiles(); 362 // RE re1 = new RE("build/gate.jar!"); 363 // RE re2 = new RE("jar:"); 364 // urlBaseName = re1.substituteAll( urlBaseName,"classes"); 365 // urlBaseName = re2.substituteAll( urlBaseName,""); 366 367 if (urlBaseName.endsWith("/gate/build/gate.jar!/")) { 368 StringBuffer buff = new StringBuffer( 369 urlBaseName.substring( 370 0, 371 urlBaseName.lastIndexOf("build/gate.jar!/")) 372 ); 373 buff.append("classes/"); 374 buff.delete(0, "jar:file:".length()); 375 buff.insert(0, "file://"); 376 urlBaseName = buff.toString(); 377 } 378 379 URL urlBase = new URL(urlBaseName + "gate/resources/gate.ac.uk/"); 380 381 URL storageDir = null; 382 storageDir = new URL(urlBase, "tests/ft"); 383 384 //open the data store 385 DataStore ds = Factory.openDataStore 386 ("gate.persist.SerialDataStore", 387 storageDir.toExternalForm()); 388 389 //get LR id 390 String lrId = (String)ds.getLrIds 391 ("gate.corpora.DocumentImpl").get(0); 392 393 394 // get the document from data store 395 FeatureMap features = Factory.newFeatureMap(); 396 features.put(DataStore.DATASTORE_FEATURE_NAME, ds); 397 features.put(DataStore.LR_ID_FEATURE_NAME, lrId); 398 Document document = (Document) Factory.createResource( 399 "gate.corpora.DocumentImpl", 400 features); 401 compareAnnots(document, doc1); 402 403 // second document 404 storageDir = null; 405 storageDir = new URL(urlBase, "tests/gu"); 406 407 //open the data store 408 ds = Factory.openDataStore("gate.persist.SerialDataStore", 409 storageDir.toExternalForm()); 410 //get LR id 411 lrId = (String)ds.getLrIds("gate.corpora.DocumentImpl").get(0); 412 // get the document from data store 413 features = Factory.newFeatureMap(); 414 features.put(DataStore.DATASTORE_FEATURE_NAME, ds); 415 features.put(DataStore.LR_ID_FEATURE_NAME, lrId); 416 document = (Document) Factory.createResource( 417 "gate.corpora.DocumentImpl", 418 features); 419 compareAnnots(document,doc2); 420 421 // third document 422 storageDir = null; 423 storageDir = new URL(urlBase, "tests/in"); 424 425 //open the data store 426 ds = Factory.openDataStore("gate.persist.SerialDataStore", 427 storageDir.toExternalForm()); 428 //get LR id 429 lrId = (String)ds.getLrIds("gate.corpora.DocumentImpl").get(0); 430 // get the document from data store 431 features = Factory.newFeatureMap(); 432 features.put(DataStore.DATASTORE_FEATURE_NAME, ds); 433 features.put(DataStore.LR_ID_FEATURE_NAME, lrId); 434 document = (Document) Factory.createResource( 435 "gate.corpora.DocumentImpl", 436 features); 437 compareAnnots(document,doc3); 438 } // testAllPR() 439 440 public void compareAnnots(Document keyDocument, Document responseDocument) 441 throws Exception{ 442 443 // create annotation schema 444 AnnotationSchema annotationSchema = new AnnotationSchema(); 445 String annotType = null; 446 447 // organization type 448 Iterator iteratorTypes = annotationTypes.iterator(); 449 while (iteratorTypes.hasNext()){ 450 // get the type of annotation 451 annotType = (String)iteratorTypes.next(); 452 453 annotationSchema.setAnnotationName(annotType); 454 455 // create an annotation diff 456 AnnotationDiff annotDiff = new AnnotationDiff(); 457 annotDiff.setKeyDocument(keyDocument); 458 annotDiff.setResponseDocument(responseDocument); 459 annotDiff.setAnnotationSchema(annotationSchema); 460 annotDiff.setKeyAnnotationSetName(null); 461 annotDiff.setResponseAnnotationSetName(null); 462 463 Set significantFeatures = new HashSet(Arrays.asList( 464 new String[]{"NMRule", "kind", "orgType", "rule", 465 "rule1", "rule2", "locType", "gender", 466 "majorType", "minorType", "category", 467 "length", "orth", "string", "subkind", 468 "symbolkind"})); 469 annotDiff.setKeyFeatureNamesSet(significantFeatures); 470 annotDiff.setTextMode(new Boolean(true)); 471 472 annotDiff.init(); 473 474 if (DEBUG){ 475 if (annotDiff.getFMeasureAverage() != 1.0) { 476 assertTrue("missing annotations " + 477 annotDiff.getAnnotationsOfType(AnnotationDiff.MISSING_TYPE) 478 + " spurious annotations " + 479 annotDiff.getAnnotationsOfType(AnnotationDiff.SPURIOUS_TYPE) 480 + " partially-correct annotations " + 481 annotDiff.getAnnotationsOfType( 482 AnnotationDiff.PARTIALLY_CORRECT_TYPE),false); 483 } 484 }//if 485 486 assertTrue(annotType+ " precision average in "+ 487 responseDocument.getSourceUrl().getFile()+ 488 " is "+ annotDiff.getPrecisionAverage()+ " instead of 1.0 ", 489 annotDiff.getPrecisionAverage()== 1.0); 490 assertTrue(annotType+" recall average in " 491 +responseDocument.getSourceUrl().getFile()+ 492 " is " + annotDiff.getRecallAverage()+ " instead of 1.0 ", 493 annotDiff.getRecallAverage()== 1.0); 494 assertTrue(annotType+" f-measure average in " 495 +responseDocument.getSourceUrl().getFile()+ 496 " is "+ annotDiff.getFMeasureAverage()+ " instead of 1.0 ", 497 annotDiff.getFMeasureAverage()== 1.0); 498 }//while 499 }// public void compareAnnots 500 501 /** Test suite routine for the test runner */ 502 public static Test suite() { 503 return new TestSuite(TestPR.class); 504 } // suite 505 506 public static void main(String[] args) { 507 try{ 508 509 Gate.init(); 510 TestPR testPR = new TestPR(""); 511 testPR.setUp(); 512 testPR.testTokenizer(); 513 testPR.testGazetteer(); 514 testPR.testSplitter(); 515 testPR.testTagger(); 516 testPR.testTransducer(); 517 testPR.testOrthomatcher(); 518 testPR.testAllPR(); 519 testPR.tearDown(); 520 } catch(Exception e) { 521 e.printStackTrace(); 522 } 523 } // main 524 } // class TestPR 525
|
TestPR |
|