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