apache-opennlp-2.5.12-src/0040755 0000000 0000000 00000000000 15217274217 015632 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/dev/0040755 0000000 0000000 00000000000 15217274217 016410 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-api/0040755 0000000 0000000 00000000000 15217274217 020054 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/0040755 0000000 0000000 00000000000 15217274217 020233 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-cli/0040755 0000000 0000000 00000000000 15217274217 022453 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-formats/0040755 0000000 0000000 00000000000 15217274217 023357 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/0040755 0000000 0000000 00000000000 15217274217 022314 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/opennlp-dl/0040755 0000000 0000000 00000000000 15217274217 024364 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/opennlp-dl-gpu/0040755 0000000 0000000 00000000000 15217274217 025155 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/opennlp-ml-bayes/0040755 0000000 0000000 00000000000 15217274217 025476 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/opennlp-ml-commons/0040755 0000000 0000000 00000000000 15217274217 026046 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/opennlp-ml-libsvm/0040755 0000000 0000000 00000000000 15217274217 025667 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/opennlp-ml-maxent/0040755 0000000 0000000 00000000000 15217274217 025667 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-ml/opennlp-ml-perceptron/0040755 0000000 0000000 00000000000 15217274217 026554 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-model-resolver/0040755 0000000 0000000 00000000000 15217274217 024643 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-core/opennlp-runtime/0040755 0000000 0000000 00000000000 15217274217 023367 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/0040755 0000000 0000000 00000000000 15217274217 020430 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/0040755 0000000 0000000 00000000000 15217274217 021217 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/main/0040755 0000000 0000000 00000000000 15217274217 022143 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/main/assembly/0040755 0000000 0000000 00000000000 15217274217 023762 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/main/bin/0040755 0000000 0000000 00000000000 15217274217 022713 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/main/docker/0040755 0000000 0000000 00000000000 15217274217 023412 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/main/readme/0040755 0000000 0000000 00000000000 15217274217 023400 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/main/resources/0040755 0000000 0000000 00000000000 15217274217 024155 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/test/0040755 0000000 0000000 00000000000 15217274217 022176 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/test/ps/0040755 0000000 0000000 00000000000 15217274217 022620 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/test/sh/0040755 0000000 0000000 00000000000 15217274217 022610 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/0040755 0000000 0000000 00000000000 15217274217 017702 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/0040755 0000000 0000000 00000000000 15217274217 020471 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/0040755 0000000 0000000 00000000000 15217274217 021415 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/0040755 0000000 0000000 00000000000 15217274217 022336 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 024011 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/0040755 0000000 0000000 00000000000 15217274217 024410 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/0040755 0000000 0000000 00000000000 15217274217 025645 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/scoring/0040755 0000000 0000000 00000000000 15217274217 027311 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/namefinder/0040755 0000000 0000000 00000000000 15217274217 026520 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/vectors/0040755 0000000 0000000 00000000000 15217274217 026075 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/0040755 0000000 0000000 00000000000 15217274217 021450 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/0040755 0000000 0000000 00000000000 15217274217 022371 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 024044 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/0040755 0000000 0000000 00000000000 15217274217 024443 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/0040755 0000000 0000000 00000000000 15217274217 025700 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/scoring/0040755 0000000 0000000 00000000000 15217274217 027344 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/namefinder/0040755 0000000 0000000 00000000000 15217274217 026553 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/vectors/0040755 0000000 0000000 00000000000 15217274217 026130 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/resources/0040755 0000000 0000000 00000000000 15217274217 023462 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/resources/opennlp/0040755 0000000 0000000 00000000000 15217274217 025135 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl/src/test/resources/opennlp/dl/0040755 0000000 0000000 00000000000 15217274217 025534 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-dl-gpu/0040755 0000000 0000000 00000000000 15217274217 020473 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/0040755 0000000 0000000 00000000000 15217274217 020233 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/0040755 0000000 0000000 00000000000 15217274217 021022 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/0040755 0000000 0000000 00000000000 15217274217 022274 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/css/0040755 0000000 0000000 00000000000 15217274217 023064 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/images/0040755 0000000 0000000 00000000000 15217274217 023541 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/main/0040755 0000000 0000000 00000000000 15217274217 021746 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/main/resources/0040755 0000000 0000000 00000000000 15217274217 023760 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/main/resources/xsl/0040755 0000000 0000000 00000000000 15217274217 024566 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-eval-tests/0040755 0000000 0000000 00000000000 15217274217 021372 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-extensions/0040755 0000000 0000000 00000000000 15217274217 021502 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-extensions/opennlp-morfologik/0040755 0000000 0000000 00000000000 15217274217 025323 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-extensions/opennlp-spellcheck/0040755 0000000 0000000 00000000000 15217274217 025270 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-extensions/opennlp-uima/0040755 0000000 0000000 00000000000 15217274217 024106 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/0040755 0000000 0000000 00000000000 15217274217 022536 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/bin/0040755 0000000 0000000 00000000000 15217274217 023306 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/0040755 0000000 0000000 00000000000 15217274217 023325 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/0040755 0000000 0000000 00000000000 15217274217 024251 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/bin/0040755 0000000 0000000 00000000000 15217274217 025021 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/0040755 0000000 0000000 00000000000 15217274217 025172 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 026645 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/0040755 0000000 0000000 00000000000 15217274217 031015 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/builder/0040755 0000000 0000000 00000000000 15217274217 032443 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/0040755 0000000 0000000 00000000000 15217274217 032430 5ustar00rootroot0000000 0000000 ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000156 15217274217 032425 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/ apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/0040755 0000000 0000000 00000000000 15217274217 034056 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/lemmatizer/0040755 0000000 0000000 00000000000 15217274217 033166 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/tagdict/0040755 0000000 0000000 00000000000 15217274217 032434 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/util/0040755 0000000 0000000 00000000000 15217274217 031772 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/0040755 0000000 0000000 00000000000 15217274217 024304 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/0040755 0000000 0000000 00000000000 15217274217 025225 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 026700 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/0040755 0000000 0000000 00000000000 15217274217 031050 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/builder/0040755 0000000 0000000 00000000000 15217274217 032476 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/lemmatizer/0040755 0000000 0000000 00000000000 15217274217 033221 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/tagdict/0040755 0000000 0000000 00000000000 15217274217 032467 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/resources/0040755 0000000 0000000 00000000000 15217274217 026316 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/0040755 0000000 0000000 00000000000 15217274217 020443 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/bin/0040755 0000000 0000000 00000000000 15217274217 021213 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/0040755 0000000 0000000 00000000000 15217274217 021364 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/de/0040755 0000000 0000000 00000000000 15217274217 021754 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/de/namefinder/0040755 0000000 0000000 00000000000 15217274217 024064 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/0040755 0000000 0000000 00000000000 15217274217 021766 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/namefinder/0040755 0000000 0000000 00000000000 15217274217 024076 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/parser/0040755 0000000 0000000 00000000000 15217274217 023262 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/postag/0040755 0000000 0000000 00000000000 15217274217 023263 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/tokenizer/0040755 0000000 0000000 00000000000 15217274217 024000 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/es/0040755 0000000 0000000 00000000000 15217274217 021773 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/es/parser/0040755 0000000 0000000 00000000000 15217274217 023267 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/fr/0040755 0000000 0000000 00000000000 15217274217 021773 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/fr/tokenizer/0040755 0000000 0000000 00000000000 15217274217 024005 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/ga/0040755 0000000 0000000 00000000000 15217274217 021753 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/ga/tokenizer/0040755 0000000 0000000 00000000000 15217274217 023765 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/general/0040755 0000000 0000000 00000000000 15217274217 023001 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/general/tokenizer/0040755 0000000 0000000 00000000000 15217274217 025013 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/it/0040755 0000000 0000000 00000000000 15217274217 022000 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/ml/0040755 0000000 0000000 00000000000 15217274217 021774 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/nl/0040755 0000000 0000000 00000000000 15217274217 021775 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/pl/0040755 0000000 0000000 00000000000 15217274217 021777 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/pt/0040755 0000000 0000000 00000000000 15217274217 022007 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/pt/tokenizer/0040755 0000000 0000000 00000000000 15217274217 024021 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/0040755 0000000 0000000 00000000000 15217274217 021232 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/0040755 0000000 0000000 00000000000 15217274217 022010 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/0040755 0000000 0000000 00000000000 15217274217 022731 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 024404 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/0040755 0000000 0000000 00000000000 15217274217 025544 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/ml/0040755 0000000 0000000 00000000000 15217274217 026154 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/sentdetect/0040755 0000000 0000000 00000000000 15217274217 027706 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/0040755 0000000 0000000 00000000000 15217274217 026521 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/0040755 0000000 0000000 00000000000 15217274217 027315 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/jmh/0040755 0000000 0000000 00000000000 15217274217 030073 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/0040755 0000000 0000000 00000000000 15217274217 022156 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/0040755 0000000 0000000 00000000000 15217274217 023077 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 024552 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/0040755 0000000 0000000 00000000000 15217274217 025712 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/0040755 0000000 0000000 00000000000 15217274217 027351 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/0040755 0000000 0000000 00000000000 15217274217 027325 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/0040755 0000000 0000000 00000000000 15217274217 030764 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/dictionary/0040755 0000000 0000000 00000000000 15217274217 031472 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/0040755 0000000 0000000 00000000000 15217274217 030562 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/entitylinker/0040755 0000000 0000000 00000000000 15217274217 032046 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/0040755 0000000 0000000 00000000000 15217274217 031437 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/languagemodel/0040755 0000000 0000000 00000000000 15217274217 032131 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/0040755 0000000 0000000 00000000000 15217274217 031476 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/0040755 0000000 0000000 00000000000 15217274217 031106 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/0040755 0000000 0000000 00000000000 15217274217 030610 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/0040755 0000000 0000000 00000000000 15217274217 030621 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/0040755 0000000 0000000 00000000000 15217274217 030622 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/0040755 0000000 0000000 00000000000 15217274217 031467 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/0040755 0000000 0000000 00000000000 15217274217 031337 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/commons/0040755 0000000 0000000 00000000000 15217274217 027365 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/0040755 0000000 0000000 00000000000 15217274217 030057 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/0040755 0000000 0000000 00000000000 15217274217 032230 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/0040755 0000000 0000000 00000000000 15217274217 027147 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/0040755 0000000 0000000 00000000000 15217274217 030433 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/0040755 0000000 0000000 00000000000 15217274217 027365 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/0040755 0000000 0000000 00000000000 15217274217 027751 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/0040755 0000000 0000000 00000000000 15217274217 030315 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/0040755 0000000 0000000 00000000000 15217274217 030661 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/0040755 0000000 0000000 00000000000 15217274217 031045 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/0040755 0000000 0000000 00000000000 15217274217 032346 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/0040755 0000000 0000000 00000000000 15217274217 033064 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/0040755 0000000 0000000 00000000000 15217274217 031030 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/0040755 0000000 0000000 00000000000 15217274217 030675 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/0040755 0000000 0000000 00000000000 15217274217 030310 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/moses/0040755 0000000 0000000 00000000000 15217274217 030513 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/0040755 0000000 0000000 00000000000 15217274217 030151 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/0040755 0000000 0000000 00000000000 15217274217 030327 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/0040755 0000000 0000000 00000000000 15217274217 031415 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/0040755 0000000 0000000 00000000000 15217274217 030024 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/languagemodel/0040755 0000000 0000000 00000000000 15217274217 030516 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/0040755 0000000 0000000 00000000000 15217274217 030063 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/log/0040755 0000000 0000000 00000000000 15217274217 026473 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/0040755 0000000 0000000 00000000000 15217274217 026322 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/0040755 0000000 0000000 00000000000 15217274217 027616 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/0040755 0000000 0000000 00000000000 15217274217 030225 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/0040755 0000000 0000000 00000000000 15217274217 032173 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/0040755 0000000 0000000 00000000000 15217274217 027422 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/0040755 0000000 0000000 00000000000 15217274217 030450 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/0040755 0000000 0000000 00000000000 15217274217 030503 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/models/0040755 0000000 0000000 00000000000 15217274217 027175 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/0040755 0000000 0000000 00000000000 15217274217 030077 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/0040755 0000000 0000000 00000000000 15217274217 027473 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ngram/0040755 0000000 0000000 00000000000 15217274217 027016 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/0040755 0000000 0000000 00000000000 15217274217 027206 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/0040755 0000000 0000000 00000000000 15217274217 031014 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/lang/0040755 0000000 0000000 00000000000 15217274217 030127 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/lang/en/0040755 0000000 0000000 00000000000 15217274217 030531 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/lang/es/0040755 0000000 0000000 00000000000 15217274217 030536 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/0040755 0000000 0000000 00000000000 15217274217 031372 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/0040755 0000000 0000000 00000000000 15217274217 027207 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/0040755 0000000 0000000 00000000000 15217274217 030054 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/lang/0040755 0000000 0000000 00000000000 15217274217 030775 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/lang/th/0040755 0000000 0000000 00000000000 15217274217 031410 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/0040755 0000000 0000000 00000000000 15217274217 027366 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/0040755 0000000 0000000 00000000000 15217274217 031207 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/0040755 0000000 0000000 00000000000 15217274217 027542 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/lang/0040755 0000000 0000000 00000000000 15217274217 030463 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/lang/en/0040755 0000000 0000000 00000000000 15217274217 031065 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/0040755 0000000 0000000 00000000000 15217274217 026667 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/0040755 0000000 0000000 00000000000 15217274217 027616 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ext/0040755 0000000 0000000 00000000000 15217274217 027467 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/0040755 0000000 0000000 00000000000 15217274217 031014 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/java/0040755 0000000 0000000 00000000000 15217274217 027610 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/jvm/0040755 0000000 0000000 00000000000 15217274217 027463 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/model/0040755 0000000 0000000 00000000000 15217274217 027767 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/normalizer/0040755 0000000 0000000 00000000000 15217274217 031051 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/wordvector/0040755 0000000 0000000 00000000000 15217274217 031065 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/resources/0040755 0000000 0000000 00000000000 15217274217 024170 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/resources/opennlp/0040755 0000000 0000000 00000000000 15217274217 025643 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/resources/opennlp/tools/0040755 0000000 0000000 00000000000 15217274217 027003 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/resources/opennlp/tools/namefind/0040755 0000000 0000000 00000000000 15217274217 030564 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/resources/opennlp/tools/postag/0040755 0000000 0000000 00000000000 15217274217 030300 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/main/resources/opennlp/tools/util/0040755 0000000 0000000 00000000000 15217274217 027760 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/0040755 0000000 0000000 00000000000 15217274217 022211 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/0040755 0000000 0000000 00000000000 15217274217 023132 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 024605 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/0040755 0000000 0000000 00000000000 15217274217 025745 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/chunker/0040755 0000000 0000000 00000000000 15217274217 027404 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/0040755 0000000 0000000 00000000000 15217274217 027360 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/chunker/0040755 0000000 0000000 00000000000 15217274217 031017 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/langdetect/0040755 0000000 0000000 00000000000 15217274217 031472 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/languagemodel/0040755 0000000 0000000 00000000000 15217274217 032164 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/lemmatizer/0040755 0000000 0000000 00000000000 15217274217 031531 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/namefind/0040755 0000000 0000000 00000000000 15217274217 031141 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/namefind/generator/0040755 0000000 0000000 00000000000 15217274217 033127 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/postag/0040755 0000000 0000000 00000000000 15217274217 030655 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/sentdetect/0040755 0000000 0000000 00000000000 15217274217 031522 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/cmdline/tokenizer/0040755 0000000 0000000 00000000000 15217274217 031372 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/dictionary/0040755 0000000 0000000 00000000000 15217274217 030112 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/doccat/0040755 0000000 0000000 00000000000 15217274217 027202 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/eval/0040755 0000000 0000000 00000000000 15217274217 026674 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/0040755 0000000 0000000 00000000000 15217274217 027420 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/ad/0040755 0000000 0000000 00000000000 15217274217 030004 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/brat/0040755 0000000 0000000 00000000000 15217274217 030350 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/conllu/0040755 0000000 0000000 00000000000 15217274217 030714 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/convert/0040755 0000000 0000000 00000000000 15217274217 031100 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/frenchtreebank/0040755 0000000 0000000 00000000000 15217274217 032401 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/irishsentencebank/0040755 0000000 0000000 00000000000 15217274217 033117 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/leipzig/0040755 0000000 0000000 00000000000 15217274217 031063 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/letsmt/0040755 0000000 0000000 00000000000 15217274217 030730 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/masc/0040755 0000000 0000000 00000000000 15217274217 030343 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/moses/0040755 0000000 0000000 00000000000 15217274217 030546 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/muc/0040755 0000000 0000000 00000000000 15217274217 030204 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/nkjp/0040755 0000000 0000000 00000000000 15217274217 030362 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/formats/ontonotes/0040755 0000000 0000000 00000000000 15217274217 031450 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/langdetect/0040755 0000000 0000000 00000000000 15217274217 030057 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/languagemodel/0040755 0000000 0000000 00000000000 15217274217 030551 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/lemmatizer/0040755 0000000 0000000 00000000000 15217274217 030116 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ml/0040755 0000000 0000000 00000000000 15217274217 026355 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ml/maxent/0040755 0000000 0000000 00000000000 15217274217 027651 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ml/maxent/io/0040755 0000000 0000000 00000000000 15217274217 030260 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ml/maxent/quasinewton/0040755 0000000 0000000 00000000000 15217274217 032226 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ml/model/0040755 0000000 0000000 00000000000 15217274217 027455 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ml/naivebayes/0040755 0000000 0000000 00000000000 15217274217 030503 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ml/perceptron/0040755 0000000 0000000 00000000000 15217274217 030536 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/monitoring/0040755 0000000 0000000 00000000000 15217274217 030132 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/namefind/0040755 0000000 0000000 00000000000 15217274217 027526 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/ngram/0040755 0000000 0000000 00000000000 15217274217 027051 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/parser/0040755 0000000 0000000 00000000000 15217274217 027241 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/parser/chunking/0040755 0000000 0000000 00000000000 15217274217 031047 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/parser/lang/0040755 0000000 0000000 00000000000 15217274217 030162 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/parser/lang/en/0040755 0000000 0000000 00000000000 15217274217 030564 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/parser/treeinsert/0040755 0000000 0000000 00000000000 15217274217 031425 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/postag/0040755 0000000 0000000 00000000000 15217274217 027242 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/sentdetect/0040755 0000000 0000000 00000000000 15217274217 030107 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/stemmer/0040755 0000000 0000000 00000000000 15217274217 027421 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/tokenize/0040755 0000000 0000000 00000000000 15217274217 027575 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/0040755 0000000 0000000 00000000000 15217274217 026722 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/eval/0040755 0000000 0000000 00000000000 15217274217 027651 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/ext/0040755 0000000 0000000 00000000000 15217274217 027522 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/featuregen/0040755 0000000 0000000 00000000000 15217274217 031047 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/jvm/0040755 0000000 0000000 00000000000 15217274217 027516 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/model/0040755 0000000 0000000 00000000000 15217274217 030022 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/normalizer/0040755 0000000 0000000 00000000000 15217274217 031104 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/java/opennlp/tools/util/wordvector/0040755 0000000 0000000 00000000000 15217274217 031120 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/0040755 0000000 0000000 00000000000 15217274217 024223 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/data/0040755 0000000 0000000 00000000000 15217274217 025134 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/data/opennlp/0040755 0000000 0000000 00000000000 15217274217 026607 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/data/opennlp/maxent/0040755 0000000 0000000 00000000000 15217274217 030103 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/data/opennlp/maxent/io/0040755 0000000 0000000 00000000000 15217274217 030512 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/data/ppa/0040755 0000000 0000000 00000000000 15217274217 025714 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/0040755 0000000 0000000 00000000000 15217274217 025676 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/0040755 0000000 0000000 00000000000 15217274217 027036 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/chunker/0040755 0000000 0000000 00000000000 15217274217 030475 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/cmdline/0040755 0000000 0000000 00000000000 15217274217 030451 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/cmdline/languagemodel/0040755 0000000 0000000 00000000000 15217274217 033255 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/doccat/0040755 0000000 0000000 00000000000 15217274217 030273 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/eval/0040755 0000000 0000000 00000000000 15217274217 027765 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/0040755 0000000 0000000 00000000000 15217274217 030511 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/20newsgroup/0040755 0000000 0000000 00000000000 15217274217 032704 5ustar00rootroot0000000 0000000 ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_test_resources_opennlp_tools_formats_20n0100644 0000000 0000000 00000000167 15217274217 032523 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/20newsgroup/sci.electronics/ apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/20newsgroup/sci.ele0040755 0000000 0000000 00000000000 15217274217 034147 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/ad/0040755 0000000 0000000 00000000000 15217274217 031075 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/brat/0040755 0000000 0000000 00000000000 15217274217 031441 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/conllu/0040755 0000000 0000000 00000000000 15217274217 032005 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/frenchtreebank/0040755 0000000 0000000 00000000000 15217274217 033472 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/irishsentencebank/0040755 0000000 0000000 00000000000 15217274217 034210 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/leipzig/0040755 0000000 0000000 00000000000 15217274217 032154 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/leipzig/samples/0040755 0000000 0000000 00000000000 15217274217 033620 5ustar00rootroot0000000 0000000 ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_test_resources_opennlp_tools_formats_lei0100644 0000000 0000000 00000000164 15217274217 032672 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/leipzig/samples/dontread/ apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/leipzig/samples/don0040755 0000000 0000000 00000000000 15217274217 034321 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/letsmt/0040755 0000000 0000000 00000000000 15217274217 032021 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/masc/0040755 0000000 0000000 00000000000 15217274217 031434 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/moses/0040755 0000000 0000000 00000000000 15217274217 031637 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/muc/0040755 0000000 0000000 00000000000 15217274217 031275 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/nkjp/0040755 0000000 0000000 00000000000 15217274217 031453 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/formats/ontonotes/0040755 0000000 0000000 00000000000 15217274217 032541 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/lang/0040755 0000000 0000000 00000000000 15217274217 027757 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/languagemodel/0040755 0000000 0000000 00000000000 15217274217 031642 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/lemmatizer/0040755 0000000 0000000 00000000000 15217274217 031207 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/ml/0040755 0000000 0000000 00000000000 15217274217 027446 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/ml/maxent/0040755 0000000 0000000 00000000000 15217274217 030742 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/namefind/0040755 0000000 0000000 00000000000 15217274217 030617 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/ngram/0040755 0000000 0000000 00000000000 15217274217 030142 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/parser/0040755 0000000 0000000 00000000000 15217274217 030332 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/postag/0040755 0000000 0000000 00000000000 15217274217 030333 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/sentdetect/0040755 0000000 0000000 00000000000 15217274217 031200 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/tokenize/0040755 0000000 0000000 00000000000 15217274217 030666 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/util/0040755 0000000 0000000 00000000000 15217274217 030013 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/util/featuregen/0040755 0000000 0000000 00000000000 15217274217 032140 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/src/test/resources/opennlp/tools/util/wordvector/0040755 0000000 0000000 00000000000 15217274217 032211 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/0040755 0000000 0000000 00000000000 15217274217 021724 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/0040755 0000000 0000000 00000000000 15217274217 022513 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/0040755 0000000 0000000 00000000000 15217274217 023437 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/java/0040755 0000000 0000000 00000000000 15217274217 024360 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 026033 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/java/opennlp/tools/0040755 0000000 0000000 00000000000 15217274217 027173 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/java/opennlp/tools/models/0040755 0000000 0000000 00000000000 15217274217 030456 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/java/opennlp/tools/models/classgraph/0040755 0000000 0000000 00000000000 15217274217 032605 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/java/opennlp/tools/models/dir/0040755 0000000 0000000 00000000000 15217274217 031234 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/main/java/opennlp/tools/models/simple/0040755 0000000 0000000 00000000000 15217274217 031747 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/test/0040755 0000000 0000000 00000000000 15217274217 023472 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/test/java/0040755 0000000 0000000 00000000000 15217274217 024413 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/test/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 026066 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/test/java/opennlp/tools/0040755 0000000 0000000 00000000000 15217274217 027226 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/test/java/opennlp/tools/models/0040755 0000000 0000000 00000000000 15217274217 030511 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/0040755 0000000 0000000 00000000000 15217274217 032640 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/0040755 0000000 0000000 00000000000 15217274217 032002 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/0040755 0000000 0000000 00000000000 15217274217 020236 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/descriptors/0040755 0000000 0000000 00000000000 15217274217 022577 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/metadata/0040755 0000000 0000000 00000000000 15217274217 022016 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/0040755 0000000 0000000 00000000000 15217274217 021025 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/0040755 0000000 0000000 00000000000 15217274217 021751 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/0040755 0000000 0000000 00000000000 15217274217 022672 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 024345 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/0040755 0000000 0000000 00000000000 15217274217 025300 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/chunker/0040755 0000000 0000000 00000000000 15217274217 026737 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/dictionary/0040755 0000000 0000000 00000000000 15217274217 027445 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/doccat/0040755 0000000 0000000 00000000000 15217274217 026535 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/namefind/0040755 0000000 0000000 00000000000 15217274217 027061 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/normalizer/0040755 0000000 0000000 00000000000 15217274217 027462 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/parser/0040755 0000000 0000000 00000000000 15217274217 026574 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/postag/0040755 0000000 0000000 00000000000 15217274217 026575 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/sentdetect/0040755 0000000 0000000 00000000000 15217274217 027442 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/tokenize/0040755 0000000 0000000 00000000000 15217274217 027130 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/java/opennlp/uima/util/0040755 0000000 0000000 00000000000 15217274217 026255 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/resources/0040755 0000000 0000000 00000000000 15217274217 023763 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/resources/opennlp/0040755 0000000 0000000 00000000000 15217274217 025436 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/resources/opennlp/uima/0040755 0000000 0000000 00000000000 15217274217 026371 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/main/resources/opennlp/uima/util/0040755 0000000 0000000 00000000000 15217274217 027346 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/0040755 0000000 0000000 00000000000 15217274217 022004 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/java/0040755 0000000 0000000 00000000000 15217274217 022725 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/java/opennlp/0040755 0000000 0000000 00000000000 15217274217 024400 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/java/opennlp/uima/0040755 0000000 0000000 00000000000 15217274217 025333 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/java/opennlp/uima/dictionary/0040755 0000000 0000000 00000000000 15217274217 027500 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/java/opennlp/uima/normalizer/0040755 0000000 0000000 00000000000 15217274217 027515 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/java/opennlp/uima/util/0040755 0000000 0000000 00000000000 15217274217 026310 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/resources/0040755 0000000 0000000 00000000000 15217274217 024016 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/resources/cas/0040755 0000000 0000000 00000000000 15217274217 024564 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-uima/src/test/resources/test-descriptors/0040755 0000000 0000000 00000000000 15217274217 027334 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/src/0040755 0000000 0000000 00000000000 15217274217 016421 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/src/license/0040755 0000000 0000000 00000000000 15217274217 020043 5ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/LICENSE0100644 0000000 0000000 00000040500 15217274217 016633 0ustar00rootroot0000000 0000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. The following license applies to the Snowball stemmers: Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The following license applies to the Wordpiece tokenizer implementation: The MIT License (MIT) Copyright (c) 2019 Rob Rua Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The following license applies to the ONNX Runtime: MIT License Copyright (c) Microsoft Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The following license applies to the SLF4J API: MIT license Copyright (c) 2004-2025 QOS.ch Sarl (Switzerland) All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. apache-opennlp-2.5.12-src/NOTICE0100644 0000000 0000000 00000006744 15217274217 016546 0ustar00rootroot0000000 0000000 Apache OpenNLP Copyright 2021-2026 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). ============================================================================ The snowball stemmers in opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball were developed by Martin Porter and Richard Boulton. The full snowball package is available from http://snowball.tartarus.org/ ============================================================================ The Wordpiece tokenizer in opennlp-tools/main/java/opennlp/tools/tokenize is taken from https://github.com/robrua/easy-bert licensed under The MIT License (MIT) Copyright (c) 2019 Rob Rua Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================ List of third-party dependencies grouped by their license type. Apache License, Version 2.0 * Apache Log4j API (org.apache.logging.log4j:log4j-api:2.26.1 - https://logging.apache.org/log4j/2.x/) * Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.26.1 - https://logging.apache.org/log4j/2.x/) * Apache UIMA Base: uimaj-core (org.apache.uima:uimaj-core:3.6.1 - https://uima.apache.org) * HPPC Collections (com.carrotsearch:hppc:0.7.2 - http://labs.carrotsearch.com/hppc.html/hppc) * jcommander (com.beust:jcommander:1.78 - https://jcommander.org) * SLF4J 2 Provider for Log4j API (org.apache.logging.log4j:log4j-slf4j2-impl:2.26.1 - https://logging.apache.org/log4j/2.x/) BSD License * Morfologik Command Line Tools (org.carrot2:morfologik-tools:2.2.0 - http://morfologik.blogspot.com/morfologik-tools/) * Morfologik FSA (Builder) (org.carrot2:morfologik-fsa-builders:2.2.0 - http://morfologik.blogspot.com/morfologik-fsa-builders/) * Morfologik FSA (Traversal) (org.carrot2:morfologik-fsa:2.2.0 - http://morfologik.blogspot.com/morfologik-fsa/) * Morfologik Stemming APIs (org.carrot2:morfologik-stemming:2.2.0 - http://morfologik.blogspot.com/morfologik-stemming/) MIT License * onnx-runtime (com.microsoft.onnxruntime:onnxruntime_gpu:1.29.0 - https://microsoft.github.io/onnxruntime/) * onnx-runtime (com.microsoft.onnxruntime:onnxruntime:1.29.0 - https://microsoft.github.io/onnxruntime/) * SLF4J API Module (org.slf4j:slf4j-api:2.0.18 - http://www.slf4j.org) The MIT License (MIT) * ClassGraph (io.github.classgraph:classgraph:4.8.194 - https://github.com/classgraph/classgraph) apache-opennlp-2.5.12-src/README.md0100644 0000000 0000000 00000013744 15217274217 017117 0ustar00rootroot0000000 0000000 Welcome to Apache OpenNLP! =========== [![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/apache/opennlp/main/LICENSE) [![Maven Central](https://img.shields.io/maven-central/v/org.apache.opennlp/opennlp)](https://img.shields.io/maven-central/v/org.apache.opennlp/opennlp) [![Documentation Status](https://img.shields.io/:docs-latest-green.svg)](http://opennlp.apache.org/docs/index.html) [![Build Status](https://github.com/apache/opennlp/workflows/Java%20CI/badge.svg)](https://github.com/apache/opennlp/actions) [![Contributors](https://img.shields.io/github/contributors/apache/opennlp)](https://github.com/apache/opennlp/graphs/contributors) [![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/apache/opennlp.svg)](https://github.com/apache/opennlp/pulls) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/apache/opennlp/badge)](https://api.securityscorecards.dev/projects/github.com/apache/opennlp) The Apache OpenNLP library is a machine learning based toolkit for the processing of natural language text. This toolkit is written completely in Java and provides support for common NLP tasks, such as tokenization, sentence segmentation, part-of-speech tagging, named entity extraction, chunking, parsing, coreference resolution, language detection and more! These tasks are usually required to build more advanced text processing services. The goal of the OpenNLP project is to be a mature toolkit for the above mentioned tasks. An additional goal is to provide a large number of pre-built models for a variety of languages, as well as the annotated text resources that those models are derived from. Presently, OpenNLP includes common classifiers such as Maximum Entropy, Perceptron and Naive Bayes. OpenNLP can be used both programmatically through its Java API or from a terminal through its CLI. OpenNLP API can be easily plugged into distributed streaming data pipelines like Apache Flink, Apache NiFi, Apache Spark. ## Useful Links For additional information, visit the [OpenNLP Home Page](http://opennlp.apache.org/) You can use OpenNLP with any language, demo models are provided [here](https://downloads.apache.org/opennlp/models/). The models are fully compatible with the latest release, they can be used for testing or getting started. > [!NOTE] > Please train your own models for all other use cases. Documentation, including JavaDocs, code usage and command-line interface examples are available [here](http://opennlp.apache.org/docs/) For recent news, updates and topics, you can: - join the regular [mailing lists](http://opennlp.apache.org/mailing-lists.html), - follow the project's [![Bluesky](https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky&logoColor=fff)](https://bsky.app/profile/apacheopennlp.bsky.social) social media channel, or - join the [![Slack](https://img.shields.io/badge/Slack-4A154B?logo=slack&logoColor=fff)](https://the-asf.slack.com) channel (available to people with an _@apache.org_ email address or upon invitation). Please, also check the [![Stack Overflow](https://img.shields.io/badge/-Stack%20Overflow-FE7A16?logo=stack-overflow&logoColor=white)](https://stackoverflow.com/questions/tagged/opennlp) community's OpenNLP questions and answers. ## Overview Currently, the library has different packages: * `opennlp-tools` : The core toolkit. * `opennlp-tools-models` : A set of classes to load [OpenNLP models](https://github.com/apache/opennlp-models) from the classpath. * `opennlp-uima` : A set of [Apache UIMA](https://uima.apache.org) annotators. * `opennlp-morfologik-addon` : An addon for Morfologik * `opennlp-dl` : OpenNLP interface implementations for ONNX models using the `onnxruntime` dependency. * `opennlp-dl-gpu` : Replaces `onnxruntime` with the `onnxruntime_gpu` dependency to support GPU acceleration. * `opennlp-sandbox`: Other projects in progress are found in the [sandbox](https://github.com/apache/opennlp-sandbox) ## Getting Started You can import the core toolkit directly from Maven, SBT or Gradle: #### Maven ``` org.apache.opennlp opennlp-tools ${opennlp.version} ``` #### SBT ``` libraryDependencies += "org.apache.opennlp" % "opennlp-tools" % "${opennlp.version}" ``` #### Gradle ``` compile group: "org.apache.opennlp", name: "opennlp-tools", version: "${opennlp.version}" ``` For more details please check our [documentation](http://opennlp.apache.org/docs/) ## Building OpenNLP At least JDK 17 and Maven 3.3.9 are required to build the library. After cloning the repository go into the destination directory and run: ``` mvn install ``` ### Additional Developement Information - [Building and Integrating Snowball Stemmer for OpenNLP](dev/Snowball-Stemmer.md) ## Contributing The Apache OpenNLP project is developed by volunteers and is always looking for new contributors to work on all parts of the project. Every contribution is welcome and needed to make it better. A contribution can be anything from a small documentation typo fix to a new component. If you would like to get involved please follow the instructions [here](https://github.com/apache/opennlp/blob/main/.github/CONTRIBUTING.md) apache-opennlp-2.5.12-src/checkstyle.xml0100644 0000000 0000000 00000014035 15217274217 020512 0ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/dev/Snowball-Stemmer.md0100644 0000000 0000000 00000005304 15217274217 022124 0ustar00rootroot0000000 0000000 # Building and Integrating Snowball Stemmer for OpenNLP This guide outlines the steps to build the Snowball compiler, generate stemmer classes, and integrate them into OpenNLP. --- ## Prerequisites - A Unix-like environment with `make` installed. - Access to the [Snowball repository](https://github.com/snowballstem/snowball). - The OpenNLP repository checked out locally. --- ## Procedure ### 1. Clone and Build the Snowball Compiler Clone the Snowball repository and build the compiler using `make`: ```bash git clone https://github.com/snowballstem/snowball.git cd snowball make ``` This will generate the snowball compiler in the root directory of the repository. # Run the Snowball Compiler Run the Snowball compiler to generate the stemmer code. ```bash #!/bin/bash # Define an array of languages languages=("arabic" "catalan" "danish" "dutch" "english" "finnish" "french" "german" "greek" "hungarian" "indonesian" "irish" "italian" "norwegian" "porter" "portuguese" "romanian" "russian" "spanish" "swedish" "turkish") # Base paths snowball_exec_path="../snowball" output_base="../../../../IdeaProjects/opennlp/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball" # Loop through the languages and execute the command for lang in "${languages[@]}"; do "${snowball_exec_path}" "${lang}.sbl" -java -o "${output_base}/${lang}Stemmer" done ``` Usage: 1. Save this script as `generate_stemmers.sh` at the appropriate location. 2. Make it executable with `chmod +x generate_stemmers.sh`. 3. Run it using `./generate_stemmers.sh`. # Manually Reformat Code to Match OpenNLP Style - Open the generated Java files in your preferred IDE or text editor. - Reformat the code to match the OpenNLP code style. This may include: - Adjusting indentation. - Renaming variables or methods as needed. - Ensuring proper spacing and alignment. # Add License Information - Ensure each generated file includes the appropriate license information for both Snowball and OpenNLP. apache-opennlp-2.5.12-src/mvnw0100755 0000000 0000000 00000027016 15217274217 016552 0ustar00rootroot0000000 0000000 #!/bin/sh # ---------------------------------------------------------------------------- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- # Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- # JAVA_HOME - location of a JDK home dir, required when download maven via java source # MVNW_REPOURL - repo url base for downloading maven distribution # MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven # MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- set -euf [ "${MVNW_VERBOSE-}" != debug ] || set -x # OS specific support. native_path() { printf %s\\n "$1"; } case "$(uname)" in CYGWIN* | MINGW*) [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" native_path() { cygpath --path --windows "$1"; } ;; esac # set JAVACMD and JAVACCMD set_java_home() { # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched if [ -n "${JAVA_HOME-}" ]; then if [ -x "$JAVA_HOME/jre/sh/java" ]; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" JAVACCMD="$JAVA_HOME/jre/sh/javac" else JAVACMD="$JAVA_HOME/bin/java" JAVACCMD="$JAVA_HOME/bin/javac" if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 return 1 fi fi else JAVACMD="$( 'set' +e 'unset' -f command 2>/dev/null 'command' -v java )" || : JAVACCMD="$( 'set' +e 'unset' -f command 2>/dev/null 'command' -v javac )" || : if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 return 1 fi fi } # hash string like Java String::hashCode hash_string() { str="${1:-}" h=0 while [ -n "$str" ]; do char="${str%"${str#?}"}" h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) str="${str#?}" done printf %x\\n $h } verbose() { :; } [ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } die() { printf %s\\n "$1" >&2 exit 1 } trim() { # MWRAPPER-139: # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. # Needed for removing poorly interpreted newline sequences when running in more # exotic environments such as mingw bash on Windows. printf "%s" "${1}" | tr -d '[:space:]' } scriptDir="$(dirname "$0")" scriptName="$(basename "$0")" # parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties while IFS="=" read -r key value; do case "${key-}" in distributionUrl) distributionUrl=$(trim "${value-}") ;; distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; esac done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" [ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" case "${distributionUrl##*/}" in maven-mvnd-*bin.*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; :Linux*x86_64*) distributionPlatform=linux-amd64 ;; *) echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 distributionPlatform=linux-amd64 ;; esac distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" ;; maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; *) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; esac # apply MVNW_REPOURL and calculate MAVEN_HOME # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ [ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" distributionUrlName="${distributionUrl##*/}" distributionUrlNameMain="${distributionUrlName%.*}" distributionUrlNameMain="${distributionUrlNameMain%-bin}" MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" exec_maven() { unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" } if [ -d "$MAVEN_HOME" ]; then verbose "found existing MAVEN_HOME at $MAVEN_HOME" exec_maven "$@" fi case "${distributionUrl-}" in *?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; *) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; esac # prepare tmp dir if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } trap clean HUP INT TERM EXIT else die "cannot create temp dir" fi mkdir -p -- "${MAVEN_HOME%/*}" # Download and Install Apache Maven verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." verbose "Downloading from: $distributionUrl" verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" # select .zip or .tar.gz if ! command -v unzip >/dev/null; then distributionUrl="${distributionUrl%.zip}.tar.gz" distributionUrlName="${distributionUrl##*/}" fi # verbose opt __MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' [ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v # normalize http auth case "${MVNW_PASSWORD:+has-password}" in '') MVNW_USERNAME='' MVNW_PASSWORD='' ;; has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; esac if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then verbose "Found wget ... using wget" wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then verbose "Found curl ... using curl" curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" elif set_java_home; then verbose "Falling back to use Java to download" javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" cat >"$javaSource" <<-END public class Downloader extends java.net.Authenticator { protected java.net.PasswordAuthentication getPasswordAuthentication() { return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); } public static void main( String[] args ) throws Exception { setDefault( new Downloader() ); java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); } } END # For Cygwin/MinGW, switch paths to Windows format before running javac and java verbose " - Compiling Downloader.java ..." "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" verbose " - Running Downloader.java ..." "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" fi # If specified, validate the SHA-256 sum of the Maven distribution zip file if [ -n "${distributionSha256Sum-}" ]; then distributionSha256Result=false if [ "$MVN_CMD" = mvnd.sh ]; then echo "Checksum validation is not supported for maven-mvnd." >&2 echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 exit 1 elif command -v sha256sum >/dev/null; then if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then distributionSha256Result=true fi elif command -v shasum >/dev/null; then if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then distributionSha256Result=true fi else echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 exit 1 fi if [ $distributionSha256Result = false ]; then echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 exit 1 fi fi # unzip and move if command -v unzip >/dev/null; then unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" else tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" fi # Find the actual extracted directory name (handles snapshots where filename != directory name) actualDistributionDir="" # First try the expected directory name (for regular distributions) if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then actualDistributionDir="$distributionUrlNameMain" fi fi # If not found, search for any directory with the Maven executable (for snapshots) if [ -z "$actualDistributionDir" ]; then # enable globbing to iterate over items set +f for dir in "$TMP_DOWNLOAD_DIR"/*; do if [ -d "$dir" ]; then if [ -f "$dir/bin/$MVN_CMD" ]; then actualDistributionDir="$(basename "$dir")" break fi fi done set -f fi if [ -z "$actualDistributionDir" ]; then verbose "Contents of $TMP_DOWNLOAD_DIR:" verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" die "Could not find Maven distribution directory in extracted archive" fi verbose "Found extracted Maven distribution directory: $actualDistributionDir" printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" clean || : exec_maven "$@" apache-opennlp-2.5.12-src/mvnw.cmd0100644 0000000 0000000 00000020441 15217274217 017304 0ustar00rootroot0000000 0000000 <# : batch portion @REM ---------------------------------------------------------------------------- @REM Licensed to the Apache Software Foundation (ASF) under one @REM or more contributor license agreements. See the NOTICE file @REM distributed with this work for additional information @REM regarding copyright ownership. The ASF licenses this file @REM to you under the Apache License, Version 2.0 (the @REM "License"); you may not use this file except in compliance @REM with the License. You may obtain a copy of the License at @REM @REM http://www.apache.org/licenses/LICENSE-2.0 @REM @REM Unless required by applicable law or agreed to in writing, @REM software distributed under the License is distributed on an @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @REM KIND, either express or implied. See the License for the @REM specific language governing permissions and limitations @REM under the License. @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- @REM Apache Maven Wrapper startup batch script, version 3.3.4 @REM @REM Optional ENV vars @REM MVNW_REPOURL - repo url base for downloading maven distribution @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output @REM ---------------------------------------------------------------------------- @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) @SET __MVNW_CMD__= @SET __MVNW_ERROR__= @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% @SET PSModulePath= @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) ) @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% @SET __MVNW_PSMODULEP_SAVE= @SET __MVNW_ARG0_NAME__= @SET MVNW_USERNAME= @SET MVNW_PASSWORD= @IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) @echo Cannot start maven from wrapper >&2 && exit /b 1 @GOTO :EOF : end batch / begin powershell #> $ErrorActionPreference = "Stop" if ($env:MVNW_VERBOSE -eq "true") { $VerbosePreference = "Continue" } # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl if (!$distributionUrl) { Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" } switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { "maven-mvnd-*" { $USE_MVND = $true $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" $MVN_CMD = "mvnd.cmd" break } default { $USE_MVND = $false $MVN_CMD = $script -replace '^mvnw','mvn' break } } # apply MVNW_REPOURL and calculate MAVEN_HOME # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ if ($env:MVNW_REPOURL) { $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" } $distributionUrlName = $distributionUrl -replace '^.*/','' $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' $MAVEN_M2_PATH = "$HOME/.m2" if ($env:MAVEN_USER_HOME) { $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" } if (-not (Test-Path -Path $MAVEN_M2_PATH)) { New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null } $MAVEN_WRAPPER_DISTS = $null if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" } else { $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" } $MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" $MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" exit $? } if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" } # prepare tmp dir $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null trap { if ($TMP_DOWNLOAD_DIR.Exists) { try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } } } New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null # Download and Install Apache Maven Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." Write-Verbose "Downloading from: $distributionUrl" Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" $webclient = New-Object System.Net.WebClient if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) } [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null # If specified, validate the SHA-256 sum of the Maven distribution zip file $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum if ($distributionSha256Sum) { if ($USE_MVND) { Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." } Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." } } # unzip and move Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null # Find the actual extracted directory name (handles snapshots where filename != directory name) $actualDistributionDir = "" # First try the expected directory name (for regular distributions) $expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" $expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { $actualDistributionDir = $distributionUrlNameMain } # If not found, search for any directory with the Maven executable (for snapshots) if (!$actualDistributionDir) { Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { $testPath = Join-Path $_.FullName "bin/$MVN_CMD" if (Test-Path -Path $testPath -PathType Leaf) { $actualDistributionDir = $_.Name } } } if (!$actualDistributionDir) { Write-Error "Could not find Maven distribution directory in extracted archive" } Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null try { Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null } catch { if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { Write-Error "fail to move MAVEN_HOME" } } finally { try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } } Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" apache-opennlp-2.5.12-src/opennlp-distr/README_FOOTER.html0100644 0000000 0000000 00000001002 15217274217 023317 0ustar00rootroot0000000 0000000

How to Report Issues

The Apache OpenNLP project uses JIRA for issue tracking. Please report any issues you find at http://issues.apache.org/jira/browse/opennlp

List of JIRA Issues Fixed in this Release

Click issuesFixed/jira-report.html for the list of issues fixed in this release.

apache-opennlp-2.5.12-src/opennlp-distr/README_HEADER.html0100644 0000000 0000000 00000002627 15217274217 023267 0ustar00rootroot0000000 0000000 Apache OpenNLP Readme apache-opennlp-2.5.12-src/opennlp-distr/pom.xml0100644 0000000 0000000 00000016543 15217274217 021753 0ustar00rootroot0000000 0000000 4.0.0 org.apache.opennlp opennlp 2.5.12 ../pom.xml opennlp-distr pom Apache OpenNLP Distribution ${project.version} org.apache.opennlp opennlp-tools org.apache.opennlp opennlp-tools-models org.apache.opennlp opennlp-morfologik-addon org.apache.opennlp opennlp-uima org.apache.opennlp opennlp-docs org.slf4j slf4j-api org.apache.logging.log4j log4j-slf4j2-impl ${log4j2.version} runtime com.ruleoftech markdown-page-generator-plugin 2.5.2 process-sources generate ${basedir}/../ ${basedir}/target ${basedir}/README_HEADER.html ${basedir}/README_FOOTER.html TABLES,FENCED_CODE_BLOCKS,AUTOLINKS true maven-assembly-plugin bundle-project-sources package single src/main/assembly/bin.xml src/main/assembly/src.xml posix apache-opennlp-${project.version} maven-antrun-plugin generate checksums for binary artifacts run verify apache-release org.apache.maven.plugins maven-changes-plugin 2.12.1 default-cli generate-resources jira-report true true ${basedir}/target/issuesFixed/ 1000 docker com.spotify docker-maven-plugin 1.2.2 package build apacheopennlp ${project.basedir}/src/main/docker ${project.version} apache-opennlp-${project.version}-bin.tar.gz / ${project.build.directory} apache-opennlp-${project.version}-bin.tar.gz apache-opennlp-2.5.12-src/opennlp-distr/src/main/assembly/bin.xml0100644 0000000 0000000 00000012616 15217274217 025257 0ustar00rootroot0000000 0000000 bin tar.gz zip true /apache-opennlp-${project.version} runtime false false 644 755 lib true src/main/readme 644 755 . src/main/resources 644 755 conf log4j2.xml . true 644 755 RELEASE_NOTES.html target 644 755 . README.html target/issuesFixed 644 755 issuesFixed src/main/bin 755 755 bin ../opennlp-morfologik-addon/src/main/bin 755 755 bin ../opennlp-tools/lang 644 755 lang ../opennlp-docs/target/docbkx/html 644 755 docs/manual ../opennlp-docs/target/docbkx/pdf 644 755 *.pdf docs ../opennlp-docs/target/docbkx 644 755 *.epub docs ../opennlp-tools/target/reports/apidocs 644 755 docs/apidocs/opennlp-tools ../opennlp-tools-models/target/reports/apidocs 644 755 docs/apidocs/opennlp-tools-models ../opennlp-dl/target/reports/apidocs 644 755 docs/apidocs/opennlp-dl ../opennlp-morfologik-addon/target/reports/apidocs 644 755 docs/apidocs/opennlp-morfologik-addon ../opennlp-uima/target/reports/apidocs 644 755 docs/apidocs/opennlp-uima ../opennlp-uima/descriptors true 644 755 docs/opennlp-uima-descriptors apache-opennlp-2.5.12-src/opennlp-distr/src/main/assembly/src.xml0100644 0000000 0000000 00000003113 15217274217 025266 0ustar00rootroot0000000 0000000 src tar.gz zip /apache-opennlp-${project.version}-src ../ **/target/** **/.*/** **/pom.xml.releaseBackup **/release.properties ../.mvn .mvn apache-opennlp-2.5.12-src/opennlp-distr/src/main/bin/opennlp0100755 0000000 0000000 00000003401 15217274217 024307 0ustar00rootroot0000000 0000000 #!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # Note: Do not output anything in this script file, any output # may be inadvertantly placed in any output files if # output redirection is used. # determine OPENNLP_HOME - $0 may be a symlink to OpenNLP's home PRG="$0" while [ -h "$PRG" ] ; do ls=$(ls -ld "$PRG") link=$(expr "$ls" : '.*-> \(.*\)$') if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG="$(dirname "$PRG")/$link" fi done saveddir=$(pwd) OPENNLP_HOME=$(dirname "$PRG")/.. # make it fully qualified OPENNLP_HOME=$(cd "$OPENNLP_HOME" && pwd) cd "$saveddir" || exit if [ -z "$JAVACMD" ] ; then if [ -n "$JAVA_HOME" ] ; then JAVACMD="$JAVA_HOME/bin/java" else JAVACMD="$(which java)" fi fi CLASSPATH=$(echo "$OPENNLP_HOME"/lib/*.jar | tr ' ' ':') unset HEAP if [ -n "$JAVA_HEAP" ] ; then HEAP="-Xmx$JAVA_HEAP" fi $JAVACMD $HEAP -Dlog4j.configurationFile="$OPENNLP_HOME/conf/log4j2.xml" -cp "$CLASSPATH" opennlp.tools.cmdline.CLI "$@" apache-opennlp-2.5.12-src/opennlp-distr/src/main/bin/opennlp.bat0100644 0000000 0000000 00000003515 15217274217 025057 0ustar00rootroot0000000 0000000 @ECHO off REM # Licensed to the Apache Software Foundation (ASF) under one REM # or more contributor license agreements. See the NOTICE file REM # distributed with this work for additional information REM # regarding copyright ownership. The ASF licenses this file REM # to you under the Apache License, Version 2.0 (the REM # "License"); you may not use this file except in compliance REM # with the License. You may obtain a copy of the License at REM # REM # http://www.apache.org/licenses/LICENSE-2.0 REM # REM # Unless required by applicable law or agreed to in writing, REM # software distributed under the License is distributed on an REM # # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY REM # KIND, either express or implied. See the License for the REM # specific language governing permissions and limitations REM # under the License. REM # Note: Do not output anything in this script file, any output REM # may be inadvertantly placed in any output files if REM # output redirection is used. SETLOCAL IF "%JAVA_CMD%" == "" ( IF "%JAVA_HOME%" == "" ( SET JAVA_CMD=java ) ELSE ( REM # Keep JAVA_HOME to short-name without spaces FOR %%A IN ("%JAVA_HOME%") DO SET JAVA_CMD=%%~sfA\bin\java ) ) REM remove HEAP variable SET HEAP= IF not "%JAVA_HEAP%" == "" ( SET HEAP="-Xmx%JAVA_HEAP%" ) REM # Should work with Windows XP and greater. If not, specify the path to where it is installed. IF "%OPENNLP_HOME%" == "" ( SET OPENNLP_HOME=%~sp0.. ) ELSE ( REM # Keep OPENNLP_HOME to short-name without spaces FOR %%A IN ("%OPENNLP_HOME%") DO SET OPENNLP_HOME=%%~sfA ) SET CLASSPATH="%OPENNLP_HOME%\lib\*" %JAVA_CMD% %HEAP% "-Dlog4j.configurationFile=%OPENNLP_HOME%\conf\log4j2.xml" -cp %CLASSPATH% opennlp.tools.cmdline.CLI %* ENDLOCAL apache-opennlp-2.5.12-src/opennlp-distr/src/main/docker/Dockerfile0100644 0000000 0000000 00000000264 15217274217 025403 0ustar00rootroot0000000 0000000 FROM openjdk:17-alpine MAINTAINER Apache OpenNLP (dev@opennlp.apache.org) ARG OPENNLP_BINARY ENV OPENNLP_BASE_DIR /opt/opennlp ADD $OPENNLP_BINARY $OPENNLP_BASE_DIR CMD ["sh"] apache-opennlp-2.5.12-src/opennlp-distr/src/main/readme/LICENSE0100644 0000000 0000000 00000100213 15217274217 024377 0ustar00rootroot0000000 0000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. The following license applies to the Snowball stemmers: Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF The CDDL 1.1 license applies to jersey and some of its dependencies: COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)Version 1.1 1. Definitions. 1.1. “Contributor� means each individual or entity that creates or contributes to the creation of Modifications. 1.2. “Contributor Version� means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. “Covered Software� means (a) the Original Software, or (b) Modifications or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. “Executable� means the Covered Software in any form other than Source Code. 1.5. “Initial Developer� means the individual or entity that first makes Original Software available under this License. 1.6. “Larger Work� means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. “License� means this document. 1.8. “Licensable� means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. “Modifications� means the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. “Original Software� means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. “Patent Claims� means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.12. “Source Code� means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. “You� (or “Your�) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You� includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control� means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients' rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient's rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.6. Larger Works. You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. 4. Versions of the License. 4.1. New Versions. Oracle is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS� BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant�) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 8. U.S. GOVERNMENT END USERS. The Covered Software is a “commercial item,� as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software� (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation� as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction's conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California. The BSD 2-clause license applies to the morfologik dependencies: Copyright (c) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.apache-opennlp-2.5.12-src/opennlp-distr/src/main/readme/NOTICE0100644 0000000 0000000 00000006744 15217274217 024314 0ustar00rootroot0000000 0000000 Apache OpenNLP Copyright 2021-2026 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). ============================================================================ The snowball stemmers in opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball were developed by Martin Porter and Richard Boulton. The full snowball package is available from http://snowball.tartarus.org/ ============================================================================ The Wordpiece tokenizer in opennlp-tools/main/java/opennlp/tools/tokenize is taken from https://github.com/robrua/easy-bert licensed under The MIT License (MIT) Copyright (c) 2019 Rob Rua Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================ List of third-party dependencies grouped by their license type. Apache License, Version 2.0 * Apache Log4j API (org.apache.logging.log4j:log4j-api:2.26.1 - https://logging.apache.org/log4j/2.x/) * Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.26.1 - https://logging.apache.org/log4j/2.x/) * Apache UIMA Base: uimaj-core (org.apache.uima:uimaj-core:3.6.1 - https://uima.apache.org) * HPPC Collections (com.carrotsearch:hppc:0.7.2 - http://labs.carrotsearch.com/hppc.html/hppc) * jcommander (com.beust:jcommander:1.78 - https://jcommander.org) * SLF4J 2 Provider for Log4j API (org.apache.logging.log4j:log4j-slf4j2-impl:2.26.1 - https://logging.apache.org/log4j/2.x/) BSD License * Morfologik Command Line Tools (org.carrot2:morfologik-tools:2.2.0 - http://morfologik.blogspot.com/morfologik-tools/) * Morfologik FSA (Builder) (org.carrot2:morfologik-fsa-builders:2.2.0 - http://morfologik.blogspot.com/morfologik-fsa-builders/) * Morfologik FSA (Traversal) (org.carrot2:morfologik-fsa:2.2.0 - http://morfologik.blogspot.com/morfologik-fsa/) * Morfologik Stemming APIs (org.carrot2:morfologik-stemming:2.2.0 - http://morfologik.blogspot.com/morfologik-stemming/) MIT License * onnx-runtime (com.microsoft.onnxruntime:onnxruntime_gpu:1.29.0 - https://microsoft.github.io/onnxruntime/) * onnx-runtime (com.microsoft.onnxruntime:onnxruntime:1.29.0 - https://microsoft.github.io/onnxruntime/) * SLF4J API Module (org.slf4j:slf4j-api:2.0.18 - http://www.slf4j.org) The MIT License (MIT) * ClassGraph (io.github.classgraph:classgraph:4.8.194 - https://github.com/classgraph/classgraph) apache-opennlp-2.5.12-src/opennlp-distr/src/main/resources/log4j2.xml0100644 0000000 0000000 00000002412 15217274217 025774 0ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-distr/src/test/ps/test_opennlp.Tests.ps10100644 0000000 0000000 00000004557 15217274217 027070 0ustar00rootroot0000000 0000000 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. Describe "opennlp.bat Tests" { # Setup before all tests BeforeAll { # Ensure OPENNLP_HOME is added to PATH if (-not $env:OPENNLP_HOME) { Throw "OPENNLP_HOME environment variable is not set." } # Add the OPENNLP_HOME\bin directory to the PATH so opennlp.bat can be found $env:PATH = "$env:OPENNLP_HOME\bin;$env:PATH" } # Test if opennlp.bat is accessible and executable It "opennlp.bat exists and is executable" { $batFile = Join-Path $env:OPENNLP_HOME "bin\opennlp.bat" # Ensure the .bat file exists $batFile | Should -Exist # Check if the bat file runs by executing it with a help flag $result = & $batFile -h # Validate the result isn't null or empty $result | Should -Not -BeNullOrEmpty } # Test the output of SimpleTokenizer It "SimpleTokenizer produces correct output" { $input = "Hello, friends" $expected_output = "Hello , friends" # Run the opennlp.bat with SimpleTokenizer, using input redirection via echo $output = echo $input | & "$env:OPENNLP_HOME\bin\opennlp.bat" SimpleTokenizer # Debugging: Log the output Write-Host "Output: $output" # Validate the command executed successfully $output | Should -Not -BeNullOrEmpty # Check if the expected output is in the result $output | Should -Contain $expected_output } # Cleanup after tests AfterAll { # Remove OPENNLP_HOME from PATH after tests are done Remove-Item Env:\PATH -ErrorAction SilentlyContinue } } apache-opennlp-2.5.12-src/opennlp-distr/src/test/sh/test_opennlp.bats0100644 0000000 0000000 00000003321 15217274217 026171 0ustar00rootroot0000000 0000000 #!/usr/bin/env bats # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Setup the environment before running the tests setup() { PATH="$OPENNLP_HOME/bin:$PATH" } # Test to check if the binary is accessible @test "Binary 'opennlp' exists and is executable" { run command -v opennlp [ "$status" -eq 0 ] [ -x "$output" ] } # Test to validate the output of the SimpleTokenizer @test "SimpleTokenizer produces correct output" { input="Hello, friends" expected_output="Hello , friends" # Run the command and capture output run echo "$input" | opennlp SimpleTokenizer # Debugging: Log the status and output echo "Status: $status" echo "Output: $output" # Validate the command executed successfully [ "$status" -eq 0 ] || echo "Error: opennlp SimpleTokenizer failed" # Validate the output matches the expected result [ "${output}" = "$expected_output" ] || echo "Unexpected output: ${output}" } # Teardown the environment after running the tests teardown() { unset OPENNLP_HOME } apache-opennlp-2.5.12-src/opennlp-dl/README.md0100644 0000000 0000000 00000003003 15217274217 021152 0ustar00rootroot0000000 0000000 # OpenNLP DL This module provides OpenNLP interface implementations for ONNX models using the `onnxruntime` dependency. **Important**: This does not provide the ability to train models. Model training is done outside of OpenNLP. This code provides the ability to use ONNX models from OpenNLP. Models used in the tests are available in the [opennlp evaluation test data](https://nightlies.apache.org/opennlp/opennlp-data.zip) location. ## NameFinderDL Export a Huggingface NER model to ONNX, e.g.: ```bash python -m transformers.onnx --model=dslim/bert-base-NER --feature token-classification exported ``` ## DocumentCategorizerDL Export a Huggingface classification (e.g. sentiment) model to ONNX, e.g.: ```bash python -m transformers.onnx --model=nlptown/bert-base-multilingual-uncased-sentiment --feature sequence-classification exported ``` ## SentenceVectors Convert a sentence vectors model to ONNX, e.g.: Install dependencies: ```bash python3 -m pip install optimum onnx onnxruntime ``` Convert the model: ```python from optimum.onnxruntime import ORTModelForFeatureExtraction from transformers import AutoTokenizer from pathlib import Path model_id="sentence-transformers/all-MiniLM-L6-v2" onnx_path = Path("onnx") # load vanilla transformers and convert to onnx model = ORTModelForFeatureExtraction.from_pretrained(model_id, from_transformers=True) tokenizer = AutoTokenizer.from_pretrained(model_id) # save onnx checkpoint and tokenizer model.save_pretrained(onnx_path) tokenizer.save_pretrained(onnx_path) ``` apache-opennlp-2.5.12-src/opennlp-dl/pom.xml0100644 0000000 0000000 00000005165 15217274217 021223 0ustar00rootroot0000000 0000000 4.0.0 org.apache.opennlp opennlp 2.5.12 ../pom.xml org.apache.opennlp opennlp-dl Apache OpenNLP DL org.apache.opennlp opennlp-tools ${project.version} com.microsoft.onnxruntime onnxruntime ${onnxruntime.version} org.slf4j slf4j-api org.junit.jupiter junit-jupiter-api test org.junit.jupiter junit-jupiter-engine test org.slf4j slf4j-simple test org.apache.maven.plugins maven-jar-plugin test-jar apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/AbstractDL.java0100644 0000000 0000000 00000011656 15217274217 027244 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import ai.onnxruntime.OrtEnvironment; import ai.onnxruntime.OrtException; import ai.onnxruntime.OrtSession; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.tokenize.WordpieceTokenizer; /** * Base class for OpenNLP deep-learning classes using ONNX Runtime. */ public abstract class AbstractDL implements AutoCloseable { public static final String INPUT_IDS = "input_ids"; public static final String ATTENTION_MASK = "attention_mask"; public static final String TOKEN_TYPE_IDS = "token_type_ids"; protected OrtEnvironment env; protected OrtSession session; protected Tokenizer tokenizer; protected Map vocab; private static final Pattern JSON_ENTRY_PATTERN = Pattern.compile("\"((?:[^\"\\\\]|\\\\.)*)\"\\s*:\\s*(\\d+)"); /** * Loads a vocabulary {@link File} from disk. * Supports both plain text files (one token per * line) and JSON files mapping tokens to integer * IDs. * * @param vocabFile The vocabulary file. * @return A map of vocabulary words to IDs. * @throws IOException Thrown if the vocabulary * file cannot be opened or read. */ public Map loadVocab( final File vocabFile) throws IOException { final Path vocabPath = Path.of(vocabFile.getPath()); final String content = Files.readString( vocabPath, StandardCharsets.UTF_8); final String trimmed = content.trim(); // Detect JSON format by leading brace if (trimmed.startsWith("{")) { return loadJsonVocab(trimmed); } final Map vocab = new HashMap<>(); final AtomicInteger counter = new AtomicInteger(0); try (Stream lines = Files.lines( vocabPath, StandardCharsets.UTF_8)) { lines.forEach(line -> vocab.put(line, counter.getAndIncrement()) ); } return vocab; } /** * Creates a {@link WordpieceTokenizer} that uses the * appropriate special tokens based on the vocabulary. * If the vocabulary contains RoBERTa-style tokens, * those are used. Otherwise, the BERT defaults are * used. * * @param vocab The vocabulary map. * @return A configured {@link WordpieceTokenizer}. */ protected WordpieceTokenizer createTokenizer( final Map vocab) { if (vocab.containsKey( WordpieceTokenizer.ROBERTA_CLS_TOKEN) && vocab.containsKey( WordpieceTokenizer.ROBERTA_SEP_TOKEN)) { final String unk = vocab.containsKey( WordpieceTokenizer.ROBERTA_UNK_TOKEN) ? WordpieceTokenizer.ROBERTA_UNK_TOKEN : WordpieceTokenizer.BERT_UNK_TOKEN; return new WordpieceTokenizer( vocab.keySet(), WordpieceTokenizer.ROBERTA_CLS_TOKEN, WordpieceTokenizer.ROBERTA_SEP_TOKEN, unk); } return new WordpieceTokenizer(vocab.keySet()); } private Map loadJsonVocab(final String json) { final Map vocab = new HashMap<>(); final Matcher matcher = JSON_ENTRY_PATTERN.matcher(json); while (matcher.find()) { final String token = matcher.group(1) .replace("\\\"", "\"") .replace("\\\\", "\\") .replace("\\/", "/") .replace("\\n", "\n") .replace("\\t", "\t"); final int id = Integer.parseInt(matcher.group(2)); vocab.put(token, id); } return vocab; } /** * Closes this resource, relinquishing any underlying resources. * * @throws OrtException Thrown if it failed to close Ort resources. * @throws IllegalStateException Thrown if the underlying resources were already closed. */ @Override public void close() throws OrtException, IllegalStateException { if (session != null) { session.close(); } if (env != null) { env.close(); } } } apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/InferenceOptions.java0100644 0000000 0000000 00000004111 15217274217 030517 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl; public class InferenceOptions { private boolean includeAttentionMask = true; private boolean includeTokenTypeIds = true; private boolean gpu; private int gpuDeviceId = 0; private int documentSplitSize = 250; private int splitOverlapSize = 50; public boolean isIncludeAttentionMask() { return includeAttentionMask; } public void setIncludeAttentionMask(boolean includeAttentionMask) { this.includeAttentionMask = includeAttentionMask; } public boolean isIncludeTokenTypeIds() { return includeTokenTypeIds; } public void setIncludeTokenTypeIds(boolean includeTokenTypeIds) { this.includeTokenTypeIds = includeTokenTypeIds; } public boolean isGpu() { return gpu; } public void setGpu(boolean gpu) { this.gpu = gpu; } public int getGpuDeviceId() { return gpuDeviceId; } public void setGpuDeviceId(int gpuDeviceId) { this.gpuDeviceId = gpuDeviceId; } public int getDocumentSplitSize() { return documentSplitSize; } public void setDocumentSplitSize(int documentSplitSize) { this.documentSplitSize = documentSplitSize; } public int getSplitOverlapSize() { return splitOverlapSize; } public void setSplitOverlapSize(int splitOverlapSize) { this.splitOverlapSize = splitOverlapSize; } } apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/SpanEnd.java0100644 0000000 0000000 00000001736 15217274217 026607 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl; public record SpanEnd(int index, int characterEnd) { @Override public String toString() { return "index: " + index + "; character end: " + characterEnd; } } apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/Tokens.java0100644 0000000 0000000 00000002225 15217274217 026514 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl; /** * Holds the tokens for input to an ONNX model. * * @param tokens The tokens themselves. * @param ids The token IDs as retrieved from the vocabulary. * @param mask The token mask. (Typically all 1.) * @param types The token types. (Typically all 1.) */ public record Tokens(String[] tokens, long[] ids, long[] mask, long[] types) { } apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerConfig.java0100644 0000000 0000000 00000004016 15217274217 033611 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; public record DocumentCategorizerConfig(Map id2label) { private static final Pattern ID_TO_LABEL_PATTERN = Pattern.compile("\"id2label\"\\s*:\\s*\\{(.*?)\\}", Pattern.DOTALL); private static final Pattern ENTRY_PATTERN = Pattern.compile("\"([^\"]+)\"\\s*:\\s*\"(.*?)\""); @Override public Map id2label() { return Collections.unmodifiableMap(id2label); } public static DocumentCategorizerConfig fromJson(String json) { Objects.requireNonNull(json, "json must not be null"); final Map id2label = new HashMap<>(); final Matcher matcher = ID_TO_LABEL_PATTERN.matcher(json); if (matcher.find()) { final String id2labelContent = matcher.group(1); final Matcher entryMatcher = ENTRY_PATTERN.matcher(id2labelContent); while (entryMatcher.find()) { final String key = entryMatcher.group(1); final String value = entryMatcher.group(2); id2label.put(key, value); } } return new DocumentCategorizerConfig(id2label); } } apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerDL.java0100644 0000000 0000000 00000031422 15217274217 032704 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat; import java.io.File; import java.io.IOException; import java.nio.LongBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.stream.IntStream; import ai.onnxruntime.OnnxTensor; import ai.onnxruntime.OrtEnvironment; import ai.onnxruntime.OrtException; import ai.onnxruntime.OrtSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.dl.AbstractDL; import opennlp.dl.InferenceOptions; import opennlp.dl.Tokens; import opennlp.dl.doccat.scoring.ClassificationScoringStrategy; import opennlp.tools.doccat.DocumentCategorizer; /** * An implementation of {@link DocumentCategorizer} that performs document classification * using ONNX models. * * @see DocumentCategorizer * @see InferenceOptions * @see ClassificationScoringStrategy */ public class DocumentCategorizerDL extends AbstractDL implements DocumentCategorizer { private static final Logger logger = LoggerFactory.getLogger(DocumentCategorizerDL.class); private final Map categories; private final ClassificationScoringStrategy classificationScoringStrategy; private final InferenceOptions inferenceOptions; /** * Instantiates a {@link DocumentCategorizer document categorizer} using ONNX models. * * @param model The ONNX model file. * @param vocabulary The model file's vocabulary file. * @param categories The categories. * @param classificationScoringStrategy Implementation of {@link ClassificationScoringStrategy} used * to calculate the classification scores given the score of each * individual document part. * @param inferenceOptions {@link InferenceOptions} to control the inference. * @throws OrtException Thrown if the {@code model} cannot be loaded. * @throws IOException Thrown if errors occurred loading the {@code model} or {@code vocabulary}. */ public DocumentCategorizerDL(File model, File vocabulary, Map categories, ClassificationScoringStrategy classificationScoringStrategy, InferenceOptions inferenceOptions) throws IOException, OrtException { this.env = OrtEnvironment.getEnvironment(); final OrtSession.SessionOptions sessionOptions = new OrtSession.SessionOptions(); if (inferenceOptions.isGpu()) { sessionOptions.addCUDA(inferenceOptions.getGpuDeviceId()); } this.session = env.createSession(model.getPath(), sessionOptions); this.vocab = loadVocab(vocabulary); this.tokenizer = createTokenizer(vocab); this.categories = categories; this.classificationScoringStrategy = classificationScoringStrategy; this.inferenceOptions = inferenceOptions; } /** * Instantiates a {@link DocumentCategorizer document categorizer} using ONNX models. * * @param model The ONNX model file. * @param vocabulary The model file's vocabulary file. * @param config The model's config file. The file will be used to * determine the classification categories. * @param classificationScoringStrategy Implementation of {@link ClassificationScoringStrategy} used * to calculate the classification scores given the score of each * individual document part. * @param inferenceOptions {@link InferenceOptions} to control the inference. * @throws OrtException Thrown if the {@code model} cannot be loaded. * @throws IOException Thrown if errors occurred loading the {@code model} or {@code vocabulary}. */ public DocumentCategorizerDL(File model, File vocabulary, File config, ClassificationScoringStrategy classificationScoringStrategy, InferenceOptions inferenceOptions) throws IOException, OrtException { this.env = OrtEnvironment.getEnvironment(); final OrtSession.SessionOptions sessionOptions = new OrtSession.SessionOptions(); if (inferenceOptions.isGpu()) { sessionOptions.addCUDA(inferenceOptions.getGpuDeviceId()); } this.session = env.createSession(model.getPath(), sessionOptions); this.vocab = loadVocab(vocabulary); this.tokenizer = createTokenizer(vocab); this.categories = readCategoriesFromFile(config); this.classificationScoringStrategy = classificationScoringStrategy; this.inferenceOptions = inferenceOptions; } @Override public double[] categorize(String[] strings) { try { final List tokens = tokenize(strings[0]); final List scores = new LinkedList<>(); for (final Tokens t : tokens) { final Map inputs = new HashMap<>(); final Object output; try { inputs.put(INPUT_IDS, OnnxTensor.createTensor(env, LongBuffer.wrap(t.ids()), new long[] {1, t.ids().length})); if (inferenceOptions.isIncludeAttentionMask()) { inputs.put(ATTENTION_MASK, OnnxTensor.createTensor(env, LongBuffer.wrap(t.mask()), new long[] {1, t.mask().length})); } if (inferenceOptions.isIncludeTokenTypeIds()) { inputs.put(TOKEN_TYPE_IDS, OnnxTensor.createTensor(env, LongBuffer.wrap(t.types()), new long[] {1, t.types().length})); } // The outputs from the model. Some models return a 2D array (e.g. BERT), // while others return a 1D array (e.g. RoBERTa). try (OrtSession.Result result = session.run(inputs)) { // getValue() copies the tensor into Java arrays, so the result can be closed safely. output = result.get(0).getValue(); } } finally { inputs.values().forEach(OnnxTensor::close); } final float[] rawScores; if (output instanceof float[][] v) { rawScores = v[0]; } else if (output instanceof float[] v) { rawScores = v; } else { throw new IllegalStateException( "Unexpected model output type: " + output.getClass().getName()); } // Keep track of all scores. final double[] categoryScoresForTokens = softmax(rawScores); scores.add(categoryScoresForTokens); } return classificationScoringStrategy.score(scores); } catch (Exception ex) { logger.error("Unload to perform document classification inference", ex); } return new double[] {}; } @Override public double[] categorize(String[] strings, Map map) { return categorize(strings); } @Override public String getBestCategory(double[] doubles) { return categories.get(maxIndex(doubles)); } @Override public int getIndex(String s) { return getKey(s); } @Override public String getCategory(int i) { return categories.get(i); } @Override public int getNumberOfCategories() { return categories.size(); } @Override public String getAllResults(double[] doubles) { return null; } @Override public Map scoreMap(String[] strings) { final double[] scores = categorize(strings); final Map scoreMap = new HashMap<>(); for (int x : categories.keySet()) { scoreMap.put(categories.get(x), scores[x]); } return scoreMap; } @Override public SortedMap> sortedScoreMap(String[] strings) { final double[] scores = categorize(strings); final SortedMap> scoreMap = new TreeMap<>(); for (int x : categories.keySet()) { if (scoreMap.get(scores[x]) == null) { scoreMap.put(scores[x], new HashSet<>()); } scoreMap.get(scores[x]).add(categories.get(x)); } return scoreMap; } private int getKey(String value) { for (Map.Entry entry : categories.entrySet()) { if (entry.getValue().equals(value)) { return entry.getKey(); } } // The String wasn't found as a value in the map. return -1; } private List tokenize(final String text) { final List t = new LinkedList<>(); // In this article as the paper suggests, we are going to segment the input into smaller text and feed // each of them into BERT, it means for each row, we will split the text in order to have some // smaller text (200 words long each) // https://medium.com/analytics-vidhya/text-classification-with-bert-using-transformers-for-long-text-inputs-f54833994dfd // Split the input text into 200 word chunks with 50 overlapping between chunks. final String[] whitespaceTokenized = text.split("\\s+"); for (int start = 0; start < whitespaceTokenized.length; start = start + inferenceOptions.getDocumentSplitSize()) { // 200 word length chunk // Check the end do don't go past and get a StringIndexOutOfBoundsException int end = start + inferenceOptions.getDocumentSplitSize(); if (end > whitespaceTokenized.length) { end = whitespaceTokenized.length; } // The group is that subsection of string. final String group = String.join(" ", Arrays.copyOfRange(whitespaceTokenized, start, end)); // We want to overlap each chunk by 50 words so scoot back 50 words for the next iteration. start = start - inferenceOptions.getSplitOverlapSize(); // Now we can tokenize the group and continue. final String[] tokens = tokenizer.tokenize(group); final long[] ids = tokenIds(tokens, vocab); final long[] mask = new long[ids.length]; Arrays.fill(mask, 1); final long[] types = new long[ids.length]; Arrays.fill(types, 0); t.add(new Tokens(tokens, ids, mask, types)); } return t; } /** * Maps tokens to their vocabulary ids. * * @param tokens The tokens to map. * @param vocab The vocabulary map. * @return The token ids. * * @throws IllegalArgumentException Thrown if a token is not present in the * vocabulary. */ static long[] tokenIds(final String[] tokens, final Map vocab) { final long[] ids = new long[tokens.length]; for (int x = 0; x < tokens.length; x++) { final Integer id = vocab.get(tokens[x]); if (id == null) { throw new IllegalArgumentException("Token '" + tokens[x] + "' is not present in the vocabulary; the vocabulary file does not match the model."); } ids[x] = id; } return ids; } /** * Applies softmax to an array of values. * * @param input An array of values. * @return The output array. */ private double[] softmax(final float[] input) { final double[] t = new double[input.length]; double sum = 0.0; for (int x = 0; x < input.length; x++) { double val = Math.exp(input[x]); sum += val; t[x] = val; } final double[] output = new double[input.length]; for (int x = 0; x < output.length; x++) { output[x] = (float) (t[x] / sum); } return output; } private int maxIndex(double[] arr) { return IntStream.range(0, arr.length) .reduce((i, j) -> arr[i] > arr[j] ? i : j) .orElse(-1); } private Map readCategoriesFromFile(File config) throws IOException { final DocumentCategorizerConfig documentCategorizerConfig = DocumentCategorizerConfig.fromJson(Files.readString(config.toPath(), StandardCharsets.UTF_8)); final Map categories = new HashMap<>(); for (final String key : documentCategorizerConfig.id2label().keySet()) { categories.put(Integer.valueOf(key), documentCategorizerConfig.id2label().get(key)); } return categories; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-dl_src_main_java_opennlp_dl_doccat_scoring_Average0100644 0000000 0000000 00000000200 15217274217 032342 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/scoring/AverageClassificationScoringStrategy.java apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/scoring/AverageClassificationSc0100644 0000000 0000000 00000003035 15217274217 033746 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat.scoring; import java.util.List; /** * A {@link ClassificationScoringStrategy} which calculates the document classification scores * by averaging the scores for all individual parts of a document. * * @see ClassificationScoringStrategy */ public class AverageClassificationScoringStrategy implements ClassificationScoringStrategy { @Override public double[] score(List scores) { final int values = scores.get(0).length; final double[] averages = new double[values]; int j = 0; for (int i = 0; i < values; i++) { double sum = 0; for (final double[] score : scores) { sum += score[i]; } averages[j++] = (sum / scores.size()); } return averages; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-dl_src_main_java_opennlp_dl_doccat_scoring_Classif0100644 0000000 0000000 00000000171 15217274217 032363 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/scoring/ClassificationScoringStrategy.java apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/doccat/scoring/ClassificationScoringSt0100644 0000000 0000000 00000002653 15217274217 034026 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat.scoring; import java.util.List; /** * Used to determine the scores of document classification. During classification, * documents are separated into smaller parts. The classification is run on each part. * Implementations of this interface are used to determine the score from the scores * of each individual part. */ public interface ClassificationScoringStrategy { /** * Calculate the final scores based on the scores of the individual document parts. * @param scores The scores for each individual part of the document. * @return The calculated scores. */ double[] score(List scores); } apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/namefinder/NameFinderDL.java0100644 0000000 0000000 00000034755 15217274217 031626 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.namefinder; import java.io.File; import java.io.IOException; import java.nio.LongBuffer; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import ai.onnxruntime.OnnxTensor; import ai.onnxruntime.OrtEnvironment; import ai.onnxruntime.OrtException; import ai.onnxruntime.OrtSession; import opennlp.dl.AbstractDL; import opennlp.dl.InferenceOptions; import opennlp.dl.SpanEnd; import opennlp.dl.Tokens; import opennlp.tools.namefind.TokenNameFinder; import opennlp.tools.sentdetect.SentenceDetector; import opennlp.tools.util.Span; /** * An implementation of {@link TokenNameFinder} that uses ONNX models. * * @see TokenNameFinder * @see InferenceOptions */ public class NameFinderDL extends AbstractDL implements TokenNameFinder { public static final String I_PER = "I-PER"; public static final String B_PER = "B-PER"; public static final String SEPARATOR = "[SEP]"; private static final String CHARS_TO_REPLACE = "##"; private final SentenceDetector sentenceDetector; private final Map ids2Labels; private final InferenceOptions inferenceOptions; /** * Instantiates a {@link TokenNameFinder name finder} using ONNX models. * * @param model The ONNX model file. * @param vocabulary The model file's vocabulary file. * @param ids2Labels The mapping of ids to labels. * @param sentenceDetector The {@link SentenceDetector} to be used. * * @throws OrtException Thrown if the {@code model} cannot be loaded. * @throws IOException Thrown if errors occurred loading the {@code model} or {@code vocabulary}. */ public NameFinderDL(File model, File vocabulary, Map ids2Labels, SentenceDetector sentenceDetector) throws IOException, OrtException { this(model, vocabulary, ids2Labels, new InferenceOptions(), sentenceDetector); } /** * Instantiates a {@link TokenNameFinder name finder} using ONNX models. * * @param model The ONNX model file. * @param vocabulary The model file's vocabulary file. * @param ids2Labels The mapping of ids to labels. * @param inferenceOptions {@link InferenceOptions} to control the inference. * @param sentenceDetector The {@link SentenceDetector} to be used. * * @throws OrtException Thrown if the {@code model} cannot be loaded. * @throws IOException Thrown if errors occurred loading the {@code model} or {@code vocabulary}. */ public NameFinderDL(File model, File vocabulary, Map ids2Labels, InferenceOptions inferenceOptions, SentenceDetector sentenceDetector) throws IOException, OrtException { this.env = OrtEnvironment.getEnvironment(); final OrtSession.SessionOptions sessionOptions = new OrtSession.SessionOptions(); if (inferenceOptions.isGpu()) { sessionOptions.addCUDA(inferenceOptions.getGpuDeviceId()); } this.session = env.createSession(model.getPath(), sessionOptions); this.ids2Labels = ids2Labels; this.vocab = loadVocab(vocabulary); this.tokenizer = createTokenizer(vocab); this.inferenceOptions = inferenceOptions; this.sentenceDetector = sentenceDetector; } @Override public Span[] find(String[] input) { final List spans = new LinkedList<>(); // Join the tokens here because they will be tokenized using Wordpiece during inference. final String text = String.join(" ", input); final String[] sentences = sentenceDetector.sentDetect(text); for (String sentence : sentences) { // The WordPiece tokenized text. This changes the spacing in the text. final List wordpieceTokens = tokenize(sentence); for (final Tokens tokens : wordpieceTokens) { try { // The inputs to the ONNX model. final Map inputs = new HashMap<>(); final float[][][] v; try { inputs.put(INPUT_IDS, OnnxTensor.createTensor(env, LongBuffer.wrap(tokens.ids()), new long[] {1, tokens.ids().length})); if (inferenceOptions.isIncludeAttentionMask()) { inputs.put(ATTENTION_MASK, OnnxTensor.createTensor(env, LongBuffer.wrap(tokens.mask()), new long[] {1, tokens.mask().length})); } if (inferenceOptions.isIncludeTokenTypeIds()) { inputs.put(TOKEN_TYPE_IDS, OnnxTensor.createTensor(env, LongBuffer.wrap(tokens.types()), new long[] {1, tokens.types().length})); } // The outputs from the model. try (OrtSession.Result result = session.run(inputs)) { // getValue() copies the tensor into Java arrays, so the result can be closed safely. v = (float[][][]) result.get(0).getValue(); } } finally { inputs.values().forEach(OnnxTensor::close); } // Find consecutive B-PER and I-PER labels and combine the spans where necessary. // There are also B-LOC and I-LOC tags for locations that might be useful at some point. // Keep track of where the last span was so when there are multiple/duplicate // spans we can get the next one instead of the first one each time. int characterStart = 0; final String[] toks = tokens.tokens(); // We are looping over the vector for each word, // finding the index of the array that has the maximum value, // and then finding the token classification that corresponds to that index. for (int x = 0; x < v[0].length; x++) { final float[] arr = v[0][x]; final int maxIndex = maxIndex(arr); final String label = ids2Labels.get(maxIndex); // TODO: Need to make sure this value is between 0 and 1? // Can we do thresholding without it between 0 and 1? final double confidence = arr[maxIndex]; // / 10; // Is this is the start of a person entity. if (B_PER.equals(label)) { String spanText; // Find the end index of the span in the array (where the label is not I-PER). final SpanEnd spanEnd = findSpanEnd(v, x, ids2Labels, toks); // If the end is -1 it means this is a single-span token. // If the end is != -1 it means this is a multi-span token. if (spanEnd.index() != -1) { final StringBuilder sb = new StringBuilder(); // We have to concatenate the tokens. // Add each token in the array and separate them with a space. // We'll separate each with a single space because later we'll find the original span // in the text and ignore spacing between individual tokens in findByRegex(). int end = spanEnd.index(); for (int i = x; i <= end; i++) { // If the next token starts with ##, combine it with this token. if (toks[i + 1].startsWith(CHARS_TO_REPLACE)) { sb.append(toks[i]).append(toks[i + 1].replace(CHARS_TO_REPLACE, "")); // Append a space unless the next (next) token starts with ##. if (!toks[i + 2].startsWith(CHARS_TO_REPLACE)) { sb.append(" "); } // Skip the next token since we just included it in this iteration. i++; } else { sb.append(toks[i].replace(CHARS_TO_REPLACE, "")); // Append a space unless the next token is a period. if (!".".equals(toks[i + 1])) { sb.append(" "); } } } // This is the text of the span. We use the whole original input text and not one // of the splits. This gives us accurate character positions. spanText = findByRegex(text, sb.toString().trim()).trim(); } else { // This is a single-token span so there is nothing else to do except grab the token. spanText = toks[x]; } if (!SEPARATOR.equals(spanText)) { spanText = spanText.replace(CHARS_TO_REPLACE, ""); // This ignores other potential matches in the same sentence // by only taking the first occurrence. characterStart = text.indexOf(spanText, characterStart); // TODO: This check should not be needed because the span was found. // If we aren't finding it now it's because there's a whitespace difference. if (characterStart != -1) { final int characterEnd = characterStart + spanText.length(); spans.add(new Span(characterStart, characterEnd, spanText, confidence)); // OP-1: Only increment characterStart by one. characterStart++; } } } } } catch (OrtException ex) { throw new RuntimeException("Error performing namefinder inference: " + ex.getMessage(), ex); } } } return spans.toArray(new Span[0]); } @Override public void clearAdaptiveData() { // No use in this implementation. } private SpanEnd findSpanEnd(float[][][] v, int startIndex, Map id2Labels, String[] tokens) { // -1 means there is no follow-up token, so it is a single-token span. int index = -1; int characterEnd = 0; // Starts at the span start in the vector. // Looks at the next token to see if it is an I-PER. // Go until the next token is something other than I-PER. // When the next token is not I-PER, return the previous index. for (int x = startIndex + 1; x < v[0].length; x++) { // Get the next item. final float[] arr = v[0][x]; // See if the next token has an I-PER label. final String nextTokenClassification = id2Labels.get(maxIndex(arr)); if (!I_PER.equals(nextTokenClassification)) { index = x - 1; break; } } // Find where the span ends based on the tokens. for (int x = 1; x <= index && x < tokens.length; x++) { characterEnd += tokens[x].length(); } // Account for the number of spaces (that is the number of tokens). // (One space per token.) characterEnd += index - 1; return new SpanEnd(index, characterEnd); } private int maxIndex(float[] arr) { double max = Float.NEGATIVE_INFINITY; int index = -1; for (int x = 0; x < arr.length; x++) { if (arr[x] > max) { index = x; max = arr[x]; } } return index; } private static String findByRegex(String text, String span) { final String regex = span .replaceAll(" ", "\\\\s+") .replaceAll("\\)", "\\\\)") .replaceAll("\\(", "\\\\("); final Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); final Matcher matcher = pattern.matcher(text); if (matcher.find()) { return matcher.group(0); } // For some reason the regex match wasn't found. Just return the original span. return span; } private List tokenize(final String text) { final List t = new LinkedList<>(); // In this article as the paper suggests, we are going to segment the input into smaller text and feed // each of them into BERT, it means for each row, we will split the text in order to have some // smaller text (200 words long each) // https://medium.com/analytics-vidhya/text-classification-with-bert-using-transformers-for-long-text-inputs-f54833994dfd // Split the input text into 200 word chunks with 50 overlapping between chunks. final String[] whitespaceTokenized = text.split("\\s+"); for (int start = 0; start < whitespaceTokenized.length; start = start + inferenceOptions.getDocumentSplitSize()) { // 200 word length chunk // Check the end do don't go past and get a StringIndexOutOfBoundsException int end = start + inferenceOptions.getDocumentSplitSize(); if (end > whitespaceTokenized.length) { end = whitespaceTokenized.length; } // The group is that subsection of string. final String group = String.join(" ", Arrays.copyOfRange(whitespaceTokenized, start, end)); // We want to overlap each chunk by 50 words so scoot back 50 words for the next iteration. start = start - inferenceOptions.getSplitOverlapSize(); // Now we can tokenize the group and continue. final String[] tokens = tokenizer.tokenize(group); final long[] ids = tokenIds(tokens, vocab); final long[] mask = new long[ids.length]; Arrays.fill(mask, 1); final long[] types = new long[ids.length]; Arrays.fill(types, 0); t.add(new Tokens(tokens, ids, mask, types)); } return t; } /** * Maps tokens to their vocabulary ids. * * @param tokens The tokens to map. * @param vocab The vocabulary map. * @return The token ids. * * @throws IllegalArgumentException Thrown if a token is not present in the * vocabulary. */ static long[] tokenIds(final String[] tokens, final Map vocab) { final long[] ids = new long[tokens.length]; for (int x = 0; x < tokens.length; x++) { final Integer id = vocab.get(tokens[x]); if (id == null) { throw new IllegalArgumentException("Token '" + tokens[x] + "' is not present in the vocabulary; the vocabulary file does not match the model."); } ids[x] = id; } return ids; } } apache-opennlp-2.5.12-src/opennlp-dl/src/main/java/opennlp/dl/vectors/SentenceVectorsDL.java0100644 0000000 0000000 00000011752 15217274217 032275 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.vectors; import java.io.File; import java.io.IOException; import java.nio.LongBuffer; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import ai.onnxruntime.OnnxTensor; import ai.onnxruntime.OrtEnvironment; import ai.onnxruntime.OrtException; import ai.onnxruntime.OrtSession; import opennlp.dl.AbstractDL; import opennlp.dl.Tokens; import opennlp.tools.tokenize.Tokenizer; /** * Facilitates the generation of sentence vectors using * a sentence-transformers model converted to ONNX. * *

The model inputs follow the standard single-segment BERT * encoding: {@code attention_mask} is {@code 1} for every real * token and {@code token_type_ids} is {@code 0} throughout.

* *

Release note (OpenNLP 3.0.0): prior releases sent an * all-zero {@code attention_mask} and all-one {@code token_type_ids}, * so the encoder attended to nothing and the output vectors were * incorrect. Output vectors change with the corrected encoding; any * embeddings persisted from the previous behavior are not comparable * with the corrected output and must be re-embedded.

*/ public class SentenceVectorsDL extends AbstractDL { /** * Instantiates a {@link SentenceVectorsDL sentence vector generator} using ONNX models. * * @param model The file name of a sentence vectors ONNX model. * @param vocabulary The file name of the vocabulary file for the model. * * @throws OrtException Thrown if the {@code model} cannot be loaded. * @throws IOException Thrown if errors occurred loading the {@code model} or {@code vocabulary}. */ public SentenceVectorsDL(final File model, final File vocabulary) throws OrtException, IOException { env = OrtEnvironment.getEnvironment(); session = env.createSession(model.getPath(), new OrtSession.SessionOptions()); vocab = loadVocab(vocabulary); tokenizer = createTokenizer(vocab); } /** * Generates vectors given a sentence. * * @param sentence The input sentence. * @return The sentence vector. * * @throws OrtException Thrown if an error occurs during inference. */ public float[] getVectors(final String sentence) throws OrtException { final Tokens tokens = tokenize(sentence, tokenizer, vocab); final Map inputs = new HashMap<>(); try { inputs.put(INPUT_IDS, OnnxTensor.createTensor(env, LongBuffer.wrap(tokens.ids()), new long[] {1, tokens.ids().length})); inputs.put(ATTENTION_MASK, OnnxTensor.createTensor(env, LongBuffer.wrap(tokens.mask()), new long[] {1, tokens.mask().length})); inputs.put(TOKEN_TYPE_IDS, OnnxTensor.createTensor(env, LongBuffer.wrap(tokens.types()), new long[] {1, tokens.types().length})); try (OrtSession.Result result = session.run(inputs)) { // getValue() copies the tensor into Java arrays, so the result can be closed safely. final float[][][] v = (float[][][]) result.get(0).getValue(); return v[0][0]; } } finally { inputs.values().forEach(OnnxTensor::close); } } /** * Encodes text as model inputs: wordpiece token ids, an attention mask of ones, * and single-segment (all zero) token type ids. * * @param text The text to encode. * @param tokenizer The wordpiece tokenizer matching the {@code vocab}. * @param vocab The vocabulary map. * @return The encoded {@link Tokens}. * * @throws IllegalArgumentException Thrown if the tokenizer emits a token that is * not present in the vocabulary. */ static Tokens tokenize(final String text, final Tokenizer tokenizer, final Map vocab) { final String[] tokens = tokenizer.tokenize(text); final long[] ids = new long[tokens.length]; for (int x = 0; x < tokens.length; x++) { final Integer id = vocab.get(tokens[x]); if (id == null) { throw new IllegalArgumentException("Token '" + tokens[x] + "' is not present in the vocabulary; the vocabulary file does not match the model."); } ids[x] = id; } final long[] mask = new long[ids.length]; Arrays.fill(mask, 1); final long[] types = new long[ids.length]; return new Tokens(tokens, ids, mask, types); } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/AbstractDLTest.java0100644 0000000 0000000 00000002667 15217274217 030141 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl; import java.io.File; import java.io.FileNotFoundException; import opennlp.tools.util.StringUtil; public abstract class AbstractDLTest { public File getOpennlpDataDir() throws FileNotFoundException { final String dataDirectory = System.getProperty("OPENNLP_DATA_DIR"); if (dataDirectory == null || StringUtil.isEmpty(dataDirectory)) { throw new IllegalArgumentException("The OPENNLP_DATA_DIR is not set."); } final File file = new File(dataDirectory); if (!file.exists()) { throw new FileNotFoundException("The OPENNLP_DATA_DIR path of " + dataDirectory + " was not found."); } return file; } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/LoadVocabTest.java0100644 0000000 0000000 00000006531 15217274217 030002 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.Map; import java.util.Objects; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; public class LoadVocabTest { private final AbstractDL dl = new AbstractDL() { @Override public void close() { } }; private File getResource(String name) throws IOException { try (InputStream is = Objects.requireNonNull( getClass().getResourceAsStream("/opennlp/dl/" + name))) { final File tempFile = File.createTempFile("vocab-test-", "-" + name); tempFile.deleteOnExit(); Files.copy(is, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING); return tempFile; } } @Test void testLoadPlainTextVocab() throws IOException { final Map vocab = dl.loadVocab(getResource("vocab-plain.txt")); assertNotNull(vocab); assertEquals(6, vocab.size()); assertEquals(0, vocab.get("[CLS]")); assertEquals(1, vocab.get("[SEP]")); assertEquals(2, vocab.get("[UNK]")); assertEquals(3, vocab.get("hello")); assertEquals(4, vocab.get("world")); assertEquals(5, vocab.get("##ing")); } @Test void testLoadJsonVocab() throws IOException { final Map vocab = dl.loadVocab(getResource("vocab.json")); assertNotNull(vocab); assertEquals(6, vocab.size()); assertEquals(0, vocab.get("[CLS]")); assertEquals(1, vocab.get("[SEP]")); assertEquals(2, vocab.get("[UNK]")); assertEquals(3, vocab.get("hello")); assertEquals(4, vocab.get("world")); assertEquals(5, vocab.get("##ing")); } @Test void testJsonVocabWithEscapedCharacters() throws IOException { final File tempFile = File.createTempFile("vocab-escaped", ".json"); tempFile.deleteOnExit(); Files.writeString(tempFile.toPath(), "{\"hello\\\"world\": 0, \"back\\\\slash\": 1}"); final Map vocab = dl.loadVocab(tempFile); assertNotNull(vocab); assertEquals(2, vocab.size()); assertEquals(0, vocab.get("hello\"world")); assertEquals(1, vocab.get("back\\slash")); } @Test void testJsonAndPlainTextVocabProduceSameResult() throws IOException { final Map plainVocab = dl.loadVocab(getResource("vocab-plain.txt")); final Map jsonVocab = dl.loadVocab(getResource("vocab.json")); assertEquals(plainVocab, jsonVocab); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-dl_src_test_java_opennlp_dl_doccat_DocumentCategor0100644 0000000 0000000 00000000161 15217274217 032370 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerConfigTest.java apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerConfigTest.j0100644 0000000 0000000 00000016133 15217274217 034017 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat; import java.util.Map; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; public class DocumentCategorizerConfigTest { @Test public void testId2LabelsFromJsonPrettyValid() { final String json = """ { "_num_labels": 5, "architectures": [ "BertForSequenceClassification" ], "attention_probs_dropout_prob": 0.1, "directionality": "bidi", "finetuning_task": "sentiment-analysis", "hidden_act": "gelu", "hidden_dropout_prob": 0.1, "hidden_size": 768, "id2label": { "0": "1 star", "1": "2 stars", "2": "3 stars", "3": "4 stars", "4": "5 stars" }, "initializer_range": 0.02, "intermediate_size": 3072, "label2id": { "1 star": 0, "2 stars": 1, "3 stars": 2, "4 stars": 3, "5 stars": 4 }, "layer_norm_eps": 1e-12, "max_position_embeddings": 512, "model_type": "bert", "num_attention_heads": 12, "num_hidden_layers": 12, "output_past": true, "pad_token_id": 0, "pooler_fc_size": 768, "pooler_num_attention_heads": 12, "pooler_num_fc_layers": 3, "pooler_size_per_head": 128, "pooler_type": "first_token_transform", "type_vocab_size": 2, "vocab_size": 105879 } """; final DocumentCategorizerConfig config = DocumentCategorizerConfig.fromJson(json); assertNotNull(config); final Map map = config.id2label(); assertEquals(5, map.size()); assertEquals("1 star", map.get("0")); assertEquals("2 stars", map.get("1")); assertEquals("3 stars", map.get("2")); assertEquals("4 stars", map.get("3")); assertEquals("5 stars", map.get("4")); } @Test public void testId2LabelsFromJsonUglyValid() { final String json = """ {"_num_labels":5,"architectures":["BertForSequenceClassification"],"attention_probs_ dropout_prob":0.1,"directionality":"bidi","finetuning_task":"sentiment-analysis", "hidden_act":"gelu","hidden_dropout_prob":0.1,"hidden_size":768,"id2label":{"0":"1 star", "1":"2 stars","2":"3 stars","3":"4 stars","4":"5 stars"},"initializer_range":0.02, "intermediate_size":3072,"label2id":{"1 star":0,"2 stars":1,"3 stars":2,"4 stars":3,"5 stars":4},"layer_norm_eps":1e-12,"max_position_embeddings":512,"model_type":"bert", "num_attention_heads":12,"num_hidden_layers":12,"output_past":true,"pad_token_id":0," pooler_fc_size":768,"pooler_num_attention_heads":12,"pooler_num_fc_layers":3, "pooler_size_per_head":128,"pooler_type":"first_token_transform","type_vocab_size":2, "vocab_size":105879} """; final DocumentCategorizerConfig config = DocumentCategorizerConfig.fromJson(json); assertNotNull(config); final Map map = config.id2label(); assertEquals(5, map.size()); assertEquals("1 star", map.get("0")); assertEquals("2 stars", map.get("1")); assertEquals("3 stars", map.get("2")); assertEquals("4 stars", map.get("3")); assertEquals("5 stars", map.get("4")); } @Test public void testId2LabelsFromJsonNoValues() { final String json = """ {"_num_labels":5,"architectures":["BertForSequenceClassification"],"attention_probs _dropout_prob":0.1,"directionality":"bidi","finetuning_task":"sentiment-analysis", "hidden_act":"gelu","hidden_dropout_prob":0.1,"hidden_size":768,"layer_norm_eps":1e-12, "max_position_embeddings":512,"model_type":"bert", "num_attention_heads":12,"num_hidden_layers":12,"output_past":true,"pad_token_id":0, "pooler_fc_size":768,"pooler_num_attention_heads":12,"pooler_num_fc_layers":3, "pooler_size_per_head":128,"pooler_type":"first_token_transform","type_vocab_size":2, "vocab_size":105879} """; final DocumentCategorizerConfig config = DocumentCategorizerConfig.fromJson(json); assertNotNull(config); assertEquals(0, config.id2label().size()); } @Test public void testId2LabelsFromJsonEmptyInput() { final String json = ""; final DocumentCategorizerConfig config = DocumentCategorizerConfig.fromJson(json); assertNotNull(config); assertEquals(0, config.id2label().size()); } @Test public void testId2LabelsFromJsonPrettyIdIsNotANumberValid() { final String json = """ { "_num_labels": 5, "architectures": [ "BertForSequenceClassification" ], "attention_probs_dropout_prob": 0.1, "directionality": "bidi", "finetuning_task": "sentiment-analysis", "hidden_act": "gelu", "hidden_dropout_prob": 0.1, "hidden_size": 768, "id2label": { "a0": "1 star", "a1": "2 stars", "a2": "3 stars", "a3": "4 stars", "a4": "5 stars" }, "initializer_range": 0.02, "intermediate_size": 3072, "label2id": { "1 star": "a0", "2 stars": "a1", "3 stars": "a2", "4 stars": "a3", "5 stars": "a4" }, "layer_norm_eps": 1e-12, "max_position_embeddings": 512, "model_type": "bert", "num_attention_heads": 12, "num_hidden_layers": 12, "output_past": true, "pad_token_id": 0, "pooler_fc_size": 768, "pooler_num_attention_heads": 12, "pooler_num_fc_layers": 3, "pooler_size_per_head": 128, "pooler_type": "first_token_transform", "type_vocab_size": 2, "vocab_size": 105879 } """; final DocumentCategorizerConfig config = DocumentCategorizerConfig.fromJson(json); assertNotNull(config); final Map map = config.id2label(); assertEquals(5, map.size()); assertEquals("1 star", map.get("a0")); assertEquals("2 stars", map.get("a1")); assertEquals("3 stars", map.get("a2")); assertEquals("4 stars", map.get("a3")); assertEquals("5 stars", map.get("a4")); } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerDLEval.java0100644 0000000 0000000 00000030225 15217274217 033547 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.dl.AbstractDLTest; import opennlp.dl.InferenceOptions; import opennlp.dl.doccat.scoring.AverageClassificationScoringStrategy; public class DocumentCategorizerDLEval extends AbstractDLTest { private static final Logger logger = LoggerFactory.getLogger(DocumentCategorizerDLEval.class); final String text = "We try hard to identify the sources and licenses of all media such as text," + " images or sounds used in our encyclopedia articles. Still, we cannot guarantee that all " + "media are used or marked correctly: for example, if an image description page states " + "that an image was in the public domain, you should still check yourself whether that claim " + "appears correct and decide for yourself whether your use of the image would be fine under " + "the laws applicable to you. Wikipedia is primarily subject to U.S. law; re-users outside " + "the U.S. should be aware that they are subject to the laws of their country, which almost " + "certainly are different. Images published under the GFDL or one of the Creative Commons " + "Licenses are unlikely to pose problems, as these are specific licenses with precise terms " + "worldwide. Public domain images may need to be re-evaluated by a re-user because it depends " + "on each country's copyright laws what is in the public domain there. There is no guarantee " + "that something in the public domain in the U.S. was also in the public domain in your country."; @Test public void categorize() throws Exception { final File model = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.vocab"); try (final DocumentCategorizerDL documentCategorizerDL = new DocumentCategorizerDL(model, vocab, getCategories(), new AverageClassificationScoringStrategy(), new InferenceOptions())) { final double[] result = documentCategorizerDL.categorize(new String[] {text}); // Sort the result for easier comparison. final double[] sortedResult = Arrays.stream(result) .boxed() .sorted(Collections.reverseOrder()).mapToDouble(Double::doubleValue).toArray(); final double[] expected = new double[] {0.3391093313694, 0.2611352801322937, 0.24420668184757233, 0.11939861625432968, 0.03615010157227516}; logger.debug("Actual: {}", Arrays.toString(sortedResult)); logger.debug("Expected: {}", Arrays.toString(expected)); Assertions.assertArrayEquals(expected, sortedResult, 0.000001); Assertions.assertEquals(5, result.length); final String category = documentCategorizerDL.getBestCategory(result); Assertions.assertEquals("bad", category); } } @Test public void categorizeWithAutomaticLabels() throws Exception { final File model = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.vocab"); final File config = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.json"); try (final DocumentCategorizerDL documentCategorizerDL = new DocumentCategorizerDL(model, vocab, config, new AverageClassificationScoringStrategy(), new InferenceOptions())) { final double[] result = documentCategorizerDL.categorize(new String[] {text}); // Sort the result for easier comparison. final double[] sortedResult = Arrays.stream(result) .boxed() .sorted(Collections.reverseOrder()).mapToDouble(Double::doubleValue).toArray(); final double[] expected = new double[] {0.3391093313694, 0.2611352801322937, 0.24420668184757233, 0.11939861625432968, 0.03615010157227516}; logger.debug("Actual: {}", Arrays.toString(sortedResult)); logger.debug("Expected: {}", Arrays.toString(expected)); Assertions.assertArrayEquals(expected, sortedResult, 0.000001); Assertions.assertEquals(5, result.length); final String category = documentCategorizerDL.getBestCategory(result); Assertions.assertEquals("2 stars", category); } } @Disabled("This test should only be run if a GPU device is present.") @Test public void categorizeWithGpu() throws Exception { final File model = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.vocab"); final InferenceOptions inferenceOptions = new InferenceOptions(); inferenceOptions.setGpu(true); inferenceOptions.setGpuDeviceId(0); try (final DocumentCategorizerDL documentCategorizerDL = new DocumentCategorizerDL(model, vocab, getCategories(), new AverageClassificationScoringStrategy(), new InferenceOptions())) { final double[] result = documentCategorizerDL.categorize(new String[] {"I am happy"}); logger.debug(Arrays.toString(result)); final double[] expected = new double[] {0.007819971069693565, 0.006593209225684404, 0.04995147883892059, 0.3003573715686798, 0.6352779865264893}; Assertions.assertArrayEquals(expected, result, 0.000001); Assertions.assertEquals(5, result.length); final String category = documentCategorizerDL.getBestCategory(result); Assertions.assertEquals("very good", category); } } @Test public void categorizeWithInferenceOptions() throws Exception { final File model = new File(getOpennlpDataDir(), "onnx/doccat/lvwerra_distilbert-imdb.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/doccat/lvwerra_distilbert-imdb.vocab"); final InferenceOptions inferenceOptions = new InferenceOptions(); inferenceOptions.setIncludeTokenTypeIds(false); final Map categories = new HashMap<>(); categories.put(0, "negative"); categories.put(1, "positive"); try (final DocumentCategorizerDL documentCategorizerDL = new DocumentCategorizerDL(model, vocab, categories, new AverageClassificationScoringStrategy(), inferenceOptions)) { final double[] result = documentCategorizerDL.categorize(new String[] {"I am angry"}); final double[] expected = new double[] {0.8851314783096313, 0.11486853659152985}; Assertions.assertArrayEquals(expected, result, 0.000001); Assertions.assertEquals(2, result.length); final String category = documentCategorizerDL.getBestCategory(result); Assertions.assertEquals("negative", category); } } @Test public void scoreMap() throws Exception { final File model = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.vocab"); try (final DocumentCategorizerDL documentCategorizerDL = new DocumentCategorizerDL(model, vocab, getCategories(), new AverageClassificationScoringStrategy(), new InferenceOptions())) { final Map result = documentCategorizerDL.scoreMap(new String[] {"I am happy"}); Assertions.assertEquals(0.6352779865264893, result.get("very good"), 0.000001); Assertions.assertEquals(0.3003573715686798, result.get("good"), 0.000001); Assertions.assertEquals(0.04995147883892059, result.get("neutral"), 0.000001); Assertions.assertEquals(0.006593209225684404, result.get("bad"), 0.000001); Assertions.assertEquals(0.007819971069693565, result.get("very bad"), 0.000001); } } @Test public void sortedScoreMap() throws Exception { final File model = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.vocab"); try (final DocumentCategorizerDL documentCategorizerDL = new DocumentCategorizerDL(model, vocab, getCategories(), new AverageClassificationScoringStrategy(), new InferenceOptions())) { final Map> result = documentCategorizerDL.sortedScoreMap(new String[] {"I am happy"}); Assertions.assertNotNull(result, "Result must not be NULL."); Assertions.assertEquals(5, result.size()); final Iterator>> it = result.entrySet().iterator(); // we assume a sorted map here, so lets check in sorted order (lower values first). Map.Entry> e = it.next(); Assertions.assertEquals(0.006593209225684404, e.getKey(), 0.000001); Assertions.assertEquals(e.getValue().size(), 1); e = it.next(); Assertions.assertEquals(0.007819971069693565, e.getKey(), 0.000001); Assertions.assertEquals(e.getValue().size(), 1); e = it.next(); Assertions.assertEquals(0.04995147883892059, e.getKey(), 0.000001); Assertions.assertEquals(e.getValue().size(), 1); e = it.next(); Assertions.assertEquals(0.3003573715686798, e.getKey(), 0.000001); Assertions.assertEquals(e.getValue().size(), 1); e = it.next(); Assertions.assertEquals(0.6352779865264893, e.getKey(), 0.000001); Assertions.assertEquals(e.getValue().size(), 1); } } @Test public void doccat() throws Exception { final File model = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.vocab"); try (final DocumentCategorizerDL documentCategorizerDL = new DocumentCategorizerDL(model, vocab, getCategories(), new AverageClassificationScoringStrategy(), new InferenceOptions())) { final int index = documentCategorizerDL.getIndex("bad"); Assertions.assertEquals(1, index); final String category = documentCategorizerDL.getCategory(3); Assertions.assertEquals("good", category); final int number = documentCategorizerDL.getNumberOfCategories(); Assertions.assertEquals(5, number); } } private Map getCategories() { final Map categories = new HashMap<>(); categories.put(0, "very bad"); categories.put(1, "bad"); categories.put(2, "neutral"); categories.put(3, "good"); categories.put(4, "very good"); return categories; } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerDLTest.java0100644 0000000 0000000 00000004247 15217274217 033604 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; import opennlp.tools.tokenize.WordpieceTokenizer; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class DocumentCategorizerDLTest { private static Map vocab() { final Map vocab = new HashMap<>(); vocab.put(WordpieceTokenizer.BERT_CLS_TOKEN, 0); vocab.put(WordpieceTokenizer.BERT_SEP_TOKEN, 1); vocab.put(WordpieceTokenizer.BERT_UNK_TOKEN, 2); vocab.put("hello", 3); vocab.put("world", 4); return vocab; } @Test void testTokenIdsMapsTokensToVocabularyIds() { final long[] ids = DocumentCategorizerDL.tokenIds( new String[] {WordpieceTokenizer.BERT_CLS_TOKEN, "hello", "world", WordpieceTokenizer.BERT_SEP_TOKEN}, vocab()); assertArrayEquals(new long[] {0, 3, 4, 1}, ids); } @Test void testTokenIdsRejectsTokensMissingFromVocabulary() { final IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> DocumentCategorizerDL.tokenIds(new String[] {"hello", "missing"}, vocab())); assertTrue(e.getMessage().contains("missing"), "the error message should name the missing token: " + e.getMessage()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-dl_src_test_java_opennlp_dl_doccat_scoring_Average0100644 0000000 0000000 00000000204 15217274217 032401 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/scoring/AverageClassificationScoringStrategyTest.java apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/doccat/scoring/AverageClassificationSc0100644 0000000 0000000 00000004206 15217274217 034002 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.doccat.scoring; import java.util.LinkedList; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class AverageClassificationScoringStrategyTest { @Test public void calculateAverage1() { final List scores = new LinkedList<>(); scores.add(new double[]{1, 2, 3, 4, 5}); scores.add(new double[]{1, 2, 3, 4, 5}); scores.add(new double[]{1, 2, 3, 4, 5}); final ClassificationScoringStrategy strategy = new AverageClassificationScoringStrategy(); final double[] results = strategy.score(scores); Assertions.assertEquals(1.0, results[0], 0); Assertions.assertEquals(2.0, results[1], 0); Assertions.assertEquals(3.0, results[2], 0); Assertions.assertEquals(4.0, results[3], 0); Assertions.assertEquals(5.0, results[4], 0); } @Test public void calculateAverage2() { final List scores = new LinkedList<>(); scores.add(new double[]{2, 1, 5}); scores.add(new double[]{4, 3, 10}); scores.add(new double[]{6, 5, 15}); final ClassificationScoringStrategy strategy = new AverageClassificationScoringStrategy(); final double[] results = strategy.score(scores); Assertions.assertEquals(4.0, results[0], 0); Assertions.assertEquals(3.0, results[1], 0); Assertions.assertEquals(10.0, results[2], 0); } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/namefinder/NameFinderDLEval.java0100644 0000000 0000000 00000017303 15217274217 032457 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.namefinder; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import ai.onnxruntime.OrtException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.dl.AbstractDLTest; import opennlp.tools.sentdetect.SentenceDetector; import opennlp.tools.sentdetect.SentenceDetectorME; import opennlp.tools.util.Span; public class NameFinderDLEval extends AbstractDLTest { private static final Logger logger = LoggerFactory.getLogger(NameFinderDLEval.class); private final SentenceDetector sentenceDetector; public NameFinderDLEval() throws IOException { this.sentenceDetector = new SentenceDetectorME("en"); } @Test public void tokenNameFinder1Test() throws Exception { // This test was written using the dslim/bert-base-NER model. // You will need to update the ids2Labels and assertions if you use a different model. final File model = new File(getOpennlpDataDir(), "onnx/namefinder/model.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/namefinder/vocab.txt"); final String[] tokens = new String[] {"George", "Washington", "was", "president", "of", "the", "United", "States", "."}; try (final NameFinderDL nameFinderDL = new NameFinderDL(model, vocab, getIds2Labels(), sentenceDetector)) { final Span[] spans = nameFinderDL.find(tokens); for (Span span : spans) { logger.debug(span.toString()); } Assertions.assertEquals(1, spans.length); Assertions.assertEquals(0, spans[0].getStart()); Assertions.assertEquals(17, spans[0].getEnd()); Assertions.assertEquals(8.251646041870117, spans[0].getProb(), 0.00001); Assertions.assertEquals("George Washington", spans[0].getCoveredText(String.join(" ", tokens))); } } @Test public void tokenNameFinder2Test() throws Exception { // This test was written using the dslim/bert-base-NER model. // You will need to update the ids2Labels and assertions if you use a different model. final File model = new File(getOpennlpDataDir(), "onnx/namefinder/model.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/namefinder/vocab.txt"); final String[] tokens = new String[] {"His", "name", "was", "George", "Washington"}; try (final NameFinderDL nameFinderDL = new NameFinderDL(model, vocab, getIds2Labels(), sentenceDetector)) { final Span[] spans = nameFinderDL.find(tokens); for (Span span : spans) { logger.debug(span.toString()); } Assertions.assertEquals(1, spans.length); Assertions.assertEquals(13, spans[0].getStart()); Assertions.assertEquals(30, spans[0].getEnd()); } } @Test public void tokenNameFinder3Test() throws Exception { // This test was written using the dslim/bert-base-NER model. // You will need to update the ids2Labels and assertions if you use a different model. final File model = new File(getOpennlpDataDir(), "onnx/namefinder/model.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/namefinder/vocab.txt"); final String[] tokens = new String[] {"His", "name", "was", "George"}; try (final NameFinderDL nameFinderDL = new NameFinderDL(model, vocab, getIds2Labels(), sentenceDetector)) { final Span[] spans = nameFinderDL.find(tokens); for (Span span : spans) { logger.debug(span.toString()); } Assertions.assertEquals(1, spans.length); Assertions.assertEquals(13, spans[0].getStart()); Assertions.assertEquals(19, spans[0].getEnd()); } } @Test public void tokenNameFinderNoInputTest() throws Exception { // This test was written using the dslim/bert-base-NER model. // You will need to update the ids2Labels and assertions if you use a different model. final File model = new File(getOpennlpDataDir(), "onnx/namefinder/model.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/namefinder/vocab.txt"); final String[] tokens = new String[] {}; try (final NameFinderDL nameFinderDL = new NameFinderDL(model, vocab, getIds2Labels(), sentenceDetector)) { final Span[] spans = nameFinderDL.find(tokens); Assertions.assertEquals(0, spans.length); } } @Test public void tokenNameFinderNoEntitiesTest() throws Exception { // This test was written using the dslim/bert-base-NER model. // You will need to update the ids2Labels and assertions if you use a different model. final File model = new File(getOpennlpDataDir(), "onnx/namefinder/model.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/namefinder/vocab.txt"); final String[] tokens = new String[] {"I", "went", "to", "the", "park"}; try (final NameFinderDL nameFinderDL = new NameFinderDL(model, vocab, getIds2Labels(), sentenceDetector)) { final Span[] spans = nameFinderDL.find(tokens); Assertions.assertEquals(0, spans.length); } } @Test public void tokenNameFinderMultipleEntitiesTest() throws Exception { // This test was written using the dslim/bert-base-NER model. // You will need to update the ids2Labels and assertions if you use a different model. final File model = new File(getOpennlpDataDir(), "onnx/namefinder/model.onnx"); final File vocab = new File(getOpennlpDataDir(), "onnx/namefinder/vocab.txt"); final String[] tokens = new String[] {"George", "Washington", "and", "Abraham", "Lincoln", "were", "presidents"}; try (final NameFinderDL nameFinderDL = new NameFinderDL(model, vocab, getIds2Labels(), sentenceDetector)) { final Span[] spans = nameFinderDL.find(tokens); for (Span span : spans) { logger.debug(span.toString()); } Assertions.assertEquals(2, spans.length); Assertions.assertEquals(0, spans[0].getStart()); Assertions.assertEquals(17, spans[0].getEnd()); Assertions.assertEquals(22, spans[1].getStart()); Assertions.assertEquals(37, spans[1].getEnd()); } } @Test public void invalidModel() { Assertions.assertThrows(OrtException.class, () -> { // This test was written using the dslim/bert-base-NER model. // You will need to update the ids2Labels and assertions if you use a different model. final File model = new File("invalid.onnx"); final File vocab = new File("vocab.txt"); //noinspection resource new NameFinderDL(model, vocab, getIds2Labels(), sentenceDetector); }); } private Map getIds2Labels() { final Map ids2Labels = new HashMap<>(); ids2Labels.put(0, "O"); ids2Labels.put(1, "B-MISC"); ids2Labels.put(2, "I-MISC"); ids2Labels.put(3, "B-PER"); ids2Labels.put(4, "I-PER"); ids2Labels.put(5, "B-ORG"); ids2Labels.put(6, "I-ORG"); ids2Labels.put(7, "B-LOC"); ids2Labels.put(8, "I-LOC"); return ids2Labels; } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/namefinder/NameFinderDLTest.java0100644 0000000 0000000 00000004220 15217274217 032501 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.namefinder; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; import opennlp.tools.tokenize.WordpieceTokenizer; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class NameFinderDLTest { private static Map vocab() { final Map vocab = new HashMap<>(); vocab.put(WordpieceTokenizer.BERT_CLS_TOKEN, 0); vocab.put(WordpieceTokenizer.BERT_SEP_TOKEN, 1); vocab.put(WordpieceTokenizer.BERT_UNK_TOKEN, 2); vocab.put("hello", 3); vocab.put("world", 4); return vocab; } @Test void testTokenIdsMapsTokensToVocabularyIds() { final long[] ids = NameFinderDL.tokenIds( new String[] {WordpieceTokenizer.BERT_CLS_TOKEN, "hello", "world", WordpieceTokenizer.BERT_SEP_TOKEN}, vocab()); assertArrayEquals(new long[] {0, 3, 4, 1}, ids); } @Test void testTokenIdsRejectsTokensMissingFromVocabulary() { final IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> NameFinderDL.tokenIds(new String[] {"hello", "missing"}, vocab())); assertTrue(e.getMessage().contains("missing"), "the error message should name the missing token: " + e.getMessage()); } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/vectors/SentenceVectorsDLEval.java0100644 0000000 0000000 00000005363 15217274217 033141 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.vectors; import java.io.File; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import opennlp.dl.AbstractDLTest; public class SentenceVectorsDLEval extends AbstractDLTest { @Test public void generateVectorsTest() throws Exception { final File MODEL_FILE_NAME = new File(getOpennlpDataDir(), "onnx/sentence-transformers/model.onnx"); final File VOCAB_FILE_NAME = new File(getOpennlpDataDir(), "onnx/sentence-transformers/vocab.txt"); final String sentence = "george washington was president"; try (final SentenceVectorsDL sv = new SentenceVectorsDL(MODEL_FILE_NAME, VOCAB_FILE_NAME)) { final float[] vectors = sv.getVectors(sentence); /* * Expected values are the first three components of last_hidden_state[0][0] * (the [CLS] position) produced by the ONNX export of * https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2 for the * input "[CLS] george washington was president [SEP]" with the corrected * encoding (attention_mask=1, token_type_ids=0; see OPENNLP-1836). * * Reproducible independently of this class with the HuggingFace reference * implementation (Python packages 'tokenizers' and 'onnxruntime'): * * tok = BertWordPieceTokenizer("vocab.txt", lowercase=True) * enc = tok.encode(sentence, add_special_tokens=True) * ids = np.array([enc.ids], dtype=np.int64) * out = ort.InferenceSession("model.onnx").run(None, { * "input_ids": ids, * "attention_mask": np.ones_like(ids), * "token_type_ids": np.zeros_like(ids)})[0] * out[0][0][:3] # -> [0.04474502, 0.20219636, 0.41306049] */ Assertions.assertEquals(0.044745024, vectors[0], 0.00001); Assertions.assertEquals(0.20219636, vectors[1], 0.00001); Assertions.assertEquals(0.41306049, vectors[2], 0.00001); Assertions.assertEquals(384, vectors.length); } } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/java/opennlp/dl/vectors/SentenceVectorsDLTest.java0100644 0000000 0000000 00000006050 15217274217 033163 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.dl.vectors; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; import opennlp.dl.Tokens; import opennlp.tools.tokenize.WordpieceTokenizer; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; public class SentenceVectorsDLTest { private static Map vocab() { final Map vocab = new HashMap<>(); vocab.put(WordpieceTokenizer.BERT_CLS_TOKEN, 0); vocab.put(WordpieceTokenizer.BERT_SEP_TOKEN, 1); vocab.put(WordpieceTokenizer.BERT_UNK_TOKEN, 2); vocab.put("hello", 3); vocab.put("world", 4); return vocab; } @Test void testTokenizeUsesSingleSegmentBertEncoding() { final Map vocab = vocab(); final WordpieceTokenizer tokenizer = new WordpieceTokenizer(vocab.keySet()); final Tokens tokens = SentenceVectorsDL.tokenize("hello world", tokenizer, vocab); assertArrayEquals(new String[] { WordpieceTokenizer.BERT_CLS_TOKEN, "hello", "world", WordpieceTokenizer.BERT_SEP_TOKEN}, tokens.tokens()); assertArrayEquals(new long[] {0, 3, 4, 1}, tokens.ids()); // The attention mask must be 1 for every real token. assertArrayEquals(new long[] {1, 1, 1, 1}, tokens.mask()); // Single-segment input: all token type ids must be 0. assertArrayEquals(new long[] {0, 0, 0, 0}, tokens.types()); } @Test void testTokenizeMapsOutOfVocabularyWordsToUnknownToken() { final Map vocab = vocab(); final WordpieceTokenizer tokenizer = new WordpieceTokenizer(vocab.keySet()); final Tokens tokens = SentenceVectorsDL.tokenize("hello xyz", tokenizer, vocab); assertArrayEquals(new long[] {0, 3, 2, 1}, tokens.ids()); assertEquals(WordpieceTokenizer.BERT_UNK_TOKEN, tokens.tokens()[2]); } @Test void testTokenizeRejectsTokensMissingFromVocabulary() { final Map vocab = vocab(); vocab.remove(WordpieceTokenizer.BERT_UNK_TOKEN); final WordpieceTokenizer tokenizer = new WordpieceTokenizer(vocab.keySet()); assertThrows(IllegalArgumentException.class, () -> SentenceVectorsDL.tokenize("hello xyz", tokenizer, vocab)); } } apache-opennlp-2.5.12-src/opennlp-dl/src/test/resources/opennlp/dl/vocab-plain.txt0100644 0000000 0000000 00000000043 15217274217 030462 0ustar00rootroot0000000 0000000 [CLS] [SEP] [UNK] hello world ##ingapache-opennlp-2.5.12-src/opennlp-dl/src/test/resources/opennlp/dl/vocab.json0100644 0000000 0000000 00000000126 15217274217 027515 0ustar00rootroot0000000 0000000 { "[CLS]": 0, "[SEP]": 1, "[UNK]": 2, "hello": 3, "world": 4, "##ing": 5 }apache-opennlp-2.5.12-src/opennlp-dl-gpu/README.md0100644 0000000 0000000 00000000636 15217274217 021754 0ustar00rootroot0000000 0000000 # OpenNLP DL (GPU) This module brings in `onnxruntime_gpu` bindings to the existing `opennlp-dl` module. If you are planning to run with GPU acceleration, please use this BOM. You can use it in your code by adding the following as a dependency: ```xml org.apache.opennlp opennlp-dl-gpu ${opennlp.version} ```apache-opennlp-2.5.12-src/opennlp-dl-gpu/pom.xml0100644 0000000 0000000 00000007303 15217274217 022010 0ustar00rootroot0000000 0000000 4.0.0 org.apache.opennlp opennlp 2.5.12 ../pom.xml org.apache.opennlp opennlp-dl-gpu Apache OpenNLP DL (GPU) org.apache.opennlp opennlp-dl ${project.version} com.microsoft.onnxruntime onnxruntime com.microsoft.onnxruntime onnxruntime_gpu ${onnxruntime.version} org.junit.jupiter junit-jupiter-api test org.junit.jupiter junit-jupiter-engine test org.slf4j slf4j-simple test org.apache.opennlp opennlp-dl ${project.version} test-jar test org.apache.maven.plugins maven-surefire-plugin org.apache.opennlp:opennlp-dl eval-tests 0.5C org.apache.maven.plugins maven-surefire-plugin -Xmx4g **/*Test.java **/*Eval.java org.apache.opennlp:opennlp-dl apache-opennlp-2.5.12-src/opennlp-docs/pom.xml0100644 0000000 0000000 00000013435 15217274217 021553 0ustar00rootroot0000000 0000000 4.0.0 org.apache.opennlp opennlp 2.5.12 ../pom.xml opennlp-docs jar Apache OpenNLP :: Documentation doc-manual-html true com.agilejava.docbkx docbkx-maven-plugin doc-manual-html generate-html package css/opennlp-dev-manual.css 1 ${project.basedir}/src/main/resources/xsl/html.xsl doc-manual-pdf true com.agilejava.docbkx docbkx-maven-plugin doc-manual-pdf generate-pdf package ${project.basedir}/src/main/resources/xsl/pdf.xsl 1 true false false doc-manual-epub false com.agilejava.docbkx docbkx-maven-plugin doc-manual-epub generate-epub3 package true false css/opennlp-dev-manual.css ${project.basedir}/src/main/resources/xsl/epub3.xsl true false com.agilejava.docbkx docbkx-maven-plugin 2.0.17 net.sf.docbook docbook-xml 5.0-all resources zip runtime net.sf.xslthl xslthl 2.1.3 runtime net.sf.offo fop-hyph 2.0 runtime true opennlp.xml org.apache.maven.plugins maven-surefire-plugin true apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/chunker.xml0100644 0000000 0000000 00000031564 15217274217 024463 0ustar00rootroot0000000 0000000 Chunker
Chunking Text chunking consists of dividing a text in syntactically correlated parts of words, like noun groups, verb groups, but does not specify their internal structure, nor their role in the main sentence.
Chunker Tool The easiest way to try out the Chunker is the command line tool. The tool is only intended for demonstration and testing. Download the English maxent chunker model from the website and start the Chunker Tool with this command: The Chunker now reads a pos tagged sentence per line from stdin. Copy these two sentences to the console: The Chunker will now echo the sentences grouped tokens to the console: The tag set used by the English pos model is the Penn Treebank tag set .
Chunking API The Chunker can be embedded into an application via its API. First the chunker model must be loaded into memory from disk or another source. In the sample below it is loaded from disk. After the model is loaded a Chunker can be instantiated. The Chunker instance is now ready to tag data. It expects a tokenized sentence as input, which is represented as a String array, each String object in the array is one token, and the POS tags associated with each token. The following code shows how to determine the most likely chunk tag sequence for a sentence. The tags array contains one chunk tag for each token in the input array. The corresponding tag can be found at the same index as the token has in the input array. The confidence scores for the returned tags can be easily retrieved from a ChunkerME with the following method call: The call to probs is stateful and will always return the probabilities of the last tagged sentence. The probs method should only be called when the tag method was called before, otherwise the behavior is undefined. Some applications need to retrieve the n-best chunk tag sequences and not only the best sequence. The topKSequences method is capable of returning the top sequences. It can be called in a similar way as chunk. Each Sequence object contains one sequence. The sequence can be retrieved via Sequence.getOutcomes() which returns a tags array and Sequence.getProbs() returns the probability array for this sequence.
Chunker Training The pre-trained models might not be available for a desired language, can not detect important entities or the performance is not good enough outside the news domain. These are the typical reason to do custom training of the chunker on a new corpus or on a corpus which is extended by private training data taken from the data which should be analyzed. The training data can be converted to the OpenNLP chunker training format, which is based on CoNLL2000. Other formats may also be available. The training data consist of three columns separated one single space. Each word has been put on a separate line and there is an empty line after each sentence. The first column contains the current word, the second its part-of-speech tag and the third its chunk tag. The chunk tags contain the name of the chunk type, for example I-NP for noun phrase words and I-VP for verb phrase words. Most chunk types have two types of chunk tags, B-CHUNK for the first word of the chunk and I-CHUNK for each other word in the chunk. Here is an example of the file format: Sample sentence of the training data: For improved visualization the example above uses tabs instead of a single space as column separator.
Training Tool OpenNLP has a command line tool which is used to train the models available from the model download page on various corpora. Usage of the tool: Its now assumed that the English chunker model should be trained from a file called en-chunker.train which is encoded as UTF-8. The following command will train the name finder and write the model to en-chunker.bin: Additionally its possible to specify the number of iterations, the cutoff and to overwrite all types in the training data with a single type.
Training API The Chunker offers an API to train a new chunker model. The following sample code illustrates how to do it: lineStream = new PlainTextByLineStream(new MarkableFileInputStreamFactory(new File("en-chunker.train")), StandardCharsets.UTF_8); ChunkerModel model; try(ObjectStream sampleStream = new ChunkSampleStream(lineStream)) { model = ChunkerME.train("eng", sampleStream, TrainingParameters.defaultParams(), new ChunkerFactory()); } try (OutputStream modelOut = new BufferedOutputStream(new FileOutputStream(modelFile))) { model.serialize(modelOut); }]]>
Chunker Evaluation The built-in evaluation can measure the chunker performance. The performance is either measured on a test dataset or via cross validation.
Chunker Evaluation Tool The following command shows how the tool can be run: A sample of the command considering you have a data sample named en-chunker.eval and you trained a model called en-chunker.bin: and here is a sample output: You can also use the tool to perform 10-fold cross validation of the Chunker. The following command shows how the tool can be run: It is not necessary to pass a model. The tool will automatically split the data to train and evaluate:
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/cli.xml0100644 0000000 0000000 00000360274 15217274217 023576 0ustar00rootroot0000000 0000000 The Command Line Interface This section details the available tools and parameters of the Command Line Interface. For an introduction in its usage please refer to .
Doccat
Doccat Learned document categorizer
DoccatTrainer Trainer for the learnable document categorizer The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
DoccatEvaluator Measures the performance of the Doccat model with the reference data The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
DoccatCrossValidator K-fold cross validator for the learnable Document Categorizer The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
DoccatConverter Converts leipzig data format to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
Langdetect
LanguageDetector Learned language detector
LanguageDetectorTrainer Trainer for the learnable language detector The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used sentencesPerSample sentencesPerSample No Number of sentences per sample samplesPerLanguage samplesPerLanguage No Number of samples per language encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
LanguageDetectorConverter Converts leipzig data format to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used sentencesPerSample sentencesPerSample No Number of sentences per sample samplesPerLanguage samplesPerLanguage No Number of samples per language encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
LanguageDetectorCrossValidator K-fold cross validator for the learnable Language Detector The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used sentencesPerSample sentencesPerSample No Number of sentences per sample samplesPerLanguage samplesPerLanguage No Number of samples per language encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
LanguageDetectorEvaluator Measures the performance of the Language Detector model with the reference data The supported formats and arguments are: Format Argument Value Optional Description leipzig sentencesDir sentencesDir No Dir with Leipzig sentences to be used sentencesPerSample sentencesPerSample No Number of sentences per sample samplesPerLanguage samplesPerLanguage No Number of samples per language encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
Dictionary
DictionaryBuilder Builds a new dictionary
Tokenizer
SimpleTokenizer Character class tokenizer
TokenizerME Learnable tokenizer
TokenizerTrainer Trainer for the learnable tokenizer The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) detokenizer dictionary No Specifies the file with detokenizer dictionary. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllu data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
TokenizerMEEvaluator Evaluator for the learnable tokenizer The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) detokenizer dictionary No Specifies the file with detokenizer dictionary. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllu data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
TokenizerCrossValidator K-fold cross validator for the learnable tokenizer The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) detokenizer dictionary No Specifies the file with detokenizer dictionary. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllu data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
TokenizerConverter Converts foreign data formats (irishsentencebank,ad,pos,conllx,namefinder,parse,conllu) to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) detokenizer dictionary No Specifies the file with detokenizer dictionary. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllu data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
DictionaryDetokenizer
Sentdetect
SentenceDetector Learnable sentence detector
SentenceDetectorTrainer Trainer for the learnable sentence detector The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. includeTitles includeTitles Yes If true will include sentences marked as headlines. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. moses data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conllu sentencesPerSample sentencesPerSample No Number of sentences per sample data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. letsmt detokenizer dictionary Yes Specifies the file with detokenizer dictionary. data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
SentenceDetectorEvaluator Evaluator for the learnable sentence detector The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. includeTitles includeTitles Yes If true will include sentences marked as headlines. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. moses data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conllu sentencesPerSample sentencesPerSample No Number of sentences per sample data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. letsmt detokenizer dictionary Yes Specifies the file with detokenizer dictionary. data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
SentenceDetectorCrossValidator K-fold cross validator for the learnable sentence detector The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. includeTitles includeTitles Yes If true will include sentences marked as headlines. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. moses data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conllu sentencesPerSample sentencesPerSample No Number of sentences per sample data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. letsmt detokenizer dictionary Yes Specifies the file with detokenizer dictionary. data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
SentenceDetectorConverter Converts foreign data formats (irishsentencebank,ad,pos,conllx,namefinder,parse,moses,conllu,letsmt) to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description irishsentencebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. includeTitles includeTitles Yes If true will include sentences marked as headlines. pos data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. namefinder data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. detokenizer dictionary No Specifies the file with detokenizer dictionary. moses data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conllu sentencesPerSample sentencesPerSample No Number of sentences per sample data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. letsmt detokenizer dictionary Yes Specifies the file with detokenizer dictionary. data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
Namefind
TokenNameFinder Learnable name finder
TokenNameFinderTrainer Trainer for the learnable name finder The supported formats and arguments are: Format Argument Value Optional Description evalita lang it No types per,loc,org,gpe No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) conll03 lang eng|deu No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. bionlp2004 types DNA, protein, cell_type, cell_line, RNA No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conll02 lang spa|nld No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. muc6 tokenizerModel modelFile No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No brat tokenizerModel modelFile Yes ruleBasedTokenizer name Yes annotationConfig annConfFile No bratDataDir bratDataDir No Location of brat data dir recursive value Yes sentenceDetectorModel modelFile Yes
TokenNameFinderEvaluator Measures the performance of the NameFinder model with the reference data The supported formats and arguments are: Format Argument Value Optional Description evalita lang it No types per,loc,org,gpe No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) conll03 lang eng|deu No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. bionlp2004 types DNA, protein, cell_type, cell_line, RNA No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conll02 lang spa|nld No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. muc6 tokenizerModel modelFile No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No brat tokenizerModel modelFile Yes ruleBasedTokenizer name Yes annotationConfig annConfFile No bratDataDir bratDataDir No Location of brat data dir recursive value Yes sentenceDetectorModel modelFile Yes
TokenNameFinderCrossValidator K-fold cross validator for the learnable Name Finder The supported formats and arguments are: Format Argument Value Optional Description evalita lang it No types per,loc,org,gpe No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) conll03 lang eng|deu No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. bionlp2004 types DNA, protein, cell_type, cell_line, RNA No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conll02 lang spa|nld No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. muc6 tokenizerModel modelFile No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No brat tokenizerModel modelFile Yes ruleBasedTokenizer name Yes annotationConfig annConfFile No bratDataDir bratDataDir No Location of brat data dir recursive value Yes sentenceDetectorModel modelFile Yes
TokenNameFinderConverter Converts foreign data formats (evalita,ad,conll03,bionlp2004,conll02,muc6,ontonotes,brat) to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description evalita lang it No types per,loc,org,gpe No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. splitHyphenatedTokens split Yes If true all hyphenated tokens will be separated (default true) conll03 lang eng|deu No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. bionlp2004 types DNA, protein, cell_type, cell_line, RNA No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. conll02 lang spa|nld No types per,loc,org,misc No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. muc6 tokenizerModel modelFile No data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No brat tokenizerModel modelFile Yes ruleBasedTokenizer name Yes annotationConfig annConfFile No bratDataDir bratDataDir No Location of brat data dir recursive value Yes sentenceDetectorModel modelFile Yes
CensusDictionaryCreator Converts 1990 US Census names into a dictionary
Postag
POSTagger Learnable part of speech tagger
POSTaggerTrainer Trains a model for the part-of-speech tagger The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. expandME expandME Yes Expand multiword expressions. includeFeatures includeFeatures Yes Combine POS Tags with word features, like number and gender. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No conllu tagset tagset Yes U|x u for unified tags and x for language-specific part-of-speech tags data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
POSTaggerEvaluator Measures the performance of the POS tagger model with the reference data The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. expandME expandME Yes Expand multiword expressions. includeFeatures includeFeatures Yes Combine POS Tags with word features, like number and gender. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No conllu tagset tagset Yes U|x u for unified tags and x for language-specific part-of-speech tags data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
POSTaggerCrossValidator K-fold cross validator for the learnable POS tagger The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. expandME expandME Yes Expand multiword expressions. includeFeatures includeFeatures Yes Combine POS Tags with word features, like number and gender. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No conllu tagset tagset Yes U|x u for unified tags and x for language-specific part-of-speech tags data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
POSTaggerConverter Converts foreign data formats (ad,conllx,parse,ontonotes,conllu) to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. data sampleData No Data to be used, usually a file name. expandME expandME Yes Expand multiword expressions. includeFeatures includeFeatures Yes Combine POS Tags with word features, like number and gender. conllx data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. parse data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used. ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No conllu tagset tagset Yes U|x u for unified tags and x for language-specific part-of-speech tags data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
Lemmatizer
LemmatizerME Learnable lemmatizer
LemmatizerTrainerME Trainer for the learnable lemmatizer The supported formats and arguments are: Format Argument Value Optional Description conllu tagset tagset Yes U|x u for unified tags and x for language-specific part-of-speech tags data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
LemmatizerEvaluator Measures the performance of the Lemmatizer model with the reference data The supported formats and arguments are: Format Argument Value Optional Description conllu tagset tagset Yes U|x u for unified tags and x for language-specific part-of-speech tags data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
Chunker
ChunkerME Learnable chunker
ChunkerTrainerME Trainer for the learnable chunker The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. end end Yes Index of last sentence start start Yes Index of first sentence data sampleData No Data to be used, usually a file name.
ChunkerEvaluator Measures the performance of the Chunker model with the reference data The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. end end Yes Index of last sentence start start Yes Index of first sentence data sampleData No Data to be used, usually a file name.
ChunkerCrossValidator K-fold cross validator for the chunker The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. end end Yes Index of last sentence start start Yes Index of first sentence data sampleData No Data to be used, usually a file name.
ChunkerConverter Converts ad data format to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description ad encoding charsetName No Encoding for reading and writing text, if absent the system default is used. lang language No Language which is being processed. end end Yes Index of last sentence start start Yes Index of first sentence data sampleData No Data to be used, usually a file name.
Parser
Parser Performs full syntactic parsing
ParserTrainer Trains the learnable parser The supported formats and arguments are: Format Argument Value Optional Description ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No frenchtreebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
ParserEvaluator Measures the performance of the Parser model with the reference data The supported formats and arguments are: Format Argument Value Optional Description ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No frenchtreebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
ParserConverter Converts foreign data formats (ontonotes,frenchtreebank) to native OpenNLP format The supported formats and arguments are: Format Argument Value Optional Description ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No frenchtreebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
BuildModelUpdater Trains and updates the build model in a parser model The supported formats and arguments are: Format Argument Value Optional Description ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No frenchtreebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
CheckModelUpdater Trains and updates the check model in a parser model The supported formats and arguments are: Format Argument Value Optional Description ontonotes ontoNotesDir OntoNotes 4.0 corpus directory No frenchtreebank data sampleData No Data to be used, usually a file name. encoding charsetName Yes Encoding for reading and writing text, if absent the system default is used.
TaggerModelReplacer Replaces the tagger model in a parser model
Entitylinker
EntityLinker Links an entity to an external data set
Languagemodel
NGramLanguageModel Gives the probability and most probable next token(s) of a sequence of tokens in a language model
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/coref.xml0100644 0000000 0000000 00000005074 15217274217 024117 0ustar00rootroot0000000 0000000 Coreference Resolution The OpenNLP Coreference Resolution system links multiple mentions of an entity in a document together. The OpenNLP implementation is currently limited to noun phrase mentions, other mention types cannot be resolved. TODO: Write more documentation about the coref component. Any contributions are very welcome. If you want to contribute please contact us on the mailing list or comment on the jira issue OPENNLP-48. apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/corpora.xml0100644 0000000 0000000 00000073131 15217274217 024465 0ustar00rootroot0000000 0000000 Corpora OpenNLP has built-in support to convert into the native training format or directly use various corpora needed by the different trainable components.
CONLL CoNLL stands for the Conference on Computational Natural Language Learning and is not a single project but a consortium of developers attempting to broaden the computing environment. More information about the entire conference series can be obtained here for CoNLL.
CONLL 2000 The shared task of CoNLL-2000 is Chunking.
Getting the data CoNLL-2000 made available training and test data for the Chunk task in English. The data consists of the same partitions of the Wall Street Journal corpus (WSJ) as the widely used data for noun phrase chunking: sections 15-18 as training data (211727 tokens) and section 20 as test data (47377 tokens). The annotation of the data has been derived from the WSJ corpus by a program written by Sabine Buchholz from Tilburg University, The Netherlands. Both training and test data can be obtained from https://www.clips.uantwerpen.be/conll2000/chunking/ .
Converting the data The data don't need to be transformed because Apache OpenNLP Chunker follows the CONLL 2000 format for training. Check Chunker Training section to learn more.
Training We can train the model for the Chunker using the train.txt available at CONLL 2000:
Evaluating We evaluate the model using the file test.txt available at CONLL 2000:
CONLL 2002 The shared task of CoNLL-2002 is language independent named entity recognition for Spanish and Dutch.
Getting the data The data consists of three files per language: one training file and two test files testa and testb. The first test file will be used in the development phase for finding good parameters for the learning system. The second test file will be used for the final evaluation. Currently, there are data files available for two languages: Spanish and Dutch. The Spanish data is a collection of newswire articles made available by the Spanish EFE News Agency. The articles are from May 2000. The annotation was carried out by the TALP Research Center of the Technical University of Catalonia (UPC) and the Center of Language and Computation (CLiC)of the University of Barcelona (UB), and funded by the European Commission through the NAMIC project (IST-1999-12392). The Dutch data consist of four editions of the Belgian newspaper "De Morgen" of 2000 (June 2, July 1, August 1 and September 1). The data was annotated as a part of the Atranos project at the University of Antwerp. You can find the Spanish files here: https://www.lsi.upc.edu/~nlp/tools/nerc/nerc.html You must download esp.train.gz, unzip it and you will see the file esp.train. You can find the Dutch files here: https://www.cnts.ua.ac.be/conll2002/ner.tgz You must unzip it and go to /ner/data/ned.train.gz, so you unzip it too, and you will see the file ned.train.
Converting the data I will use Spanish data as reference, but it would be the same operations to Dutch. You just must remember change “-lang es� to “-lang nl� and use the correct training files. So to convert the information to the OpenNLP format: es_corpus_train_persons.txt]]> Optionally, you can convert the training test samples as well. corpus_testa.txt $ opennlp TokenNameFinderConverter conll02 -data esp.testb -lang es -types per > corpus_testb.txt]]>
Training with Spanish data To train the model for the name finder:
CONLL 2003 The shared task of CoNLL-2003 is language independent named entity recognition for English and German.
Getting the data The English data is the Reuters Corpus, which is a collection of newswire articles. The Reuters Corpus can be obtained free of charges from the NIST for research purposes: https://trec.nist.gov/data/reuters/reuters.html The German data is a collection of articles from the German newspaper Frankfurter Rundschau. The articles are part of the ECI Multilingual Text Corpus which can be obtained for 75$ (2010) from the Linguistic Data Consortium: https://www.ldc.upenn.edu/Catalog/CatalogEntry.jsp?catalogId=LDC94T5 After one of the corpora is available the data must be transformed as explained in the README file to the CONLL format. The transformed data can be read by the OpenNLP CONLL03 converter. Note that for CoNLL-2003 corpora, the -lang argument should either be "eng" or "deu", instead of "en" or "de".
Converting the data (optional) To convert the information to the OpenNLP format: eng.train]]> Optionally, you can convert the training test samples as well. eng.testa $ opennlp TokenNameFinderConverter conll03 -lang eng -types per -data corpus_testb.txt > eng.testb]]>
Training with English data You can train the model for the name finder this way: If you have converted the data, then you can train the model for the name finder this way: Either way you should see the following output during the training process:
Evaluating with English data You can evaluate the model for the name finder this way: If you converted the test A and B files above, you can use them to evaluate the model. Either way you should see the following output:
Arvores Deitadas The Portuguese corpora available at Floresta Sintá(c)tica project follow the Arvores Deitadas (AD) format. Apache OpenNLP includes tools to convert from AD format to native format.
Getting the data The Corpus can be downloaded from here: https://www.linguateca.pt/floresta/corpus.html The Name Finder models were trained using the Amazonia corpus: amazonia.ad. The Chunker models were trained using the Bosque_CF_8.0.ad.
Converting the data (optional) To extract NameFinder training data from Amazonia corpus: corpus.txt]]> To extract Chunker training data from Bosque_CF_8.0.ad corpus: bosque-chunk]]>
Training and Evaluation To perform the evaluation the corpus was split into a training and a test part. corpus_train.txt $ sed '55172,100000000d' corpus.txt > corpus_test.txt]]>
OntoNotes Release 4.0 "OntoNotes Release 4.0, Linguistic Data Consortium (LDC) catalog number LDC2011T03 and isbn 1-58563-574-X, was developed as part of the OntoNotes project, a collaborative effort between BBN Technologies, the University of Colorado, the University of Pennsylvania and the University of Southern Californias Information Sciences Institute. The goal of the project is to annotate a large corpus comprising various genres of text (news, conversational telephone speech, weblogs, usenet newsgroups, broadcast, talk shows) in three languages (English, Chinese, and Arabic) with structural information (syntax and predicate argument structure) and shallow semantics (word sense linked to an ontology and coreference). OntoNotes Release 4.0 is supported by the Defense Advance Research Project Agency, GALE Program Contract No. HR0011-06-C-0022. OntoNotes Release 4.0 contains the content of earlier releases -- OntoNotes Release 1.0 LDC2007T21, OntoNotes Release 2.0 LDC2008T04 and OntoNotes Release 3.0 LDC2009T24 -- and adds newswire, broadcast news, broadcast conversation and web data in English and Chinese and newswire data in Arabic. This cumulative publication consists of 2.4 million words as follows: 300k words of Arabic newswire 250k words of Chinese newswire, 250k words of Chinese broadcast news, 150k words of Chinese broadcast conversation and 150k words of Chinese web text and 600k words of English newswire, 200k word of English broadcast news, 200k words of English broadcast conversation and 300k words of English web text. The OntoNotes project builds on two time-tested resources, following the Penn Treebank for syntax and the Penn PropBank for predicate-argument structure. Its semantic representation will include word sense disambiguation for nouns and verbs, with each word sense connected to an ontology, and co-reference. The current goals call for annotation of over a million words each of English and Chinese, and half a million words of Arabic over five years." (https://catalog.ldc.upenn.edu/LDC2011T03)
Name Finder Training The OntoNotes corpus can be used to train the Name Finder. The corpus contains different name types to train a model for a specific type only the built-in type filter option should be used. The sample shows how to train a model to detect person names.
Brat Format Support The brat annotation tool is an online environment for collaborative text annotation and supports labeling documents with named entities. The best performance of a name finder can only be achieved if it was trained on documents similar to the documents it will process. For that reason it is often necessary to manually label a large number of documents and build a custom corpus. This is where brat comes in handy. OpenNLP can directly be trained and evaluated on labeled data in the brat format. Instructions on how to use, download and install brat can be found on the project website: https://brat.nlplab.org Configuration of brat, including setting up the different entities and relations can be found at: https://brat.nlplab.org/configuration.html
Training To train your namefinder model using your brat annotated files you can either use the opennlp command line tool or call opennlp.tools.cmdline.CLI main class from your preferred IDE. Calling opennlp TokenNameFinder.brat without arguments gives you a list of all the arguments you can use. Obviously some combinations are not valid. E.g. you should not provide a token model and also define a rule based tokenizer. The following command will train a danish organization name finder model.
Evaluation To evaluate you name finder model opennlp provides an evaluator that works with your brat annotated data. Normally you would partition your data in a training set and a test set e.g. 70% training and 30% test. The training set is of cause only used for training the model and should never be used for evaluation. The test set is only used for evaluation. In order to avoid overfitting, it is preferable if the training set and test set is somewhat balanced so that both sets represents a broad variety of the entities it should be able to identify. Shuffling the data before splitting is most likely sufficient in many cases.
Cross Validation You can also use the cross validation to evaluate you model. This can come in handy when you do not have enough data to divide it into a proper training and test set. Running cross validation with the misclassified attribute set to true can also be helpful because it will identify missed annotations as they will pop up as false positives in the text output.
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/css/opennlp-dev-manual.css0100644 0000000 0000000 00000011531 15217274217 027276 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ :root { --font-family: system-ui, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; --font-size: 14px; --code-font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --black-color: #333333; --gray-color: #CCCCCC; --red-color: #BE2043; --purple-color: #832778; --blue-color: #0033cc; } body { margin: 0; padding: 0; border: 0; background-color: white; } /* Main content holder. */ div.book { max-width: 1320px; min-width: 320px; margin: 0 auto; font-family: var(--font-family); padding: 1rem; } div.cover { text-align: center; page-break-after: always; padding: 0; margin: 0; } div.cover img { height: 100%; max-width: 100%; padding: 10px; margin: 0; } div.toc > dl, div.list-of-tables > dl { border: 2px solid var(--gray-color); padding: 1rem; } a { color: var(--blue-color); text-decoration: none; } /* font plan- serif text, sans headers */ h1, h2, h3, h4, h5, h6, div.toc { color: var(--red-color); hyphens: none !important; -moz-hyphens: none !important; -webkit-hyphens: none !important; adobe-hyphenate: none !important; page-break-after: avoid; page-break-inside: avoid; text-indent: 0; text-align: left; } h1 + p, h2 + p, h3 + p, h4 + p, h5 + p, h6 + p { text-indent: 0; } p { font-family: var(--font-family); -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; hyphenate-after: 3; hyphenate-before: 3; hyphenate-lines: 2; -webkit-hyphenate-after: 3; -webkit-hyphenate-before: 3; -webkit-hyphenate-lines: 2; line-height: 1.5em; margin: 0; text-align: justify; orphans: 2; widows: 2; } p.first-para, p.first-para-chapter, p.note-p-first { text-indent: 0; } p.first-para-chapter::first-line { /* handle run-in */ font-variant: small-caps; } p.no-indent { text-indent: 0; } div.legalnotice { max-width: 660px; } pre { overflow: scroll; } pre i { font-style: normal; } pre.programlisting, pre.screen, pre.literallayout { border: 1px solid #BBBBBB; background-color: #EEE; font-family: var(--code-font-family); white-space: pre; padding-top: 1rem; padding-left: 1rem; padding-bottom: 0; } /* * Java syntax highlighting with eclipse default colors * and default font-style */ pre.programlisting .hl-keyword { color: var(--purple-color); font-weight: bold; } /* Seems to be broken, override red inline style of hl-string */ pre.programlisting .hl-string, pre.programlisting b.hl-string i[style] { color: #2A00FF !important; } pre.programlisting .hl-tag { color: #3F7F7F; } pre.programlisting .hl-comment { color: #3F5F5F; /* font-style: italic; */ } pre.programlisting .hl-multiline-comment { color: #3F5FBF; /* font-style: italic; */ } pre.programlisting .hl-value { color: #2A00FF; } pre.programlisting .hl-attribute { color: var(--purple-color); } table { width: 100%; border: 1px solid #A0A0A0; border-spacing: 0; caption-side: bottom; border-collapse: collapse; } table thead { border-color: inherit; border-style: solid; border-width: 0; } table tr { border-color: inherit; border-style: solid; border-width: 0; } table th { border-color: #A0A0A0; border-style: solid; border-width: 0; border-left-width: 1px; border-bottom-width: 1px; text-align: inherit; background-color: #ededee; padding: 0.1rem 0.5rem; font-weight: bold; } table tbody { border-color: inherit; border-style: solid; border-width: 0; } table td { border-color: #A0A0A0; border-style: dotted; border-width: 0; border-left-width: 1px; border-bottom-width: 1px; vertical-align: top; padding: 0.3em; } div.mediaobject img { width: 100%; height: 100%; } h2.subtitle img { width: min(650px, 100%); } apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/doccat.xml0100644 0000000 0000000 00000017631 15217274217 024260 0ustar00rootroot0000000 0000000 Document Categorizer
Classifying The OpenNLP Document Categorizer can classify text into pre-defined categories. It is based on maximum entropy framework. For someone interested in Gross Margin, the sample text given below could be classified as GMDecrease and the text below could be classified as GMIncrease To be able to classify a text, the document categorizer needs a model. The classifications are requirements-specific and hence there is no pre-built model for document categorizer under OpenNLP project.
Document Categorizer Tool Note that ONNX model support is not available through the command line tool. The models that can be trained using the tool are OpenNLP models. ONNX models are trained through deep learning frameworks and then utilized by OpenNLP. The easiest way to try out the document categorizer is the command line tool. The tool is only intended for demonstration and testing. The following command shows how to use the document categorizer tool. The input is read from standard input and output is written to standard output, unless they are redirected or piped. As with most components in OpenNLP, document categorizer expects input which is segmented into sentences.
Document Categorizer API To perform classification you will need a maxent model - these are encapsulated in the DoccatModel class of OpenNLP tools - or an ONNX model trained for document classification. Using an OpenNLP model, first you need to grab the bytes from the serialized model on an InputStream: With the DoccatModel in hand we are just about there:
Using an ONNX Model Using an ONNX model is similar, except we will utilize the DocumentCategorizerDL class instead. You must provide the path to the model file and the vocabulary file to the document categorizer. (There is no need to load the model as an InputStream as in the previous example.) categories = new HashMap<>(); String[] inputText = new String[]{"My input text is great."}; final DocumentCategorizerDL myCategorizer = new DocumentCategorizerDL(model, vocab, categories); double[] outcomes = myCategorizer.categorize(inputText); String category = myCategorizer.getBestCategory(outcomes);]]> For additional examples, refer to the DocumentCategorizerDLEval class.
Training The Document Categorizer can be trained on annotated training material. The data can be in OpenNLP Document Categorizer training format. This is one document per line, containing category and text separated by a whitespace. Other formats can also be available. The following sample shows the sample from above in the required format. Here GMDecrease and GMIncrease are the categories. The line breaks marked with a backslash are just inserted for formatting purposes and must not be included in the training data.
Training Tool The following command will train the document categorizer and write the model to en-doccat.bin: Additionally it is possible to specify the number of iterations, and the cutoff.
Training API So, naturally you will need some access to many pre-classified events to train your model. The class opennlp.tools.doccat.DocumentSample encapsulates a text document and its classification. DocumentSample has two constructors. Each take the text's category as one argument. The other argument can either be raw text, or an array of tokens. By default, the raw text will be split into tokens by whitespace. So, let's say your training data was contained in a text file, where the format is as described above. Then you might want to write something like this to create a collection of DocumentSamples: lineStream = new PlainTextByLineStream(new MarkableFileInputStreamFactory(new File("en-sentiment.train")), StandardCharsets.UTF_8); ObjectStream sampleStream = new DocumentSampleStream(lineStream); model = DocumentCategorizerME.train("eng", sampleStream, TrainingParameters.defaultParams(), new DoccatFactory()); } catch (IOException e) { e.printStackTrace(); }]]> Now might be a good time to cruise over to Hulu or something, because this could take a while if you've got a large training set. You may see a lot of output as well. Once you're done, you can pretty quickly step to classification directly, but first we'll cover serialization. Feel free to skim.
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/evaltest.xml0100644 0000000 0000000 00000006656 15217274217 024657 0ustar00rootroot0000000 0000000 Evaluation Test Data
What is it? The evaluation test data is the data used in the tests that evaluate functionality and performance of OpenNLP. These tests ensure reliability and can help identify potential bugs, errors, or performance issues. The evaluation tests leverage the k-fold cross-validation procedure. This technique works by dividing the evaluation data into k equally sized parts or folds. The algorithm is then trained on k-1 of the folds and tested on the remaining fold. This process is repeated k times, so that each of the k-folds is used exactly once as the test data, and the results of each fold are combined to produce an overall estimate of the algorithm's performance.
Where is it? OpenNLP evaluation tests data is available at https://nightlies.apache.org/opennlp/ (file name: opennlp-data.zip) Here's a link to the evaluation-tests build on Jenkins.
How to use the evaluation test data to run test? The evaluation tests data can be downloaded and saved in the desired directory and can be used to run OpenNLP Evaluation Tests as below:
How to change evaluation data? OpenNLP Evaluation Tests use nightlies.apache.org to share data for testing and releasing candidate build. You can also upload the opennlp-data.zip to nightlies.apache.org as below: More information about changing the evaluation test data on nightlies.apache.org can be found at: https://nightlies.apache.org/authoring.html
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/extension.xml0100644 0000000 0000000 00000004413 15217274217 025031 0ustar00rootroot0000000 0000000 Extending OpenNLP OpenNLP extensions allow customization of existing components. Most components define a factory class that can be implemented to control their creation. The implementation class must implement the required interface and have a public no-argument constructor.
Extension Class Allowlist Extension classes are loaded by ExtensionLoader via reflection. Only classes whose fully-qualified name starts with a registered package prefix are permitted. The default prefix is opennlp., covering all built-in factories and serializers. To use a custom class outside opennlp., register its package before loading any model that references it: Alternatively, set the system property at JVM startup: A registered prefix can be removed with ExtensionLoader.unregisterAllowedPackage(String).
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/images/brat.png0100644 0000000 0000000 00002175546 15217274217 025220 0ustar00rootroot0000000 0000000 ‰PNG  IHDR |Zbv9* iCCPICC ProfileH‰•WXSÉž[R$”RBo‚éRCïÒÁFH„0!¨Ø‘EׂŠØÐUE×ÈZÅ¢`¯D”uÑ*oR@××¾wòͽΜsæ?çÎÌ7€¢ +77 U ›Ÿ'ˆ ða$$&1H=‘üœ�*‹-ÌõŽŒ PÆÞ—w·¡%”VâXÿÚÿ_E™Ã²@"!NáÙÙ×`ç ò ´C½áܼ\1‚XU @ÄÅ8MŠ5Ä8EŠ'Ilb¢˜{@V`±iÐļùì4‡&æhÃçðøWCìÁNgq ~ñ¤ììˆÉ›¥|'ío1SÆc²XiãXš‹DȾ/.bÄ×…™Ñ!2ßÇéÌð1�(JÌÙâ·©ÿ(© ¦‘-Ë ³f³$cÁ¹€yå¥ÇJ}±®0!tŒ‡ëë'å€q¸üX7 Î.Ÿ(™oqnV¤ÌÛÆÍ ˆ’Ö;,Ì�óíʃLZìI+8R6ֻܼÈ)7¡€ |ˆ`K9 ð:á?i�?`H\`%ÓŒyÄKzøð Àq�pÜÏGÒËùPÿe\+}Z�TIo¾Ä#<ƒ8×Â=p7<>½`³Ã�q—1?†âبD?¢/1�èO4çÁ†¬³`Þ¿Ñ…À7f'æÂËá[<Â3B'á á¡›pÄ�§’(2«Ù¼BÁÌ tÃhþ²ìR`Ì�1ܲvÀ}pwÈrÇÕq-`…O�™xãž07¨ýž¡hœÛ·Zþ8ž˜õ÷ùÈô4 šƒŒEÊø—aŽ[ý…ù]�8ðò£%¶;еaç°ËØI¬0°3XÖŽ�ãñ™ðT2ÆF‹’pË„qxc66u66Ÿ›%_\/aw^žx10srç xiéy o¸sA|¶õ$†��­â½]ºu ]“ìÙˆ¦ò7ÝÒ­Lu=ñMv€c« Üü¦3[÷Ç©\ÚÎ ò¥:ñv €áªÐºÀ˜Á|ì€#p^ÀƒÁ,Xñt� 9Ï Á2P JÁ:° T‚í`Ø‚# œçÀEp\·À8/úÀK0Þ�AH¡#šˆbŒX"vˆ3â�ø!¡H’ˆ$#i! ‘åH)R†T";‘ZäWär¹Œt"÷�dyƒ|B1TUEuPt2êŒz£!h :MCç hº­@kÐhz½ŠÞB»Ñ—è00yLÓǬ0gŒ‰E`IX*&Àc%X9VƒÕcÍð;ßÀº±Aì#NÄé8·‚s3�ÅÙø|1¾¯Ä÷á x+~ïÁ‡ð¯*A›`Ip%i„¹„bB9aá8á\7}„wD"Q�hJt‚ë2‘˜A\@\MÜJ¹�\NÞO>Mî"?'�È)É˹ÊEÈqäæË­•Û-×,wM®On„¢L1¥¸Sb(”e” J=åå!å/yyyyùiò<ù¥òò‡å/É÷ÈTPQ°P`*ÌP)¬QØ«pVážÂ_T*Õ„êEM¢æQ×Pk©ç©�©htš5-ˆÆ¡-¡UÑh]´WŠrŠÆŠÞг Ë�*^ST’S2Qb*±”+U)�Pº£4¬LW¶UŽPÎV^­¼_ù²r¿ IÅDÅO…£R¤²Kå¼J/£Ò™t6}9}7ý½O•¨jª¤š¡ZªzPµCuHMEmŠZœÚ<µ*µSjÝ꘺‰z�z–úZõ#ê·Õ?MЙà=�;aÕ„ú ]ÞkLÔðÒàj”hÒ¸¥ñI“¡é§™©¹^³Qó‘®e¡5Mk®Ö6­ ZƒU'ºMdO,™xdâ}mTÛB;J{�ö.ívía]��\�-:çuuÕu½t3t7êžÖУëyèñô6ê�Ñ{ÁPcx3²ŒVÆ�¾¶~ ¾H§~‡þˆ�©A¬A¡Á!ƒG†CgÃTÃ�†-†CFzFaF �êŒîË;§o6n3~objo²Â¤Ñ¤ßTÃ4È´À´Îô¡ÕÌÓlŽY�ÙMs¢¹³y¦ùVó먅ƒEºE•Å5KÔÒÑ’g¹Õ²sa’Ë$þ¤šIw¬¬¼­ò­ê¬z¬Õ­C­ ­­_M6šœ4yýä¶É_ml²lvÛ<°U± ¶-´m¶}cgaǶ«²»iOµ÷·_bßdÿzŠåî”mSî:ÐÂV8´8|qtr8Ö;89%;U;ÝqVuŽt^í|É…àâã²Äå¤ËGWG×<×#®ºY¹eºíwëŸj:•;u÷Ô^ww–ûN÷n†G²Ç�nO}O–g�ç/C/Ž×¯çÞæÞÞ¼_ùØø|Žû¼gº21Ïúb¾¾%¾~*~±~•~�ý üÓüëü‡œ $†®¼¤Äª  v ^Ü¢Rò$Ô"TÚ††‡m{nÎoŒA"EšFΉümqZä´ªiÏ¢l£FµEÓ£gGï�~ã³6æA¬Y¬(¶%N1nF\mÜûxßø²øî„É ‹®&j%ò›’HIqI{’†§ûMß4½o†ÃŒâ·gšÎœ7óò,­YY³NÍVœÍš}4™�Ÿ¼?ù3+‚UÃN J©Nb3Ù›Ù/9^œ�œ®;·Œû<Õ=µ,µ?Í=mCÚ@ºgzyú �É«ä½ÎÌØžñ>3"soæhV|Ö¡lrvrö ¾ ?“ßš£›3/§3×2·8·{ŽëœMs†!‚=BD8SØ”§ �9í"3ÑO¢ž|�üªüsãæ�§<�?¯}¾ÅüUóŸøü²_À^вPá²…=‹¼í\Œ,NYܲÄpIÑ’¾¥K÷-£,Ë\ö{¡MaYáÛåñË›‹tŠ–õþðS]1­XP|g…ÛŠí+ñ•¼•«ìWmYõµ„Sr¥Ô¦´¼ôójöê+?Ûþ\ñóèšÔ5k×n[G\Ç_w{½çú}eÊee½Â64ldl,ÙøvÓìM—˧”oßLÙ,ÚÜ]ZÑ´Åh˺-Ÿ+Ó+oUùTªÖ®^Uý~+gk×6¯mõÛu¶—nÿ´ƒ·ãî΀� 5&5廈»òw=Û·»íç_j÷hí)Ýóe/o÷¾¨}­µNµµûµ÷¯­CëDuf¸~Ð÷`S½UýÎCê‡JƒÃ¢Ã/~Mþõö‘�#-G��Ö3>V}œ~¼¤i˜ß0Ô˜ÞØÝ”ØÔy"øDK³[óñ߬Û{RÿdÕ)µSkOSN�=SpfølîÙÁsiçz[f·<8Ÿpþfë´ÖŽ !.]ô¿x¾Í»íÌ%÷K'/»^>qÅùJãUÇ« ííÇwøýx‡cGÃ5§kM×]®7wNí<ÝåÙuî†ï�‹7ƒn^½~«óvìí»wfÜé¾Ë¹Û/ëÞëûù÷G,}HxXòHéQùcíÇ5ÿ0ÿÇ¡nÇîS=¾=íO¢Ÿ<èe÷¾|*|ú¹¯èõYùs½çµývý'ü®¿˜þ¢ïeîË‘Áâ?”ÿ¨~eöêØŸ^¶% õ½¼}³ú/Í¿ö¾�ò¶e8røñ»ìw#ïK>h~Ø÷ÑùcÛ§øOÏGæ~&}®øbþ¥ùkÈׇ£Ù££¹,KrÀ`CSSx³j"ôëðü@“Þ½$‚Hï‹þ–ÞÏ$â@=|‰�Ü̳†Íä¬äÊ"¼ˆñ¨½ýx“‰0ÕÞN‹VItôMr°}‰ýï~ØMN÷Kï|b!Âóý[1êÒ; ~”w%lkòcâ pHYs%%IR$ðŸiTXtXML:com.adobe.xmp 2428 1626 AÛ�»iDOT-(--ˆ Þ\ïò@IDATxì½ œ\U•?~ªzß;Ý I' $�€�Ù4 ‹Bf\˨¬£ÂŒ££Îü>—ù� #.ã¨3*àFüÍ(*˜î°„Â"�”$ vw¶Þ»«zïÿ÷{n½N¥ítW½÷ªº;9/éªWo»ï~ï}çœ{Ï÷�YóÙ›‡Ž9óÝròyÊàà þ‰-†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`YC � ÿžÚø¸¼²éE).(’âÂÝ&ÑûŠD$òÔ}ÿ3tòÊ e`` k7g†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`ü%999òä#�É‹O>+U•Ó¤  _r$ê$á«§§gÈÈ^ œm1 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 C`" éëþÿ÷+ÙùÆŸ¥¼¬\r¢9ø‹Ên&‹Åøm‹!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†À$A`WÃN¹ÿÿ+…y…R˜ÏÔŽý3Â×$i » CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0’øõ½ÿ+�ÛßB”¯R�½˜Ö)-ÂW2D¶n†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†Àä@`ÓSOË/ïþ…¦uÌËÍÕ›2Â×äh» CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0öC §§G¶lÙ"Gy¤J$b¾öÈ~†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!0Y’§Ÿ~ZŽ>úh%|1­£Eøš,­c÷a†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†À}ôQ™7ož[„¯ØØOCÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0&7n&|Y„¯IÕ4v3†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`†€!`ì�À#�<¢„¯’’1Â×þØØ/CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0 CÀ0&á‹)�ð5©šæÐ¾™¡¡¡I@$ å^&C�ªK(€à"““°ê2Öu&îcÝ«í3 CÀŽÀ¡¢ß‚#eW0 CÀ0 CÀ0 CÀ8°ùÒC±Õ­Î†€!`L<‡Ê¼íDëYÃ9;}ÝpÎΓ½”‡~Ø"|MöF:Øï�Â(�ã¯[úûûd` _eH"ƒQ|Š�nÁñ ŸX÷XÜ;$C‘(ŽÅñ‘!Á¾çExt”¬"|sqÇò ½®G.×Ð J‹be�¿Ý±CøöÊ箜œ¨äæåIQQ‘þ�§(½:uwwK_/ê48€Û@9¸·tË罆UAù9ÑÉËËM¹. ]&lëþ¾~é&¬Ûxø‡Yÿ‰ÂŸýÅõ¡|)*,L©…¹]Â0 C ìÓoÐù}}28ØO+&°ýq0è?¿?ûËêžý7Qö�µ?°þoýobdž¿á?‘óÖÿ¬ÿYÿKoþÑì_³Úÿ�*ò—ÃæÜhnbÎÝæKÝøÉ> CÀ0ÂD yÞv2úŸ3mÿåDáÎÏ“âÂÔ|Û~±ß‡³ùÉ#�Cçnâ< ýôCìãJÌã/ެrsa7æ’«avãÈ>ä¾,Â×HdìwVèêê’¶¶V�òñ—RLBÍåp„ïÈXÃ\-�±¢ƒØQþ•àð. RÉ[ÞIܧ?)êô@�À@‹ñ†ÜÜ9zzR}Qþ)Œ‡âƒ$“õ)Q©§§W***¤´´4éœ}«¬SKk«H~®«OƒWî«|½2î7ŒúG@j¢T§t__�”�Q—}µ ¶ÖÕ LÚZ¤0¯PrósA:ËE;Gô/Ñ|Iì�˜õ÷Óþa”?„ö‚âí’Þþ^éíéC*—Ò²ÑûP¶j†€!0‰ ~S;:?Ž(ì¤IjhµCÒÿ¥ÿH¼÷kYý�€µ(ö¯õÿôÇ?öüÙógò'œñ·É“?éÎ?™ü5ùkò×äoó¿SEÿ òåhüõ÷è<5çK++Ë0ç^¦âÐ> CÀ0 � Lÿ³Ö/Có˜X„_;IÏöŽíÛö‹µù³ãÿen÷ /?_òAâË…‚p"‘œCbþ�T�Á�éçˆn}=ÝR^®F™Ù�|vzè!‹ðåWˆÙyÁhkk“x,&Å%e’_á¤d/ìs”lEr’›ãc̉BG⢒⢼-~ƒHÅ-dw2¨>U¸�^E.‘ž—¦GáC�çqXâ­K½˜GÃo^-Q¾F Bá8R…Hoo�Ä X‹‹ŠA–*ç冗¶Ö6éF¤²âÒ"ÝBuþÒëÁù$8¹’Ó+ßyŒÃ©¿F#� dþööôHgWmP$åû×e¸RWZµ�»1X/‘|Dc¤46pT ycãfý' ÿ!Y¶›Äè—V±.ô}°�I¸³Å0 C`ê!@¢WoÓ—”‚à��Þ.!¹[0ÈŠBÏÑn b úÏê¯&:‚³]ù™ªýiíO´Â± ëèLúÚó—Úø×ä�É“¿¦&jþÍä�É“?‡–üá<© pØ g4¢e÷ööcžs¦]h‹!`†ÀÁ�ÀTñ?gÒþBð�Aú¹z¶¯¯Wºb˜Ë¦_D™0óÿb¾) þ_‡s\Êà‡È+@Pø"èðø\=Øç?UE«8ã±�AmàgïŒÁnDô:X9Ô—dÂ#ÌEb±˜›>Ô‘±úg2Q;Û;À¼,—‚Â|%q�G6ª’°ð…"¢ã”Ä-b›NÒc³‹š¡/½O7%BÅåxvæA�¸xµÄ&'ëôò¸ ²Sò Ž%æÊH¥ü~¤œìîŽv)s´– ëÔÑÑ!ex ©iû¢ypør‡»¥ÐÊç-‡Uÿ>¼AÕÓ—D(!!«4QÞv‹¶30a$«àÝKSgÀ?Ìúûiÿ0Ê쓞x�´wtJYyÉp s»†!`†@æðt>ß aª^F(¥¾Ï¤ý†þ bÿXùáÙ_eXûû·ÿ­ÿ[ÿküeÏúão{þìù³ç�¶-¥ž]#%&;ó_öüÙógÏŸ{êìùËŽü¡#º‡/'s¾sÉÞœ» ?û0 CÀ0RD`*ûŸ3i ·Mp‡”#KɲX¥³úÄ;ÍÿK—‡k¤©ÿ;lÿ/Éð]°�œŸYFT%Sü‡Lö¿Tøé”?ˆ 6=àj´ƒ«QZŠŒZà8Ê˃>h¾å0ugŠÄ††F© “¹lsõI£`àfh‹ ¦Cƒ˜ÐÂxr�ѱ°cˆŒDlãF=LÇš8?˜ìÑ}òM(lÐ(_y¤¬þæºW®åf-t[ºå÷A�Ä»cÒÞÖ.³gÏÖ{®o¨G”¬J),±)Ä&,™*_«Rýû@`‹AÉ···ËœšÙнÞ|À¶s#0)C«¢ÂbäÕeXÉpð³þ¼§tÛ?ŒòðæZ<—¶Ž6ô¡9¡á°ÙìtCÀ0 �qpvLƒFÆ,@´ÏÜ\ºÜ²c„¡‚Ø?V>:GHö×DÙÖþÚ‹}ÙÿÖÿ­ÿÛóO91ão{þìù³çÏž?“?&'bþ×ôOöõOÒôÄ‘�/U×Ì®±ùRŠ[ CÀ0RFà`ð?gÒþ`*¼îîna¶ªÙsüûƒÍÿ;¶ÿ?,ÿ/q®Ÿ¢¼¼‘ÙJÀ§p/�ó�˜ üƒLÏ÷�ÄGÔºövúÙý÷ç”Ì$>0™ðe¾&qCL·†(rf¯)ó òAìŠB0!a"Sü) ËEç"­+¢éþHå"¥ËýÓˆ\ÐxØ«°( çéÀÜ.}Ïq˜Á,ö) ÌíÁ‰z�†¸Šßò»{z…aAË@\£Ð�1JVe¹²NY(?Ìú÷õÄ¥×øöIxa,®�cJìc·DË„†˜õŸ¨þ×�í-ˆWîÈ�aàn×0 CÀÈ,Ôo|SŒ„æÂüü¬ÛƒþƒõåÛþ²úO¬ýkøþ”°5þ²þgýÏúŸ=&Üˋٞÿ2ùkò×ä¯ÉßlÊß^ι··h´†°æ©Ù‡m1 CÀ8ø8XüÏ™´¿ã½ÝfÒ p¹o°ùñ,!8ÍXüƒ0ü¿ž¢m•WT�5þC&û£“…ÉÿèFnCpf_;”íÆ 6X„¯ƒ_ÅM®677K4Õp‘y9yp82Vœ°bº?�²Hþâ?òT±Cò¨Ó,ê`ub!q¾›Ø¯òlž‹o\f_È{œAŒŒŽØ±â³ü�¾~M…80Ø�{‚`�F0EþÜ\D÷ÊBùœà «þHíÈpÙƒƒƒRU]åÀøÙÜÜLrf¬cD< ÿ0ëÏö›ˆþ7Ð7 ]íÍ®ª*Ü6›�n†€!0ÎŽÉ�S �Ÿ‡£i«dÏþ8ô_ûËêžý7Qö�µ¿ÿñ‡õëÿa�ÿìùŸ˜ñŸÉ?“~çŸLþ›ü7ùO·ÐÄÌÿÚó—ýç�Ù(º:1O�h_6_ªÓ öa†€!�"‹ÿ9“öGß RvÈÀ ôluuŠÈî˜ùÇç„áÿmŸ"| ¦+Ì÷@ùSŒ�éù§>p5�Gûó!ìgO&|Y„¯ýå•ýÊ;wî‚p*–¢âb‰‚DÅÅ¡#¿8|×ß�ZJÈr»^TP†¸�iA cô/Fî"?Œi¹Ï ;\ ä+ey%®�œ�Jîb9œ`ŠÈA²À4ª˜¿ò‡‘Ê:¥»+®×*))‘RüEq#Ù(?ÌúB±wB vÇcrØÌ™$ð² í\Œ6.)A;#�#'·ÃÄ?ÌúOTÿcäFÑbÂÂ=pÃÙ CÀ0ÆD`ç.è7è¶²bä…�@¿eÙþ8ô_ûËê?±ö¯áoøOäøËúŸõ?ë7ÿaÏŸ=öüÙó7Qó¯&=ù344ˆ”Ž˜/íŽÉÌÙ§s�o; CÀ0ÿs&íŸAêYd¯`*¼™>ýÁ“Íÿ;Ø?(/¼ø‚ô!¸ÉÒ%§€{€Ô‡üÿaà†ÿ—8ÁA‰_ä=L5þA¦ýïÈÂWLb±®CÚÏ^WWg¾M6E*ÒÐØ(•H}È|³¸gåÁ[J¢—ò³¸ 'áå¶áqeÄ/ÖBšGê>žÇß<‚d°„¸^H�ÅöA°x¼;kŽ8†ß.Ü"N÷Q>X^J’êìêÀý ¡NHíTX„¨V‰º.?ÌúF2`ÛÁꮩ™E@/ RŽ—¥…pˆS·†Œ˜õ÷Óþa”ADµN(¡�¾jf…ƒ{à†³ †€!`Œ‰€ê·ò )y�&I¶í�0ôOûÇʧ�Š.2Aö§áoø[ÿ³çÏäÕtöÇÿ&Mþšü5ùkò×ä¯éŸìè_¾®ÝÙÃ|i»ÌžUÃŽg‹!`†€!�‹ÿ9“ãO‰�ìÕ ð,ŸþàÉæÿ}éÅ—e÷î]ʘ1½ZN<éä ç„áÿmh„Ÿ|ŠR�¾8Íÿ!“ý/lþSD’ßСýùе“ _á+%uaA€Ä¨F�*ª*¥¤¨X§i)Õk†}*D’ÈY^YŽìÏÕü®<–/œ@g+¨[Jºbœ0‹Èùb 0²Ét¿r½ÈóäYÞ5Ü0=Hù�ñ.immÑò+++Á´-ÊjùaÖ?Fw+ÂCÎ9üpvßßlçz´ó´Ê*�ðÅ6@ÞÂÐñ³þÔ–ÑÿbñNiii“ÃgÏö�·�h†€!�ÔŽ©OØ1ˆò5QöÇÁ ÿ‚Ø_Vÿ‰µ Ã"Ç_Öÿ¬ÿYÿ›¸ù{þìù³çÏž?ÿLÌüód”¿÷Þs¯¬¤‹‚ÿ1?7O_ ®„î¬F*ÅÂÂ…ŒîSçÔö|×wà_&õ?£!µ4·øòO6ÿïë¯ÿQÞxc‡ÎÓ“0_ôsŽ�··¸N,ÿ ˆÿ—874ÖKÕ´*)R>úEù™ìdgxKý?ÖÕ)ÍÍ­èÏs¼Ërß$|sÌ1àd *Åb±}(rpX…3�€PŽT E†�r�ð�ðB0.DÝ¢"£Vºª>ö2qp$Ïç mw0Bõq;w¾õ‚Jö‚lwQôâü�}ܯÇ+?†ÐÒÍ-­Zþ´iÓÄÕ‰÷‘�òùvaXõ�ƒðÕòÚœš9À ÷`Ñv᫪jš¢�‡Û+\üìÿDõ?¦slî³kfÆ=@“Ù©†€!`)  ú „¯iÕÐox³f¢ì�ƒAÿÑÒpæÒÔ³ÿ ÿðìω²¿¬ÿÙógò£â)8þ6ùkò7¬ùëÿfMµùG“&ÿ&›ü»õÖ[0�•3Ï:SN?ý4‰F�Þ!Äùß"|µ¶q¾4øþæ–}‘Èô \*Lû… ÊŒêéiõ?ž�ÓÝçê’-˜ôÍ0¬lC¡²CÀ0&1ÃúM£zRç;e3Òþ`Æ“ÿZÍ Ù?V¾áoý/ñÀþ²ç˜ü°þ1&ÐñeBžhü¡³±$'�ü™^U Œ&Æþ âÿ%Îõ|ñ|Šbd›ÿÃÞ¦fÙ_|Oo�ã è\"z�s‰aNxá·ëˆºY{dbþ+¿ @އo½¾õ0ìO4ÿ"Ö~C ìÆ9þý쯿þ:o}Ê.;vì�yóæ)9pÂ"|õ€´ÑÔÔ¤d/’ºHðÊÉÉq�вS (Œ¤+’¾8�(@GÉÆb÷ÊlËÆz(Üj† dÎYŠƒ„@`[³(ý™Ø®�.Ä2ÉN2„ÐÙäCCyAºq ;HB¸ð·‹ Åã›öì•5k×J<Þ­‚ð¼óΓ“N:‡àxœ;„k-Ÿoµ@ˆðž™¾°¸Ø³Üýòú®Nž ÖûM¡|†ûüó[o±rÍÉ•cæ# _Q~¦^ìK«|*žæDøòÁèÖz%}h;#·pe¥#|¥[¾m«ýâí¿qã£J Õ"µý]]�bAc ýÙ´?á[±p»�Ø©G$ºŽnô¶ñ¬áíXå…°A6�uæÙØ•ZÿK2¼[á+ÜÝ�Ú§!`†@¦ ~kÀ›5Ó ß8ÐrʆŠbŸý‘ªüÏ”ýcå§gÿ°¯¨½€fÏþHÅþ4ü ¿ö¿õ¿±í{þ ¤Æÿšü1ùcòÇéô°çLþ˜ü1ùËñ�æÄd™N”Ùø‡ƒÁ ó¿SÙþ»å–¯*áËÍß:ù{Ò‰'ʲeïÑT2Açß»b�xA‘Gæ¤yÄuXû4 CÀ8ÔP¿d–üÏÞø» Ä©_x~è8àv¾EΧë,†ÿ÷ä“OqóÍ)ø¿½ò9§égüGú¶k|¢È´ÿ7•ñW¾ù§ŸyFy#Ç/<^æÀ^¨­­Õ&X±r…44ì”W^yEù&§.]"%¥¥2ÿÄÿ«~dÒš†LZÅàSL„ÿaã#�¨/žÃ¿þ÷‚‚|9ëlúÖy�ÌÌ¿ó9l¿Á�‘·Åå` |MhJÇf00÷îÝ«Œ3Fñ"Ã� ;rò’¼�Ñ¿HN™Žp‡UUUɇ…¾n÷.¤l×ú†z©f„/:JAÅÑymo¨@n¢VÓ8’à¦Àèèƒ�Q¸Uõ@lrç¸_wú;*{wï‘5w¯‘(-NÌäçÊ•W}T*Ê*ö ÆõÁÊ�#ÿr+Ÿ,¿ læÂ’"Ü+T-6pЯ÷� —éFå ‘¼†:ŽQ~OO¯üñ�¯IjŠúç"ßêüc�•BÆTêï§|et#gs¬×[eÚÿ›Êøï±'’©Žš{¢ @‡¤n}�â¿rÅ ý~ýõíH±¹ÁgŠä]ï:C]Äڽà�8ºÿ9•òSµ¿‚ø‰s#_•à” “ÖHÿw6æÿÕÇŽ~¼QÓ*�z4þCkk›>|ùŠåÅ?ÆþÜD~ƒÿ<ƒ³LÅå±Ç›¸_$zuvvj¤.Fõrp|)ø˜î‘‘·JÁÊ$ñ+‹Ý_ø¨+¤?t©þè&UY<œâ" ¨iõ਋2õ”�S—Ô„Ì»{ã‘.RŽ�"¢£c­Y·VºIöÂ~¦C\}ée2ó°™8¢ýGÏÓK+Ÿ$)¾mÄ{¨®®@ºÑbGæÂe©/T½Sac+n%­òc=ݲý�Û¤á@yÇ9¹9rì1ÇH!”ÓXõW2™�ò;Á@×�‡!DšRE„P“•hçâR¦tL¿þCc´m·ÈÊËþ¢ý“ë_Kb°X¾beÚø'—¿¡n{š¬\¶|Üþ—\~*íOòj+ˆv5{˜-†€!`™G@íD°dg¾YCýïÙéÊÞ-m/ÅWPûÇʇuçÃþ1ü�]lý/ØøÃž?{þ ùÇkc‹ôJžTΜ!ʼnñ÷Tèÿƒ�{dwK¿ä–UÉôÊ‚aýËí{›$/†UWúš˜ õkþC¯ƒÎnö�ÙfÿºùG{þMÿ úŸ>˜'ŸxBü øcÔAí¦ç9øÂ 61ÿ­ëîÛ†d¢}­ºø"·;±=�ñ¯f¢hƒãÎGª©ÌÏ X †€!`“�løŸ=ûo ¯_žzú)‰wÇ¡ë éÿÅÕ"\Ðú­Ûô¶óH˜ad gC¸3" ‚4ýßEEÅrÚéï„?8×]/Cã/‘Ú@øªñIøjÌ ÿ—ØpQtPÿçžÝ$Å%Ųàø8ÒùŸëj×+î+A.RóWغu«tuvÉâ¥KõzÙžÿ âÿõús%²‹•–*ÿÁëAùÉþï±øëkëÐm#²rå2_å×Á—O»p|ôlÏLáÏll­ÍMèÏÁS:NeÂׄDøjAhµÖÖV�ìÅ\’ì¸#o›Ý+y?· ‚ÝÇ¥²²Ž·iÉ»¯Ûý†pÔ ¨€bHMDf+‚0V© ɤ¬P|³P9‚ëƒï„r„0Ak;‡(» ÿ<�ÏsX…>¶5�D¸ní:„ÏŒ¡ �U(—^z)È^³p/Î ƒ†þÃUw-ÿå“Í4ˆ¼X%Â*–#¬"Š!;›å«ç óQ~ $,’¾ú´þ¹Hï8ÿ˜yZ/V›å$×_³Ïòµ.Œðá«í\ÅP“%ÄÄ_ýY7*€‘í_»D.lUÂÖ¶l~Õá‹mü·páqŠÝ(ü^áEøâ}øh5ÐŽ+–ƒð¥7…ËòÊ!௑ÕZÀ¤Ÿ�>“ÞÝ…}†€!`d o U…7Z”¸½¢*º&Lý ýÇb¸„¡h—„e±?´.¨pûÏÊ·þgÏŸ“ aŒ?LþËQÆ&Eâ[ï�éKnÔáÐmOî–�ŸT X¦‚ü‰É/®«–¯…]ôMÙõÌǤ /–E"q¹÷Ú*ùð]X?Ñm/Á„„µ?[5µù—©ÑþáÍÿ˜ýÞü“ÙÀÒì_³ÿ!mýÎgKþ¶µ·Éºuë��e�ŽC?ü9áÄErøœÃåŽÛoG@8¬½ùoÚX¢9Qy×gʧŸ&¹yy:^Vã!Íñ'w-­áÌSë�Ù‡!`†ÀA�@¦ýÏÉú÷¥—^–�»vSl¥]—Ðsšf[9_Ì}Ë´"yþµu«rtóœu�Jx¢ÈÌš™²è„E�ÿíBt²fèÙ9>ˆÕÄ9“þß„I‘výëÖo€ƒÀ¾ˆ¿›àÚÿlÏ?ñÿjn¬¦JÉmÉýoªÌÿÕ!( çXV¬ /ƒãŸ.p5˜�-ˆŸ}ªGøzôÑG5ÂW 8äPE@ â#�Ñ¥»»[Þ|óM)//×ü©ì´Þ’¼îmKþN&q�o™´··Ë‘G‰èJ…ɇú^·ûó ݸ'zjÒð#!ž*D¾$¢+�Í<ˆ|éâ¶Qññ'?à\å$<6x=‡§ïÙ³WÖ®] Fu Û#R„þ°ú’Õ2s"{ñýÇëã,ïDlçõ¨`IJ·ü®Äà“§³NêüÕûb‰ze-5Hù,cÇv�¾ðo<77OŽé«d6¯,‹?ô·Ïò»º:­Œ!ý3`y\´�j’éIì RÿÑÚŸ¬b¶(7—­[¶²Tüs%·p¡â_Gö1ðX±|¥î%>~Ú#…aQÂK¥ÿ¡þ×òÜ}¤Öþ1D¢k…aUSc„/Âg‹!`“ê7 ¥L;FõîÖ§üW-áÓþP}ƒ¢ÃÐÿ~ì+ßõRÃßú¿=ÿþì_“³LAùßýêíRµøF€ßxj—|bQ™¯ñO¶Û?í�;/™)×ÿ ·¾ê{²{ÝÕÂ;�H»Ü±z¦Üð+Œï.þ®ì¾ç*)…žmüæø/ÝúG"]òÂÃOKCW�Ì>ñ\9épޝMþšü5ùëgþ%Ýç�ÇOäóoåþÙÿZZZå'?ý²³tè‹ö^x¡Ì=ê¨áñï-·|E 4U'Q/a9zîÑrÞùçé‹Þ~æ_iqÚž…p¾´™Ž;‘Gx[ CÀ0=2éN´ €ÃsÏmr9ü…ø¯ ÖôÛW.‡o2yü_·Ù„¼�<’º4Y™ªý)Hí¸DèFw³ïÓÿ;rþ—~t¾ñI3ÓþßÑìÌ™:“†q`ÚLmàQ�W€Õ!af(⿜�;° $lyüHòÿG„(šã@÷šÂ³?¶¿ƒø=œð¨‘ßÂlÿtù,ÜOùÁqÅrfëº>ùã•ß…ll Î$øÁ@øÊz„¯Aø ‘ ¥‚M=t¶6Ÿ»Äwbóð—Göò¾¹ƒë$håäähd¢áƒ¬ØýoœSÙ¶t”j*$° uXA­£CjDUVlW\ˆ¤¡Ç@« à¯Ä>¬ê:™Ó{÷4ÉÝx㨬dž•_�'«/»LjfÍÂ%m+Q„Dq~¢´|FknmVÒ6£YB躻Æ[¤P¼Õ0Ê��ŒµmÛvédèl‘¼œ<9¤¯"’¾¨‰ô¥U¼‡‹ºú-ŸoN)£;¬_��R¥Š¨(tü™‹™í·‚¡9Ǩÿ†ZµÏ2(x¶…ßög„/¯×¥ÿÁ?†p¢öÆÇCÀ0&?´cê¡ß ó‹JŠBÑ¿:#àÓþ ¢†•sûËʧyÌþ²ö‡aeýŸæªÚøì©Žìù³ç/Ûò§{ËRÍ_xfo{b—\Ry ñg¶ä_Tºä®K“kAø:çû²û·WJ©Î`ûe3äÚ_â|7ˆ`¿Œ“À9Ž3ÿ�Íç/'¾Iί>GÆmžxëãòÔÍï0û#„ù�lõ¿0çŸ84Öü§*˜šLýŸuֶ✞ÕßÚŒù?ëÿá>ÿ=}½òÓŸþDvíܥѼV¯^-…ÅxÑ>Iþ~õÖ[¥ _ÎÒÒR9/å·À½€ëwþ5Yþpν%`¤H[ CÀ0!2åNÖœµyþ…礩¹Ùùa§Ò‹ÍÅÙ®\Ñ_ü�åË@>òlZØ2µðYª]‹ÔŽ‘ƒ�¸y nÄ´óð5ª«§Ë)§œœ1û/Ö…@-ÍRãÃLœë3èÿiÿïlØ)[¶l‘úÇñOñ^ 30óü¿uÌ …ߌ&EÐI6RLµ}pmIüÏËË…Ír¼ÔÌ< ?q• ŽÿƒøÕÑ>E_àSñÿ+¦¨?ªŸèc’®þÍèÏ/oÞ"}½=Š‘vZ=ž˜9¬[ã/ñçö‚‚9þ„…2½j:NÕRÛÚõèïX#ñ1“ó¿qdlik�Ñ@›©NøÚ¸qãp„/fVÌx„¯žžÙ±ceU”uà ;.ï{xLj�ìå}{»ÙçÎ�«�ÊÛæçÛî¯Àl)Ÿ£Š€‘Ÿ� ©XÓBPxB}€½@sc]ÛI¦ßU©¬bÁõ'ŠÜgSSÂK¯F¢¤ÊËÏ—K/¹v Îãõp]ȬÒ6h*_lÓ·ŒT�+?Ö(ßx¢Àª¹‰é y‡œdCi¡–O&ðëÛþ²$AA=ékÞ¼c@œ,rjÁ¼åÇ“ŒîÙþ"«Ì…í¬Ä>�ðU:þ.ï¯#| íC£ÔŸÆbˆaAÚ_•¯“`†'÷¿±ÊO¥ÿyiAý0éÚöi†€!�-œCB³³c¤R‘ÿAퟠúÇÊwv'm6šéÚŸ†ÿ�í/ëÿ™$¬ýÚ¿†¿áŸ©ño|ë�R½øḦ|ãé]òñE¥Xõ?þÌ–ü锵 |]Cb׹ߗ=\)LÝ•¹ ¾®¹ÛÏùž4#"þùàœsÖ9ÿñÿç†ç‡pÙÅ27ÿ²}º‡d/oIôg¶‚·[.0‡ /`ÄJRÿÏ/ÌGŸ=[Ç nGD˜Ò‘c´• >ò4¯ÿ¥ÊÿàuRñ¿Ä;ÑŸÛüE¬Ãmér0¾²ákÏž=ÉÓt~ì¬\F~'oÓð‘lØ{ëÉßÞ5g̘á�âëÛî/~ã�îTÈQURªÑ©t6Õ�ç¢*!’Ä„—J'4T0Cë�ôÌ¡E57ï•5k@öÂ[?<¸ ¿@V¯¾Df‘ÅIñAÉ3è˜Ò<'Ñå°'‚—�ÀžÖ¸…‰ÉBå«°FDʾi••RB®ÎéãL”ß%¼í�Ûdp� �‰œ£‘¾ €%•…Ÿßòc݈`tûÉÙÌ{I^¼vžFb_a) Çý†ˆí„æDu½¼¿[¶º”ŽÚ丑ã¯ø×2#˜ò+W¼'Pù3|ùÊûõ?OÑ8Ý熚d*Í9> «dÌmÝ0 C ó8ýÆ_•ˆ²‰PÊP»Aõ/bPãÆÝ@ßÕ a¯P¯óú´+FØ?a赨º¬|ÃßúŸZÐöü“?:¤2ù;ªþ‰o½C¦/¹AÇÔ_áëz¾ôéÙ7þ� ¶È^zUÛ“±ÅÓeˬ’Ü1Çß‘�VùÃ+[¥¾µãwL¾N›-Ç7_ªL$yüŸ¬ÿ¢}²ýµm²so›ôà>òKPÖÂc¥¦ÀIãÏH¤S‰]×ý ÷ Â×îûAøB‘œ.Y³¾˜ê„¯æû¯’ÂŽ½²yëkÒ듾üb9âØåè*8¹óÉå{ú?2Ð"¯½‚:óÞ1HÍ+:LŽ^8_jJsÇœhjØ"xkÞ Ü{¥>�^޲’ú_GS›ô5?!œô!y·yâÍÿO~ýÙÅÒ×�ù‡YÕ‚Yl݇¿’38ÿ1Zý­|Ã?Só_fÿî?ÿiÏž5Œ]lüEUãoþQåu ã?¾ÜüÝï}Oz»{å#ý¨qÄPƒ‰ÿO~òcÌËž�®g©þ {þ=Þ‰H ­$|Õ |ê;[ CÀ0 �±ðü’aùŸGÓõõF´©W¡ûx/4NþglàÈÀ-°ã ¯iÏ®@ U݉ù×:D�rGòøƒŸZ¯¥ê�¿Ýfú?¿@tdÂþq©“™/}=ëáœ)ÿïÈñ7S5˜3N?‘®˜ÚptÿûzÁÂhRòÿwvtÊÓO=‰kDpÜ \@öLÍ¿ñÿz8W"ÓHI2�$:Ê�ê¯ý Gùá?Ôið”ˆ,Y¼DSyÇÑú?¯>²üVDÖÚ´é9ݳ˜&—_[‡ìY€xùJDøÒ=¼2—pçcàN00T�€6Før-“òç[o½…LwQeO²³rá··îýÖ#>’�{®{¿ùMv'I0„Yìþ‚á7öÃJSý�¾·EÇ��zâag FJ(MÆ�A‹ŠŽ³¾ÍMͲví:¡ÀdW*Ù냺ęžáú‡ö-þÀŸ~é·ŸZ2@ù¼GFc:>–_]Y…ðÖHéȺ°,F3P>C@nÛþ:Þ¢BþaÜC.ÂO2½cqR'j¹þÊ׺ ÷timg„ô$ Žñ°ñ§’`“ªBÆÊ„šÔ>ƒmì Bø3#YòË•ÑÍÛð×þµµ⃈†|Ûz ¤åÕÜåô;Šrüàß…ÈjmH Z Ô$«m‹!`†@æ ~kl¬—Jèüb0¡üÊ¿öOXúÇÊ÷gþáØ?Öÿ¬ÿùÿÙó7±Ï_7"|U�r£Žín{’„/¤t„êõÆ¿zôNY}Þ òÒ(êø3?|H>ùiR8ÊøûÍGo—Oœ÷IMYÈÁÇyêÑÇØíÓ?zH>sÅéHÁ˜HÝ ã¯nyîžoÉ ý”Å ‰%1þþ䬗/^�7¡±™ã¿H©W3¥#®ŒÔ�»�ÒÑÝy'_³äÁ"—Kî;¯EÞwå—ö+Ÿô—ÝökùöõïFºGÞký=ý¿ãÑ;dõù7( %p÷ó�¨óç®8UIYzÛ‰ù‡®�È¿Þp¾|ë!ÇڲμS‘‹oþ¡|ý_/—#à ˆö¾ +§½Kq'»#u]O‘o<µ[>¶¨lÿLÍ?„=þ5ùoòßä?çÀñsBÒ{þù{ŒùOÓ«ÿ5ü_@šª_ÿö~™{Ô\¹âo.s:*¡<ýGýÏyRê¾Lé%|µ5JÍ£·i†€!`‡ k4 ó1•ó?HÿoÞò2æ†w*¦ÅÑÿèkØÄÁs5ñÁ¬AÉöo�`hbÑÁ–‚ø�%Љ…d/>8 Wd±û †ßxس}ë‚°©� IB7ˆª”‚°J�¹°!Ë0ªÉtm® �Ì]Ù« d/DöÙ‹¿óÆñDöb¾aAÕMô�>Eÿàd-þÆÕùâ°ïòõ¾pz ‘ÅZ‘‘õš–-Ã*f£ü®ÎNÙ¾}r»!vnNŽÌ›?O }—ßë–VDšš œ÷œ/? ñhdnaMéXý.þ$rqY¾ ÿ†,xפûÚŸ)Ùî+ß³,Pû×"(ùJøbÁX×]j¬òõP1Fý»õ�5æÊžJÓÝ”}†€!`d ê·†zè7¾Yƒ¨žÒ?,?“öTK`ýãÇþ SÿYùè$°uÓ± ÿðì/ëÖÿìùK_þt#ÂWÕ’©‚äëOí”OœX]Ç!uD^ºó9íÆµø•ÐCÇË òŠ#B9�%C7Ý-M_½HŠ“Æÿ¸ë&9ùºº#tü�(V¼^âJÔvróÿHûWVJ.·áçö{o–>òC=Âm:QŽ_ô’l~Åm¢þ]õOÉÚ«¹ |­»t†\Í”Ž |íùÍU �q|“µ— Õã}ª±ñµQ1s"îýeÜ=°¶ b}÷9M¥ÈŸÞøï•_+§Þ°V�Ð##‹dÎ{‰GÀ^ÐK±Î·^,|™óÑîMriõÙ b,UpÆÅ«¦É}¿Ü¸¯üËï�]·_.=/ÉU•ïUÞžÅkÿÇsMrÕÿãÓ?è¹2…ù'Ó¿Ú›µóyýŸQáÃJ¶æßX¦•àù/ôf•+cÍ?™ý�Ìþwüñß÷¬“?üñuyß{ß'ï8é$v­ yþãÈÓÂH –Áµ�}†€!`Œ‹@Xþç±ìÿçžÝ¤(�ã>ø#ì‘ߢCJþ†U¦.Dl[¹Œš}ãïº ôm&HA´¨q¢;—cH5xq¸³¿+PãÔ¥§âZDcW˜öwWœ™‡üd2íÿ‰m¼ D®±üïŒR¥þ`�ìÆòÿ“ðE,W,_PÉE ¼:ª!ÌØæðwÍÌþâÿUœI`D?ÐÏqkcÕ_o7í‡ÿ°�ÁSpî øÜýÔ}"+}èÉåoá‹8.CÔµLŽ¿;á‹\� ©À§z„/¾²šÒñµ×^ÓÎéJØaµŽøNÞæËmÞúÈo^§a~ßþö·ó0ß‹Ý_0üÆ^T}=B""cà6ÀÞ[A<’˜|ÀAHÙ(ÚU£zA�ª“°ƒùéÏ~ìXÔPž¹¹9rÙêÕRsøŽ<Æ‹ò:ú‡káx Ý —{!¾±ÍoùÐà*ó&�iI_¬¨ª–ÒB’زS~§FúÚŽÈvZ~aI©7ïXß建ËqKd¹°�”y\©Ìã°ñ' ž(“ðņ%þì':y•„? _lr§¤p�Ïöß ©!ÉøFîgíO®ý!�Æ,Ÿ&Úxý�i:[ZðÆš¾€¥-†€!`Ln¨ßêiÇT!ÂWqÑõO*òßÑ9`§.�6KÁþñì�0ô�•OÜ ëöü™ü1ù›ªþ‰o¹Cª—|’]Ñ¥vÉÇN*×ñ×Pão¤dþu|& J}ã—käªåó¤ã°]¯þVn^üÁÁIä–ëåæÓªp…AÉÙ}¿Ìý ‡s*Šþï½ÏËõç¿]ò1ÖÞ³u½ü3λKÇo'ʽ;�Öð0Ìôm‘Õ•Kå>\a(r…Ü÷Â×äÜ·OS2XÓëäOºXÖr (Wȳ-·ËñŒ †H^—Δ«Á²Š uã®®–Ò!l�2¥#_ ‚Q ­’Ÿnü7YµäÉ‹Äe[ÝÉ¢‹?Ï‚p½Ëä½/޹‰úû¥øØ¹ ËÈ rÛ}wÉ•ËðöíÙ|¿Ü¼ÄÕ™wò• –¿C�9ŒÜq×µrÂu¤p Éþçy¹ùüã¤ú?'þ–Ü~Óqr㽺üdk«\rd¾Î ¶>)—×,S ϹõaùÕMK%Úß/Ѽü¿ÿšý1þøÛìög³Ìþa?€¼±ñǸóχâøë;ßþŽ´w´Ë'>~½TUW:Ÿ_óŸéÊß®N8îZm¾TVû0 CÀH �°üÏcéÿ'žz\ƒÏð†8:ä�5AñâŠÛˆ݇ŸÎ‡¹Ïþv�`‘cœÉ£H²I¨Y7ôÔëq»€äS*gœqZFæŸ;»âÒÂWÍœôQdÚÿ;ÿ HéHœ”<—äÿ9þeàÇ(Scùÿ9‰ø¯ák4þÁÈòäYþhþç þ_õC4Ô#€Î4ð)J3:þ¯[ŒÑW(A1}ÿ7}ñh"œ:V<üIc£¨�žk0b#| ¬2Õ _?üðp„/ÝÊx„/#T#TMvü𼎹8Õ U |#–Ž) ¡ïÈM¥ UMF M©‘¾¸“,[üc¸DêÌŸüôg²³q&i©ýräƒï¿}ÌQÊÚ�‚ø£ê�‘C€ 1$/Ìÿ¼´Îèb·JÐJ³|½ \(ÞÝ%M-­´ˆð…A0£–e«üŽöÙñ¢|á>X~qi¢|ë»ü"|µ„4�V…æ±ËáŒ÷™CÆ=ØlÚ `±-¶"¥#û‹kòˆ,X¸@Ûº.AÔr‘¹ü·m"ÄçŠ ñÉK㸳ÿq� ~ö#ýJ³ÿÅЇZšY-}à ·b‹!`†@PýVߨßEˆðDþ±?ÂÐ?V>t·OûÏðnÿXÿ³þgÏ•Wêãß0Ç~Ÿ?¦t¬^rƒŽ¾ñ$"|�„8YCýòð—Ï’÷~1¹Ð­¿òX½üÝÉp'�ÿ¢»+K�þ�¼Œýrñ�d÷=—Ié@Ÿ<ä�‡Í_øÝ›òÙ³§ï?þýçRrÒu:þºô§¯Èí8F¢9òBí£ÒÐÑ+%'œ+gÍé,iüµçÁ[åÈ÷}W\%÷Þ-KŠ è£�²„/»äœïÊîß]‰ò�("|­¹l†ÛŽ]?x¹M>| HVIó/þ`µœù÷÷a®·çYZ:€õyè‹gÈû¾ö²N'ÜòXHm•Z½Y £»�¥s?à"œ]|;ê|…”bû¶{?)‹>ú#{¹¼¿SŽ~Ä�3üÑöWä÷ªô Øâ .’¹% ¥aŒ›Óû{Dú:CÖà⫾‰ÈeG ´ãO¿íÖø×Ê7ùoòÏü“ÿöü‡3ÿ7UäßWnù ôÛ€üãg>#yùÐSÁêë-·êËÊÿôÏ Q§1þb„¯f̹‰ÔÀ§ÍCÀ0 �C�°üÏc�¿Ÿzò)¾:u,8LÔ¢�» ÊìÃ~>ŽóRð?ÿ¹þ-Ù²åUm$Žÿ8>TŸ#¶””Ëég¼+#㿲gµ¶´� “~ƧLûGâ_§Q¢\ZÀäñ¿7þöæ\„/ø�eJÇÙÀ¿n#| �ðµŸ0NFðF–düÄÿ«ý©3«+á þ?þçTíÏZøÒÙÿV :šŸú3B—eÌʕĿ¨}×ÄË�µ®ð¹à~”u þ‡ŸòãèÏ-šÁ,ý¥zãø8_Y�ðe)ƒ¥LœìøyÆ�¾�£”D CõŸmž€MÔu&±Î�üäVUvb^¼io“ܽn�t"�'#Eó"òþ¿ú€Ì�;×¥Ûåùz!œË W^[/† Mì·|^“—gT¬ÖæV”9(U•URÂtƒ–‘ÉòÛÛÚå�; àq¨OnA®Ì?fžäc î·|¦§lB´²95 ƒÕð»h;3‡3˜ÇE…ˆ€2þ.g³cdzþ›_Û ]ÁqÍKÊø«‚GZ‰PŸAÚ¿ röÄåd7£}½ög!yNÓ@à”•.þ�À½ ¡&™ŽÔ‹\èw;Ï0 C ³8;ÆEø*)BJÇò_ÍÞ.u¤Z:XÇFgù¸Ï‘öO˜úÇÊWè ëöü™üÑq�ÉßñõS:2Â�üúÓ;åúEeP\�rÇe‡É ¿„09ñVùÓ37Kõ’R¶ �¿äwŸ?Sþúß™ìðby|ï=rJI»Üyéaò æ6\ôÙöôçd6ÓTàˆ}ãÿ>ÙÛ°Wúp�Âé52-{Æu¼t‡Ì|ç ®œ¦»å |E‘¼Høú´ªFøºJÊ8Žìçˆðu-ïÛ÷Ü"ÇsøééßþÍwHùÒ±ábyrÏÝrR æp½;@»²¡n•77Ý,Óqëû�ÿûåþ:CÞÿ-æ™ä¹ÿ�sdó®–¥Ÿº÷„­Ÿû‘üóÇ.”ãfUHîú?Úÿ{¹ºât¾pÎ7Ÿ‘»ÿv‘Ùf¹yö×,Ì?™ýI‰€eùÃCˆÕþògªpÀ5Ø^ü©×2û߯?‰~5†ü{R_ÿ(@IDATþ1Õþwë­_‘ÁþAùô?~ZòM2Hÿïé핯ýß$Q>÷ùϧÕÿcÝ |5ažÚ^�¥Ô°Å0 C Âò?�eÿ>óܳÒÖÚ¦F�Úw°ñ4…ìr’‘N]²TÊÊ+p·ãÛíêñì¦M20Èq«35ËV©5¥ã¤tÌÀøG 2 VûñKfÚÿ;ÿõ®Wÿïr’‘ÆÿÔÕÂ� ì–“ð5þ ðÁ´™Œ:…Ãy$Lv¬%ø#Ë‚ÿ/qnÄ‹ç•Õ¢~ÜâXõgüò6 «Ïe–+?õ_ïEWÓaì½®ÿ{©¼%“ö'R”¶’ð “–¾Ðlé,o½õÂ%GALÁ›“dG`á··îýÖ#>’É\÷~ó»ˆAÅ#Ž8bÄYéý´û †ßxh³�륾JAráœùðãQ‡0‰r"„ýB¿ð�™²?)gÉDÅú#G¶æšµ$}uªòË�2]õþȼ£çª�æDô þi_aÃo®“±ËiÚ(úK�òYHgŒá¥[´üi• 71Úv°ggªüöV�½þ´]†0‘N3 ??OæÏCú’½´Tåw1„'Ò¢úat³y’¶scC£TLƒ"*&!ãÏ<×ì5Ëš“+\'è#뿞J {š3Hû¯á‹–‚2Ã9™�þç•7Vù©ô¿ú�¥tdÚb†ÀäGÀé·zè·*è·âêŸTä¿Ó^éÛ?aé+ŸÖƒáŸ®ýmýÏÙ›Aí?{þìù›Šò'ÂWÕ)HéˆæûÆS»å‹J±¾S¾öΣå ðuî7Ÿ�ß|ì¤QÇ߯Þy�,¾~ DÈ*y„¯w”ì�[O=N¾ürDιå1¹ÿæ“ÝœÐãÿdùSÿû:ùõo“ͯ¿&¯7´ISS“¼òò+8ƒBÜ_dè"y$«w�Ái—»VÏ’ë~‰½ç~_vß•¦t·Ö^6S®Åv¹©×�ðÅs“溷þXªO¹uzH[÷ȉÅUFåk§#_D�ÏF�øØ;X*ŠÝþáÕ;¯•Sn\‡}ï“'öÞ+'öË`ÃrÒ_"6˜=<Œ7¹ì¦Ëä¼å§ÊY§Ÿ!5(#yþ#Úý¢\SÂNyß7@øúÄ z/1rüköGfçˆwâÿð|@¦ç؜Р˜ý“öü£÷¼Yû»äáaýßßüëd·¿¿óÝ—޶ùØß~\fV5,ïüôÿ={›åßÿ¾:¬o¼‘i¡SÅ:‘š§­IjBx1Y•®}†€!`ô„éöì�‘úoË–ÍR__Ÿð5»‘ ¾°JÿsaQ�œúÎÓ¥ 'gLÿsooŸ<ýìÓÒ ÿ g¸k±\’�8Rœxü nÁ–Ãö0Ç]¦ÒÒ†Hš5é¢È´ÿwäø§ŽþY¼XA"×Xö'�£uÆãÆòÿ×2Í |ÖËW"UÒø?™àá=²ýÇ*4þAÿ¯ëÏ̘6MŠl7“nù©ŽÿêHØÂÕ™Òq$þ©ô¿õ$Û¡ÿ/G–¬dþ…¶¶,ÃuÓᤋ¿¦tlCĺšô#Öññâ’iÂך5|�OäòË/×ï°?zè¡ì¦tܳg�Ä’—éüØY¹ŒüNÞ¦àƒÅ[¼õäoïš3fÌðóõm÷ ¿ñ@WUß •U•R r”NdBˆ$’0êéTfÌŸK᢬Zí&c�¼d¨RXè'úD r ¯[w·t´·)³5'’+«þú¯d¢]‘ M¢9Ö\8uª"û˜ä1hù]�� |�Í�·‘+«§II!ê„[÷Ê»üDöÚ¾ýM­…c.Œ†ùHãXÒ—V…û-¿ Ïe "M…*›í\ßET‰P“PDaã_"1^¾ )Aô#þ£ÕŸ¡>Ù“4\d€ö¯…²R—†³Ü×ÿ†È¼£üTÚŸ²Ë"|¡ql1 C` @ýÖˆ–•$4ÃÑ}ý“Šü§µà×þ CÿXù†¿õ?礣èIgüaÏ_pû×äÏÔ”?=¯Þ £gEä¶§‘Ò± ÙŸ“Í8[~…m}ïi¹ûÊã9èÆ²ÿøûÍû>+ /ýv] òÓËbyZ>4�ç‘kõ¼¬½ò8>‰ãŽÿe¨]~÷¥Õò×_}˜‡kYZ¸Élä² „¯{ä¤â~L*vÉ]ˆ&v :Ä®û¯–rêïH'"¹_Cç|Ûù‹3zA7ÿнQÍß„ë]¢¢tõKNüy¹dúYò+yÑ<#k¯"‹Çï?ÿð§û>'Ç]úíĽ¬““Œó±??)·}úïäÖ_½Œ_¸ \ÇM�¹:|åÞ—äï.˜?<ÿé}Y®©É:­-M¸~é +5Ú¦€pÛœ(Æwˆå··“ìµCÁaý …oaAž–Ïz±þ~Ë��Ñí7g3Û!yÑv±¯ª©;‹ CÇ¿v}‚ðÅ|À¨1ñ­þudjcïr(Nþúmÿ ë3œÊ –Æ~ýo¬òSiÿ8 «fŸ†U2æ¶n†€!�yT¿a Å”Å%ÅÔo£ëŸTäûƒ5 ª¬|æa êäLúö§á`ûËúfÇöü›ü›(ùÓóê�¥j1¢]Aû}�¾N,EôöVùÞsäS É9_¨•>w&äê_Ž¿_C´«“á ô.yÄ©%¥MòãógËõGä„ÏþFžù»qUÈäqÆÿ-�Þ*‡Ÿ÷%‰çLΑ/üè&yÏÉGJEa�”•VIßkÿ% Vrÿ*yjÏ:Á-bŒÜ!k�ºñ¤`¾ö€ðÅWÏ"Âí³�êÇ( ¾tlÉñ<Ÿ4F5cKAÄ0—–‘é*›åû.ÿð�œûÅZùÍgÏuüÿÚ×ÈÉŸ\‹«¬’� Ÿ-)Ðkzú·§¥Q^ÛºEž{ú1Y¿îkòË—X=D~²¹M>t^ê¦})‘“¾>¾›Íþ 8Aæ?Lÿó)2û‡�:»TäŸÎ‰’¿J´²ò ÿ1æ?ô¿Ÿ{Α´ÞvÔ‘ò7W\YK�ã¯ÿÿüg?—7ß|S.¸àY|Êâ´Æ_±nÌ—"‚§¥tTøíÃ0 C 2áiÿÅ»{äÑG7€ÄÈNÇo°(þf¼C:9zî\9þ[oü—<þؾ}›lß¶M Q=‡îdüã^“õàygžu–"[ZÆ]1DøR¿ä”éÝu ã�Lû“ýÿÄ=R0r�¾þ`¿þïdüëHNÆš¾�Hz.üžDþ_âÜ‚aå´jð)Š´o„Q¶öÈñOmm"¢ž�Ä?•þW‡óÙ—W�Ø…ç�A[ˆ'íÈ))8ø»¡úÖ­]ë"}¡Oä€ôµêâ‹ô "v1�FÁ­×àî\¬$]ëi–CÄVDÅâ3¬b „®²¶©àIúB�a”ߎÈ^;ÞØ�Ègnj;//_æ{ŒäçhýY>k…Ò|—OòZKBxÎñò· ‹¶3šV‚ØÉ_aãOåöT"J%ï�Ã)”�·<ö5™B‰e.u$$Ë_�ò•ð…”Ž0¥#ï¾>4S®¹F¤zÜõÀG¥ ú@�ØD=­„/�ÜÜõîFÄ0Luâ¼Ûqï7<ÌCn’WzXgÎ/°,7þ�FA&»é"Á÷b�[o—ãóxQ,,B”øÖ?ƒòê}ÿ"‹Wÿ›î»ø»ÏÈ:Dã9½¿—«+‘Òç)áëc'˜ý\c�ùœž„¿é?Óÿ� Iò‡,!ÜJHó?£?ÿÖÿ¬ÿM®þÑê»ßý®ð¥øË/»\æsž7ÿžŽý¿}Dz殻ô…åo¼)® !xºpXÿ¸ÿÇ9OÝŒLsÒO5Eo‹!`†À¡‡@¦üÏ#õß Ï¿(M{�Ë9u\¢h« É‘ Æ*Pyï8å™>½¿ö鿽Í{„çëÔ¯8Ðù�9–tD/’qxÞÉ'Ÿ¢æãÈò½ñ¯7þL;2Ê㙋~í+ß›ÿ‹Å‘½ª¹ ¼ŠôýÁ™öÿ*\Iö7Ó¯•ÌÀ”4þ÷[ÿº�lE"š•–§m—WRùAðâÿ%Î�àÓT(÷~vÜhõmþ—ÁSXÞ �êFâŸJýë´�ÉËE«c`Ê M .@žžÑñ·‹Xׂ”ŽþíF#|9‘‘Ö' Z|»£¼¼\rssµy`‡kIöêïïGd§v9òÈ#•@6Ö¹©î³ûK©ô�SEUYÅô‡$áG“kHo0=ÉÖÅ;³ø‡íøÓ¨L8ÿõ�ÂL·á×°p£ôÁ@±½½UÖ0½#È_s×{ÿû]zG �µ O0QÐЯ´ü®xi›µüiÓ*¤é�ÔË#fñúz{ÊoEä²7ßx×qÂ1 �‘ÿ!ŽˆuÍÎ$øÁ@øÊjJGí1øhð­0ú™Ö/Š4{ì¸#o[2ÉË;†Û1Gvdee¥¦Öñö…ñm÷Šy PõˆðU…_ʼnÁ"šžr{¸°/`ƒ¶;Ö©ËTáár%Ÿ¿ë%Å÷?65ÉÕ =çG·ËËÉW9þ”så¿»MÎ:jšL«©‘²\aúÏä�É_<ÁçßLÿL^ýöñÆM6þrê…š.“ò¿/Øÿüç?“†úM©xÉ%’b�¾RÁ¿+Ö)÷Þs¯Ô#ó�ÈþðGðÂŽên¯µ¼Øãßx¾Hø‚¾³ùR×îöi†€!06:o›Aÿs²þ}ùåͲsçNÕoî®8^ãO|ºÿº¯¬¬ ¤¯¥:¶{d¯N°Ñ…J‹Ž/ù�¤dgͪ‘E'œ�Qû'Î`& |ùñKºùñÌù@àáÙ @yéƒÎ?)¹ '9)yü¯m¡Í‚�¤ò“šÛ±/�ñWÿ¯âLÂøäÒè­¥Y>;˜‡£ëpnÃHÿƒKéŒás‰*õgðÞßrFM ‰áÝw*åÇ@¦lmf3ÿ~ö©NøÚ€Œgä”Àf'ï*ûtV–½{÷Jgg§†ték¬`Gdd/†.--u¡àÆ:Áç>»?ŸÀ�q”Ë9KG) _ˆ¼…mœ6�‚á¬Ñ. ¨É uLYc:¨ô„�>èÚSq$è¨C˜Ü!›zèék"}‘Dƒ=Ø•U­’ùÇ«$!^�§:vh°òc`�¶¶‘ðÕ4•EEˆöÁ7È{Ô›æoa’VùíÈ7»}ÇŽÄÍzd¯c%Qñƪ?‹óS~7"|5!TöœÞœòÑ4�1©ˆüÔ¬öwlc° �G¶rýUI¡±W ÂWºø'—¯zÍ †£D ÷ÆZ3p·_Úvöa†À$F@õ&½™šº¤”„¯}ö‡Þvú?YÿðšÔ¤bÿXù@ÀðW%ˆýiýÏßøÃž?{þùÿýRuú�*g¾Ž_ןTªãoöÿ–§Ñê=ˆâ•¼$ÞÞøûÚŸ½ ßþàqû�ÿÛ~ÿs©9í:›SþPç�\ýënDÿâ¾hïkrSÕÉòŒ¯½Ô#�w¿WÉ#MwËÒ¢�ðuÇj¤�$;ëœïKãýWj„¯Døºý’ÃäÆ_¡Üw'¶ƒðÅ™.,¯¾ª߀-«”@vRñÀðø³åéïÉœw�¨³ž™øÀe®ýÉóò�¾}xþ!¾õ^™qÊGô7u»êxÖ›úË«ÿå?“Ý·PJ0·áôŸ<ü/årá­îº8çEä–§wÉM'pN‹é?í— (ñð1ÿbúÏôŸŸùGv7{þ‚ÏÚó79Ÿ¿ŽŽvùÉ�Œ—ªÛ¥¢¢\Þû¾ eîÜyèònþ}´þ¿}ÛùÍ¿•v¼À\�Ì.W^u•”ÀÑ�e?ýŸÊü¬ sîö‚¬Âl†€!`©!� ÿ³Þ Æ_òÔSOH<Ö�M¤A?º‘$~b,éüÏÜ3äÒÌÁO]ÿçzÕ£z<Ǽ˜~ðLž‘"¤@>í´Ó%'dináÿæ)aØŸŒˆÔ—¿d¦ý¿nÌËŠºú×Ö>¨ëË–-ãÆÀõ÷ü½Ëè_Æ?.:6O<²ü óÿAü¿ÚŸëAøª‰§hxþ%ŒöiÓ—N,ÔçHˆ‡‡*õ¯Ýà_.BÎ$ˆ¸^ØüÞÕhõïêND¬ àg7—¢ëÿƒ¡I¬")$??íä=\Ú›†/œ¼½··W#{1çgUUÕð1™X±û U ¨z8Jƒo©àdÚ�Cq¥ÈeˆÊq�oèQ$ðÏÅÿÃ'Ö]¡°áŸ†b×ÉP�ù¬G¥DÂukïBèè62”ée—]*³?B£eéPxÐòIøjF\…¨e…H_Èòõ¾³QƆ'÷Ê›¯üN¼ µíÛ\}p•‚‚<�앃 ©ÔßOù±Î8ÒáB¤)§ðëá¯FJÇ .�ú�×þNù0¬ébä/®RüuÂ!Ñþ^ý™‹™ŠI™ß>ËoÃä¦MÏjÏ[¶bŸ0VÿóÊO¥ý»ÐW›Aî› ·0nÎCÀ0 �,  ú )IøbgêÿÑôO*ò(öO:úÇÊßþ4üi‡û·dzÿÜ#N”G·ÿ Ãßú_fŸ¿¾úßȪù”‡1ˆþÁ‹{åÃó ‡Çß|þúê—o}ñSòED©^8à>ûZ¹÷¶/È… «!#ð�н»6É7ÿÏõò¥»6ï; Ϲœ{�Üõå–¿Z23±Ý=ÿ‘ö­òýÿóò?z„GaÑѵ\ûÍä³ËZäý'^ŠÈ`—ƒ u»€“†ñ\þÚ•òÞ/Ý'‘+~&»~ø~)á)ƒ=ØþQlÿ•¶ïþᇤƒGîòæz^ÿo©<ñJl¹\žäõJö›è~ëIùö—Pç5/ã$Þ +èîýÞ¯ÿrÁñÓÿbþ¡ëO�Ëw¾þåK?|Ç»h¡Ç¯’ýçÏÈ'.^,˜ÊÅ¥ô.° ÿzÞ’»ný´\ûUÜ«‚8$ßxºI>vB!~Ÿ0ùlþI[Þôú³¿ù/ëÖÿ‚ÌÿÚóGµ�9ýÏ—ªñ Fëú34VDŽ8üp9áø…røo“²²rÕb��mòÖ[õ²ù•Íòç?¿¥ºmöœÃåƒø€”•‚ì½5šþÇ�cÎÿÇcˆ<‚ 1–Ò‘HÙb†€!� Ùò?{öG¬+.ŒÚÕßßëÜÀªð úp³xE¿¹CÉ/8‰Û9nÔóù’ r[b-7/WN]zªúÎݶÌÍÅánF$Í9sÒ�¤™iÿ¯B¢˜¸ú×­_¯¶Ä2¤` cüËÌPÌÆµ �Bˆ¿7þ§E¶ÿ=ˆÿWûsc£TUT€ðU¼ßüKØö_m|éø·téR�(–Nÿc6¿gŸ…ý9Ûˆ èÓþó‹¿ÇÕ˜ 2ìÁBøò2+f5ÂÛœ #u555id¦Bä²e´/²W“I^dË2ªWww7eR]]­‘ÁÜ2ûi÷¾ÃŽÒÊ*‚�“¢xú9'ºo¡¢Ã02y;„oaù°óX ï8™ÞO�OœÄ}]xhÝÚ5ÒÜäÒ;žuΙrÆ;ÏÐÁ¤j[£³ärô&R/Ÿ)E©Yþ´*GbS®×æ}Á™¨÷‹èe€G „“Yã•¿s×N„mÔsùLsô<¤sÄ3‘Fýùü¤S>ëâÒþC*|øp Ѝ²Œt†šL¯þãµÿc�>&ñžn\7ш1ð7Ÿ ~«É¤¿±Ü©ÄymîI®}€}ˆ›±[·óþ݉£ð³°(_Î>ëìD{&ÊÅ•ÔÿRÅ?†å͈¬ÑŽÕ¶Å0 C s Û1L鈔ţÙ©ÊU=TIÃKêöO ª¬|`hø÷>g5¡WÑ$òpña[ÿOÏþÞ×öü�gÿÓ*îš`&ÏkÒøw²<Ý-{¥¥?_J‘Ò±³¯\fÍ@*´°Œ5þîmÛ+Íñ~=.· LfTq‰g ?Zû÷ví•ö�<Éí드ÊH!‰ã|Ž¿ƒö¿îVÔ÷R‘“ö¾2©™^6îø §ãïna�srKeÚŒRÉîä¨ùhó˜‹÷#ÊØPÆÙ¹€Õ mž6YÚßµW¸ãÿÑÚ_«nõW¥míoýßž³¿2©ÿ˜ÞqÓ¦MòøãOH7Ò?©RVmíl3§á!‰ðŸsÀ§¿ët9uñ©’“Ç4ŽnïXú?!ÊÝ“Æ]]ˆÔ—ŸTS‰Û³/CÀ0 �C �áyÛ,øŸ=û‹úê…^”" ñ?È)'Ÿ¿9æ›Ñn´ñ¹djþ—©“é—œã#H¦ý¿#ë_ÇèSظ|Ò bÀtüS[»^í™å |9�0þÿ þ_â\ßÐ(̤U ÂW&Çÿ�>ö°0Ø’Ún4ë€÷p;à7ñçÂñ¾.ºŸòæmà/Ì/”³Î>Ë�Ì­äxÏŸ7ÿÐï”¶æ6©ñA`ÔúàÃ_!|“ÌÅ7GøÍŽE‚Àý‹Ä’½ø=‹Ý_pÔ=…[ Gi ^w…€À[€J‚r“Ö£’j És9ŠƒD)Š .N¢è)ø‰:¯Š�/ªpÁuqÃ??°þw2ˆIÑ /¼PY°Þx\Ðò»@’bT,Þ[%"M•&&¥Aîbù,�û/èòþÜçXå÷÷÷ÉŸÞø“VømG�g ßWýÓ)ß •=;@ÈC­ë—PDŒäVE”ný‰ÐXíßÔ´W¶nÙ*ñî§4˜$WgâŒuüv}Hâ·Û®mÂMøÍvÒt‡àx^Çñ\Þ¶É‚ éc]¦ÒÿRÁ¿««‘è:58Ñ·j‹!`†@ ~kD¤RµcJ‹¨-TSð¥jÕõÿxú�U KÿdÒþJEÿYù™³ 5ãB·?íù3ùcò—Z ý`Œñ·É“?:Ö¦]ÄΠ=&Ñotd�ÙùëÖÿ¬ÿá±³çÏäO†äoOo\¶lÝ*¯oÛ.»wiöΛ#òõ¬™3åèyÇÈ‚·/ÐTTaÈÿ.dÕ áË^�¥>µÅ0 C ²íöÆý}ýòê«[e¢1a$D×¢.©úgΪQÿ#¹žÍôüƒFøò™ñ)Óþ_‚—\¦`ä\Ä’ÅKddðõïgV°ç˜Ñ �´�ƒÉÿÀkÿ±ìï þ_õC4 ¥£úÙAÌ ÿa/|î[¶nÑMÎ?Ξo‹~3Wg�B±¯cÿ äø… ¤™ù{qVöÆÿ$0¶´Ë`6Õ _uuuš)nB#|io±�CU¸õˆüT])Å G)�F¥*ÞÆe8FøŒ‚ð…�X8Æí#@*N°Yy;z6Å‹6¤Wñhþ'»s‚†WKlòÂåq\—B8hù^xi °j¾ŠŠ‘¾0‹å;ñêU-Xý»º:A^k“ÙBn.ªð€ ¢žáí.â£Ú¼ááfý'ªÿÅÀ<¦‘î„ÙCÀ0 �Ì!à´õHMí"•R¿M„ýq0è?7J�šöŸá?±ö·áoøSÊ›ü5ýcú7Øø¢Æ¿¦ÿ9Koö�õ¿©7ÿiö—Ù_Ù¶¿¼ˆö‚,‘·Å0 C &ÚÿÜÚÖ";¶¿!MÍ{ݤ}ÖðSÓŽRß5¾;”Ð4}FµuÔÑR�LI\ÔÞÂ!Ùðww‚ ƒû­©™£þt½�?²íÿݸq#‚õáîèÔOØdŠ+oØa:ÄíÜ–øvNéã_˜W gŸ{Ë,ÿ ˆÿWûsƒ{ñ¼t²Í˜Jö ‘öØŸg×ø¬â—ðµfÍšŸœô»üòËÓ:Á_iÁeEÀPÓ «ä(,”¿ ­JŽÛHØ„pƾAìŒBPkä%lãF%QŽc » æùƒŸÎÜ pœç�e¤¿¹®2Ÿ%à”}FìÃ札¨,—Rt:Êâ¡Á(ˆYíb–'„�‹´®ˆ¦{ä„ §Ü?}#½tX�'„·NüÇ¥p-f‹—å�ý‚X×Ä�8o�,0�*æŽá¡é”?Ð7(]Bâ/•““#åeeJøÊFùaÖ¿¿¿ìWF*�ªªjxiB˜M:ÂËÊÐÎy¹¡ãfýÙ/Òmÿ0ʧ"êìè@ŸîU�1· †€!`dê·hnŽT”–ÁŒ€~˲ý†þ bÿXùkþ†ÿDެÿYÿ³þ7qóöüÙógÏŸ=5ÿiòÇäO¶åÏÀ@¿´# Å æ©«Cš§ÎüL�•`†€!08XüÏ™´¿ú©g™¹Jý’þüÁæÿ…G™Ne~€†ÿ·~úÊËË$„lñ2ÙÿHä“ÿÑc¢Õ à;ˆŸÝ_“A‚Û=L)�6T˜Oµ´ é�òó•ŒJo)‰^*)"ñ&O„9Fu UŒ…˜BƒGê>ž éË Q»@c4)½�‹íƒ q)AÌ�‡#Ô9«¹‘Iãfå÷v÷Hkk› ZæÒÕ:Áù[Xˆ†¼¯ —fý{z{¤½µmR*ELÁÂÂvîD~êÊÒ É/Êáâfýý´å÷vwK[{Hqe¡áBÓÙ% CÀ0Æ@@õ¢b–#=uAA~Öí�0ô�Kw�Jú°¬|Ú©Àn‚ìOÃßð·þgÏŸÉ*éì�ÿMþšü5ùkò×ä¯É_Ó?ÙÑ¿=½ÝÒÚÖŽ«Ã›§fïµÅ0 CààGà`ñ?grüÙÝWb5ƒuøõ›ÿ—Ü‚±ùaø™a¬é7+Ë+$/~ö,ñ2ÙÿÂæt÷u'ø Áüìá‹)™‰N£Áá!¥ ÃC c�UßX�A[9”I‰äæÑcF’V‚Ä•DÎòn‚T!F£ ís’†éAÛrëØÁù¼.ÿ‘X¤‡²'s�û•k☞å]à Ó)Ó- ¯Oºã|v´ÉœÙsxwœÅe`ÙK^~.ÞBÂÆ •fýûz‘Ê„¯6Öe6°R´µNA>´�를ù…‘î27mþaÖßOû‡Qþ@_?Ò�÷ŽV™S3'4܃´™�k†€!0>ªßê¥ú­øÿgï;$«ª´OwWè®NÓ“33L²*AEAQ7èÊš ¨kXWEÙß„®Š EPÄŒqW ÉC3Ì09çÔ9Vu÷Î}u^Ýwë½J]=ÓÃ|W{î»'Ý{¿÷*¼Wçð÷Éðy¨¾TãóÇܰÉ÷® ¾ÿ`þÃûýøÿÃyÿƒë×®¿Ã÷ü¯?¼þðúÃëÏ< = Ï?ñþƒ÷ŸCýþ“1eyú³ÏÜ«÷œºø�>,€@à™€À3á÷çñüþ•áß¶û˜ É(fóoÛ•þŒßùÕRà÷ÿjýþ+8ïÚµË$ ©o¨§xWMªÄÂ?ïß$+¬!0vvЬ1\ÏòÞ÷L!|¥RÙòŸ |=>Ò&þz{{©»«‡ RMTŸLfKþq™E~xQËo’Ò×È;“�ä}«F~�d²�¼¹‰@ÞÐaf®üûÇ3áóÏ| «ðûö_½ï‡ëûÎ?^ÿò:ÆõÇ×A™÷ŸxÿÃû_µîÿñúÃëï?òÌï)ò\.ût°Ðó?¼ÿâýï¿ü¾É¯ùÏuÅówy,ÏLå¾A~0ÏÜùy)g°ÀóRó@ÿ €@…)¿?�ç÷Oó{0ØŽŽðï’þ=˜+WõðÀ,e«õ9‹ß½ï2ãýû¯ü18À¿Cpö¦xÒãS˜ìlYþÁÑðüMèò½qD~gg®†ù�]ø ü½qRø |Uøf 7 tó‡KWG%ø *Τ¯Z.‹TË¥ÿ„Ï•#oñcÈÍ&³„ø�oùÇÃ’ûP¹;4w¢òr—›Dµç^nY"±<˜˜0‘‹™F£Cn^ÅËûdz5Çl£óK¢±áÑa5)ÎÌ44Àom‘lQùÀìèê ú3m…ÄÆ{ŠñŸÎQîü²Âjí_ö;Âìò†84ä‘×Ú&MŠÜ‹@S�&˜HŠPC‚ã,(Búª©aL¸ÿšû7–yþ«1¿ìqxd˜†ùÊ ÑP&mvÈìeÎþ@±Èç[g'�áRÎñx‚jcµ«•Ï7ùÞ1¶ïÕøüË÷Ì_½ï_æ? ß?pþåu(¯DnÀ¿¬û¼þñú¯Öý'^xÿÁû/¿£–ñü ï¿xÿÅûïá{þ‹×ß¡ý�rùFyx/†¸¢Æ WÔhãìª]�Â|Á?@ pÔ!p$üþ<žß?F˜è%d/ùmRÈ^ƒCC4‰nªrÅ!üþ{h~ÿíáÌlò;„¾’ò;ÿQÉUêøïhxþ9Ê<�~¾›É�”ÌäßÚ[«x=ƒðuÔ}D`ÃÕF@HHýýýÔÏÙ¾2œù(Ã>†5e…àÅd.S²QX3† Uëg¼ª©a�ü˜ã‡F$E>;aL’¿ìÃ5#4\1yx >æ§XÓ¸B÷?IÇ%C�_Èd1~ÃŒqÆ.É„%ìçbu�uO¼¯43M…=]éüÕÜ¿`%„:ɨVÏû(e/ŒHUšb"çZØ·Ãüç}™áðð¯æþ=®`yç¿ZóÇ8ó‹…m|(q¯ÊÉC €ˆDÀ|¾ñw˜�¾só,7¦,õ¿Tëóg"|ÿ8œŸ¿Ø?©­àû/®?ùê.7üÒç^òhƇCqÿü�?®?¼þðþƒ÷_|þàóß?ðýë™þýS¾lÇø?šŠÇTŸâç¥õÅŸ¹GÞ˜C€@ ÿwÉ úûóx>ÿ‘ï’µü»d<3¿IŽçï’>Îøýw\ÿ àÌ$¾a!õñã“£áù·p>¤œeœg¯‡ßÙAø y…ŒyÓš(­¹«ÔuN„=Uk/¥î¹˜ÝDÀ¤Ø«¡Ÿh¸WcOˆ€Ñ-ŸoÑ@€@ €@ ×¢ €@ €@ €@ €@ 0�ák� , €@ €@ €@ €@ P¾ ¡@ €@ €@ €@ €@`!ðŒ#|­X¾bt”®á¿QþÕÈ¿5ÒyMúÚ¡ššZ#«¡¶‘c¶dGÖ°ý¹g[6ÎÆàXµž üÆVl*ö2o­Qa~�Cþ¸þðúÃûOöíï¿øüÁç/¾àû¾âû·ùPÄýî¿pÿ‰ûo¹cÆó<Áó'<ÃóG<Åóg<Çïøý¿?á÷7ï7$üþˆß_ñû³ù¡¿¿ƒ�Eü ðOÀ¿9:øGO®XAK–,¡T*EµÌŪYþ$¾„|%.îkF­H¹w`��±ÌA-�„ÔÅCñ�ž_:,Cùc) ƒLärlTÆR|ÙAŽÅÑp ì‹ó3.À×^æ½AÞ+ä-Åë¼¼ÿ0xÿ•�|þx£øüÅ÷|ÿ’ ùÃ÷O|ÿÆýî¿ä³‘¿9âþ÷ßæB¾1òõ 7xþà}qôÀÀó<â¯Nr7…çxþ†ç�xþˆç�þwóÝÁú¸ÄóG†ÏåÛ$ž?z¯ <ÄóG<” ùÃóG<ÄóG<”ÏF<Äó×ÃÏZ¾|y�ðõ/W-7�AåQ(@ €@ €@ €@ €@L^ßÂ×Ä9X @ €@ €@ €@ €@ y„¯+þút^†¯Z.…Ñ’ŠSc²ŽëcÜÇ(“Tϧ eF¨w0C½ü78L]}i‘\‚e¶£i¯eBs €@ €@ €@ €@ PUF}~OÏGŠm{­†9LGs»wsÚl¿(á«­1AÇLKQ2^wDá5˜¦-ûú¨½w¨äuM{- €@ €@ €@ €@�*#`½äxtD_Üg `¹«†LÏ<¯À¸Êk9R•DøZ0­‘fLª7{JÄꨩ>Áį˜!Åê&V†¯Ìð Ék0�¡ž�!Ê ›uïé Íûz‹ž—£i¯EÁ€@ €@ €@ €@ €'”Ô5::bˆ^##ÃÜó±Œ-ÂWMM-ÕÔÖRmm÷ùKdGk+Jøš?5E³ÚH¡MiIѤF�øu¤ÖÑ;@ºú˜÷G´«½Ÿ¶îï‹\úÑ´×H @ €@ €@ €@ €‡“Ñ‹É]#ÃÃæox8Ã=ÿ é‹ÿ¤ Ñ«®.FµuuTã¾6–%}1 ì(-íh¾/^L���Œ ãñí¿®�”JÐñsZ xs¦´PC"fŽ�´ú‡2´ã@—Yöš]ÔÑçÕ±�Wõs”ž‰{]Í{íÌîU÷){fž£t‘ͶÍ7Êyí4¦' ›ÅµW�ü9‚×ÏÓêh—¯WÏ �Ju7º®üqP¢v9ÿp}nÁyË•ë<ÚçüURj|Ï>ýåÉuV·¢�ÓæÖë®3j^�”‹Qø(Wm5Šî·Ø8Ê/JžÛ—Z¸}p]ùó«Dý‚ö*Õ^­ËßOÐ3ç¯r�¡Z}¹ûp×î¯Vº~]mî<”ëçEÐxQq¢äùó«ÄíƒëŠÚ‡zåæS‰Ûã©6*n´\5Aû`|µÊáäÙåÆjå_LïÆ Ž5ªFÉÍ´Ë×%ê—‹§z•Dõž§ú矟 ^£³«>7�w¤ëËÉuáëS;틯'jž <8«FÏõ®Þç,½£ÜºJ݇ç�‡ÎŒ—›§˜ÞöË÷RïüÞöËiK�åïÅò´¹¸îQnž`œœÜõˆ»þž�;ñ¸Á8:[ί˜^=¢ìª».�-ª/v—êµÿœÜ�ÜÎ.(W¯(}´Üóô¢i”èÞÅ!*®FpísrÕ¨$ªß§ZçæWIÐ^gÑý³×(ÚçìƒqË׫‡ÛãFͽ�(�'¨W©önÜœ\5*qû`\µö¤rŸé5»Þ¹}ª&O¥9» >J®~ڻ뻟Fvûàú\mÔ¼ÑëÓÁ¸¹8ª�ê]?ÏΓæ|¢ãýÕ#ß>h—¯WÏ �Jó÷ïit�¹xQþÁÅü¢âEÉu�ÚçìT\WNïʃûRïàêUZüõ“³ôŽ¢ã59|J®~Úç¯+(Ñõª½öA+Ù�JÔÂíƒësµ9ÿ �FÕuäì4‚k¯ª�ê]?ÏNçQ¯üùTôWi¾}Ð._¯žA;•ênt]ùã DírþáúÜ:‚ó–+×y´Ïù«¤Ôøž}þúË“ë¬nD!§Í­×]gÔ¼)£ðQ0®ÚjÝo±q”_¾|$“¡t:MÙ!ʤ½?!~ áK]µLöª‹Å)žHP,žàqÜÀ4ÓWô{S4Vºz]Mµúpì4ºÎšÃP%jî¯VêGtßæŒqyIæNZ°`¥R)�ðuÅM«FŸwL›)Û8õÌì¥@h/™¾ös¦/)÷øÄ–vNû¦>íŒËѲ×Ü®q€@ €@ €@ €@ /Cý”ôþûihp�†™ø‹ÕÒ9§žDw<¶Žˆ³z%ê˜ôUO±DÒÏøu¸3|iÙIM9DR‰ZÂMÊm*¹„¯††Æ„Ë]^wφÑÅ3›)«£ùÓZ+‹>Á¼¶î뤡Ì0­ßÝMû»ýÕMmNÒѲWÓ8@ €@ €@ €@ €‡�¾ž.Ò×`/ÿõñqÍŸÑFï|ýËhZ[ ÝúÀStÛ£ë©>ÕHÉúÅ“LúŠÇM‰ÇššÚòz›èeŽ9ñ”'Ó Tœ]LH^òCöÊŽ«´Z%|½¾e9IIGÉðe_7?±}tRc‚¦·6RK*Y¥é¼0Ã#£4˜¥¡áQbþÕ1ö�ÉZJÔU—Íæ.º«o�övöRGï­Þé•x›ãg·ÐxíÕ]ƒì¹wp„†¹Ì(séÌž“±Æ º{�Ú«»Œ�@ €@ €@ €@ €ÀáB «}? öõPO7õ÷uÓ±³¦ÐGÞö:ÎðÅÄni&}õç7ÑÀH%SMLújÈ–väŒV‡�ð¥d¯ÑÑ.;9ÊD/îýc�ðUS[kˆ^µ¦çcà ªé+’ðuÏêÝ£qfb-˜>‰‰IÕeÃõ �Ðþž µ÷�P“ŸR‰:vJ‚ÚRÞ‰¯ (Ã,«Í{;(Íý£úÓœrìd¯½ú“dÚû†iã�!ê¥&¹µ¥jijSŒ1¨.ÆQ{u׃1@ €@ €@ €@ €8\ؽ�ú{»©¯«ƒ¦µÖÓ%ý %q9=}tí wÓ>æÕ76O—Gð¡‘‘a¦aþåc%ƒÕÖÖ™ dµu1Ò—Œ…ôU-‚š¾Îo~’–,Yb2|rÙëöÊÙâY“}Çz ™½8³W{ï0mkâ1L]#4¹±ŽNž×@³Zbc�¢¨ÿú]Ñë�uû}ÛS—L5ÇÕÜ«Ü9ØÕ•¡Ç·õÓAÆ ¥¾–¦5ÕѼ6&»1õUÎô¶Wg9 €@ €@ €@ €@�ÆÀžm©—É^}Ýôé‹þ‰Î�é¯eÝ–tíõwÐÅ©±¹Õ¾IÉðg•dÑ*/Á’W^ÑŸw „­œBèSnÕ¾Q&y Ù+CÃé4e2i6“éKìëbqþ‹™LdæXˆ_&áVu²|RÂW/göÚ×�¡��iÚÌY®ôfLIÇÙ“âtú±�L|ʱórÀU÷(Œu( _ÛÚÓtÿÆ^ÚÙ‘6%§4Æhg7›Ý§iÍ1j¬b¦¯°½ÐÌ• ˆ#¥Ú«�r¯{•»½úEÙWªW?�/*¾ê‹õn<µ¯4®Æ/ÿ±Æ×ýi_íxW{�¯ãJqQÿ±öºž¨uÓW:¿Æ-æµ®b~QñÝxQvßµWyT_,žëWn|×_ÇÕž7*^±õª_”�êuÝnåçÚ¹c�[©¿ÆÓ8:vã©Þ•«½êue§úböcÕ»ó”»õ×¾˜¿Ú•ºîbñ4N¥v¥úëºÝ¾RõsãEíCí‹é5^”�ê‹õ:ŸÚEÅS»(½úê5†mSn<�áú©\c»z•k¯öÅìԾԾܸåÚë:*õSÿjõº7^µquã—:¯õiÜbû«]©þЇÚë¸ØúÔ.ª×xc�_åÅæ)¦/5ŽÚ•Û—:¿·R¿¨8*ïó¡óŒw_.>¥Ú«�®¿T¼Ô/ʾR½ú•»µw{7žê£Ö­ú¨^ã�—ÿXã»ë®v¼¨ø*¯õk_l¿Åô•ίq‹ùWŠOT|7^”�®ËµWyT_,žëWn|×_ÇÕž7*^±õª_”�êuÝnåçÚ¹c�[©¿ÆÓ8:vã©Þ•«½êue§úböcÕ»ó”»õ×¾˜¿Ú•ºîbñ4N¥v¥úëºÝ¾RõsãEíCí‹é5^”�ê‹õ:ŸÚEÅS»(½úê5†mSn<�áú©\c»z•k¯öÅìԾԾܸåÚë:*õSÿjõº7^µquã—:¯õiÜbû«]©þЇÚë¸ØúÔ.ª×xc�_åÅæ)¦/5ŽÚ•Û—:¿·R¿¨8*ïó¡óŒw_.>¥Ú«�®¿T¼Ô/ʾR½ú•»µw{7žê£Ö­ú¨^ã�—ÿXã»ë®v¼¨ø*¯õk_l¿Åôóoßð4õt¤“Ϧ÷¼ù5¾Õ¦m»èsWþ‚êS-ÔØÚÆ„¯I|ÜDñD½!TÕÖ ü'óJ7ª à±uhH^Yì<Âäÿ5Y¡˜_)ÏÈŽò;– Ÿóá„W#ÃLöb’Wfhˆ††(ÍÍõ1êí¤¡Ìˆ!¤ÅIŠ'ë)OPŒ�kë¼”ö¼ºp³öaÞ·%c†ãšá+ÃL�rV« måÌ^»™ôupp”º9»×à`†æ¶Äé¥Kšè&>�w � ² œºôÐeøÚÂD·»×õÐv&½%ùD7sYÇÉõ54“É^ó9Ó×d&€%ã53µ;džF`¯J/¹^åâ̆7—oîÎJƒ�}ìAä‚úÉ(`Ÿ¯ö$ÖzŒ�³;nh<Ë? ·ä:u@¯B]·3¯ªý>$žêBãªR{w+ÞXýe ë½ÈÌ8£¥ž¦ðßÔ¦$¥GFè`÷ èä,{C$÷´)¾®¿êµW;‡­Wõnœ(yð" ¿~Ì\ÙóÒ˜ä×L}<àÖ=�¦^~©¨)Ùøy1Š�Ÿbú¼€YAóF…°å>Þn\w¬Ó«Ü’=œW¶+`ê{ûóû’ˆƒã¹Þ‘ñuqQç/H¯?7n¡±‹ƒ±Õy ìÃöÓyuý:–X¶�¿Žq}ñÕud…ו«�êe:¯ë#ÖçÏkéÃæ±×¡SìØß´ìþÂìE6ŸçèìÏZO¨^…Ž�_õÚ;v*¶ûÀ~TáìK^T*R“€Ÿ¥wåÆ>‹�§ÔuûvQóè¢t‘Ö|QóÖ©þQ½5¯kǽüõ«sH¼°8j®½Æ­4žúK¼RæÓyý“oœÂ?÷Ê�8UÙ¸îõQt�Ž�ùÁsëõqsôîþìuŠkãiíÇØ«ŸÙ«Úi`Uºò½ž_ŸY»(¹†±÷ë˲fê¨ùãRæ1./byqØNM�)½p/«Ìós™7°O�LãZvâæâ+2Ó¢ì,¹=OÔ:U®a¥·ýlyèq�õŒãú…/ ŒØ§ïQL¯†–�ˆ|¼£ÖçÊÝq6®�kY8Xë õsçsÇûRqäþ Ä1¾f1|äØé>ý¸:Q¥½ß�/òu1Ÿ®OÔ<�yl; °W¡Ûs %*;nh<Ë? ·ä:e@¯B�Ü(UÒ‡ÄS«Ð¸ªÔÞ�ÇŠ7V™ÂÅÍ>Ï¡úìºß<ÿ¬^;µ3±üTËç0»?7N”Ü?éYÜÕ.Ñ;*9žëXlìž×¾Øù)¦wã鸌yÕ¥PïããÆuÇÙ Q8‹:pZû+iþBF¢+1žÆßŸ«ˆØ_ž™Ú¹Šccš½N íÃöSœuý:–X¶�¿ŒñÑxê§q]¹«—qè¼jX¬�XŸ?¯¥›G×iO°Óód„¹÷Û^ŽÃæS7ž† Õ«ÐZ·ˆüøª×Þ±S±ÝæW…."»¯°ë'àgÍãÊMȈ8¥®Û·‹š§Àº£æ¬Sý£zk^×$,Ž{ÝøëWç�xaqÔ\{�[i<õ—x¥Ì§ó–ò¹Wn<†À´€_¹¸Xönœ\ðÜëÒÇ-09[†Œ"<ÄÎLâÉK²ý$”¿>Hsí=iî_G¯ç×�%÷q å˲\]¥3.eãRϼ8Ö'ñÊÞ¯®ÛŠا‚a­SEaói81ÔÎ’Ûóäí3Hå~\>°ýlyè±."dýã¸~¡Á #öé{Ó«¡e'"ÿüF­Ï•»ãl\ײp°ÖêçÎçŽ#ö¥âÈýˆc|­ók�uŸ~\�¨ÒÞ]GÈ8 ÒuȨëuÏ@~-éØŠ°·ä�Cö³]]측ñ,ÿ€Þ’ë|½ ur£TaHO­BãªR{w+ÞXýe ·È÷7]O¶W|óü#ìD¶Þ¨8Qrÿ¤gqW;gÚ¼}©]±õºqòÆîùp Š�Ÿbz7žŽÙoóê'¨»ã ýǯ¦ç¬jè¿¿q mÜy€šZÚ¨©u250á+Ù�¢“¨¤T¢§”¨EÌ��ÿ™W�µ9;b§å%#˜wÌ´å•hÂ׈÷'ñ\ kÊ2J61™“³{1á+=Ää®�~è3ý…çŸAÇ/œM›vì£åëwÐÃkvP‚×›¬o°HjLúò®˜ì…ão7ï@§ÏS°àþCAøê”Ì^iÚÑ1D÷Rÿh 5·5�Áöî飩Lx:si3gºJ†­±ª2%A-[›+éxÚ!$|m>0Hw­í¦ý£4mzŠâÌ6ì:ØO©ÚQ:vj’æLJp¦/NCÇD°±6ÝëÙ½Êõ'MÞôز2=v{×VôÙ÷?NXL;ŽÚ‹Ì�å«>®½ÄP�KsmTïÊ=ëp D§~jçöQñ\;‡ÅRÕé8Ì_ej+cµW™ŽÕVzÑÕ'êèì“fÑâ™Í¶Ê?ÞÏį_Þ³‘±ZZ:»Å— lå¶\ì@æ [C1?Ñ—ë+öÏ?v ½äøé�ð÷¯ÙKo8�•:¨tí¿ØúEÕÆ2oTÌjÊuí¥®3¯cRï°Y‚ú†­§Ôxa¾aq5ž­SYXŒ±ÊtžjÍ!ñ*�5–µ¨ocY�ëkÏãêÂæVY)¸²ÑyË™Sçv{�%òRãÙ>¶ŸÊ£âDé]¹;v×\ÊXb¸ëиê¯z•G�Õ¾”˜b«qÔ¯’^×t(ã›ÓÖÚ“î_íu\ÈGmÃl\µuåê+ú(�ÚHïÆ)æf/qŠÍ¥~b+͵W½Ê‹�½(ÑÿŠ¿Æ ³ Ó»sªŸÊu,}¡Ø¶�»þQ¾®�øª­êt,º±¶rcŠ}±ù ÅT�½î°xaó„Éì8QÇas†Ùê:Ô^Çj6¿-S?µ·{7–­s�Ý8¥øÚëpã鸒¸êk÷asÙ2�Ç]·Ê5–êUîŽ];Û½=¯-—c�«r7¾=Öcµu{7–«wýKYW˜�WÇ®­ÈuMª+4§m/Çê#ÇÒ¢|Ý9*žk'cw�"SÕéXtQMmE¯ö*Ó±í«:Û>JecÛ:–¹ÂÖPÈGuåúê¾ÜùT®qËéÝXåø[¡u�eÞrÖX©­®½’uªoØÜ•ÄÓ8aq5ž­S™úU³×yª5‡Ä«4ÖXÖ¢¾aØŒe=®¯=�« ›[e¥àRÈFç-gN�Ûí5–ÈK�gûØ~*�Š¥wåîØ]s)c‰á®C㪿êU5VûRbŠ­ÆQ¿Jz]Ó¡ŒWlN[_hOºµ×q!µ ³qýÕÖ•«¯è£tj#½§˜_˜½Ä)6—ú‰­4×^õ*/6ö¢Dÿ+þ+Ì*LïΩ~*×±ô…bÛvrìúGùºvâ«¶ªÓ±èÆÚÊ�)öÅæ/SuöºÃâ…Í&³ãD‡Íf«ëP{«mØü¶LýÔÞîÝX¶Î=vã”âk¯Ã�§ãJ⪯݇ÍeËtwÝ*×XªW¹;vítl÷ö¼¶\Ž5®ÊÝøöX�ÕÖíÝX®Þõ/e]a>n\»¶"×5©®Ðœ¶½«�K‹òuçð¬½U§²°˜¢såj_lNµsû¨x®�ŒÝ5ŠLýU§cÑE5µ½Ú«LǶ¯êlû(}”�m_èXæ [C!Õ•ë«ûrçS¹Æ-§wc•ã[lý…Ö%ónXñ0 övÒÕŸ½˜ê8 –´e�.§¯^}¥˜äÕØ2ɾRÜ á+÷²e ûm”“ߌȰ˜‰å�­3Qk^µÌת3¶„(VkÈ[<�.LÁ$®ááagÄô|Ì2iIŒcpIF‰#D°Lš3{ Ð`/ ôvÓ0gøú潃ñ˜ñy`ù:úím�RCc3—¡lbÒW*[Þ1ƫ˒Ќ¥÷O¹ø�+áËËì5Â…8³×�Ú%™½˜èTÃYz¦NKq ËÚ¾­‹&s%Ç—×J ˜ð4ÞMIP‡�ðÅ„·;×tÒÁ4Ñœ¹-cÂÍþ}}4:”¡)L|›%™¾¦pV¦&ÉôU;¦L_a{­ßE3šiÞ””q_¿»›¶ì«4üÆ�“ßþ’EÔ’Š.‘*Y¾~q÷Fcóî—-öW$Y¿¾{ój<ÑN !|Ý7—ì×vùg¹­1As§4ÒÜÉ)îS´e_/ݺ|gù�à€@ €@ €@ €G=k¿Ÿšã£ôµO\ècqåO~C7ßõ ¥šZ™ð%¾Ú˜üÕÊ%›M¹D!^ aKÈ^™tš‰Zi.±˜á~ØdàÒ@5lW‹1?'nÊ@Ƹ¼bKyE!p'­f²WÆ�¸2R¦‘É\#K2y ‰¬¶–Ibñ8ÅêįÖÁ2CiÎêÕKýLöêëé¢%s§Ò'.ü�–®úÕ_hŦÝfÍ©¦&}5›,_²Ž&œI+«´£Ù;WÂWïà0ííbrÐ mÜ7@}#5Ô2µ‘Ùk Öëé¢];:ij²†^~Â$&|Õ;Ë«þ0ŒuH3|í ¿?ÝAû¹¤åÌÙ|Q6%ø‚a¶ß u·÷Q£dúšVÏDŠ$MoIp¦/�¹X a{­$Žøüëé hæ¤ãþ«û6ÑÞÎ�JCÁoœxÁ¢)tÆqÁ,X}L(\·«›3ÊÕÒü©)äk„/ïDàÚ.~ANæ÷©9“s/)­i·UÛ;Aø²Á1@ €@ €@ €@”ŒÀÓ�Üc’]ú�·ú>ÿÜå´bÍF“!kò´é«o¢FÎöUŸj¢X2É™À8S–”VÌ S:=Hµ£ÃÔÛÛË&~1éKˆZ’,‘`¢—�¼êçR�‰dÅBú’?/[—�»„è54ØOé�.Õ8`Æ’=¬©!IýC#Æ'Ƥ¯:&}ɼB ëïë¡þî.&|uÐç�I¯}ùéfýBB»ðÓ—ÅLf2!¬ é+Á¥…p&d3a«M8ÂWfx”Ë{�Ð~&tma‚ÓÎÎ!:À™½ˆÓ–M™ÖHõõq—¨«k€öìì¤æº:ù˜f&%üWè –Oˆ”B¬ç XÍ 1S–®�½­ #AUBøbÂLw†xŸiÞïˆ\(%´Ý\Öòñ-ÝÔ=\K3fµr�QN3W[CýCtp/Õ¤345UK³[t à¦2ÑÂdúâý–ÛÂöZn ±rÇEg/1®½úáë* ŸC€€¼6Þ÷Ê¥�ׄ\š×qùFÉê%�M˜LXO{˜´'YÀŽæ _¸¶ _”“›’ôO/šoÞ Y‚ðUè€@ €@ €@ €@ +º“Íl¥O½ïßìÂ�|†ÖoÙN½ýÍôš³^B—]ýêM�R§âLÚ³ºLv/IÓ'Þv.=òÔ:úÝ_î¤!&c�r…³ÉmÍôÑwý3íÜ{�~uÓ2CK64zå™ô%å…¦d/)Ï8ØÇýTW3BïxýYô'-¦{[M·,[AÌu’ì`&«ØÐ 'wê¡Þîvêíê «/û8Íš1ͬåš ô™Ë@M“¦P3ÿI/ÙÉdîD‚yBœqÌ”‰G…m\2|õò÷tÒ6.ã¸aoõrf¯Ö©M x‚†2Ì>áth1&kõ÷ Òž]4<�¦¶Æ˜!p•²�—Al®¯£Y“’´tV#Mi.�(&±ÃHP•¾tÑÚ]½´«ƒ3sñ~…VJ‚X{o†ê’qšÎ„¯†T’/>®!ÊP]Ý(¥‡¨·½—š˜Ì·hzŠŒõ4£5I�¼ßr[Ø^Ë�!ö'ΛD¯|ö,ãºbkÝþÔ®JÂÀç 0)• w¾lQ`&)¿ùl Èt�b2Ÿž[‘IIÇ??¶]Õ®¯vIG\Û…O±dõ“ hÅ_Å‚ €@ €@ €@ ¢xê�; áë’‹s¾.þø¥ôæ|�yú‹ŒÛî}éKßÿ ¥)ÎÄ©”!^‰B2m�ÿ’çÐ+N}ޱ{ðñ•tÙ?¢—.¤O}ð]4©¥ÉÈþÇÛé¾'×›ŒaIΖ¨¯7„/))1„ìÕÏ¥¥DãôIMô‘w¾‘fϘj|åŸk+=²j‹)')Ÿ!ÎÖßÛÅ„¯jc®Æ�¿õyßö‡×ý/]ËÝLöšJ-“§Ò—dùjhî”GV“Ò�Búª´U•ð%™½ÒôŸË8nÚ×G;9›Õ�þåôhS˜ðU˩к»3œÝk”’\ªPjhv2¹I²[¹M²…5!·Åø/É¥LIÒ‹–´ÑÜ)^©Á0{WF‚ª„ðµý@?=¸®�¶p¹Ê4Õ’á± —Í_·�¸ÜÙsãd}‚ZÛùBˆÑ§~“òœ©TŒ1ÉPû�ªåtqÓSu4»-A §¥h*—w¬�×q=PÞ|‰-l¯%ºÌ^wÊ\Z4£ÙÈnxdmÚÛÐc0q8†3è½ñó Z¾µ�îxjw@v¤ªMøÂµ]øJÂ×›O[@û8ã6&n?ÐkÞ‡Îyîì€#_80@ €@ €@ €@�2X±ìv:vf }æo÷½::;iRk«?–ƒ'V­§oþüN®ÄeãIS±�+œ}áýo2ÇjüÈOÑÉÏ>�/å’+ s™Å¯\ó[Ú¶¯‡ê›™·TO5µuœ'Ãeû™¼ÕC}Ý�tê³ÑEÿú:S RãIõ¯n¤Wl4¥¥Ôã0—‘<ãyKéù'.¦% æQK³G,Û —™RWmäVCÿöoLidžFÉNVÏk—ìbˆðÕÃåþvw ÐÖýýœI‹Ó–qf¯IÓZ¨ŽÓ  2»�³[e„Å-‘�… SN6é‘£XçýßØÈ±69{)h²`uôÐì–8½ü¤i´�3a•ÚÂHP•¾6q沿?µ�vs¶®6Þc‚ \’©K2$åö`oƈÍ2Í9åÍÈÉålgiÆEd1f²ÉµÆbâZŸ�=ÔÌÙãÏj¢ùS¸äe=5ÕKJºÒZØ^KóÌYÅï÷r‰À8/J}ß¿m�és8šHœÄÙØ^‘ÍÆ¦ëzhý~ºí>Ñ}5 _¸¶‹_ òºç·´2;½‰Îÿ‡yg¾p`€@ €@ €@ €e °bÙmLøj ¾¢Üô»¿ÐÝ�¯aÂVŠ [µL¼JÓ«N;‰Þôš3£\|ù¦m»è‹ßÿ�!|ÅBøªaÿ —pì¥Ì`?½íugÒËO{¾oo|÷g¿§ž\k_',šGoýÙ4{úÛ$òø?.ÿ%¾8×£Lø„¯:æAM� _ûºiÕ¶.ÚÂÙ¯ö÷eh”iS¦·šhœík@ŠYr“lVuœ©Jz!pQͨ©o鿲ä/!� ûŠs9ÇÁ�!jß×A³›ãtÎófpZ·K.à2PÔýk÷ûÚÓ—z)ØÏšìËŠlØÝC·<±‡ör³9ó§Rª©žs„6%°åzÙ#ÿ±@jyŽ0y*Ã$ŠÌ0³þ˜'riq.uÙÈ™¾„×ɤ¶ÛÎj�s–¯FzÖ¼šÖ’,¶4_oï•Qö›âjË|%¨^d §5Ñ^à‘;6rf/Éð¥-Ê_² 9O›ÄÛÕÞ¯C“!hÉÌfjkJ’�ntÒöƒ½t°‡k¨úVÞ�†¹ émv[Ê�ß¹$a}¢Žú‡†©»Ÿ3Æõ¥iËþ^O'\`8ËYgšÏÇ~^‹4™o ¯o!“[ZSRu”KqJONßÇs©�9à’|].�ÕB“Ù§Ž÷t�m·ñ:ôxñÔNz݇-3rVHIÆ©Ì>�Öœ¤$gtlöu˜Þ.êâ4£•Sþñëi13^OY¼ŽWnï §¶u¸Ó…Žå2ÜÕá�+]§Î%çU^®ÚD^ì¼nËžWñQW�§qT.ãobgñ~ZwyOÙÝÙo2LÉÚ„ðõÒã§««éï[³—Þp s_À×ö­kûFëÚ½ø¤øÚšÔ,+ÄGÉxe77¾ì©–_²m]|}ö2)VšÚëÞe,ײ\?Sš¦Oó{ƒ\?R>ö ÷2¶›íkËÝcÉ ØÆ{˜ÌqÛ“æõ×ÉY;zÓÔÑ7į™!’k_š®Kcè:–^^¯� |¹þbö Ó‹_˜�-›¨¦1ÃìU§¾a6ª‹ê5F”¯«×±Æ³ýTgËÔÎîÕΖé±í«v¶LíÜ^m]yظ”xâçÆ?W_e¶}ØœËÕ©\ãh¯vÅôjïö•úEÅÑõ¸zë\…l\?õqå2–8®>*v©vWmíXa2±­V+?L§²°ùíu«>ÊÞµU»(¹Æ+Ô»¾j«±eeãÚ³S{··ç]Xצ˜]X wÞrÆöüÕŽ¶�/j.Õ»¾aöQ¶®¯Œmÿ0?Ñ»rÛ',¦Ê\?•Gù«½«W¹í¯²B¶®Ný‹õ[íÂâ¨M˜Nýܾ˜O1½ÄS�­ó«\Ǫ/§×êcÇrubcëÕ'ÌNuQ>"W¿°˜êïÚèXõ®¯ê]¹ÚÛ}%¶¶¿}\Ê|¶}±c]›ØEÅVW¯ò°9\[µ‰ò±ím[.1l�ÆÔÞµU¹ôêgÛ„É\[µ±c…ÛqÃô*+ÏŽegÛHLµså:Ÿöj§ã¨ÞŽãúØ:õwmT.}˜½­;Öx¥ú³�Ò«Ü^§ÊÂæV�®Yl\™ê´‹£:íÝaq5N˜­Æ‘^õjoËäXåav¢/¥Uêæ&“5¨Ü^�®Ý–©]!�moÛ©¯­—ã0[æÚÛc�f¯:µ³Q]T¯1¢|]½Ž5ží§:[¦vv¯v¶L�m_µ³ejçöjëÊÃÆ¥Ä?7¦ø¹²°ø*³íÃæÔX®NåG{µ+¦W{·¯Ô/*Ž®ÇÕËXç*dãú©�+—±ÄqõQ±Kµ“¸jkÇ “‰mµZ¡øa:•…Ío¯[õQö®­ÚEÉ5^¡ÞõU[�-ã(×¶˜�Ú»½=—èÂâ¸6ÅìÂb¸ó–3¶ç¯vì°uè|Qs©Þõ ³�²u}elû‡ù‰Þ•Û>a1Uæú©<Ê_í]½Êm•²uuê_¬×ØjGmÂtêçöÅ|Šé%žÚhl�_å:V}9½ÆP;–«[¯>avª‹ò¹ú…ÅT×FǪw}UïÊÕÞî+±µýíãRæ³í‹ëÚÄ.*¶Ú¸z•‡ÍáÚªM”�moÛØr‰aë4¦ö®­Ê¥W?Û&LæÚª�+ìØŽ¦WY¡xvŒ(;ÛFbª�+×ù´W;Gõv×ÇÖ©¿k£réÃìm}رÆ+Õ·˜}”^åö:U6·êtÍbãÊT§}XÕiïÆ‹«qÂl5ŽôªW{[&Ç"WÂ×¥V†/ÑI¾†áyCêíë§}þJ©�sYGÎÐÅüš�¾zçΦs_vZÖ*ºûúO®§5[öäJBrB&á'|ô¯§y³‚|;Ê?þ-ÝÏ„¯/¤Ï~ð­^Œmvüáoþš›'qIGÍðg.U>á+ +�§:kIÇó§Å‹Sc#WŒÅ¨æ�u{ Öå� ¶ì륻Wî5Y¯&Mk¥×»äÌ^ƒC£&‹•”rÔ&t.!> �p-Ìa.óÈéÌä$ˆLˆ_†•%AÉé¯aòDœ‰ I&ûŒ²m_g/ÍoKÒ¹'Ïâ X^¹A�]¨·IPjW áký®nºùñ]´§w„fÎ�Jõ©zêëã½(q"»UÝ‹ìMR¶¥­½ Ù‹ÿ¼={«1¤6&}™½2Ù¤v”ñ`rÆ1““ôÒ§“”ì+µÙ{µO¼ž[fÇT½ÈÎ:i&=w~›QßöÔ.Z±5GrýÕïýœLH&Úä4~û¦§Íð‹¦Ð‹O5ÃT/½œïeLÂ{xãþl¶7[ë‘gÎ8nš!éLe2T¡&įG6 '¶´2#w�»™èôëû7›µ¿ê9³ü2–v!ÝÜõôžBB:mIøžäìZ¬Ë‘ %–â¦x‰l6“©¤LžK.�´ ¿�ݾb­ÚÑé œß÷Š¥ÔÀ×ËX›d¨ûÎÍ«Mw�.^åžWýÔ´÷m¯÷ä“é¥'L7D)[.ÇB,»ùÉ�Lîl%|=T„ð寓±{m?e]󼮾ú8ýûËÞ¨åZ½öŽõÔ;è‘·Âb‹LH�ç=®¯þͲÍ‚œ*Zât6¿Î„€ÕdN¹¦äkI®iîùq}åzxÉñ3èĹÁ—®�Œozb­ÞÙ¦22{.ÉðFøºeùÎ’ü]#�íÊõ¸òjŒuÎñœ£Ôu–³µ•ØQkW›(}©ë;�%ÇåÄS¿R}ʱ�²U¹¬ÕnöÂll½ív¬þåøhœ±øjŒ¨¾XlÕ‹¡µ«]!›J×åWª|,k+e�ïÚºX¨�+wýÆ{<Öu¨¿®³Ð~lÛBv }ð½ÓÆ£üo×6JnÇ;V?Õ¹qU.½Úº6*W'²ñhã1§ÆŒÚC1ýxìÓ�YÍ5h,™#jÏîü…ÆÏŽ¥²°9TgÛŠ_Ž.,v˜¬œ˜ãm«ëÓy¢pqíŠÙ«^{×?jµ×^ýJµW?éÃ|U¦v¥Æ-ÕOíŠÅ‹�úê¤/6Ÿm«ÇvœJü5Žô«Ô8Åì‹éí¹‹W3–Î¥1e\êžÕ÷pôºÞr×Z‰_%>6&…üUgÛËq¹ûrý �uÎñœ£Ðü¶®œµ¨­øG­]m¢ôöÜÅŽ5V¡ùÂb¨_©k(Ç>ÊVåîzì5„ÙØz×׫9>c,¾#ª/[õâ_híjWȦÒ5Dù•*ËÚJ™Cã»¶.jçÊ]¿ñ�uê¯ë,´Û¶��ÆBŸûþäbQ ~Š·k%wçpÇê§r7®Ê¥W[×FåbãêD6m<æÔ˜Q{(¦�}º1«¹�%sDíÙ�¿ÐXãÙ±T6‡êlûBñËÑ…Å“•s¼mu}:O.®]1{ÕkïúGÍ£öÚ«_©öê'}˜¯ÊÔ®Ô¸¥ú©]±¸c±S_݃ôÅæ³mõØŽS‰¿Æ‘^c•§˜}1½=w±ãjÆÒ¹4¦ŒKݳúVÒ ákѬIô™‹ßp_µf}þkWоùe.ïØâë®»áotÓ=�y噋3ÈÙ¹Ž™1‰¾öéù6rÐÕÝC7ß~7½é ¯ñåë¶ì ÿ¹özæÔšdLñšúì‡ÞJsfxÉ¢Ä0�ÉÐÏ{=ýû¿½É÷ûö�~C÷?áeøºôýo¡g->Æèž^»‘’´`Þ3îèì¢?ýíN®|Ø@‰†óœèöÇ7Rª¹•’\Š2Î¥(ëbBø*¿¤£ž9'˶xœ…¡›/¥¶ÉS8n‚Î{Û{r„¯…3ƒÙ‚ü�„lÙÛK÷¬Üc_­S›=Â×P ዳX™lVL\RÉ™„è”a"”G†bÒ—O~�,ÏËòÅt/CøŠ13¯ž 5ì3ØÝK '×Ó¹§Ì)‹ðµi÷A³ò° _åìÕ¾ÝÁ„¯aš5o:¾¨¿ŸëzJyFY9ÿ#$ ÙkFö)d/¾ d¿îeφðÅ:Ù«äyYÌ˜ØÆ„©Æú:Š œÑìÞëKNœAÇL/�ð¶W3Iÿ\xÖbÒ‹´Þ±Ž¤lg±E :— M'Ì)L>ù“šÂ²QIi¹žs\±©ú{‹d~r×)„¯ÝNo:õ“)ÌÈ©úÃÃ[M&1!i=«Èžþðð6ÚÌ5`Úd�:•Éb/\45@* ³Ù›Ò�L8Ë^.¾Ùx¾üàÙ/YƒùÆr^%´dD;ëÄ™$å( 5yÿØË¿f·5Ì$ÃW%„¯R¯í|á|:fjðuwÏ꽆€Xˆ3�ìaJâ’ ]?»{£cA$$7!2Êõ]J“,sòÙq°¯ ùs˜¤)qmâe!‡[˜LE&tý*!|¹10@ €@ €@ €@  ¬Xv;-aÂ×%¿UEtÛ]÷1Ùë;4Ä%Ï;çlúïÿü€¯Û½ï}äKW3á‹1w!Í„¯†x ýôÿí۬߸™>õÅoÒ�ÎnúÁ×?OK��ot}ýƒtéw¯£í]4ÊI›>ö®7ÒóNXìûíÝ€>õ…Ëiÿ�ƒtã/¯ñåßæ _Ëž\Cq&rMŸÜB—^|ýä·¢›n¿“>þ޷ѹg½ÄØnÞºƒ.úÄ©yÒó×Ô6…šZ&s9ÇfJÔ§(çÌduÌ}b®ÄXJ:*á‹þþ9jjl¥x2Nç¾Å"|Í�æewòwPà`_ç=Í¥ã$Ó×>)ÏÇ챩3&S-÷]iCêⓜ< ¤]óú™½X呟„åY› »-Æ¥ó˜AFéöNZȾÎ9e.-ž�cñXžQmßçe} #|•³×õœ ç&íã’ŽsÌäÔk)¯¤#“RdÝ’…g��‡ä�÷lÈnBîb¥ìUˆ`RFÍÈ9ó™Gp#JHIGÎøÉÐHO/5ÖŽ2Á¥žŽ�ÑL'0!fZk®D\%{-æcë§qiÁ·¾x¡íásû«û6ÙêÈã0bÐ}k÷Ò‹�‹N}§Áú†2ôã¿oÈ+_g¾¤¤¢”ì`ò‹”£“2Ÿó¦4æ‘rä<ü’×ì–ßÓ¹Üu á«?=lÊXªMT/å-÷p©ÁÓ–L‹2ñå;Úûèw˶øcû@È^n )³·aO_##&˘”–´Û_ßaJKÚ²=m�! Öóõ“âÒ€v¼´ ¥-—c)õÇœ3¿Ù¾|aöÀÅKðëy•Ð/=aF^J‘K Äíú¨©�KxNâ7=.Ö*!|•smÇï/¯yžÇÄÕù…xõÓ»6è0¯ob’ä…Vf°»™ ö(gè²›�²$³—Ûäz‘}K†®c¦z%Emyoù“Çä: kB@"bX“’§û¹D¨Á$³X3ÿIá+ -È€@ €@ €@ €@àP ðÔw0÷§�.yßþtïþÈ¥$¤-!5Ô0¹èŠ/^BÏ;éx_ÿ¡Ï‡v÷ÒTzh�š’uô£¯}Ú×ùŠkè¶{¤dC#½ðùÏ¥Ï~øÝt×Ã+èúÛ¤žÞ>Ê0‘ìU§?—Þö†Wú>[¶ï¤^rµ·wд©“é?½Ò×]ñ“ÿ¥–¯cÒVƒ¤­âyG¨»³ƒú{ºèÃï~½êÌÓ�­‰ñÿ¾AM­Lôš4Ùô�&»W#%’ œÝ‹Ë.ò~„ì%Õ+mJø:¿ù1:°â!ZÕ‘¡s/¸(—áköÔÒ _=LÐØÍd…­{»iíöNâäWÔ:uÕriÇžt-1Œ:¹ š� „èU;:Lu™!ªá²ŽBáÿ›L^¯ìXäY1ÃåeÀªÍ¤©¦¯�Mi ³Ÿ?‡Î,�ðµs¿Gøºwõ>/0ÿûâã=ÒN9{Ý´»‹nlíê¢ÉÓÛøIræ./£—ÖÒLÊ0d¯,éKˆ4²IÙŽìi„ÈÔ%(Cµ&û™øH’Ÿ8¼R|Q$†‡¨®¿�¦5ÔÑR.É6z3ÍlK1ùÅ#hø‹/p {µÉmÌóTRzñô¥6ËÖíË+M˜ç�¸Ä Ëžå:’Êc›òßó´Ñ|&j¹í×÷o&!_ÙM_ÿÄ™–žÜÚnÈNOÛ€�…P&%#ívת=ôgÅ kî:…Œ'·¤mØÓMOsùD9_§2B²›m+Ä$±Rœ”¿tËn2±ïª[×Øîæ¸•kÀ¾ý¥‹(ƬMmRºP²‡‰�4Ù÷?¿h>Íä’�Ú$»ÓïØ¢Ã@/óK©B»:wxÕq”e¶•Cø—±ž×T"Æ%¹ø­&YÞ$“•6Yã9Ï™M‹¹L¢Û*!|•smK²÷œ½$/[–œƒ¨L[v|¹V~xûz2£¶F&å½ãÌE”´°ÝÝœ½íQ~}h“kãuLjÕLa*ßz —~ÿàVú½�ýÞñÒcóÖ*äÈ™ z€3�ÙM_’½l÷`Þkζ³�‘áËFÇ@ žÁÈanÞŒw|$ý+ßSÑ€@cx~.TæÝáeïór·{¡¶ €@  "€ûó‚ð@yä"€ûó#÷Üaå@`¼Xùàß áëSï}‹?Åû>ymز�ÇÞC¶W¿ü úgÒÒö�Ÿýžxr-Õ0ß`˜É[’˜åÚ¯|RÕtùÕ?£»|‚[¸”bŠæÎžM»z d˜yGCýô±w¾�žâRã#$°‹/ù2íØµ›F9A�¾~ûƒ¯ûñ¾Ëó=øÔFS¢±¶¶ŽÎ|´ag§ÉR³�K° Ä’T?}* Åë™pÀ噕`ÞR-ƒ7z`? -øPÞûã?§—~ç—-'b5ÔÌ™ŒÏj¦3NšEó˜ UjSÔ]«öú.g>ËË“R‰@Ø›ŸØiTa !¯H™>»­dâЭËsÄ![¶N¹ïxj7-gb™6YŸ¬3¬­æLo7ñž´ Aç¢W䓃®ºu- rö0»½�Kþ-œÞd‹è×÷å“Ý„ä$¤»ýâž�´Ÿ_[n{î1!„¯µÑd½p™Ì<Â×M«Ý°f†—(Ær^_zÂt:åØ IOÈ~¿¹³ó~à-É”Ðd¤Ý ák}0{–­;.÷Ú�`k·ULj•ÌXa;®7ðu/d+»½–‰ªKg‰ª«™4x_ûn“kêßÏ^LB޳›ÉÊÅk°[X\!$^wϦ¼ëÏö+çøØMôú˜p)„EÀ €@àB ÷«)‹–;./[´{oy¤ì �æ3_|Ø%òÂ{ÄrØ—RѼg)ÞÆkòàz|g¨hëp@ €@àˆC÷çá”áþ||ÎîÏÇWDG*+ú;-™3…>ùž7û[øÐ¥—Ó&θå=i¥…sgÓw/û/_ÿó?ÜJ7Ýýˆ!P�r¢©¦†]óå�ûúoÿè7tßcOs)E&|54QBÈVuu4Ìeúh ·‡®úÜ©µÙKTô§¿ÝMßûé¼÷O›<‰®»òK~¼+þzxÕ&K²tIœ4óžúz»è½o~ �uú)ÆvÛÎ=ô__»–š['S#ÿ5µ´Q}c—\lઆ^)DZ’½d¢e[½¤3’á«}ŃôTÇpå¾t—’ékg ÙÌY°Önk§ƒi&wMn£¡úFêIRº¦ŽëQòbf¹ oßFõC}4¥¥!¯�ÆsûŸZ˜„3gZ�pÌdC†rm¢ÆJ‚º}Ånßäìg{‘Ê!| ©íé-iǾêâ¬UCLt+¥õq†³]\:0‘¢šÙóh”™„Ã\Ò±†K8&†(1ØKÉîšQ_CKçµÑÎ^6‹³`•“ÙKס{½ûé¹MuÅzÉ@t1g’Ö3�¡«ÿ–Ÿ¡Ê�¡Ê?xîñy„¯m|=HF$!TÙí5'Ï!)Ag·»8ËÑ#J#ð¸ìï�½öYv(ÚÌççú‡‚™�t�ïçýIi;»Ý¿f=¸>Ÿ ÷n.Ï'¹ì&{úÃCÛ6ÑŸÿsM)FÛöÚ;ÖS7¿.´If§‹™le7ÉÂô“;7Ø"sœä5^Ì$:»E­óP¾¤ôàÿ=˜^Ï}Þl:Á9¯rºe ]™ì1ŒÈ¤{r˜�ÄìV.áK®í÷0)Oš\Û?¼}�.ôx—R½ [ÞT „àúƒÛÖqÉV/›ÊçNIÑ¿œzŒ醇·‘”Õ&¥)?į· ÉM2¼…µ38{Ý ‰q[ö÷ÒõV–/!†ÉkÏ}Mü� �’1­Z „¯j!‰8@ PÞ—Gç+di®Y+÷ûgYÎÆcYO^Hk�U�›7Q^ˆ®e¢>ÐŒÚ�Ài…ë¢ �¹Ù‚Ù�,Ö{À?–-T¯™i"¬¨Ì5ð ¡î¡LÏ’ÌÍýfvqp¿Ÿ—¤ Ff§ÌE|5F }™Ó˜ˆ¹¹rG%L €@�CŽ€w“5–[-ëö·j«Ëzòa-°ªqó&*CÀ ѵàþ¼ ܪljÎ�.p^5xù6÷ç…ѬôN÷ç…q…vâ"°ê¡;™ð5™>a¾>ò¹oÓæ»ø[-sMF¨†?¯ÿ÷ûÿä)�çqÃßî¥ßüå.&qÅX?LÍ\™ï_úO“WþìzZÆ% I+ž�Ên\±oh€úz©!6Jß¹ôý¾ý7¯ùÝqÿ#¦Ü¢døšÚÖJ?ýÖg}ý÷®»�Yµ™É[Í\–1N#L2ÂW?¾.üçWÑËN=ÙØnÛµ—.ùæÏ<“½[¥j`#Å™p&D±j�½d¢ákùC´²3Cç\ðž\†¯9e”t4+ç„Ñ/™¾¸¼ãúí´e_/m爛XÕΘÅ$§&¶!îè ‘m›iNr˜N;q6Í�VZ¦.)±cÂL7„ø%„˜RÛŽlIGÉ"¥MÈ)ÒÊÙ«dk¢W?¸2Lø°³Viܰ~û¾nZ¶r'màmóPMË$Ϭ·›hß.jeÒ×ü¶$g~j¤ÅsÚh—ql(3³—Ϋ{½Í"·‰®”µž¼`²ŸUêq.‰(™¹JmBº’5Ûí»7¯6ä[&ǧ.™F/?qF@|çÊ=ôІ|ÒUÀ(;�,)Ã(¥ì´ôžm·‰ _ZúN?õCNm6á«� W?½s½íî¿åŒ…~¶3f8mÛ5L‚ÓÒ‹¾!¼’Kž4/{^³ŠkïX |I‰F‰i·5œ-ì¯�3A©þ?^}‚ÙŸŽŸÜÒΙÈò3—y„¯Yjfúe&ÃW®„©­üÀ9LJdøzÚ6ñ�Ãr×ܶ–zù5à¶,šÊ¥RƒÄ,S®pcŽÈ'×Èû^$½Iœ+ùZIó{HXó_ÁëÅ#|•v½HL97rޤ­àLn·Y¥#�0⟷½äXšê”ö_‰a·sŸ7Ç'» ¡ìÚ;ÖˆŽRô­ËnRîñ[k‹Ça׋GVËù„ÅMó{“”•lƒÕjÇÎhÉðÕ™í¬Zó"@�è'˜~”é¸d4ØQ|Ô¿d¿C‰fbqв×3»ÆuYbYÛ¸<®ÖfËÚMùƹeæŽÊ�2±<ü�ø`}|c¥÷V`5.A)�S§ÀÖdV+3¾ú•º[½_6Óð?å %¾žŸù·à”j˜¯ ”@ €‡½%Ñûk—¼¦ì½¯ú—ìaˆûó`&ˆ8w}äŽ&ÈÒ*^†¿ÿ âPÕsÔ{°êE< ‘ʹë,syzãY¦[1s ‹ûób(A*C`ÕÃwÑ’ÙAÂ×Ǿxm޾ǰ„\5œÉÐ/¿óyjnL™Iþú÷eô‹î Z&Q A«9Å„¯Ë>æ/àªëþH­ÜD�Í“()¶â óÛ¹”rìçDLs§6Óÿûà[}ûÏ|íjZ¹n³™O~ hkm¦_þ_õ¯n¤‡ŸÞBõ©\,Íðõïo<›Î|ÑóŒív&|}æŠ_PSë&›M2BøŠÅ•ðå‡ÓÁ²­^b*/Ã×CôT{†Îý·1¾tEÝLˆÚu ‡6íê¤Õœ kïP O™J™ÆVÊÄh¸»›2›7Òæy�wÆ"Îh5Y]Ç­WÔ_˘¤ š´r_•.pí¶ƒôçû6Ð:æwÕÎ?–jššˆ¸Œcœ³�Õwí§™ÉQ:ž³–-œÕÊ™½šø‚LT:é^mr›+…ðu“‘ŽÏfhúõ}›hí®®’×ñ‰óO ¾äG§Ëþ°"Ôÿ4&|½âÙA‚ÒíLdz`]4�gv[�¼p Í`⌔qlL2yNŸ;³Hf¥ß-ÛìKõCXÿ!™È,bšdW’R‰a¡�9“½7 ñ•¬Nß¹I‰QÁo ¯zî,zÎü`ù¿k8‹”�áëĹ“H‰†Oš%ÝlQž†ò²ßIÅݦj¿Â×Ù\æÔnBøZ¶.œðõÁÂ×þ¾ì(d2¾Ù9¹1ûÖ_W�²£0™¸‚Ä,!|=b¾„Ä$¸ÚMJÂ^U ›\XÜ{×쥇B²²Ùqíc)G¸ˆg!–@IDATIKÒþh²oñ‹±„öü…“éeÏò²ª¹”Ÿü¿>´Iæ¶÷¾â8.½ê]B\¼wu0ÃÞñ\¢U2ÛÙmoç]wïF[8–¬dï}E0Ë›\yËjÿš ‹»¯kÀ\Ó�`cáë y%;èæˆò–cœî@ P ü]ɳ§€O`µϨ$S'D¹x+%1yódIZ¼†JÖê,ݾäÁrU‡‘òïÕY™�½¼H‚Ï,´ŒfØýj¡�ª_9 7}Ü^Î\z¯]‰OáõÒæt¹»òÜ‘ÑZCë0çh}1#ˇ@ €(Š@ö­¨�c¸£ Cè•dêûxåÞ>âþÜ0bˆûó` Ïô>»œû_Ù¶úáþ<û‹¸p^œg¸êi&|-–’޽ÉßéG•ðÅ/:ÉðUËšßÿà|ý/oøýù·˜ðgÂ×0'ŒJÒ÷¿˜#|)A«±™3l I+Á„/SαŸz»˜ðÅÕö>k¾.¿†žÞ°ÅËðÅè“[éÚ¯\âÏw•!|m¥gøŠq,ùn”à’Ž�ôî7œEg¾ð¹Ævûî}ôéoÿ‚š'y„¯”ÎRœá‹ _RR²Zí‹ðÕ±‚ _n†¯iAâJ9›L_œýgo{/­ãÒŽ›˜|³­}�ºâ)ª›5‡FÓ\ÏrãZÜBôº/¡¥óákŸ—�'”ð5†½–ŠËÚ­éO÷®£uÌŸª[°ˆ8U�ìÚA-Ã}t gö’riK¸”ãô¶F“Á,V'—lemGv¯}<—ÍL"ûHæüÔëO2™Ÿ$ÓÒWoX™q)leâkgø’ìB_ø¿åa¦túqÓèUÙlKjpëò�t?“”Ü6�_lB’šÃYÏJmBŒúå½›|sûâ¿^wb`�;öÑ�þ¾Þ|Îʇ®ÝÞyæ"~±çæ•Ì^ßøÓÊP¢Ù«y�Ïã iv»š³7ueK:Jd)K(ÙÍ*m»˜h$D<·I„¯ãf·ÐkOžØÂþîAúùÝùe-Õh¬„/){(™Êâ|�g¸”êU[mz�_¨—kú=g/ dZ{Y¯¬[Ús˜p÷ ‹p÷Î'™ãìvúÒiyç~ãžnúã#ù>õ“Ëñ#¯~VQÈfB:“wǽ¡@\�_NÂW9hÁ Pô!¡‰&ƒšXüŠù°±ú3Íé="U¹~=æIdžò[Î+wT~”€GÕUº§Àj‚^[ÕÈhÁÈ 00D¬à­jI«ªÀÅ‹[†cÎ4wTlqƲˆ¹¨Ýûs;®Þº—bçÍœPGG�íør&r�' Ã €8êÜgãþ¼Ì󟻙ΕÂ5¯Z ÜŸ»Ðb €@apž��Þ7{÷СwØÆÉ¿ÿV‡l(õðõî¬Àý¹ Ê3oFøúðç¾Å%wóù¯áÿxz„æÎœFW]ö_þæ¿÷‹?Ð}O¬1$*“á«!Á„¯�úú«ý'zäé­ÔÄeë9ÃWŒK*gÒ\α� _íy„¯K¿Á„¯õÛ¨†ùorKýð+Ÿôã]õËé‘5LøJ1á+™Ì¾z:é]†ðõc{8_í\ÒqEW†^ý–‹r%çV�%™¾vp)ÃM;;èéMûi÷` µM§4×uLïÜAK&Çéü—,¥ãŽ™â5^Û ¾ª±×bë^³åÝxÏZZ{ mHoq®-Zß±—fÕ�Ò §ÒÂÙ“h—¶Kf/]CØ^UW¨_2«…¤|�4)3øË™‡Ââ\ò†gˆTBøúÜÿ>fJg7�Îy®W^O náLAR¦Ïn’ êÝ/_(Á(zɈÕÞÃåB¥´&x„Dd·u»»èw‡gNr×¹� _R¢PÞ,ÌgŒ~²pÀç¹…p¦MJz~õÆ•fh™™ñkŸ?—$”ݤ¤¥¾D~ê’©y™¸d/}vyD7°P²…ýæþÍ–Ä;¢Ù+�Œi÷3–yºì‡â‡8ËY‚³Ri“ìoßþ«f.S©×àœ` L¹ŸK†/YëY'3f�7áká´&zã ç› mÜË$+ÎðUN{Ý)siÉÌà5öئƒtçªÝ&Œd,“kUš»l³Ú s¹K¾îí¶™K�^ÿÐV[8–r¥沞nûÙ]è_ÿÒ^RFsëþ^ú¿·¸ncƒð5&øà €ÀB Äç²y+6Ï 8—ò¬±€{Þ|"(‹ Å Ð5”ågÏ£BW“ªYYóÈúäÏ_e.Ž€@¸„ÝŸÛ6Þmsöž¡·Ñ,yqÌÖ™göÙ˜Q¾bæã„_—eïÏuXN_ÊÜåă-@�Ã�@¹÷ȺFsOZÀYïYÕ>¬/àfŽûóPT @�£ÜŸ>˸?/ŒO©ZCøâ’ŽŸ|Ï›}—^ú5Ú´}—08Ìï o:ïlzÇ?Ÿçë?õõkiÇÞ&|Õ2‘k˜šëctµKøZ½�š™ð%%븤ã(—…èï5¾æLnà _oóã_œI2|ýð+Ÿòõß»îz” _ œá+Îä1ùÎi2|…¾~,éhÊ@Ž_†¯vÎðµ‚3|½ú«¤ã¼*¾4Ó×n.ï(®$›Í–ƒÔÞ=@£\ó8.øú3�ãR†S} Æë`[ÂW5öZlÝ«·ì§îZC«·wRMCµ5×Ó‚¶z:vf³Ép6“Ë86pù¶±döÒ5„íUu…úó˜Ô"äi7rv » _!?Õ¹Dª±¾„�ô‘ל@Mõq�ÂdûócÛé©­�ìc_x“WU +!|©¯ý¨øÂ³Óü©AÂ×—ÿøTÎÔ:R�d¢²›£:ûÒ¾h1Ÿï·¾Ø#Õ©PÈ9’Êkò–ÅÍü“Y�|hd-,)Ñ)<¯d³Û=\RÐ-+Èü!û#¯yIBmBøúÆŸW™ÖîÔ”˜ñ\zA¹ áK08ÿ”y:µéû†2ô}ΆÕÆšáKÊ]J4i·­ØEË·zÿ¢æså §3aìaLuR†ò·¯¥¶Æ½ý¥œµ/Û¤Äáªí:ôû°}#º5óµÑÙKür ¯+!j‰V)S)å*í&$ÃkïXg‹Æ| Âט!D &ò&$¥°&R£�"$±�W‚/ÌÛ‹«1Â,„è1u˜¹0£²+‘¨åµ²<²ÆeùèrØ©t¿Ò-5ÿaßßdør_#iÎðÅ„¯>.é8‡«¼Ù„¯ÏpIÇUë7{%¹DdgøúñåŸñã}ïº?Ò#«·PCS+—gLùÐàõ÷tåeøºä[?£æV.éØÚF©æVª7%%ëǵ¤ãŠö4�ûo6ákzå%ý]gºz™]×Mw´ÓÊ�{I`Cœ)iÑÜ6zí‹—2á)H’qý«1Þ¶7º¤ã¼*î5j­k· ¿Ü»–6lo§“g„àuâ±ÓéX¾pçLo¦–Æd”kÙò°½–ä?Ï;‘ZS\ã”�¿Îe %›T9­Ú„/!˜HIE»EѪKøÊÍxáYKò__úÊœ�ut>“n\Â×7þ¼2@øjM%è?Ï{–åE”á_�¿|ýrÓ!y3 û|Á¢)$Æìvת=t÷Ó{r"voy(üq.ké¾¾zÃSæ 3çà éÎ.Õ)?”_þ§U®™K«—=kF@w'¯ãá û}ÙŒÖúAJrƒå-kh�Ù·n“ýJf4É g7!³=¸>×ÖŒÌ?žô">�Í qð&iõ dló¢Ç‚ÙEg-eòa,`+äÃÙ\jT3»I¶¶p¶8)‰ê6!†½ëe‹b±¿êÖ5†ÄPd³8kØ[8{˜Ý¤TdŽ H†pæÆ<…ŒÈg©à„¯ @ƒ x†" ï1å´’ÌKZJœBaÄ_É^Qv…2V‰�ÉNå,Ä[`%b�ßã €8Bˆº?—íÈ=¤Mö²nO½ÝŠ>{¶}±·ým‰-­ÐüžÞ˜ü'o]¾µY ?Òƒh{µÈï�O%Žù¡ @�¨{[ÇÌFÜ®úzsPBÐRâ cßGÙáþº�IQ–àË =•Ìl’¡Ín_¹›KZ„/VjŒKÞp%­¬]B:»ì÷Ë��Úh¬OœRáë‹¿wHoì$~§-�F¯pJKJF­Öí—÷Fc#ä±�¾6Hz“¹n]¾“ç2‰n›Ão¶o:mA ¥ØÜ³z�‰ëÚ›õódÒËœÓZêýR¥{:Ê.Uªñ_|üt?žÊ¶è¥iœ­¯ž÷$mgûï7¬Õòb$[ZÌügÜ9‹?=º�$#]X{é 3ò®©õ»»Íõ¢öQqŸÜÒN·?¾õ-§á«´` ž™èCX%-{À+öÆF#`› Ixd�´µƒz´¼9m¹wìE �-Q~v¤hïìÑ‹óËáâ €˜°˜ûÎ"«‹"l©[ÑlPØÆ»ïÕx~Ÿõ“ûᨢµgã{úöª·5æ83Ü7ÏÚ[?+Õ>?$@ †€Þzâþ< O¦ØD[dŸ2€ €˜ð˜ÛÔ"«ÄýyöéÀ¾?_ùàßi1s†.yßþÙ|ç‡>Ië6l¡ùóæÐ5ßø57yUÙúé—ÿ˜ú9¿K]<Æä¬QJ P*^Cßûì‡|—ðã2Œšá«·³�\Â×'¾ôZ±z½ñÂWk3ýúª¯øñ®øÉïèáU[LÆ®dCÊ·ÒCCy„¯]{ÐÇ¿úC�ì%¤/.)YÏe IÉð3~~Ð1_\Òqe{†Îù·‹Æ‡ð¥ë”L_Û÷vÑÎðu°³ŸZš’ôœ%3hÆä&5·>Œu( _{öÐòu{¨«g�/ŽšÁ¾æNo©jf//l¯ª‹ê_ö¬™L®òRàÝÁD!! •Û\"•”ž áëµ'ÏáÌNÓË#FI¹½w;™“ ‘ÖÜuJ—læ4ÞÓkxovÓÌP{»lqÞ±|h…ýP,„/))i·BçñR&�¹„¯Ïÿß“¶»ìâv^õÃTHQ¯zN°´¤¹î_»/û€×³|—)œÉ$C»IÂëîÙDíü>¡MÈ^’áÊÎF¦:!³-ã¸aÍ8Íg0 MÖ%í>&Þ·&ÜGãè^t¬}[S‚$ã[¡öË{7ÒÎöþ€‰OÖrÜ4sþm¹þ~»ls€ì >B½ðå‹)Å¥^íö›û7Óö±›d?“,hv“óô‡‡¶Ò.Z�ÂW5PDŒ#~à {Ï-wcŽ‘}’[qœÇqäöü’„ìXÌW3a³“Éd{¥Ú›ÿÂ7"¨ˆõ�n„IäÞ @ €À3½�ü/œÙ@l¢xcÃD-3ÈG¦�¿kmߟG„s]üqQû¢~(sà›Gm,hô Ñ•#*cÊrÂÂ=˜ûƱowÌ÷Џ?÷OîÏ}(p€@�Pô÷çùð(6úàaÕƒwÐâY“èÓ¿Õ7~ëû>F]]=ôÃ+¾L3¦å~ÿùo£»}š �TǪa® 68ØK)ÎÏråg?èû _Í\þ1Á¥34È%{¹¤ãì¶ú@IÇ�}îë´|ÕZþ�i„F†‡iæô©ôëï_îÇ»î7ÓŸï~ŒK5¶™¹kkk)“¢�ÞzÇùgÒË^ô\cÛÓ×O}æ[†èe²| á«©™’É&¨IE2yÞâ#àÇ/÷À&|up†¯]\Òñ-V†¯cfT?ë–fúʘ’ŽñºZj5Ùq‚„†r7SŠý–=^IÇ??jeø:Å#ÝŒÇ^Ý5Éž;»L©7)éXŸˆQC²º™½tཪ.ªï+—Ò\&×H»úÖµLZ J¢ül¹d®²KÿbÐïÂIDBÀ ÍðÅeú´I™B)“h·öž!ºé‰´vWMiNr)½)t:zÜ×Ä039¿ñçU¡e)ÝuÂWDF³‹˜˜”—áëz'»Uv�&ïÙnR³³/XSÖ*qçMñX¨j/Y¶`“df:ÀY̤,`‚I?RRˆOKg5Ó,.xÅ_ŸV¿—RŠy„¯§¢‰{—þcá+"›‹Wäyå}Een¢•4óßõ²Ý sZé_O_`dö?}ü:Y»³‹„üµtV‹O à°õVF2ñ‘ìU÷X׋Ç~‹’–à'íšÛ×Ñ®0B;ˆ�{'ëŸwp‰Q÷¼©z¿¾ÈñÝ&{Ö¸qÎîõn^�”w´ÛÿgïN£(ïÿ�sß„pƒœrªAÅbõ'jÕz V±Z´êO­hµÞ÷Y{¨ÕâI½µý[[­VD¼o…Š È%7!BÈ�ÿ÷™Ýg¯ìf�l²Ùä=m˜�™gž™yÍfÝ<ûÙçY¼®LÞÐá!ÍóÖœH¾¾6œr`1=ïùNæ¹at�“é5ì5ôX¯iƒú|ùùîÇížç¡9—®¶¬C¦îÔ¡-ͶH&_‘(Q¦= ¸Ûp�Qs„}ë‰ÕÇßSOب•)ìüß³�k)øÑ�kkT>xY[�³O¨"v}D…\…#.êœgÓ¥�­M±gÈ@h¿î¿q›º@û÷yÓešØjþˆŽ`ò/濸»³Uÿ1sûwt`ÿe×ßÛžZ=üKÙ%ß¿ÏÃuí¢…L¯ÚÍ�ìqãPUsO…ýHJÏßÃú 9îùÖ+„9¾§žHÎFwðÝÇþ]ìøÎµ5*¬¤Y甎ä lÑPù­wÕê·*ø‚sžM—v¶6]$xݬE@Ú“€þIî¯Jþ>Y2ïc¬�¯[|_7þñ¹tò9Ò§WOÏ3bñòÕ2å™W5p•«=fåŠ ]Õh說¢\;�i�¿Ýr±§ìcÏ¿¡C0®q†VÌÎ-�´Ì iÐüEU¥¾L_E9rÛ%gzÊ_~Ë_äë…‹Åôî5x@_ùÓ —K¿=¼£Ñ}ùíb¹û©ÿjà««dåå»Âfu5Nàë¤Ã~"'ýì O]Ü|ŸÔ¥fê±»hð«³ääurÎ9=#SÛ;L[F¸g…§ª�|_¥¦‡¯2íák’öð5kñÆ2éÛ­³¤k «=Lµzã~ܺ]L/Jï~ãâìèýz;�šŽp­MÝÇüì ¹î¤}œ´™òê¢ÈþX ¨4â`�îIàËô¨t©�g‚��“ Ƥ �XÆÜï¯Wm3džïxž­ø2çÒ£0[.Ò�]°k³çjÎßü.úN»4 ó— }W9�ÛDàKÏ$’ûjNؼ„]¢÷¶§:„›vh`î«•%rØ>®èlù÷¾Ý ³ûYi·Ùy¤ÏmóšjÿcìåÕ¶M0¨‹˜`_°é]=ŸÏ—ï=ÌS¿îhz¤;ãà��^È�שm»5Ø–ê´§æ` ¾çè)È@@ àùûY߸Ú÷®¾§aÞ£›Énsý]iK]ëÃýë©?\As sæÇs´v RÄU‡©Ðw£]°Wä»-ØcßòÍ=£Æõ›sl�S¼.+Ò»”L†Íý[7ÚkõšGöÎx×6YŸ3%›{ξûFxä §ÅßçAPX… € Ð<ëÛwûÞ÷2í{j»ÍõwelŸ/ûj– í](·\âíá«V{îJO×n»ÜÓ²U?Ê_ž~YR35쥽{eê�æo„Úš*©¬Ø)Ùiõò·›/²ÅåQ |Í]²Ö5¤bnž¤ë�Š ÚÃWuÕn§‡¯^…™ò‡ßy_×þaŠ|òÅ—ò‹c&W\xŽd:½qyª“]Ús×onºW2s;i€«@RÓ3õøuR­=†T¼§üæ—?÷þÇ´wäã/—:a/3¤cN~'1Ã@¦gdIІÔìgõžbx0÷Çzg¯ æËösdai�é8YR^�·¦Á|ØßµSžädÅPuÛÛeçî*)Ù±K6—UÊËK<'8vHW'XÑ®ÕsÑAüdÏ®ò‹1®˼%2cÞÚ ¥Â¯ R…ì J«Š4d†À;fÿ=BÜNÞœ¿Î £@ãrÎÐŽÚc™ïxž‰|™ó1½1™^¹†jOV‘Ní%ðe®·‹ö2uæ!ƒœßÁP×oÂMÏÎúÁée-°G¸H_Q?·ÃüË -y݉Å�‚x&€hzsÛUUôR_´M�cæw®G§ð�7Sá‚5ÛåmíÙ.Týö ¦^Ó+^$A:³Ïÿi`Î ý8™z _¸�]6!²÷µ÷µp“ù�¿u±oÂí“Û�çPäofšº&ó&Åùîª}ÇÔTá6¾Í^‚«qÖ¹ª–=cÇÎ4Û#Çv8gïæUá9p<ª±~žJ#xx\ûûæ·Þo!‚J)‚ € €@K 8[5>ˆ}ëjß×6.ÑôûwhÓ¥¼[c=Ž·÷£×Ó¨\D+R´ç1-§“sªr'¾âTeDWÑâ…ôbL4.a6þ>oÆÝÒ_Zó{Ëßç._Iûûf_לm~ ¾¥yŒ € €@‚œ¿­Û¾uµïk—hz�ïßç+æÏ–a}‹ä¶‹ÏºÓŠ5ëäÿGêÓ³%· ³dfçJZzºöÆU/5•»¥RCW¹iuòÈ-“=û?òü[òùâ5Nù,øÊÈ–®±ººBvïÜ!u•;åé?\ìù¼úëEKekÉ69òPoO]žÊÜ>šóµ<õÊL ohàL_º¾¦ªRRêkä¡ëÏ•¼\×gÿ•UÕrû#/ʶŠ:=~¡dk_NàKCj¦W²”ÿN�Éò×î�ø®~GÖ|³HÊ5LvÌ¿‘”Gß[Ú0j`‘dhZ®o·ÂHêjóe~ÜZ&5šœ¿ªT~,ñUØ·k®t”k5¿hö—.ð†™Ð�bÏLÏþß²T‡Ô‹d²¿¼¶Þ›ƒ éx[C:³_¿Ã¼ýÍz™dˆ¾ýv‘ãöï#¾½ ™0٪ͻä §m+¯rê9qt_­á5ßž‘6﨔‡ÞZâwœÀó4�¯ÇB é89È�ŽjbHG3 ¥ïô× C:ún7�Göë,‡îÝSºë•¡zÕ3½(­ÙºK~ؼS>YÚ¸)ÓÃ׉ó�>Ô!ƒ…yL™[ƒ éx{ˆ!½Œ}<î«9 2Á'óü ¼öewÊ[æ3÷П/&ð53L_±<·íóÚœŸ™ìóÛµ$rÊØþ:”h»èÌ¿û±Lžûd¥ßºp ¦‡ºÃô¾›çwg ÿ× éiBªïë}\¦C˜F:™zÿG½Ìp§&T¬aÓÜCS·ñ3a²Àɼ6^tä°ÀÕ-›á;Mog‘LæÜ\×xõ‘ìÝ6ËØk æÍ›ç�iP6“�»–ÚÖ¿öÎþž4>KW s-áË6Þ;Ú5ñùÖn´G¥<tD�È_;¢׌­)ÀëQkj·ßcµµç‘=+ÞKØcµå¹qqþölîž>iÿ–µ¥ûlJÚ‡öššËdžwöïr;o‹(ö÷%üŸ·Å»È9!€@s"lÎQØ/ÀëQx#J„hkÏ#{>öÌÃÿÝaKF6_µè ѧHn¹è—�v˜ûíùë?¦KJfžäæw–lí-Ë �˜š¦�¯:í±K_U»wJ^ºÈÃ7þ¯gÿG^|O>ÿn­Ó»– ˆeh J_R[]©Ã0îÔ^¾Jå÷œ$Ã6îTÈVòÝ÷+dÈÀþîʰ«d΂åòØ+³Ý½u‰ÔUWë9TÈ/Æï/�ò†Å**«äþç?� eÕøÒ€˜žƒë¼Íh\Í|-Úâº+ÕïÜ*]ºtѺ3äçgè�Ž·¾ðuÃáûôpÂ5] r¥0/²h6!0Ä2û:A/ g™°—é]ËL®�˜–¯Ú-ÕÚÓWuå.'0Ö³(_9X>ø|�”îØå³là+55M†ÚCªëD¶î¨’tÓ[—ÖiÎÂÏêô˜æØæG ?Ñ_¾Z¾A^YÎù› —yl†¡LÕÀ—ž s.Íù'tàëù¯œÀ—9Ä>ý;Ë ®ÐWfzšäggJV†v9–‘&f¸´¶4Õê0„U5uúS+å•:Nf­jë´rs¹,Z³½Éáð:ÒµÞ³ëN,–N¹ŽÏ=3ÊÎÝú$dB ðÜn7‘K@@@@@@@h·åÛ·:¡­ZnѲLˆÊô„ezò2a©4 K¥gêr'­42彤À°”; e ¸úØò5�BîëÞϳ�=¦ÿîžsh¼:àœBœGÈãVÃ2=|Å€Æ. € € € € € € € € €@"|%B�c"€ € € € € € € € €1„ |…êµ,†c± žŽöÚÛóÊvÖ×V®«¥Î§¥êM–_ {ýö|ï·Ý¸Þ–gÞ´€õ³¥Ãm·û%ÛÜ^Wàõ†ºŽhˇª§¥×'Ëy¶´õ#L ­ý~´µó fÆ::º¿§ýÐ2×ß^ŸWmíºZê|ZªÞ–y¶Å¿V{ý¶æÀ¿§ìöÀõ¶<󦬟-èn»Ý/Ùæöº¯7ÔuD[>T=-½>Y㥨�`mí÷£­�O03Ö!ÐÑø=íèÏ€–¹þöú¼jk×ÕRçÓRõ¶Ì³-þµÚë·5þ=e·®·å™7-`ýl©@Çå¥éΦ ¾‘¡C‡Jnn®¤¦¦JÊ�Ïå-ë}äªÇÖ¸Þ%Òy¼ê‰ôx¶\¤Ç ,¸lë 7·_¨í¡Ö/Òr�ûµö²=O{\ûü±ëí²ÝÞÜy`½�ËÍ­ßîoëµËñ¾[o¤óhÏÇ–·ç¸l�k×Ûe[Þ.‡šÛý"-oë‰u?»¼çö|ëµ×¸Ý®,ë²­?ÞõÚóiéúíqBÍíñ·Ûë ·=p¿p˶>[¸ò‘nWoàv»lë·çc×Ûe»Ý®·Ë�ÛíúHç¶¾põDZÎ×–·Ë¡ê·åìöÀe»¨y`ùÀe»_àúÀe[®¥æÍ=^àþá–#½ŽÀz"Ý/ÒrÍ­¿¹û7÷<›{üPûÛõöüâõü·õE;u>±Öc¯'Úý#-oÏ7ð8¡ÖÖX.p9°|¢–Ã�W¨í¡ÖÛëµ=Ôz»_¨y¬û…ª/Öõ‘žG¨r¡ÖGz>¡öµÞÖn{`9»ëóßîjéù„Ú?Öõ‘7°\àr¤Ç·_¨í¡Ö7Òr�ûµö²=O{\û¼²ëí²ÝÞÜy`½�ËÍ­ßîoëµËñ¾[o¤óhÏÇ–·ç¸l�k×Ûe[Þ.‡šÛý"-oë‰u?»¼çö|ëµ×¸Ý®,ë²­?ÞõÚóiéúíqBÍíñ·Ûë ·=p¿p˶>[¸ò‘nWoàv»lë·çc×Ûe»Ý®·Ë�ÛíúHç¶¾põDZÎ×–·Ë¡ê·åìöÀe»¨y`ùÀe»_àúÀe[®¥æÍ=^àþá–#½ŽÀz"Ý/ÒrÍ­¿¹û7÷<›{üPûÛõöüâõü·õE;u>±Öc¯'Úý#-oÏ7ð8¡ÖÖX.p9°|¢–Ã�W¨í¡ÖÛëµ=Ôz»_¨y¬û…ª/Öõ‘žG¨r¡ÖGz>¡öµÞÖn{`9»ëóßîjéù„Ú?Öõ‘7°\àr¤Ç·_¨í¡Ö7Òr�ûµö²=O{\û¼²ëí²ÝÞÜy`½�ËÍ­ßîoëµËñ¾[o¤óhÏÇ–·ç¸l�k×Ûe[Þ.‡šÛý"-oë‰u?»¼çö|ëµ×¸Ý®,ë²­?ÞõÚóiéúíqBÍíñ·ÛëÕí¡_Ïù¾+`@@@@@@@@@ Õ–owõð5v×;2`àÉÍÉ•””íá‹ÀW«ß ˆ € € € € € € € €4%à |UhàkÀ@ |å¸_¿|ä[ÛXSû³ @@@@@@@@@ •NíºX† &yyy’šš*)¾Zùp8@@@@@@@@@ B�F�¯ÊÊʆºº:1?555ÎOUU•èz±sûØ,Û2f^__ïì×ÐÐ öÇœ‡yÌ„ € € € € € € € € ½@JJг“™›ž½üzø2�/ܪ­­u~L¨«ººÚ {™Ç»wïö<¶�/SÖ7ðeö7“oèËYÁ? € € € € € € € € €Q ˜°—ùÉÉÉi:ðeÂ^æÇ·W/ô2Ëf½ zÙÀ—éÌ„¼LàË7ìE_Qßv@@@@@@@@@ß¾²²²ü_æ :¤c°Ð—oàË„¾LàË„½|{øÂ@@@@@@@@@ ù&ø•žžîøÒ—ø²C:š¼L°Ëôêeçö±Y6?&èeÊÛ°=|5ÿæP € € € € € € € € `|{ø2ËÆ “¼¼ËÕS— rÙÞ¾làˬ³�í6;·Á.ß¹}ܱɹz@@@@@@@@@ vú2?‹/ø²¡/æ²½xùÎÍ6»Ý–7§ò \Žý´Ù@@@@@@@@èX¾=|}ýõ×�_†Ã„´Ì�íåË7Üåò2ÛM9³Îîç;wVò € € € € € € € € €@³æÌ™ãøÒàVƒoxË<6?6Ôe—}×Ùp˜�›D™ïãfŸ% € € € € € € € € €XÀä±L.kÖ¬Y�_ÆÅ0¡.ßÇ6äe·ÙP—�;…Ýûšu¾]‰ÙmÌ@@@@@@@@@¢0™¬>ø xàËTgƒ\�s³s³Ý–w¸ÿ±ë}×ñ@@@@@@@@@ zÓ×[o½:ðeª ê²0³Ý†ºìÜw�yl&;Ä£k‰@@@@@@@@@"Ì^½þúëþ�/ n™É¯.ú2+}·>ö]<�_…, € € € € € € € € €D%`2Y¯¼òJãÀ—­Å7ÀeÖ™å`ë‚…»L9³ž @@@@@@@@@ ù&“5}útÿÀ—öæåtïeÃZá^�Á®ÀòÍ?Mj@@@@@@@@@0Ó¦Mó|i`Ë |¹,W¨@W¨õv?æ € € € € € € € € €Íx饗‚¾|« þ2ezùJñ@@@@@@@@h9�ÿþ÷¿á_-wxjF@@@@@@@@ˆTફ®’³Ï>[òòò$55UR´Ç.gHÇH+  € € € € € € € € €@ë|ðÁòðÃøjnŽ‚ € € € € € € € €Ä.0hÐ ™6mšÐÃWìŒì‰ € € € € € € € €´¼@ß¾}å‰'ž�¡C‡øjynŽ€ € € € € € € € €Ä.`_7Ýt“uÔQ¾bgdO@@@@@@@@@ åLàëôÓO—sÏ=WžyæIiЩåË@@@@@@@@@¢0�¯‚‚ÉÏÏ—ÒÒR_ÑR@@@@@@@@h-øÊÌÌt†s4Ǥ‡¯Ö’ç8 € € € € € € € € €@”¾¢£8 € € € € € € € € �(_‰’ç¸ € € € € € € € € €@”'�t’,\¸PRRRœ=Ò1J@Š#€ € € € € € € € €­%ðâ‹/Êš5käñÇ—††!ðÕZò@@@@@@@@ˆRÀ¾† &³fÍ’©S§øŠÒ�â € € € € € € € € €@« ØÀW^^žL™2…ÀW«És @@@@@@@@@ JßÀ×¢E‹|EéGq@@@@@@@@@ Õ|_¾ZMž!€ € € € € € € € €Q øŠŒâ € € € € € € € € €@¢|_ 阨»Àq@@@@@@@@@�|_S¦LaHÇÌ(‚ € € € € € € € €$DÀ¾fÍš%S§N%ð•�»ÀA@@@@@@@@@�LàkÍš5òøã�KCC�¯Ì(‚ € € € € € € € €$DओN’… JJJŠsüM}5$äL8( € € € € € € € € €@“}ûö•ÌÌLIMMuÊøj’‹� € € € € € € € € €@ââøºã_U‰» ŽŒ € € € € € € € €$¡ÀÍ¿ÎŠê¬ |EÅEa@@@@@@@@@ ~±¾rrr$==]jjj$æ!m_Ñž@ü.=q5=ñÄÎÁ'Ožœ¸“àÈ € € € € € € € € �4±æ­L_'N”³Î:Kþö·¿øŠåŽøŠE�}@@@@@@@@è¸Í |Ýpà òóŸÿ\RSS |Åò"ð‹û € € € € € € € € Ðqšøzì±Çdøðá¾b}úøŠUŽý@@@@@@@@蘱¾ $Ó¦M“‚‚_±>u|Å*Ç~ € € € € € € € €tL�X_ãÆ�ÓÃW^^�¯XŸ:¾b•c?@@@@@@@@:¦@¬�¯Ë.»LÎ;ï<_ÍyÚøjŽû"€ € € € € € € € Ðñb |½øâ‹2lØ0_ÍyÊøjŽû"€ € € € € € € € Ðñ|%ðžøJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@ä(Î:@IDAT@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦øJ >‡F@@@@@@@@ |%ð¦Åøª¨®’…VÉÂõ«dÁ†Õ²¹¼4�Wá=tzjºŒèÑWŠû ”âÞdP×^Þ�XÆœxº˜­˜‚èËÿ×ïÎ�Åÿ÷¾qËSÒÿ c‚b$«À’MkeòóÊÀ#dÌ?ãµ°nd]m­|öÎÛ²~åJyá¼›¤w§.­pT� € € €-%`zJ?îÑ[%·¨³üÏ 'JVNÛø"K]o[©wÑ_È¢/æÈ-ÇL’£Gü¤­œç� €ÄE Ö¼�¯8ðÇøºü¥Ge]C¥vò)î3¨•µ¯½"«7TIþ~GÊþöŒÃ™5¿Š­6ȇÓ^’ûN™,£ûk~…Ô€@VΚ!3ï¾DŽ¿üVéÔÝ÷w«N~ú‰Ì\¶Q6ʪj=»L)êÞYúõè)ÅÅ{ɨ~ù 8ãIJr×N™~×�2îâ;dÄñç$îD82Ä]`öŠErÓkÿ�£õ+éÜ­»_ýõ[ÊÜé߈tÛ[8e”dømMÞ…òùoÊë¼'#�—c¯9Rrp)›Ö®•™3^‘‡Oû�3ÄcN�C"€ € € €@œÊvï’ÿ½0~¼ ¹o@­mósž€“Œz±-´¯˜/ÕM{ìQ¹è�ãåŒÑ‡G} ì€ €´e�X_Ï>û¬ :Trss%ÕôòE_Ñßæø¾vÉì#÷‘fŠ ½ëu¹ìšâèO¤ö ðÕ¨TÙê¡_•òðäIrõ¼Ð§T<ñRyíæ#¤wè"íj �¯vu;¹üš |UÍÿ‡\3öZ~œ\]ú˜$Y×òóeÉkdà'I·Fç\%__<\ž~ÒÅpúüErHqžŸIk,øj eŽ� € € €@ë4øj›Ÿó„•©,‘U³fËÖŒýeô኷�ö_·…E@hW¾x;ãøšsÊ>ò¯×DFÞ÷ºL¾”ÀWo)‡ngM¾ž½r’\ AËâã&ɵʺí5"åkå¹Gß•…Öaâu²ýæƒ$Û.·ã9�¯v|s¹´/Ðdàká¿åšQ7«ÑQr]é“’�î’�Gí#ÓôÅú¤/¾‘#G6ºÇ«¦^ ÷^õž®?Y¯ëþ„\�¯F·… € € €$­@¸ÀW[üœ'¶ç‹€Å¿—»çŸÛ¨‡ô¶Ð¾Bà+Ü]d; €$³�¯Þ½„¾jwIÙê�²cÇ©“ÉïÕ[ºõnüa§Me™lZüƒìÖ‘ëÒ2]ûê>©~…¼ ôðåµàQò DøšpÓòÒ©>ß^ªX-·þïò×åæºÇʬÙ7ÊXŸ±ÀJ·l”UwHMF–æåJ�]¤(+-©N‡‰¬“ô¬LI—jY»v³TÔ¥K§.]¤w§LWÙªrYºr³”iÎ,#'Sºuí,½‹òµ|�©®R6¬ß*wUH�diÙ®²g÷F]Ú莾ǩݱMV¬ßî#· Wöë%ù�§ê>�¯ î¬B �Ä=ðÃû�Š5+dó†:zn†dæI§¾=%??ð¯VªJˤbg¹ÔékcZF¶äê0»Y¾©[íÆ_¤LfŸöyAÃòÇ4GŽ9¤«ÔTÖ‰¾èJ†§ÊZ)ßP"©E=%×w{O#¾†Z§î´ì,ç=S}é&Ù²j‹ó~*³°@º YžcÚÊ]s_þ,!€ € € �Ìq|EÜ6áU‹[ûŠVY¯M,_þCnÚVÒyà€ m1õ¦îZ[w­”­X-;¶š¶¢ÉéÕO?ã Þ;;�/ïýç €´?_ ¼§‰|mz÷qùûñwÉúÀë±\ýìU2°·}#î-°þµÇå®Sîò®ð<:CnÜy§ô òA(�/’X ¢À×µ÷ÊK“öô»Êò¯K·sžÖucå3 |�2�¯Šåá;§ÈÕo®ö+k.½ã^ùë±Þ:Ê—¿#ÝN{Ln»ç6É~ã�r“ö$æLCΗ­/N�Í3§ËÞWþÓ½Òw6V^šqµLèç…馥ŸN—3÷Oo¯c¶øè‰2ëŽI2¶»7Áe�{çãÈËß”cþú®-ížký7ký�é |P±ˆ@;ˆgà+ê÷!¥Käý+®�Ï-i$zðSo˯ΡéÔùú�‡eÖ�—e�Jißc/¼-'ž¢åd—Ì;gyæ¹ …tÕPí)õ2wO©U¶ç²3¦È”gNÕ¨¬wŠæl='½û¶ô_øO™zUàÁÇÉä%OËÈÁ�% |yÍy„ € € €@² Ä3ðMÛ„ã×ö‘š%/ÉU#¯ qKŽ’«µø�ú}cÛ."AÚW¤|…¼É%AÛ|ŽzjºL8g”O‡î!/Kn”Ÿ!³Fž#Ÿ}èõOÉ…>Ò¯ Ç!ðÅ" €´+_ ¼�­ø*}í¹í”GËûáä˜ tŸ�ßé>Ÿk¡óä�5·‰OqÏŽ¾<çmÿ9iö7rä�þ£Ùøòˆñ@Ú¡�¯ÞÔV |ù¾©•Üøßˤ�;©UúÑ?ä¶£µÛ]�†Þþ_¹ìæ1.•ò…òÏ¢ 2×,i`7þ÷*ÝÇÝXy‰lÚ$Òs°~¢d"ð…UI'Qà+pHǪåÖ³.õ éøÙg7JÆkÈè;M7]Ú׋Ë„!î?:«¶ÈÃ7L–«Í¦ñ—ÊÖû�3Тoðêü›4lpòÞ’­C8–ê¬9ëßwzÿÒØ˜|ðñŸä`wX«¶b‹ÌY´Sö³§S‡T­Ö�Ù®�ÙèI2oÊiRì.»vîë2ôBWüìÐßÞ!ï^°·so|�+ãÏ—oþp¬ ïdÂc•òúÔ;äÔ˜P™O¯eÎ^®|ù`ð�v&—ÀW ïCÖ?q¥ÜuÉtGÓôÒ5A{éJu–t8í¶_ö,ùÙ.ìõ/ÿCÖæ�‘}~:Â3Ôcý–ùòbŸ“�À˜7fÊ—ÈìS\C:Nœý¥¦ �fÓQRÝosSùþñ _�¾H{Îú¹Ós–'x5d’¬}ñ4éîS¾rÕ,é|ÊýΚkï¸[®?z˜ä{Geô”ôÔ¡kž™ñ’œÞÏ¿ÐÇOÞ*Ç�/ŸÞÆ<»Uý çtµ3”ä½Ï=+—ŒðÀ—GŠ´;�x¾Â½§hü>d�¼=ê`yC_"�zwŽœxxÏ0®»dÕkoÉ’9ßÉæµk¥rg¾tê¥#'>é tàë |¾+òi°ôi�Œþ|ê9aŠ6|žêê)Ì^I¥ö¤ZàêIuâ�σÀ—…bŽ € € €@ò Ä#ð}ÛDK¶¯ø´{ø´ŸøÞ©à�¯MÚæs Óæs¼¶ùÓ¨ÍÇóöØå |�>‘Rìÿ¥9O/fzwkOíÚÔí™|y(x€ €íP€ÀWojk¾¼ãºß(wÕ\èòÍçÚ=o¼}†Z;õ¹ç*E=Ä·3|voô�ÀW#V$¡@¤�¯ Ç�×/í–‚n=eäð½äðCFʨ^î@TÅ÷rê!×Ëëá®ß'ÜåéiË'æ»{í–ï垟•?¾é‹Ù�: ãÊ)¤·öÖµvæ¿dè•ÓtËÙ²ö«“ýz 3Å=Çð¢Ñ³.Øq |Yeæt8�x¾¢~"ó剢“e�j CùÝ„ÊòöA?s ýÖû,ø7 z CÕíy_äÓ`õ5è‚Õã9-_  € € € ÐÞâøŠºm¢EÛW´{è Ú.R»Z^Í/úÉ“ÿÑ—rÌ!]n½·Ý&Xà+X[Žoàkо²|j$ðåƒÁC@hw¾xK[3ðU®=|ÝhzøRh§)ä?›÷�·o_ïj¯`Ç›}ŽÒ}žl´OSt¾šÒa[²DøšpÓòÒ©¦[éPÓ6¹O{øºI{øºó™g媑þ=cÛ«Éà•Ï•;¶É· Êÿßý2užkäۧÊ?Nì+[´‡¯~¦‡/Ñá?Óá}ÿÊÕµžcëá‹À—�2@ �¯è߇x¿�:òá·eòä!o„' .ãäôwï�ê+Ùéš|­Ý$³&,ÓtHÝÓuèÆCî�¯&>­Yøo¹j”²Q{ʘ­Ãè?|ÑŠ):Æù�:ƹ\,¿ß}�tÓqá•ËߑΧ™!EîÕ Ù%A³Ož¹U~ö é!l¢|7÷ײ§f#š<.=|9–üƒ@Gˆ8ðÕD8<ú÷!ÞÆ=ÿ{¹ëýsõNêºÞrÞF@{—¼Cø»¼�„Á†0{{Þùôðý5¯Çž�øòPð@@@�ö.qà+®ŸóxÛMâß¾âÓîq™òò©~=k™û¬}E‡Ê�9§ì#ÿzM h›ÏÝÚæã;£”Ε‡züR–éæÃ^þD&ž°‡>òîã߯£›t"ðårà_@èx¾xÏãøzýƒrú¹ÅR·»¦ÑU¥6Èì=�•��-GÉÅK¦È^ƒ]¡¯Mï>.>þ.g‹·‹\],_¨Ã)Mp†Sí5ãüùËþÅ®îuk¶¬�oÞüQö>g¼ÿ›q§_nfI-ŸÀ—ÈÒ·•ýn~×±8ÿ¦?ÊŸO)E°2SéÚrß?—˹7œì„®Ìº&ƒW¥ßÉ�ÿZ+Çþò`©ÃFj6S¤âG¹óŠKå�ÚË— |IÝF¹vÌoeªÙ®½x½:ãR9ºŸ«w±¥ŸN—ý~÷Og‹§¼.5y\_Žÿ Ð" |�“sfß.ýòDê!eH×!éòzÁø¨Þ‡¬â¹ë’÷œÚ†^ÿˆœwËq’ïôPZ%›>z[6w?LF§{ ‹/–ëÞ½\úuÏ’ª Kä³®�iÏ-qö÷vy;Ç<üº~“´X¤²LÊvgKa‘«;Ä  ’:äÀ4ràc§ÆÈÞK­ÇÙ_ÿ!ðe%˜#€ € € Ðî" |Åûsž–k_ñ téÈ2Wo¾_iSõ†ÉèÝU2ôކj)}í�rÛ)wîùÈ»ž‘__ãþœ©|…¼öÏd† ƒùŒFCàË¡â@@ ‘�¯F$­·"Þ�¯¦Î¼Ï]ÓåÒq_È�‡»‚]¦lŸñGI^É{²ÌtòãLçÉ-;o“ž>Ã=®}âJ¹ç’é¶€vQ4NFvÝ. fûÕ[ŒÀ—ׂGÉ+IàëPíQëÝ&{øÒë÷ _�2a|OÙ±î ™¥C=šiÒ�Ê?ŽíåU=aœìzísYoÖ�×o�¾ªTø4úõ{xð³ȯ~5ؽÎû­PgE±¹Pß×ß!SæŸé|5Tƒdùìè®!T=Îq}‚õÁ¾�ºiíZ™9ãyø´ßÉÈ>ÝçÎ @@@’Q ÒÀWS×Óç<-Ö¾"R³ä%¹jä5îS!C‹—8Ÿ7ÙvŽÐí":¬ã‘:¬£»™[d„Œ<¡³,Ð6;…j˱uÛrf¾vêrÏUú¥Aí©ýî÷Ïô뤠®¶V¦=ö¨\tÈñrÆèÃ}wã1 € �ô¾x [3ðe{°(›3C^¸èrYà͇8C/ø½œ~ϹÒÓ?áÛjeÕî“çÏzÄõáª�×Ð3n”S8_ú9} ùl¡‡/? ’V ’À×µ{BþôÓîá¯Q{ázøþÇåêi¿|ºç¤s/’«}¸¹‚ZžàÕø‹dëý?÷ÆlË‚YrÝÔûåùy�‡,–©O_&Œò?— ZþÒ?Ý/¯»ƒev¯C'ž/S¯œ Ã}úËnê¸"[äÎÓ&Ë—�—Þ¼G&ôr�«­�À—•`Ž@ûh~àëd¹®ô~1� Fû>¤~Ë|yýÂå½×\As¯î89é…ÛåˆSFHªTÉŠgî–~ãúf¨S¦ø(9ý¾ÛåÀ‹åªþ¿ÿFBý¶é—äúQ¶AÒUk}_sÁÓúk}‚†À^v…Àì±£¹OÃf�zDÖÉÛ£–7Ž�É+fÈÈþîô­û@¾¬8s@@@’_ �¯X?çi©ömé‘yŸ.Ï<éÛn3BNzãi9òè=¼=|k©Ý$ónÿ‹¤¦´DÊ·•K]Fºdät–‚îy~�wÎyè{•ªZ}¤ßÜÌÈ÷n¯×åÔô ïYÊK¤twºdEú^(àb£½†€ÝÃ.ø KD@@@’F éÀWl—mÛD‹´¯h§åkJ$µK¶Ôì)è]ظͦ©Ë«,“²Í•’ëþMÕ­Û|…b3 €$µ�¯Þ¾D¾Zú² |µ´0õ·†@K¾Zã¼q _‰P瘴Ž@K¾ZçÌ“û(¾’ûþqö € € €ø ´DàË·~ ðÜ…µ € Ð>|%ð>ÆøºêåÇåû[äè3ΔÔTߎix!A½æûïåówß‘'^$£ú R‚U´}�U³ß��ïºPÿßK¤×�½Úþ 'ð ·­[#ïüPÿÕe²W¯þ!J±@@@’A ¼j·÷è­2ü€d¿Ÿœ §Ü.Îq‡Ž|ñö¿ÿ-¿;ôD9í€CÛÅ5q € €€ ðe%0�%ðõ+Ê-¯=#�ŠŠ¤{ß=¤°k7Ò-7gßø�õõõ²³´T¶oÝ"W­–A]{Ê£§]*™Á†Qj¼;khs5;åµË�•Š’�ÒgØÞRÔ«¯të!)m8lÙšˆ õR^²U¶o\'ë¿_$é¹râÔw%»°kkžÇB�¨¬©– þó ¬+Û&½�ÎݺIAç"^ [À½¾¾Nvls¿—Z½ZFôè'Sù[IO�ï0¼-pêT‰ € € €aþôösòþÒùÒ³_?)êÞC?ßé*i|~F-úÍ ²kG™~VU"›V¯’¬”4ùû™WI÷üÂè+c@@  øJà͉%ðeN×ô´1ýÛOåË5ˤ¦®6�Wüн5ì1~ÈHùõ˜#¤SvÛ£?SÖ"^ bÛ&YðâßdÍgoË®­ÂïÐKäu—þã~.#y±ä÷¤šøà’;€À6 Àþ{î‡2Kƒç›v”v€+Nì%îQÔM²¯œ9úpÉÏÊIìÉpt@@@ˆ‹@M]�¼8–|ðýײbóziÐÿ1µœ@an¾²ç>2é'‡ImÃfB@Ú›�¯ÞÑX_ö”kµˆ­åe²³ªÒ®Jè<]{=êš×‰�WBïoI�ÊÛd÷¶ÍÒ ¿{L"))©bÂ^N�^))� €@ØQYá¼ÿ¨ÓoK2ÅWÀ¼—2ß6%ä_WjC@@@ ­ 쮩’Í;·Kµ†À˜â+`Zª»èhEyù’¢ÿcB@Ú«�¯ÞÙæ¾âqê}üŠSÍe‡ý"ÕQ´‚@éê¥2ãâŸÉÙ3VI*]~·‚8‡@�dؤ�§¿|úÏòáew34b2ßHÎ@@@*pÄC×Ë/’}÷”Ðóàà € €._ |&´…Àס\ã̺bJ%84D"P£Cª-}ûßòÝ+OIEÉF)´—Oü­ úŸ ~EHèpfìGþïuY­Ãó÷(—Ž?QöêÅгî‰À#€ € € €@ÌkJ·Èßf½*Ÿk;K�‚Îråá'ËÁ:T" € €@b|%Ð?‘�/Ó]𓟾-‹7®‘4–mp÷Þ2ù§ÇI^VvE84X3tdÙ�ËeûÚ容öêU²ü[éwàѲÏ/.�.úõº¯fÊ¢Wž”’eßJ�½GKç~C¥°ß)ì«?ú83¯ÀVÇh÷æ½ÍŠ­dÙæõ²|Ë:ùfýJ§G¯óú¹¤Ù·¿›'ÏÌyOŠ´Kÿâ>eX÷=dH÷>2°kOzþj÷Ï.@@@"¨oh�·oÕö•u²LÛW¾ÓÏ�Ìé&ýä09y¿ƒe¾¶Y?6ûM©¯¯—Qý˰}�ŸA´¯DÂK@@ ®¾âÊ]eñ |Õé›ëšú:©­«•ó½ÆÌuÙ™ërye…¬Õ7éëôǼY_²i­»÷9sÌáÎæ/hpäÕŸËPýð³oQ7Ù£°›ôíÜM sò$#-MÒ]?©i’î,ë<5]§2zt·�Ò‰Ð?TꥡÞ5×÷r½ž‘>6ëõw¦¾®Fôw¦^‡êkku�Îu¹ÁoY×›2µ5®mî2fÙY¯Ë¶¼©Ç®sê3õ8õ¹÷Õåªò2©,Û*•ÛKd·þ~V–•8a­Îý‡‰çgÀ0)¸—®ïÔHЄö­Z,Û×|/ÛWëÏš¥ú³Ì)—Ó¹«dëïs¶þ>gv• ý�NÕßçýqÍÓ´w° IÕßmg�é¬×egî^n´�gSÞ”ÍÐýÝû¸·yê7ÇKMIIÑÿëk†óXçºì¬Óe³ž ’G@_1õ5´AL#`°y�¾ÞÖêk]­yoâüÔK�™{Öév¿eW¹º:÷zßý<û˜2¦ÞZg^^µ[Jví�­æ§|‡Tékð °›†ÆáNcãæê%©æµÆ=™÷H& ¶tó�²t“þè|Méf)ÌΓîù…Ò-¿“tÍ+”,}]L××&óþ'Mçéæý�û=�÷±w}šn3ï—ì6g÷r†nKólóîc^͹›ëZ{ÊÌ@@@@ � 4j_qÚ]ê5TÕ N‹¶“˜Ï€L[ŠiÛhÔÆân+ñ¶Ã´Áø¶­¸;Ÿ)é~æ3¤Yb«¶Q›ö•’ŠÒ³ H†÷ì+#zô“=ûÉ0}œ­m%v2çûƒ~éÎ|Îd:0óÕÚ¾Ò9'ßi_1m,]µ;SÛU|ÛVlÛI`;ŠùÌÉÕîbÚMôs'Óc×ù´¹øîgÚ^RµMÙ·mÅ,Ûv{®Ì@@�ö,@à+�w7šÀ— i}²b‘ó¡d™†·vê��—WUê›þ:í©Ë¼)NuzéÊËÌvæù™9®¹öÜåZ—#} »ÈØþÃõæezÆørÍrçÕUb>HÝU]éúÑc”ëã ÷Üü`¾ÁÑ ~9YR��#�²suž«šæ:oì÷ï;XF÷ê|hš@fÝVô�B'è´}‹rÚ­ÝBWêóÜžÌÐ…®À•†¢L¨Êþ˜ç]MuÀ6]WÛx]�®s…®ÌþºÒÿ¹ÂF®Ð‘.¸—MÐH§šÿàRª†�RôLh²a(ײ LiY”2ÛÜe̲³Þ,›}ÝÁ'WÊ]ÖYgêó.›WŽÈ2Á,Ðê*éY9;sÕ»vºƒd®™±­Õ×ÇÅXê�'Üæ<6ë\A6WøM·«�s/ÌvmPð„Ú<û»÷ñ Ê«¿A_/üBv&|§Ïg�óZÒà„ÎS2KÏT[3W'¿s?×ÙeÿmÆÐxætîîò-2óî’Õ©È©»ÙÀT€@¨×ß³ÒŠrÙ¢ væÇ4Ü™ù.ýo¼w }‚âî?WXÜw½+DnÂZÕú»oæ¦QÐ6 ››ÞC}æÌûÓ(ç]g¶»ðÌz÷OšÉíc×\÷Ó×Yšr5üixÊy¬ïwô½Ž huÓ×Ñιy1…ÐMcè6}½46&@f~LxÌ —é6oHÍ>v…×L«mHuZÕÄØ™uN#¬õ4Ëž²Þ@[° œmàµ�1Û0jÃ÷ÆÀ¬3Ž~sýïNFº{�>ÎÔí&´ß=¿³µPènlí,¹™YmüYËé!€ € € Ð6ÌßìÛµ�esùvÙ¼Ó´±lwÚZ*´½ÚiпýM»‰Ó®¢m5Ú®Z£_ ö|A_·7jsÑí¦ÝÁL~í+¦…Ä™´ÍÚicÑöû…4ÓFàÛÆâý¢™O›Š–ñ¶¯´ÁønÓÇ&�Õ%7_ºéàL;‹™gjûl´“i)qÚW¶;m,¦­Å¶#Ùös­¦£Xs:1ÐeoÛ‹÷‹~Þu®�›«½Å÷±â´í˶¥xç¦ÝY´íÄõE>s}¶}Ŷ§˜uN[‹ÓžâjGqÖ™e·I¾¶-›á+� °™¹YÇ„ €´%_ ¼‘¾Ì‡�~üЬ*Ù(cŽ�~V0=o™^¸ŠôÛY0Ñÿ%z2´˜€ØÆÛ´±ùQ{+Z¾e½óÍŽså„rÜ�MÊ ùè^~a³œ2e\ëÒÌïƒÒYt�+¤•¡�õÛG>=¼tÔûÐÖ¯Ûò3!2Ÿ Ÿ_àO×G¸­V_“œÓ4Lhæ»5\XYºUªw•I§>ƒ¤hϽ¥Ë ×OÏâ%MÃ#L$³À t~¹v™|·a�v·¿Z»Ý_ï|º; v¦aJîôq¾†ÀMØÊÓ°ånȲ Z¦AÐÓðå”Ó²f�6ö9Á+wÃ`2[µõswBõ½•mu榱XŽýÖÙ2¦¹Ö4šº–«u½m„Þân„Þ¢ßÒ5ý}z�}z �}÷ä|K·­[p~ € € €$B RÛ$¿ÔQmX¥?«�^³µÍÙô^ÕÝùr•†�ô±ùr•«Å²m,®Q�vÛãþW[øŒ'Æ-uLóåïZíEÞì<í*Â3�=¡<÷ãjmS©Õ6×6Wû‹igÛ²SÃ}úÝf3×s¯‹{”â>Åtx0´{Ÿ–ºêE@" ðSË ø2½KL~þAùž?•_ìwPR¦L`íoýK޶¿œ¢ã»3u,ÓÔŠ_’/=ê„®zésÙ KX4p¸3TaFnAÇájÛ„€y^–­].¥:ܾz‰lZ4Wv¬ûA†–ìuÂy’¥ßÖbB ™*õ›¤Ïù±¼üÍ'²¯†÷ÛcOÑK»Û×aš³5$Ë„€0ÁüÅ×Êw›ÖÈlí9Ö4RÿîÐuÌ=læ € € €thÓSÔ[ßÍ•¿öŽô/ê!£ “½uXÃáúCÏÙú©á„¾é—,MpÖò2°k/¹TÛUúéÙ™@@�DøJ„ºû˜á_ï.ùR>úþ¹ëÄóx–Í?ô:íYç’–—/¸ÍO½ù5RC2˜áÿÞ¿ýgÀιAº• §Í9vP�òÍ?Ê×ÿ¾O6÷…wï«’Ý©K•ಓMÀ4B^ýò’“™)W~ŠàI¶kà|#`¾íúÚ‚9òÄ'oÊ}§\Hè+1·�£"€ € €´1�'?}K>×Q*n8úWôàÔÆîM[:3œäó_Δ¿š)O�q%mrméæp. €t _ ¼Ùá_æ[f2Cï$ûôÊ·ŸÊq{��iì÷d¿öŽzþ5»ËeÅ/Ɉ ÿÛQ ¸î$X­Á‡¢A{9C>&áésÊPÀôúúÂ92qÿC:àÕsÉñøvÝJIKMmï7ãáA € € €[àíÅódì€áÒ…Ñ):ö!«ÿtåw²GaWÐ¥g„{P @ˆŸ�¯øYF]S¸ÀWÔ² € € € € € € € €´k_ ¼½Ñ¾vK�TëÐM5R¯ÿkHà™7uèI—ÉПœ”4çqS¥ÙÖ�tˆÇ†Új1C=ŠùaB Ñ)©’’š&’ž))ié‰>Ž�@\jõýÁî†:}¯Ð æ±´Ù÷ q¹\*‰R@_õô=Zªdéë_¶Î™@@@@ ´€ù¦B?�©ÑáûL;‹ùSÇHóiWÉ¢]¥ã>¸r@Ú��¯ÞŒH_æ�Ší µR­X$ÛÔ)%]rELZ ¡¦Jªwwh.¾m ¤˜ÐWVnÛ>IÎ�0 ߡD S&;ëû4cB@@@óyŒù\¦í~ùÞÿ|Yj]óEºÂÓõ € �8_‰³—H_Ûj’2ìei;ë›ÞŽÜ‹Dåú%2wÅåÈ�ÁcÆIŸl+f^¹^>Ÿ»B{ié>bŒŒèéŽaêmåÍN¯^U­|Ô¶{¸Ê­ß˼ïKô3dÏFGþ|hµKª”%sçËV}âe’÷éÕjGNô�R2²$%3'‚Ó¨•5_}&«w©QçÁ2ndŸö¡Hc}®}>W¶˜çZ[vŒñµ8æ×þÆP­©t!Í1ÚÓT+뾚#?:¿k{Ê#{·§‹k×bB_]ô}ZÛ™:Þëkméùláj½2`Ô8韟軑$¯Í‰fj�Ç�ñ¿wÉCÑñ^_ZòÞTnÑ¿q—þ�ÛŒ×�<ÿZû½ZKÞWݱø'ê÷"QÇmù»ÀhŽ@s^—Ö/ø\Vl׿óúȘk;l2N±¼Žµüu¶Û–w z„ ÿ}o›÷9ØùëX²µAG«¶1iÖÑ®ÒÒ·*G;;(Ô/Ó1!ÐÒíé¿GÁ¯%yþû ’LçÚÒÏÌðõo?¿%@ r_‘[…-Y·sƒ,[³Mû×Éé>Pöì‘×ä>‘¾Ì0Že»WÊ왋�àOá€1rÀˆ¢&ëí\x՜ٲr{µ~vÔ]Æ1Jš>“ ÕÕ–Êò/¿‘‹ɪï7JéîJ-”-Ù]Šdð�a2´x?Ùgd?É ²kà*ÓsD÷í='pC�åòŸËìeÛƒlñ®ÊÌë,}úô—�ƒû$EÆW.?¹ücçîþl›\7.Üýs]kùWIÁO.wFÞý™|{Ý8׆dúW‡ ­ß½F濺Rýþ6ý¬ÂÕv erÈÿüÏð¦Û®Ë×ÊìOÌç8™2hì!2°(ѯ}-Õ®R* >œëúÂp÷½´�¤_pD³¶ü5Y.5æ»fåÚsôa²GˆféЕ´í-æ‹tæ uL´œ@{úïQˆkI¢ÿ>H2�kË=)#®9ö÷¸‚‚tx_qz lX4SÞúd©F­\Súà#弟íÙd푾JôÜí_ýM†Œ¾Ú©k¯»gɇ׎m²^}çìý€T•7v¼+Dñ‡þòWï“É¿¸I‡9ŠŒœ$ϽÈ+_ð˜ìû[çÌO|ðK™qÙ ¼ }V­Y óµK£>#ö—Áö6æôîU2Ë {ÇÊ#¯Ü.9,lÉd-°àé eÿË_tNÿþÙ+å²ýÿ?{o]Gq¥‹nˆMlb“Ø „!@‰8„@2 ~N’YCxps +Äâ>~ž5áå9˜; bq w!ÏÄ{€âË�³‚˜û,î€ cd@!‘Œ-ËArl!˲e#K¶d$\oW÷é®]ÝÕ眮>Dzì}Ö’NŸî®ª]_UíÚµûë]Å$|íƒ?üæ!øßï¨É Oæ§�Àÿû‹[ 4|GÖÃù\êd×<þþÈ?Âó7an(lkÇ!X~Ýt¸åy¬V¦~r\aT´ÆZ‹„¯K�~—¥.¶Õý6øÒè^¥˜ÃmdŠ—f:ÞÞÓ?\r.!“Áïÿñs°Ðk�A×Êùñ ì‚løÕ?À?,lv®ÞÛÒ?ý–™ÚÚõïwÁÜ>æç²`å&¸'“Û¾óož “Ñ)ùÙ£&Ê×ñ§_©½WÝ6?»ÄÜ�Xwš ºùˆá1NÙØÝIE¥}1îÚc<ä�_ßãO¿ÄǨðž¼ .ºý'�¯»è�$ý¯p©õ;£mµ!ØðÇ�pà¤Sáâ‰%''þQu*í¸ˆÖ ¥-Woiþ¥ˆêêŽbQ¢G_X1e˜hyEë¥|5!c 2Ð6ØËœ/÷ø×-ûZN=_Šâ¤8Ú°-N­ŽT.Æùý¨lç0"2º—|±Žúä]U­}ð_r¬Ù¬}ÜŽ“Ë×.1é™#ìWú\Êð–;•㽑¿À}' –úÕ» Z.†¿=Æ_Sѯ"·väO2¢mÇdù©�¥ù(¢.d~púSY¹‡GœÑ¾�Ï0Œ@˜ð•<'éh?¼ñ¿þ6íñ¨^n†Ó¾rüøÊ/æÌ½Â×.q†6,…/}m�“×UKZ`ùϾž3_Iøò�µðòþç U c£÷¿€o\ýÿ�ü/„«Ê¿_û>|Þ ëÿøüaõFrý X¹ëeøÖ©ä”áðS9bz¡m©â7dc<•©nF2Ô\ãµ£á¤Üª§cû‡(Êd8sö,(ôÅã¢xÜ*4Ïß9®[‚k¸ÑÆÄGà ÿ¤DÊÇ3ká‘<§À»'Öm%#|�¼ÿòŸ¿ÿ}M� .‡ŒÜr°w#<¿fSàâÕðbÇ2¸ê,²Ê¦„¯¹Høj<¾_pâ$8qj>…I%i$|½Æ„¯@Ç*ð'nå²¹>Äè“?}&Ì:{œIRÛêb[Ý!FÎÓƒb `DÐRÍá9 /Âűÿg�ùÌ)HR'öL _«ŠGøêxêøîí¿s¤_ŒÛÿÓà°Ýöü/à²T6ÑÝ��pçU9ÞZ-ã‘…ŒÀúù ‰Ùz$¤;þô+Õ1>iâH@YÆÄÐÍ‘âììî¤U§}1ák|ä�_ßãO¿ÄǨðtÝ®t—½þ°ï…˼3ÊVÛñ‡;Üð' ¹lÇ$ù+i�¥ù(ª.c~p{T”¬Ü�M#Îì?0ÝÉçFÀ&|Ù"‡é>Þ÷.Ô=û&îÖþ‹ðµ _t¡PRÂ×ÈF4Ô¿áêX¥ë—¼ÿú¥áÓ#üÃ-«á¿�ÿ}ÿ¾Ù‹^‚U¤Ã �3'#á딘„¯ªæ~¸{î Ó¸tcÐßõgxæ_ ?Æ[-Ôu Â�gå#i�&À¡yQ<^‚ï€Å}îCÈ35íÐ𓢪‰CA ýY¾æ>;q‹@Ò¨ccCл¹ –ýòðà ^ýn€u{ž‚á!yW&úwi_{àWWŸw²×ü‡VÀ]7Ì…ó>§ÆÅØÐh{uÌ)ûïÆ uçSðuï¶ák¾ŽN©B1q;Gg[Çœy’E ¾�ðu\a”›cïâÑ¥‹Íø:„/»¥šÃÍ¥ïì«€ ÿ¾3¼^>XKt¿NøÚŒ„¯bm騜¶&'lï@¼”Éý‹‘½¼ºÉïÓ�RÂ×ñ _©Žá‡¡´WÏÇvvwRÄh_Tä Éu|ä-D2ý¶ßt<’ý*¶ÃÖ¾ÿ%«‡)õîU‹á´ï݇—Ê møi¸äX“Fש”ã"—n(e¹¦Vås�è~P|è¸f§4«\ɘ: _Gº¯)Jqtta[Š–2OªâÙ—¥”ª°¼½HêÔwà¥Ìõ|†>Ç1ù¼<Šý}Äý*”ðezAo¬ý‡óá¡ÕÙšÃd/YC&|eÛ9ÑW.Û1QÆÇHâci>:–êì^Ü�ƒˆÈßÅö˜ÊàsŒÀñ޾ô€‘î7àßþàFÌ9ý¢«àŠ3ûáÙßqrœ�„¯½oÂõŸýžŠ7êÍŒ,^c[~g�ÿdÝ«>³s8Bm_Õmƒ¸­�ÇB 6Ô¬ø§90ï×.é+�[¾–Ýòp÷–Ͱóà(œüÙóá¼3Æ`íªUÐþþÀIgÃ57|NÕl#aflÚˆi†>ÂBN‚™gŸ §.†³sl[86´:ÞÙéÙ‰IäÛ˜îóçÀ¬¯Ï†3¦iÀØÐèÚú Dáë¼P„¯½[þ�kÖÁ~˜S0¯³Ï½þîÛ³`Êæå0yö-NÅ£Å#=lÓÆM°åøÅ?iÚL8÷+£ügcná�ÂæÄfŒìÞn{zvÁG²§Ÿë28›„!Ûûþصãm¸ý²yîÖkåµÐq÷·atôd8–¹¯äá+×�c[á¿ýo—ÀƒïÊÔWÃ[;WÀ·LÍ�¤¥ ›à½­ý0$+�Ÿi3ÎA¹¿Žä&C­GöÀæ-ýˆÿT8ÿ‚s`¬g=¼Öò. `ÒÓ¿þpÕŸsòpþÅÍ[¥„‘}Ûaýú¿Àö]»P.‰åેeÊKøÊÊ‹áPæ™0û˧ã¢1÷gÇ«•pÖ?>êßôÄk�ðOß$õò¯¸c=MðÃÙ?¹Kšü¤îm€u‹®pPÂ×5�Ã�ßÿÆúÞƒ?­m‡ž½ÁÈ¡CpÊSð÷éoÆ’›Üý?»ÿúløk'ìÚyû~Núœõå‹`ÎÅç˜û&Þ¿sx Nžy6œ÷7Ó`¨o¼‰[¼9ãÓκø[ð-ÄÂûìýëzx£µÛ{îI3àÜ‹¿‰×£êC Â×0¾& ½-oü)çXòdw¿Q¦-°¡ó/°Óxö¤ipö¬¯Ãœœ[ÇdÓ½‹é†0 ª9îÏ<\~™ær@IDATtÞyûŠ.ù…:mÃFÔiÝ©ÆÕÌóàë—}Ó¼…ëÈnØÜ¹ÓÑkç§Îƒ±÷ת7ÚÝqué5ðýÔ©X¿|ºx vlé‚P_»¾¦¢>Þ1W˜|:Ì:/:t¤“7Þ¨Wƒz(®^ôPH¢‹½<èw”îW¸®‡i¾¦c‡ðµ·¹Èsøt½ýGذ®?9·Y< >ó7gÂWR_…¿=#LqÛÛ�Û?@ñN†3fŸ"‹K¹?|ÿ/°CºM>ùóð%Ù¾#{a[o?lü͘ÿ`³Sµ%¯¯w¢†Nþüá 3ÆTÄRt nCÂ×'†z íÍVØÑçÎ[R¦ ÿî[xo>Médïÿ£NÛ vךGàâ+ïñï]P¿î¹þ+þïðA<¬pò…®Î]Îø97u.ŽŸwà�77¾C§]ú}øŽú9´·ÞÛØ]ÛwÁGxÏIÓgÀ¿ü5¸ uÙþ’¦ÈK[åÝwaË_wÁ�Cî|ù©™çÂ…—] °q¬ _HÚÞÒ±UŽZ˜üY·Oë’àõÍîu¼Û=¬§öîØÛ?8ˆýB^?žñ¶ÌEB­�~•]ËÖ>*�í¨ã¢~ч ÕíÃð³Ô$xC üiC�£�O:i&œ…véehÛEõò¸õU¥›Ž‚º98ÞK4á+4…ÚäCØg¶~€º{Þ)ç¤Ðö×Ã���ýJŽ´ÓÏwìzª—åÜ5£"o^û¼‡ckH†8Ÿ¦PŸ¤rFœ,\ΠT²�Ö½³ ¶ï”s­kw_p©>ÏÆ±»mÛ½˜ó],ywo†·^_ ïíÁUÏ”)ŽýrÖ¹À……×GAì¢Çé�Ä©œD¿X¯Ÿ¢v„s°¿»©\‡uî”ý°)´†„±½¨_·£]4>kº JLh&#°ù�oÁÚuïÁ~ll!gmxÁEâº1¨¢¶ùô€}ÿËÖ+†í¬l.³nŸ1X§KÌ{wÁ;¿¹~øËÕ8µÍ0§åÉŸÇuÈ®�‰íTŠ8: Š<‡žýšm�톶Vt�þ×ýcj«úãB«þȯŠ4cÎ÷A9££®ß°6mÝ;†pÍ%çâ à›ÎÜ•*ÞÛ»#Á»¶³ÉO$KÙûþfØîØÎúÚHõí×yûúQr¬ïfžÿ58甩NÅ?‹ëÎ3 nçb6y,çÞ™;—Ãô‹nw.… _¶ºÊÉ.ðOéYîyhçíØ ï´¿»°ýpÙ §Ÿ•‚o]– ùãrÕûôìºVfgÓ(ç†?¾Úë¶íqçRôŸ\ò�¿ƒYgL±<nqœØòèGßÙÔÏ~ ý1c°aÕjØôþ^€OžÿŸ¾ƒ»ÆÁ¯’“ðÕÿã»çÀ/VgQMÝ…}x1|)jþpn+¥_e_6ï€÷Þ}ú�žŸ9û¸0u|!àÉJœýƒзÙÑÕ »žþä4øÂW¾ß¼ä\ÍS(á«äã{n!6½·^–-xn?×Õ3h#ÆœW²¨š¾òÛŽ4Uau,¾­MôF=åG÷k˜`>òóˆ8H:_ò,Q+:v]&ÆüàÖ1,káý¸˜v0¾Ôá?ƒ)pm�m¤$ë¯� ñsÉ{ !|Åퟞ Iìž¼ãÑ/Ä=(­ŸÇV§Æõ•¨¾{íäãQ öî·YWxi�ïâŽ-ëcèG±_ ,?ÿòôˆ�ñ3ܳF<õT�Xß3äˆÿ‘óû)<÷”¨[½-o•ä}ò/×§ïðˆèZÿ˜À>çüá$BžËý·G,ɸ÷\+^ÞŸï~÷zW«*îx.OûDËúVѲ½Glûh(Ͻ#âÃ㹪é_k¯)óëŠ!ÿ¼é`°­Ú¿7]ÕìÞ2Ü.2Y¬ÒÕ ¢n¡‡ƒüN‹–A•Ó`Gƒ(ËÞëáK¿3•õ",Á€h¬*÷Ë¥÷{Ç™Š:ѯŠmÕiÿþ*­Nâ©ZÕ×Kï~—‹ÚÚJ�q´œ´Hø"9ÊÃÑP•V¦Éˆúö€ô6Í¢£±Ò—K/DUSw¶¼AQ�reÞƒ4! Ï€€ÎÏÃ#ÄÇ{V‹yÎsíÿ:Å"ï>¸Z¼µ3xßnÑúä�‘2Kùæ-~.”ÿºê«³i®+_x\KŸZüJV»¼ÝztˆgþÙ+#ŒÕ¼Å+4™ÖUßàËðè[XlÎ%yüh©–ÖŒ[‡xð•fÞ“oò âèþÞóÚƒ¾—‹W¶eï£íõ£{IJÅJ^½ ží=¡²m{E,¢uðÛÔ“ñ±rm Ýž7ýq{åC â­e·Ù¼tø}ërq`¨O<ûÏ—¯_yoƒ8è[±å9¸ßÔ•çE­§cËjDsc•Q‰—K*‹ÑþQ‘&õ aT&:ˆ²Ê&@�U9e~Q×Bµ�*3úhT´ÕVDÊ/ëPVÕ(‚Ò´×d²i2¢¡©VK�Û¾ ¡é›]<Ü&Ò^ÝSÕb€þƺ´ GHMò–z½ÍÎB/:E$ÑÅ2âi£î'²§« ÕÃÑexWöã[Ì9|óúçÄõ^Û¾gÏ{X´Ôm‹——\á÷ƒ{[û vÁ±Øë¿©‡Åfiß´>ì§Ñõ ˆÙ8¯÷&ö̼ÇÄÊÆ"ï¿÷ÕNC™ºŒÔvZUs£Ÿ¾ü´[ˆ-„uŸ_¿Þ¿FÓ{Ç6X­ª¹6[öµbù«K}9$n½=¹ûÄò*%g#iã-]¯d÷dê;<$^^v—–o0íõUÏ‹.bOz})î÷hw½*gac(ùpÕºæÞ<@쌌hN¦_“ÛGú*[3;Û1‹vb°½ÆÇ°º©YT{óKpìeªEwÈœ¶Õ{šúª‹¥n&WK3 W5áÜ—®ÑdtÅíUž¾AËê:œÓ4]McƒXHî¡c$]aZÄ—SA×+ê*¼y3<ÿ—U5dçÙBínÛv/ö|W,yS¢º©KÁUàQüþXjý¢×£¡\µuCopð+[û¨c;ê=ТìKŒ°¸jþ7Ÿ�öÜëâTYµè ØeÆu{ý�Æ¡õÚ×ÊvÖl.³nÚjÔ¿@u‚ˆÊú&QSæõÝðQõQGÃâcÇ |·‰ªšª=Ò®_C­Ã³ÏWÈsêkpïË·Æ¿P,~u“îƒ8Ø*®ÊÚs–<'ž¸Ã«‡ü¾B<·fœü*[”ß(ýñ/ôˆ*mM{—Xð1+¥_¥kSnÿÖU÷ÿÎñOeêÙÕ,Dé=§=nË7íñÛj÷áCªóD•tü£7$†=Ò^£tKº&z­ÑQ«Ö±Ô°™W¢`‘öh¡ÏŸâԱ趶³JªgÃvµ7ìç£htÝ+Iç«ÂlN*…U]&ÈüàÔ3$kaý¸øv0}¯�¬×#…ú¹Ü^aôøÆ¢:iK;}ñÈA©ü<¶:ÕÎWBü1×NŠ8z؃Îf]á¥-ú˜ñ2>¿mùVÿöoÿ&ZZZÄúõëņ ÄqIø’ýalLõ —6q _}û›ýÀ…bIk�o´�Þ¸¿KAøêoR‹b¹Ðu>8Ñ:„/ãµ î¨S 4ÇHO‰²…ba¹2b�ÅáÂ\^«OG�N²J¥ËDyy¹ÈÊ+«U†rÔdÖFÈm²¬T¦\TT,é@^òšNøÂ?y€@Ózd7Gv$dÕSÏü §e�zûNìAQ¿P-Ü|QÖ4:’R EGÁä™_{„ŸÄ´o­¸Ãi ¹`½Z´_[ {]p¹˜ëÍbÞ5_ÕÚ2S½Z#!Q‚•'¿÷}åCî½¶y<Ô#–ýHÊ«þ®¼æ†�LAË—‰Ê£¾¶Š'h^×<"vFaEÎXKÉ7ˆÖ=f‚—�³Ÿv«x”³îøýWF�ðEHd²~©¹7ˆù? Û�˜·�”‡m¨H{.&Wþèfl§|ò¢‹U }w®vÇm Ì ¦Í)Îò8ƒíŸ ¤YFÉd6òŒIø"mRÆ%š |TAÓàqº¬õHY#¥¯œ…N� Š: uO¸¼2$LøC0ïAwC€ì•J;:­,ã9‹ÝvÌÔèŽ}ª×‚íâ8 ÑÅx�_§L .ïGEãBUn%}*@jÒ߬€êh×Éi©1_{]L„2RŒ|³•6d8% _ÅšÃ7·œ…©+ÄüEw‰ùåI)«ïRˆu„0¤œ  ÂNMéø$ä­Œë ܶé·bN`±40×ÏÎÜ&,Z@l5ÙŠ¥�û49[WÈ^؆7•ß&®Ï\¨ÍWWÕ¨—]*ÆÏn¢Ó*…G÷2h¯Õí¦êJ»šÕCU|¨1J(ÞݶU|¸}«8°O’•ìóÞùÂ=ªÜ nomëó‰];ß^.®Ä¡;�}U¬ìÜí\3¾úÄÊŸ’úϽ_ôøÄ,B¨2œûðmUwá*LìŠNÿÞ37ûò{ä7-"›#ÿåâÙ·;U¾;ß‹É*S­ÚbçË�;źín�™öuh„6šîcŒð5ßÇJbv³x«ÓÃr·xë¡@”± hÞ}âÅ{/÷ë‘É’ød™Vò´!|áXj#ci00–ˆG¹¿™DÖKUˆöòNæh/yã m5Š8Jß”MW4ø¯�18Ú¯½õYV§?øŽ§tᢢ^•'Óô6“VP¦EÜR¬üì¸*G'~ÿ€òJ…èbº0Êê*ZOóC2}àé©$zÑ'�aŒ£‹£qu¯Dé~[=œ«<‡ðU”9|«¸›Ì×/iÒœ^ò Ç›ÈX]Шœ�&•n+ò–ööçòö§r–¹iI§Ü+ÄRJFß¿^“wq‹)Ú•-Kÿ¦òVm=GàMËr“½ú'ÁJ'«Í.X¬ÙÕ'º>èè©®œºÓóZ±¢S½9*‰p+hä/ Ïq/iÃõz=Ö½N#˜Ý(^ξi›«å»Ö\™Îêà”h$@M‘ƒ$ÁÆ}xNœ N›®_­õ@!ú µ®�í˜=D‰ØXÒf�Ñ¥úÉÔÐÕ@æ B ±®o>‘ ºY&¡ú¹xóP\û›ˆÝ�ÍžYÞߨ×øƒë@õ²‡5�†Ûµ ôa©½œýM¤ýðe‰–~o="„¾v@zvüä²»­Û=ÁÚ#o—!}8¸NÐê�¶DS·ª¿ŒBÑRKÈyE"K`×íõ‹U=HMU4j•Ž{¥•˜‹x/%5†‹&½Úú¯ £�j-„Qi©ÝB‰kt#�$àTÊÞ¿cÝÖ¶öe Ú™Îé�ª” ×A×SŽŽ c$Ø#Ôï0á ýrý¼íw¾RFÝ^ù�îkˆ"|m|õ>’îFQ¿�>k/,»�\¿K´z¤ýAÂFk\/6ï߃^ãàW¡„¯ÌRÑsX¾´F_2[PÀ®3¥ô«èϹ®º_�rÞÕù¼ŠP†ý¢ªUù\6¾NÚ*u—XõÙÝæ£­¢Š�Ú®ªq}.¾J6þmì$j§]Ÿ®\kA²Ã`´‹Dt÷m_ûyE�.óQnÛѦŽBÕÖÆ5�$^T?:Bb;™ÑTg‹7_á:�ÚW9ž%Z×e‚̺²æêÇ¥±ƒíŸùÒ¹ÓhߣMçGƒ&v™æ)ÐÏU–uÿ,ñxT#(pTt?�½Nµö•оëØE�±¹v²ÓÃA[[³$c&ФÇÒO&|±5'>ákDôl)9B~�ºVÌ¿ÿa±üõ±q?1t½HŽo›_59ÂÔê [ý­Âòì.´™uG­ù †A&U‘�æ=”J£�gq~öÝM5¢²ºVÔ74ûëL“™¡¦¬Ns¬»™õkÎwµˆÖmUÍ„dâK�Ƨo°Ó‡¯d‚Æ:˜Þ¢§ eê£%”,~�‘!–›š{µÈ\£þ®$ä!¹ÀHÝúˆèqˆX„¨´çmñà�nÀtHŠ2’¡úIJk¼¾ªoùáŠp»x·hy÷‰gHD®ek=‚’’»u±""Í{òmáËÝÚðõÅ$rÖ÷ˆ÷‚2ˆ^±«g¥Š|¦‘¨r¤ñÒX«¶¸Ì<”ÝÞÒ‹ð…m!ÛÃ�üEò£é`îƒÂ‹ÚöÞïïwÚöJLwÿ Š$–M{€�Ó(1ˉ”æ·ˆGßlù¸ýEBžñL;!’ɼ;Wøwi¾VòŒOø2�%jøÒ1ÓÕP%2™Œó�Ú”.jQ@Ñ5í탌þšÊ*Q[W/š;LzÁ0LqaV%£šÈh^è4¦QÜ»évCø RypÑQOÉ`í/$R~]l|(ˆõX˜í{òá§Ï·õÄl!!ú½ özÑ^{E›tðá–©Déáè’„p _ÉçðmëI„+Œà%·]ÔI[ø¶*�6ï·>!Œ¨òFøÒJ”ÔŒÒE¯�ÐÞrÍÊF�¦…m{í։ʻ æaÝöÉ<ªw‡$XiÛo±&KòReìO⽯›"®"±+íÍ{ŠÛ³vÙÁõâÞy7Š«d4¯´…ÍÍŸ¶í·-WÿÊw�’¶(ÀØî�i”7ð°¹*�ujK{E–”ßV1ëW{= 䩇û Šj;æOÖ˜�e̺˜.¨=½˜¤¾y„¢ âÐ)ÅH7aäßJìú£­~±­%mUjvV0†´¹5r‰~è¯EIýM‡6˜ ÓhFøf¿Ç›¤ùÒ7éɺ•Ž'ß9¡?’ô?[Û¹Ýn¬ƒ6éö¯$⩇<*Ê��×h!ÈyvªÕxPÔ94}n ÖÉv\«£�ŒÖ ò6Ûríõ &œáÇp‰Oúº+®CÒ¾MSæD¬*úò “#2kçQžÂ×$?I2%k;§´<ë;mûQ–•À4º¦òÏ©ëÞ‘�®òÒF~Ó¾�˜˜Ê×ÚŠØ£ùÖµÖ6@ý‡: „)ê#µ�é:ÚZ~›ú&$�&ì/ 6*¾ æ÷©Ü}-²åÚ–Eé÷9KËt®Žƒm]DñÁù_ç KliÔuœ-½**�f'&ðïØ¶µ¦Lzñ¥/ûò½�éüŒ˜ln9•Ž‘\=ÄDøòÖÏ/,!/q•ÿÎ÷‹È5·™ð…¾ m�ozYM'(-Ù䑹0ªYãÜäDCúj¨ïäùU4Â×]bñ"‚ öÝ¥Ûƒ2†—Ò¯²mño¡od£Á¿µùõ|’ÝìE/ù~ –• OåZ'"½Éµ�DqóüP¾èÜŽküks\ ›¾»^­§ƒ;;ȱÑV­¢dzsk’y%×x“×rÙŽ¶u,®­]J?ºí|”ÕâÍW•†ˆÜfv‚ºL�ùÁA=BÖ\ý¸$vp@¯ÞNº�Ì_Ók]ŠØ,¾]¦÷)“Çäç2¯½õ¼âø¸ðm¬>×Ò@ü ý[·�mü¯sÊî]]Ý¢_FÉtBdæ°»´{)ç;jx˜¹uËn©çØËÑäJÜ+«Ñ£�Ò¶¡Çvý‘Ž¥8úž wúŽ"™fªêýè®Ôž¢PÍNOІ{lƒ užyqB9kd|ñÕhçDè…ƒ™ˆ!ˤùiý($Pà)SOGÛÛ¬Ûi™f[M·eÉ]õ*âM&°õ+};Y—% 3ýYÌ9”`Aõ·>ÏëDqŠ1.h"Ž#uƒs¿e¹ ô`„˜þiº uÔxèïîݽýb`@nF/ûmøA¨Ÿ¡wg yiœo‚‘ÿ€E^ ç!Ž_‡¦ ö}î¡úÈI«G�0FßLçíç�6ºŠ¦7Ó¾oziH&Ò™J~ÚOMõ¶¶D¢$þCý%Š({‚ÎUª ìå×û„é…½/*Lƒçƒ|&cz'i[¥ß{G|SbF5Ûjlé": ö‘†AxËg|bæÛ—Ï5Ùê«yOõy‰Žƒ8mm=¿kuÔ£Ãù‘Dâè7ÚŽè¢{hø-ß«G.¤_š_¾¿Bó‹€ /iÑõ¾ïñ¶etìb½+à¯h]©Öø×g#GÉßK|Âסˆb®ÿƒÞ£ÖùákEô«x„/aœúVæ,z£~…})®LîùRúUÖ�ˆi ^5½D'e þ­ôÃÆ—©¼þ±WwlO{ÂWñÆ¿µ=B ¦!b/ÝQéø$óŠ?#¨. ê7ë:ÓÖŽ�›ž.DÏšì�$s=-?t\´ù*†ÍIurœ¹U ?AæçYsõã’ØÁÖk} ®Öô›Å³Ëˆ‘íös©±Až“$êŸTNó±*3Úî1ŽGsvþYeÿ$÷ó”R§Òñ¤éTÚwc¬�¬õ0"GÇE[³4cÆoÊcî€ _ElÒc†ðåãõ‰5­/‰%Kî×ËH>¹E'ìTµDÍʨ·!|E•§ŸÇÐ×tß:ÁùD-½‘•¢Çz¤ÊDee…¨¨Ðÿ*+”#—¾ùÓBÞlðäH—•‹êÚÑÖe&`Ðò¼‰“ž«i÷_ƒÓ¥JÐWÈšÁ„‘**C²WTVŠr²ØRoh� :CÔªXc™x9ê¼Ji> ¾.÷W?.ž¨~Dý=t¿XôÓüM.®W‹W²[ R¢Î¡íkÅÊ'‹n½#I].®œ{¹H]ðUçÏk€hÂ×£¯m E�òò��7’…2Þ˜¸æqaÚªÒË›~+òF3û!kä¦ir¿û¤ÚîÐ'-QRSŽc� çmIHPpÍ#õêËüèfzDµ�‡v‹÷^[!½÷N1ëGÛ(u�Òº¬˜ŸáËTf>™Èu=_IøŠ)ÏÁ˜¾bŽ%w¤Œb”$$¯¢î)/Ãh_é´�©Ý?‚‘Gh’‰pî÷7¯ß!‘ª¼¢Z44µD>5�Rô}t‰†ÚjQQ^ŽÑ¾Òš”¥o×cÄosé8V‘MHT…zÑZÓªFÓ¼=Ý/ëà;0­ú޹0�ð•`§$¨ªõ*œ½ïÔròFG¢ÿfªzs”¦õ�šž,^:ÏI™#—ï@ ¦É<&º´ü\ƒ:S=G›.¯²Eèy*ïlL©ñp[Îíhú¸XQ™�D-oˆ¬\×/ºO,Xt—þwÿ}â&2×_UÓ¢Çz>Ø$–/{X,(¿ ßL½BÌI_!f§.tþÔ¸VŽ`sÏ*ô,éׄ„ïÛL¨úÉ8õ¢& [=4'yÅ#$Y?kû(B_Ññ×v̇"µ±Ì6!ÁÄ[ˆ'ªo‰èÂßsèÈ$%˜‡Š‚+b¡HUÞ.¦@Á´<µe»Ž}»Î³¿iºXí�Xús7F6[üzùòíž Î] Ú�ÖÁÜÏr”Q;)/íKãYfdÂ\+Àôê?’±!�±. êAóó#Α‡Õ¸%¸ï4#úGm=¢®˜`ÐÎY`RH¿pl?ò�’‡¦õíŠÑô^»þga;S›‹`K1£rùu é<�K‘ö“‘9`T4.ôH§j‹VšÔ|LúeÒ94§ =,T'R~œqa®Œv–öM—9wY–›@jÂ~ÐþÕOƒÉ Kƒu-t iŒÈxÒÚ3V›‘üBý@ŸÌë»@¤�ú._ÚQq(åowé_Ö,t•ž�áíû˜Dé2ÚOMõ¦mË@1}[˜¬5lü‡Úº9Òž0oÙ™D~Š�yLDõ©¨ó†¶ ž¢mY”~, ð›–ÛDºˆàcꯚLß-¹Ö­Éý;qÚšö/s:]·øò’:P_�µ~£ù™0uš�û·½Âÿ™“ð…¾‰Í4ú9‰Ü­­÷[³‘¼A"|Ò_A£R)ÿ!sE’’È=¸Íäñ«Ð:¡¯Aù¼5ˆë—é~ ê“‘Ç¥ô«Ð¼!u£¸ûþ€O},w/¢‚¸ ‰––çÄbLwÓ<ŒöE|*³©/f‰[ÇØ¾L}5__&×ýñ„=¶�±hž‡E=y�ŠF�¤k4ú2-+î¼è®ˆ:ïÐúÉÛi¹QúÆ\G¢s“ÚÚY¹KâG'm+w2ûÌs}œîéRÎWX‚±Í’Ô…¦-†@ó3�9¥øóƒ“ŒæMd5bâ¶FIüjN¿÷ÖzuŒ’‰Ž+µö„•ßdüxuÄzÛø¹Œe%꟮œ%�Ã1Å3©Ÿ‡âb§S-|%´ïFô§íkX*k<=¬ë sZÒ×èZµkGC›+§˜ðUÄ–<æ_�«=ûDëúf±$ýë6±Jîa¸Ÿþ.6á+�A’U}³aÛ ¢"”UL¦ÅHø\š„»M5” ¦1nºŒ¨nh×"ïÐò¼‰“ž[ØhŽÓE'ßȥʘ8�Â2+¹K™`ãMÐ�þo,ï‰:Hú"|!1ê@i_§xöŸÕˆ0÷«@IxÚºò~ãâ1\÷„¯7Ì„/«¼ ÉàNÑU¯ÀyJørd÷IPHœÚž'"U /‰ %m…ÉN¹óÛóÚƒ>¦~ZZ/l3‘­SÜï÷¿›Å»^T2Œüõà\Õ÷Âm£®ùå9u"„/S™ùd"×µ|mä‰KøŠ9–¾­¶\Ux˜°òÇ}vdÉ­l)™3˜&³°Z´ä�:Hjwc•ß‚ùé¿u‡Õ ž^£ùj ‚]¬9®5i8~õ`Q’ Ò^¿Ãûý A ô¢µ.Ö+küEóVÙëac!Ù“FÂW`N.d§13iKÎõ=ân¯�åÍÿùÓ¤ áKK£lêLUQu�Ú"ô˜Ê p£XÑ)#–nwÇà¶–ë8zyÐôq±¢2ÓRÇ©�un}A#…µ6ªm ôqÌC94sõ¯B®uÔzÑW½­U¤×Õi·|Ï.¡[ϨŞåI  ÑWt<çÆÔØڎ¹Œ¥O½Eo¢úæ–'Z7#1§ÈóP±pí¥[;☉ŠàKËSzYÇc ¹ÒŸ½·ÎhºXí¯µS…a+$½lïíš- åçõµÜßÞx£uˆµöð„Êñ]�¼Ú<¯gfÂ\¿Ãü+~,‚~‰[òö«·5£zC£N¡'¸Í‹€èE¡"[dE:û‹ƒ íQcBnwUéÏEŠLiLKû(ÁŠÞ»ÿYÛΤ½#lQ*—ª?Içé\ n$vUxÄ.>‰™´uôC-#ÿGÑæÐüµy.T'R_Òf¾px9ÆéM†ãÜé,Ë¥uôûeazÐ ¢vŠö‡…î>ÓÚuÓšFõ¡à�1Æ�–4 £¨ó*±{’.Ôôvެ !vÑmºit4eÓ)y‚Gñõw0‡ÀoÚ/"úqP—y;¾Q¬Lõ¦mËpD,ŽÿP³Í0’BxkEY˜¹}“ÈŸ›¨2£ÏÚÍô3²-Iý"ژʫÙO¦r¼s´¼8Øjérë ¯ßx6™†�©.4ï<׃õ<"þ¢?hÿŠ5¿GÖѲ�#óóZ~�m™uÿ½‹ç#|õËïPD§9UMγãzŸ®ñ#|Ò×°ùõûüµˆÚº‘øR"Ébäž\„¯ˆ²©ÌûUh�pN¾¾êygkË�¯ª:ÈþoÚñHøU¨ÏƇ¹¿¯Þ–�2²ý½éÂÆ¶‡WlÂWžñ­“!³=“ôu:þéX4Íenj³=B# Ó<›«Ò~_¤yÒ²rãéág硲Hùi¹Tž,2Ù/s‹fkc)%Ó³¤meÔ¤8s½ŽAà—–¯×&¹¿ ž¯°(ãÜ«•³.4­6FŽ®ùÁA9BV#&¤YŠnSPÃL%SþqeÀ�Ö;²¯ª²½#cYZ^¹û¥§oTÿ,áxô„Žú&kÿ¤~Š‹WÇÜßD§ÚúJ(î}Æ´v¢²ÆÕôšÓ’¾FlMÙÅ3Q ;ñÏ3᫈mx$_a˜{†²ó}p½Ú (däçªåñ sÛ¶çÅUÄÁvoKö�•ˆûm_U-.jttTпÜMFC„²¢Š 2¢¶¶FÔÔDÿU×4-ˆ 0:Ð-ZëDe¹ áO±ŠTa6H© ¾“8P1º'®oäReŒøWÔÔæ”½¦£ÿà›ãî'?6Tñúebâ¨ó‘C?C„/™G#1uˆ}ÔåÂÛ*ðPÇr‘!qNýèñì ¯ˆukßïul=Û:ÄÊþjöžx„/ë¼ Éȸ͠V/E¼¢„¯CNÿ™û Ø‘.*Êׇo<¢°¹àž‚‰g2¿W|Ì@Ì{òÍð–Ž‘íµU<껼mûÄÊ[©aöU±¨z¹xë�7Å»íkÅÖŽNѳv…ÉM#f •‚ðe)OI _â�¼9�Â1\/ZÚÚEGW—èîî½ #áË]£¢»£EÔUWŠLšâí#AÊgBù‰Œ£ÝõªïÈqUV)ê›ZD{G‡èÂíJzû{Eƒÿ@KwˆQ��×H‹ÐÅšã:p�Î6ûÀ¥«~¡/¯¶ÍJ½h­‹�ˆê'iÞ #{=¬ç®ÿ*„ðEçö¨9œ:ÄŒD$gŽï#¤EÜÒ1»cþ´Ä©Ù2ä|Èf!×´4Ê–±rLb=tyI4³šÅõT7—ÿÖYLOe™±¢2q8NÔ,U5�Eÿ-yX,ou£­ölû�?Nä¼2{Þ}bé«ÍbÕ¦õ¢e[§X·k«X¾ÈsJ�ð5L"ó9d›AEÐô¶#ó£`¤ù¶bsE:+«"ä}‚é¨þñm•z �2éx¶µõQ«~Ñú(]¡®kòy‹ÞDõ¥yŽiÞÝìÞ]¼y¨8¸ö‹ïmFoì"¹Ã4ÒòÌX#Ú>ù„%—¦‹Õþ–†-y ðËS´Oø}\^ ùa]ã¬hb­=d¹y>ÉkìKnÆ&ÌóI.Çé�–s0Å=v=È[óÙm§[¼‡'¨ �U‰UÕ‚Úq É·Ëj;H] =,Ú/¢Æ„|@Z“öìLÜÒ1ûº¹1mVôÞxý/‰íœ¿½©\ªþ$�§sÐÓu:`4Zùº}Xæ¿åHõ³hshþÆyĆÔ7¢GŽq?óAît–åÒ:ÆÔƒf)ÕYÚ¢ú©ºÛ=¢iT Þc iI£0Š:¯›±'é }›¦‰® ÍD½⎾¬Sñ€RÉ¦Ž ×U*MÄíý8J—å«7mãX65©ÿP›ÿSQömµvO">l¢u‹YIôad[’<#ژʫÙOÑ¥é¶Ul©œ±uQžºÐ¼Mu%×i=�˜‡èÚ¿¢ô&�3}yItRKl°-�í™müø‘qò¾Ð/±¿Y{>òDçˆèÙô˜¿&÷×ût�áÛ�>›®Ö‡ý´*Šw~¿ˆ¾í£Zç»~ üé©�Â#0Q’ñ8G�^®¹Ñ¯‡ôK<±‰ø\ȳ£RúUhÞ�¹K,Y–ç‚þ–Å5ω�I_Ó>±\óÝ^(ÔüN¼ÐÚ*Ötn­ÛzĺMÏ /R¼‡×ÑOø2Û#r›Ørl#繄 I ýs4¢­þœËv^¤#“Çwöªo¢ís‹ek—TÏR=g>¢šŽi¾Åž¯°íP’üsXÿÞf}µ¾Ë`+樿éR.Lüí$q®‹ŽÊ£? •œ4ù¡}Ê·s"ô½7Vÿ£ùŶ�ó·7•˯u˜{:×­2ùß«æ0¼§_PS/u”·”%‰Ã‡ÅšC)^šþ&X„êD®ii”˜tŒj:IÝb<Ê�βÜzÐ($9ÙV£ü9QÄr»sXô1¤@¢ýimc‰]ž¾MÛK�M ç�К©ér;Goþ5ͽáÌgré*s r6²ï“{$yÕ_èõd¾z[Û´hzlá?ÔÖÍ 1Æ�¨ð#«µ{ùóaƒ^QK0U.ܨóˆˆãȶ$yjãAåCå-XWÑòâ`›Hå© •ÉTWr�Ö“Îi%õï�y„–i=¿kũ 6·±� &ÕŽ£„À¢ÆˆêAᣂ_¸¾n]¹À׃òEý5ë•?Á_ïkküÇŒ/•ɵ:õÌÉn¨‘¹4_ŠzN»çHùU(á+yl�Xª‘¦®+wQyÝãRúU^^Bü[›† zÖåøNh½à ±|›Œ�}ûÑFøR6L\›^öü¦Jïe<uÝè =¼&öFH’yÅË#êÛ8¾³7'±¹än�-‰¿Šê¼¢ëÙBôXÄ\…§s¾”ó`l³$u¡i�âùÁÁ6BV#&9 Ÿz$x¾£ÙcfªÐ(™hŸ6Ûÿ†õíS1ü\Ʋh^ |\E� ºÈ£bùy¬u*íq}%4mDŸq^–!v¾ô%Ñôšû±‰­ÕÉÆLT®ÿ<¾ŠØ†¥$|ÑhK6 MbxjoQàƒÂ.r-d z×¶’ˆ$„­wÝðM gc¸O–iGø2½›Ÿ¯ÁˆbˆPVÝ ŠH•Ƈ’QŸáÁAibX ôλ¹P¹¶Ãõ†›&3ªËj¤д ÕVj�NtÈ»5oÛS †Åàp�ö�ªxU™Æ›©ØÀ9—Šuµx=»Å!%I=ñ¶�H¤‘ž0â”·Å ’�è–‡&2”uÞ¸] %§y²RbÕ‡k—ŠÌÜÄü[o�þ~mˆ¼öèÛ=Î9eÌ'·`û>ørg,Ò×[‹ÉV˜Ü)ÞÛ§"ŠQyÔñnñʽ$Í5dëÆQÊT¯�µ{²[:â9ÿ;ß}òfß ’©ÎFsa„@fŠ*FËËsÝ�f+O‰ _>FhÄšáÑÈV™€nƒÁq�tH�J{º¡¬]¯ù?T7Õ´¤ne^ž€È-TWä5Ò"t±æ¸ÝCô”‹–ŽFU¿… l¯íuq<|F¤^¡:»yRl©ÎUâþƒïeo©WŽÊ«–4‡�ZrŽÿ IÌñúEê>ËCJ42’Å>xI¥Óœ”GáKÚ-ëõmæ¯Ü¤á‘+êÄ5ÛO�b�‡1:W~p.ú¶Ö>ÑuPw\êí`°5{#´e·äÎÕ¿ »F¶¸Âè©> ž.þZüy¢²¶Ú?Ö"öÑG±Æˆ½(Ä9’ÌvÌ� óJWÐ4Doø‹Þ$õ¥yŽs,ü‹=%Åu´‹Fª¬]ôAŽŒØ·;­W¼µEÇ|)oàÁZTR?â꽊&󿦒ã÷G2–âè—¤õ dþŠ¥û(¡Ä�€˜©Tú·GÀç-±>q1¡ÑSi„j­Pº¥6F)óZˆŽ'_wEèëþ‡ùÙÛÎùÛÛX:ù:WCÄùÑU_î¯k*jk}›9UÙ¾9ï™"Í¡økó\¨NùqŠãyê•;�m¹öz0�¸‚އt¥ÉO4(ê–‰ êëò…ÕBn HÓ$CƇ³íÏ_ßi:Ë;’.ÔtŸ�?¦M ¡Nô#� Îª­ò¶õN‹&/¸¼)9WW‘¤æCÚ÷±n¦ùV®=}}‚ëËB·t´¶I‹ã?Äð£Dv3©t´[oùé6÷‰¨>uÞÜ|ÚYÚ–Eé÷ZîáÖØ&ÑE­ŽYñ"1_§v"�ÓJêß!ý+Éüîûš4 ò`ƒÐ~é×_kGß·}©ƒŽ‘p§Pg %|õÆÈÞþCQŒ²�ò"jƒð×û­óý5>¾8±Æ¡ê ß¾Xðª÷B>ñ™h¾ê' ÷ŒáË(W§¸Û'¢Êgw‰'‚–’»”~•Ö•wùXzÛmšž‹mÛ¿GÉŽRÀçjÛ|ÿ‹’{ͲÛü¼¯ªiu|Eãá+‰="{ü`{­_Ÿ²ÚÑ\¥dõÝú€J2¯¨Ñe>2Žïì­ÉêX[»¤zVÓcñæz3šÞÙÎWX„±Í’Ô%r<ºæÝY�˜xÍ�ßE·ƒéúU›SU¡Q2é}Úð4É´±ôsѲ”]iß?i~Å·{v‘GEòóXëTìþÚ&îsFÚwc¬�’èaÚUûStÉ'¶¦¼£øc†–{l3᫈í9¶£E<õÔSÎ_Ýšž¼9{÷æºÑ5D‡Ä û4�S ÄË ƒÖ×Uè_I ºûuw‹ß =Ø#Vµ¶ˆ—ñ¯e}¸G[œÀ¼Çĺ€îç�†nצßù¡ke9K;U^;[�ü_^¿É7Š�&— NkTF§Toc–€“UÙ‡/uj;±¨èct±ë9íèäã)3ªà€8Îý¾€åûÎ=Ä×_Äâ ô¡Ha­1» [º¬J¨g]DiÆœü©¼AŠ/³á DøŠ ¹D¤Ýâõêü€"nQRÖ£o¸$)E^ê/þ3!/!^~´ª˜„¯¸y¿NHS™‡Â‘¹è–‰óŸ1¾H4®÷ž¹�Ô]‘ÝT=s�¸¶¿(®Äz˱èüͽS¬ÛîFG §ï/.¾ZÝ‹iž ˜Rr^›§³\zVÞ©ÒߺB’¤­�„ð…Ï>tˆ\JæC+t´”Dj+áËVžR¾è‚IA3Z:ié¸$n9�ª‘xµÐs’DŒ]Í��F^0oÃðÔ|‡uÚ°hô·[sûU­çÇ̨Nðôš^F~}“›ð%�rè÷mì“Õ†'ƶz‘Ö#®.ÖëþeÒýˆœz :¢-©LT÷‡KPgöÞ[œ9|×KdnWÛ5ÒùŸŠfßÿ’O‚¢ç¯¯[ïŸ÷Ò®¬RoWêÛSSÇä�bU–€ä¦#׌Dý X/”¾Wf®o*¯ï„ 8ò^ o„Ê>XÕJ"�%À*?ákDPGo”sÒ³ çÌ{@´dqÓëÜ6aÚ“Ê�,ëä½Dàô¦á~ÑÞÖ&Ú𯫷-¢ú <¢¼1«“jTïº$Á4jíLj­(d\ÚÚŽ:Bæ_tÌçÕ§dÑk__³þYºð÷ôT‰æ¡d¸v‹Jonľ\Óæ²©è¶j€[RP ÕË€{Ã\gt6‘<}˜åÚAbÚ\™öm& Éß:Dy½�ðU£¿bÛî´Ÿ{¾£y× ôeo‹L¿¯É´�ü~¨Œë2-þ°î�öú%Y=È[±ØW]ý§oÁ­" z×eÄÖÄ![LhDUIî7¨~:n(™‰ž÷u—IÈf&Qbõ?[ÛÙé3ùÛÛXj«!&a=‘í�ÞVœDgȶ¥örö΂¾Š2‡Fà¯Ís¡:ålj¶_¡¶©¬´–. Ë4™¼¹&€”–žDÿ³Õƒ�ìÃ?é 48߆–ýž�HŽÓìöFECeu!yèÃÖ¢ly–§oS¼ý1’Ê=á“T³:ÍyyÍ[»F¤qNÛêª\yÊk´ï£L¦HcÚÚ’D—Í[oK ˜þCm¼`ýLÛÆÒyJ#³XÊ/aÍ‹�Ö§hÄ$¢WB:GæœãCÛRÓ $Oí¼Ê‹Ê[¸®"ùÆÄÖ^‘2Mu‰Ä [Wr�ÖSŸÓ‚zý;d=B1�5¿“:_¿�¨lôèé^ÿÀÈœiecicÄ»Åð]8á ·qÜæE|Rd/iP_Cýýj-®¶kT$¢>Œ¦^ø¿BÔû±òûEô_GȯB#aEøkú>з¼„yK…¶M)ý*ôeE$Á)< æÛŸÏúÀ®÷zÅM÷ÿ@IDAT/ùÑhlé‡C�d[û/Abüß:ϿƓð…Îò"y<›Þíú”tAÆ }�Ï# æ/‹¨oªS‚ëʤu,†­}äôl̹> Ðìù’ÍW˜¿Öf¾½N湘s«fÓis$ÉS;¯*_ˆ,ÅšœR#æ2Mº*•Lí±XØè/EÆY�Øø¹ôñ£Þ†´íŸz~Ŷ{T¿Š>*’ŸÇV§&ñ•о‹c´àµS‚¹†Ž óZ“ŒqÏÖ,Ù˜‰nÕ‰~… _ Zp×{ëÅŸ²ÆÚÖ¯k~㾞úí Bž“ÍÚÚþ$Ú6öˆ±@Y…¾Ð ì àî¾²u½hé\/^xõwâîrµppÉhp£{ѽàgct+ú0´«Uí1ï:¢ÑØ]öœ�Ä­uÛ·ŠuÛ6‰U-/‰ªûÕ[ n9¿ó‰]r�±ØwzªHaGá cèmʤ[&ںŠnÅ0:< :šëȃ^ä‰áõ¶ƒ\Ö4â–ƒbx£i àCÒÆjb\§}¡>ùx“Y·JVb˜*¯½˜× èjkÐÊ—×é"ž†Ì—×ʪD7Ê1ŠòôvˆºJï KY7|3܃(͘“?UÈ�®mݽ¢»£K øy:wögˆð…Ûÿ=ñÌ ñì3ËÉßRñÄC÷ˆyd[CY¯yOªPï>Iˆ`¸ â[[Å�=}bgû+âÑ[½­Õ‚äŽe*m¾_Iò>Ô¾<ûÐÆ-{~õsbëö±gÛZ±rñÍän{hˆV¦GëÏúÛRb~HšÚ M…É[ŠPÕóÂý¤¼¬<÷>"^|yµx·}­x÷�WijÕ÷(æ7bìà\ ª_òžûŸyEìÙÙç`¾õµÇI?Çk^42-ʈEË0 ¶Ñ���¢õ÷jidž·‹u;=RZ _¶òÜoîÌÚY˱„FŠz¨‰‹·º1€úcx°_´5Pýá¶�|�ÐîDô"å!véŠZÑÖÕ‹QüdÚAÑßÝ&ªËUD@�`¡ ®ýè¨%ºÇuK·ÔAâ¿«EËÏm/Ô…uê¡3Õ y�´}½ˆËŠI WÙgœ¹%ûpE« ÆD$[‰Hy ׋öº8 Bè§Y÷“¶ŒÀ…bKu¨rBnéXœ9|H,§a÷Ów‰¶õˆm÷‰mû{Ä uê I‰óÒm*º”^þbIË&Œ>…¨vmK«nÔõ“î_'œß]ß"6nï-Û%Y)¿c“’§ŠMø’å?AñÀh[+¶{uN€ÕzeoQ0µÉzp‹oìÉï뫞­à›§áÖ�Û׋'Þ%Z³$ý5ËÈùô}Ø~}Nûmìl‹Ëuç³Ìw~�û6ªìNƒþ6Œh—Tµ�Và¡¶HuõX� ÙBÞuê—ªß+�£Â^ä—2òª�íXrtÌçÕ§Þ¢3¶¯o©èÂß×S#ì7Åš‡’àÚ\•öÇ%¡ÈÐß%ªT„ ¹¶ðÈ´Oínûv/Ý|—SÞn…-kû ¢ýâØÍ¢"íê §=ʃ<£úªm$éü¾­—AëBçàÑ„õ ýÕ©kðá‰AV5ëÚQ—4ø‹Ô-Ö¥[b[¤+pLô;í#íÓ–º œI¹éþt<ùºË¨?¤¬–ýÏÚv–eL"ÚÛXL§¶}ÇÆõm¢¿·Û@„êÄ/4§I9 üú@ì94ÿ\uÊ�SÔ¸ÈW3š.¨Ë iš^�Öv>‰‡E=µûR Ec;ú‰0ÊrWK½(÷ý\8V{v’ýңͤEmK—³¾Äù¡Þ�š•Õ‘Úe¶m–«èìü1™MÊ•±² �Ed�¥«"ñNÓ¾�ùJ}U‰kŠ�ì|ÓÝR«ù#h4IÚÏÌõŽõñð¢õ·–õK‰š¦Ç— ûKC°¿{1‰­•Úž:á«0=ê5 ù¦m©énR–v^¥¥òR�¡î0Ùbko“å©K$YùÉuZÏ#æßÑú—íüNÿZ{æÁ!ˆjç`;V7 Ïwèèîh•$ú–ëW¢ýÕÜ/äÙ8„/¹–¹†¼ä–ÕEt½ß³íwš]µ ®YlÞ�¾ô›lìl ÒY�/Ó–?G¢Nå÷‹Hß�2vDü*…¾œ j‹K©ŸçÜÿ<©[)ý*@áê¹Q,oí]èSé9Ø'Ö¼þ[B°CßÈÊN÷9™„ÓNYŸØË+&/Izíµ@¬Ú?$Æ•ð%×ÀÔ†‰aÓ{#€nmí¬W°­f_Hòîq¿íæE=ó/:¾Ã¶cÂ:ÁÖ.­žM2×›ñôΖl¾Âh›Ñ9)¨“ ¶[ÈWBp×b̶²RLô~Læ8_Åó«‘|µ9ÕëÑíd»±ñs™×Þö¾ÍR�G…^ôQqü<–:5‰¯„ö]isà_ak'{=LÇ…yÍEú±okÒsÅ3Ñm:ѯ0á˺‡Äê߸Ѽ<âVÎï߬C�²¼û§µŸôá_צÀÙÁèaÚ÷¼‡ý‡Zä!£éÁhËÊû´Å‡–§©<|˜¸&�C-00Dñ~÷­‰ñ"|yô* Tùc¸KT¦=Ã<ÇwY­Py ‹ò~.lÊjÚü"£&³Þ¦ª‚±¦“̸«¡² ´µíJzœÚµÈ2ôŠ',U¼Z™8 ø!"I? [‘xyÐo�ðeJ› ¿Ì½Ï‘èO�èQ¤|•ÇÍbåïħek{òné¨E¦Š™·$`­[vsÞ¶X´rƒ¿Eãºj]K'|a=÷½M¶‰D¢ßâýt¹È^ÞµžKácî㋞QÄ8/�Ϙ×�{)­•ÔÍtÿüêâÑk²`¤¯‡tÂÍÓ‘K‹ÖõˆVf𺿥#Êe'Ïop¤äûØ�%ÓšbU^Ó ª©3JöI|[zwWƒæ¤¦iôcó›\Æ U¡þ_.ÂzJnWKuE^# &}£mMa¼�È….‘-•}À¢®„kd§1’X]–B�1ë~û¾£rI—œë“Ïá’`Þ*n õ…À¸ÅëóëƒQ¼è6„áûµ~š~@l$Ñ´V£�zßüÔ›Ú› Ùô¥%|!·!¸ �y®mc‹•™:€©½§=—¬'‘ÇèÛ¨Æv¼M,_ù@hÞ ŽkÍw¹ˆ3*‚—»M1X u %«SRîØ—“lŒØé�üe:¶²# "§ Ñ§ê¡™Ž©]}Iá¦C:7Ý<\ŠyH–o�ë@[ éà ÃÛ¶`(ÁººÅ%ÎP½¬é$ÃXñ"†ùYÈé¥m¯£Ä.³~¬h$±ÈòØÝ¶í^ªùN¸M¶¾·N(¤þ�ª@’»‡Xþo»þ˜¬ÓñÔOIêáGðŠÔ}ý¢:íö�(ý™;L0×Ávµ=›a,xcea½�ˆF¶ömÁý!e·í¶¶3Z«y×¾T'øu@YiݼúCª:dÏÒþ"ï+¯s£ôÉúÆÿaÍ�t�òãDë9ë™S7$+×Væ”W^,d<`„ö.úâ[!i°Ç�$BVäs~ß“÷¤)AÞ»è~ ?¢ãÁŒ‘Á©ƒy 5SZk]eÊÌ;‡}Í™÷ )OÃ�âŒä9º6¥ý;²ÞV6@qý‡¨EŠÌö„[oÝ^´±µ$´ù±¡$B½Ì\}Ík6ãw¤#}ŽØ§4*o,]•[;]”§.‘dkK®kõ$çÍý?™'j=b5¿SYµö̃ BÝÎyÆH·äõu„Þ_i?¢Ç&—÷œ#¸vw‡}"ÁõþªºÀKôT?yÇ©»”ÏÁñ{ä÷‹Èò�¸_…n}ˆ¾Lþ§ÖFýåÁ›²/ž9×-}PùUnw§séËìµ@ä1y�Ž«›jž‹ƒ¾[ ¼�9“§�GŽ�<ã_^¶¶Gܼ™Û{¡Ç �0³"8_Vó"Í â8§íˆiձȶ¶7^µï$zVb’G�ie¦Ç<¤K2_9M¢|3Úœd[—È1�gì$‘Åb~pp�’5G?.‰\Àº7zî´]�àš9¦Ÿ‹Ú†A›ÛªRüµ±áéü¤ãÑ=ÑßEóóXêTk_I‚µ“­¦}0Øþ.ÂæuEiÆLt›Nô+Lø²nÁ�ÄŸþ=á #¹8[s‘òâ¾#øàV±¼æ.1Ç_¤x Ìýž“Y žxu=yS"ûP2û`tÛú¥þ’ë—¹Q<ãÛûÞ¶ #GT-ÐÃÓ”æœy²œVÙË+!ó<™p;¨,L>Œ.äÓQ«ˆÔÆñúû™ãä_–-¿¬6�¡=(šj+Ì$Šnåˆm6Ô‡ñMç*²Hôêê~§Ò墶Iwôv�É/X§þ–:ã’²JŒÚÕ¥¶u4½Q1ØÕ$*2ž®Ë‘.¯Â·³ƒÒçÇf¸£ÎïÁPަ‰×Û¶Ò‡?ppøÐAñ1FZšè?t‘äU\yÍ bÑâÇ�è]>ùˆ�‰t4ˆ;æêõ”i¯¼õ~ѺMFºÚ*–ݪoíøÄÛ’ðõ¸_'ù»˜y{y½÷ÂãbžA6˜{³xö�N­Ìw Al™Ažk—“>ùUñb§KEóòÊ5~ïÜ ^|#y™ä‘ípÁåâŽÅK1b_Ÿ&—Ÿ×¾µ>éLnS¹õ�å"c Í[¼"L¼BâÖ+Õ·ûx«v¾\<øÌj§¼=oè·ùt_?ʶ-’È‚ÛA~¼çmÕ‡‚X ÒÇ2Õn9n}lä©1Œû@Ç–†t==–PïÔ¨íaF¨s0‚€ü ´éo Cv‹ÆáÞQUž1à+±K‰òÊZÑöAÑ¿‡»›ÄÂtx\IÒæ<µåi­L9îÛUÄC³È�‘îP‘Ôf}€D’ulP! 5qÆ×‹nº$ºØ(ž4ëþü¸D÷�¨’„ð_rO6‡gçòƒ�AÊ순�¹K¬ØDFYûB–ݳ«Y,:½¤ÞÁHa/Ч¶Df Ý6úàzqw0]f)F)%6:à‚QK�únRo‹FÙ5ž}C¿×,Sõ[²>¸õ¡gÓd¿w5io~Î^ô’Š�j�U±Åªò”ÝÕùbJßJUãuNùÁ+,û¶m/‰ù†q-ïÙÙ¢O, D…•ã˜ö=ÝQÝ÷‚WÚjHäÀÀ5çÞ�Íî ë�äc$¾È_¦ª§�í¨R›ŽòëÓaQç¿­Þ†0~}MR�s9ts)æ!·ä8¸b{}Qá…Ö¶vÌ>H¢äŽšæ6Q¯EÅÍŽ­T™¨kQ±½2xGN=eWS­(3ŒKÀµC½;áj òÙݶí^ŠùN žOÞn\ó”›ê�sûš&íá»DŽñûcþ±Nõ`p-$E±®:#5bv RZ½¶jbã•å[ÇÒ”ê8>&Ù´ÃÝ%Z­Ã•}Š3¢±#ü´Çhçäв$»þgk;çooc¤ X-ˆ´eŒ[¦ÓmÒ¢9 “Ì­àOâ94þ‘uÊ�S¾q‘«‚Ѻ!y¹¶z0—¼ÎµAŒøXAìÙþÙ¿òªzÑkrmYŒ!YÖh útTþ^92Ú^ÛÀ€h¬H»e#)V‘Ì`Ùä3Ô|ë;9º5R¡¦½¬u•—AðÛ{h!Û©¬F´aD¶2ƒÏ´¬¢.Ô~…×ÛÆ(®ÿÃ»Šº 2Wx}m—zŒF×Té]£ýÅ+¾üù±Éa£æèkžDÆïH=– ß œL€m|]”§.‘deƈåÙ¶n—]:ÿN޶F±bÏï‘ũ –•sN’íˆöŒKž÷t+Úš¸3Ƴužϸµ{ OȲÄÇκ_ùðå/í¥÷€ß}"]­ê¹‹Ôé¦õ~kËoÅMiO>ú}¡˜_ó’�8•ß/âø:Ž´_#aù/ Føk¨æ…%$9î\£¢§#Ž%õ«ìõËî2DæBìS¸» FZ ûš0MÍþ÷çgŒú~/F�”õÚŒm=ÛÓÃò}X&¿¦Þ³òôñȱ‘Í%Çøwî°´GÜÜ´(·©…ù¢/ÇŸWt,Ì¿¢mÇìý ê˜ØÖFJ§g³õK0™Ug‹>_IsÈIóßÊ>;íDOðë_ÿÚ©By9.Õ">{ÄG0æØþáíÝ û†¦LÁïi3gÀ§¦L ßh}f ìļG`ll 嘓¦N�Ï̘ŸŒYÌ)'L‚“áÖ’”4áØìØ1€õÃϤI0uê)0cÆ4¬mîÏÈÐ îßÈͤISaê)ÓaÆ´)¹¯ŽÀŽ÷{±üɘÏ$8eæ'›¡½;``¥Ÿ,ÅŸŠég`ú|ÒÉrd/ìÂFGaòÔéyË£‡@|„�³ˆŸ½}Ûaxò4˜<:“¦1×ë:62#Ǥ)Ó . IóÚ·öâxÁÞ3uúgàÔÏØô‡â�52´¤<ØGݾ= ešfUÀО�00ŒùŒL�y:æ£ã®e:²Þß=Ó§OÂñ1 NûÜgãi ††F™¦M9Å�gú´épÂ'?¥U§$?p,½ß?ŒMv1:uFá��ÀÐà ìƶ•:k*LG½·¿ÓzíÝñ>Ž«é8®†aÒ)§u\ÑrŽÔ±�^L¦‹�TÝLå„�a¿Àñ©}Š0‡c_ûpï^ÊŽýI§Ì€ÏŸš_‡8öIVN™>>;£�q>îD;`lt2|ª€yX«îxÿ°ÄªP±ìíƒ}þ\?¥ ›ïÃ=0‚óå$9_žr*|Ú0_Ân3eÊtøÂä“Q†Öþ ¦_z¤«Ûൟ]R¨xGå}vz ÀªXÚŽænu[I딨ó�SD‰qÝðäMpÑíÏ8EU· ÂÏ.A}†vãî�¬=�¶íi¡ù8Xyü�@Î!\¿íÄùÛ±g©¹ôcv·]»—h¾+@Þ‘¡½0°_Ú/rΚ3ÏÀuO“Ò€~øT©úc¸$ÿLIêáç^„[L0ÝÞ½0èÏû3áŒæýx[ö¿$¶s<³w�Á^´K&£]2ŠvÉtƒ]2öþópɯƒ 2EyŒ>• ØóV—0Qþ:•¤ðtC’ríô`%¢®ßݯü=3O;5ÿzËr �àÜ€Û67 zî[ŠÑÆàù;/�ë–8½p»WøÁÙÊÜVW+8²nšz)83|º_û ÈËÐnÄ×ÌÒ2}&®q“,˜½2-m€âùÑtA`/® &O–>ÚSâéiKù½êÇû.F_‹WbÒ»“`[2]dQ©ññïXÎïõËŸd F—#Ú›“¦dçæÝðÐwNƒŸ¯ÆÔÔ ®žÈ•—|#ŸË”êsíâ}û³>[”ò3gü |ÊB•êò±_EǃüBý·kÇ^œkñƒóÂ\û}Ú`ß‘RáBoÿLCÿöú_?Z+¢ß-ëßž9åd˜q>39>–öˆ•襘W ±�d À”ZÏ&™� âj§Žô|Uʺh+èGq懂ŠÊ×�‹e$Lþ›’¬Gbù¹òˆbÓ?K=óˆ\ÜË6:ûZ¬çŒÅZ;i=|”�™â6|qr³å[=ýôÓpþùçÃÉ'Ÿ 'žx"0áË¢= !| áCÜ¡ÐC\‹ÂÆ1É Xö©'œØMÆQ .z\‡áðÁýãR4ÊØ p”OÁ Ÿ8Jè6à4Ç%‡Ñ¹‘VÌûã1®4E`’ò§9¤ü1xéžKàê_n€Ê¦^øÅwÏ ·ñ1#0áÐ _Høš1áëÄ`�ñB`VÜ4æ9 Œä 7§ò“âÇKZ.—(&#›—ÃÔÙ·¸Yfj‘8q³C°*f±òŠxh+¾™`&4ï¯Y�þÏX×ÔW?ÞwÏ=U«ÏÈÔ[eõC�ZÈJ ׋øZüã¸Gà3Höš‚O¿øÃ0G¥šŽ®Z²4Œ@ xí¬‰u+¾Æ±½ !|ɇ·rqññ~Œ«$Ž#Ø\ô¸! >�ÑEøÃíœð‰IpF†ã#08â÷‰.ó'�Œÿ9$åKJþØ–0ùKóð(mƒ ƒñ‡8–`Â×±Ôš\F`üÚ+˜?üåjWˆ£�ð2~ppÉÇc°cí³0ïÒy°:[oÜž~2ÞdG~hq\õB®,#`Bàýçï„/^·${© ;�¿ŸuªÝk÷æ—à¿Î¾Ú�ˆw,¬ï‚Gpž)›Ð¹�à0 Üê€?Œ@d˜ƒ™GKt¯rò%FàxD TóÃñˆ%×ùA€×NÇHC†«Á„¯0&GìL!„/)Ì(’½öââBFð˜hùfƒ|Ã�?Ç7âÐc¼@>¾{ÁQ^û?'J²× ’öÀF`b"°m…´øÃ‚€Œ¼*�’HuuoÙ ›;w|úL˜uv!ï;R ßÃ=0áëèi –„˜ˆhQ�ü ¤¡±÷øþ‰÷`òsäFàèC@�hçÉ—ªl‚µ¿ønv»4ïì8|Ó‡nÕ6Rr‘Œ#PRvÀC}~îî4›-))ÜxY?U ½í¿€8±¬âkøû'øî+%…þ8Ï\úSäVŽòe:þ0ŒÀш@鿇£±¶,#�^;å…h¢ÞÀ„¯ql¹B _RDIö;r'ñk2¹ŸÂ-‚8”í8v°£¬h1†Û��ÂÎüñQ&‹s\#pR&ct›ÉŸDxq~\÷…c¤ò’ðu�‘’,ÎFÀ„€$zIûlÚ Hte½g‚ˆÏ£¬ýÕwàÒ;V;µ«j€»¿ÍÄÆc´©¹ZŒ@IZû+˜~é$ï 4tÔAf‡Ä$ ðá1‰À^øÕE3ášÈT6@Ý/2㻕£‡õÐZøÎôKݨc©jhÿYA[µyÉù›`ŽFÞ‡å à–%Ï+TVUUÿõ`ÃÑ–¯áËç2‡ø;#¶ÇãIIðšŠùü‹½ÉÇcà:O(J8?L(XXF@"Àk§c¶0ák›6ዊ) _Gküiàʇ‡lèÒãc �$ùÇd þq¤@-%£yqD¯# <—w„�ZVÚ Lû:B€O�bND9™ä5A‹Å,:#»·Àº-»1ߓ་/�S§½Î�`Že0æ†M[àÀG¨E>s|yÖÙGÙåXÆœëvÔ °{Ëزûvþ“àŒ³¾ gŸz4G`ËÚu°Û›çÁ%¸�FàøE`lh7toï�GO†“G÷Á>øœ÷åÙpê´äÑ8ÙÏrüö+Zsö«P4ø˜˜8”r~˜8(°¤Œ¯�ŽÕ>À„¯qlY[Â×8ŠÌE3Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0ŒÀ8"P —À`='à?« ¶Œ#fE+š _Eƒ’3bF€`F€`F€`F€`F€`F€`F€`F€`Ž lùVO?ý4œþùðÉO~>þøc&|Ùô&|Ù ÆiF€`F€`F€`F€`F€`F€`F€`F€`�ã&|�cÛ3ákÁç¢F€`F€`F€`F€`F€`F€`F€`F€`� ˆ@RÂ×É'Ÿ ¼¥£eÃ3áË8NÆ0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À§ƒðuâ‰'ò–Ž6ý‡ _6¨qF€`F€`F€`F€`F€`F€`F€`F€`FàøE€ _ãØöLøGð¹hF€`F€`F€`F€`F€`F€`F€`F€`F`"�„ðuöÙgÔ)SàðáÃá˦í™ðeƒ§aF€`F€`F€`F€`F€`F€`F€`F€`Ž_’¾>ýéOÃ'>ñ f—Mb— jœ†`F€`F€`F€`F€`F€`F€`F€`F€8~HBø‚O<<È„/›.Ä„/Ô8 #À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#pü"�„ðÕÚÚ “'O†�?þ˜ _6]ˆ _6¨qF€`F€`F€`F€`F€`F€`F€`F€`FàøE áëøƒCø:ᄘðeÓ…˜ðeƒ§aF€`F€`F€`F€`F€`F€`F€`F€`Ž_˜ð5ŽmÏ„¯qŸ‹fF€`F€`F€`F€`F€`F€`F€`F€`& I_þóŸaÒ¤IpøðaŽðeÓöLø²A�Ó0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Ç/I_áëСCLø²éB…¾Æ†v@×Ö`N†óSçÁ‚Íkß�÷¶ï‚¡��¦Í„Ôß} RgÏÐÅÙ ›;wúéÆÞ_ «Þh™äôK¯�ï§NÕîÙ½Þz}-¼·g?L™2NÂ|Ï:÷¸ð¢ó`Æ$íVíÇÐî-ðNÛ»°k3†“à̯\ ßH� “`¶l脃0>{ΗàŒiÙLâÈ5´6lÜùëNúHæ/«{|ý²oÂy§Nq~kÿHÞç VÓ« kÞ€ [v‚L=íôY0çòo£,ÙTc{amóØüþ^? fž}.|c^7d 0»·tÀ†wÿ;‡°¦'ábtæù³à¢óÎÀúò‡`F€`F€`F€`F€`F€`F€`F€`F€(-I_'Ÿ|2¾’4O¡„¯ O^Ýþ¼STMcüåîë`ɆpÉéŠzøŸü<Ú—J—�†¦ÿ ×}ï?QªªÚïþvö÷^xþ¡ŸÁu?Æ¿®¤ ºéÿƒŸ}÷<ý4’©^Z<®¾Ï•M»˜®„¦_œ ßûÞíÎétu¼ö³KœãÂ䃵ËïƒKoù¥–-ýQVÕ5wI]ê£òNCS{%ü¯‹®€%ê²Tß5 ×ÂÀÕ_ú!¬öÏzhìþ=|ÿlÅúÚ»ùyXtÃuðkînª Ôµüøñ·u�—#3Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Å@ áëÌ3ÏtAI9Nø±ÈV›²Ž¶4…¾nBÂW�Œ•‚LÙ×Ö?ÏRºº‰U.‘kÓ¦t. Š€µž¼î4ÈòÉœ‹é²…pÙYïþÇ-ïʦ^øÅwÏða\‹D´Kõ„Pþåýðë_‡ `$|5ø„¯ür½ÿü=ðÅëÙ+•†ò˾ w¶À3¤Â™Ì÷'.‘L f¬s*åÕ¯Ÿ ËåV¯Ÿ¸ž©ƒá†c45üŒl€›¦^ªRPV~œ|pg Ï2h~RŠ'ædÏÿF€`F€`F€`F€`F€`F€`F€`F€`�b!`Ë·zúé§áüóÏåëÄOd—MƒØ¾œH^•É+»‡à†wÂEó¼8Vhl€K0않våJ—*¯†gÿå&8ÓMš>¦à÷îU‹á´ïÝ—¿ šº—ÂwýÈVcðÇå?…Ënùuözt‹àlùkd-’ .õIP ð@f–{ßÐfXüŸfÃ}«ÝŸò¿NøRËäµ°\»á¡‹NƒŸg‰lõíðÀRòVç³cÍ“ð…+ÜÈaeІ$«K²$«ÍËÿ fûò”×´Àã?ù¶»Ýâî5pÓiWø2ËÌhÞ#ï¿WñêlÄ/…ãÐÚ_ÁôKïpÊNW4`µŒE ÆvÃs÷Ý?üåjçzY]<ýã`$4çÿcF€`F€`F€`F€`F€`F€`F€`F€`#À„¯ÄÚg`GøZˆ¤«G]Ò•_ô,¿i:Ü’ AUÕ2w{ ­}‰J1j!tŒ> ³²$17i ]3¦›ëmée¾~õ�™pÇj÷wmÇ0Ü ?Ii Œm�'ùï0å¼sá¼K®„¹³x[G`þÏ0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#À0Œ#Pl’¾¦N� r3GÞÒÑ¢el_”8E‹Ü²âŸàKóÜH\Þ=CH~šž%?¥«p«Ç»Ý­ýt¥ë:ŒÒåntH¢wù7¸ï?'n¯èF+«i‡§’‚µ¿ÂíïȦl솾ïÄýÒR®ºç"øÞ/Ý0]žLò†¼ri¹üÿìÝ|TUþ6ð‡ô„ J Rz]x)*(+EÄâ"º€eE±ƒÊZP,ˆ¬Ë_XTtÅuAl €,ˆˆ!ô$tBI �:!“ðþÎ�>™If’I&“<Ã'ÌÌ­ç~ï™™{ï¢(@ P€ (@ P€ (@ P€ (@ P€ðœ_ž³t{Iå | }y+6<ѿĺ’Þ‹®÷­Ö†»Ü¥£þfv‚1’å´uª_ À'7jËžõÓ)Ì»:Z_–õM’.$—K’¶·¼;¶ŒE‚)„¦¦q'”õÎî|Ü›`÷Ò%áÎЮøX[á$ìÌ_ŽžÆIÜY¶;�/]N&òQ‘á¢\éë1¬É5بÊ3éd/Ÿˆp­lü� (@ P€ (@ P€ (@ P€ (@ P€ž`à˳žn-­<�/`vç/�mê8fwm­‡C)Á)ù¸¹]H™Á*UØõ/Ã5s6ª‡0u©=1ý'­€Ý)­€ÂUCñÓ¹ ¸:Ê6´…„pj÷³ˆ6Í#÷ië Å5Oš‡”7ðµh§}‹f:|?{$FÎßh^öGûóqWœ!ñåñÀW@föí ­1±¡ï {ý%Ã\Ò5æØPSKi!{Õ]†itéHÚw…RÒ1�Ñ.Ê.¸fÞ> (@ P€ (@ P€ (@ P€ (@ P€ €k |¹æT)S•/ð%Eó¶.þº7 òOá³þŠ)ol4–QÂWW ᫲ÂOjýñ•lu‹q^`Ö'[ñø˜î•†¬²OmÇ¿†9[5m —Œ1vW˜Š™uÚ[&-ÂÒçnF›úzìY÷.ß1ß¼LõÀ�À×�¥w¢ÓCÄ Ce[—¶5ûÔX±`zOuåh¹=üÉn,œ˜  (k›­»¢t­…¯,•–ʦOÃÐYáµ{F C‹†Ðë‘}áV̽Ë\&ëØr~SºÙ|H+W‚´Ì¶ÛAËl–­à# P€ (@ P€ (@ P€ (@ P€ (@ ”-ÀÀWÙF•6E¹_¥”è��poÏHmвÂO¦Å$}:]ïxÏôÔñ}Â,ìþe¬ú*Lÿß4liÅË~ÆIÓÆàã÷ I)w_�VÅÆJ«bÆŒ•ýbåù4¬ZÕcÇÚ®û£ýÙ¸¹ðcÔëzŸ6�ã@—¥+JÇãï”®1UØl ¶f¯BÙ^]êjôm?¶13Å‚t/™-ÝK�¬ý­·ßÑœF P€ (@ P€ (@ P€ (@ P€ (@WørE©’¦)Oàë�M;ÑxãBÜ2ÇØ–©l “ðÉ{/cbKÇŠ9IK%ü4E›â�ÝÙ¸×:­ešÏxü×O1wÖxo£Ý$àáwÞÀœ{¯†!Ff;>Mæ{~ÖK2ŸÄ¡T#[ênÌØó�9öBÛß¡Í0é£ýX~WœöØ•r鎯ǬÉ×ÀÜp™qµC§½Œ×þñzFebéô›0ŪÀj'a¥y›?’çwÙmó ·u2†ÛT@ì®8«›¬Ã2Þ6¼¥Kûo>?OlÆâï0í…GðÄÌ»ÐÎjq:ñ5úOúh·l¿¡2ÛyùŒ (@ P€ (@ P€ (@ P€ (@ P€® 0ð底ǧ,OàkÑÎlÌPMHér�~! ùÒ­`@h=4‰Š4vµX±bêr2q!+zY.d‰ ££.Ý;–uÓët2y€Ì„„fÈ”À[++pælù™iÇ‘X�…ù¨ß‘v…Ñ‹ƒNÖãj�-Ê3Ãõ:ädg#+_ 44õ"#«fÝžÙ.… (@ P€ (@ P€ (@ P€ (@ PÀ‡øòâÎ+_à낾µµUÅ¢?Ž¥óßÅÖC[±5k~Z5Q6EÐaé�¡˜blˆÌQ÷‰6“ó (@ P€ (@ P€ (@ P€ (@ P€ (P¦_eUÞ>øÂqÌ¬Ó oy&-ú¯O»QÒÌ–^—Žß{#2u;ù0R ¢� -…Už6—L P€ (@ P€ (@ P€ (@ P€ (@ß`àË‹ûз_@ÚúÑâš96‚ HJJ²öÂO§ðìÕÑ6Ãø„ (@ P€ (@ P€ (@ P€ (@ P€p_€�/÷Í<6‡«�¯ß߆^mÔÖûòÖ x¢5èÒѨpüKñàà)XíH%a¾Xú:nîiÛÙ££I9Œ (@ P€ (@ P€ (@ P€ (@ P€([€�¯²�*m W_ºôTü‘š.åB»î=¥ÛÄJ+R9¬Gúñc8“q � q1-u£Û¡S»(°Çr’r6 P€ (@ P€ (@ P€ (@ P€ (@ 8`àËJU r5ðUUåáz(@ P€ (@ P€ (@ P€ (@ P€ (@�ê-ÀÀ—÷_^Äçª)@ P€ (@ P€ (@ P€ (@ P€ (àƒ |yq§1ðåE|®š (@ P€ (@ P€ (@ P€ (@ P€>(ÀÀ—w_^Äçª)@ P€ (@ P€ (@ P€ (@ P€ (àƒ |yq§1ðåE|®š (@ P€ (@ P€ (@ P€ (@ P€>(Pm_3Æ^öA¾ŠyÅŠÚ&L˜P±qn P€ (@ P€ (@ P€ (@ P€ (@ P V¼¹*HÛΧ'»µ½Ë—/Gll,ÂÂÂàçç‡:WäæÖŒ›g÷ß�WžÙ}zž/¾øB+ÿ-·ÜâÓÛÁÂS€ (@ P€ (@ P€ (@ P€ (@ P€U#ðö7aÚŠøªo›µ0ðeÃÁ' (@ P€ (@ P€ (@ P€ (@ P€ @ |•T™£øªL].› (@ P€ (@ P€ (@ P€ (@ P€5O€�//îS¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUS€ (@ P€ (@ P€ (@ P€ (@ PÀøòâNcàË‹ø\5(@ P€ (@ P€ (@ P€ (@ P€ |P€�//î4¾¼ˆÏUû¼@ÎeöŸ=�ýé'q@þ2ós«Å6û CãhtŒj‰ÎMcм^dµ(WM)„¾¸‡ÒÓ ûýÜIœÊº€+ò�7Ï „… “Ôá¸&-йÉUˆ­ëÙÔà¥edçc÷ÉtìUiç‘[Pès[[§N´i\ñ-¢Ð¥E#ÄE7‚Ÿ ã�5E èr2SþÀ…Cò—œˆ¼s'jʦUx;üCÂÙ®+"c»¡QÇž“cÞ(@ P€U- Ó“ï©s}uÎ.çRU¡V¬/24\ÎûZÈyŸ\¿hƒºrÈ(@ P€ (@ P€¾#ÀÀ—÷_^Äçª}ZàÈ…³˜³îSdä#¼^}Ô�ˆ@PppµØ¦¢¢"ä^º„œKQ¤×ã¯}G`T§>Õ¢l¾^ˆ<ù‚þùõŸã€ýBCÉ�ºa¨#ÿx󬀾ð2r.^DNVýüñôÕ·¢[óÖž]I \Ú–äSxî¿[P|å êׯ�úòÞàs[zEÊŸ—“ƒKRòuÛÏß8Aþ>·-,0ì .�Ç//MEÖÉ„Ö�@ýFQ ¯g?Y­}^TXˆì È9ŸŽââbô˜ö"b�®µÜp P€¨z�ŒÜ,<+çûiò™]7<á‘ ­ú‚Ô‚5^.Ð!W�÷eg£¾„¾_>­"›Ô‚-ç&R€ (@ P€ j†_^Ü� |yŸ«öi�g~øÉ—ÒñÿF�Fd“êy1Rù2¶|÷-Î�8�Ý>õƒÃ|Ú¼:þˤ_°|×Fô: m»t©EªñeÈͺ„M«V#¬xï¦jüöVdU;s7.úüCêbä˜?£nÝšÑ*Ú®¿cû¶íxê†~¸¾kÛŠq^ T �=Ÿ¼‚#ëVàO·LFL—îÕ¢LÕ±y¹øù_ïàâÙ4üù½_àX=‚õÕÑŠe¢(@Ï üó—o°áÈ 9Í[µöì¹4‡Î�ÅæÕ_#®a3WíÓ÷ý÷]4i„þ×]gÜ=N|ý_;]€ðn×¢{¿¦ÕbûN¦¦â }½9vZEDU‹2ùr!Þÿm-ÖNÂØ©SKlFqúlÿ*hÜ=oê�ÀSøâ€óøcî[Ø}è1ë!$Ä5ðÊFìþå¤&&bå¤'½²~_YiaQ1†/ø}ú÷E�^=슭CêÊbïáL@—­“G¹GHC4h�6½ú⪸vÕ²ÞËv}ðîûøë�®˜ô'-ív,Ÿú ÀŽ>ŽìɸaÆÓ6¥×g×ß'!5Gµlwº,y‰ÖG³æ�ÑJ¾lî׳-¢jY#w)Û·`ûª¸îŸëÂã›úÂ' (Py/üô9Žfãš[n-±ž÷• ñØ€_¾ÿu2.áŸrý‚7 P€ (@ P€ |C€�//î'¾¼ˆÏUû´@ÉÀW.6_ÛŸÿ ÄÎ_ƒ�ÅW‹ícà˳»¡´ÀWÁ®�ðXßçe…ýñhæghîÙuWÖÒrRwáÀOÇÑzâX4¶+sqê·x(î~êG¿ŠWÿs3¼Ñ¾ _®íýÒ_9Ø|{>ûµ´eÝ�é?½…„vv¡´Y�+HÇÑ_DF`_ôþS;GS¸5Œ�/·¸8±8 |åXƒÆ?,e Zañ²ç15Á;áÛR Vi£øª4Z.˜ J(-ðÅó¾Rà*8Š�¯ rv P€ (@ P€ €øòºi• |™$xO÷¾¶ÝÔ $¼¾ÓdàË=QߘºÔÀמOðXÕZËp<‘ù>b*˜™©‘\lìÑ_îÆþ–ˆk{Ø…2·ã½&· I Óç­5øË4ïÔk¾\« e¾~���×ÑÃg`ðuÝ ‹Õ¥%"ñõ7‘lµŠÛפcP|¤Õ÷ìYŒGGÍâbÁ÷¢¢�É2ðåž?§®þN_)? ñ­ïÊ´Âã³oB‡Â,dI{|û~ûþ|̼a+V}Žq1Aæç5ù_5yïrÛ(@ T_�R_<ï«´ÇÀW¥ÑrÁ (@ P€ (@�J`à«ÒhË^0_eq 8ðHàKŸ‹KÇÎ ++ EEx³æhÜÜ.pc·ò¼ã©8wZúx DPh$ê·lŠðpÛp|c _Ž]Ê;ÔÓ�¯‚ô³¸x6ù¹²KÔCDëV )¥tºK8»ÿ0ò/þA†:Ó@ꌟÝ,ź\äe^„.0lá@IDATO 04 ¢êÚN¥—q¸„Í·öÂçT¼aÃ6\?¨ uE@@°šM»çœÇ¥ìD:«›.×c½¶lÿ�`­¼Å™g‘~T¶]¶Em{£ö­ì¤*3ðe»ëœ=s5ð•0÷L¿Ã:¼—ƒÔOǧß7.úI¼pt.Ú­¨¸ y/HWs…RGä=HuÙÈ6ÙX,Õ*/i1ž§_/aîšÇP¯H'ïqRíw°>é)G‘+•À?´êF6EDÓÈ’õ™]:Úí >õu�²_C°cûÈ·ê¾ñà�£Û_j›>øñ×°vB[†Ìô38zFâa�ÁhP7 Mš4Dd°Õdj}Ñeèõþ‘Ật;W€Àð0DG5DˆiRy�ü0V}zÀ4¥ù~àßãöÉqæçÖø²Ö¨øc�¾rRñã8ÜŸÃ?ø £&÷(zIûz æß4ßÁFLĬìyˆ– XήoñËÿÂÆ¯ôÛ7úÌúp¢µ†›r±cr,ûÔÁâdP¬´R7Ck¥Nº*•–ëT lÒ®½èos§ ?ví÷¸jÏ¿°øû•÷Ç´Jw‚¶ëP%dàËñ~²êràëïÛ1}JûÙ‘ºdΗ�-·aÆøk¯Òçìù?,zÖIŸµö·áÏaö«Ï Z²ª…©Ë0óš{ì§0>�Çö~…ÖÆÝ{öçÅøpòÌ’ï�ýŸÄ“o=�˜F–÷@¶ðå„”ƒ}V ìÀW_lÝ< =lšÇËÁ[ÓîÄ£;€QøZi |å�Ä[ó^Å£ßZZ3Á<8÷5¼2Ò Óáýið &`õ�3ó_¦ÉðÚ§Ëñ@\8ÿü:[ 7O€¾X¹êQŒ²jUìà/_Ꮏý Ò@¤í­÷xlš;}£, ®cËeó–¼�ž)ßâúWÖÚ΃xYþÓ²ü’‰g¾ì¨ø” ªDÀc�¯špÞçæ6Tä¼��¯*©Þ\ (@ P€ (@ PÀ£ |y”Ó½…1ðåž§¦€I "�¯Ì¯`ÎMo›…>3îŽü‚í_›Â\ãðè¹…h­sd2Ý|Vïzl1Í1d†vNmý ÉòMëÐÿlÁøÑ-Lcmîø²á¨ð�¾ôǰ:tÖ™J£ög7àЛ_™Ã/ ¯%Ý‚Z9g?›�Üi Hõ™*uæÌ>©3*Øu7^(œU]2¿~AêÖÿ—‡ØÑ1R·ÖiõD8ñm,Zög “`Çý±ì}ã¤vwÖ�/SW¥ã¥ËÇ¡V]>º[�Mþ­W;zœ”ÏP�µáCþŽ—œR¢ @¾¬Õœ?®hà ¹Û°¤Ë@­ ÏØYñÐôAÚÊ.üøæüõMãŠ;¼5pâk$›ß²>Ç› Ç£(u…¾îtR@KàëìªûðâC¦Ê—€>wCЉ زNu*7é ò%é ÒÔN_þ_sÊøº„×§Ý…ÙÖ�¯‚“x`ÀƒøÐHß{†uƆOךƒXó–-Å# ªõP–Ïœ€©%r›ñØ´ùEô >†)}Æ mY­0a|W„e‘®$ ‘®Õ?­ÄˆHCˆëÄÏ#v¦¡µ15ù„‰£å d7V˜»�‚MFßúÚÂ` |žþœÏkË�}î Ìxº�ö8í½™˜ÿÀWÚãáŸ�Q7Å[Ò#'UZôhÑá%ÅЦgàKcðØž|Y‡·Ôþ#ûS»éNaãÄ�øRk`©?>÷Ú©WÎü+r¶«‰¤¸Y_<"­t[?’îÏžš¶k¤-9°ñÝ=hwë0´¸ª‘¹ž}o^{@ÆîÇßóŸ@csãIç¥/C—Žã7ïÄÐ~  ºä“þúà§M“ ‡�¯rÔc› ÿ£ÿŽg>¼MµíÈEÒ3÷བྷUxm8žÈ|1¦¤�*ŠÜø28”õ…_ÈÁæ©øL¥û¿�ŸM3„ïr÷`ãÇ;ÑnÔŸÑ¢E”¥^}ò ^Õº�|O™‹(SµÜeìÒ±¿·>{aZ÷¡�:%äî².}´úœðˆ´tÿh˜z¥½ðË«˜3ñ)m3'}ý¥Å!ucàKcà5H ìÀWé]:ŽšýVÞÜ {V¾�ÞóT‚KZàú÷ýÕ^»äV�Ž·žš†GÕ¨!"cáÕ ´|�ÀOßNÁÀf�ÈÌÌAhdè�­pAZÛúiã‹h kéóÒ±mo6ºõika“�ÙÆ�Yï Øñê­ˆ7N{bûÄN7ÄÏß7k§vÖŠcørŸ‰ŽõUxL‡5‹çâæ�T¨ÌQ«f_!ÿ£(@�*ðDà«&œ÷¹½ ²Ÿ*rÞÇÀWWt®Ž (@ P€ (à¾<€XÞE0ðU^9ÎWÛÊø²¾ø9ù@ z·3'o4ÒCsoÇâç ­6=“?M,]êaª´Îô¶j�Éõ_®[¹2eÅ_eìÏô_0?z¢ÖÒ×ÀÏÆí7µ²¹`î¨Î¸Rn¤®Äƒq�ɤÃñ¨ªZ›UÖ�®½Ò‚—}wŠÖã--|¹_�­/ü�“P×BÛPWæ/x³ÉD$K '%Iבq¶å`àË¥½ŒŠ¾tØ5{>üTZÚþ6^{‚K[õ±eø›„7Kë]jò‚ïáÑëïw¸ ó8 Á̽?Á¶Ïl¼=+å-ðæ5é¯� |iü¯F ”øj…y &£§ä·232ñû–ÕxÅÜec_i=k–´ž%]4J‹]J¨+þ¾—±cª4ýiuË9°�'Jøª÷½ÒrÖuÒr–%ð5gÉRÌîc ‡çÑÝ„ˆ›jÏŸû2žÑá–^ÍK¶o-[µ·ÅØN´ñýgqý;*À5‰ÛïFGm™gˆtUù°mW•YI1t6Éïÿgîlb^—zÀÀ— ŸP€ @ T<ðUÎûÜßµ{,çŠîŸ÷1ðUEœ«¡(@ P€ (@ xP€�/bº»(¾Üãô0”7ðuiÛxfÄëòíì#øÇ®°ýºU.Žîú�õ}ZVb æœÂ÷=âùîtøÚm3¬©[»€�/·¸Êœ¸â�¯³²?ûiûóٟח؟–‹ê ¯¯‘nãQV�±/tÁñ]øãßÿÃÉÃGpþLBêEÙ¿» 5Õ+Ó\Ž]¦±Ò“þÊ*SÉzluáô«xõ?7Û‰tÒŠY=C+fö]Gª²0ðeÙ#¥=ªxà+¿J _k-|-”¾¤u.ã Nmî5ëpêX22Ò³ÞLR¿b»Ö £“À—´öš´f»ôË?ðôÄç K�‚Øë-úÉ*ï*7¾ ü¿f ”ør¶Ý}±â?31N E]À¼[ïÁ Æ.÷Ž·™iÓº’›¾2$ðeÝÂ×âOW`jœm° HÇã=§a±a.íÿ ÿ‚ñ× Àõ ͤÝGÃíôö£Ítéø±ýù÷­hn5½z˜sà š½+�$˜¶Y‚iò&b|™[³š©à0¦ xTëJòµO—ãcË~¦)ø2Iðž ªR â�¯špÞçþ6¨}d|•ã¼��¯ª¬å\(@ P€ (@ PÀ3 |yƱ\Kaà«\lœ‰(oà+óë˜sÓÛ"8 ó §ºG²ò4_5um‡]x/r¤½8 ÂXÍêð!_YÊ=°Â�/ý1¬•§¹aÃN\?ÈØ£¹D–€•)ðubñT,xDæ=W‚RwØ„g̳dHýz^«_öcŒÏK -ës\¿�w»K‹bæº=D¶ãG»í`àËÉsopÅ_DZºu[¬•ÕFßÿ žzâ:­EÁôŸÆó}ÙyaâžÃÜïŸ1XÍ­x9|�øh^~þkçË2޹]ZøÄ¾Êtâ¾)àJàkð�¾ÐzJ¬Š6M[¡w¯nѯ-"M jåÂ̓žÄš²†Hàk¡màËQ°J-FŸ~ -Ç ßÃb¦eKK~G^…æ²î?ŒØ™_ʘ¿àÄïã ‘b››9ÜeÕE£y˜9|f5 _V|H P€ÕE Â�¯špÞWŽmPû¯"ç} |U—WËA P€ (@ P€p]€�/×­<>%_'åk‰@y_9ÒÂ×,Õ¤{ƒléÖή� óÅQ-|%¼õ=¦M‹sK˜�/·¸Êœ¸Â�/œÅ�ÒÂ×*ù.½�ìÏ¿”ØŸ–¾b¥…¯ª…¯µÒ*Ü ªÎ —:ó~‰:c.tŽ%;ãUÜöØp4Œª • ÈþõC<3l¾ƒÐ˜ã@—y™NZør¿WìÂ?[ø²ì‘ÒU4ð•·ëU<1î)mß>ˆ n'�¼mÃ’.µÐiìÝâöécаQ=C½Úõž¾E¦·ëþ±´ÀWŽ´ðõ”já«¿m b¥mWqQ1>x÷}üuHWLúS—Ò&å8 ø„@Ù�¯¾ØºuzX7�WbË.àuiák¶´ð5oÙr<’`î«·Ä”†–.�¾L3ê².`÷ž=øbéB,Þa:á¹ÅøhLK¤K _1ª…/é–uëVéžÑ®Œæp—£¾ø2óž ª¹@…_5â¼ÏýsWµ[Í×4ÊñC¾ªù ƒÅ£(@ P€ (@ 8`àËJU b૪¤¹žš&Pjà«”`VážOðHÕe£´Øµ9CûÙvê˜úêíxc–êÓì~ü=ÿ 4°€0äï˜ÿã”­‚i sò_N`Ê9ØåÀ—Ó`–%`¥öç˲?M]æiEÊÜŽ7›Ü‚dy2ô?[0~t Ës6VZ»¶D«`†�1_Xw »´v�„Ƥe¹Ý-å¹m×^iQ©®aaæÿ-ã­[s¿WìÂ?_æRꃊ¾ŠÏnÀûý†kÁ.à®Èy_>ô"aQ)@ P€ (@ P€F¾¼Xøò">WíÓ¥¾JÛ°èù_áÁþ¿a–ê^Ïx‹2uϯC²jC»Ý�g²ç ©©»G üüK?ÛM£å>vtä~ý«!l1äU¼úãÍ6­è˜&eàË$á™{×_¥­+N‚\Ë�r£të(_ºnqH�$ÙŸ¦ÛÀå?áöÛ �5ìÄ{3±à�¯L£�øþHhtI?Іi­sÅeX…°,“Ú>šˆYÙómª[V�.mºø8`�,3~.^Ýu‡Ô)'�/™8gó·êq©þ­Bm6Á2cáø²Ý‹Îž¹ør6¿>lÑ?V‚¦›>_¶ïˆ ¦çï§böÁw­2‚r+L]†™×Ücx"-yÅÆ%!YªÕÍkÒ14>éß>‚çïÓ8^îú�FB½,$­3½(¦âÙ”wÐÔØø_*>ªž |Ù†¯”M+ŒÒY§~Ã&éêQÝ&Ì}�l&�J|üî �_ƒí[apD=lÚa>0ÁŠUŸc\L�¶Ìô]ÒÚß=†`—ß»/^´¬SÒÅHÜz7:ßJ |åÆÍƒÅYŽ£ ZÊö-ؾj®ûçz„DDiëç (@�Êp-ðUZ)jÊyŸtëx­{ç®9ïcà«´:Åq (@ P€ (@�ê)ÀÀ—÷ _^Äçª}Z ¼�/S+J—¶­Âç÷>„$Ëw©šGìÔ¿ã¶SÐÔ®á�âô]X3}Ö}møXðúcìçÏáê›âàgh~ÄÀ—™Â#*ø‡'2"&ä,v<÷–½lâÒJØã¿™‹¡#,a/CÁõ8úÙëXqçÛ†�ŸÕÖÄNœ…›ß¸Ñ‘(<½«ï¼M¹™.aÆ\Ü4÷F¤?Ýo¿9Q„ó,aBŸ·g%žìñ˜Õ�hYæÔ§k]Šn»© >–VÇnû-ƒzض$çN=6_ø/ÑʘZõ)|ßc ¾Ù‡i©«�p•1%`,_6»Ç铲_›o�Àg–\¡ÕrÐçþ»1äŽ)hÝÂîÍG¦*<»«Š Vó&Üý6nzr"Ò_ŽÀÛÿ'- |55ï¶Lì˜}5–~šd³Ž—­ÂµC -w¥ÿ¼ŸJ aªûR›[ܸ}Öãè7DZ¨3Ž`àËFˆOj€@Ù�¯!غùá2[øÒ(¤®·.Á£_ÚPÈÈ SîÅ£“†!>Rµ,�¯ÅÒÂ×T»¾Ò“6á‰Å ±b‡=p<8S{؆­NËô¾¸kŒÁ2Ó\ƒÇ߃Å3G¡£UëdæÀ×�{‘±ð:»®©Ó1ïÖix!¥V~»£šBe¦å1ðe’à=(@ T¥@Å_5è¼OïÞ¹kEÎûøªÊZÎuQ€ (@ P€ <#ÀÀ—g˵¾ÊÅÆ™(€’�¯ò¡ä¥ŸE!B¤‹4Šë5Bx¸±I'‹+Ì<�œ 9( @`hêEÕuô2ÍÎÀ—IÂ3÷¥¾ÊµÕ}â9† 0¨×¼A©ûúä¤g@—§‡XÂ"!8¤d�)ÌÉ…ê�«XÚ貌ףX¿’“Ks]ç‘™€`ë¡ý¶º[�íç/ë9_e Æ—ø’ú û·°@�"éÊz©j¶€P„5/½ÞW_˜›c¬W!6U$gõJ�œSçàŠB™­^ÓHëÐKW�i( h(ï�Y(iˆðææçŒke—Žf>¨1Î_Ù@}ANg^Fdý dç!²a„ø»¿D]Þ%¤g!$Ì_>kŠÕ¬¡¥8¿ef^�(YBô—¡¯ÛQ2Ÿ'o |yR“Ë¢(@WJ |¹º ›éjÂyŸ»Û`àÚ¾\sâT (@ P€ (@�ê$ÀÀ—÷_^Äçª}ZÀS�¯ÊF`à˳Â|y¶x5vi |¹¶kË |¹¶”ê7[øª~û„%ª˜@e¾*V¢ê;7_Õwß°d j²€Ç_5ËƒÛÆÀ—1¹( P€ (@ P€ @ ”7ðµdÉ´k×aaa¨S§ê\‘[yÊ<÷ãm¶ûoÈ+Ïì>=_>½ûXx/ ümÕ{È ÀÕãoöb)Ê^õ¡?vá�Í›ñÖ�÷¢eƒFeÏÀ)Jøpû�øöÐNÜ0ù.‡†–:-GzNà×µ?àÜ‘£ø|âãž[h \R±]óÒgˆëÒÿoèÿ«1[xéâ%|þÉg¸wXwÜÞ¿S�Ù.nHíØùÎSÈHÜ„Ñ�<‡€ s_¨µ¤”-ß½îkìýù\ÿö&×�,eJŽ¢(@ xN`îú/°÷âi\?éNøû{¶õJÏ•²f-I]Ò]¿r%êcÑè©5kã¸5 (@ P€ (@�,ÀÀ—w._^Äçª}Zàûƒ¿ã�_¿CdTGG#¢Qc…”ÖéQÕmnqQ.]¸€‹é8sìº6k�箽]KÆV])j暎]LÇcß|„€à`4mu•¶ßÃêÕ«™ëå­*¼|—ΟÇù3g�q: ãþ„¿ôæåRUÿÕ/üaVÿžŒæ-¢Ñ¤iéÖMºK ¬þ/QÂ+ÈÊÊÆ…Œó8qü8qÜ}=šÔ+1%PÀ×ÎË1Ä–¹w£nD$šµëˆˆf-Z?Â×6£ÒÊ[T(ïÿgOãBÚqœI9€è¾#ÐûÁW+m}\0(@ PÀ^`WÚa<ÿãg¨×@º+nÙ�KwÇuí'ãs\Öépñ|2N¥!S®aüíO7`xlw,™‹ (@ P€ (@ P *ÊøZ¾|9bccµ¾üüüØÂWyv_åQã<0l:²?¦$bÏ™c(*.®v,-#c`«N¸)¾?B‚ª]ù|µ@)çOcվ߰ãd ò.ë|u3|¢ÜªùÎŽQ-0´m<®ïГ¡EöZQñ|µóÖí=†C§ÏKLÊ·o ‚ñ§Ø˜Ð¯®jTß·7†¥§€•@Æþ8²îSœKÜ }A¾Õ>4 4¸ª#Zô¿íFþ~�<Ž1¹ðž ªF@…¾¾“�¶º¿¬/¬š•ÖÒµøËEÝøf­0"¶µf‹¾µ´p³)@ P€ (@ PÀGøòâŽcàË‹ø\u�Ð!#7 ùÒ"Eu¸©‹¥�Ãê#ŒÝDUêîP]N\ÈÏA–®öu\©°Æ…¢qÝúò¨ŠÕÕÈuè ‹p.+W¾ *ò¹íSa¿Èº!Ú_Ÿ+= L×®H`\—y—s.¹>S ŸR…»B6E@[R©á»š›G PÀ'Š®ã|n6rùcŸJÙ_¡ò¹¯ÎûüØuf¥s¡ (@ P€ (@�J`à«’�K[<_¥épªN`þ†•ZKF7Ũº•rMµNໃ;ñá]xcô_kݶsƒ+G`Ü¢¯ðÄ }1 }‹ÊY—J T™@òê�)­—ö}ha•­“+¢(@ PÀóü¶u9xlð8Ï/œK¤(@ P€ (@ P€V |YaTõC¾ªZœë£@I�þ2nûä„ãÓ �²Ûº’DRAÕ Ý·vbéΟ´îG¯n×wöІaõ*¸dÎ^[Îeåá�õ»°aÿqDH·‹�\߃;ÆÔVn7|^@/­U~7} Š‹ôþÆkíóÛÄ  (@ Ô6�ézò«½¿bÅ›´M¿9áO¸¥ë „HëɼQ€ (@ P€ (@�Ê`à«2T]\&_.Bq2 T‚€êpÛ‰Cø÷îÍèÓ2gs.â|^6nìÒ=[´»1«ôZ²È‹ù¹8"]„¾pG.œÁîÓÇ´ä&vŒ¨ðøÏž­øáà/ôÛ7n޶ ›iMëE°ÞÕ’:âîffdçãà™ 8$ûÓÎãÀéó׫në‡}§Îkᯢâ+è~UtlÞPûkÕ¨üýøNæ®5§§@U äž;‰S[¿Å‰-kÐjÈ8„EµÀ¾Ï"ºßuh9pê·l_•Åáº(@ P€pCà’¶Ëùž:ï;|þ4OE�趘ØcüëøáÓ?~ÆŽ“)èÖ¼5Ú7ŠFÛFÍÐNþƒBÜX '¥(@ P€ (@ P€ÎørnSécøªtb®  K`«¨¸EWŠ´{½z,-)©{Õ¢’§Ý_)FvA>Îçfk�®óyYÈ�`×¹(Û©IKŒŠëƒÎMc `œ>‚ï%ˆs(# ­#› ‘´ÀÔ0, C ÷¡uàç/! È\uïïç'ÃÔc¹¯ã?õXÆ©auê0lQÙUðЬ@í;õ§ê„ú§ÝkÏUýPõBÕKý0ÔC]±®'–zc7­¶ ™¾H–c®o–:–%ú/äçà‚Ô« y9ôÐ.ä«‹ùí$ÌÕ^‚]QuëÛPä].@²|)�"©ê>ã42eªÕ/S½‹ —e™ê˜ñ^êX€¿¡î™ê ¡þÉpUÍuÒ4Ÿi˜¥Îš¦S÷~RWU=U~Æ?í±DÏj{ý5Õ-¤2Ô/C]SõKýiõAêU¡Ô‹"U7d:í±±¾Y†¦Qãµy´iezÓ½š^=.²,3KwéÒŠWzvTØ+,(@B\�Ð)º!â´ûF¨li)@•çHú%- ¦aêïdf6Ö AT½0DÕÓJÝQõGí{õX{ß’{Ãã:Z} ��˜Í4ÆñZ½1ÎkžF=7³®?*h¦ÞþÔ0­~ÙÔ~>¡€ï \‘Ï�+òZ½RT$÷VÆçªe.ó8y\¬¦‘qÅÒŠèåìLdeï/àrÖȰ9æ¬Û-úŽ�€×Ômz•£»˜Ž´mkqjÛÈ—ã‘ðè6nÐÁõ"¸~CÉ_pýHÕ‹„_@êÈ焟¼÷בϞ:Ú½<·z\Ç/@žËxu\"�Õ½öõ½ÝÀS€ @-0ŸÛžû›Ïÿ¬Ïù,çvrÞ&Ÿã–ë¦ó@uoz¬Æ[Îﬗ£®7èå3] ˹,×äœOý©ó>uÞ¯ÎùÔ�xÚ7jŽrÞgߊ³:Ç;˜~ Éò™ž,ç|êüO#«s¾FrލîÃŒçq–s:uì­]w�Ïö’� çxêÜÏðg<®7>7\£°Ìg>N—sFWÇêµ¼Nqó)@ P€ (@ P€¾.ÀÀ—÷ _^Ä窫¥€º«‚XûÎÇiùr4¯°¹ò—/ᘼÂËÚó|¹/�/PÕ´¦‹•ê"g� B,_~ª.B䢩v/�Õ°PÓ½L…Ž�[Hˆ"Ø¡ƒZ¯º{üâ9è ¡º},Ðë�÷…òX S÷2\¾ØÕI™ÔóËêK^)—!R¬]Ve‘õ«u…ªrH¹B¥ûHu_?$ ±ra8N‚g‘¡áËRÊò ù¦ ã–ûËbZ¨]d/’ Œá‚»ö\Õ½i˜ºønzlº7 “/Ø%è¢JäbµváZ»ˆm¸�­†«‹ð–Pžåºáâ¹iœ„£d:KXÊtqÝ4Ìt±\žKàÊtÝt_/8ÔÔ2„�Õ«²ö¥ªW*8fø!—t¹ÆP�ÁF §™g¦/% _>8 ;ƒG†//d:©›öөב24}i¢ê®öX‚sò@Â<†/%$ ª/L÷òXÒTÀMÙٌӦ ÐÆEJP²q˜|™QW…Ù _j¨ùŸ“ÕÍ¡éO=/ÐêM¡Þ¸Ru粫 µá–a*˜¥†©q*x¥M'ó˜ê–!¼¤ê”ÊHꙪk¦ “–ÒBO*0eªSÆ•ãýµçj˜<7?¶S?lë$áqu¾$ûž7 P€ (@ P€  }-ß¹A»:¡û`çVã1érqwùïðGÚ ®Å¢£zb¥[‹˜ˆÆ¼8_�÷[UMýÂü¸tY¦º5Ùî$¶ŸHF¿«:`R�¡Z0ÐYyT퇤#øàçD´nܽ[7Cç�Ñ¡YC-Üål>¯yª.œ8Ÿ…½§2�x"¿$ŸÂõ m0yP¼MW—5o˹Eå8²nŽ®ÿm¯»-ú_/�®ÚyœQ;ëy.Ù‹£?}!­�É{ö#ÿÔº•´ÏÇ (PûTëÜn_uØO~¸d:ÿsçǵO­æo±úA_Š´˜®º²ü=í0Îå\Ää^Wc`ëÎìB²æï~n!(@ P€ (@ T±_U n½:¾¬5ø¸¶ |s`‡ÖÔSCÇ×Vóv«_ÂÞ÷Õ;øÇu“вA#óp_x Zmš¹æC\Ó®+ní6ˆ¿àõ…�VMʨ¾XþûFì<™‚…£ÿªuwê¨hŸn݇µ{ŽböèòŠt4 ‡ÕR�¬üËXøÃv\�n+N¼š­³ÕÒzàh³/JËT¿-œ�aóÿƒ@éjˆ·Š XùO䦟D¯û^ªøÂ¸ P€ðY�c™çðôcb�!Ù±ƒ<>»'+¿àäG>‹¶|�Ñ�úàÏq½+…\(@ P€ (@ P  0ðåÅ�ÍÀ—ñ¹êj#�xú¨´ê†Ö‘MªM™¼Y�z‰®ßPûóf9Ü]wštý¤ZmêUGwgåôÐ~>¼ñÍZ¡‘tûéè¶~ß1­ ?Õm#op$ðŸ‡0ª{;é’ÓßÑh«…—ŽÄå싈’.“yóŒÀåœK8#!Ý«�õ̹ P€ðIÕZ¯êÎ/AŽßy£@Yg²3¡Z„Ð*®¬I9ž (@ P€ (@7ørËÓ“2ðåiQ.¯ÆÔ®øùáŠÜר›ôIVGº¶«S¬:'«¹·+~ud?ÊŽ¬Éû²æî¾ÊÙ2OÖ}©[WêøUN9¹Ôê-p¥X{­Þ…d骫€|4ñcÉÅ�£Sjö‘Š‹œŒ \ÐÎÿÔ-oµV Ž:ßÓ xQk+7œ (@ P€ ªL€�¯*£.¹"¾JšpHíP!/}h ŠkQë,r Ôÿ²ºBùFµ†\•Ž>$EA�üF½v¿¤Kßz©ïzø¨º_ú¤öc¯ø@"ÁÐZô^a�Àçø*†aü¤[PÞ(P–€Ê‡ø×A3¢eQ•_$ïÑ:ùO_\bP€ 䘼ŠBåü/€0 øÉ�C€t½^§ˆf> (@ P€ (@ xX€�/ƒº³8¾ÜÑâ´5]@…¼ Âkm@Hý60Gçó-~©‹ý…á*ˆÃ_u×ô׬§¶O}˜SàrkMEÁòeRˆ§VÏåÔ¿" ÍäÖ€-á&T–€ä¼P7 Tè‹·ò ‚_å_ç¤(@�š&pÅß—ÃÕy AHÃH´kß±ñÝÐ%!Æé{¤i1Þ¿/�*½ì™HZ¿Ýˆê„A=cœOžs›·¤ PzÉDN:ŒŠ5ìËjÕÊ—Ÿ^>C�ÜrO&bË‘\\©ã‡Æ�"!Æá€6÷Ù=›±/MRŸÒÓ_Ë�× 6ÒY÷2z$oùI ˆèqu?D8›ÔI¹\,õ¨w<³GÍ1ßd¬G/ç›àúb«Ñ”¹»ÞD»3µuš÷ 6<Ò¯JK˜Ÿ­uóX±•^”ã«�æã+‡Ë DƒÍѲU šEøÀ 1wÆÄŒÀfµ1�çãðæéRÛ]¹•ï3Ý•%Wå4ÁÒó«êÊÑþ–yâvíÞ��Iûp1S‡|™ 4²®j‹îÝЭƒóõ®·G£÷š(^Úp�÷qMÔ¾ ¾ø\$Ev¡›ýðVƒ M\2Ãfö™ïœ·Tœož×U�×äž_oîyùòÔªG}HŽùœòû�f®F§¨Ò¨Oý¾‡Ò/Ë´Ú£¿¶(}êÊÊýý-´ïý¨¶"O^ÈMý ¿¥\”åÊùÛÀA$s¾¥G·mÄ‘‹ª›rq‰ê%熮ÿp­ò…*¾už§Î÷x«\~žW®/—NwxLäž½ÜóâÔ (@ PÀ$ÀÀ—I¢œ÷éÅÆÝª•+g·Hô½îj´ª_²Å›Š¾tÉŸ"ºßß,+½u)ÒÞS¥-ûäîû1ƒ Åæo8ŒéÝ|áË®\|zG þ¦edFbÉOЭÆ¾r±oÇ~ä6B|•µdV>ß‚¡V­{å`ó’çqË}‹-õÛÉ£;Ÿ_†‡¿Í.ø’ƒÏolŒ‡WËLc#å¿Sáê.®�/W[:ÒY‰&½¦ÙÉLÆæ´…èì¥üAaÝ`¨®9Õ-eõë˜vãlì·+a‰§ ðécX;ï'_r�ïÁžcyh×­mZ&*�*±½Ör~Ãøúƒñ‹VZ8Qwsºá}ó¼�ckÞ‹hí¥ýl.†‡øH·|ùêKÇ·½K'áÿ=ò­aäƒëpæ•«Oˆt¼Ò /ÇÞ¹â^×Îñ´9ÛpSã?öA¥‡°¤ÝÜ­QEƒu_!ÁûÕÞ±K9‡æîY‚v½ï׿¾îµXö@�r.©|³ù_·¿Þyri©Öá(f4y>^úûtt®Î‡@¹‰øV®ÀWõ:f*ßqM¸´îe�÷Ê<ô^|èf,ú_Y;x$Þþf.¦iSb¤§£ûCÿÖ†/Ü|3ºWç P¢ø�#�¯"2_¹'÷a÷‰<4‹�G›ÆÞýÐÚ÷ѽô¨aŸùÎyK…w•Ýœ¿†|ó¼ÎnójùÓêôz+í˺ª.gU¯¯¶UC­u¯ü–sPæ9xeý˜¦,ýìß¶ù��Ñ¥g[›å&½�öÝÔðâŽÓøkOÏüðËÕë )_>Žÿw‹åúǃÿ݇ÙcÚ–µA>7>èR¾ü8£ì¾nË¿kùy^~;ÎY]œ¯V—ºSçÇD5k;Ý1)mZž³•¦Ãq (@ PÀ¹_ÎmÊ“ux ~Ø™f5�?Â"ë#XŸ‡Ìlë_®5Åð[—hM¡ü�/=~š=·¼«5Se\ÿ ü÷Ðj nlUœJ~è›ÊHªdÊJY¼þÌwhÒùYvU¶dæ¾ïÕ „ |©›þÞº9ÿPa-ë[Â`tJº öoԚDZû þ—÷ Ú›¿G´ ç •À×z×_ª+‡ä“—dÙ�ˆîÔ œÿ×jýž}¨º9PÝ”u³~ýužüÖ¼rs%¶LTVi ãµ þþ~8õóè=ò«™âqÝ´aèÖB.œçg"ñ× øÁf?ÆÏ®E¿(«Yªü¡?Ì Ç]‹€N/oÂúÇûZ• üuÊj!%êváoað¥ãì‹ÝaÌë׋“Œ³'ÌÁÖ�³ÑÚ u³äxvHYaÇËiß Yü�Æ•>…º¹hé¨éë1,f¸%l8ácûh‚Í—:¦Ù.þö â?ex:êÿ�ºr²ËQÓ2\¿gàËu«òMé‘nu‰¸7z ±WË1ßúªðÌÕ’¦Óãdò!d©.ëG#¶¥«á$÷?ÓÝ+—{S—÷¸¦¾¾L=F§~ó :Ü6¯ÄЇÜ0R{?ÙýÍw0½Ýš&òÌJ|ûÔ56?ª¨í�/׺uÔã»ÙMpǻҰÜsk±yFo©Wîùå�f—rn`}\Y{q^©šZiõz½©.Å¥eɶÉ9U‡X«s”ª.gU¯ÏC»Ó‡£ýp«àó9M')»úÁÏÔÿ&ã…1ÎZ/¶:·rvT ú´5ˆiy³,y0¾ÉZ‹žV?¼¨¬À×þ%Spõ}+´­q$;ºúY ¸ÑrîüÄwɘy�3»J€©ÂEºÖ­#_·Ù%ü<¯ˆç­¥¯V‡ò¹[gÇD5m;Ýuq6=ÏÙœÉp8(@ P€(]€�¯Ò}J{¾X� ãa1=puÿö0ÆVPp>?®ß…<ãø¦=®Ãàöõm–WîÀ—´>q‡tÍó]gYœUækäk›ñÉ5°jn¾y!¡z}yY™{*c“|©yã|YÅ­Ø�ö.º™Q•¹V÷}¯øI૾zåÈ…ß;¥e®O,åÿò =_m=w�£Ë@òásæu�LĦ_÷B­®iç~hÛ I?Š»nÖÐÿùÍ6­å‘À¨´Œ°º² ÷¶U[˜ú¯B¾æ¥hL�¯KÛÞBÜ€GÍ#ŸønŸü²Õy7g׿Žî×Î6Oÿò¾ ü%NÃl/ •À—Î ìܲi§s 5Í["¾o?´ˆ´­óúœÓ8z伸†I _mÍ!¥ó©q.Oöp£ÖhŽ‚ôÃøã÷Ä2—g.ô8ŸzûS’‘®•AƇ£EÇnèc×�D™�/Ù÷GNgbëËýð·Ö0ùŸß`†4-£××C›Øf6¯7]F2~û%©ç³ ¯©�-ZÅ¡S—6V¿¶·”4ãH2Îå˶6l‹6ÍŠ�¸iöžÌ”—fKŒ¸q0Û’Yf”GZà+k+Æ7ºÆÐE^¿ØÖ§~Ž˜ØÉÆe܃õyo9åè�²íW$ý‘Œìài¥É°ÿ:&t–}aßÕ†g¤âB¡e_ÙP=Ñ¥#%ù¬ìã@4‰íˆFòr¸tü°ì—íxrÀdC¹§½�ÿI _……ah#ë,�*±~륾NルÛàÙ�ÆÇÿ¶½hÕ’�õ‚L�ݱ’y̲� m¡?¾ ›·ìÁEi ²I¯ë1,ÁºÉ5NØ�C{á\¶á½:âª6ˆOèŠ6Ý_šÊbºw½î—ø À–·FcìlC@kü²½xë¶8ÓŠŒ÷ÒRÛã½1ÙÜ$šað‚­—ð—–à¨ah^ïc �%`Yò\c]Áåýñà~$ï;€sÆÏ§ˆ˜¶èÒ¥Z–¶ÍúLì\¿{�e 8$�‘1HèÕ±Í$ðU×a—ŽçË:´÷˜6hÝ\½Ç¤â�]àÔÙ©«Rç›Æ KŸþhi÷že½ñ™ÇqhŸ”÷äÊ. oˆV±Ý•ÃÖÍ óÊþ9¼û÷É~Í5Ö�Dt{y�hmó^b½®‹‡·aý–?ä•!¯I9–hѦzô�CðÁehÙínmRÇ]:×—"ëÓ¶M& ’÷ÂÝѧG;›rªí9|Ê›o(åijýÑe]©ÇÉ)g´!á�¯’.´­G–ã±uàkäk8ñɧ­¾é’WJ÷ÚÓŒ+‰µÒMtocÂî¼—ê¤%”ƒû"ùÔYÈá“�D¢uûÄËñ“³Í–bd9„}R¬ö]¢Ûv@—6¶ŸjÚ3GŽà‚¼·;lá«BŸénGX¿´’c¦ºrr$q’’K9vÔ]”Ͻt�kJîsCàë$žOÀK¦Ñ·¿ŽLA´éy‰{=Ö/ü †?«õ.caÝѯqµ±7ëÀ×ÛÛNcz=lÿ»Žœ”}X [UÝÿ4ýÚg(±| ÁÁ$9ö;tÄöد{¿hçèX줎ýÚÈgx¸¼“~Ù†=‡¥ÞÈâ›uÀ€þ½!‡)†›ì×][¶âÀ‰LíØ§aL“x¹B@IDATkôê'ã�U*7ÊSV _OAú™�xtÄ4CW¢“ÿ‰m3ú P/ÇʱöõZ‡ä¿!1)U>烵ÏùȦ-×¥“‡”Þ�;Ç8e~y`¬›rx ï» ÑÁîxʨêäÎøz<,¯GyoSûC½·µŒM@_'ݪ[Þ#ZÉvÊ+!ãv%&iïûêXU$ôê#ÇíÖŸK¶«wyû]x yå¼Îêý@�CÙœÏt�k:—òú±¥�gîÕ£òŸ¿YÞOC›È±²¼VsÏ$c÷Þ¤gæÊ«RÎÅZtF¯>�g›Šíò¾3Î`©/%�ÏûɱLq†ó×[ÀÅ3ÒÚ–´”,çªÑÿ_<™Œ4i20´ bÛXÜ-ëu¯žZûšÖéü}ÁO^÷ÅòOš¡ °]¿ÉËt¯•GË`;z/1Me¸w¾>GóºWl×Tò™¾¼æn½&råós7KWr¬-ïݵ÷ õ~rø\¾ìφhSâ˜@•×ÍÏî’›hâ0ðekó£,Ó@uo{nå8ðåÁóšøhY„=>ˆ©/mÒ òÆÏ‰ZëÒ�M[É5y[wé˜xMÀ©¤mصç$r ä]9XŽ�㻡WBŒÓãcë-4=.­…¯³ÿ“ëCf›&Ń_$böøŽæçޤÄöMàpF–œÛ‡ ¨ž”«MgÄuµ\»°žÏr£½œ;ë‘´~#ö—sûà\{ËP4²úˆQ?¬;´g?RNÊq…œªe·êÐ ]d›ƒ­jÿ8'û÷îEª�(+u«+×âô’îÙt”ørçuëîû¨}±íŸ[ÞïJ¾Ï–¼RÞ×�ûÇ ¦rªó…=»"íÜY¹fh8NˆëVòz¡g>ÏMkur_�ë—.ÿ;YµÓÁî–ɼ ÷ßKÝ©+å;ÏS…s³ŽY}~Œ¥»À­¿bßãyBÓè+ç rÈi¸ÉyBâ/[åÚ�á›ÂÊwß#,ûÕ½cûõÚ?/qL$ö®žÛzò;1�àÞëPŽ}“åZ‚ºÎÚÐ`c¿�–eËuÖ¶±px*ëâ{X™çlî¾6Ì…uÿý×R'\ù\0¯H.¿ÈûÊ¡crFmšÉødÃx™Àá±ÚÅ3G�vÁñ±œ[¯E«býöÞ>«âJü>*TTTÜÒÖºeWm±%Bm+»Vm+›•fmÑ´˜¥QY0­›úb‰ 4”D?)*ºÔÀOCÛ”Ñ ¦jjL7tIÀH$¸OšÄ!h‚‚óž¹÷Î�3÷¹÷ùsŸ@@Oüàó<÷Þ™9ó�3sÏ™{î $9NRÝ ý¼+IM3×ûµÏPvü� 0&À˜À)@ ¿¾@„üûÅ“½BþÛ¿ÿ)õ¯s_�ØòÂsâ¿yFw¨VLrÚc܃[Å«›º×P¶ò»7?Y‡ÈÛ¯ˆY¤nÞ4ø†±(nètåh?zÈm#ÊI}�T. ,7M®N7‰’‚¬˜×.-Ûf–ÕZ%2œº¦/-«su›àÃn’·Ùo”lRö=µ+t™s6ºõòoÏ.Q]W+ª["bßÕ~ºÝwÕmSy¢¹�•](ªéëÛÞ«ãÔõc Å.ÚS«Ç­ùÕ²�;Åâ1´žôûhQþžÌ?¼Nù×Û‘ùPµ®ßÄb�+oD,S:lÕg®x•ÖÓ½N×=iV˜ÇK�NvÚj²(~q�n7,·µtÛnOCìv˜´hƒ/ëduÿí#=¦>zƽ΃Õ˵œ“׊½½ÇD;ý×ý†˜æèÀ¸©3\}Wøšy¦ii.£”¾Œ^$êH>{ëÊtÛ¨kÈ礅ψ]äz%CËî-�é¦,Y+LãÈŸ)¶t:²wm×cLáËâÕM‹tI™²,x¾9ªí½�bÝ’ìÀ4¸_¨øumgTº]XÇi£©¾{¿gŠ•¯´{Òõˆ�…AeÍ­Yä2Å€/#mKä51{¼· ú;[¬«;覩,œàÖiœ'/Å[~¾¾a†{]Úâ×bê�«b~¶Vj"½0êþk¦�ˆÂtU‡tQÞèŒ� �¥ñÆé Q\m×5¡ý”`kØce†X]ѨY`�Ò•.¥-5l«Tîéaìm¿ ¯mU¢Àå§8:Ÿ®íë¾Gí³mô}ªïý¢½ü^WOnÛ;ˆcÝñþ5‹å×h¹&ÌÎM³ý!uM‹û•ÈV|=Ÿ™ó7ŠƒQå¼#j‹mûe/ŽN·ý!eo¦‹-5ω9ž²Ô}ò™ú6ÑS_,&øžÏÏ½ÙæÖÃf�¼<ïwi¾ÑÜ#bi ~R;e¿hªŠí ¤e-ÛZýÊŠ×wÒ„×Æ©*Tm·,Ôýú×Ô›º˜µ:Nß×2u4Vˆ¼ =¶Ú K”ÔDÌòŒ1¢\Ô”æýÔ:'Û´ ¬ÞLkÉ›\ýéCá×éñ ÚŸI¤o+Ý £GºlIùot<Í)¥E¹m—î;~ïߟ\ÛYu4ôÅkŸ_-~ô%SgÔX ü‚Ê¥d® J÷¥.“>KïF¹Ééit™¤Œ¨±éRq…{,Ú?Wí¼¿c›Èq¯‹ç—Ä*¯¿Æ!=¸2:¶ktý½×ùs­—±ûDë¶×gÓímëA~q™(ÌR:Í3̽Û[?ú»íú#ħ™²l…˜1Q•b±åoiŸÅö�ˆoeø@öuýí×|qöì€~ª}ž=uÚ‡]üâV±ØðÅt} ³PÔñÖ'ø÷K�NuËÆ-]ÿjgµ.O¶áŒÒ:÷œ¿ÿØ&Š—é¼¼í0Z,~±ÁÌÃ˜ÇØ(VÎ!õ€ñŽŸ+e�—÷d±¦NË®åëkçºõ‹– Ä”e›ˆ�Û+:ßëò¹§©þAú…Ûו̴߆G=~%Õaë»1ÞyÇYs¼ Û‡BÙ –Ü buž²ý™UPbØ,©ÞÏ£ØìR�¿LÜþ�-‡ÒùN&™¨±4a]‰§§þ~ž”+ŒŽéûGº(«*¹Q}ÈÖ™âm­Xïbí×eˆÒúVŸ>š|]¨<'ÊçÓ:OÞh?a¿Ñ®ÉÙ<º\ª—ú»×&HÄ.—öb?à Ó&VÝ"Ás ªî´NÑÏ¥’Ãbùlaú†”1ÔøkèDìû‚â >;Ðw¥Q}ªµ†>Ç1ï1vMÄŸÆg®?O·ƒÆ•pã¤Ö™$ý%羑´�f0O¶öŸQíÉŸz hu +*cÍjý�C�iéY"''GdxÈdUE¢4ú�N$¸†,œdÉ|=>Ò—Vù¶Ö¬ÖƯå`bºÜ<‘›ã™ÈÀ:úÕ‡Êa|GGÄ "K9y˜o–žè¶dµêmN€†•‰:#”CFVVßô¥:àJÊ]_âyà—–nµKV† J³�òŒB“Ÿ™öµã~2ßÇyO¸Ù§È]]cµCغîO�¯ÑNDG­€¯w_q3'Kßž4ÕŒA×� d:y1qª˜–­\lV“ÉD§ €Ñ“¨î„,Y_ž  QùUXBŽlGÄ,*~—=]L›9Õ Š°uf²Péâ|ɶ“m©uM~Oéé¨3iy¢ÆrE¡'3=+WäååFéd~Yƒî›øË øòŒ vYfñkO){Û{¯¸Á+râùÁÚˆ9ñì¬äצ»ªÉX'ë;f¼˜1o®˜1ÓÓ†c–ˆí*Oò°2i•Öc2ßštïkæè@?ÅuÔDL8Ë ´ ¯S~us�Qy݇mâÁlÚ¾³ÄKT§T]Ég(V˜žê»ª·ú÷`µÕnûÖytm´˜2ǧ0¸o‘©-„î'ðÕŽÁQ:0S”« )'øê­ºµ®¼÷lªMuX޾O¼á ЪÝ0ǽvÜöVÝSîq›Ç1eÖ<1sz¦y|V™x‹æÙYKd“åŽÓæbº©:pÉÊÏ ²"_˜Îc<ÁW£Æg‹iS=ebð–(f•Ý#~=�ê >¸š4~mû~«u×ë;ªþìý «Gþe§‰¸þ›O=¶rZz†Èòi»Š&z_J¾í¬úƼ§|[üGìþFëjê¾’-"Š”ßà¹G„ÕÓè2#"x\˜)š¥Ç¿Ü¿ G|NçArŠ­y¯>èß±Êë�qH±óÿŒ®¿÷:æ4]`ŸPã‡{?ßùpæ;ôË@8otæ`¼_“ÖÖ‰]$x `–¨Ž �"¾•ëÙþÚñðk¾ž¿ˆÌ5¨qf´egÎ(±­¨�¨Ù£ß3sº˜4Q¥±?•ŸäútÔò|§þ–š_ØUk¾h3£¤6Ž¿ì}HÎ)̳æÍ“Ö^À€Ü"7€Ón§ôŒ,á�/LË/s}…Tîçz õa„ ûwþ2¶ýOu>¬LrnÓºÇ]õ›ËŽKÒ•�~2«c¾÷�´ ‘ôw´]¢|È ï3…puñ•'àyAù|¶N„#”>DÙwøìÄǾ«t_´õï+J?å'e!í°Dìòãñ ‡Ê¡Çèú¡²}e_¡v"Wé¸cÚšÉ�aTNšWؾ!_å¯%Ô׃ڿž”™/ê +K'ŠÌgtK½‹74•ëù׿ ×eyaÇIÚTgâúKXf(-…~x<ú íÇü=H×ù8ëëëëÀɤðå1ºú¯qö‰?üÚ^ÝK®äµ¥¡ÍuÀUɯðew…•êmñQà:%i¢T­0áÖÍ\�¢¸Æ|«½±Š¾Ý“#j|VãR2ÓOjÐKÃO®`ÕHÒn+!o«§Ó%ðM–‘o®`ÙVj<ÌÔõŒ?xÔP£9½ÀX 5jå/=q#ßž +“×¶Vò"ªVÓ7¿i™�¤Ý@ä›Áv å4à%KTºotH‡Ñ|¸—–³TÔ46‰H:�VÙØæjâW‚3�Ñðu Ï7¸ídÀ—±*T@ N"ªö5dÙš¼/ÖР£÷êÄ=db”¾uì7!Û†oƪƒló«#AL‡<ùÑ7w_&«��™+^z—¬bu¤Y,#�=“µ'zã|©>Hu`©;ØœËHßÇþeÆ[z¢¢ˆ®ö—§�Ï(ç ß|+­M‘þ#îØb¶«ð…oÓÕÚ$³qs–ˆõÕµbç»æ$qp›6m4WV£ÁDrå(Ú&³6;Û¾T:ØK–G'óÕ¤»<¾�<˜˜ä;iùÂë”ÎÔÃ:NåÍ\#"Ê w:A>Ë  Î'$+¬³^áËžô5³P¼úv›Øón®¸&å5ÛrÒ"ó í=»7NËp)%çκŸPÀW¯à´À³U¥�4Flh;,^]¡¦&ˆ ¸ÔîÉçÕj¬Nñ ² Õ¤…Ï«ˆímxΨ3néQ½º†C�¿O¼N¥ÞŠZù‹6aÕg€ ¸"YY«ë q ¨Ò²»^!+ža0؆-O{ïA±�®ü5~¥[ºRÚ¸¹eæjeÝíâ×su�Ú”u�v�`;÷l¢«�E¯üE¾ÞØJV-=OTbÛ¸«tuGÄý*0Ç‹I+¶;犕ä8­·›6B‚ÂÆ/»»c¯�¨ÆÏ˜ŸtB3î _õƪ«îCÕÆRs ߦަl:9®Fð�^2 Hä oϦç•«uíïhÅyúÁÖjgÇ€:…¿§§bGÐû�ŸíH‚¡H½%“`»Æ¼yÛ·ïýˆX{ƒz¸�«cí ðŠZõ««†¬¤•!^k·Ózƒ¯&Ü],ÚÑžQéßxŠÔïõîŠb»Å}$ lÞSfðY¤âWä!)Mw@¼ñØ­ä®òÐqXní{.j•1šwÏ›ÅË&’2D­S�cÝáä‰ðe·G+Y X=ÈÑmCW,Æ`…¥åÆ ò-ìW^´‘KupzX‡ÚëúáA«(ÉÕ�&€¾ƒ\[·ˉ½…A÷UMNЧ´“:Œ@²ŒBbçcà&­Ÿ\Eµ¸Š®ÊWCÆsE²°õ�ׇ¯£¶¬´£ý™Øü÷ï¯GT”Û”ˆÿFÇSKG=m×Te¬öLÛ=tÛ%pO‰Õßh]µîS¶$øˆŽ»)èiP™Ar+  ~«|—åé¾õ`,À7 *Ï‹Âë�Ë(Gý=¨þ:�?óDúÍÒòE yè\Cç_,ý¤óáïÝZn]Gu,*àËò£º� ¢qdå`ÛW ¾•ðu<ýšN²‚² vÒþõ-ÿuÞ±“ªU—¿~¢ÿJÒÊ¢Ÿt~aYC·ˆx^¦™¶6^°W¯Øù")W/ÝG}ênQ¾v:ÞÛ•�3WÔ¢ŸgÉõâ®¶òÞëÄvf€Ýd±~·öçä*×ëéªbF[EÄ|2§2«Ô¬Çö—é fSE…³Zuì€/[¿bõÛÐãhÀ¡ôØ þ!óªÑó áûPX{Á¨oZ®¨hÔs2æ“Ì\h 6�ÙO¢u–êš¶Ãbù¶ÇçNè6¡¶¯ÑVº®tÜÑuô´G‚c˜?¯?þ&v_Ð ¼z wãÁçtêÅ@k,%6 sïö.ÐTQàÞ×Õ‹aûâ~|YH?34û¾”9ö³'2'…²&þ¼+¤�ºŸ>ãmSþ¬ïٰ̆°°œ:À_–±Õß�Ñ!ªËŠÝÕ½V­Y´ù”“tÀWcqÂò�ÛVëhtbÙêhÊ!•†dF‘vúˆLõe…"i‘(.)7‚¶buTjÐû? ¡žžl4't |ߢo*ׯmZž~[-–<Òˆ¥A[«éŠN]Mç¯d¢Î@®žqùšo´¸Ë·Öàö’¸ ˜\ÍË÷S«~Û�n÷A2æk¼áŒeFéQÂLžx¾±ÚÍ øŠl£'béäiðw2�Œ:o¼åêL~ÒISÜC'du0Püü¶oÖo·ªÀ-)_uÙ1)s²õF±Ÿ~AF‰|iÇ‹:Ôò�} ´ Ü ð´ÛÂt–‹jÔÄ!®rá ‚ÈqV„‹Õ~ôœð…ÛX¶<ïY]HM@ã'nÁ9cQ¡(~¹Zìt·á4Ûx_yëWðòÝš‘®–½Î£TÆ„´ÎŸNæë66Á¨NØz_‚t*XOQ&*oæ\±xž¹zÙš-wP>¡Y¡~�–øöý«ä¡†,o_i‡‰KÄN§ÿPYv½¬·L5ïy7à+Œî'ðuLÔnœçN~ŒZø²­ ÝÕžœ-ߪ]é^;›(ÁK3ÜU¬è a€A[ÞUÁd Ñ®­zÅŸQs·8å·�b+éjZÎjToe®nf¥k7ÓhÀ×ëï“&gÚc¡Oýh;ÑtF™¸¢Z‹’Ïù|u�ÞÎqæÆfñN|¡Í¼Êh«([ªÇa€<±Í ˆ7–¶ŠÕämý‚rèáÚ81çÇëIBú0¸°Š—¨tøka~�(Z],Êkœ|}'iÃßÓÃÛrUZÌŽª£ƒk¨íˆÁîîƒì`»†Þ‡ü¾÷½¿C,rƒ¬Ì * üIWÀ¯¿€/½ò—ΧM¬%«Š-¯l¶ƒÁ:kÄ}?È™r5¯k‰ˆ Ør?1�œ¦Ìd¾=5$ì†_EmùÚbì·ë`0+ïwÄswª` ðRžD¾¨Ÿà ø2V'Ƽü‚;"t0wãð6µ×U |yy�õQ÷áÄ|Ãm%hÇgXþ™±bªÓ©¾› ¨>ƒðKÛPª„iß.|ý-ûеñLß@öÚ^þ~ í›ýãCÅ÷gb·Cx=2W[HÎ3W“VaèØcÈå¾ô”JÛÅ»§˜ígêšYWÓgP|‰>òÈqô©×Óà2©ž™rÒ‡Q¸PﹿuÔ� Iò²Šº÷|—çY%=©qHq þ4Ç?_Œ°%Ìã÷ Ê ÄjׇӲTÐq�<¸OåÞMõÛûÝ?à }\ÁÛZ]JÎAá?su(â[Ÿíxú52xéAw›Fs•oéÛPÐïqW�výŒ0Fý#ú�Î/Ìz´Ð`™]߉¦1¿£Üä%±ù/ûm­h¾¤ó`ƒ k#An ¦9«™éü»ÄJ#oòR›[o 욨|ùÑb}‹ó¾ô6?{*ÎuàËJ¾¼º|y'ðÜoSGuñê°ý;þ8›J g/˜þ‚ž³Ñu©,ж_V‘½š?å—ÌýÜŸ‹.k ó—Ô’�ª‰Ûÿ¤|¿q>´LáÇR”{ÎÌl·dü¼TtÌ`ì³ SÑpW R|;D©û„¶ñöïO¡.àó¥6JîËIÚ<ñúŽ¿M@ËóØåÇ鎡#ÉôCß¹¥;ö'w´­iêO¢c˜¯TúF¸ñWÖ+^_7xõ€mÑ——Ü@2Ç>²¶]ÁγÜí¯rH3Y&3®¤2vÓ¶HÆ_2|¡¤llÚ/’ð=ŽSŸñ¶)ÿŽ­ó̇ù°°° ¼ôWÀ×irOH4R’þûåS‡­4?¾áPÒiOÎݰãÅ Øuà˜#Þp¸æ»×Â…ƒ¢¥---µÞ|óÍÑ'}Ž4¬Ï…ô»ž±ÎàÖ‹ðØ-¸±›ú몆ÌKo€*ëw.lëX—¸evªÌË ß> ¹…e0;k\xŽ{�Ê%©Ïž†ÇaDúÝVšœÕÛ`ùM—xÒ÷Àúìp×fy8*#%pÅ9»×çÁUw­³®Í+k„ã‡{ÒÉŸÍpïß] �ɯéK¡iÓ0L~�õ×SÙ#®«8ÈC 'a/^s‘º¦djxÛån»]pâJî¸"JÊæ�ypåL»ÎA×D%Â:o-«¼Ž²O/¨€M³Çz’û³—…æŸ_�pÆOqúipà­§à Wàæ‡ø‡Á6P<û«Æ5Éý膧oÿ¹I¦š¯y¾àQõÃ;ÖÀÅ>å½¹ê6¸îG¬â0þãkàwšßtÌï‘„ó³2Šõ¿Þÿ…»Î¾~ƒ×¨zŸvìCøÄû½±RYç´n C w\áôCÇó ~ÿøœOn-›ï…/g[= ² q<¹MŽ'ToÒ¡¼i\·ãéÌ�œ;ħۺ#ðì£÷ÁŒŸþ·¾ÀçÛ¤9…p÷Üé0æ¢!îÙ7WÝ„íð¬õ{FÙnøyæ÷œû¥¯ ~" ÖX¦BÅ¡Ça hž0qìyià�cüõ`Û+]ÓmŒ5'ÇU[è„T’Ó)�‡Ï7ÕþcðÜŽèóãæm‚§—\õ5. Í qÓ:ã›÷ð›¹ÿlä½§øN¸æv»ýf½�{¯û”qÞþ�ípºÓ a×KwÂù>WERuÇŠ÷é}Ç`p·mD]�>ù<%¼¹æ‡pí¬ë¸+gÔU>�Í�ÈÆ Uýäe}Èz¨Ã2¡™]i1“'À¯¯ó_‘ßmž_rÎ8ü”)ÿp ÍE;Á¾«gÁê²[àÓG�ÂQ+Á`<ûNÇ›ðûóá™�K^YÚ3:⌥½ �wQ:XVAZ>4VÍ?K¨eŽÓ·Úã4®fwŒ]µÃ¥×Øå¤åBéã³aÂÈ c¶Ð:¥BdÓmpN ÷ôÐvJMí *FÛq¤ÃL}PvP�¶ãXk 7�+›R¥ŠõyÞáz&‚­½Ïí;“ü€ûfÒÿ5tÜg�Kƒ²7_†ïŒ;þûøÊ[KpëEøÝôhÛooÙ½pÙ¿?j¥Ì¼¯ùqô5~Eê¼3 ¶}=|ÕÑùî7‡ó¯ú‰•dÞÓ;à—7˜ww�à¾Êf˜ûOæ |ÇS(s®”ÙÌ×OzLç«ÓêpôCzUôwÚÖ^Û·áñl´�m‹f`I†Y+·>ô>íø�•­�Á@íøälj7ÕDàê7çÕ·Ú¶9N`CUëHÓ¦Ht…Â!}Ïd@õ9j:–G�û½èg]äøYnÚ~³ñL¿BV�¶×‰òëh™þþLlè¡õÛ™êƒË×Sœ¯ÿFÚ”ú·FÒ¾Ý�÷é«ì1û›5Ž�^w±uˆOíoŸS–Þúк>ƒ+4É_Ý#¬sä8$¡§˜6¨ÌXr6oBÙé“K+ЧëJØU» ï}ùÖooýÜ‹|¾Ä*/ýñ)Ê8T}aK˜Sy}û½w£ýP�öCÔèÙ¾ÒÓnÛDÑ}=•{·–;úÛáóÏ8¬}0e×Ë+ÿö›¹0öæv"ôv¢Ÿ`۪ķ">ÛñôkLŸ~2T¼·Ñ±Ãmñ¨_4­¤îŸz©}Âý?‘¢Ó»—y¾ÐùÏ)ü9Š÷m‚Iÿãæƒ6ò­8_`ûs¡öÃÅð÷ÑÁß6!ëmÖS­…¢;FãUTæñPön\%§7Ô_ïN¸çì±¶/1f!쬻××— íˆ«£Ã™¨Ì¢?uÝ5¯Áݽpz_l‚ö£¿§tŒ–Ï}&6>͘`Là¤#°²çgðï¿þý̤d{òÉ'aäÈ‘pöÙgÃé§Ÿð%ñ~þô¡õ°by.üsÆ¿À?º'Õqû3¹€¯Xüw_†åVRúLçùÊâL¸qy•u£ýaöÕúiVíªl¸>ß~°¢R¤gåÀ 㯇¯_ýU¸ü’8 U"òI úªÜ–ZA&§µÑH FHË‚üû{èõ<ŸûaérõF§%ÅG%F:®d‘’[¢‚=¤sþ8¡ÙϘt¾©ÈDÓâö“p›Œjóüõî^]u—uÔk$÷u5Öç* övÁ®Ž½ðþû k]ÛРž&kYå Ê^=¶¸ÿ£F²™–Ê›|Pá>O’¯+–Ï—¨€/œ ,¶&(}.Nè™ØÌÄ Ÿ²ØA?tRZOJè` ðùÙâöÁ¾šçáÅŠhl|öþí=8ð®Ý¾;áÍöUJŽþøÒí„öKðÁ¾7�$z“h %ÉÛøRÇûÀžú:ØVõ¼úÒoá7›vª3Æç²êüð*;¸†¶Ã²ºNø¡c\oM`OÃÀ>+¶d2”ã¤ý×é‡ Ç-à+I�òmþ$AO0'åwD³™²¶ŠnÅàž€¿Ð¬ð¾DløMÞÓ¼aÌT¸ç¦ÏÁ˜‚œ…cõý÷© >=™o_•œî'ðï` Ï…N ÏøõîZ˜Œïþépù7f�«]Á�ß�úÔ ¿½íø±Ç©ƒ©hð®ü÷^o/Ñ€%� ÷|oôzê<Þ…û°ƒÂT ÑÔ=°“×ÂÞ�9>ý®žÀÀ®{ž•"|M^‰iïˆJKÔÜ@*#È `ÊÜEøÈ#ìYgÁ�ßþ žtTkÒ ›�ú„Áq9g?<²�áÿ&À´¹7·¾y |eìøÌP3ꌲ¹¿ö üpt´qã+§ÊPþ¼^|ñuøëî Âç^'#ßT2Ò€/LKÛjæ†Føùw?oåØ×öøö%7Z�£f=[˜göõwÀ—+|Ì/¸eE‡hÞÉ0§òúö‰„ôâË~Ö´�ߨLÉöU£rž±¾¬àüë> þh'¦0�ê‹øƒø×FÀ—~ù*)o‡ñü£LŸ€-šÞ¿l"³Oz÷'õ§FáÑ7Ý3êËt >{Ä>Sg¬Oê/ø¡òºÃ»ž„‹ÓfXIÔ¼‚Qg¿sЗ¸õ<L†¾Ä¼…p‘�/ѵñç𤚳x_λCû¦}š`ëï7ö× ±}7¼�öŒšëxÓõmµ�˜jÀWXÀód¼ gSïCIÚ ØßÝ—UmõèJÑqÄl#u%÷óèœü�¤:yRÈ”ÂXjø$~º’‚Ÿ—ŠŽÅkwš7®t‹/Œ¢1Dþôy}߀êOƒ£¡‡)ègB횀�œ¤ÍC0ú~Õlé˺±ëy2=Ãñ}yÌSSÚÞ®Ýr óãE�…³a’­ú‘6òëëÑ?Izȇ†ýsáB¼Èm[̳qÃ×a޳p�ˆÙù d^v£µ ƒûD }QÉfì¦Ü“yÞe¤ó}^(¥B>^_ÿÂ,É~èrUÆÏTŸ{’¬ø+`L€ 0�S‚@|�\á+ÌŸZbìT_î­£©V¬_µJoãøë2ÑÐ{ ·d¶t¤KÁ¢f‰,Ü®'??_ÿ+À-Eèr°îÖ'JÜz¨Poû(ó0ÿeˆ¥%U¾Û=µ�ÿ’½ª<ùI—bÕËB›KÂzåðû�nlg$Ï~ºÌ0n­½Løñ‘‰Ö¬7e`o*ÏwyãÛMî5õ¥îq³=¼4?™Xö2-•7v™J‡ |ý˜¨c֖޵+4‡™ìíùÜmâok§·%�×’íÈôºeNˆº[)Ð-ôváók;Ò@¶@P<ý?•)oéHÛ‰l¢x«O�$}Ögx•6èSméHY{¿Gµ‰ÚºWă˦ë6·Æ£éâ¥Cv[û·ƒW"âwsÒÒ-h{ÝÆæ6ª-´ì)è@,=¦òb]¦,Ûdé>ÝRöQ¿í@•l¡Y¡\´P~y'6VŒåï9íB÷ÝÒQn«X¹"ÛÕŸië­-7ÎãËå�öVˆòÚ×7èmÿªëÁk;Éö‹Äƈ¾–æ›X�'ØeuÕŠ)®>Îuž­¥í½tëÆL±Å•‘¿RìõI»—lMényh”é?®xë0nÉkîv‘oíÞ"¦�N7iÖrQÙ¦·{¤lfnòÛ>ò˜ð•SÖ·ˆ\àn-\¦”×­ŸâÐ\&ð™Ý¶ã—‹]ÎñÊ5Z0ͪW¿oé¨ÊõûLK9y…¢|›ß}?ÎXJÇi¿¼}ŽáJ®íÐZ_&rÒ‚9fä.UMd;,Zžº/Ðc'Ðf o¿¦d‹ª û=Þ÷~ÄØ&±¶ÝÞ–Qo¿ëw³X~�b­·BÜþ�ÞÎsy•³]£»-£�_gŽî85cm�½¥#^Ó\F·wUyû}êò¤¬É–Ž~eÆ“IŸ7ó #Oª[:R[4Èv–[µãûÎÃQÕŠ65Õ[¥Ë ÚÝ´Lkltûn£Òm»S üŽ[¨ê­W•¬þŸ„ãöaÃG ¨í+nÚêo”éÓ‡hyþmâߣ¸ºmæÏ§Þ]¿.~™±Û…–í/³Lï£G((­¯­œP˜eÖ¤¨»FÛØç”¥«/N߈ω´­¡�AÇu»•TfÐõvÃ-¥òÔÖ³ ðÁ—ÝgZ«D–Ò+Üj9âÓçƒúh¬ò‚d4ó2ÛÒ‡(?~Þþl©¼¾z™�þ5‰2¾©­‘©L^ûÐÿ·î«&Ýþòxà–ŽŽÙ·Á½âŠV¢ìmÛ__¦¶W$>ÛñôkŒ9ˆÞ’1ž_/½òŸ¼Ÿ´NSÅúÝr»Eº=$Ž•cü¶�t|*ê/VÞrv½¼Ð嬷n$>læ ±Çë—Ò¼U‹ó‰«B»s'µ›—¸eúë�ºhÞ)mé˜�þï¾cwÜ~KúdÀ8›R c/ÐúÚêf”}2î80O«Ÿ«s1©Êú %ekÜ÷(Oÿ±4î=™æ§?©~£ü¼Tt,^»Ó¼ýî/ú<™{N¡.ñä18v)鋯qÚ6ß©¼�í4F�rÒÒ:ym­ ý”Ç5[š=)Ï·ž'Ï3œDü/ÊÆ­#m�$Æ0?^ô˜ê7±?‰ füµî¤�î ±Ú]ž«)RsjkÆ&±4ݾ7Úý>âù½_4–éçG ëØÂæ–ò±ëNó·ûJ¨q2PwÍþçwÏ¥íåêƒÅ”¦õ³± ó¤ûaÿ÷™xíËçi{òwÖÖÖÖ�“AT¼U²±ZO<ñ„¨®®uuubÇŽâc½Â×­uðìŸÑÞrþ.¸ &]wœçìl¦{?_á«6æ^3íµ¼½ÙüNƒÒ†*ø¦|}€üõuµÀöm¯C峿ƒ¥ëÔ›íú÷í}(ð›ïÆÕ$2Ÿ¼±C#ý!#ŠpKšÃîªhFÖ�#øÄ”i€ *Äþ£oó¤á6�U~Û@ö¿L´>hÈê­õˆ´=î’½¸ ®³JG_Ë&øô—ou¯JËʇ{n¹¾ðÙóá,\•å,\Žý½ ²—Ë·™É[Vø+,{Y•7)þ}d…¯$ùÊrƒþä _‡º¶Âõßä¼ñŠÛ&Âmcìl”—}œ¼}KÞ¦iè¼ú X|ã6Þ–ŽIå× /äƒ[­}ßdé£aÖ£ÿÿòO#á<Üúâ¬Áç C505Í®·’£_Wø2ÞÒ§P‡|tÒxË.FZ3'ýËw…/}:êÛáÿ«€;.ÎtWš�[D܉[Dø·ƒ7ùxßÿéåqÜÒñ=ÜÒ1�¾èvžz7¬y¢[:&¥^™=¿éÛž|w .^ïl/*S­lè„ï~É\ÍEÍÊû&¼»…©ÌÕþ£yCæ\xðƈ3V¾;}2|rP8ÝO|…/|‹ý¯ë௸Ýt*nÉøøx¸È…ð°<âY%«/òøÜH|TˆSÖ4Â#ßmƒï ··~t·d´Îš[Âäyðпa�= /9—ZGð=øïÞöødYák4nóX‹Û<Ò ­ï86¹[7¬ð5WøªHp…/ÔwU1Ìöе¸­O,aÃgÆM…I_¥ÛTöAË_·ÁŸ_Ü¿ÿýÏà…W¼Bã6Šm¸�â&›¸5ä�¸5¤÷ïðNl—±v»¸+‘¡L/Üy䨅àpóÕÙ+À¤±—9cáy0øÐëðƒ+ìÕºt:•;åðë†Ã0ùÒðÈØ a±µ*Ø"¨ë�ŸÁËÏèï¾ä[—¸¥ôð¾>\ŸŒþ ‚A1mbkø�¥Ô^Áló ‹°íbBh }} d\1œ�m·{;¼þR%ü®|)l¶Vò §Ñnp· å)yè±$ïé¡ídÞ~!L=6­µß÷ó÷Àê¨Uº•¿ ó'x d¿„òXçVø Ú'öÂY°½sŒAûD¯–%WÓjÆÕ´|züöUp~ú<+gµíc_ä÷pæ¨[­còc~p/,˜v-\öÙóàì³Ð68kl[1n,´m¿ ¾üÊŒ'“>¯Wø +O®ðd;ãrvðxæ¥p·¥Û¸¥c·t¤«$)]viê/~6ÕÛ4¼TvÿT_w$ò¥6ç]ÙjAbHþ|d|í pþyhÇK;ïƒÿ�›®Ê¶ÊÂCdÛw¢Ïõ }ÅMKûm@:)¹_ý ϧÑòüÛ„ÈLÒS®Iù �±Û�–í/³Lï£Gž¾‚ÒúrL¨ |ÊLAw�¶ hwÚ~®¾8øâs"mkät\·KP¹Ae]¯rìmÀU±Óï²æCÇòL\Øòa¸ì†ëX^)nŸì�àP‰}>c•$£™�O[š‹¢˜—;¿âçíÏ–Êë«— é_+š÷ãLì¾l ;¾ ®ÿÏgíÙ íÉ xúÆaðŸ›ðñ�¨ïAý4«óáã&à׫]ù¬ÐE}Aÿ²ÉƒOzSFýˬn­þ5ÇŸ;ðg¸ë“ãímçåå3×ÁžÇ¾µÊ/Äðu)8JüçOÆÞmšä®ÂEd&œÝt4o<8ëÑ5±}‰ÃGà3éY0ékŸ‚¾ÿûŒ¸xª›Õ¨ì…ð“Û¾Ÿ¿ç²piÏl_þ¸õ>i¬‡¾Œ±ÊÃúâ;v›—øüòï“ôBÚ¯“»ß…´ŒþŽó›è“D[›TBû{Üq$䪹5]C}$´L[\uSnw¯³u¾ù�¥qïÉ4oÌ)?/¼Ž¡T¸øg+p¿ûÍ;öy2÷œB]âÉcp$veðñ¨Š>@åMzŒˆ?Ð:ym­haôö¤<£þ:�üv2<ÃId…/º½«_F{$>†ùñ¢ÇNÈøk5i£úd¶˜ù«·y#\tåLë`^Y#,¸r7dޏÁZ½KíÌã®L…þhÇùzܽçk÷ž¨j]iòÙe‰?“WB�“Xåî¶«Uý?¿{n"éü}´øÌãõÃþì3º–ü� 0&À˜À©A ¿VøúØ|~glúã.·µÏq%Lúú¥d[÷TÔ—„¾Ú·BzÚÍ΃‰4ÈÉgEåfØ¿óx¦Ê~„×éë…öæ�°ùÿ-‡»—«à¯´„·I F–¿áG 5âÀÔáö’×:ÛKÖtÀm#qÆ¿?þ¨°ô+n�™Ž[cZˆ´#›ŠL¦!½4¶¬ZO:ß×Úpª]hºôüRxfî7Áã´õÞtgû -«•_g>–“º®)ð�Õ¼2àëÈÙmpÏ'ÒàIçÂ8™ÿó)—ÆJf�S[ÌztLϹ>ƒArÆd®ßÄ&^A'tU •ÌМ�mà YÐg¢4(?cu<ïÛ“þÁÓ­ÏÂuŸëç€/ºÔs`?@D‡Òñ!ä¦;p«0:ù¡µ¾>„ƒï´Á;ï‚/|鳘gì?ÊüA jú>5½¹ê&¸îGöCÿ-5dž¸=Þ�Ãá§òAN"'º¥ãÛ/-�¯|ëç2Ù¶3X'¬ Ãê€�8øÿTG¢¶èè†gs‡Ã 7`p2”½½œ]/ÝD™%Ó7Cû²…‰-ê_fì–hx<¤E|%î¿\Ôx%& ec°¢å^;Û‘¦ »FÛ”IY*_S‰Euߟs;<�žf÷#ÿ8÷2OÒrƒÊŒ%§-o;<Œ²8¾zUÇ:xkî§�ÀÊ,|ðõ˜ýàKU.Îg¬òRÑŸ8Å&ð€ÌŸ9•×·­è¸4öí†{?}Cã2xíÆ/Ûv°óâƒ5ODY&Ù)ÏdÇnšÖo+XYUÿç]a}´øÌ“ê‡)öY?þcL€ 0&p*à€¯TZ냷 üÙ?Ã!'� .û|늋Î1Ñ€/jت‡�…àJé—©à°\ØÖ±.±¬Ã^èê셡ÇùNâ¼ò@&ܸ´Êʶ¨&·ŒŒ~¿É[&5²\ƒÞ¸ˆjÄQkÙ¼¾œ½Üº2 ÞM³¯6R©½==0èœs|åUןÔÿ ᾖ͸ªV¶“L;²©ÈD à ‡EtB·t„å7�4&‚ «Zá6ëµ R£ÞȽ(ìÇ“¸²Np_á².¶ÆtûªÐ¬09­3e¡ÊÿÛ¦0öƬŸã–m…ßÌõ<€p.<ÜÝ g ªÇj¬WÝO*à Ë®\ð˜ú€„3fÎý:¬~`�%nÛßÿ¢ùн ¯½I^;:î¹ö}¸…)+ñÚï‘k[žý/{Ó}V>ã–¼ ¿ýIºõÝû¿¨:Óà+Ȇʮ'`”)ôEþ€+�ÙAJýðEÙ0�ê÷m/.�çó× =½ƒà+ VŸ>Ü}>€saØP¢Pêô;/Á÷F|Ûî_SŸ‚½�O…ÿ[ó] ø²¹MÁ@¹GH œ�¬^˜;rœAÙ ÜB}È6Ö 10í- LóŽ…»ŸÌ…kfØíç ³òîÛs‡^nO^�k„9÷Êà³ °1ò’{¯è÷€¯ã Í"ÞXŠ�T‡ÁçÖÅz²ÏNKÿïßv½=]¸nÚPvŽOÛu¾™—Ýh½5 Y«!òØMp�èTuJážÚŽÀª…·_SbSRZAßeÀ×i«1Àú_áeç¢9Oÿ~uÃ%AIìãm[ẑ7¹ièªZF Ôâ-ð>ÔôþÑkpKGx,ë2ce°•5mpÇåž�m¿ÿØ¡•YP‹+Š}Õ¹„�QYT¹´¼Øçõ _4M2ò¤ðÕ¼é^¸òV'ai®|Í—õ�ÌKí7 !-ªæÂ…)Ø8Ô^_Z…>iç€|ãy"®¶ëÄ|�zÓZ1�ù‰ý*û¢kíKœxoņ¡@IDATÀMOkÂîõypÕ]ö`…UPr›\[Lþ}V}Ò>áþŸö÷¡R õ7ÊôéC´¼å×Å/ÓÅáû%´anT’ñߌ‡^ȱ¼©ÄzXcHur ßÎ9È Âéoûœ²tõÅŠÖÕ7À² ï—:÷ CCꩇ/Õ§Xr*†Í›òp|°ûM^Qüí®»,8-¿ ªæŽW—%ô«¼Tô'^áa™Sy)7·<ãÞ�ºÕ!uË=k}¡Þè*á©Ü»ÍÌ_‰|áô—5¸Õ,'ñh;íÕ½‰t<ýcŽà$ ø’0Þ~_Fʰ_F’¿g _þs\ÝÒýëû+,üÄ`[Éø’Ó»Áz'ͽÀþò—®‡~jû¸³^Ä̸¶QgÂY'�` ÞH°½îñPönE¾ øZV×?”ËŸÒ¿Þ�p×Ùc�y\�û®Æ�— îî…Óû>¤WF}§ýÀÏRºFã9¼ ݇è=!{� Ðà*xÏî�0óîáÓŸ? ¾týl¸#ã’lmšsôws\;qó—Ñ’è#¡eJa,5ì)ãž©ä ïç…Ö1,šö¿ûeû¼ž'·^˜鳯“ÇàhØ¥¤/Çߟ)�¤\ßv5cS ‘ä)ö¤<ßzž<Ïp Ûǰú<ÞyÖj|¦tƒóLÉÕ¯�c˜¯Ð}#ìøkµ)i£�ˆÓôxº¶.ž7ËUpuÕÂ/í²\ p]µ�}éõ–O™_´¶ß•o}Ï-©‡%ŸsŠ?®PžÉ>{¢i“ñ—ÂÛØñ™Ó±Åì‡ýßgâ·/_Á˜`Làä"Ð__�ìž�êzµ§äɰ¿er2tˆ—ׯ«VÙÿž©l°÷ÕŽÚ“:xïR•6f¹5ßù¨6ø/M”4tÄ)‡ìw�iðÁ…¨Y�뤗ûÅ;û{ä¬*Ìp¯q÷÷\ã•Ów�v# •%CTFMå¡;åeˆ²FF ¥‰à5颠d[œ:«ô´<¸åCTº²üt·žhm÷‹Ltor€QÕªäQŸõ"/MÕDñ¶VK.š.º]ZEi•DQ��N¶Crì³L™BóO�¯¡Š‹ýùn×Ñöa¯h{¯ZLrõBòš*Öïn³ÏÉóä_äÝZqÏDÍ7 ¯Q×tŠ3�sWˆ=$�ÊcOÝ W0àËÍû¥G§ºÇ1Æ92?ZŸ‰…QrDömãh}³×‰}(kûÑCQzëí{ò·©?MFªç¸…¨qÎÊ+R)²Ü²ÓI$mœ^("1ÚÍO¦ö£b™b/óÏ^!¶»í¢ÚGîiØ F¹r€X³»ËfþöóäøTQñžN£Ú�¶Õ¨EÏÛéQšNtÂI�ùRÓmÜ+ �x´ÖÕ »¼�:à£{J~ëå�¢ê «mï¾bÈ ÙkÄ.šoXV˜­3eáÊøîV¢£“EéÛÑíÐÖ²Éi«ñb~YƒÍ-¤î¿}¤'ZW‰v|O´÷sÿ½±õ>«¿º:4Zöû9âÕn}�ºþ�ç¹}ÛºŸ:׾íeRçL±1�W{ósN�'ˆyЇ&ë1iö¦ˆ+§’aã D†L±¥SåMÒŽ_)ö’:ª´{kWºi1�ÊÍ»|‰ÎÔÜã*�üÜ0wŒ•vÜÔûÄë]Xf×v1Óª?ÊP^{W­Ö»Ék-™¨ 0z‘¨óʉ\è˜æÊÙIò¿<ª~-»ËŒt0õ)ñ–7oü]^˜é2�mhµ»çÚw:ßU••¢ÿmkð·wüÆ.ãX+CŒƒv^ñÇÒŠ}�Çàw_Ý/ÍK³êœžU ¶IÛ¢µJä*{"H6”?C�+Eö8î['"#^¢l¦äìb§í§òzì2Nméï{ÿ€8Ö}@¼¼X3—:4ï©? |´ÎÉóôßÁú�"Sq”Ÿ7<"’k¶?”Eô1KÔvšé�uïó.×cÂ3o¾cåOÓáÊ`F™ÇºÛÄsw›2®ýK›{ÍÁš_¹eb@—{\Émæë|†¨m·å5Ó$.Ïû]¦-çÇ�¶5;™:ÞXæØù’Q–¶ÇI[R;=Üôamš>ˆpóÛV¬ý$é”7ů›U_´¥Ü¾–¾4Êfê¨/!þÖ3kµhuëGô9 /ü–j[.lý÷ÇéC´<ÊG·-‘¹Ÿ|¨øeÆi‹ôˆêC2þÛ~:žâØ�UäÑmlã†Ò<·¯BN±èpÚ½_Ú.}ñô7Z׬Õ5®î«¶-/Ðó`äOÚÜ8®Û…¶!>tqó¦eR}2®÷È©äÙ©°û–ºß9c1õ…ÝkÝ>¥e¢çb–—‚þÐ2ü¾Óú'ÜÊK¹é2H› —ü¨ùŽQ�®ï=ý5ß¡Ë�æÜv ýâÓPßÚõ),ߥ[¬Ÿ3Úê®í.Û–ú@ÇÓ¯ù�øs8ÏðÒ!Ó¯‰ëé'ûú§f}íü©Ïêëo!›ò'ë1™,sç!ìÑyãµëçÙí6.{‰¨v¸™õêô¤ëÂ4:_is=Ø`ûù�ïu¹ãD�^Ñ~àµÂ�£Ñºk–OúVÀx·?ì“QìIyè Ñç'Ý3:¿€ÏñÄ¢ººZÔÕÕ‰;vˆ�]ÀWÇ__vƒ½dàÖªþ,ª«ªD•ï¿—EUmƒèô‰|†¡zpçÉÇ«@F|¸Ð\SDŒË QXZ)š"¢µµUDšEUéRòÐ%]T$ø ƒYÔ ×òC�>Øß!Js퇘¶±›%J*ëE¤£Ct´6‰šòÕ$¾Õ@ áØF} }h“& ËjD“¬gã6QR@ÎIš:•áe2 `Ì7#_TÔ7Y|[›¶‰¢\úð._48íWSDäI×i·Uˆ¥9”�íä®Öa_˜a§“Œó‹+EcC½ó<|]Ãó n77à 'wV]µå7s¡X³y«x©¡NTT?/–-šuÍÊ:Éb“NèÒIisâ2Å€¯CµdâĬ’WÄ®C]bß{QQVHšT;Í/½×Ý/_õÅ£¼Õ¢)Òjédã¶r‘G�Éœ÷ATª­ VÛS«ƒéìþ��@k7ŠŠº±½¥Ylß× ^òkÇì VÀ›=QÞ-Šg*.ø9q®(ßû~å%s�ú­Ù×íL2wgãæ¬ÕowbºN¼am0ÚCʶ¸Vë Õ ˜¸PTìkµ b—°^§ü&þÝcäáˆñ°ƒLÂËk÷4¬3ê‹Ûfˆˆ{MXV |}¨ÌØm9U×î{Žt‹È¡6ñêËë ¦3ÊvÛíR÷“ øjï|M%9'0«L´ø µ�\¶n�š»Å'@ê°Ø0Ë�²ëœ-ÖU7‹½Ý‡EKW§xuëSF�gnlvó¨Ý8‡´Óqÿóoˆ]]=bo¤Q¬[’MÎÉòû'à«¥¹ÌÈwÊ’2QÛvP´ ¼»šß+Òrç‰Z+À�˜!·qs׊-µe}«ó xcw­øÅtÍ`ܒל:6‹™Š3~Žš¾R¼ÚÜ)Þê:(^¯.3¸HvnÀ˜é‡P f¯{ÍâòVg»Ø²q¹ÏX8GTvv¹ªà5f·‰îÙÚn\·¯ê÷š4c-ø¤mçú0?`’)*M”]F쟀<:J\Ye½² JD=Úfh 55ÔˆÕùÄF€]s«XùÔFQû—äW#^+/‹n'ÁÈY$½ÖbtÑ@);Ÿ{Åko6‹žÎ6ÑÓ²CªîDæ~ò¡â—©Êú ¯GT¬>œ ÿæ ø’ió‹µ�]_QDüjÔ †W÷ŒTÚÎÐo‹TRÿ*]Ul³îÒ?.öúÇô…Òæ ”Kõ”ò¥úDÛÜ+§â´?j®ûPZAbýÒÓwc—^´¬þº–9•—r£åyïÝKKpn§± Ç×2‘ïÞ?%39öÐûhø{7-ßû=ñ€/˜äy‘EÞc�@¤ãéט~â=¥ÕbgËnQÝbûƒÔôÌ"þ ôoÀW“­¤¾/m­oQþm¯ˆìÛ`،ּNIßxçî­bÖDÙÖŸHd68Û�dÒÏŒ´lÔi1�)ËÐ&z·SDÐßÛÕR'V.Ò/ÄájÓ¢Öy™ëÕµä8úÎåûÚy^‹gÚb®L˜ïŒ’ZËOL6àË;N„GýûªÖçøã]ôØ”àKÝLðy¨Z¨ÂãOÄl_¾Öõu™Sl;Šù0ÖÖ�¡ýðušŒÛÒ¿|ê°•æÇ7J:í@&8ܾ 6½Ú”¸g\ “¿÷OpIKÇ.x<ûR¸{³�(—wŸkm»F2ñûŠËç}ú*°7BHƒ’†ÖL‚l¹„lœ¿¬ÂJxì¶+â\eŸ¦Ë¨â„$Üqn>nüõ ü#ùq/òH ŒUëþö6ÃYW‚³â¯‘Êø‘UM�ÝÞœ�kŒíðpf8;Õg¢ô�Lt‰Ûè2Ì#…Èé6ÅÉXFܼÎþ•%%—@vv�qRn¹ùoGŸ�éw[ÇýÙËe£õžéniK¡©êš |]!Ì/jKGuôà_ž†ÛÇæØ[‰©ƒ�Ÿ“¡¸¡&}i(¹ÂÜ~o×K3à|rV~¥[Ù%»¥c2ùíXu\ÿ£g=¥ëŸÓÝ—m¾ Ø»¤Ù'ny"EÿµD¶Ne£íë§ ó }¦= xÓº¿Óò ê…€»9æòÉM›nK¢ï9wˆ3N‡}›–ÀÕ7ê­)Tî�Ÿ«ÏÝ _ ;Atï„{Îkoᘷ½(­ƒŸOù¢{Åß°>c3ìm݃_æ¿�;¯qö ¥Û’ëçW·Á�W †§oÿ)Û ·ÃHFHVÑ_i™ùªDÞzM+©…û§Ê-Lñ/$+ÚðÁü‡ßþ ½M°ü_Óàþ?Z%ÿ/{ ìzršÛ׎‡îxÆ è;ÓUVYqxú¦óaéb€?Ÿü>r€__?æÛ;�Xçlm‡;¿á³olï^øUæep?¹Ö'C\„p-ìz<‡ô‘Vxäú°8^:+³L(ïü\i ]¤ãW® £=öì\Ÿûc먻U¢s;g_¿égžÑ?ªí„ï�¶÷|<Üôø—´í­t¢/%G²aKç0ÆbßþãpÅ¿Ì#烿R9wàv�ßv¶ƒôK1mE|ñ…a>iK\éËÚJR·8áde2^í~ÌØÊ¨·î¸øªÙÖYœ„Åmâ³g ™è²ÿ¸t²ã �WbcióæàÊì¥Fñ~?Šªšà–4[+z›7÷®Ìv· ó»Þ>†[AGp+h �ÚF�R¸§‡´#R±é}Ï­·²kÜÑ_¬-OsŽ÷µÃºŸL�Ûׯ·‰­×äÁö aŒ§Sîøï[à+s=ºHãÈÚªfÈùŠ“Aw|÷‰@oûÆÅp+”=} Üø}³O¯ýK¦-…ó¯ú‰u¹ÿ–�Z&ÿów Ìr£ð x­}=\%ûuHyýs¾ÿÝ;Í:8¿h_"T4Áì±È£§òF¤;þ ¹Àó5·¸–dŽ4ކ±q¨þDÙMÆ0H·œ/ Ørž R‡¶öµÊQ£'œï9…%ð¥³!ŸªŠµÕjü}¤»äq£OêLh_ñŽgaê/s¦ Ü’œ>4¸áñ8¾Eÿûu´ŽQmâ çKH= í¿¡^çâVžÏÈÝ9ã #x)1mépm—À=%fë&ÛÇá™^�›fÃpë²øåÒ6¤zJùmSN=ÐÒ|¥(9«·Áò›.‰#¼Ïéxå…ÔŸ’<‡èÖ;žSÞŸ„9­·ÁÍHçÞ�žûŸ�Í–~öÏ|‡Q¼ç‡ÚÒQmçN}kÏ¥ÖOºe¼uÀ»ÕàqôkÞDßü:¯o>¦vÕÝ ƒvà–“WØ[NúûEÝðúƒ?µnีâ{¸µ¢cûÕS£[úçë\Ù�åWŽ„ûw¨”Óá¥÷�QNon¸®ËþouÒÿsÌ\xéO‹Ý4Þ-ý|X™Q¢¾ûƒumðý1Îþñ¸�ý­ç]moÙî+Ít(.û<Üzã½ÆÙµ-¸uÕÙÆ±¨qúm¸q4ªÏ�øã�• ¤ýÞ^¸ ÞJ`^'¯´|ÓÞú+þ8ã~î¡bü¤þ„qBýHeþòÄËtËÈ÷cÏŽ¥‰éJ?Ï"RÇâµ;µýî/ú¾í¹o PaêOtŸPY•vA>Ÿº6Ü¿]i�¨Í£Ê úÔl(ûàzæ@õâo�TÏpZ¶.†/ß¼<¨ŠÆqÜif_m[’òD"íAÇ0Ê…ò‚�}#üøß_3*ø£ VáVÍùU¸o�ä�¾¸ñ| �uÕ> —^_€à xEÀ\V˜¾hÌùʺ"äF/›ëÉ�æCßȳVÈjÅ·å D†¹î¼è¼ ˜–ž#ŠÊÝ:ÑŽÆŒTé•Ãü·�l«Ýˆ~¿­#¢¬(Ïx ;� Ä7Rq+G|S>Ù-å, bužçí+Ï,Q\U�K<«syb›w)b|û=Y™è…å•¢ØX•CÕ'K¬®Ðox«¶j­/¹tµ%§þé9¢ÒZ¾·Iå�U"ð¼dŸ=¶Qk�ù–¯ÌÛX%.ùº¦Î×'’÷€³¥£»b¾qz¨Y¬_»DLšèðs¸¸ú1qª˜_²ÕY}I¿¡j¯œ„o²f;épû;¿-÷‘“¦¬µß6•i_-Ñ«‡=X§V ŸŸ|[·ôÑY¶NuÀU¯ð­bYæ®Ú5æ 7ßY•�ÞÓ-ˆŠP'”NÑÏúŠÕ"ÇG¿äö°¹…e¢)j Á·i²vYÎV`Q×ø´¡s�\áËnƒ^±ïm|#xÙ,s«6ƒ®,”=K¬|±–¬ìåiËC»ñ­bÝ&nûc>£2çŠõ j6š®[TxVSéfá›Å{p+Mµ�È,µ"•£{Õe £Új™¥©è•ÍóWš¦˜èªâ)?ËœJäm¼ù݂՞º5n~v==ò9\,=^;×å¦xZŸcP—qõºè~B÷'ÇÖýw»Ì-åÊO¯o «jMðß‚ÑYñkK!]í*[”»[*ª­éçA±qÍ<ÿ:�Æ­q•*¿­Û»#bå\sëA‹ÓèlñëÚf±q¡:7Oèí$qÅ­©N¿›joŸ¨VµRŸoÕ=å¶Õ”5Û�U­ä5{¶ˆÙ“õª\´�ÆM¿O”ï>•æ­æ×Ä‚éJïX;FL[¸V¼îÃè�WžŠ^Y õxÊB\]¬Aoë8sƒÚîRrEž+h[©ò�å{‹Ê]ÕkMÞÎV’Š�ü¤[sê•Çt»µl{Üå„“d¾ã"#}¿ã[ 9ª_†í<K#ÛÊD^FôÊN² ¥-PQ=¾·6Tˆ‚eË(–ê3Mää‰môíD´t�V›÷˜l3Å·_bØŽqíÿûÓQgKGµõ¡ül®Úè³’—bbÂòÄSå5¢‡lãHÓ7>õ#GײÄË»wˆgî&+w)ýÁ•ÁÊþ½µbÏ›¿s¼+�aš ·/µûäJbÍbíí¦í·²&"Ö<âê÷ZüMå‘ßßX{«>ÿ—Xçq JgKG™.Œ<¾­—~ýi[I¾+“— Ÿ¡µW³£+Tè6HËÈ¥5æÛÏ´ŒdmœšÕº?»©µ¦˜ø$i¢´A­Æå¯Wª¯—ÒÕ…•üèÇàêºòš¦JsÅ'Û�?F´Ö¬vÙùm˜lý-ycô¡”ú¦e&ïWÄ/3{r.„…öߨžU(*åÊ>þuVÞjÑågÚ2'ßvñõE¶o¬þÖÑX�÷¥ŸäW׫lj¥yΘ“Fýãøåéi¬þKN»_IN "ßåšžøV«ŽO¢ó‰ÍÅîáÇ!ZŽ÷{æ ÷ yïÆ± ºã„åßáj¡Mûñ>ªü9Üz‰ne˘|_õÖ�þn?öúîÚ§¡¾5õcô÷6í«Kù3}üõãåת÷dRfºüø~QY…kzÔ–�º~¦?õêZíËêùó7íÛ[�UqGÍ{Þõ­å5µÕëÄ´‰ù--f<ú¼Øåún*ÿø>¬*{ÏîçŬÌ蕹ä½{ÜÌ%¸‚—šQy£¿¿ïy1ÃGy}ÅÛò:lë™æÖŽ…Õ- ÙçñƉäÇQrÏð'¬•\T¿‰kÿ‡éC˜&”½`˽­¬HdùÍëàZ|æÁý0LŸ!åáÜMe«©·^öü›ù°°°°œì:À+|¡…:PñWø:>’õöô@÷ûïCo_ 4†œ;†�C—Ö9>åæÚ×íí O^0h r. v L�؉ޮvh;Ѓ‚A˜ç…Ãã¬D@³MB&óm�®t†åôö@g—ÃxÈP>|XÌútµ·@ï ¡0¨¯�;Ûì}æwøÀ¸ºÍó•Úç{tuvÃ`\ZîèÑÁ0Ô�ku¥¤Ä—f„ß�œwÈ•¾üþw€®÷z¡ÏÒWÔ�ó.€ó‡ ¾ú ïXïø[G/ =wö»AðÉO]àч>èéîµôÿ¼ÓQ_‰—cRç{{º ë}›!\x!xT,©ü‚.î;ëpìL¯‚bÝ`_øÀ.GtÖvÁui`ƽpðÀèþG‰£XÔ�Ï|*Î+ÕØ—Þí8àŽsÃ>ý©ÄÊö:Ø7Xv”ó\8'¹Tƒwë�4«D¥ë놷[ÉX�|οǭXé“Ðýóá 8£8èï´ÓàÈYç�=>Çe�ÛöKµ³úçYC΋_g¼ôð�Vëþ3ï?ƒ1M\}í'é{°ÜxßTáÁƒÎ‚¡ØÏâê0êLÚݽÀQŸÎb§‹Ý?{áíÈß�Ë`,g–s–“@%PZÞù† ‡ãŒ…ç ñfØ/Ì 9+ì¥~½û0Lajß Ã‡àƒ¿Áˆkó!ߊÜf…¯ªq<.éA›Eµ�´ÍÎ6,±¶ëî†÷{åø*í§!xŸ–¤�`×&¥{zH;"ÇìOÆg: Ÿî9¨~¢þèê‚ðþ"íPy:oØpjª–º:ögo7´è¶�·ª!ð÷#†ãÿƒÿ´µÀƒ‡Âࣶíw�§Ð>̯ó„v䉸%#ÏQ!àCf�È_/Ú Çìûê`¬‹ï˜„íÐ…íÐ-+,ïóç^�°Ý~¢lœ˜UÅ:¶t¢�‡m(í¼h»m¡\ÕúŒ3°þ±´"f)¾'“¯ò}È·à ƒ't<ð‘„…ößpåk…/Y4®ÎÁÕp­…;;áŽÅÒ—ŠcȰ:mòm穯ßÏ8ý­·«ºÐç�öø�¡Ã`ø°þÕG?‘|�Å‘³¯e3Lü²³šeN t,ψmoúBÆ)Ϻ2 ý!9Çýz|™÷�­vÖÍÂaÔ‰«Ö\f¯xŽ«ÌEp•9ßY�~ê«G‡ž :#.‡P`›ô¿_Óßyï÷}8?rN<_&”àÇ7�ÁA†]ôÙ~óí{´A×~Ô'¼mK{tèßÅ÷%¶F í™AÒž9ïS8WcQÒž9,UôÌ¡pÞ¡CöãìD%Ðo�Ë8šˆlòš0}딊½Ðƒcøû'Á~üæ/…}]j2¥0–F‹u$”Ÿ's £cQ¥÷ï�ÐuIZŒþ±WtŒH¨ÎñëyR=ÃÁûrgg—žgŽþ®9äǬu¿�aaúFŠãoÌŠ ÀÉ0}1Ùq2´¿äåqœllo1ê÷IÕg”Püɘ`Là课>v[:öGÛ TÀWÈÎyh¦ì·µ¥¾–¿ù8væ`è; gù>��Y§ûð”$!·s”Û:òHš|âýà´8}Ÿ8 *}"éì9Á©Oàð_×Á?^q»]‘ÉkaïÆãæiâCüÁغx"ÜŒ[X'¼ ö©�†k‡À ö:ƒ¾ø¯ô¡‰ÒÓ—h´Wÿ”ɹ0�þ&Ú øêoù>ÞùõÀÆÜ0ÓÙAWÃÀm�}C–>–˜Zª×ÃÊ?üì|åà[”Û&I ½ ëá¢ô»l6[Æö'¸ŸGÏ9³?³ä¼>¢ÎÀ¨¯Aôï‹mQT\­@àdKO@•¹&À˜@RBûKI•Â3&À˜`ýE€¾ú‹dˆ|8à+´“0 ÀýÓ(2PH }œÿ> “ 2pOðñH†€œü—úïOà*_}¸b£üä¿� �>xûKáGWÿ;¼æTùþÚƒðÃÑæ*ƒ÷À‡{þ|úÊ™xUTFJ@.¸ÉL@8 ¾>ññ61úEd˜W÷Ñ$V÷ê—R9&ÐÿBûoðÕÿ�Arìëi‡ç~5n]^eÍ(ªn1¼Éå˯-›ï…/g?æÔ= Jk~F·V÷êܽæ_u38±r�[¼ –d^rÜ9É€/øÅL ˆ€|©G¾Ø¸B(ÿ1�“�ÀÉ8–ž \X&À˜€"Ú_Rð'`L€ 0&pB pÀ× ÅmÆ_&�SõÀýÓrV ‡œ,–Kq| ÿ> Á^ªÙü·vTgù“ ˜á6Ž1·r4/Çí_Ï€¾3ÏÆ ¯�çXáÁñþÙ ¿½í|øñ³Š£n�-÷^G¶v0èðpú1Ü®·v7uœwŒüÜ03!ÿúØà ¯ÔT@.ÀxWö:ÆÏjSÉ©O ¡ý7ðk»¼“¢–§Ž½»qUª«œU©\±Ó¡´á·ðÍ “Ø+ÈMûQþÒ§§AA­c¤AþGþÒò¡¡j.\H·¯øÆÑ³9èë¸ñ=Å3–«—Æm�ã­ä|ŠW“Å?圄cé)Ç�fLà£L ´¿ôQ†ÂucL€ 0&pà€¯lø@øýXtݪL¸6ß~ ¹ ¢ f�å‡Ì©à•o8HþÃ`Ž�ø*>§}ø¡µ}ãéG�Áér�¤�Пl?Ù–rÕ6q:æ|„š¶_ª"'þå¿3P÷ÃmazŽƒáC þ’`õ±¢_ Ÿr™€5ÿôi˜¿S >iáoáÑüïX+}œö!êþ;½ï(Èíù� $B@šƒÐ¶� Šò�)>1Û%½úpE®�c½â3ã+N ¡ý·ž:Èq-Xž_ÚRhªºØóK½Í{êVÁˆkóIFPR³2FòR�ŠþÚÛëþS¸ë±Íúù–UP ?΄+§üxÛÿãÕxI“|ü¾¢Ýpºô÷pŽãŒ#ñWqþøâŸNÒ±ô¤`ÃB0&ð±'Ú_úØ“cL€ 0&À†| w«Tø@øýXtog3ìÜ÷.æ8.} Ò�™sVL€ 0&À>¦:›`ß»‡ðö:.üû/Àç†óƒß�©*pµ™`ýJ ¼ÿÖ Íu;á]\Trðùø•ÿõ\¡³á¯ûà�ÅõBøÂÈÏñ6Ž `íëé„HëßལgÃÙGÂA8.þÂe0ü^-|| `LÀ"Àc)+`L š@x):/>˜`L€ ðuü–À_�hø`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`>8àËʉ:Ä_'Š4—Ø`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À>8àkÛ‘¾>͘`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&ÀNAð5€�Æ_Ÿ‹fL€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`§ �“&àkö¿9ñ¥&ò† ¬ ¦N�šZFœš 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0���‡ÿ «žÿõïg&Uß'Ÿ|FŽ gŸ}6œ~úépšÀ¿¤rp.þåS‡C ¦¬“-ÍêÕ«-‘fΜy²‰Æò0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&poÅ_ýИðÕ9 &À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&ð1"À_ØØð5€ð¹h&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&p à€¯l4ø@ø\4`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜8 pÀ×6| |.š 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ œ‚8àk�¾>͘`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&ÀNAð5€�Æ_Ÿ‹fL€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`§ øÀF〯„ÏE3&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0�S�| `£qÀ×Â碙`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜À)H€¾°Ñ8àkásÑL€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`Là$À_Øhð5€ð¹h&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&p à€¯l4ø@ø\4`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜8 pÀ×6| |.š 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ œ‚8àk�¾>͘`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&ÀNAð5€�Æ_Ÿ‹fL€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`§ øÀF〯„ÏE3&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0�S�| `£qÀ×Â碙`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜À)H€¾°Ñ8àkásÑL€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`Là$À_Øhð5€ð¹h&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&p à€¯l4ø@ø\4`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜8 pÀ×6| |.š 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ œ‚8àkíT ø:tä0ìlûÿÙ{øºª2ßÿ¡o´Ð‹X (¥NÑ­Œ£ƒ/3b¼Êx}!Ì\Ç?ùÏ�q„1wæF¹ñ3:ÿš.Ô0ãDF#2QlƒcPšBÓÚth*MKZš¶IiR’6i×í}ÎÞûY{¯µ_Ö9'§Iù|Ú³ßÖZÏó]ÏzÝÏ^kmÞ½ƒ6í ¡±‘ R›½I¿êô3)÷š×ÒšåÉß×Ñé§.œ½ÊB3+pø²ÂVš@3Áák÷˨î‘{iï¡a:}É:ý¬³èÔ…‹J±(Ž™ ±‘ƒtxl”Î9ý ºûº?¥K—)Ïà@@@@@@@@@@@@@@@@àä&‡¯ æÿLpøjøq+uýö7tÕ|�Î½à‚ Ò:y’Þ¿g7ýç�~DW^p }éCŸ>y‡¦                ‰à𕈨|̇¯[¾×Lƒb‚ª>òш)Úõèh`ÏZüækè-ouùMkÌè¹/~�zŸ'º¬þÊ­>sZS'öÔ£�Ò™GŽÑ}Ÿ¸%| ç                '18|U0óg¦Ã×aúÅ5o¤ïþœhÕ]?¢›?·¦‚3$=q€vtý‚öÏ ½õÝEßþtËê?Ï_ÿÐ?Ò?þûÒ©‘§¦ï¾¦�5R�™D_Ì­™êðõ«�¾‘¾ó(Qî«?¢Ú›f†Ãבg[èsoûÑš¿§Æg?M§…ó}äºïÜ�Ñ&yýʯÿˆþ¨¶²zÁá+œA8pÀá«‚vp29|Ù·—îÝG㇉œ¹„ÎzíEtÚÂø/ÓÞ¾ßÒøQ¢¹ Ñâó^Cg¾æLš r|â0½2r�&^™"š?�æ/:‹Î\vºòÔqy땞ª§ãðUOÿðÌÿKK¦ŽÐ1šKóÎóŸ=>v€^�GKe:º¿ô:LÑ䄌}á©®¼ÇGöÒ¾Rw©‹£û9—\D§Éê’"8|i±à"€€€€€€€€€€€€€€€œôàðUA8)¾Æ¶Óº¿ø jxk„ô{ÿï÷éÚ?¾,âĵûÑ{é®�ÞyžèST?ú%Z.ÅÆžýúÉ�ߢ'}:ú܇>KõÜLË—Mný}6÷¹è3î•÷Ò_�ÜO¯]ìœÈ­*åÊeß•+—Õ<ûzûæ4–Q‡#›[és—ý-}øñÓŠÍߢ¯}öáPúk©vë”[ÉÒ=‡¯œ‚€€€€€€€€€€€€€€€¸àðUAC˜õ_SôÃEzŒßõªz3Ñó÷|Ÿv®å¾ú}¹-äeÞ´÷_ÿýà �ƒÔ•7þ ÑK[è×±ëO¨aò’~\4òhÝñÑo­¦Uº�è…ŸÒ¶Í…KŸú5=ôtlk»tøºÅ�_=P¾¼­*¯ûõFªº¬°Ê—…žÃOkÕ‡>"åû~ ß»äÖ’ë4[KÁá‹ÓÃ1€€€€€€€€€€€€€€€€€G_‰ üÎv‡/î¼õÞïþ˜ª?º:Oyb�žüÔïÒ#r5-¢µT7ô¯´ÒñâÛLßZz-=ã\~ןS}Ûgå*]…½åv‹{÷½zå9Î]ùìVzòŸ7ÓÊÿñn:Å9…U¦hÇ}wÐWþÂqûsúûñÛèU^ð_¶t”ŽVw9ŽVSrŸGù7gž··âaÒ9|eÖAÆ©8|}èïéön W»z¦M·†îktV%{/Ý&W»Ð]]Ì‘DýƒÃ—Êg                ypøª %Ìn‡¯`‹DºQ®¶õ�?P·nÜ÷Kºkù§Ü•¾~÷»?§O|ô"ÅQê�·öÓ[WzÎX2iû÷è¦ÕÎŽ|õ.æ„õ¡/Ò?þûõtj$J�ÃWvœh‡¯�H§®R�ºF~I÷œû)Ú&Ÿ«Ù$·Ž\­ßÖ_‘ ÂI_4ƒÙíðµ—~|ÙÛé1¹Åâÿ}àݯ‘œ©r_ý‘ÜÖq ½ü³{èö÷}•hÍgéž½™ ›*†Â§Gv>KÏýÛSôâo_ /�ÑÂ%ˈF7Èí·Ê‡ _ï’_ëÒ:|e×Á‘ÎwøúÐ?Jç²?T�Ë&ä*fKò«˜)[Gj¹Gpø Á)€€€€€€€€€€€€€€€€€K_4„Yíð55@?\ô.ú©äûÁŸõÐÞYØŠÑ笨å9|íúÚ�ôåÏÊÆU¸üÀ´ÿÑ/Ó>ú�àBø(ä4æ;aeqø²ÐÁ#6-8|…s ç                Àá+¬R?:«¾h/­“+|µË¾®üú�é�jW‡ð+|­’+|Ýì¬ðõ¸\áëƒr…/¹:×m£÷Ó… CA¼Ó±gé¾¥¡Mò|ÕÍÿHÿÜ{éìe§Ó\y>úôtû»ïŠ8�Å:a¹ñhÁÊ[Ùup¢ŠM _.mü                `G_vÜJjÆ;|IG®Úˆ#—‡&p ¢wý=5®û4�æÝr~Gž¡{Îým“‡UÿþŸt݇Î¥äµËUÁ®‰¬ ædUǰ—ÿ²t“+…Vòò�°tÛ,º±ò_Áµ´:(ò…dp“�׋ÿ�€€€€€€€€€€€€€€€Ø€Ã—·’„šé_«þ¦‰>þé5tl|2Âcî9Ò‚õ_¡;>úM÷^¨æsïÊ;}�m§uô{Ôþ¨së½ô×#÷ÓkËñÍrå®kÝ•»ˆÖÒgžý:½eM~+ÈÉ}Ûiã¼HoøãwÑÜÍ­ô¹ËþÖ�·êÛ?¢êO¬¡ùS‡i÷ÿF}ð ´Û¹ÚÒwø¢�Ð_ý½v)Ñ+{ÐüלCóݘç®ÀáKú¥=Ú�M—Ÿ¾\²ø@@@@@@@@@@@@@@@@ tàðU:–™cšé_q /¿ëûTÿ¹å´î¹­ãϽ'WSîCgѦGŸö.Ðï~»“>ñ‰•þù®ûþоüß÷ÏiÍZÊ�s�6ý|«{íãÏþ†Þ¹z?=²è]ôdð”æèST?ú%Z^Ørrë÷賹Ϟ[M«Öl¥mr»ÉÀ¹KïðEÎÖ”uˆuøbNmAÚQñŸzôQ:óÈ1ºï·Doâ €€€€€€€€€€€€€€€€ÀIK_ÌúÙìðuå×DT»†hj/­ÿßÿ‡jdN\.óµtÝc_¤ª÷Î^ù¬˜¢ÿúUú—¾‘_©‹åϪOÕÓÞýZ¾tMîy†~xÃÇèIß™Œ(wóé£_üï´ïoßH߸çSt»tøzuÁá‹èeZÿ秇îÏ;Žå£]M~ìºæ}çËÓÀáëã¿ÞHï¼ìÌ åŒ:ø_¡UÆòÒ�/û]zlójªÝÞN¹§é°#8|18ð ÀáËG1ý3ÓáË’ÓÄËôòÐÍ?{!MŽ-yÍ™4'.ª©#4¶o?M¼2EsO[H§-=‡N]8/brì0‘¼|œNe÷§èøÔ<šy|ŠÆv 9ie§–U‡pø çpøÊ �‚€€€€€€€€€€€€€€€ÀID_Ìì“Êá«‚œgbÒpøš‰¹™A@@@@@@@@@@@@@@@ üàðU~ÆÆf‚Ã×gÿý^zþÐ>zß§®§9sb×ä2ê‰Ù!è§ÿú¯tÁ‚Åô��ÿe¶Àx@@@@@@@@@@@@@@@@`V€ÃW³w&8|=µ}3ÝþèCtÆÒ¥´ì‚óéÌs^E O;­‚ÔfoÒGÆÇéà�ý´pPþ ;>p=]³ú²Ù«04ÈL_™‘•.ÀLpør´í~¡�¾ßûKêÙ¹�&�M•bŠ˜?w]vá%T½f-]}ÉšÈ}\8¹ Àá«‚ù?S¾1Ä                ÓL_Ó œ'‡/NÃîøÐÄ+´mß =?4Hÿµ÷EêÙµ�®¼èõtãU¿ïFøÀ/BOïè£+.\E¯õôúeçÓëÏ=ŸÎ\tº]‚                $‡¯ Ÿ©_Ç… !ÿù¿äœ§ãÇ“¿SÇ�ÑÔ1ùÏù=.Ï�MåÝs~O=ž”aŽÂL¸çòúd!ìá#´ìe’ÿœ_GŽß‘Ž\«_}¡ü·‚ÞðšôªÓÏPrõÀáC´å¥�®CØÖ½»ÈùçȾlñ™ôªÅg¸¿KN=�æÍ�Kóæ8ÿæäýsyM9.ÜwžU®³ðsç©qÉgO9åš#ÿ©¿sÜkŠÀ88|ÀLÇår;|�O¡}£ŽsÔAÚ;z�öI©—Ç“ãLå8W9¿GÇ*yìüæ¯Ë_é\59U8wŽ Ï9¿Î³ÎŸâ´DŽ“t\šs Í•¿®Ó”ï%Ï]ç§ðõ¹4_>3×u°Ê;áòçsä=ÇajŽ{î<—wÄšK§�ºP:h�!�ºÎ¤s—œEK.rRÏœ]ÎÊ`ŽÃ˜Ãd¿t;2ïœ&õ>&�×&�; NmŽš¼žwlãÇž“›s/xVq’ó�æŽK§5’Œ>ó\& Ýå¿Ro‡CþŸæØ{~Þ<:uÞ×ÑmÙÉeñY.›³O["ùÍÉÌ@@@@@@@@@@@@@@@@N\pøª`Þ”Úákçð�ÜÒ°Ÿ~³g€6ïÙAÃÒ‘ÉqŠZVprŽÏ’[r"ǹˆŸ»ÇÒñj¾t"rŽ]ç#yî=ç¬hå¬R…¿Òpð¦¤3™ó›wÂsœñòÎv7[Wî@IDATyG¼Ð±ûlþyçþÄäQ×ymH:øí“~CÒÁÏqb[¹l9­yÍkiÍò‹è­¾žN—sø˜¹àðUÁ¼+•×ãÜÓü‹Ñs/þ–®¾d�ëàó†óVÐò³Î±Zýª‚H�t ™š¤ç‡©Ong¹A:öíÝI5Wþ}äÍW¹+¦•0)D                0Màð5M uÉ”ÂákT®âô'ßù ]³úrú“µïsWåÒ¥…k ðâÁýôÿ.]tö¹të5�H_Ì´R8|½thX®à´‹Þýú7WP$=S>:Aë¶>K~Ó;fŠÈ�@@@@@@@@@@@@@@@@€€Ãƒ1݇¥pøšn™‘€€€€€€€€€€€€€€€€€@åÀá«rì©_Bê3IÇå?AÇ„s†¿“•À)Rñy§œBóiÍ#ç                 3�¾*˜ƒ¥vø:*½^StL:{á8�…ÒéëŒSæÉÿáøÅ¹à@@@@@@@@@@@@@@@f8|U0ÇJéðuD:{�ˆÉ jS|ÒS#»¨góNÑ|ºà²·Ñù‹‹�1æJg¯sNY �¾’ÿ¦FvR÷æùà|ºè²µ´y‘ -ñ‰)Ú¹¡›Kªg­¤µ¹å‰!Š`‚¶>ý í“UÃô¥Y¼Ôˆád#;us|b7=ýÌv¹B'ѲÕWÒêe O6Cˆè‹¶(‚$rá„f45FÛûž§}‡�-X@Ë/|­˜mv}2豺ô&vo¥g¶ï“æÓÊ+×ÒrTkéá9O¢]ÈÆë„|z¶ôq*1Ž)&Cgš¼&]+c?»7=MÛÊééËéÊËWÒ‰\uOì“íÌV´3& š©×gBÿ¶7S­«ÒrW¦^¯´Ö©ÓGß75*Óƒ'Bý9½õãÌ,Sc»·Óó;÷‘œ)¡²¿õ†ÜŠº¿e²7ûë³¥¯ž'Pj›/u|iò©i¦‘ Ïd!03ëÃ,Îìg‹Èô�fvÖO£ôpø*ìÉÑ!Ú¾í·4¸˜OLÉ}ôæÑé§ŸMç¿öbZyѹò‡þ/�Ã×mxâ4${€g­z;­]¹”¦F¶RׯvÈNázÃ;ßCJgœ}b/m|â×´ßyS|„è¼w¼‡.]6OŸpáêà†'éù}G¥#È%´öíËmÿ*ûwxÃ×é’·þµ+ÄíÝ{è/Þ¾´D�Ц'žqÙÌ_v)½óò ÍñŽý–~ñŸý4édÚØzýûªèüy†Ó¬‰öÎ"šKgÊ•¾’þÆ6ÜCK®¸Å}¬±{˜n[[ª¼HJy6ߣ{Þ´„nÙ$uÌ5ÑpïÍTvªcOÓ»—¼ƒžt°NWšNZ%ý“ƒÀ§»hËAÇaà\zû{./?·’Ê�È Ì ;MÔ2ñ^ïæ»©÷¶µ‰afûœ Ú"}nŸ¨Œ¦v?A×�ÿ{ôC&öl³ë“AG–}V‡îy7]qË“nX”áìyùžmå';�bÖôq*0Ž)*Ëgš¼e+b?ŒUQ÷èÏhí üñÚƒíÌðË3!_g‚Œ3Ü f§ø©×gJô}‹Ï«¡nšVf\™š¢'¾|ýÞß(3%²¿Õ{B÷·Š·Ìp ¬¿9cßW:•ÚæK_ ©ù¨iš¥Á+­“}²-(2"}"~åúDYÈ‹Ï:k9­xÝkiùÒð¿ˆüAÿÈh¸"P*‡/–ÿðí áü›™GÅóO="î½÷^ó¿;MiÕóÂiozG»E¹{4 9Ñï^êjpöltÿÉ—'bLL‰=‡ºÄU…kî½ê¯‰þãb�ñß~qg.å¾"¶Ÿ‹‹Ãî^ÿŽõâ?ïÝ{*òõoüš¯×�ë÷(÷Ìz¤��³‰Óõ•�âFÎ�nݯ¤ˆÙÅ¡ ç1qܳ.ãïho³ŸM=ÃÆçp# �QÑR](sÕÍb4KPÛgG{üúC:|‰™™“£¢É««¨Jt‡À�ôŠ®®nÑ?4nK ᦉ€1¯f…�‘×»ÕM=ÅG8cb½ÝÝ¢»§_„K1gr²·E¦òsb2mµ…öŽõ«jZzgŒU& :3u4ÙQ²¾qO˜ËpOS•ߟtÆ,øËF€—ï“«]ÈÆéÄxÚPf\Ç ‡¹Lû8ÆÍX“î´1”§~4Ôÿ1e*­¼ÓùÜd«ßoñÞíÕŠÞðdØt UÖ´ ùÆû›ÓÖÇ-Ÿ¢¥¶ùRÇ—FóJ¤™F.<“�@l}h*‹â�{4…C\ðÈ=_PWF白{UµM¢÷DŸrŒÍŸå‰Õ?*³-)šã$+[«o}ë[¢[¾ŸÛ¸q£Ø´i“8)¾vuÿ›êèõ@«hì1ñHëêõ{"F49“Êá‹Mòyý¼€;“ZÃÇ�Š=¯t‹ë “�—~oüÁ¶§©ýânßù$É9¬”NOcâÁ[ò•ó¥�]Š|esøblÈä÷Êq“ïT"åËÝ!º�–Rï'®qqLc�ꥰ�©wqfG€½x¨š&‡/1)úzEoo¯è8Ñ{=&ªŒ[ä¥Ã¤h¯Ë×'žC¬)\¯4�¸¼š vZ<_^ïzí}ñ±žø1L¶&¼4�p>.d ¹üp»9q^tŽŠf¯�I9ÑÚ;tâbf g¢Žf;ʬ> W†'‡Ü>HooŸžd�p˜Š/ß'S»� Î ö�¹̬>ŽYÖŸ¶qŒfy’  2ò&I•ù>› ¢iãÎØEÆ^ñØçW|¼qwñr*ŽÎ̽gê?TÂÆLa{&2¸OÀÔ/(O?=^–ï.ú¾Å物þ,>æô1”£~4×ÿ¦2•^Þé|’Ûx®¶uÖ�‘ÍùÆú›ÓÖÇ-_N—ÚæK_Í+‘f¹ðLæúÐ\³Äó,·zsW¼¾Ë<_Íâ󜺒«E× =ýlΟ²î-ÎÒ㛦\÷ËnKåü$‰_¶=ö¼xˆ­ìµnón¹ÎVð7¶«G½¿},¸Y8*•Ã×þ�×[ù¹ÎK׊Ç™�˜ÃWÕt:|½ n+8V½¿yýô;|ét=ºMÜVÅ<„g±³—³BØaÅR#fé^à�HæY%®ò¯Wä`f¦º_MF²A`ä¥Ã h(Ô'Õͳiå˜é§\þ‘WIŒy½[éÎ{’¬¥¼?Ôé­ZZ#zB_5r&'w[d.?'$£É>Që¯HÒY¹­”öS±¸f¤Žf;*†c\.&^„‚—ï“©]˜‰y?[Ê�YÖŸÆqŒYž$+©Œ¼IRe¾Ï'º§íec{Åk`Ÿ_ññÆÝÅË©8:³ï^%lÌD¶g"ƒëvÊÓO·“¥r¡Ð÷­ûR¦\ŽúñDªÿ‹aÕ×Zë¯ðÕ<{—õò™ó�õ7§qlá VâƒRÛ|©ãK£n%ÒL#ž) sY,Mü‚�[½¹+Þ¦gžÓgñQU“pü¸&''•ãâ«­Qä¼ùgç·¶mVÎAs–ßå\æhÊnK™%BN T_§8‘JG£Ì¶{JfN¨Äo{œZ¶#ëyk©¶úM‘ôþ�yú%÷úÂßy?ýÑ».Rž¹ï¾ûÜóÚZùZÌô7¶�>¼ä rvö–…™Úo¾œÆ6ý3-yÓŸ¹!ZûÇéÏ¥£=ô—§½ƒ ÇsË÷h×?]KóÂ×iŒ¾ûß_EuNÄU_£þ'n¤Ó#ÏÙ÷_ôL×sôÛý‡èÔSÒ‚%KiùëÞ@«ßt1�ŽtbõoÛK“t]œ»˜¦v>K¿øÏÍtðѹW|€.?s”öíy†þæL¿tÒª½Ÿžºõm49)Ÿ_}!MmºŸ.yóM®wná½KÏl"ºî¡ÿûž×Ñß=Yx8w+=õ«;é’˜m31‘ÑØþ_4ôÊ$-:çzíò)ÚôÄ“´eçÑ©Ò5«¢sÇ##»èùÍ}Ôÿâ^:*¹9¼/zý›é�RçS=}t¿cû¨ï7¿¡í¿Ýë²r9ýì‹iÍ;® ×.S•9ã”y2‡æêbñ¯qkê§›e^ìÜÔM¿Þ´‹ÆŽÊ¼Xp6]˜{ ½#·ÂœR¦M›7Ñýö%7Œùâ³WÒe︒V†dò–SŽ.ÏÊp»dÙ‘{1ËÿèìW¿ŽV_v)-_Ì`ñ@‰ÇS´o{mÚö_ôÒKctÔy~ÁbZ±ú2ºêò•¤JŒ,ôÀ„dómyáEzix¬Àæ�te.ï=øá%ôi·Ì5ÓøÏþ”æ�í¤î_üšv¹2I=Ï»�ÞòöwЊ¥f='öm¥_þ|=/ËäÂ…²L.–yqñiÍ›VR4ØíÞÞO¤ýÍ?óZ½biHv¢‰‘�ôܳ[èÅ—œ|ÊËðÆ+âóÈ ³eóÚ*óHšƒ+ÃÅ¿óz‹´‡âXFÄ“7ª¦žÑvº|1ÑÈÎí´w÷¯èÏÞq==é«m¡¾ÛÖºõɪÕYåH›‡NB…¿¬ö-ëÇ­Û^rëÇ×IÛXL´}Ã3ôìÖ eÊKÛøk¡‡”cëÓ¿¤ Ï=O‡¤=I‹ríð�oZC+—Gíeßö­ô’´§ÓÎy�¼/µØ·�žéy6Ö†“óÊ`§ÖÌd|[¥ÝOrF�ùqϧóV­&]•T.;Ùþ4u<õÉL e·ââËémkWÓ­ÒüK?íŠêµ÷a¹Ó–ÿ±ÝÛé…“2ø|ÊÛ›““oÛ^’õ‚¼|Æë.‰Ö­S#´½ïEzE>qNá¾MÞ«©†Î&dƒ{éÙþŒ>vדîÍ–®>úoˤԯ~­¬*ýë¶HÚøÎ­[d�%mwÌ©ý¥�¯¸XÖWo¡ºŒ‰>�ÛMý/pËò*·ž£­ž¥çe»=6,ã—urîmo§œ¦¾õãÊP$•Ÿ)Ö'´gäKf8H_O¸òü”.½:ßO%ª£®¾¿¤e²<žq�´µhCeHÓ²}ÊÔF’ìXÖi :ñ®’uåmxâ êÝ9,Ío}𼇖±f>m¹ö@q—²öbÏÐ_JQ†yy¹àR]?%½m¹úu÷i…º­ mi†òY*™Ši¼œã¿œ{Öz*°¯ÒÙî”ì7ö½øŠ+â9²Í]nê,ò×yð´ V¹í@ WF[ ZôuKYæ%öÅem—©/&;_¥ïS&–穌cJÉÕdD^ƳñC•í¸+ƒ¼^²îo!Üoä¸sLVûr8ëŒ×.�¶ÿ¦•ËÍcg%ŽÂÉĺaÑôçTê1*Ç�rú³ìçȾÞÓë:é¹ûócʳWÐåo}­^>Oæõ¢ü˜•�½B‰ª§‰öÃó+£½«)EÎ6ýó ô¦?s ‘|‘@7_¿Øñ±™“° Q(tÁ6NûqLÚñdã-V‡9mÔÔÎ ôÄ/zÉéFŸwÅé¹erN(èo»ýglb7œG´÷%9n‘cŸùçÑê•r0aøsÛ8gˆ$gIJϨ‘&Û^¾/›uÞÄ&Ïm¨Úgœ}9û™Û¾‚ˆYt-F—€H¶:$¹�ûˆï]øj¢]YûPçÉ>T–qî,èûFûFc´é©_ЦírÎRfæâóVÓUï\+ç=“3ÜîüÀ[¯’÷ys�<ÊØv¥¨ç‚è³ÙXNÄí^7þÊR†x YƬÉõc†>Vbc¦ôµ÷Évì=õ¿/¥Oç»-r»‹n“`““gÐ%«—Óˆ?7‘<Ëj“AÝ”ŸCÛ½‰~ñËMù92ù~dõåWÑZ)ƒ÷7²}ƒ|?¶U¶Íùw@_þyßܾzáüßÄ|+ÅØÂ®�õeŒ9“s¦Ïöü†öæ/�ï<Þ꾓ó›¶)s¥N4É6/eÍ0WÅ㓎�ô§¹)9^ü5møíNùfBÖHgÐ[þÛ{imLŸ‡2Öí–'fÓv¶g®çœØ3ÛX4#WÂõgð@ö2”›TŸEÇÙqõcÉû„‘2hì—ÓÓ×væó»÷ñùÖ¸9 �”º©St·Ö)m¯?箌3.ÚêƒzÇ¿'ËTUC§œO÷Ûn»óBÅõÕíÚÙ4²�ŠŽ†`LÊõ§ªÑÙÙì³ããÕ8›O–5® åDCK³±ß^Ý {¿f[·óÕ™WcÙÇÝ6\D™l9¨³K؆”¤¯œ±ÒÔ‡qeqUõåZ{—”t}Œd†p¼±ç ã`5ì¨h®òÚsÉÌn+öW¯&µsº~»´à¬cMþz37˜]~nóißSÆÙ’7† ôÁQ¥Øú[}ë[ßÝÝÝbãÆ�bÓ¦Mâ¤søJ“a{{Ú‡¯§vE‚¤sø—N0u¢¶¶N´÷çgÛÆûå ÆÚZQ[×(úäX$ìðõþon[7~ͯ°‰nÝ©8‡¯°#‰«®¿IÜôù›ÄûC˜·­{Áwúz¢Ùì vÕÝ�âþ[®f2å+áK«ÖÊÝä:Zq‡¯ CµF\Wûñ~¿Ò·»êîn?ݼ[Œ£–Öák�¸ûz¯!p~oO·¿tâ¶c²G¦í:|…¸åõ»V<î¦yPÜÏ^Î;÷.­þLž·<æ,îßvPÑ{ýBÎ^¹«Å ’×uÕ’+ ûþæ€WV‡¯ žœ¨‘vWÊ ÞÁuŒ| =äì•«’ö[+jª½‰ã¼NÕÍê$D_kбtÒÌUÕ¸áªCìjZÌ/Š"…LNêÕ3N¼U5²ìÔÖøŽyýÒMfóøG{ÕÉIùÙµ¨© Ç+;о³Ìp™=kƒ‰ê�ÓÒ�hfy=êD}}�óiè Ää�£jþ’@ÊRÃmKr©®‰äQNæ‚?9è Ùi®º6/×GT�I”Òýqn^>�жº*ÅÆó6#m,WçÖ‹iÒÏž‡ööÍy›søëËTÔÙ'^=†»‡'WYNëêëeÛ²Å\£¶þä`Åuø •I·¬jl8ÿ‚(E^ìÔš™!>O çWq’QœÊgç=Í¡:®P~ªB<�üPm {ùìêáú?óä€Gqô“K#«nBt7v W•Àlòž��÷éfsnÝ\×Úçàù”TnÂm‘¦PÞê46^מi¹g“]VËú?\W5©NÙÛÇäòS £h®¨W²×£¢µVS7ËúÅYb»®-Ÿ¯j*á3›ö){qSµ²ë:Ê:HWWæíÑkǦWæÄ6Ó¢¿”¦ óòÂ' ³ÛVÞNx|Aù.M[š½|/“}».7깉Sb=U&Û�húݲ_áÍ¿©R„Nÿ¨½ðE‰­­È†+{_·å ¦Ob«›)uã4µ?¡çgÉå™÷Ç�6µð/Í8¦\¹ðÚãé•×!Ü¿*ôó£ã¼‘zn?¡-­û9²íSú�RÎZg Pj¿Ýþ©×fi!û“íGNˆÛŒ=ü̼<ðvÆ–�Íœ„M³Fù;vqÚ�c2�'¹m*ó �f¼�Êó†ç™_—ê¯?ÏŸqÂÆÛØfÑQÌ5Õµë>žs†3ÁKZg»—´/­�Ô£°ŒÁ]»|°És›0�œú#®W�?9Qš>„}]`£«µ.�U’¦); ã½ßv}(ªzëVæ ÓÎÇÍú¾o®Z3×Êû0šûÕ­ÊÜ€mÛ¥·½|Ú^=gecúb«\åióº×¦ Ùk·™‹6É ÊÑ'Œ”©Gió¯¸1§“ßʶcn»—UUÎF²ƒ§wª_®Kh ?ÄÞÿ²w±2Žä¹YËúÄfìÏu �Ÿìçíä×Ú|aþ"Ü.xu]¬-ÞãDóW¦›¾ÊD|ÿö§Ä÷Þ[pøz@l™Š¤”Îá+,r!âðå:C�)NDW5v)ŽBq+|m^wG0‰KŸm;¸“јx웟a÷oë «G+|å;E—Ö~E<µw�è?°Gì(8œí`Žhï9m…¾®úü¿ˆÍÌQ­ûL®ª¯ˆ­lÕªX§/îðU}¿ØuÜq°âQ7¯ÌNc¶Lö ;|É•Ñ:¤CÞ¡ýò_žëÖî¯0ž×Ї·ígyµ_<ÌWZ ­Pv;ëäÝÔ¶ž…›Ïýœ;ý}R<^X½ÌÆáËY©dˆÍˆõ·³•}gþ²†D}›êœ5ØÅ&Ù¨Æ]¡.oЪ'v[Ÿê~0ÔË¿Àª}L–H�`†º˜œrÕ;ÌNŠfæôä®bÃÂÆú+ï9Áº–ž`ÂprHý¦®£p/<˜©m=ì•×hŸh`ùÙÄV öFvÊV�èT¾:›Ý-Á×|Ä'�xG‚uŽ”ø¤ƒT÷�tè(ü©¬å ·‚Ú:P–_¾PóÁä0|õ1––¯ý/禾tï ìÉë|¤OÇ&mí[ˆ>%�¤ƒ]¤L:rË–Èüf½lôTl­F®ÖX€\ÃL®ŠW[À:öí; ÉÎ,¿î89¶õ2Ù0s¤ŠÍ+ƒ�Z33ÄÇšUe³óÐ@ ¡ƒOÕF¿âàö¬”×´å¨Óÿj5WßÁUWœÝòYé`ªT¹C¢©ª0¹áÕ'Eä½’xäDÖý¾3«Z¾�Gy>9²FË «ã•¶h˜é 'ªB_½�öw(/;›Ó,_Q�=<(rWòbMK¯òµ$×ɾþˆ+?öŒ"™º`YO8±È2è­˜­>“SÊ�,OS¶OJ˜´eĕӾN‹Õ12¡*¿Øìèã£ò_¾¶­„Ìqvdß_Š/ü¼/ìm˺]YwôÔ¾|ZËTD»•_½Â¹{u'ï멲ٮ|é·+¤ý0`R®¶�o“dû#ûAùfÉÞV”2–¶.±7Ä”cŸÄ^7k›SÍDs£Gä¥L†qL9¸j¤W/ññƒÓ§)¿¼ü‹×ªúvÕ™>4>¬i ­Ê¬ œíǾŸÓ×Â>@¨jTVó�¬üÅû1�Xú£8û±·w}ZÁU^ßíŒ-©ƒ_WI›I5'a&�_d§ý8Æbö1žß†²8G�Ì)ŒÏµ¨O¥?ÓË~ŸvÞÄ&ÏmÂ$ëÇõ*uBÈOÉøœWêyÙe/›Ž­±ú®0–LÕ’5x0Î0–LÑ�rƾÓ-›÷1÷ÓåÇ&lÞ’—%?7‡˜S˜2&öŸÐÌ®¾o¸oT+?zö‡èC]siŽ]ó¹êñ�îÄYå+˜°µ×4õœ¥�ir2|‰Û}`/veHéOggëe�cýrô eʾ¾)çü­jM�±9^É!DŽ肵N‘ù¼ZÑ=èÍËw á�”÷'Ò‰£¡Ê§ñ¹Ê°íEÏ¥Ýçûìûêöý�¨„ÊnKN=ÑÞÜvÞÙTåëoÌÊYmžÏoY–!¯-æïåúÚØ;o�—�Ò‘ÊÛ)*\×9ʘßË©mfPwLGJ=‘vÜmÉÅYáK}/Q[.KÂ퉵÷œ£©¯–':ÎòŸÇmLÓTËÕÇàZZuÑÅ7Àú—l�õªm}b5ö7éTÄÜ ­üÖ6æôÉ�õº.opmº Àá«DÄíè?‘Û;>Öþˆh} àèUø}lãnm*åuø’ÎKºüí�F^]ʴ—¼ÎV¾ºýçºm÷ˆ;Y'çî-yÇ¥þõÜÁH®ÚÅœµ<‡,îÔëðUõ%ñ\Ä¡ëq›ïã­ŽevÒòÒtVÙºNêïvȪow~ÞÛz2íþ“â°gâlÉ·�¼¡u£â”µG:Ÿ}Cá½+tß‘m—¸Ýç½F<üâXþ™W6ŠÛ¯ÿ¤x¿³š—–×Aq·__ëo™ÙáKN‡Ö‡‘ö̾l@,>�UNœÕ¼´áøVbšØÉ§ê–``ÎJ΀\6·¡©E´µw)Îgì‘Èa{£”¥Ú¼++_ž4OªD¢R.Œ÷³•cjÔ/ÀÜG»Ù„AMaÅ)u0£“‡w’ƒ�ƒ Ç&x»ÏŒ‚\êdA‹³ôŸó§íHŒ+Fþ³ùîÿ=�Uþ`®¦Åà¨aýµQY gPáÛiNtø+›ñglŽ97fk2*Þ1x¥KÃ*mí[ŠÄm�r eJÖRlŸâhj£Ç8_�N®´¡³¨Qþ¾oãÏÒ¾Û· úÒïrî™ê)Ù#&oH”ÒvÚ‚­C«ü:²÷4+Kz«³ØÛŠM]"DYÊA¨>ôºwöºÙÛ·ýq\yæ÷ô}@ý8¦L\õ °«Ó//wbiîõ_32ÉU-šEKk›èêcLOD�Lö£8·déçðþ! w×Pª<Õß¡#§œ¹Ú§+ÆÞ#É„.ðúÎoglùx/²ÌIØ„ é9µŠS­÷²Œ×mÆ“á~�W·q]x¿ÃËç¾²Ò–ìKë>æÓå« É¶¥WmÌY…&xÁ¬éË3ÙÇ^šV0ðŸNu —Ñ2lòÜ&L ͸^¥íC8ísÌË2a©«­.öcɤ~”ÌC½ÎËK¸Ÿ®ôåêÔ᦯5øÔëC%fõ,ëû*ýñЪ‹n6Ç]áoRtÔy«sŽÖö*ÓKªçìm,1gGG¿îµ*C²Îµœ‹æeÏ—AŠŽ¾vœSMrýao“¼ý”óá g6è̶ö‡j™Á`µæpýo‘<Ýp»Íïe[X¶³ñ‚ºw•ºV7oâÄYèm¾4eHù°ß×C¾_cåÓŸÓ-¢n×ëà'h8PócºçðJeËåhCLí=ÉÛ~^W*òdy‡dècÄõ¡»/Uƒ+i{Ìu‘ïŠ}ŸÆH|á�èëEP…%Õ«ªýf?Y�ý¹NÌQOÉ]Ý#Ç9üƒ‰ î±—ßÚÆbÇc‘ÌÁ… €ÃW‰ ïxò!ûFÏ‘Ëù59{9ÉzÏ+‚~…¯¼Óú¶›|Ç ’«bmö�¨ _Þ„Î$«wùÎS…ðëÄ{]s~e)îÌ]Q,/&Îáë†Ö-Ç'&3Y8|ùÎbyG/×LêyÕç(WýŠqú*‚‰²’]-~p ”Î+ëÅ .k)Sî–?ês<ïìÖ9á©Ï{ùl³ðÊêðU«ý™w̃q[:�<œ:ù\×Ü)GCŒ4‘g}†5´Ac™I/û2Ú4¡240 ‡Äðð¨f…/ýÄ&ol}y¤ŒþJ)Þj;Úƒi5Í…•Õ˜~þ*+Š×8ï±HLJDÿ€r¾´u>³å_PÈŽ¦é™ç6X´v‡f[ãcŸWÊDìò09r½}Ë®5{!}�êÄ«êÙ­›5×$o£ì×Yj½Î«›ü¯…¸Œú•ö´6ìhÇô�ä•ÎNCa213ÄÇñqyüAUí\÷"›Ëã¶Ã¾Š(ÿAšÜ3ìT7¶ù«V5[ò�F0رÏû°žê9�—· ù§x>ei‹ø—*õ�¦‹Ùxê/¡ ù¤*%úÙ¤{ÄÞCÏòÓÀTœC8>~/ #ž®îؾž�±¥(ƒº4�¶Æÿâ]¶wÁ �=iŸŠh#•z7[�¯#·ë*ñA+¢\«mE6™¹­„íˆÖ²éæ$lÂè4á×,â,bc3žäõ!¯Û¸¼®òòƹϯó1«ËWµRmÌ Ûß8½T‡¶Uç_¿«õ O5Û±VFë|°Ès+{MÖ‘ëebeÕ‡�IÛ×6|Ô~h]ìë^júQ~C½ÎËEDVen&è'ås“ü-ùgìþlA�—Ëš¥?^ξ/—©^Ó¯t!Ñè}�Űõ` «½½&×sö6Æ„6r]ƒº×¢ I[µ�‹ÖË`˜_fåC-¼lyäeax{TªüËbã\Ó±™ ×Q_ØëÄãÖ8=+ ›¢³±•š/&-½ë<ÝP¾)s1úêÖí¬'“ù—×QõÊ® A¾Z(g¡Íו!ÝÇRŽDýüƒª¦ž@È„£@V5O‚ëÁÜMBTîû¢ÊÍá•ΖËц˜Ú{Δ§Ô×j’©RÊ2ß=&¦,V¨�Á9h�¹.ò½Tkg§èìèî?y,ÏÛ[›DMè}}'_¶„ë­©W‹¨O¬Æþ\'æðÅëžLsƒEÈÏm/“�)u·Z‡hó§�¾J„|ÿ柈xÀýç9ry¿<òkqH“Žw_s+Ó¥8‡/g…)¾W°ÂsžâÛ*«a}Mô¡vl¹ßw$ó·¸3—É)‰?ã…óœ“ø½Æ�|[CÏ™‰Élãðå8/äøVŽ�ã×ußìÖ8˜Ò-‚‰âð¥Û†ÒÛò±àXqÝçï7}þVõßî7°Æëýrij�™ó»ëÀñà7¿"nªýŒ\íëjqUÕÕâR©§óÏsj#Æ+«ÃWs¯Îó„7˜ÑÊ}r¸_´·4‰zg¿÷ê*¹'}•Èårî¿@&5\7û²ß{¦Jî'ßÔÒ.zú‹™0ŸýÝí¢©¡^ÔÖÈÕ¾˜,9Æ•wÔ“ ïëùèb`Ì4_œ9!xcëËÃ;†pNXþ…˜6¬×‘�ñùƒvé!¯Ë]'>åOy9@¢¦¾AÔ×׫ÿD-çÙœ~°¡¤9aÜ”åÕ ¼"áõìò0—�}ó¼ÕÛŒYO½ù«6z¤ #åñ¿ò&™Œ[äzúv(E5]wµà6îÙi(L&f†øòÄòÿsyüAUí< s.“ÏŽëb`îh¤+ÿ<>[N¹ú Wþ›ä–²þ„sxêj¨*´^¾;)Øç½ÚüÇâ •o' ×!‹ pÞ”« ²þ×Y õÁK¡,+Xð¸M[AêòÃcPlýáÛF!B[Fž<¦_EOm?À ©«'äen·¬L›Òò¯Ëpž}:«}¦jŸxZËHQvÍÓ�èÈìš•-®§?)6�2s[ ÛQ^6›þÓUS†¹yu-¿¦/׎4zÛâ:èÃÆËãç�á Øò™E¦4¸¾ú<Ó+¢Äþ‚»D_O1~%·ÝqÑVŒ½øÊB\b_•*zd©‡lêe‰Ë�¡®°ÖMÊÉí"‹Íù*XþGÊ3»g¨·¸\Q{-1W£Þ� È+�ý6Ìÿh¢JÔÖ7‰öλ�™RØO¦~�ÏØÎÚnÓÀ˜‡ì§{÷rÔôËãÖµ3™øÈDlæ$l˜ôñ®g޳ˆq g¨¯S<©Ø/·¥H?(ÿ¯¼¼qî(×5ŽÎ3\¦ ¬ÙÆœ0‚�sœ•©‚øê=rõ¯­D®•±ˆ|ÈœçRe›0.«˜ÿ¸^ÙÆ:,t}™¦w–vÝRW%½ ý!.[’ÌÀ4Nâå"Ú††VBm ¶žd+ïäê:2;Ï–¾/ç§«ÇxžFV„Ql3˜§æatqæ‹‘ÌóȼYr=ÇãÎfcùTãþçqõ§E}ÁëyCßÏ‘ƒ÷ã=Û5É�—»Ä}B.'k�¸ ÅäŸ>,+ë¡>O\Þ8÷¸\<¤Õ«X–¼eqëò’3L¸ïåq’žùû,Ý'vO—¦Œ€—k?Ý"ÚÙ$™yÞèóÝÙ–4øÀ×IFÌÃúùšÄµ PRÊÖç#µ©Ûµ:$A“:úããØ"I\”r¢³›¤¸Ù}žÜÖty¯²‰ÎT÷ƒ6ÄÔÞs<]ßnäüºN…/[L?îk|¾ ŒâpTÂ>×5ó1×Å[óIÞ»cþ«lçì&Èê]½ZL}b3öç:el¯¸Mø¶[„ü<¾L6ÆÛ*n{™3ÊE_å ;uTìÝÞ#Zå _žS×COäÝ‹ÜÈx!ÞáK:íøæø#W™Úë82í¶49|ñë!ǯ­?¿Ã�Ós"ã[w®×¯BÅŸ‰søÒ‡/�×l ®kü¡Ø!õÙ¼.ÐÁin[÷‚âHå;Uq‡¯ŒL‡¯j��;eãÅWO[ßñ%?x=¶_á‹w8Ód f¨rè:¿Q9xÃÌ:AnÄr Îfþž?ëW‹¦öÞlÒK=Øf0Ÿzî7–�’Æ£ #'WeèàžãÆ òcÆu‚7¶¾<†Îçw5ø¶à{fëÂòkòËîTÒ+aTn¦<6}­–;ùœq Ùš–Wr„îvy(„­}sY³–©8•lôàaô²8)Êåbý:©Vôºkç²¼ÈbÃ26®¿oÛžbܾX¼<Œ^N&· C|^rί6nÎ×=ÞÞÓÚ9g^ס_qŠËä3â216\çX_þƒÕ’¼- ƒ/Pä—-rŒ:ÞÓT¨7¼/]؉Ê`�±6È¡•?,häœÅËó°ð�3‹ pÞ¦:J½^%R¯ª×\ã×µz™ ù!u*EýáÛF‘Œ"YºÀšôÔ×2¢”vJR gÓ>lÓIG[FlÛe'ÂX™]'MBM£Ì¼<…íÈYÕÑ®¿ÄtÕ”a�é®9HÕ?]d¨»•€ñò(�†NJQ>õeE/ç�©]É­;åqëeJQ&Jn»æ ò.¶Í—7�Úzˆ—Ï´u‰²å€ËÂÊ»µnRL^–9¯Àô6Ü7Å…c÷˜<&.—RÇ”ƒ+OX{\ yeÓ0Щ|£ö5äJ}uM¢w8Ã*Ö)ì'œ†þ¼ÐÏáñËc§©×µ¸Ý‹æpÅØ»9½ü]ÜüšžG¸Ïû�6s6a’4˧’·aýôçÞ8†óJ=·ÁÓKQ'ðºŠ×ü:'Âe ž1ÛX>¬tìª÷¶ec«ø°•IRPÀ…1keä\2�'3æ¹+—MƒB…ËZ½BAûÕº>„Œ#MÜÚvÝM?»®iÒÓéÂÃe«C˜�˜Æ¼\(m¨Çž9v{i¬LEBÿÂ΋ ú;›ú¾œ_Pg:ó<�¿ÌS'…ÉÇn7fáqg³±@'Ó�[Õ5câõ™¡žwdH*CŠ åèä4sàäìòOöÆç¬L}¥¸z�Åi¨?ìubqëòÒÀÐ'Åîkë'ÿÁðK7‰ÝÓÉ$£âåÚO—É’®ì�ðú;aéÂçiøwï^|™dDÚ°\VƒŽŽ ™ÊZιm[·ku`éi¹ŽÆ±E($“‘‹Röta“âf÷yþq[SꬂèIl‚ûAbjï9 Sº¦ëAXV~xÙbúeqøeèc²Zq]âúÔ9ç«fÑÕŸßQ@M�qÒÕ«iÓ`éóú$óØŸ§Çì7°ç=³å;#&c\ÝèÉomcE´jÞà¬\àðU.²N¼#›ÅC¾Ó×#b÷Q5±érør—¿ûZÿ%]ÿ/ұ頸»º0ñÃ�˜¸¿røê_ÿ?>oÅ)îÌ¥wØšü™Š8|…tz¼ù“¾Neø�-š•ÅŠ`¢8|…ÒvÊxÜ2ý›šï�Í_3ÿ»û+âÁõ»\Ç4Õ‘�Ä¥×ß!î_×%žØ²QtïØ&žÛû‚xðóÞ*_Óãð59ЦðÌÕ4ˆ¶ÎnÑÛ×'ú凃Cƒ¢ÝŸ„c� V4&‡DwG«h¨­Vâò«ðòü,hèp\´³•ˆr¢¾¹Mt÷ôоþ~100$ûìö¡ç ±n9ð� …SÖÉ`�:–7¶~ÇÓÐàáœãQßqC¾LhîÉßÖ…U®i–jGìœó0ÒNë›[Dss³ù_“ü’]®Tš?Æ�wbeäZ^)µÉÃbì›Ëª<(ƒ–�žq*ÙèÁÃèeqR”[ÿUy/jDþƒX–YlXÆÆõ÷mÛSŒÛ‹—‡ÑËÉäáÌ ñyÉ9¿|ëI?n®ÄvΙ›êŒñÞ¿Îóq™®‹s¬-ÿr‡{5•ÂV¬ÝÞKu9Iì–Pö%|£ãñ4Ü)rRw§¾­iécÉ0Ö9x~ùò³ô‡,^ž‡…‡yœ~>)éÃsÞT]/ZZbê+Y—55·‹¡”ï_yÜz™ôùQªú#ÌÖ–‘‚Qs’FO}=!#Ki·‘d•pí“Á6�tôe„Ù�!,ç«°WdåK¥»©ÀºxcÃTJ-³QYWØ÷—CMÖÙ‘îZ µw¤kƒÔ¶D_þâåñbÿ–ª|f‘‰sÈÔ.„…לó¸õ2Y–‰¢lW Ê—œ§†üGòÅO°…4_‘Å0qÑWc+Šœ)ë’r•E– ®H“G¦:–—e}þÚ•iAÝ)Ïìž®^“ùÂå êËòÕ/SP.TB^O€I1Ð×-Z›Dµß—öúÔί\AU7íç¿)ì'S?‡Ç—3• Æ.b\¸ð±9\1öN%|®‹›_ËćEn3'a†%©=L'ÏÛŒãÎËÔE„ãéêíxKFÄë }fªÿÍ6æÉÇÇSTÛæ~,ÈWãðW=öñ˹ùzp.óÁ%už{ä¯M\9Ôê¥`i©ÎW�¦ö}eV~xÙ2¦ixÞ…ß/¾�áG[Ì�¢KáÆä¤˜Tþ%%ÀôJ²ëú$ÃØ_Ñ)°ýÀ~Ø+!ÕøÇ·]_Fù“l^)kÜÆ”þ(³÷�¼8­8|Y²?4"öîÝ-vlß%ƦL‘Œ‹îVo•¯öŠ:|í9¾EÜ$ ¾ç4sg÷Fq¿ç Ñøƒº© Ž_Üq못ó[ òk'¬ÃWD§ý—ϵ…мm$åoL¾”¸ï»BŽuþ*cšëO0gµ«¾�_µ,üü÷L¯Ão ª:ä«“è_G�÷ÕeŠFar\:eu‹æzîü•r~¥Ñ«íi˜»ßXFEŽ\éiäI=)ÊD]'C¦Â[_¾<§Î½ [åíÝÎxiòøØ—�%ùF®ú“Ò/‚ÇPÄ1ëœ) ¯”)Ùäa1öÍóG7x0w¤â²Ó#°_óW êv.ùÕ�X^xö�ëéÛ°|ÆtÝ ®³ÓP˜LÌ ñqQ;ƒ¯²ü¸ËhçÜvLËqvÔûm´ÏN‘) p]œcÎ×/ÿòú@{]!N¹‚—t¸mªÊ÷¼/:œ uÿš¬7Ùòämý¼Î´Ïû°¬ê9‹7T¾�ç¸^~>)èÃó娛ûJ[cñ¼ÔmáÊÝÓÉK.kûÈ9ø¶QàÀïea¤`ÔœøÛ}ʾQ¶zBF–¢ j’”Ζƒ·jŸ²–f?ë´xâåzfm×mû8·ÅŽx~QÖþÓUS†¹Ý{öYŒmq¼øT[Š—G}68ãrS>³ÈÄÓÌÔ.b�xÜYê)i%�Ã�®Le»yq;ªüú±u@¾¤î�Ö—žbÖ¶ÂåL[—”«ðxSkÝ$œr•%ÿ#å9Á6Brùu ׿Äõ‹g'úßJÈ«—d|xPt·7Û�Èv5WŸrÛ-Î�Ù�u?‡ÇglD½ï@�b¼î«Í˜‡ì§{÷£7¨õ]ޓΚ�! a3'aÆ”¾w=.N^ïe¯ÛŒ'ãûAy�µã-y+¹3¼8åmTÈÆÊô.‚I¢Ã×ñmÌOn·iàí¬ÈÖÿʘ²å$wøjÜxP¹—_=l½¸ÎÏËOŠÇ_ÉëtX=}ãµ­ô•*¿œ§{À—Ó'¹j�R&ÆÅðаљˆ¿ jéÓwv•Äd#Ê÷W’*<Ø×l!YÝœ~‚„w𫺔dó'£¢­®FT×ÖŠZ¹uGŸ›8kY£Îsî~Çs²�­|`þ"Ü_¹Gæy}ga£F]GBYIÁÛÆ�K!›ô¾VùEz�¨•ò7µ÷Ë›râß·%}˜| ãbt¼´Îæ†Úù÷y©ªÏlò°ûæy«<ÄéiTBްу‡1®˜'÷"¯òò\®•·(K–rrý#y¥³ÓP˜LÌx|r¢]W[t5/œƒ¸Ëgç|b¦F[×È—už3,›8(¦ü;†ÃœZë››ü:‘;ªv7&Þ«˜sm½,õüÏ>ïy,Ñc¯f Àí&È'‹>ü@{àVÇ„x+$sœ.öý%¦«¦ s»÷ì³Ûâ:xñ©¶/�úlpÆå,¦|f‘‰×™Ú…@lã×'K=¥ôEte¢(ÛÍ‹;ÊV³¬ié]�A}Ù6 ö!­mŦ.‘eº,åÀPWXë&1–«(ù)Ϭlél#$—__–‹«Ñú½•�W6£ÃbxTµcO"ù¦>è[×2ëZ@IDAT´jû§þ³Þ�Á~¬û9|R[ŽÅuÝ‘É�À�ÀY�Ì0çìIÈ~óP¸bì�% =äõ�W[óqS°™“° £U‡]̧ý8†çOê¹ n›™Æ[iê0ËÓT_Îø8˜ã©oi5…1m®¡“ñ-þPg{ÅÍ›dÍsG›0ñºs½JÚ‡�Ér[Ë6a§«­.öu« m¥iœÄÛv¿ g•ì‡Õzs4rìÞÒXS˜—¯�ØçlfCß—óóÚŽ�ë?h÷б×$yìmŒk¥?6ëš±¾(¢ß¯•¡\}BÞ±rWÎü‹ï3ëóÅ»ªeãÞL®?ìuJˆÛÀГ™×[Æúɘ°tC}C…!Ë7%´Æ¡©¸v–Ç=VÆç­}Ñd?¤ÙÛ-IÖÅœ…6_KT†Ìm±×�(ż£V å’͸».‰vciËIuv›à~ІðrcÚR\ÿn"M_ÙP¶Œúžç™YÂ>�ÖúبK–™ÞÚzÆ~üäH‘yìoÐI©{²¼3*â}m’Í+eM©¿Såz–|Á³å$‡/Kº»ýˆð¶î}èI1¢‰gdóO‚gX'…žñ‡.g>=pü¨ØÃ¶ o•¬ú4&¼Ÿ|g/g°r‚jûBàÌåm×Ä‘_ñ*p$ºZ´íÍ;evøj^¯8)%‡ßlC)�Ñ?Äœ²|ç-Í5Æ&¬«¯×�.ñ~oàìü^¿ØÊâ´e’ìð5!¸óÜU�� O¾‡ [3^uý—DwÁq‹;|ݹ>¼åAñðçƒ|tûîÞ’w ›.‡¯èŠ㢣>p²pdjÉ{B‰¾Öà ‰h¸|‘à�ŸéK ¥ðð mù•AØéÙÌöZœ<—ï:§0%Nï„OØËÆ-²-ÇP‡¿-‘·= kµ� µCÇÜÙÍ߮ѓÅù•ºz™$¿”ò'{  Þ¡ÔM´uúÛnÊAC›ãð%w(39PtÂUÕ4 eq ñ!ÑÛÓ#zä¿þ¡Ô”ÝtÍŒ/m‡¨…îÇ"ƒ¼³„oØ¢Ìöí$oß‘Ò Ï®Yèá¼pò¶í#Çñ2¬ŠŒžëLŽÛÛ0×?â\i°SF7)g´ ŸÿÒ–jEd�'©p_]޹(;gÙ>äº�ï@ÇžìP꣒”7úAÑ 84˺.Tg w7ùÜN½ìüËÕ‡_ˆØç=ÓRsÈâÕ¼xäÜ2ÙwX”úúu"—@2Ï—ƒ*Ñè:¶ò›æc^6HÚWôe©02æÞJi<\1õG¸üX32«˜¿c]OÈà†2�”¤sߦ}²n#ù‹ÃŒír¼ŽÌ® ñVBfn+ŠÕ_bºjʰj÷…=ÌŠ°-®C¦:!ÁøT9Ã�byÚw®KÖv!A¥ ÏRO)íjÉmדšOªåÛ·íÑ}\„­d®KÊULõaºqÛ)e9Pò?RžYY7Ø—ËïÇ”‹«gNÆßi–w¼WÔym¿��ÓnøýOƒƒLD“ýX÷sÙßÓmoÇÛ'{‡¯�3Yöaº Öß…vÆ’�Íœ„M˜� ‘SÛ8­Ç12‚y‘”sÜž3Ž·x]¡¯ÃÔ±hð ·ß��qŠÞ–õ^™,Œo¼¹'ïÑ¡þ^w~¢§·?2Wä=÷«µ=À&lòÜ&Lœ>Þ=®W©û¶ó¶ºZëbY‡(íhL[àÏݱgx¹Púé^Æ~ý�µ¼q»ó›e.³gSÌØ4(Ÿ\P^Vƒ—ß\ÇR÷}yÜ:™T}£û*÷ymíÕ!‘$�°¶1ÎYèÌuÙ–!Þ'È2­“AY1ó=·©Pýoê+Ñ÷HÌ?>��ñ…·–�›•LGV7(¹l­SBÜ&†^âì¾ßÇ÷îÅþ²tK5¶�éÙ´³±bnò|×ÕQƒ��ÊÜ)gaÊ×R”!wÞ>ò*%4ïXøpJ•#Û¼†6ZOšfwˈl¹$¶³ÌVÕ® Ò³û<ÿxÞ—¬ ‘iùc¿’÷•yÙbíÓOÕŸ?ªCYƦêcðw|ƒac‘{hÔ%KÄLoC½jUŸØŽý :qûÓÕ="æ�‘•ü!OSgóJYSÚ9Æ4R¯gÉ<[.pø²%;ö¼xè^oõ.ùûP»èy~—Ø?rHŒìÝ%~½îßg/ù\ëS;")M¿Ã—ã¬rlr‡!‡¯];þEéÀÜÔÚ%¶:(v¼rPlÞÖ)nªb“óµßó·!LvØ’«Œmd«ŒUÝ!ßñ‚X¿e‹Ø*WÔâ÷ô[B–ÑáK:wõoyHÑÛÙ&ÑÛbÑ–I‡¯]/~OI÷ºÆï‰õö‹]GÇÄÖ7Šo|á“ìþ­b}aõ±§¾É®K–�íØSÈ£.qg­·•c�W7¶æìÊéðÕ×|]@U ¢{`XŒ��‹¡þnÑT¬^ã9ÔµæWÕïka:V‹æ¹µØð¨vtX: u41•ª¨ƒU¤tÉ ²ñõ'R¤�×·v‹a)Ëøè�èiçñyŒêD¯é‹ìHüã¢ÍÛÕ)C¹:ÑÑ; FåWÝýÝm¢–M.V5uB³ÑÐÉà�-ïx†÷`wu•º¸l»D½R&Ûƒk ‰Éþ6Æ[:u5wˆÉ{x¨_´7_ÄrǾ\¼“5�íngïìáÁ>ÑÚÀòžäê@ìãv¾¯|®Ñã�j¸À¸) µsâØ[ÏÀ èëÃ,mC¤òrö<´µoGž·Ù:Rf òw²ë!—Ña[[Hû­ª—euȵ'§|t·«#9y¬¸Áò"£ sý#ye°S&3õ««ªºVéhèÔ'£nùäõ‚£Ÿà,ÆÎãsj€­Ô'ªj›Eß S?J™zÚ•ºÊ‘©$å¿ PWc•RÞ)üR]™lÌׇ�]áO„íó>ž‹šW m=bhp@ô�ö60)‚íƒ�jD{�¬£e}59>,úºZæuíêzfq2óI'¯H~]íµuãÃý¢¥ŽóöVÇ¢TõG¸üØ3ŠÓÒ¹g[OÈ †2�”¢›ªMû4 ¶i©ÛH>Q›±N‹×1¹¼X·ëEÈÌmE±£ÑbúKñe˜—— ··-®C·,Æ>ÔgàO…�KU>³Édß.„åŸsîYê)eRÇP&ìm7�’oæÊ'ëÒºÂÁSΑ½­dîë5nˆ)ÆúÐ^·r•'ÿùWëj›ÌÊ–Á6¸\~?¦\\UCÑœM·¼,=iÏUõ-¢§P®|ìŒ=GÅÐ@�26}©Q$Æ~lû9ÁvßNÿ('š;ûÜ1ò¨;äã9ç>{�.|!Î~ìí=œJøœ×wAl×´™“° Ö!|n§ý8Æf<©æw–ñ¯+‚o÷ìÛ®$yœ²`ÛŽ¹¨?Òéj[†lûý:Š›£�©ÿcúJÁ–¾²¬¤ž÷,çü­É¡ÙÉËõ‡õØ(!n#Â�±û~_o~¡«1ù–B_^Žxº6ílH0Ãi¿:o[Óäö燇DWhžÜ©{¹LZ›—©”¢ ¹m1{Ç6>< Zù¼#ëãS·›t0Àò/gwÁ%±œ0[Už â²û<ÿ¸­Å·�#­@ìx¢ÚiûʬLóñÓOÕ_•ÅÔ‡NÓÇ(î§–plÔ%!œr›q2ôËìêo–±¿Q'û¹A;ù‹içÒÙ’’ 8™Vpø*÷Hß:Å©ËsàŠü>´N»˜÷\"¸A½¾¼ªÌ+|åW¿Zÿƒ[ÝA¡Ûa�•RØáËYUê‰ÖϨÏ8Ï…ÿånO°U¶’¶dúrµ-ONßíÝ{R9|5úK§Êí&YÚÞJXÚ_ž¦tnã+w…Ÿ_ß¡²¹¡à$eË$ìðeJ»ûwDù†yËó»7î V;¤gpýŒxð_ŠÄ{oßÁD“Kêè8¬à…€ü Ô› ã_qkäw¾loW¿ˆpäméÛ'ÚÙªR�Q»«iîI”ß{@÷B‰Ç]ÛÜ.š|›*¤•v‹ ù‚´V«#“Y®äÓïOа΀ìd辕àÜyÇÓѧ·•;b±4¸ ¹zé´æi/y~„ÒL_}‡êÑßÞ±'ÎÓ;néUµ‹Ó‹Ik84Øšó´ì(_KLøvu†H󗳿!çɹûÇ&ûMåð¥-S± nfÕà –&ŒÔ«®�/c]„ ÇåçÊì”Û�nÀe¬‡¤zªÓšg›ºß°s“­�rÃøþL'‹w­$å¿ ‰¿‚W.ïtŽ[È×MUùò“_ñŠÕé¾6E佇þ€¯ÞèéO¹&·Ž,ÆÄx¿h(èåÇë—Õ ¾ šm}¬—–äYºx嵿Vr;×>o®?â꺢™”ô®[Õ20ו•i/Ú¤_›ö)M ·‘¡IF–[¾ˆœ¯RvbuL./NÓ.sL=\L)® _¡‰1KÛâù‘µ]ð3UwÀó3cù,F¦bÚ�Þ5Î=¶þ ×S)Ê„“†�ízÒ9ßÞ–qÞÇ še¼Ç-m%­œ¼¯[–rÀm+\ZêVŒÍyXM¿æòœ\¯q¹x}Y®&üëÓ/ï¾þvö�R\A¿º®/:?ˆ³ë~Πh¬Š“�ßÓõ ¹€ê±Ù~äs–ö®¦=ãi*킟q‹9 ›0Q=Ô+öqZ�cÒä�2·a?Þâu…’g oÇø3<¿ýö­0n`Á•±·ó\mk~ÕòàuŽA·âuð¬þˆËÂetžÎž6ynF¯ ¿ÊÙûŒµ}£ÐX'e®.°ÓÕ^IĪIn{Œã¤˜~:Ïg¤E™ÃÔ¬h®ПñöE›¿æ±irVË—?_,%)Wß7I¦¸òê l%Ô%?uÞÌiòšý¹Ópýàgˆ•�ù¡��.|üeW†œDlúý&Þeér[ža}mÕ6XÙëÁsÛÊ&âŽcè¤Íîó>>ËtÌmÁoSÜv;A&'YVŽÂéfogMª×‡º¢ï¬|¹eY¯©­öË6—‰ë©ækñeˆ§¯;n)Ѽcœ*¥èYšz‚�»�Ò„É<‡ÇlÕqxŠÌñ±û<ÿ¸­…óÏ•µ9Èwý} ±}7‘$�ÓоCbú…õçùëÛQ¤ÍÊ¥Û7ˆö1¸lœaÔ*мÂûEº¼L=Ó'&›údÜfì“?Åô�läçù¨³i£�Iîél)Uá¡2€ÃW‘PÇ÷>/~òH«Þñë�‡ÄOºŸ7nW*‡¯ýî–ŽëÅ …AÚußT·J ;5í9¾GÜ}=›È«¾_ô³í ½ç×w?$n¨bÏâ'Z#nlþqÄqªãý~§§qcx‹Á`«E�s“ó|røƒâþªJŸO¶6ôä5þ¾°q¶jÔéÊÃ>v7[9Kêúð‹c¾“UV&®Ã—Ç:!íþm?7UGWærá«j¿$WðŠ2ݱãÇâFM9Ï?înµ)óºVÝÚñžÞ4_ÁŠ[úíÇE«Ÿê–Vã�¢N#SUm£èq?«-µU¾­8úåÓ—+ 5ŠjÿKKÕörUµ¢¥3íNàQ¹šK½×©Så­mlƒ¾³—û°h©)�ÚÜÕ#Ú”Õ ub®F´vúa¼Ûúà o*?Å3ò¤3üf®'d<“}Á—‘5:{2¤Å.Û´OÙËHv«cr¼žªÓ*³LÔdGnY±í/Å”á>æ¬Þ¢x¤Ka,l«œön[>‹•©˜vÁ³£ð¯}=UNÛåR³ J¹êe[�–?æ[ØŠ4[]RĸÁT }O¾­“²µ´ï–�«ÐtPyÇ»E#{¤ô;äx­¶¡Eôgéx$Ù�m?grP´Ö³¾Ÿì»²ÊþK›\µº³Á»WÏ>^2±f×�öSx¦ˆ²ÌRQcÛ+>6s6a54'öqZ�c2�'íÆ[Éí¦\×ÔH²1Ÿ$ßÖ¾Jt…‡µÒ6‚9† N˜~ü12žÉž6yn†)¡9œŽ>„MÛ';Ž™ç íuñÀdK&·=N;ë8š£3÷Ó=yò¿C�Á‡˜©WŒT£pÏfSß—×+‘1‡ÔV©Sú¢ qp_SX´]\ýüŸ—!YmÌ gþ t‘W+ã¯ìeÈK%ë˜Õ,Cú„1eÊ•¿,ùg?Ûß¼£Pó'EýáeHf�âNd|ð®ÝÚÓ“K÷kl·d’q%½#ÉÞÎêŒ^tß½Þ{ÞQåªëdYîÒÐÏßÛH›m>Ö2ØI�è’» ´iß=ÉÕ'#óööï-’tˆ’R¯dwÛqqæ­bǤ–¶Ìëlµ\æåTØdjCÊÕW6ÔAqúË¢š�I} ^.ËëðÔ;ú÷ªÜú³{a�lê“Ìcÿ¸ü‘²37˜U~nóú~ŠÁÆf)m‰áÅá4(•Ã×)ŽÌr’(óß¿sÄ ó·5§f{B˜œ ÑÃtìØ1:6w.-˜¿�–œ¾0VÄûî»Ï½_[+‡{Eü�ˆI:BÇ‹ˆ!>葱:xh‚¦¦¦äƒóè¬å¯¡ÓçŇI¼;1B/OÍ'šœ¤y‹–Ðé ‹�01Å’>P& �졃ÒµÄ3oÞBZ|öÒD>/ïÞEóÓ¾<édð¯I{Û94NK–Ì—qΣs—-•–Ìÿ¦hllÂN‹Z¤35Fû†yÏ>w…uâ©{ÍÄ22­2ÇÙ‘¼g×_*¢ Wȶ˜™)‡ÖåS‰%ëIqíB8µRÔSá8MçÓj»EØJ¦ºä¤/E”g“¡8×+Á5Nž¤{Öòʈ¥­Ž�ŽÒ¡qg¼æô;ɾÍÒò�-û9r<7(ÇsóçÏ“s2g”¨ÿŸÂ~Š(ËIÙ¦½oËÇbN¢äóR!Û8­Ç1YÇ“2?‹oió,öb²�Míü!]~чi“Om;MÞ[­[ŒÐ=ï>›ny²šºGÛim™†¿6ù`“ç6at˜§³áÔ•6óiu-™.–uˆŽoâ5ÙöÄÏmMÑÿêrúðÝ®uSÛÀ$ýáŠâFγ¡ï›ÈµXÚkª¤§ÓƤ@iËPXö’õû­ûXÉõXfÿ¼œùç'2Í3F§"ò-R›v6E´²‰Ê¿'r^‡.,¼ïyêËtöÕã—Nô§¹l�‡¢Ê�œwÜ=,ç5Ý©ûEtþ ùî)F‘ÊÔíD™ÆÝù‹âÃà„¹%Ëêôö•Mš'•Åt}Œ± ÷Ð’+n¡ª¦úÙÍ—››‘׭ꙿ¥û77h%¿UN%Ù’U¤T¶þVßþö·iÕªUtÚi§Ñœ9s_™Q*‡¯WèîkL )äd"pŠTvÙ) ¤»—s„?�,ÔÃÒáki–àx@ÊNõTÙ#�–À=|ú>ÿ}É•èj^ÈNí–NaçK§°\ öþ-?aõ™^ÁfSb6éâYÁÄÖiÑ¥ŸÎŸV·Ðhûÿ¤lî^LøPLí¤ïúgê~¾›º}„:Ûo¦eÊôà ‹èÓ…þ…Ü=ó� œÌtéúSôãÿu9ýþ]›¨¡s�þî=èAÏô|‡ü³‹¾*˜Ÿ¥rør–VÛ/ŽJ·/«EÖ*HIO7�Ói.-9¥¸¯¿¦[f¤  ' �ÙøâàDa 9@JCõTi8"�™E`jl7ýàK×ÓÇîz2/¸Ñ!f‚¾'_Ú~L¾´­j–«üéìZ� ˜\›M}ˆÙ¤‹\:’voø7ºþŠë©`Ýd³ºL1¶�°  0» 줿:å"º» dMS}µöZ&W÷ššØGëîû,ýþ-o/ª£þÉ¢•xÅ6»Mâ¤Ñ.}cjûÃ4ÿ’ë%™jê‘+ä:›^à@àÄ!‡¯ æE©¾ŽÊ-�­áòUÁ =Á“ž/Wõ:[®î…µ½NðŒ‚x  ',�Ùõâà„Å Á@Š €zªx   0ã(+øÒWQÇàOéËõocGvn¥_&:oÕjù2×tÒ̦>ÄìÐE]±Î3Ð\C'mø»÷h¶*õžÀ/€€@V»Ÿ¸“Îÿ½;”`¹\Ž6mÊo£ëÝÀÊF üÎl} éü¸uÛKDg^@«W`Ç‹™�ÿ�~6€ÃWsµ”_ŽSÒÝëe¹µã¤tþÂp§Vö‚³§‚cÈF`Ã=ï¦+nyÒ ÔØ=L·­Å7A<  Pn¨§ÊMñƒ€œHÆ6ÜCK®¸…‰TMí}­T½Ë0(©gSbvè2B÷¼élº…ùT7´SëßUc+ÇT�‡@@ ��O=H7]ýiú¡.X®†Úü*ýáåêf�ºGq N|ècœøy A 8|eãUÒ§Kíðå ç8~yÿk~yXNºßSäZ^óä?ge¯9X×ë¤Ë(   Pzû¶ÓsÛ÷ɈÐÊ·\ŽJ�1‚IõT‘@@`f�« lÚ²�•=ô³–ÓëW¯€3ŒeΦ>ÄlÑeßöM´}ßaiÜ hù…¯§ËàÈhiÞ ) LѾ�ôÒþ—iþ™óéàîÃtúò•téÊeXY1%A<63 �13ò R‚@ZpøJKª Ï•Ëá« ¢"J�€¾*˜ pøª |$                 3�¾*˜ipøª |$                 3�¾*˜ipøª |$                 3�¾*˜ipøª |$                 3�¾*˜ipøª |$                 3�¾*˜ipøª |$                 3�¾*˜ipøª |$  ðÿ³w/RTgÂ÷nr÷0%*ÑQDE7Áø®ûN4h6:nÔìH²ê˜õ’‰Ÿ‰àjHÜH?b4D…¬JVÑÌIУ¨™ˆ(ˆ fÄAAp@d€�~OUwu=U]Õ]]ÝC3Ãé[]Îù�K�ª~ú € € € € € € € Ðø*a¡ðUB|v� € € € € € € € €@ à«„…FÀW ñÙ5 € € € € € € € €P€€¯_%Äg× € € € € € € € €t@¾JXh|•Ÿ]#€ € € € € € € € Ðâ|͘1CŽ:ê(éÓ§�téÒEº$Ì_œüÇM@œ}íkë𵯕éA@@@@@@@@`߈oEÀWÊ•€¯" ² @@@@@@@@ö#�¸_sæÌ‘#FHß¾}¥k×®Ìð§ÎðG�u@@@@@@@@Øø*aÙðUB|v� € € € € € € € €@ à«„…FÀW ñÙ5 € € € € € € € €P€€¯_%Äg× € € € € € € € €t@¾JXh|•Ÿ]#€ € € € € € € € Ðø*a¡ðUB|v� € € € € € € € €@ à«„…FÀW ñÙ5 € € € € € € € €P€€¯_%Äg× € € € € € € € €t@¾JXh|•Ÿ]#€ € € € € € € € Ðø*a¡ðUB|v� € € € € € € € €@ à«„…FÀW ñÙ5 € € € € € € € €P€€¯_%Äg× € € € € € € € €t@¾JXhq¾vmo‘ o,“ õKeãKeÛ¦¦æbßÚõ}”�Çž"‡7F;þ4ésèg÷­’@@@@@@@@  ૼBW�ðµuý{òçɕҲá}é{СÒÿ3¤gß~…&¥Ó¬ß¶s§lýh£´lÞ$]ºt“³nž)Gœzv§ÉA@@@@@@@Ø¿ø*aùÇ øzáŽk¤qñŸäK—^)Ÿ>¢„©ß·wýéÇ›å¹ßÞ#;wµÉÅ/ß·Kê@@@@@@@@ˆ(@ÀWD¨öX,NÀןnºHö´l’³¿}½'Im›ß•ßýi¥¼Ý²E¶·î”ÖODzØO}n€ z¤Œ=e¸ ìæY¥Ó¿x}ÑS²ò™Rõ‡w¥K×ý,ó�¾tÉ  € € € € € € € ° ðUÂr/fÀW˪?Ê€KîÏ’›¡ò«ßþH®yP–e:×G|u®ò$7 € € € € € € € €"|•°5àë­?Ë€ÊûLn†Ê�“ÿYFìúD>‘]Rÿòórÿóï¦sùè�É׆�~Ý™ŸðÕ™K—¼!€ € € € € € € €û§_%,÷ö ø'K_ù®œ î`øæ_–Qßÿ��Ó3oœ& ¿1ÜÍõîY³vƒlÚÞ&=z÷‘,ŸØOº»KØÏÚvï”¶¶nÒ«g7s»È�òî†Ò£_<ðPé•Ú׿õëä��ŸŠôè.}úö—Ã;T1Ëýµln–÷?Ú"oéÓ¿�þ¹AfÙ %wKëŽÝÒ½çvšÚ>i–·›Ìz»’ë9d�ô Þ…ðäÉ{ € € € € € € € €Y€€¯–^û|�&‹k'ÉÉ}tÆZä×W~SnX*rž øz<ðõæ‹”K¯¹_^׋ZÏÇ|]ÿìrò!N$U«üæÊoȵò ™i™Póßé5¦=ò�üû°-ò‹›®•ÉϧßN?9oâdyøÚS¥—óΧëä·ÿÿ2ùIwÖ1磧üL~8a„'ج%5sÙí3~)§¼õ¤üß;:‹§O�ÇŸ¸YÎ’ÞCús¾Ò33Œ�7®¿Ú§È·ò+ùuÅÎÙ¾>]#–ß 4Kg¤Ë¼÷ú¢§då3 ¤êïJ—®¹f1Kï’' € € € € € € € €ì³|•°hÚ'àkœ,®ýnö¾Ry^óâ¥úšûíÛ(zŽ'¿úî×ä›ÿ04¨å|ýꑇäŠcS³�Y+ín–Çîùo©zОžË³™3/1³ˆ]ûeÒS½ºü 2múUòïÿà{Yk¥gøW-›îü'Q{6Ÿn”Û+¯”¿eÝšòçæÖ”¨ðåÁà € € € € € € € €@§ à«„ÅXÌ€¯øÙØ-›76Kk÷þÒ«íSiëÙOè œŠ´íÝ;esóÇÒÒ½·ôÚ±]Úú$ŸË¶sëÈ6ï”^f™Öm"ö“î‘v}!føŠnÅ’ € € € € € € € €C€€¯–Ó¾ðUB€vÞ5_í Ìæ@@@@@@@@öº_{�ÜÝaœ€¯…7C¶®k�¯\;YºvëænŒg/ÿ~¶¬Y¾Dªæ¿+Ò¥KÆç¼� € € € € € € € €@G à«„%'àë½Å’gr…8ð³òÙa#äàAƒ¥W¿K˜‹}k×m;vÈ–ß—�Ö½+Ö®–ã¾:QÆVß¶o%’Ô € € € € € € € € S€€¯˜pÅX-NÀ—µßu¯<#o.øoiz­VvïÚQŒ¤t®m˜Ù¼3JŽ:ëŸåØóª¤KWfBë\Ln@@@@@@@@�ýW€€¯–}Ü€/'É{ÚÚäÓ�>��Û>qÞÚï»ÐKú,Ý{öÞï-@@@@@@@@è||•°L ø*aÒ3v½ä¾[ì÷¸}b o € € € € € € € € P4¾ŠF™ÿ†:KÀWëÇÉÿ\2Êø—Gë¤×�‡æ�Á € € € € € € € € �S€€¯œDí·@Gøú¸qµ¬ynž¬}á yÑ5’سG^ÿÝ=2ü¬–áã¿&Ö~xl@@@@@@@@�ýP€€¯úÞ øJ$öHb·ùoO›ìÙ½Û<î6�mæ=çÑ}ß~Ï,—0ŸïÞ¹C¬Ù»Z?nN=nJ>nùH>~ÿméó™ÏÉ‘_:OŽüâ¹Òwà`[²eÃ:yç¯0ÿýQZ?i–ƒ.½ ½úŒûh=7³€uíÑCºví.]ºu“®Ý¬Çîæ±[ò±kò±‹ytÞëÒµ«Y¾›H—.%,5v� € € € € € € € €@éø*�½äðei}òþi^[/[Þ}Sv|²YÚZ?•¶ÛÓ�»¬×©ÿvïlµƒ¶¬/éÒÕüßúÏR™Çnô”n=zI÷ž½Ìs뿞ÒÝz´^÷0Ÿ™Gûµµœúü€~ÉÁŸ!=VèÛ?«ÞŽ­›eó;«dË{«e×öÙ½£UÚì4Yé2ÿy^ï0ùH½o>³ŸïÚ!{̉= ;HÍ \“DÂйiíÑ«�t×ÿõL¾îѧ¯=ÃØ¡Ã�—CŽ(@ÀW …€¯â³k@@@@@@@@: _%,´|¾m;Evï’ÄîÝ"‰D SÞAvÝE¤K×î"ݺI—î=Í ó € € € € € € € €t`¾JXx‘¾{dOë§"{ÚJ˜Ú¾kìÕµg_üeÀøC@@@@@@@@ ƒ ðU‚‹ðµ§µÅÌìU¼`¯ÖM ²´á#“ó2ü”12¸W öæ®­ ¯Þý­i¿öæ^#ì«UV½ôŠlÜeJäà£äô‘ƒ#¬“\¤iåKòö³bßÁrê)GÉþR”‘�X@@@@@@@èd|•°@£|Y·qLì0³{ùþ676Èòº:Y¶²^¶ln•íæóÞ‡ ’Ï?FN:i¤ŒqDhðÏò{¾*c¾_koñ§‹ÖÊ�§ìÛzç}Ù¥{ébÍôµ/ýµ¼$gõ?Cž³Ò4ò.i®»N‰”¾¹ûÄþrýJkáñ²xë"9½_¤Y@@@@@@@@ ƒ ðU‚‹ðµgûVs+ÇÝéTnnxFn»þB¹ë¯é·BžTÈ= ~"W�–ñùÊû¯’“®Ÿc¿gíZ¹î¤ý'àËÊt×>™Y¾ºd¸”ì�–WMÀ×èX_³Îï/ç[)Ÿ ˶>!§ðU²bdÇ € € € € € € € €ÀÞ àko(‡ì#RÀ×¶-éµß^p‡Œ¸øöôkçɸs+äó¢nÁSbOöä|`ÇýÇãòäMg{fûÚï¾z™¨¨nÝ•R©Ÿ¶É{«Þ��­[:t„ûùhó{‰´_¥.;ö� € € € € € € €ì]¾ö®·goù|m~e† 8ë&wýã/—y3®“!à+O0G@@@@@@@:¼_%,Âè_ëäæ~#å§NZÿåÒø_e°ó:ã±Mž½ó_åoy*õI¹<ýÎäË’/uÀ×=K>�«Žo“U¯¼*Ë×®“�;wH«ô—“þa¼ŒžZ!cûæ�–M²ò�ziX»AZvî´—èwÈ09iìÉrÔ€^™k´n’Uoo�]Ò[†?Lú™Ù©V¾¸D^_ó¡Xk÷4BÎ8}Œ vnIضE–ÿm±¬jÜl>?@r¤Œk>Ø´½³<Ò“OÀW[ËFycùJy³q½È˜]™´|v˜{òq&­éH;_~MàÝÛoÈÊÕoÊúõ-vþä€~òùcO–8å(ÏlkÉÛ¤éí·ä£OwÏðÕ¶Y^úË3òÚ;›¤W¯^rÀ¡Ÿ—SÆœ&ÇînføêÍ-}ú¼D@@@@@@@:³_%,ݨ_Ÿ¿C�ëÜÊñrymÓ�22,ð)�Ÿ-rwÅ0©ùkò�qÿñ¤<{Óö 7à«L~tß¿ICõ÷dvz=÷És;ȇÌí �¬ä'm²üáÛeLõ�g—Þö¸ÜSã]oåý—ÈI×[h&ølÉdùãØ¯È]¾õ¬—sê>�såÏò•/—ç3>¯�'ßx@þiˆÎ|þé‰ðµYþôó›¤â33Rá¼1aÒlù¯Û/‘�Îæ±mãKrkå2õ9õ¦çéeòÄ÷Ê„c•jë«rVïÑb¯2ò.i®»Nœ›:¶½÷¬Lz¶<ìÙFòÅe?{PF®ü…üàaëFždÙÖ'äµÙ€Ux @@@@@@@@ ƒ ðUÂŒðµ^ý·ÏÉeÿ“Lè„»þfnÏX)ÕÞÛ@ÖÈÚ–[åófM7àKo¦L.ýÖi²uÉ,™ÿw÷ýq?ZžýΘôï-ø± »X{_.WŒ=Z>ýðe™½ Úm$Ó;¾B®)ò›ÿqf"K’|ò%óùá¾ÏÏý�l{ìÂô,YqÒ%àkÕ#ß”ã.uìFŽ¿LÎÑGÖ/ž)ó­øªÔßeÖÉC—›LXmoËäGËÔä+ûßñ—])#ú|*‹g>,îj¾à,ðõMðeïm½²õ‰êd�]‹y¿ê}{k#åÊIçIŸÆÅòˇŸs÷bí~¥o›î§ùíë½ä¸#�’q_ù’,÷öüŸË÷îÿ›|2¾|ù™÷å–/ûtVÞ'½O¼ÚÞÀ„»–É×�’ÜX`À×F¹û¬Ãäúç’‹Ì~k»\âD{%ß’�Ïš³³SfÜÒ1¥Â € € € € € € € йø*aùF øúðyùÚ ñÉà#“Ö'ßÙ,ÿ4 j¢×ËÍýŽ“ŸÚ‹—ɼ7ž—¯éî™ákÂ]Ï™[DŽÊØàÛó&ˈËîµßŸðs³Ìw2—ÉXɼáΦ³Ìû-&àë TÀ×M�­”Ÿœ{„guw=‘Ÿš³­3õ·òá«ä¤ê9æïvÕ"�OÝíºëå øo°Õwï}Fn¼ìLÜ/5[Wàž"¼©»r|é 3™$oíº]ŽòïÞlï|s+H;0�€¯À" € € € € € € € €@Ç à«„e)àë£å_|1u»Cï¬Y¹“=�@IDATÞ"3Ìí ¿“¾äïå˼_÷Ô6ÊU'Ù÷Gôl®µáé{Ê¿Ûïù¾Ú¶¬•§þ¸P^zy•Ôø–|ü‰Hss³½ìÊ¿[³pYn€•õJ|ݳÄìóxï>ÝÀ,‘;Mš®ó¥ÉýÜ»]kÛù¦'wÀ—ÈKf†±3®O†RYû°þÆ_v¥|íìs¥üKcäÄ£gÌú•\ªMÞ~éIYðôKò÷†¿KúOä£�>J~$+eåÊäÓœ_*8Ìšelë—{fDKnÅÜzò|sëI;™ÜÒ1…Ì € € € € € € € Щø*añF øÚ¶ÎÜ&qHú6‰K×?"'{c¥²ä`‹Ü]1Ljþj-âJ¹ÁSVp•¹]ãIÞÙ´¬¥7¿x‡ 8çvë©\ñÀ¹¯r„ýü½¿Ü-Ã.ø¡ý<û?îþ¬åtÀWÐ>s¥ÉýÜ»Ý8é‰ðeÝžòÙû®—³¯ž’Í r×ÿ)ß™0Ò üj{[~þ�GËž YE½�WÀ—™áëýÄí¾ÛgZk‘Y&àk"_J–§ € € € € € € € €@ç à«„å5àË�¥KäG Þ�ÿ7(Zª7=#'y¡™WÊú«”×6Í�‘½ômþZ^›!•ßd¯éÜö±­ñ éyÜåö{Ö?#ÿe²ÜòͳdÄç”>½ûHïÞÝeÙ¯¾.L³fùòfµGÀWÜôD øJf³mó{²tI­<ýûÇäÖ™Þ¿¬%&ܵXž¸îtó¬Uæ_Õ[ÎOLJ�”I÷Þ*Nû‚|PéÓã@éþébù¿Ç�o—G^_#ï’æºëä�d’Ô¿|) ž"€ € € € € € € €û…_%,æh_[dÕÃWÉñÕs’)ýÒ/dÓS‚23âΊe>;÷7²í± ÅÄ{‰~?èö‰Ö–t€–sKG½Þ¸ÿx\ž¼él{{ÖòÎߟðEùʯ÷NÀWÜôäðåäË~lk•¦·^“ùÿ=U®žê�”'ÞU&Z'ßì=Z¶/O¼û”Lø¼¥­þšæË‰‡Çøšp¯¹¥cuÀ-ß“É'•©vD·tTÒæ“ž>(Ò¥kÄ-›à©–ÙúÉ'²ÝàtïÞ[zØßä×Üþ2ì¯u³¼·a»ôïßìÓ]xˆx Ú¤¥¥Õàt—~½²lGm¿us“¼ßÜ&=zt7å|  ˜ SKñ@@@@@@@@ ³ ðUÂŽð•0U‰�&8ˆ¿¢téÖ]º˜ 4þ@@@@@@@@èˆ|•°Ô¢|‰$d�=Ëמ¦´óìºkïþ"]»už ‘@@@@@@@@�ýJ€€¯w´€/“@sKÇ=­ÛLìA_…W—ž}¤K÷ Ùë"€ € € € € € € € PR¾JÈ9àËJc"!öíÛvø•O™ué"öm{ôbf¯|ÜX@@@@@@@@`Ÿ à«„Å’WÀ—N§ þ²nõÈ_�.]#,Ä" € € € € € € € €t ¾JXN±¾J˜fv� € € € € € € € €¥ à«töBÀW ñÙ5 € € € € € € € €P€€¯_%Äg× € € € € € € € €t@¾JXh|•Ÿ]#€ € € € € € € € Ðø*a¡ðUB|v� € € € € € € € €@Øg¾®ùjkä+,É�=ö˜½�‹/¾¸° ±6 € € € € € € € €ìÓÿÐËÎçÍ—õÌ+¿sæÌ‘#FHß¾}¥k×®Ò%aþòÚBja'âì;ç~gõ½Îܹsíô_tÑE:$@@@@@@@@öŽÀ= úØ;"àkïx{öBÀ—‡ƒ € € € € € € € € �C€€¯@íù1_í©Ë¶@@@@@@@@è||•°L;{ÀWëúÕ²|í&#ÜC†�i «'a臨ݶMÖ6¼%}j�Tö�A‡AŽ÷ì"ŸôîÍesìͤìûÚûmvß*ßàü3�ÅÜÖ~P!÷‘,îocнÇÞÚÃÞÏCp?¥Ô‚ÓÚQêwGIg”’è0Ë´®—¥Ë×Ú×°s²“ïs¿§Æ/Mêt|»à5ƒû¸àeyØÿøj�2ßÓ"ï®Yo–¤Ç!2|èg¤kÀ~¢|m“/¼d�4|´Œv°ùvµ¼¸ì=³ýò…ÓÏ üÙ²nµÔ­\!¯½þ†|¼y»l7iè}È 9bØ12rÔH9á˜ø�ÙÉxkÅŒ rÖ¤Zûý) ×ÈucÎX†7¢ l[1C†œ5 Ïèd¥]rÛR™0ä±[@ÙTYS{•ÐJ[$í»÷6yáî*¹`ÊSj7e²°±VÆÄ Î ìC©WÊ7àé~éSüºgÉîsÇœý²lêx{¼Õl;CÚ£l;Ø6�{,ù$7v?[Ôú¾Mf”‘Iõ&åûêx5,¿!ïïõz’Ž|êBG^v¯{wT¬°zö¾ÉgÛú¤ªìñœ]LY(µ×�é¨ ÁéÎb¼ï"°×Ûì>V¾�ù/f‹¹­B šuó¬ym�…:C{(Ab×Ç�´ÆÞ^`¡¶ß›%�í'°÷·¬ÏGËòcî7ãÔŠ…:]^Ъ!}\Т¼‡@û Ä�×h¿4±e’|µCMh|i¾¼Ô¸#¹ånGÊyÿ|ªôØO¤€/u s^›ß!#Î�jo1(�jËêgäç7\$÷%c­öì¼U!Óæý§LóŸ¥æ�Ìbn+ï�wŽJчgƒÆU-E>⦵ðõBŽ�¡=”  ì§¢RHZÛ£~GINØ2amc_KgXú;Óûú|´bê"™}Õ¨ˆÙ+Õ85bòö‘ŨÓE.ˆ�>®È{asdˆ¯‘}ƒ|Š@ñø*ž¥½¥ëWÈü¿6H·n"»w›·z— FKÏ€ýD øR2gà¥cé €Ôö×>u‡Œ¾4 ¦wY^Q!ƒÍ¯?õ”X?àÖå“æÊœÏ.zà•u›’†¦OÌ®zÈàÇÈÁÝ“{m[ÿ”Vv©yQnf¿™{ö�‡ýáy¶rßò_HKRçTÛ•rð5Ÿ€¯BÊp__W·Ï²ª™òÇ;.L÷yqÓx‘‡z•�s?ô)¤îeëõvýc�ì…Ð^ŸšÛŽ­n�O¬;8XŽ9¢AÏmòÔäÃäÒûÌÄ6yþš±½rÙ~ÛÍ–×ö°m¿œny?lû�üͰs3ÏM§l«ñûÙb¶YðµÏŽWCòÒîÇOíÚ6BÒ×®ûÜw6¾÷½­¼gë²}VB·�újå%x|³M4Á˜7ØÓ{•ÉÌÚyraÙ€vÏ@¶±aûí<Ì`-ËöƒØ+[Þëm6´îï•ìfì$8ÿau0cõos[v×é)M»ƒÆ.M>⦶ÐõÂ�� =”  î§"”RHZ‹_¿#¤%t‘ð¶±o¥34�ê}>ê|ï-ƒ¥§FKÛ¾³uºÈeÒÇy/l�ìª:ý¦îK÷�ïP²g�O;¯_Å,Û=É¢ß=+›ô6÷bÀ×–¥3dø9É[þÙI(«’Ù¿¾NÎ:ÞÌ¢• ¶².(nZûŠ<ò³eÊ7ô«bš‰âŸ5Š_g0ÿç›^03”]`¥UÊ¢¦ûdTÌÙoòßsÇ^ƒGüò+I�S+àk� ø*FxB|ÖlO�Õ�×ÈØ+“?ÁŸVÛ$ãNë¥x‘ÇW¯$T`ÖSŸÏþÐî ©{ÙúÆý㘳^î(/“©f8T1­ÖŒƒÚsÆ _]Ýë/;y^}mŸ¾q¯W°vÞa笿ûF?ë øêPÇÍ�v8~jçº?o¾4ÞÙú„lŸ•°¤BêkhŠÚVKÍacÅ>»¨˜.M³/)úô‚ö�ml´|û¾·�–eûfºÝ·¾×Û¬¯î—ú8³×óßî%ÚÙvÐYÚ}gÉG´úµo;¢¥9òR¾>loœgÆî§J�ÖÈŽé÷¯¶‘Îö>úDŸ�:� ‘’Z¢qj¤´±Pçè}\çå'g)U�~S÷¥|QSJ)@ÀWõ×üm¾,kJÝÊÑÙn¡_fúãKÍ-Œì»l¤¦VÕÈÌeMrá0+bj�Üvè‰r§³ßÊiRßDä¼Îxl“î®’ ¦Ø?5Ÿ–˼†ùr¦ó£ÑÖM²zÍÙenF9¼l˜ì^·B^xéï²y§ÈgO:GÎŽðëÒ¶mëeí»Íö6�&·m‘µl”•ß —ß™¼ßäôKä ³Ï‡ÈçùÕjf{½îMiÚð¡´ì<@ùìár쨓³Ü’É vk�ú5oɆ[ÄdEä€~rÄ1#å´�[KnZ»Z6l7 ‡•aƒúJ릵²|ÅJyß^?¹Ï‘£O5iOGÔeHçz#j>t¹O5%W•u—uõ¯È«õï›üï”8D/)§–!a©iÝ´Z^~q…¼ýÑVéÙ³§É¾Ygè±rœ Ìž…VY½ôeY±òmÙjÖ3k&½�?脇1µmÛ$ uõòÖûŒõ†¢‡±Û]žõ®ÇK]'"·ÃœuoPè±Àt,9�ÇE9æ«/·�ÚdýZÓ–Ì1Ù?׿.E9VoY·V6®_&7œseò6‘UÓeÉu§Ê®63î9Æ{¬‰_·‡›cänYñ ò÷u›ÍÁì9ç‚3í>?Nšu=s|­Ã_ßÙ`�¬Ïú2LFžš9Ê�×p[gŸ‘ëej…‚ógÿ@!�1›nûyö�NÍèÃŒ«^—7ßm’7·¤ÆUÇÊÉf>öÈs|¤ú‹¡f»}ÅÜþdñKR¿ÖŒw¬2üì9íô1fŒ”J•;¯xq±¬6õÇ9ícàɧ™Ï} ò{ãxܶe½™©·Ù$¤·™©7xœ¸eÝji2Óîõè}˜3Ì=žûÓ¥MZ9Î8w0ã£ðúÛÕŒG÷˜ÿ™iÿº{÷ŸÒK?Øéi³^f¶ïôBžl[¿VÞm¶6Ô]’åç]ÉÊçš mf´+Òè°Ì±®u.ÔÐ$Û͇šÏû¿û�{»ö¼Æö¹Ûlôúì øj2?Pè¾m�¼òÒ«±ÏwŠídµ‡Àþ?¤ÝŽŸ¼E•ãÕ6Y»¢NV½»Ñª]Ò£ï`9ú$û|/YƦ{*Æ9ÇYyô2ã×FSÎ…ÕÍ|�=92å~œÇñÃ])ü™öNþèa·9o\&+ÞYgÎãvˆ9ã‘‘gŒ—1ª�ÈÜZô±WxŸÐ[>Ó{—|ñØn·‘|Î3TÿëúHH}µ~�ç¯ßvŸ“±çÞ�¢ª–K®�»Ú¤ÿ`Ó·xNÜ£Ûeº«w"Œ ÕÒæºHÜë z+ÎóƒHe™:¯[e®ñlK^rèÑ÷`<|„Ÿn£Î~r=ºéè}˜Ù“²mæü½îïoÉÆÍۤŬþÙÃËdô©eY¯�Äo»ù�)ô1Óª“&µ²Úô]o5m”mÖ…;s­§ì”ÑRæ›W·Ù°/$âç!ÀX×ýÈçgV½.¼ HMð-ÚarVŽíö&5çèþ±WzÛ©¾ÁzÝ{ðpûXáoÓβqÇGÎúÛÌ8£nÅ*Ù¸Í>:É`s�ì$ûú_«¬­_“_d»ÖælËzŒ?Ö+N[Ñi±žgëßýçgV祟ÎkÝžô¸7N™å“�|Ûš›žv<ÏÌç<,ç±£{Æ1Î1wó+K× îuú<¯ê>¬€óÌ|ê«î§ó[…¤5¬~»e�ïØ×]³˜×%ºû¿G ¸Vžïø£Ðú÷{ %ð4ß:è~G—<5}þŠå²ruô¬]*Y¼RÌ·AÒÓ|?sÄ‘£dô˜c¤çêG䰱רitìy+ßqj>uß 0óø>2úžç±'¬íZ/ÍMÏó<_õaà‹¸iŠ?–ÐÉ0eåZ\HçÙRÜëÐùž#çUWu Íó6S~ ­¹²”úÎÙ»„ù|uòs³€ºîà.µÅ\›jjö_—°>�Û.òì—ÔØ¹ ó¦<Ï)ãÖSG®(}zäx g¯<"°÷Šð%‰˜ÿùPkÂú¯¹¹¹Cÿ÷þëO'f̘aÿ7kÞÓ‰?Ïù¯äëYO'>É›³|ö¼7$¦”IÂT‰„xÙF�µÓì×f>ŠÄ¢¦¤[üI©÷¬e«µ©÷³o{MbjyrÛÖöË'-H—Aí´Šô>fÏ›®¶- sÛ£ôrÙ¶¿hjyz½)‹Ö$MM¿¶ö§ÿ‹ºÍäþê3kœôy·cm³rÊìD£Ï|CÃÂD�Ê«Þwòyebö’Fo¾šj©t–O]�X2W{÷;e^�w]ßþƒ�òˇ[î’˜:oAbj…7 é1Ú]œzWŒãeœv¨ë�nSÉç¦î5ú�îëlë:Çãö=æÔ‰,íÌö1eØ–D-'͉Xý´nûùô�©z×°p¦[¿œ>;ý0F4ëŹýEyb^í‚DuzºžHbÖ²¦DÓ²Y!iªHÌ­krÇBžúT¼ã±Ÿy|QuKß<éɯü3÷©ö‘a5Öó¦e³ÓçþüOš5/1­Ò©ªÎùÓ§_«óuÿ¾šU[1?¾Ru8W¿ãjç?ßã‡Û/g¤]yºÞe‰IÓ§¹ç?év—4«˜¤�Mî¶ó{eëŽM|çX§|ü�ÞqQ~ûL¦Õí¿Í¹[œë#!õ5³~gË£÷ZLœ|„•e”±arÝ\õ3`\ êKàþu›±�'٠ܲ\cΫBÇsV¨HÌ\Øàë«Ýº—‘�Žªé‰¹ÓCÎoM{ ¾&‘Ë&¼í6¦�Ä´¹³Õ!å5Þóf·ÍšëJÎ9fºŒâç!ÃÓÙ¦®ûQÏÏtYXýh�ñ�ù×ûK�ij§¹×/ÊÍ1;,K¦»×&Ë­k¶Û²×U}~þ×s'¹ûñŸÊ'%æÍs®›ëº©ëÆaéÕïgŽ»üíCµEÏXO�—Åj+þýX¯Õ¾|ÇûºŠªqÚ‹ÎwÐó@‹Xe51Úš'=íqž™ÿyXÎcGX{Hõy—¥Ç ¿ó «ÜKqž™wM:Ý~*ϱ•ñN_¿WçÄ�õ;U±Æ¾öºùŽ+s·�lélnÎÕfÆÕ—¸ßkõoî{qê ;-O,XV›˜öýVÅ”€ïƒšó¦º×–=Çóýáôé“fž{ûÕùÞ1¨�tßËVŽÞqj¼ºïë²�·ãŽ�ã×÷x×ëtAõ2æùjª½»åèÖIû½Ò˜GÏþT�Ñc‰Ô2y]»éã’ùÊÕG„�ÃóíË’vn»Ì^WƒÌ7ÔÍJ_’ê¹c̦%ú»ø kXæ;ýô¸¿"·]Äé—<ãÝXcÁ\åµ/÷éÑâ5‚Êž÷|}�§¯à³bÔ'Þ*ßp­Ç{,±|ùòDCCCâ­·ÞJìß_ÞLÌI{͘1'ñæ¦Ï?” þšQpÀW“ œ©NTUU§ƒB¬ÁIuUU¢ªzJb‰hÓ”˜™¾øli²\ŒðWš5 uVM¢.ÕÈÜ“ ÿÅÒèô6¬ IMK‚¾L+³–Õ3—dÜüiM¾6_J¨¼ZÕòŠÊDeE™{ 4ï•™ ’ôú拞߃òJãWU™Ô&¼¾ I�‹’üÓФEYye¢ªÒ€:>¾usvVùçC)äÐË•¦.TøûÞ‹< ‰iê (Û¬²:QSS�¨ðåmÒ¼z×ÍäÁ[?L^ËÊÕ55¦þùò_6%Q¯ò¼d¦÷dÂ6³ÒéÛ_åt}áÌ©/Ò¬t–UT%Óé)¿2û‹Ðtùªýúß‹Vçâûø÷çyí B}y«? ×èƒZ\‹üëUssÌü‡´� Ó¶üõÑ­¯¦ ¨Ó}Á–V¹éu¬ |•Õõ®z¶ &Ón9žÇí ²ìÃJ«sr즹,Q^nú¤²šÄ’µê‚KEp€–nÛú¢»¿µë—S¯¬6¡.àxê^PzÛ­¼bÖÕöJ�ã£ÝÅ­wºœÜ:�<6xûâlõ3ÿv˜³îeâºû·ÖMO¥ûWïñX×K7_QŽ91ëDP½Õï9ek¥W·¥�ºÖ×&¿0jL̪v¿ÄqòWf·ÛêôØ*Ö1ɤÓ÷ÕÁä>Rc…XiN–_Ýl_°—9.W™~Õ?2·êNÏ#ä5̶ÈLJìe’ªŸqûi�‡|úFSÇkõÅ«í–'*+ýcD ¥|âŽ�û‹²Š€qe²±ëMyÀç3Ýã_H}*ôx¬Óª�MîñF Ü&“培Ïlõ÷ÊÄ]׺ãÿêÙÁ?¾h\ä~ *&=(ÈÜÍ“ÛO½W?×m5s½cf+x'ý‹}ŒÎ ò^8Å?›Yš=_N?d�yr�íu}×ö±ê³*ÇôñÀÔ¿�ó�lÁÄŽY±�¬‹‰i[�_ý¾j÷™õ({¹:énvÚ’r:Ï»¯p«u:ìômHÌ­vëæ¤yÁ' ¦¸ã]3¦MÖÍv:†šº‘ÿñ#š›öΨǾcaùTïÇò{eëþ-1õŠ\Çvó%IÌóŒà|&ûêHã=]OT}ͬß�‰™Uù0Ç{뜣zVòºIÜ|¤ë»c™çQƆ±Ï}ûÊHƒ¶±ÛP¶rN�Óü}®u¾húÎÌë4•é/A2öëO—“_½-3ÇáÊ€ë?Å9�Í%¸N–%*ÌÆÝE·=½ž÷øÞNýO¨kðuµ¤«éGkÜ~´˜ÇøÀü;i´úÿÔqfCÝl÷<ß\ïÊü±¢ÕGº_øXÇïÙu&<`[vÝsŽ1õ+ØA¹-Jÿ 7ÙçØÇhÿ5¹Ô±+ÚöÉþ=ÐÂÓ.Ô!èø›‘—(m%ìØ¡Ý›´Åƒçjÿ�±Ê,J>b¶5S·Úó<³9ÆyXÎcGX{ˆ[–±Ê$UçbäÏ®7:úøíi+Áõ:n}Õõ1¯±UHZõö<ý¾ã™ïØ×ä=ÿqeî¶šÎ\—ˆ÷½Fp=H÷?1ë vɨ¾ïƒüÇ€Eê‡ÄÖºÎ÷,å¾þÛúÌ¿n:ÝžºmœZܺïoÇPß‹‘ŸtÛsÒá+ƒH×Ëœuc´ÙàòLÕYg»1Ò¤ëg:�¾:“þaœK˜eò¾ÒÇ5[ ÄüN1ÿ¾,i¦óí¶Ko] 7¯SßUOJï,_;Ýû½êT59€½Ìšî5ýÔ5®Øí"f¿”ïfÔ™(cÁü¿±ó]@=-nŸ%^#ÇñÀÓFXÖ©û<^ø*¸qmJ¼4Âöt_“~ÞNå·®Z_ŒëþÚ™²(õGûäÕîâ×;]öö”ÇKOÛͧšº©÷ï©{9ëmö¾Q×K+_Q�9±ëD®ôê²Õm)£.ùúÚ,Çê¦ôŒ©™·bç#ãÔü*iî’ÄšÆFó_ª�Œ�fý¥’$jfé éæDýØbêÑ"ô—-¯éu«Í(ÛØõ2vþÌ!ö˜M„¨<¤ûÀÐúUŸžIתçÕÓ¹A¼³Sš_Þ%2âŽ�šKÀ:ßY¤Îw}ç;þ‹�A†Ev ÍoÈq!¬yÊ2 Ýz=)›”X¢fY¢Ï³l'u�ÏŒ��†Þ‹ÒÎø/ö±' ?ÞüÆ?~x·“ÙN6'Ë#~>²—gö±aìqA®úb�­,u+¯™ííÿ}ÇïÊ™Á3™gXèt8ý¡¾þ³¦Ö3‹V1Îßã_sÑ3À¤¾\²fòRׇj=3p»}–n³NßcY´[ÿ“Ë5äºH{ãó¯Ó˜Ó¬Q×µ’³¯úëÌ3«ÕØÿ9ã�Àm™¾3îøHoÏì«f¶ú±¬uŒN_{K¦Ã{m%³ÏÖy´ð´W5FH»XyQãî<ÛŠÞÐólí¾�ö´/ý^ EÜ2Ëq,ŠÝÖÚõ<³€ó03;›û#c·¯±}u]Ñu(îõæʤç™ú;ƒè×Ôƒûw}ý?tlâX¿M=Õïç5öõ»zÏY­r�{]B§GŸb�?b×S§Ó}«97Šø½†îS‚žÇ­ƒþkþ±ö2ý£@ÝÎLþÓ?š1}õ¤¹úR™3åsü°ŽáãÔø×Kr�·ã��uýʯ¾’7p']§c×ËBÚlöñ@ì1НIçѼï¶��±Dœk!}\ìãj}Y 2Ÿ/H/V–˜«~\jÍxš�K�1õ7,W=s|òGñÛEÜ~©�±`géÓÝ:žY¾|†I©ê_žPþñ½åO¦oåø_ó^Nl²·÷AbÑ^ øªS�9Þ/ørW,=;˜ûÅ„ç×ðb~E©.åÞfÒQ¤Ü¾>h¹fѶ©Ó*‰éKœà·ÜMqƒH*§'/„,›=%QQQaAãŸÁÊÚoø�V30öÍ~e­«Á®/øeÏO¼|x¾*÷Ψ•ÜŸ€:'Ù&jF´) ¼ÁWÉõ¼ƒǵIÏxa~Ñô%Z£ž!®25Û„s”TLw¿ÈTm­ÎL9?iêôĬ٠RAk^“) ÔMéõÌé.ÿ`È­™öºýu.¾Oæ~|iЃPcô«TïEL'H/®…w=§u:3ÛG!ù×®Öí |�Wú×&ÿ3—©@K«LëÝ_Ìê“J¯Ið/iרÊjÔl~éºâ+‹Ôûñû‚àíiÛàþά§ë�>ñViÕmÛí+½'ré÷#lO§Ë}Þåå­sùµÛöH�Ï;�vWH½+üxYH; ©'ª~¹uÀ_�uøûFë—V*x(ò1§�:áOŸïuhÝ×ùÈïX­ó¨û!ë×azæÔüê¶ùrHͪY8ƒiÌ4›àµ)Ö¬ Ö¬¦�e¢o)ç-Óð¼úÚMºŸ*¤^ÆÌŸ©·±ûéÐúá«G¾¶Ñ´LÍ(éŒcô2� Ó>V ‚5³nìñ‘Ù®s:3Hè6ºP�c3g£Ò³9ã<+^ïb�C�kiµßt½ÉLO>ãç°}†×_Ä’šY#�>“óÃ7¸Xÿ¨!{½Ðeâ}®ƒ¶&yf·õÿzÚúò×`¦ÆEÎØEç+¸M�íMÚCê{œúì¯?Aå¥/ÈyûÊ0Çâ:…å7ìý°zä-KÚu]2ãÖ€óL=C›Зž}%¨<Ì/eÝ[¶ªe�úiú–ô—$âÔÍBŽ=þüø^püÈîæ‡H:/zÿæØ¤ÎG�vQÐØK�QüuR·+ÿgíSÏçúHP=±êCÄ÷õ¹x!ùÈ^žª_·‚VUУÝW¨rÌçºBö}†d+Ký%Ë´Zßy¦åjÚà´ISÓgÎJ,XtmA×ÑÔs]açúIúGvñÛn!c Ý׉©“Îlý®·)O]f©€]½^ú³ ±o€¥Ó×ùëx˜«¾uMÚU÷ËÅ;Ææ_—½ÓÔÍroëéΞëæwÑTwæÎôõž�mE9Þ]_ôÌ4VUã kìáï÷Üúà¦Ûy/ÐB—�c*O¿V¦�m%3 NZœÇlí¾�öâl?ì1ØB÷‰�ü<Ó”{ìó0]OüÇŽ�ö¿,ã—Iìü…ä!¬.9ïÇÏcü±•§mª6\¿u›ïØ·}®K§Ów,Ëã{�¸ý®gÖßÈßkäîßâÖAÏ5ó£}‡•d}ÓçŒæ{ÁÔø-çñûè Ä|Žþºæ§êþ?Ÿï“L?”ëújü1püú^¬¶ì޹âöcñóàôKá�qÓäí¯Ü<êö ¶­ú¥X×.ûãøãðæΑsÕÕpë¤�Úr'Ñ0ŸéïUÍ+ù£ç;Ãäº Ò× ­ïGÍuFÏ8:¿ïÒâöKž> ¯±`çéÓs•1Ÿë~€ç{«>ðå9™Í³âmx=ñˆ¾•c:(j/|ùsó™áËDS»·;t/¢è“ìò) UTvt£Ð�zú‹Ð€‹ßÙÊÃóË„šÄ²´·JSSCbÙ²:s¯Q3YSÀ…¿ í«Á‚wp«$fö™  7=èö®«ÒäßgÌ|è2© ü•ªNoÊÖä-ó˄̴ÕÍv/dU¦n ª/¢¦/^ùóâù2à 6Ô_ò˜@§ióõ�9ÊBÿºÁœ¼O—o¦ŒVÜœ/ rw–.N> ðɹ_U¯ì_³{.˜§ÊÀã—º¨×"N½*(ÿÚÕù¢JÕ-�ÿôE[ý¹ûK#Ývô/—jBn�Óܬ¾D Ú¶S¾ù>ª4ë4å,k³ŸàþÎäWm3ó×ùIݶõÉQà6#l/8½íP^qëª].í�k»ÚÇšE"b»+¤Þéò‹u¼4iŽÛO[eXOlcÕÞ_ë2È<ë|E?標ۊݗë²U ¼ñò;Vë³Õße³Ü™j+|·‹Ó¿ôôÔ—uÃͧ·Î¸_îê¸�žSf¥gÖÇ}ÁÝ "ÕùŠÜφµYó¾[?‚h`åÉ_Ÿ½}hð�|âœïÓI·{ÏX*ä¸V�ÂÊÔ~_ŸO›ãWfà„©õsÝÛ{å ø2Ö:@¬Æ÷Ã!Ï—úSS·à-èØã­§YójÕ¡€ÿ\7Ý¿/«×w×3�éÛ {×[¦Î᜶X¬±—³='Mº]ù?+Ö>uÛvö›ó1¤¾æ[¿­ý’�ìéÔý·¯4.ðÖ‡Œ4„Ød+Ký%‰˜™­ç.©ü¡Yƾê~z�ÝÆõ:ž@âÏßÍv SxÚžÓ�è´šçËfêcd²¯Ñë¥�ïíÙÿx\£ŸŸYåÒÇøàü‡Œ#u0UÆ—ìúv<*@Rç·ã#÷xjfÑñÌÎâ¶+=›©¿ßK×o_ݰÞ´ð,§ú��Ç|ÚŠgÛnúu³µûBÚ‹ÞGÐó` •ÿ<Ç´¡ù(¨­éôìýóL}¼òÖ3�®ÌcGz†!U‡â—¥ÞWqÏ£Có§ë»ÊCP=ÒïÅÏ£·mæ3¶ÒyÐcæÀú]ÈØ7B[v÷é­¡m#¬O2þñ¯—Å­/1¾×ˆ`¢ëGàsU×tÓf¹Pè�ôñ#ìZ‡[Nù ‡Õ5+_…Ô}�× ñvì1põ½�ühßô˜Ë$›G?V@ë›§ÎÆm+ÞþÊÍ£>Æ«m«>4Öµ ÕFÒ}\AÇU�Îàçn†÷eAu5§¹ú˜ž=Þ�ŸÒL”155“¬i×ékË*ð/uËñØíÂS‚ó¯Ûºî—ôûžÃémž7íG}º¶àyà5¨œí·¼ÝŠðÕ%aþLÄiÞ?yx‡½ÎwÎý4ïuK»B›¼¹h¾ÔmÚm'ãÈÓÏ“S‡ôN%i‡¬X0_¬,õ.&Œ–ž‰�;w®ýîE]ðioµÖKõàr™c¯R! g˘¾Q×ß&^:DnxÊZ¾\æ5ü¯œ9 »l«P†”ß`oÄÖÈUcŽºÁôrõVKù ÉT™¾\5ÊÚÆ6yÄìï{²È¤uTÔ´¶®�KŸ%ÉU§KãìK$êª"m²véÓ²pÑRYõö*y»i«˜%•Öz©¯O>5.™}Õ¨Ôû*­ÓÌþ&fìO;y×Mm"è!f>ô¾¦Õ6ÊÄ2îUz%eÛm…©g%ëFH¬$¶®~D�½ÆN­“]~Áû³7û¬6åi³[÷–θTΙd—”½MëŸòÊ*9÷Ìsäô3N–㇠’îéOÌ“m¦l‡¤ÊÖ¼¬¬™$‡K«^B¤W/i~bªüÖ)«i¦¬&:eå]Ôû*ÀÅ¡3e×Ç»�€W‘¶à'1-¾!ù·�Hi ®ž¶T·rm[}îÔ9KQ×;)«”I盚௠Ò,Sïüm =Ï~$V_P¾¾·tºÝþÎ,¤òiNF¤q~ö~D¯¸ÍÛó%-õRµƒb•WAí¶ÒcåTûåÓÖÈlw}æ¸Ç«|ë�î›c/#¥9¬zÛŒ®?©‚Ïò ÊÀ9f8}£YKç+ø°~Üþ+J_®�Ü}‰÷-j¿sõ~ÐþL>´C”}†-o—ζ¥f yNòü@ªeÙ†Ûe˜=Èl“g&�—‹î³Že2»þ9©ä}Ú«çû�N‹ù%¦Ürö “!7 S5È—^½Þœ™q°êß1AÎ�Zkv玗õ¶‚ꃧ-é6­ÊL�-t™o/(·ñË+hkÎ{:o…:öQÖŽ"8×]'•êQo+¤ÞŠl’»'Œ�)V1F(�¶µ�Ëa£¯Lî¤j–4Ý9AzÙ¯¶É㦸Ò>2u³ÎÔÍ#LÝ,h\•ÜM®ã?rmÓSïL¿5Ñ×oYëç:×,dì¥ûk_ºîù?Ói-dŸ�÷tŸ©ë^”÷M ɇeþ§ú]Ç­t:CÛHpY‡ï/õ‰Þ¶2ÈV–²e±\:üÜTßïì¡\ªjΕsÆ�.'�>^õͳÏ×éÍ£1òß ÿê² ï·öi†žuc¶½tÙžýO\Wk¤Ž¯f³¢ãµ[:ÿ:�ªš-ókËå©K3—5É…Ã’=¹îפz¶l¸½"y�+t[ª}…Ô¯ :¯ÓVG6-¾[Fœ;Ånþ~ÏiA�zÛi Ï‚*ÍÚEç1$/öÆßV¼ÃZÏžœAÎg:½aq÷«·íZ¨ü‡ä3,½aïv¬WéQcLÇ'ù¨–É3ÍÉõ ¼vžíØ¡ê�öί,K�?]ßU¼î™¯âç1~ÿî9V«´ê´¤ë·ÎWH] û¦²g\Ú6Ì6ã§3lü¿¾äý½Ffy'ÿ6¦Í‚ۋʧjƒÚ3x½ìãæ� $ßÖõGÕ5ëÃ(û ë«u^ƒÆÛzÛy�å#}?|®§÷æ–½nºíéïFCÚžvH×µyÈz¹Úlx™ª:²íÀ4ùÊÛÍ£Þ“Ú¶ª+Ú&ÜUoÇ<×ζŠ0†-´/ ª«¾”¼T.2Iê›oseIÒ}�9Î7U>Ó¿>ñ­Ö¶·a{�õQÿ‚¨Xå¥Ó’w»mŸúãi?Aù´í3Û�¶®gþ¶èÖ»°ò .‡€º¤CÓÜO[ûÐi÷Ô=_=ËL�*瘡ÖÉ�¯€õu^ò®6*=áe«Òâ§ó¢û›°÷=ûÊ;*=Ó�:éçj™<Ó\7wŠïxꯛÎkwLg•}h^­4érsÒô^:ýnY�<39Ûó­šž¸ýtÄôúÛ�n?ÕsëÕÐÍc¶uÂÛœ·ŸqÆG:ßAëêôdÿ\—oŽú”ËF}®ÛG®´„—sŽôd©�aûÔn:�ɲ1·º¬1·9MµÕôÌhæ—ž•Nû5·ân‹áåì/÷ôkµ]çÖŒîL3f¶3³dÓ"ç—˜Îì ê6*-:_Aåí1Öý´*3=¶Ð~Që³gù¶W_»NYïÑ)°�²÷<#‹vv (÷SOžš×$¦”ô±¡ëª_ßšòKßOÏcÌÓ·@ÑÛqênŽÇèçCf¦ä˜Ç¯A¦]ï c…^Ïi¿ÙƒÇ^þ>A·+ÿgÅÚgäz¥Ûˆ._ÝÖò}ßl³�|d/OÕë>'K{óo/¨¬ýËd¼1ÈV–Ö6šêæ%ªÒmÒi›îcEõÔDíš3�G)#½ŒïúGAçïf»º,ÃëUð˜"ʺA帞.ƒýŽÓN#÷?zÛºîçrµ?/þ1>gþ}iÔ3tê>Ž�޾Þiÿ‚�Mq�·�éõØ™óÄ…îõ<�ÆŒ¶æ[/÷¶UŸ ]Bó¨�Þzk·ßþƒÒ—­ÝçN¯µï~�1xоô{ÁÛÉ¿ÊGXzÃÞ÷Ô�¼ÛšJO;œgZ·Â-øÚyÄcG°·®?ae© t�ŒP&±ó©¾ûÓ^šþÝS¿”O w¤|…Œ}�wÜqehÛ0ÛŒŸÎ°ëeÔs«ã¼¾×PuP÷-žç1Û˜6 +¨|ª6¨=«çßÞZo;ŸãGX]³ò«÷œÞ°öí½n´®Þ¶3Éþ˜:( ¾ë}¥)YÆÁÇžàuUyyëŸb@IDAT©vªëJ`¹�½íàç1Ó©¼ƒ·­m"_»2Ðïå}\-N_^/2� ÚIúŽÉ[36›ë SË“ç2Éqv£ïµ™±}ž;æ3�rö5Lm™½=8çIîyuû½í"ã¼)¤þ[FAç0qÇÒIóvèÓ£ôû,é:»n<ÏÞoäòqâ­ò ×zì±ÇË—/7wÎkH¼õÖ[‰ýk†¯=å/¿{N6›Ôúròérx�=²'ùRºšHíº—ÿ.ŸZ¯»"'Žþ‚ôؽGúÜùLo—ú+Ú _fî,]"“æÕË�gZ1Áþ6=#å#.’ä¤I•RÛtŸ”™¬é¨msÐJÍÎa{j©ínCG/ëÙ ÔŠaO=QÜa³føWn•§Ì/ò.u&2¿ð¯™ö}©8åh9èÀÞÒ»Gé¾ý¹p쥶�ÜÏðåD�û6¯�¼ëúÔ/cå#J™Øê¨é� >>ÆËŸIHü1[Äôº)O>Óýlúsþ…|¯õ:ám>x|¤Ë!hÝ\Ûv?×å›Ã;—�ú\·w_Ìð•g› Û§vÓitЦµÞÌT[žœ©VÌLJÌLJ[Ôl馜 zT³}”M’†Úå�»'È9Ö´OÖ¯0ͬ~ÔŒ$S6ÊuG/“òáØç•Ó—È}—c§@ç+¨>˜ž?xfdUfzl¡ý¢ÖgÏ>ò,¯ìŒÅs 죬�Gpv Hyȶ¼KêsnÕ³¬»ú‘{MòDÔ©‡kçO–Ñ—ßgoÚÜ^En¯8"¹½óN~ÇoJý¯ 9~ø·å­ë]˜wбB¯—ï˜_·Ÿ�í³bí3,Ÿ~Ïk]¾º­åû¾Ùh!ùð¤)ãEHŸc-–Nß6‚ÊÚ·HæË�mg+Kw#m²nõkòÒ³‹ä÷ ¦ÊSöyµû©5Z¸ÆÌ€Ÿ9ݪ^(ù<$ÞŽïŒuY†×«€}šëQÖ *�ÀõtÞM†‹ÙÿD«;™çgÎd�Å>ÆçÌ¿nŸVá›;*Ô˜;*${òÔ mkeòa£%Õ“«™Ç¬åÕ,òžm©öåyßÚIò/¨Î¦×Y!Ëz¾E_æÞvHšCó¨w\oõAσ œår§×Z2Þ~ƒ·’'Aæ1,½aï{ê‡Y?¿¶–;=ñÇuœ‡…�W-§�ºìm­ ÿ‚Ê2·A°}ù ɃNiÐóøyŒß¿çå)_ÁcßBÆ•Áå“ 4‹”NSó¾×ˆßÜ�ü½†»JȳøuP›�T»P×�´gع¡>ÆúÇÔ!I¾�¥\ô~ƒÓkm"¨}{ûÔ uõ¶ó:h ;6ë\×w½Ï 4%·œŸàuUyå1kß:V�w¿#Vç«Þ…^ÅL“ÙRpõ.‚·­× «Ÿz+öó z§ß3 ås\-V_^/2rày£ÕÌ>85#xͼ¹eôj™0ä\{ö®) äº3xfüj4ךên33Çßi�ðT™ïñï´¿Ç×–yµ‹îñû¥hõ1 ]èó¦�úo!íû}º§(y�À>#À _q¢,?x=ñPjv.g–®(�O®xßÑøÿØ;À(Êûý?@„K�[D žˆh© U+i=ÊÏ«¥Ö¿ˆ¶ji«l-µ­[Tµb­X«hEëÑ⡨ "Gá&dÃü¿3»³óÎî̳ÙLŽg5Ìîïû~?ï÷=æ�gÞ×¼&ž*/‘ã–"X”º¢Ž ¿)Ç>›xì\­8t¾ª$—FË–îDÒ£Ÿ£†m…¡¨º•· S]«zÔŒÄl´©¼Gió×GÛ²~¾6$¤—έr\I«‹âXåd¿6†Ó‹ÂS�Ëâ©Æ£¤×d«Æåú˜=ìQ!êå¦b<:ŸŠ´YcMu¸ò溓ßí-ÖÖ¯X¬Íš26< ƒ,±£Í_/oÝÚÒ9ÇšùË)œ¤÷9p1ðÅë6‹3Ÿhj^ÈwÕ÷\üǦL—<3Þü·¥) êu‰–õš$ýÖv'ûâÙ¯WËNÞ Ë?f­Hâ�l3OݶJ|òD6ɺ "oâp®ïóƒõÊÛjÙv SµÃ‰»CÚ‚¾ª”§ëâ…«ç—Í’ðU#�iH�®’NuÖ{yUâ•»Tü.~ÝÇl“¯‡ýÄÕÔ´Ø9äɬ4*§øv9\o³%YŸ°Ç¯¦Åøîš·J:œ|[X¨¶„ý7ÆþÔÚ¤øé‰[º¤MÍëQS†ûl*«…“Í™ŽÔ Ü¸²µåe²~Ÿ�cž¨yœl=­^ëâ*'ó{Þ,«Í‘A&[0ωܦÒ?RíVë{35�cWó7ïxl”ãjùˆ—–ÒReÖ*ó8éqño��[œ*75�&7=-êÌKËöîÕæO4û§”hãÔ3’+L÷ïkæOõee¯�ë£Þº´½™)ýêõoN÷}çå[÷"ª]Nùm«+̾½žF%ÏԶ΋?Ûâ°å£e¿šNgþÖ¹*¿Úâäf¯Û~7?RÓõ]eêÖ'Þ»B›~kX)ƒêµ‘ 7. ßgbÂ<ñ¯b÷{'[½[»m¨Ê$Ùö#ŠUD9QÖ¥hË�“ÕVß+Ò'�â2m¨­8�Ë«s90ãvóפ÷ ÿTì§'"ƒû•ú[­sôsmþ™l¿À›XyéfGqázmñüYÚØpY…6dÊÂÄÆb•å0¯Âè2lc“\ÙM¥O‘PÙË›n̲b¿.Ô÷IÁ·¼ïOˆ«Ý÷Â3"Ük·�w´?NMæ8wM©¶wY4×øö*6F¶!ÿròy5½nãrùóÌ~ 43ŸÃé ûnt9TÃv®×\úzqxãv(+1Òb¦×‰�y,•òb†á¶ufá-Ïô8\íH©¬ÅO�ç~�š§ÉÞ‡©³ÉG¶j¸Šß{ÏËø Ù«éHÖ>õZÅ7_2÷{·1òž(ñ¾•[ŸÂÑ¿U»’ìûªá%Û¯tÌŸPÝ †®“le&Ùþ‡Gq««b=×p»ÆÜ¯òNÒUfa.f¸ÆV±S)ƒ*ÏY.}ôõ §„Û·dÚ7_Óý?ß�g«ç>°Ê?i·ÆŒÜÚa½îuz>¦æ�•wJ~¹Ô)*‡p¾¤`ƒY/¹o=¦ÉÈï a²lTûÎ} Oc*“�­ŽH¶n¥=•ºÌÙn•�Ëw™õÏ_2ýMm}ÔLñú,®æìñòÜpãkÜkâ¼ðýM­”‹$ë¥Xu€åg}A[~5à:ÝV»ä/Ïq²üƒÜÒÁ¢¶føjZK:î]¯½¤ ¾þö7íoŽrL„É9úïwÖï²9¹yN­d¬º4„ nMžŸo‹Ë1Žõ µQÊ@˜Ú8© u¿c8.•WÜN�Ò M(\¥ÔoFW E+æjcGMÐ&Nœ(K é„ûd SЦƷb޵ôàØYËnÞ;;jøQß½Ø!Œã牒^“mă‰ÅÌôô-žn `MY\ÒÈ>h´Xá¢pWýnÈTe™Íb­pca¸ãÉ@0›³B¿y]£M û¢sÞÃ(ÖŠŠ“9p1}6>‘6EýV;¡.þjëa¢œæÞ# /~•’ý W³“mrÕ·ªýqއo^äº5ó­›ÍQÒÙ�⊣¸¨ÈÕ¿¯I©.P|^µQùî\ßEpP–qRÓø¦2€¬Ö·ŽaÆãª¤I�#îÀ_¼p•ãV~yôU#�éñ›ß%QîRñ»øusÿI©F&&X ú†’f›¡øO|»œ®OÅ'âpR|P8Äõm±IµÅò_÷ý©µI §º/ÿwI³Z'ÌZf‰FÂe]YB ˜ å…—YŽekD=e¦9%¿ŒÏÀ1O$�=÷Ù\ý#¶_©}�QS�Úœ"mÞä ÚXéWN”¥¡ôvZ½fìŒäúGªÝj}o桚DZ�+bõ!‹™JY¶Õ‹qŽ«åCM‹ãÀfá"ë>®Çü—4«qªö«ÜÔ4šÜômþ<«??eΜðrŽC¦.ríK¨×'õ]yYdʬa¿UEƒ‹MûØ©ÊËS´5JÞ¨v©öZiQXªõ´‹¿«¾™¨?§R‡Zét)gµÄÉÕ‡]8¸ùQÌôª�zŸ|o´MEŠpBf ÒÂBi—tãSóp¢¶x…rÿ=y~D_6}m¨Ê$Ùö#&·ˆrë¶Ä›ÿĹ+Œ2Y[}¯È:A-W‘Çj+Nçòí36vn~’ì~ažŠ¶4)õQ´¿*>®Ÿ—R¿À›Xy©§·¸¨P+,r±ex¬kÂÜÄ–õUóBʸÓx“^…û*©Þ¿‹ j½�lŸB-WîeÏzHi–=õ:Ë—ÓWÿØêð$îÏT_­Í6ÞÑ~5ïm}š ï-›~˜9aÎbíÍé×yk"|Ð5,¥=pˆC·×ÉçÕçBõ§ÊÆþ�Ù»à+©¾žjcRe%N]àÂÀ´7•òb†á¶uô‹x}ìéuÊË`Ü©”µø>ä¹_§Öm©Œ�«ý#ác+ÿŠß{ÏËø Ù§bŸêïŠ n¾dî÷n£ýžÈ½~·„ fýîÆÛÑ¿Sèûªá%Û¯tÌÝWäO 7Ü>¥Ôÿðè/Fz’}®§~KÁUfa.!fASìTÊ ­ý°=ï2Ó*/I…_L®ýpó5==©ø~<[=÷�Sð÷Tìqôi¯mK 6˜õ’ûVñ!—zNÍõKµ1™¾„Ê5á± ÇúØ{»jO»÷1Vçri–³X[eéò±S¬q#u"‡ÂÅá{�©s¬±'™)<<Îå¹\¤P/Ùê€dú‚�¥N·ÕÁ±ò˜ÇÜë²I ¾ÒR8wiïÌ ‰¾æ½£ír‰£V_Ç›ŠhGæ�Ó¦Ì[1ˆl¢¢ü…áÆB?Bµ÷Úh©�¦†Ò��‡‘Ë”‡‘‰8¸*Œp[4ÅœÙÚÄy"øR;CÒXEäÅÞ5ó­�@�ƒ Z¢0%­IvvâÙ’´’îøy¢¤Wéà«â*Y®1ܧQMPÄV‹6†üD}#]p1û‹~½šÇæµs­· ÝÞòVo:ÌΠ*:sú, åï¨ Óµü„}GåísžùDøR˜§¹_í„ ß 7Wê›4˜h=ôñÊ‹_y·_áêT>TûãWoJU¡øqØM®úVĪÁYùFiÓ·êפTXugT>‡Ò¥–«¾“ëÔγÓD)gÖCh굎aÆãªr²}OO~yõÕ¸‘ñìTŽÛüGÙ¯·m —»ü.~Ýß¼—C{=¬ú�›¯ZûŸph�ãÛ¥^o=ôîq8©yk«S”tØö[á©¶¨þbÛQG{·#~zâú¿”][ÚfÛn{�ù¦o±¶pŠ%ÞÖýÎ kÀÂ^„­¶u…¡w¿ŒÏÀ–ž�})ÕÓ®þaù�åûÊ>õ�°´9QÂø�f{£Ï5YË×E ûGzüªÝNåÕžÇÑNë¸UæâúS<6Êqµ|XqI]êð€Q}ØY["L5N•�ÊÍþr†’—E¡�°!z^Yj9Ðó`cþ2-//OË[–u_àè#¶¶ÔŒOyK5—ݬ71­´ ™bŸ©v©öZéPÊ’Ò·w+³ºo†‰ú³×gG.&s[;œ\íU|WõA7?²¸šéS·*khS_€±®‘fFYy™¸à«T³õ÷Ãþ"}>‡Y½·=ª-ÑßíL’k?,ÑáêÇÔ°#ÅÆÁke^)—aqD-õ½"ëµ\EKå>C ×¹¼:ó ósñ×dýÛ/váô8–aµøt߬ôCTæ¶¼�ûdÓ§”óm¶ ïð=VÄX—í<•ƒšGRV'ÌQ_ 毭<+oÖ{.»)ô)ìeo¢ÃØZDÙ Í0©^§ú²gT†Nß#¹FöCå;Wk\$œW ¶ñáó�ÒÚçh¿šFGŸR&*m�ú@ÎŒÓ5,¥|9Æaï'š}2µÀö’eÈ'M·õ{Ìë’e‘T_Oµ1ɲ/]ª½¶r¯óM¡¼Ä‹×Ñ/Rè#ŲÃ{Y‹ïCqï „£-mµq¦rŠWP}Eõ{ÏyŸA­ÛçfƒYæÝ¶žmL¡oå’Ö¸þ-å8™¾¯=¼äú•¶ü‰hìáZ÷Âu=.áõ¹FÌz&…1i•™Ún[ñ)åB¹gT¯sj?ô±uëÞ±ö_©ÔÕjšmõÜV%çï©ØãìÓJZÔzQ©KTV»®\—d™µ|Åí~E ;©4Ù뫤úRGZþgK1Òë4çRÇymWíùã½.sôU%?cñߨ¬úbŽcÙ…¾…áåÍãúD( Íç·z<^ËE õ’í6ɾ`CªÓÕñCK3àVޏ?–¯óXÝø_ V¾É9ä.-ï¹�à빺|•î•imÑ21j¢6kÞB-oÅ -?…¶xÑ*ì{{e«ã"¬Óçy»W–å)\¿B›;Õz{IVäÖÖ8¼yïÌ=¶Ïyçãì£á4¨�Ð�M�'þb¿fñ›ÿM}scXŒç•…¿òn¿âoN7ªýqŽ[7/:Sy»AyÃHp4?o�V$~°·¸P[ñæ\E ¨Ïfh½ÑfïT¯§TÄÉk‰Ï¹¾Ó¯³ûߨÉsµü�zy(Òòϳ٢û¿*’t 3W'Û�}éÉ/¯¾w 2ž�Êq›ÿ(ûÍú$±rçÝïâ×ÍñýÇ{9Œå{ñâµûfd{ß.ŧÔ6']u¹š·¶:EI‡m¿e¿j‹ê/ê~Œšªå­Y¯­Y‘¯Jû’6ßN¤<Ê9jÚÌ4Û—ïž*mra¨-_¬Í˜h ÞMߟ<×zP©†i«íF]aèÝ/=æI*õ´«X~àÜFkóÂKÿI_gÈdmá2isdÖ½Žžh>P–úyTx6/oý#=~5œú׎õ¾á3A;¬ãé|Ùg3¥ÍY,)½/'}îyÓÕ>™p³-‹à1ÿÅNË>»Zåå¿a>‘õ¸žŸÓµ�áã:Ã"mF8O‡—Ò¶�ç/ÖñÈmùÐ×6è&iš®ôõñ[[©Ô³neV_.0yöž_ÎeÊb¤¯ N®öº”{7?Š—^k J=¿†ÈlÑr#3¯Y±H›^Â^÷+ý¸R]ÒŽOHÕï ŒëCÒÿóÞöع‡ã…ŸJûVäo•·ÑþH{j¶OÅ…k´¹“1²­LF–ÙÄûü±ê„XÇR¹ÏPÃuª¿#¹Dývó“d÷yê�]Tºl>»oè½_Û?ÝʸÊÜ^÷+õ–Þ>O™£åå¯7Ú(}è�kòlý"ûC“iQóB/«òë>œ]gê½ìzïSD•=™QÒ*{ùÚµìÁš�]½Nõeï6Ä`ªûW’\ÕqË_#}^¯K#Ûø8éùº£ýj•¾°¿,¥ª,îkë/™ÚÊP„½¶°¿µí·Ò­ú¼Ùÿ/-µ–ûÑã2a†áï…²¬Ï›crúqë:+ܨ4†Ò칯§òJ²¬¸¥Åܯ2°—{ÝïåÅ ßmëèª�)©<³÷ù#íð^Öâû�­ï˜LšS¹‹ó²�+¨¾bK�×¼ŒÏ@õ¡pyHÅ>Wâ•1¯6Úú&Ѿ•KZ�ý[Ÿ1Ôza;™¾o*ýJ5"ˆ[:½÷?¼ù‹×çnõ‹±?T™©í¶Ÿb§z�"«©˜ËÅíÇÄYÚŠõú’ŒGçÍ��——ÈvÍé·‹¯ÓäÝ÷ãÛÙHüþÁ«¿§Òö8û´’_¶zѪSTj¾x·Á ÛòuŸ÷4yîKx»pñ;¯íjmÕeÎåRåã»Ã¸Qä‹a‹§G<Ë�ê{,)ÔKÉöïm÷MžŸU{óSïuº:~(ϰ&Cq.O1òÛ©>å¾èû)2ñÌ„‚¯´8�Ìðe ¾êp†/£‚‘å&ç8<ô3nB7â¶ï"âYæ°ÌŸÚ±ðÚh9wjô—ˆFJO×�Za‚y±l®*ì ÄÙl’ð¦,´D N3êùgÍ×f¨ƒøzzŒiÿí�ˆSúTNj,‘Ê>Y;Ô¸œóD Á›Ò%†ˆ/(×6-Ó&:ùMľÉó‚Ksí.Öæ+3­©¬#¿Oˆ˜q,þTc`5ò¼Èßs–™ÂÄÐx>ç™O,Ÿ5î„,:ûªaÛ„9Qþï•E"¶¨åCϳD®‰ö�8åô_÷¹�‰*?Êñ¨²Sœ¯MU…ˆþön±Êž÷º ¾Ÿ©>Y>×,´‹#Ãéw°K}ì¦ÂÍ‘««O¦/¿¼ùjšÒcòñRî<ú]üº9¾ÿx/‡ö65Ò÷b•#Îíq|»ÜÛo>‡“™·QuJ_’2¡Úb«od° <ûƒRÍeÙ¼Ù?=‘ñQõ£[šUJz­:e¢6þô¨vÔX:9–­j¸õuZÚ7ûd¿çz:† ñÊAi"}™QÁ˜ÝKÒh„—È5’Göþ‘Ý�Ê«c½oÆ)[«o­öóâø\<6Êq[ù°-·£c”Iõ¡kœôˆneÒ²Ï.øÒ“b•U3�Õpõr1qnäƒX{½å4{­V¼mx¯!A±¥��î'Ãobg%Uó,èGjz�üA¯+f…ïQ”ë•<‹ê $â›6öž_ñéÇkƒ“}ö?¥OéÂ!^9rOwä,^~?J–w ÷/Ì£üÊC�ÐË CB×[Òè¶Ï[ÛŽÍN•U²í‡aƒ{ø*o«=Š`ŠsN^Ä=œÇ¾WÌ:!^}á1ÎøåÕ�‘‘j¨mm²ûÍüðh‡Í/̰”­c~*c5ÞúÙÄÈËâüù¶—§Ü}Ïy¦rGŸ1óy¸œ;û±—�#ûožËn"õ¶”¡È>…ÚfºÛ´a–RöÔ<Žl{<Û øP[ÓÇáãþ^-ƒº½Ñm|? ¥ÑÑ~3�z]¥–OÅ.}u€ gó% iÆR]Û¬ñP¤ÿèÜTÕ~ÅÆ7§GõïÕ<Ÿ ¼Ô«^•Š=Ác.3—…êl5ŒRúz)–•˜éŠQî�ë<–—˜q µR;¼•µøéñ|Ÿ) <߇ü\Æùc•-OyŸ�[9òl_,¢ÊTD=äÉFû�­:”M[ßÊ%­Îþ­§µú¾i¼�K¸§S˜$ð,(éqkÉ?gñþ\#V]ãÕ –Í ·Vý¤úšË=£Ø·>bÈXþ”Tûáâkaû=ú¾šζŠÝžûÀý]/çíqöiïõ˜ç2¯®J¡�RêyÜ(A®êØE ¿óÔ®ªá%Y—%ä«q¹ëåØšÁËmܨpq¨è:öä½\x­—ŠRì 6Œ:ݽn ×u 属Ïü#ƒºñ ¾ÒRØöjË^ú›f,Ùø\^�-騚5y fò öè�»Q¦hs­P–/´;\Ñ2k–&sÉ=5üD¾¯P:ãs–)3x¯°¿%­7¨‰N³ʯüEs´ N‚™Ñl^ž5SR0�EÚ¢Yê[+&YNfÓÏ)̳϶L�tÀ&„Ε�§Èå õëŠWÌ wº�¦ü�Ç);âçI±67„ùD³³l(íuL©¼E`w\jTn6Í™â<�?DÊ®ÌÖçT&M{œ·^낈´;乺ö¼­¾3ÎÝ«å9¼}«×ÅSdž"<vêå·2c™c�«CÚ‚,Ò›_ÉûjšÒ“r¹KÞïâ×ÍñýÇô×äËa©Û÷âÄ£nŒoWì6'yŸˆŸV³ÎвÍóãø’”‰XmµÓ €ÚïIÞŽøé1â=ö/Š×,Ò&;´åzû˜gLé](Âe6©gL{\m�S¯$ï—ñ¸ç‰Çz:Ž fsÝÉLS"f­ µa§ÏÓÖ;Í*ꡤ–«è¶¢T³Õû+¢û;ÖqõvÞñØÄh�÷n\,}2{_Ì$–Fò ­eDå¥K'=1ʤeŸ,IªÞ;È5®þkk÷Ô%GioF=ˆ-ÒæšeOfMEð¥?е–D�¨…Ò”7Cyøåp/¡úƒYNí>êRÏÆËÓ¤üÙ{~ÙÓjÖÉÛZàTêf¯ËþX~7Íòò”~ßcöË‚Eä^Éè¯K~„ýG¹×rI‡WaÞŒð=£>ƒÂü5{cú%ßöDp·•‹à±TÚÕ–ÈïV?d‚ö¦ÌÜ=ϱ.•·ïïõ´%ß÷ÒÓ«Nˆu,˜þäãŒ_^ãä�›Ÿ¸í߻š•Á¡þðjGdþEý–ôØf´ÓÛˆ±šäûÙÄÉçâõ‹µéŠÐ%X^Í6kˆ6qê-?ò…6‡²f`>¸Ðmž0KËÓgcv)M˜2×¹_ a{.»úêCÄYoæiól3¢‡8 ™ Í]l_¢6^éÙ7¶)ߟ™þ¯�7Ï‹½u´ß­Úl*Ô,¶Ì´5ÙaéIý|×°Rko×ãy¡q²�_;Y›'/Cç«ã’ê˘±Yè¾ï©¯W e%\îlŒƒé�[‡{(/±âÓ�9ú…þÜl÷]êa÷{šØí”gòe-~zR¹Ï4ÚcOcçA¿wl;\ËCÈ7“ÎËø Üóħṳ̂mTÇx’ì[¹ðvöïPxéûŠÿ¦Ò¯t+ã1Ó)q&ßÿHÅ_¼?×p¯o¼ù`AÜgt.÷ŒÂLOËFi?œ^žš0UVVÉ·–uœì4ke(Œ(›é§zðýÄûÛÉ÷å <ú»q­{œ}:¿”<2~¦/“èÆÎBÑü�n÷IGÛã¹ýH†²´A»Ë¥ÿnÜ6fáø^Òç�w½—¾W¬:!Ö13-^â4¯­OÛZ·#±¾a�õ â奴Õ8(…6 ã^€Çÿ½떮ą^„ÛÏéb‹±jýôõÓà>ƒŠ$Çv� 4h..ê«MvÁW¡¾s�”X__ó*¥tv`ÁCÏ`å–•XyðR,š3"Z',˜Ü? õd ¬ôûB++)ñçÅ$Ј °ïÛˆ3—¦Eh þÞlˆÊîh˜Øl˜ùÆT7z|ù˜Å|ùŸQ“ � � � � 4x�ÊÝxëÁIøÑCúÔKò;Gf_ºÖaö¥*¼.E$EGÍÊÃë7œ<Ÿÿ’€Øñö4œrÝ_C,&`áŠ?`ôÀ.Æì^û6½‡_ŸýýàÌ?r†,y‚ûÇŸ@n$@�‰@{pÑT_‰·ñ�ÉU[v`Z§Sn�f,Ä&ŽF™Ý+PµKžý5¾?5¤öÂdäï½'Ø'þU«�ï ¬¬ÔŽÑ …ö}_žÒ"w�Á߃ î9Ä# Šû‚ *»˜Ø¦C€‚/óš‚/á3j     �K j“̸tvhÆ¥°£°pý¿ð­îÎO;ËwlBñà¸þåaiø"~!!°�Œ‚éÆš &�!"‹„Úwqv8“·$Ш¨.êhÙÖTø5vÁ——6>žõùÚÝKÿŒ!ß›aKâ�!Ò:­·µN˜ºh=î<¯æ.m`eÅŽ?H€ìû*0øµÑh þÞlhôŽÖ4 d_°iä3­lp(øò1Ë(øò>£&    h°*?½ÏŸª¤,毘‹±Û*ûø•’ P%KgÝw7~ú×·/š0}¦ß:.zBÇk¸“H �¨üã{Ÿc®È!3P¸ìæz½lëçOŽÇùSƒ3[N_\ˆÛ‡7®%ÙÆÛË�¾ŒÓÝ—þŽ­Ó� ˜÷Ø0þTûb�öjñW++µh9ƒ"�ÆG€}߯—§´È�@cð÷Æ`ƒ{ñHC!À¾`CÉ)¦³‰ àËÇ §àËGøŒšH€H€H€H€H á�¥ŒÖ¹‡ª�ÌÝqâÀ^Ë86\ó˜rÿ*÷¡¨x'T·A›êýØ�6èwâ tië£&ð�ÀÎò}¸ã_O¢ä`9Úf·CÛœh•ÕÚ·ô¨;VƒÊPQ¾ÕÕGqÃÈ‹�?õ~'      ˆO è“wñÁý7CÓj�ݱ Úu–-ã_ØDÎ8RY�ƒ_ïCåþR´“—Ͼ=ãEdwëÓD¬¯[3·–”㦹¯£ä@%Ú·ËF»úXTVÝ&¢–b«:|ÊËQQQ‰Þ]sð·IãÑ­Å‚µ„—Á� � � � �@ƒ"@Á—�ÙEÁ—�ð5 �€oî}óøhÛ—øÆ¥—¢kÏž¾¥#VÄ555X±ø¿Ø±e æO¼½;v�u:�‘ � � � � � � DxñºÓÐRf󣟠Mûœˆ£üiسåKüoÁSè}îXœ÷ËGÍÝÜÖ"�;æ½…å[váâK/A÷ã»×bÈþµ}Ûv¼÷ßw0þŒA¸÷Ê1þ%„1“ � � � � øF€‚/ßÐ|ùŸQ“ øFàÖ—æ ¤E F÷{¡4PôïEضë²O½§�]?–QÜ»s'>xõ_˜}Õ-8½×ßx1b      hh4™AûÙËúâ” Çaè˜KlÉ”mÃ+ÿY‹-å8,ËìU²Úg‹§ úö퇳Ïè�®-l—4úï==ÍÛuÅ%3^jô¶úaà5�¼ŒŠY¸dÜØˆè«°åå9ø¢° ¨:Œjý¨l‘Õ  à gŽ@ŸÁP_M\´ð_8©s̹áÒ»ø“H€H€H€H€H ) àËÇ\¦àËGøŒšHÀ7Ñ‚¯J,»p(^\ œñnÿå0ßÒ¦FLÁ—JƒßI€H€H€H€H€H€H q±_o ËµOǬ/}öw¸)·CŒs×! ¾Ò›Ÿî‚¯ ,»:ÿ\+þëpó{�!w@ŠË&)ÁÖåïb_æ ?·v^,¤à+V¾ñ � � � � 4~|ù˜Ç|ùŸQ“ øFÀIðµâŠ¡xþß@îƒo`Òm|ù–9Œ˜H€H€H€H€H€H€j�@LÁ׿ÿ¢Ë„¿J,}qç´+0¨úÈÜJë?Y‚§—l ÇþÂk/âòÞ-ÿó ¾Ò›»±_ËoÊÁóï=.ºç}ûTdHRªŠ?Çç>‚MJ²®~££†uTö$÷õȺGñ‹qS€Áá�ÿ܆6É]îx6_ŽX¸“H€H€H€H€š  ¾|Ìj ¾|„ϨI€|#P+‚¯@%öoÛ� ­‘Ýýxt9>ö›¿‡¶oÁÞ]²NDËL´lÝí{uCv¶>Œçüá _Î\¸—H€H€H€H€H€H€âHLð5Ÿ®ü†)Ë7~ùîó8õ®WŒàÏ»s_Óߊª¦…_ížÃd¶nƒ.rp|×lC c�jŽ"h�¬V-d¹ÈlÛ{™ÙmУk'd…â*Û½[K™hÓ¶Ž;®:ÊùNŸŠ²Rìüºûe¥¿6íÚ çñÝåÜè3Õx!£»Švaw¹G+tèÜ ý»fE_ÚCÁ—+šZ9�ˆà+÷�ŸáæëÔ—+°eþ�xèž§Bi¸÷mý#:E¤èØ‘ */•åIeAÈ sÒ—ƒìlŸ ìX8´öQüêr]ðõ'üñ�_¢]M•xI†¸GÄØT  %›·¢òðQ´hÝm;vCN·Žh¯þ“‚/(ÜE$@$@$@$@Mˆ_>f6_>ÂgÔ$@¾HUðµgñ“øû¥3PiÁè[ñ‹ç~Ž~ÇG ”•àÝŸý ¯-(ˆ¼ßøÛpõÄÁQûõ|9báN      ˆK 1Á×|¼l*N·MuT�Ç&ý¿ø'‚¯—C‚¯/?z×ýôi¬‹Œyø•øxæ58½£)ÖªÂS“®Ám¸¯_—‰ñSþ¾bÖ‚çð“Êñà¯nô%áÝá/ãn˜†ço; aYÖ¡xðþ¿`Ú[Ö¬cæÉwNŸ‰ßޤˆÍBñ–ÿŸ>ÐO\q"­Æ÷Šu¯à¿³GÞ;ÎtÑtLû˯ÑCÞM¬Þò,¦|ëFãšè.Ã/¿xýÚ�ìYò(žž8%zÌkäݸû±ß¡wgû˜_ÑD¹‡H€H€H€H€š ¾|Ìm ¾|„ϨI€|#�Šà«ìßàÞ+§ý¬Û |õVþÛs]Ž_ì}ýÌö« ðÏv—àCóŠÑ—cÌ `çǯb“Œ�ùׇ¸ò²žæQÛ–‚/þ       �„ x|íǃ“~„iŠàëË·ŸÀ©÷,ÅÝ×\{ Úì\c-ÿxâ�(ziºgTá¹)×à¦( Î0,]ö{tx÷aœ:=xpØðÑ8¿/ðùçK°t³\|Ã}¨º-7OÍnüæ¬[ðçP¬�so“ñ„¼K¢³qwÎAšì4>ñž8 úáÞ²dj÷?û~ž-ù¢àË�žm*‚/T®À“C¿�µ’´�S?À7�2YúîÏqïÿ{$”à\ ¼¨Pôol Q½ˆGº5[^Á×BçEn,Áמ×nÁïï0gËÅY?>-‹òðá;zÌò‘¥ ÿ$KAªÞCÁW ÿ%    �¦J€‚/sž‚/á3j ßx|©â­Ñ?ÇÔ…·£GHØU–÷ î½øw†M§/Äí÷œe|/ž;3~òªñý¢ÿƒqW M�@Å–m@ÏÈ¿ºkGBÁ—�‘ � � � � � �@¢|Å^ÒqÜ´‡ñòwjpè_à‰xÜ-ÓðÄ�ÏB×Ðd^E+_ÅÀ›ƒ3x=õÒ øÁ‰ú ¾*¼ºï½u¾Ñ=eeh-ë0. ‰Áλã�XŒûzöìoÚ:ÿ6üÅXònüvóÑ54)WÅêÐ’Ž#E¸õÏÛÐ& ë<ʧy†œP¹Ï= +åwîÏ_Åu·^†ìÐu¥ý÷^û+ãÜëÿSŽ‘ƒ-É_þC$@$@$@$@M–_>f=_>ÂgÔ$@¾ð*ø:²n>~yú=Fº'lÆð¡‘¯�%ÿx5�¾\~ý¿>|/ºeTbÙCñ¢>ëþM�cöãß ¾….ˆ³¡à+ &      ‰ ¾úâþ&â Yö®l_V}ø:þ^>q–~0Cöþ]&üUbq•ÌÐõ Ûò�U²üã5Æò�Ær�†Æ^Ýûä¿—|d‰Äór‚_ƒÿ®ÃRYúQÿ8 ¾]ðnlt-ù;NÑß }d©ÆûÇ}ßsú·M†RÜ?áFÜ'Ë<ÞûäÓ"ëdžÚZ‚0kÆ.Kðõ¨Ì6v“1Û˜uÙº—ÆðûEA6|2vÍý6,ÉNð ¾,Véø–šà«Ëe†¯ç�¾’¾dv®P"�ì\�Õo¼ƒ�Û6a_Éde‹ø¯b9VË0º¾d–°Y2K˜*ÛÿÑpϵӃ¡��6?_‚Múû�ò¡à+È�ÿ’ � � � �  Pðå£'Pðå#|FM$ூ¯²?€{¯x\Ò=3ªo†5�}Ðk°‹p—¾zc5æv¼òþ%®üäsŒ9=R"_±ùð( � � � � � � ¸HTðuÞè0VDlÛ'të‹ágžŠ‹Ïî�Ž!íÕêfàœ?âMxÿ£ žq—>R` ¯,Xø4ùrŸ¼½·Þó‚1C—zä~wý\wÕìÆoκ–ƒ÷>-³„E�'Xq8 ¾œâU_ûDð9¦AÁ—šµÿ=5Á×v¼Þ¯?K²zÜú&~u×·�äKÞ½¿û3Ý;x:þøŸ_‡_X Ïâå ø*zærÌü�"Dt õj™ákgør¡ÃÝ$@$@$@$@$ÐôPðåcžSðå#|FM$ூ¯ ™ákª>Ã.Ç]BoûKºP_‘3|å>öLš48)›)øJ O&      �0�Ä_#ðñÇSqº:ÕQã¿ÝÔ@IDAT8„à—™á«·>Ã×ðef¬qQ3cEœ.?-1–“ðÊ:ÿ(vmÝŠ¥KÞÃÄÙº”Gÿ\ŒÏ?¾'µ*Ń2Ã×4™áëšiËòŒ}ƒ‡ÃÿZ3|�wç,,¾F_¾1v¼|…áùò%ÁסÕÁ]—ÿÊH÷7ÿ×|gP¹Oý†ñ’áÀ?�«o�N�ÛA×)\ý0îù¾œ±üc,ÁW…Ìðõ+}†¯‘öÄâÁâ’Žññ8 � � � � 4n|ù˜¿|ùŸQ“ øF ¦à+†0«zÝ|üüt}ÉF™±k™ÌØu¶}Æ®-¹OÕ縿¿=|ºdTbÙCñ¢þ‚äèßbÆ»7D½A«‡åö¡àË� ÷“ � � � � � �@l‰ ¾–.›ŠæúxAVlþ/ºLø«é‹—ßš…qÝÍeN6vÅ^9]eÅ1ÁôXa8 ͬÇÅcîÁR 춇æâÏ£»Ê7ë'¡_NäënŸWÁ×±=yxêì‹ apîþòYô�bX¼…Ëdß«Æ>ÓšýKîÁ=e毈™¼Â×\ô4f=5Ѷ¤cørqó‡+‘Û3à .æ–‚¯˜xx�H€H€H€H€= ¾|Ìb ¾|„ϨI€|#Kð5ðîÙø¿†¡æpuTúZtа¬ÿX|`¹·ü'оö,~¸t†q$÷Á70é¶aÆ÷â¹7aÆOÞ1¾¼ûqüø×ßA¶13ØìÉûövƒÜavá˜q²üCÁ—I‚[      HŽ@¢‚¯�Eðuz ÁŽìÀOι OëÑŸxþ3kÆô-ˆx¤þ{–tý6¦¢+ý¤X«|òò+ø¼Çp\uf_tl�}¹ä%œ:å¹Ö|EKþŽ�S‚Kì�»ã^<5ñôàìb‡vàÁ{nô%z\Öù±ã(øÒyù÷IDð5ðçïছÏB‹@5ªÊwbû/àÉ{¬%Ï—Ù½®Ôg÷’�%ÐΟ½ã¿{:2(þðÌ›8ÅúIn3|‰pì—Ÿ?‹~2uhO 2»uE摼pÒ0|¨_7øvÜþäo0¨oGý—DV†-/ÿ»ÝŒ±ö î ýKÁ— � � � � �@“#@Á—�YNÁ—�ð5 �€ob ¾b%ªÇŒWqÛÈO0õü °K?·Çè‹Ðöëw°i�yå�ñëƒ÷¢›¹ÜcÅ:ü£ã8¬4Ëvàe#QùïåÁÁ·ÑÁ_Þ½ÊöV¥y*_& nI€H€H€H€H€H€H 9µ&ø’h ßý;†Ü_©>ãÚÂKÌÁYŠq¥,Åhè·b¾jvà†³nƒ.íÒ?ÆC§òuX*K7Ÿ+§¡üž³R�e'É²ŽŸ†ŽÉ cãF·Sânüã£xll¯Ð 1â•3V¿0çüùYšr²,Mùí¨¥)ß{z6š·ëŠKf¼dFÈm-HDð+ºóg†+¿|¹Ð8/°¯œxòb]„›0íË'УUð¤ê-ÏbÊ·n ]‘‹�ƒ×bSpÕ%3¬#JÞú9~wë#Vˆ#/Cn»XûŽ¡.”ý7á7›Ÿ@7eò/ ¾,\üF$@$@$@$@M‘_>æ:_>ÂgÔ$@¾ð*ø:ë±7ðÃIðÅkxqòXkŽë†,xÓoñÜ€n¡}M�•¬Æ7OÅ;ÿ–Q4Ûg$¾ûât\pÅ`4·íþ àË w‘ � � � � � �@|�ÆÇË~{†¯P\…½�É?}ÚXFÑý‰£ñèÏ.ÇÎíjY«G<‡›+ƒ5¥xññ`â3¦€Æ é¼ke±Û.°-Í×ó‡aÖœ›ñ“sM±—NŒxåè®�^ ?}î�†å¿< ŠfÇH_†´ýKðµìêüs¹SÔ¹8ëÖcôu7 _OÅ�B§VïY†×ïƒ<åÚÜ?Ž+î¾%3sðøßE %‚¯n!ÁP†O§]€y Ö*‘åâ{Ͼ† Ggî*Yò(È a›”3Œ¯ƒ¯ÃÕSïÄÙ£‡!S9FÁ—ƒ_I€H€H€H€H   àËÇL§àËGøŒšHÀ7Ñ‚/oI9T²Õ2œ›¨Â±v�‘�9\j·ºìkT”V &3™­sЮk[G¡—y_& nI€H€H€H€H€H€H 9±_É…¤ž]ƒ²’RTe´CV୲ѵ}Kõ„ľ×EYé~Td´F֑ôé€ãc…#KGî*;Š,9§ªèÚ5;J°•XÄîgQðåΦ6ޏ ¾€c2®T}$€YÊ�ŽéŠo´é�sÜÈLWue…œ/áÈU«VæØ”„È@só§y2¨Ø¹ÍsZ£Z.k×­£CYê±Õ�dÌëŽeuBvs*ûp@Æ ¾ì<ø‹H€H€H€H€š ¾|Ìq ¾|„ϨI€|#P[‚¯t@ÁWº 3|      �ÆJ =‚¯ÆJ  à+½yKð•Þ˜Ó:_éåËÐI€H€H€H€H ¾ àËÇ¢àËGøŒšHÀ7·¿ü¾:T†‹¯¾Íš;-¦è[Òlo-(À'テÇ&ü¹=úÙŽñ � � � � � � �€;M;†\Öýω߻ÖýDÁ±š¼õèýh×û$\ü‡$’?xì_ØYY�+&\‰fÍš¥!†º²Füæ¥ùÿÄð>]ñðıuŸÆH$@$@$@$@$à; ¾|Ì ¾|„ϨI€|#�·ésüöÍçСSgtíÙ9]:£Uë6¾¥G�øØ±c8XVŠò}û°këV ìÚ�}ÿ§ÈlÑB=�ßI€H€H€H€H€H€H€âXñ×ß`Ãóp\¿ѹW_ät뉌V­â\ÕtWU@ùîbìùj#”ìÁ÷<…>ç\ÒtÔ¡¥o®Þˆi/¼‹Î�;¡{�èÜ¥²²Z×a j/ªC‡¡ôë¯Q¼c'öï?€Ço¼çêS{0$     �C€‚/³Š‚/á3j _ |Xø^[»ùÛ7¡º&àkZœ"ï‘ÓcN<×�uÚµj˜€Nvq � � � � � � Ô�cr¿_ðƳ(üàUì“—¿ iuuƒ‰§Ef+ô8ý›8é;?@¯³¾Õ`ÒÝúþºB,\±+·ìDu ¦!šNs«Ì œ3¨7®>wÎØ;¼Ÿ_H€H€H€H€H€š ¾|Ìo ¾|„ϨI€ê�À±”TìGÅ‘ªz‘ž Yb²KvмêEn0$@$@$@$@$@$@�…@àÈaT–£æhý¸ÿ¯\[¶m�6��GóŒŒú�œ&“†@Í1ìÞ_�ʪ£ Òæö­[á¸mÑBưø!    hÚ(øò1ÿ)øò>£&h4f½ÿ Z˱·~s\£±‰†� � � � � � � ¤‡À Wç✟Î@¿QGHa†ª/Ù¥}üüÒs ƒH€H€H€H€H€ÒF€‚¯´¡�0_ññ  ˆG༇iœ²ôg‰w*�“ � � � � � � 4AšÌ0¾}ùb|ñê\ì]¿-۶àK®ÇÉ—ým»öl‚Dhrº¼µz¦¾ðŽü_oºŒK.¦ 4Ã%    _>:_>ÂgÔ$@ žÀ¡£Gðä‡oa‹¾$„v 'wë�Ͻm[f5xÛh � � � � � � �€7G–aÿŽ-Ø_´ûwÛ’‚|tè}"†Œ¿}Îù¶±¼dÁ[Ïaó;/‚¯N'œŒö½ CÏþh¯ÿõ8A–ZÌô–^Õ¤TË‘ëŠö`å–�ø°`;TÁï'| Wáw/€Ý:áÜA½1âÄ^ؽ3š5kRxh, � � � � �@ Pð•F¸ñ‚¦à+!'hJjŽCµ¼q¨ à¨üjjP-[}_u €ƒGcGù¾Ð_ ¾Ü³ã†��kÎMþûgþ¼±n×½rº¢gNgÙvA‡¬¶ÈhÑ™-2‚Í[„~˶y†|oŽfò?$@$@$@$@$@$@$@4¹ã–—¬4ÙÊ?ÐäÞ]ÿm|×÷Ó÷Ã1¹×ä>þXMµüÕÈ÷€µï˜|—ûúà¾Ð1¹×7Ï1Žé焯SŽáF³â8Zy‡e¬ jÿ×á¿™-EÜ59}†¶ƒÐ±ïIhÓ¹{„q@MõQ”oÿû·‹8lÇf”m2bwmE†Œ'dɸBV‡Nò×ÙøËhÕÍe|¡™ü·-¬­Œ14“ñ‡ðñ 9ǶO9&cFú9FxrÌv®¾?tN(.4“ñ‹æ2‚![]5¤o›5—ïú¨†²?ÊÈ&¸ã˜øê1ñÍc+þ)njŒ;‰� Èø“l«ú÷àŸ.Ú ÿ6Ž“±©à9Æ~ã:ýwðÚŠª£ØYz;J÷£äÀ!œÔ£ Î>±§üõ©}»cM:öªê>ÝRŒå›Šð±ü—DïNЫs{ß±Zf´°þô±+ãwóà¾ðïà9™2~<.¿å˜~­ù»…øCsñ�æâáïT–5AϧÉ$@$@$@$@M�_>æ8_>ÂgÔ$@uN`{Y >,ü;d»¿ê�¼ñxûW¢B„\Gªd®F¥taV ´iÙʘ©«m«,d·l c+ßõÙ»ÚÊàj/s ï3(j6/}Ö¯O·oQX *�V¡RÂÕ·zø‡ô­²O“éƒ}úG�/[ÂmŸÕ&ü—Ó&gô:gÊ qK€å‡H€H€H€H€H€H€ü&  ”ª �Ó>.Ó…Nògü.E@îy�ª !UMà¨!²²~‹HÊ<&a-ù­okªõkô㺰*xž~®!Ä’¬‚Â"ýE)]X$"#›àHöËï°h©E¦M¨d DÈÔ\"©�ˆ),x �¯Ÿ#ãæ9úìZÍ䜰x*|ÌNË6íB¢¬  Kfe¶n›r6颶#ÊB"²Ò°˜¬F›Â5�UP仉hÍú©E�c ØÂ‚7Éù"[‡ëâ8¹NÖ;ýµ·�ðNßÊc¿!Ä“_:3�Ÿ±ñ›íwx¿~\þ Á™°–m‹ 9Wù­o‘)Ç$¼–mÛ‚·ÖºÎÁuFëŽ]Ñ2»CÐR& @i—DѾýØ&ÅepèH5Žˆpꈈ³·Õ²_|×8&ßu—þÑPAñ“ø§¸i ñ]}Ì©eFP8ün §tA•!À2ÎÑǧ�•.®’ý™r­~Në–™èÙ±=z‹p«G§öƹA bÿ[)¶ìøz?¶ËßžòаàÌž™3Ÿ……hº -$63„j!�š¹Ï©…mºÈíXHä& 7ù´ÊÌ�¿h%ùªo³Œßò]lË�}¡ï²¯SvôíÒ}ºäÛ¶Y-cÄ£$@$@$@$@$@¾ àËGü|ùŸQ“ Ô�=Ë1ûƒWQ$Ñ#ú2fßêݱ‹ÌÀÕ[gË“ Öƒ¶ô·;uñÙ®¥Ø)ƒå;åíàÍ%;�™Ä~4òb\:tD�1cD$@$@$@$@$@$@$P¹oJ6|ŠÒ¯6 lk�ümÀáÒ=hÕ¾ZËÌÖYò2Tp«‹p:#C^’2„>†¨'$æÑ¿›"Ùêâ},CHÚõXâŸp"1Ä]ÌŠ†C@ŸÑJÄa†`ÏÜâ½ ¸/¼_D~Aq_Pä§…Ä~ºøÏ©…ÅÁ°ŽVî—™Ôd5yÁΘQMÿ.bÀ¼`—#/Êuì78üwœŒŸè3¡%úÙwðò¾ø Ë ¶aea1Ú·neˆ�zw΄•ݪ%ZŠP)KIúV0™B¦à6xLd5çìV2«™fȉNŸqL“éÛ @. ßu‘\p»ï`¥!´ÛVRŽ"¥éypÞÉ}qþÐ0´×q‰f)Ï#    ¨#|Õh§h(ør¢Â}$@�‰@• *NZð0®:ý›Ÿ;²Aš¦ Ö~÷Öó¸dÈ™bÃ9 Ò&šH€H€H€H€H€H á()X…µ/?޽_|‚î§œ‹Î'æÊò„ƒ�#ËfwëEVÃÉÊFŸÒ€>{»¾æ¶�²4æFìÝ�oüxñÕ2þF´î[$ôïü/1ë��0zH?ãïì=ÁY¥ê‡Û肱‚�û !Þ¿>Y�sOꃻÆ�2f «)d*H€H€H€H€H€(øòÑ(øò>£&¨o}±}µ7±NâKW$Ûä ê)¯<‰WnúM½˜�,]v2\       lüï ø|Áƒ8åê;0ð¢«�%öüMc'�ä.Ý‹5/=Š­¾‰±zí{öw à2£×ï_Y‚Çn¼»wv<‡;ë�ÃG«ñËçÿ‹²Œå=—ŸW?ÅT� � � � � €‚/�€‚/á3j �:!°n×V´hÖ'wïS'ñ¥3’W?ÿ—É,eÍ[¤3†M$@$@$@$@$@$Є |µô5t=é ™É«w¦@Ó�]Ÿ-Cf›lttš£9ù²|c+Y¢qXïØ³€9^Ì�uN ¬ò°Ìöµ—�yR�ÇÍI€H€H€H€H€œ PðåÌ¥NöRðU'˜ � � � � � � � � � � � � � � � � 4|ù˜•|ùŸQ“ øF@“˜k á˜üÕ×O Y¸Qÿã‡H€H€H€H€H€H€|' Éý³vLþêï}´ïŒ˜ 4“1”æÍ% ©�¥cFòÏ1ºº¯ù©çb =KSËN_m`ä$@$@$@$@$ÐPðåc.Sðå#|FM$Pçt‘×A-€*‘z5„Os¤ÌnÖmDúÅ � � � � � � Ô5­&íèaQ¿ÔÔuÔŒ�<h–ÑÍZf‰îK%þ ˆÀ«Bþ9B¥WâÐêàÌ |eË?­¨üªÚŒ‚H€H€H€H€’'@ÁWòÌjí ¾j %"¨çŽŠÈ«L«®Çsz¹l…æÈi–™â;ªîáó � � � � � � DЪ�Å^‘ø›ê;™í«yV¶L•Ø tGEäU^­5È1£úžµ•¾¶2Ý—.üâ‡H€H€H€H€H ~ àËÇü¨ÁWÛW}Œm•@fÎŒÌíá£Å�/êªâ¬ÜR"†ebÀY#ÑC^`KôS¼v9¶”Wm{à¬3 ‰K�¢ΫBÁò•(3‚ùÁÜ�8ë 㓊B_ºqŸˆ½êóŽñ j+³|µk–ï´”Ž§RŸÄЏªDê©oõT¬py¬n4ú:¤ªËWn�4#è:ø, îÚ0[úñ†tÆÒ°Úót’HGØÞÊqãÏ“@Ùv|¼n› ÏDßÓG¢�<L÷Çs›XÏê*g;£Ïx±‰÷¿É•#òJŽÏ®K©Üyk{ëÒºøq3{UUÄ?‘g4iUû6âÓ�_ ƒLô?cxRã’ÞÀIÛ¼r5öéã€NÀÙC»»#3|5oÝNfúŠ-Ò'ôúúè±æ‚`ÇêåØyÈèÐgkÜcß{Ö­ÀÖý’mŽÇi§@+÷¨õ#9™‰ÍôåG?¿Ö�M"ÀTÚ«$¢IðTöí•òiMÍÏSÆR"P·õŒ—ûð”ÌãÅ$@$@) à+€wmÂöÒ£ñCh‘�~ƒû¢mÄ™‰¾Ê¶,ÇŠMåW&öó¸!£pFà‘SÚᎵrMîl”®¹»œg%@`Õ#çãÌ;>0Μùq)î™(Ý +_0ÌÃÈ:xÈ•€IÉ�R±ç·;�zï_~0÷#Îä²°.ÎÖ—q,\µëKDyŠœò­èG;(+ÄòO6"�.'Ÿ‹\O�÷‰µŸ~†‚/·`oÙaT®BVë,tè;'ö; ÃFœ‚ž—èÓ]šµÙWì�ÊTxz¯ObÇš®pcÇZ?ŽVl_…eë÷‰ ¶‰îmñÚÿaÍNñQiÖû}óB îèæ¤üï]lÕÝYüùì GÂõÔ”14þ:¤bÕ#hwæ©Ü™cÍ]#S¦Æ<hPí¹û|½Äc9ny¢–ÿäúÑÞ3Ôk›¨¦µ>ÔUŽv4FŸñd“RæÒy(CÁ§«±ª`¶lÜ�ÒòÜZ£u§ 0ƒsOÃi¹}ÀK=éäU†Uï¯À^é[µ[ðþ²M8ÚRN¨h‰!_€>‰uÓÝBlrû+dìhYœ±£–msУGôУø&àX×%”³Š_7àñ–c‡¢bó |X¸_¬ÎÄÉ#Ïq´Û=JB`|<©«—äc¯þ–‡|Ú*F íüóß*¬]ò!ŠC×ev9 œÖ+æMíàêÇ/Ãð»–fÿ)ï+ÜyVNzT|Š º_„%z,Cÿ„}+nŽ9ά/íØ,3F….íéû‹¥­¨ÕW²Ÿ–ÇaĘÓe¼½Þ¿^' {HÚçÛåN½±~[1oî{gºsÔ:™ä ]ZÆ_ªSí;×U?¿Ö�M"@ïíU‘$|ªÒ¦³/œpz¢O,“èWº ë ¶`wùa–~tëÖ­‘Óg÷ŒÓÎ> }¯�½îö¤ÓÏ­~�ô‹G�³ýß²ü}l*ןQ•>÷pés÷¨;Œ©ÎÔi=ãé>¼ÎP0"  |9@It׎%ÿÀ[_V%pz.üáÑ?âþ6Á—Ú�'‘í”àÈa˜÷Ýv¸áu94þ |m2êð>ЖžÆøCÍŸän`+¬|Áxä| gøš1X»|*[vÅiÉÌ6Vµ ?h}&ž×3·Þû—ÌýˆSž‘l_‹Õ2­_�Á§a@=˜-§D+Å“§vÆotá)ÎÛÇõ÷ÊU�áÄá¿Ð/ÀÉ3—âý;Gßú§âKÞë“Ø)Zû×à”[ŒRŠÙù¥¸ýŒD…©±ÃmG×þõ»b»ÞÊçgïA{è‚à÷¨Kð@³ãpwhÿ¤…›ñäU¢Î2v¨7½i€äOâlxzöV¬ý+Ú�r‹øøÙùxíö3ÒC�M b•¸Ïl îØ¦Ô¿£Ëq�ç‰Ç¾` ÀÕò_Wí“×6QMk²uU:úeŽv4¨~y‚Ž£¸sUÊ\šîO ^¾{7Œ®m,Sr¯ÇÛ¯>�Køz£g¤Ð^jŸ)ÖǪLi}2³œŠÍ‡ïÇ€ˆñ“ða~q$ ÞK8ž`Û9³_{·�ϵí­o?T›šÜx‹&³:€:ó¤Ë T‘�Ç-øªâ~Ä��S²ëm´x­•ªFÖÉMãÛÚ§oÆiw¼dûв¯pûii–:U}ŽvƒùzŒ—>ˆý/Þ{œY–t4fùrËi+FÉ‹¤º�¹ßêÙ„Æ8¶à/$ �†A€‚/ÏùT�UÿzŸîK$€Žøö¿�¾–‰¾l«‰J9gükðÚä,aÑ|åQð¥ Jù«>uï†Á·-{�<8‰Y^”›¯z ø ¿ŽÌžßIÎ6¦vþê½ùÁÜ�8x}J&¾+÷zõa ½�í־Ƌß낟º›qX|àå¸R•kŸÂ‰§Þf”Ño?ü1æÝ~ºñ=î?�"Üßr UO37�<[e;eƧ¹o`ƒrüÜ™ïá•;¿¡ìqþšîe½×'Îé5÷:>66òm`ûËÈìûý�•S±Msy¨Pò>N9î[ÖƒÛëçãðs×:Î|P¶üt:'$ ÿŒ©”Æ(?ê�ºu u€,YEݦ´±Ç&Ë>l€¾2Hf‡^ܧéCÓŸ³^ËqÝæ‰ç¾` Õò_W‚¼¶‰jZ“««ÒÓ/s´£AõËu·r‹«RæÒp²ý?ÓÐwì Å€\ŒŸô- ïÕ 8\ŠO?~¯ >ă¥{óðÍ®Ê%uþÕ'^ªOº‰ïª¶`Úˆ1ÃD–{6¯ú 4ÔIŒêé|ÐÜ[]­É´¶¶?Ù£-�9FŸëÚø›¹t§¦UÛÏѯ©6Â8¨=3>xÆ<¡•šárë3%_0^Ë?èorö¾w_ÈŸ®×ò'‘–ÃùÚõ!?ÔýËg3â$Üæ~ĹS»/7XæEô‡IÝÞulŸö°Yaœ¶ø@•¶ëXì¿ÍŸ?®ãDð÷|3¼ÿýýšðuÀ�ÚÂM»¢¯=ºK[ø°zÞ0mÁŽŠèó"ÒxàX°V­jµËš'®3‘A‚Ú ¸A„d•½Í\¸Ù¹‚ÛùöÔ0£`Ûz½¶ÆùTmé}Vû;iþæ4Sð£I³IÁ\óD˜½ˆ("Žò' 4 £{î ¦�Ejù¯«öÉk›¨¦5¹ºÊj‡j³_æhGƒê—§à8Æ¥±¸*e®¶ï¯±î}¤_qýì÷´R‡îaéæ÷lçåN}/UƒS¼Þ/^qî«·i÷� �UOäÞ§mvà™¢ñMærµ^˜¹t¯Ø]­UËx’õwXÛ¹a©6óúÜpßKï÷ÎßP¿ïâ½e R4Ðñ–c�j­¦¢Lûlö„p~‰˜Çاïopû>ЮÓ˹ù7T¾ÿd�v$¦-kµ_™çë[ýšo>¨í�yMd“¢=uî#j^&”å1‹ñ19º£¼RÛfû;¢m+Z¢�kæÿyÒ>¯�}¶sôkŽh»«jäo¿6{\È¿Î{\+0öéûãŸb«Ôoïì«{×è¹û£ö�몟;E�ï¨ûý›ÒÖv_8Œž±Æ&�IÚ{›Æ'«Kµ÷f«çåjoïô»sèÞ�N§Ÿ«ý:§2´ímóYN°î›úZºÇ'SÈ|^šfî>ê9â&5¶à™/$ �zEÀ«ÞêÅ_ÔV¯^­mܸQÛ¼y³ÖL·JnÜ“þxUœ%Q­_P…å þ�5pöüðÚQŽ3�ÄŠ6‘¾Ü®·«üÊ]nó7Ûßê8,3|eTlÇÇË>AÑî }eotêÞ[ÖF?GÖFw�¶Jf²Z¿n= Švã¨, Þ2»úŸtNËí“´Ý@Å[6ãëCÕhÓ} ±ä\…¾vûš�ØSZi÷Þ¹8ûœÜ質JP°i7äJ Ì€ÀöUxÙ”JšºŸy).ÉU_�®’Ù*ÖKº °»BNÐmíÓ_Ò,ëÀÇXæ.PQ‚ «×âK±-[¯ëvŸ~2zdÛ*бù«¯�ôô:y@tzeXþî{ølë>dee¡e§>8cø î‘!3¯µ.µéúÆi’éWØœ l²Q…-«VbuA*$ÓZ¶ì„Þbû9’ga+ªÊ°eç¬~ú|Æb+ðÌÒ Æè™Ýú‰ODLKgœ¡ü“ˆÚ_x®]'< wéЯÎî4§Ÿs–ãrƒ%[$¿tßè|ô+J¶`eþêÄýµ.™›(RŠÓ Äe›¿²í[°§xn9çºà²\“žÁ†»F¢ºZÊËà$Ëjñº¤<¼».gøZõç«péÝú<þÀïe ÆÿçZ7VáÕäàVcàÊ¿Ž9?:)œf§/IÏð•$C·úÄ*R_ö`ÕûïcÍöR©ŸúàÒ  k¸@;¥PÛ‹'ÖÆäÜ –‚U…Û¥>¯’š¢=NûæE9@­?#ÂJÒóêdêSó}[›mÎÿ8çÝý�üõó7à¹kß­ô7¡Î�YñÌ©%‚GžÈ?ˆÉQþSŒßŸÒ÷§æâµm«0¾�šIÖÛf"<Ô!–_x¬+%noœ(Ù²k¿øRÚÖ`3©÷ z ŒSô°ÚӶжlËr¼ý¿Ïp@z YÒ¶öéFŒŒ¬‚yÈ<ùã,çYsBñm’øŒ~‹œÚ2}ŸŽs#– ÖíÙ´ã�VgIO·&,Ô^ê'êý�X}#°ˆå|û.Éôô’ôØÚÞ$}ÊK_À°Ïê›Ùføòž­BÚñÕù_`O¨/ÖKú�Ã�¾ˆôSÖnÂ!d¢ó 'Fõ±¬¼|KÜoÌÐS.Sʱ·óÖ%OÂ'{+‹áËÍ/Iõ«¤ýø«>ÛˆÒ¯•ž­q1ô”aÒ>%?+œí�hiŸnÏÍÀöµ㓵1ú®fºÃÛäÒ¤¶‰2pµÌ±÷º*œ ð—¤úeI¶³Žv$Ð/7ü\ŸÉ¯ºíOPïmjÇŸ*Š·à«¯%)×Áû‘0ã‹Þ¯ß´»ZŽBâw(÷R޶lØ¡Ô ß7šuS|®µsÿkOyèWÙÿp~§ó‚ýl·«B§¶,@æ‰"o0>“°æð“È�h—ªJ ðÑ’UظOZGý^QÚÓÞý‡bØ)÷•ú=t�ÜCKÞ™÷I¡À­M¸ÎÎDwiõ[^_yÅôÉbŽ·DWØ$œwIµ±öøjs†¯ªòذþKìØÏëˆþsqêÐ^qÆó¤\lüR®Ýd�©õî'× CŸ.1 «Ý”à/sV¨¡òó ù3¶cñÑî8Ûe8³â³gÐaÔÏí¡…f”Ê›6í õ³ ŠÑï߇‚-{�0Útë/éÎ@ñÆB©Kh#ãsŽwˆ¼*xMµÜÙt—°ÃÇáý­qÂЂcnŸ­Ægw†ÆÜ:¢÷Ð\Œ®ê¢j@ž¯ðÙgV¿XòáLã|éQ(í_:÷íŸT¿X�áëñ»póP¹ß_¹ «¿Ú!ù}Dî÷Ûá´sÇàìþ]Ô¤(ߥP¸k 7aÏîJ'–O˶è=èœ{Ú Ñ>bæ¥~žË _zx»z#€ö}OB¯n�õ³?úĽGŽE«Z�Ÿä Ç+ú‘¸Ë4ÚgøÚ&3|µ�±ïü�Vbçž ³m‰œn½1ô¬‘è1ö(+_úZ"iƒã@ŽCæ•`—L…œÑ¦;ö·ÆM¾.,À^¿lÝy úÀÚò°¾H«é� ¯¼�Caéã"›>_‹-RÍqæœãúaà©'£[Ä8s„ô‰òeìç‹mûÐJú™{#÷Ìx|†,_Ù6¸|¥Œ';.é(ñmX/ñ}µ•ú ¾|Úv€agG¿°Cë{«°ãË­8,„�i·M?ª~ [õ.žp:mX_ä$3ÃW ýü¤Æõ•z:]m˜ÊDýî6ž—–v?nÛ°­öR?žËø.ιÛXú³e¼ÍýYVü 5®{>HøúgdïGƒUÜÆ÷äú…ééGÖþíN¹ÅHÏlÏ~eš±ÃÞ¯³ß·ÿïôðª·z饗0hÐ ´mÛÍ›7—Wn<~¼*Î6gøzö2çVòŸ„før 6žÊߺLy«ãú'´¥oÏ´Þ¨3ß” mg¾·Íº,ü­T{m¦úfEè�©ðµãµ…kÞÈ_ïðEâcÌë'=£½ýÌÏ\Ò4&*ì5OŒ�;^{í½gl×ÉòuáÈnxÍöVµ:Û¹ãï[è0ÛY©ööÌI¶ó¢®›:_Óß•5?ù³Ç„ÏŸ1sNõ6û›ÝjX×Ï|Fy³6z†//é·ØŒÑ–n^£Íc·9ÿø™Ú¶ÐË1óg‡Ó>b¥ò4í�ÚÆTûWkùÏDΚcOÓõ3ß¶Ï &oÍ�Å?föRmCÄÛ*j�üµ®™ë ÁJßPšš( äX$bµ ÿ€ Eèkq³h€(üA ·ËI,ˆ1Á(€!(N$°eŒ\,ײ°‘…d#É’,ÙóÎìÙÝyfÏì¹ì‘tŽìŸø˜³gÏÎÌ3ß¹îìoŸ‘—¶×Š˜{­òB!ýkúQúm8RbÔ‹ÌûJU>QÆö.9¶‡ö3ªnŠêz>JªöÞÐäu¸XTU•ùLƒ^s†:êEi¿>x\$j™WŠ&6&ˇ—*që_K�ëcåá×%ÎŒ[Se�?ÆT†{\l®òæ6$¸ÝQêT”¹€“O>7‹Uøs¤Èñ9‘öˆ5e:oÆØTP&êê´w7žïDî™�É´ÞÄóŸ»ùGhîBÊD]­-ÚS2úH¯s?ù\°«)ùÜ:VT!Bœ(Ú–g�7¢ëÖ‰  ´õ îÊ#‹b“I˜oJG﫸Mú8ÝyY´qÖš�¤ór!Ú}�¾q¾Unÿ9’õ©¶X—]mÂÛøýÚó´¬c¼~yܺêõ½ªã-¡¤Ã5Ûû_ÏšÄÏžFÝoQImâÆ™~ÑÒÔ$ZÚ;D¿ô²dþ¥Ob¢¢.ð–~»‡fý4�—·çòzu�ž[^"´NvˆJ£½—Šæ¤ *xs¥äsè(ã­œÁe~¯+K$»q•—vâ±µ_H¼Ì9ÃëŠÜ.É¿JÛWˆõŸJü@³›õ–‘ñðµ]¬ºC{3æbÎXÿ±b½Ýkؾן0=ræ…·>.:3ñLŽB±¸.=Ä[ÙñìµgûsiÿÌõ(µáÞóýßæÝûRHÝâíåWù×Åî�×í~IÌóÒ?g±5û^]ì‡Yü¢æ³¡â îùóÅËM¿‹?«Ç<ƒíüEbûÞ §±6ñì­^ø@¸ÏÞ"Ö®¾ßO3Y~lžÝ´‡¯³Å¢Gî-·Â[W&xGܱVÜ–‡Ó×Ū×ÛL¾¼,-¾ÚVßâçEqYúúÎ@k2¿*_QVO\{Ä¥^YI¯]Û’zëb^¯.XÔ>­ËÐ(ßmÏm7Ò[{ß<ßÞÛê;�ß<ïawÎuËlîÚ{ØÞ â"×¾Oß·J<ü}^®óÄjÇóV§xòî…~üA[Ô÷‹~´\lämçÖµ:ï÷óÒ»—ŠÛ.÷<5=| еKnNšÞ¥w?«YJÆŸöãÆÅ<‡õ¾-®ô¯›'^Þ—¡‡¯óü(c³î§Gc 3ëmð›u=O^¤mJìÆüÎÇð`�ŠÏ¯³� §šwEx$ç¤zîµÞƒ‰`æÜïý-¢±¹Etôx;Øð SÙ7vóèlïgy®‚ÇaóºŽzv?"ÛeIMs0hà{^iÏ£SÅVWòo­ uÔWûkÂÁ¶Ed®?Æ!g›•kjEIÈ:kA©ùü2±ŸIç^OÞµd¸¶êä-ô>.žsü@@ ÿDÕ[=|y‚¯áwE­³�£ÜÒ±º^ˆP¶c.øòoÎäMhA‘(. >„+ ˆúE [´W�Xa±(--ñE9ñÉO,t›,+o˜ÌÄ E‘Í&¦'ã“ÝàÄË{XØß\¸¹�‰¢’RQRȯ\¤çëÊÍÕ¦°-¦‹Â€�EUú¡-·Çxh$äý­î1Q\*m(*0msâ6_Qíç¶h62ï*|á�„÷P]¥UÀë…k«ZL+©Nuà K×+K.°¥ckm@ì+pxz q› +ÙÃvÉÍ|˜;ea©ÆV˜9`.²HÓÚ6ØÉÌùõˆš’@ý’å+�¼c%)¢è„3OW‡ ;;Á×€xþ§ûmì¬ë—‰7ÓrqQW²ãt_Qò6ì÷'²�ÙÚD¼�›}GoBßhkA‘SÔ¼DéO•0htƾýRpœ“©6kñpÙšFQUäö—±rCà«ø¶Öh�rGí·#÷!Ùô•Q9ËŸà¸¦Æ—Ĺ„¹f#ÛRTÕ?oQ¨{ê7olrêòP‹(Uc ûW yÅÅE¾@,þkíkØo¥Â&cWb7½Ð¾Ígb{ʼ~µr�`b}ЧÑ!Ê}zá3j�JÚÞ Lžo>žê-š#Ç'3×è‹ôÝt�yU`.æ–¯aK"üôÏD©7*ölÚÔhÍBÊDDl‹aÓ™ vÕ^�sº5¯ έe¿É…°aizçù¹nëö¹«7Ï÷ÂFµ‰×i¬•‘Fî«<ƒ>Ó›—Eg­ùàu&0/ïâB%Ùî*8&ªƒ"ç�pÆé ØIŠ}‹Jâ÷Øþxï7ËêÃF¤ÎÞ¦âõ;Ǽ¸Í~�ìÒs-§|JDSÒS¢óJgu¼‰¶›ªßËtl´ö ‰ÕÄ9ÓQÇæ´ezËQ‡¶/^½~8*³(÷ÜÞgGžCËÜGµŸÛ¢ÙØÇ,¯ìÒcCŠHd/øÚ%V\mÎýbó¯7ßø]Ö�©ßÏ+šv‚ž¾×—spuÍ‚ko×_,É-ûÒ}1‘Ђ[‹…j{FÕ|v±Øm‹C ³¼—çÝø�xàjWüå Œ¶®dóþÄv[½ÛÅÃó5'ŸÌšoßrßúûýüóm4µ°JÇé°¹ú*QMDh ¾XÌË÷×Å OwÌ †µ‰¼ø¹¤vyœÝ¸çÝ»V—õÞ×Í-3å5ó.»JÚõuÆVÙûѰ› Ø8C¯<\þ�¯jvª|xq«L/õ–Ž#*øróêÔ¯ ˆ+/×s‹xÛ-tÅXqAÓ‹.ðËûÎÁ—¿]äÅLx&ÅRŽà˃ñtÝ­_Y¦ãViŸ¥ì¹f¡¸(æÒ%´Ð¬“ Ýœ8câÊÝ,Š/×Â4'N¦H«ae@ì5wž“Þ¥›ë°=Øà¦7(žü‘þ­x¥)†óÊe[ýÃ>#ºf…èÉpKÇ8wU—ì}¦7¾xýáÈöÓñ6ç¥5n϶°O>FðñŠŸOÅÁ;ÂÒðΧ[²™ g¾îáÙ•ê³±B·ÅX‰ùB}ª°ú÷èóB=‹­wèx/#9/õ§žGó¹wªòõê O3Ù1¯;^�êjÔë—*½’jýŒÊWt^©çÑÑëJ>Σ{šL¶Dò9epý±@Ô±—šF:…2½àsH¾NŸX'R×Qu�Ìzg¯e8   � øŠZý;Dµ'øú�¢¾þ±bÙcÂq=öØ2ñËß¾"¶urI‘™˜w­y6½o‰|X¸à$_zÍâ Ó=Í¢Œ-,W8oÇã2¤Š5-|%Vzmàž¿üÜ0;Øy>apn^•'/¶XÞÕd(Û�·»Ýàú͘ø [¬¸B4wt‰ž®.ùæ´º¨KTÄSß Çšž–5Æk¹e—³|ÓÄ'íif*3yEGS F‹f÷%í°r0ö¥/(7<ô'xþb«#Û/Ds•öX¢ò®Þè`/“·p–Q^ü-n‹‹&Ù/K#Nþ›Di�yÒ¾Ž¿�R$½f"yžvâ7J�ºÑ¨¯Ì«Zn˜3‘`Fåœ ªú-"?²¿I³Mw±@[=]GâÑX ¾¶Ôß§¢d;�¾ÿÅ­ÕO‹ßíh; ˆd‚®T¿¥'øŠÎÐÚŸ$ˆä›jkšEWO�üç5œDæü �×Ö74×pq&k�‘ëa´þtÔÆœ€À©Ü{ÈíBÒ|bbM×�höE*b šdë2iÞ‚KôqGõÛû�,úʨœù[¤¥µ¾(ãP‡¨)-ðÛ^Qµë•$ðp¿l —`%zÓá}VǺ2?>Š•Š&Y6þßP»¨ô„yj¬¯ôƘQÍÎë2òCÊÂ,bv¥q�›—ùs ²Šã‡Zjt>å8Ÿ}D�Ëd1Ï#Ï-x|²ŒJk›5O5÷d\T¿ÄË^_˜ùQ´z#ÓÉ¢MEnÇ©²Ç²9V¤¶˜*-ã�ëà\°Ý¸W(’Xùè£Þås·‘O’´ƒ ä‰sWÖí5ºMºÏg¾²è«’dÏù)ù¼l„ç !u¦_ö3¾gÙÞÊ™ˆhÄëSG�Ï+]cà –·ò Én=åµì>Îí†å)é|7úý¯a°õ‹Ù?;óª’r±¦¾Ittñ–a ìœì0<­‰ºVnHÔ÷tL¼‚§Äó10y=E^ÜæÂ*éKÍ¥ôƒe¢áߎóŒ°ãȼҚC›å™þÚAô¶y\eL­ý[ÈÅíÌ“6‰õ–°õ¢,æXIÇØ�’§³|u¾È=}A<ÛĽ4IoSÜó—!ÚÙ.`⥠W¨}M+ R¿Êãe¢  ‹‰„<ò’xí^-[œ)1Óö§nðçÈK×o+.s×ù|[ÛÄrïœÛ¸0ËCí`¢0),s<’1;äv„ ¯TØ0Á׿G®òmRýÿ¼»™'¯·™ÍF܈ 88(f ì1È»«¨÷iÌ£ÍòÌä¹a>ΣÛÙ‹˜RHWÕ(ï[Ü¿Àz'•¬q‹ž^¶^½áKžMÕúÅ ÕN¼û%.Ý{½èkd�újH›ñá@@ ?@ðµì+|Á—ôò•äxuã»ÖT¼0ÖSœ àƒ™“|ã-a÷b>ùÓÜú�‡¦å댧Þ^H¶m |PÎî‰v°3|’-;Jjùàøuý\UÏðÛhÈbOxåÅÎ=µ�àØ¬îZWîßÌÆJÝ·Y½‰¬´‡œÅh/FýÙ*·*«¨5µë|!•½øÃ ÎÛé:çˆ3ç·ÈöËXùB~p«±xòüá˜uxZ7¹Yåo©‘èý&`ºù•—%ŸüIaV¹z+Ayó’åÀÞMwÃó-]xšÜ¶úÊ=è‡ü¹`=M¢å[d~æ ªnÏ–4l§²H×�wn,_»õŠšríåKÝ8ñ-ø¾¸céJñüÖ¶´¶qä"°´_Y0´÷'¦7¢ât<ïyàÝO/{pè_'Û#ÉxO_£æ%R:ŠcŽÌ'ë*V¦·­1¼=¹[4ò¾´” ” A@±hrŸÏFï·³éC¢ö•Ñ9ó€•MþÒ‡_‹Ô[c•e墪ºF¬kŽ�¾l¼¥¢jC$ØaIxŸÕR[.Ç�BG8` x9ñpFšÒ“gÐÒæj-޶Í?t†øQtnÜ+œáÑÒ�ž¿åêÙ½Ne1Ï9çLæF9ØÊ¾k�/ Q}4/CN>Óã¨õFŽžl.46ó�”y )“(m1eZFþù¼LÕ)ö¦«ôàe¾�¹‡{³•wˆÆ¹u¾Èç®z¡3›ø˜è-’¦¬¯òŽ‚¿ “I}åyLuœ•¿È¿&vc­%î`Zò; V¬ƒ[÷ã˜wë³�8¸g®D[ï.±ÔóÔÅF»™$½� ò¸yéU~×?µ)ž³Ãe±°a‚¯>æù‹Î¹EÚÌg³Xä{Ô’Â*×+–açeK½¢í|Vo3©æÅY ¾lÞÎ$?&ÞzÀݦòí§‰Âù_pÒ^䋳tžx~ ›l wÔó�›Ÿâ[u޽àë¦çÚ´ØË0m~N×Û‹îó<\‘_�âÞ‹õzÓ•Ë6›iz‚0Y¦tñR±Ó"¤jxîaqÓ}KÅÏW¾,6;‚¯ÝâN_$Fâá·”pL ¾¡ˇZO^ël)¯Ù»Ynõ¸@\¤¼yI¡ØÆ@¸Ý%:�ö@IDAT}Â÷T&ÃÅ·œTqs¡XL,Û:h¦Ù»™mçx³h�ñf,øÊdžÏ<°g´®?šc˜ß3‡ð1˜ÏÁ¢�áiÅI6¶ðß2™ G_÷Hemü÷!QǼùshÕ÷I�·Uµ¢±¥#aÇÏsžÍ£ù=‰ýù‡ý~6^¼N•VV},¦ÚZ^¥0šóè,êJΣû[ØnA¶õ éå¹@õåο¢ø.*Y䃗­z&ñÉh ìÜuzŽ÷3¼ïõ"¯‘ñû8om!�Š‹k@@rF‚¯¨è _Jðõ˜¨}á±ñÍ7E£ôö¥½ÅÅ`õmüÍÝx¢c/øJH)KøÍ‡?)àžäCp›pJ…å2�{õcØŸ00•ºqùP3ó Åø†o§å…åoΔօYÝ"J¼Iš/&ã'¤­²N´[é½”âŸÖ‰;HqE‹m­_2Ð_ô¬èöËi<[à·-h;}«°‹ßj[Ìœ†|ãe™áäO³ãir[´'5žºµ¾æ‚yiòüD=¶ó3ë�ßž£&b –®åRÿÔØ ¾â^¼êŸWx7caŸ‹;VÕ‹inû˜–àËÏuøAC}žy1ZësÁð¤œ_x¼6Á‰º¨…mU˜I½Ñqóv¡?Í1GeP>ðÖÞM˜è�=\.ð„`\ØÅC¼�¥â*r¿�U±¯Ì‚sW½K«mb×4·û bÛŸM̼Nס E?lü1꬞ùc¼œcÔûâf•2ˆÎëlЪÀ÷,¸qC¢`ª•m[©m�\§¤Ù¼žf4`<ùÍQããeo'ÚºRíåÅ(Cv͈²|šiFlSYµã¹c¶ò2‰ÒS¤$æù7ÛqQ€§ÑH㪄/fý2…Hñ‹ívecïs¼ER^_ÃòÈÙu'![Æ žÇLÂy‘ètƒå¢=Dzù0_…Õ¢G.Bsïk¶íÚG£>ižü… -¾),¯ñ½4òû9.¼ó_6 iɹòz“Áý¯=�ÏžVù‚�Xyß K*Dc;[�ùÑ÷€l>H³µV¿Õ]Téz± aÁƒr.~½�ðó‰õpyy63�âõY ½ÀÙn•ý³|uþ^,ôÖ¼¤0ɺe¢+m_þ]_剀¸«›WÛ„bJôº¸Þ‹ßóœ• ~ÒÂ!GlÆDB…÷*oQÛ™àì*±Áõ:¥®l~·+.4Ú¥·fd‚¯ƒrKBß¹íàk|ÛA¿öTƶ$dvd*øâB°…K™—.?ïmZ˜Æìi`ÞÌn^å Ïü0qNkot·¬”\ qUàºDá^·à¾ +^ ˆçâñ¿ÍÊ:íø+# ;Oó—ˆ}�ëu}“ö_ŸÀf¬_×ûÞ²¸XªµA{¸Á×>& š'jw™Â,%¤ââ­â׊��1UP”ÅEbt³øƒëõ‹çc··•¤Ó™à+—å»·™áþðäB¿Í]tßk†àk˺Øoq¡\¦‚¯bϸÑÙÙûÆ‘ê§Gv 3 ·~±ŽWòJ>®f6vX“a'íüâðß2˜ g³îÁ,KuØZ_#Š ÂÖi½ó…¢¢¶Ñ|i0›y¡7'Uí&äù/+Î!3ÃÏçÑü·Lêy*Fêw^§øü9~\ j /Á–³á•j=ÊuEçÝœ7™¼›-™æu_¯±Y.4N5±ÝÂÖ:Z[Ek{‡èêêI~ÿÂbˇ>¾ÚÂ^Võê—neæØYÛðÒq.dçÃÚŒ=BœÈ¾¢’î¯ÔÖŠZõï·õâ=¶Ž�òQ¿‚yþZñGq �Ö˜ ¾ÒØ£ÜØ�E4E¥e¢´´ÔüWV&ŠÙâm˜� �m©0c.ACl’Óiöö³ž ñ‰�M`Æ'>+ee›eÊJù⼞8Ö³½ä½‰tAQ±ûv‰ýÁ6OÏŸhù«’9±ýÙ]/óø2µŸ³©l²¥jNzÃ<|éó6»çx^-7LC]-¢¶ªB”KO-¢  @Äb1çŸÇ˜{8sÊÝ¥…Ô žO¿¾r;¤‡6[îUÜú-o]î‘™g‘f€bè×ÌùÉ\2áŸÏ'4ûQÒµÇ?› Á—ç™kËÎ�¢fÕqÓõ—‹³œ1oñ€}>(ÞLCô•‰à+ C^ýþDõ…^›ðªÉh'þÆãÕÛØš×qÁz%/÷§£9æ8Yå™b¢¦5þx‘»¶ö.Ë%%½- žêØÒC óüÅùfÔogÕ‡°z‘I_™ g)ŽÓ©½öS ŠK¥'“ºF«Hš³±�K©ú¬!ÑR/Nʱ¼¸HzûbcHŒÏ?*� Í˪¤F‹H†Úk}á_ÌwÃnµɆ›³}•ÇËôúÉÛ1q!ç–Q�’Öó1ÀΜÕ.ºçõ‘�çQããy°Û!u˜ÌƒF°ß±Dºg£ÔÆ%“6Źe8ÿH™7+%"Ì´-¦L‹�5¼^Ȁ锥šci¯EzÞž*ÝѬ_a6ñüxc-?V_¹­™Ô×tÂEg¹Í^>Œ{,*EìA ß²Í(—Q¨O<ÏþŸò­h¯ÞV4vÈzåzzbs›ueîEV‡BÚO#±<"¶gLš_†ºDsc�¨ª(EʳqÈ\³ÒÛNšç'¤¯Q)óñÁÏËûf*çâ× ù;?ïÇç‡E^ÜfyhãS$·L ýãá3åÅû5VÏxZ¼e:Þªx¢´]^öþ†•G ?æ¶ÛŽ�ü„ÔE³ ŠE}‡)¹ãöa½EÍßôºg“YÙE+Ó¬_»_òû\Uæ n¼EÜ|ã æ¿[o }oTê�c\(ÄÅCtÎ×Å¢[ád<‹n¼Šµg&¦J&Nb"!O<ÄEH‹˜¸L ¤Î«ÏcLHÅ_2=}­-×^¥·>¡çý×®ÔÞ¿˜Ù¾^oÛÊ’Ù)_ž‡/ÎÔ®[p/`%Š{mÕbÕSÁ�‹g_ÔÂ1#þ�-6¹ç6¿ƒío¿ø„x@–óÂˤ·¯Ïž/bçœíþÓ÷0FÎ�Î Ø–”ó¬ÞÉÆXðuñÃb›Eì´m4_<`Ý qõ}¦gKÕ?}ùBqç’Ubí[m‰^¿¤˜ëR¯ÿ–^Álùp¶Šô=‹™Â-% Û¹ëm±lÉâºkJo_óħ/˜'Κsþé1 ®óµøö”NÚ×3¡Ù xòûÞø-½m� Ö2|eÒgcY†ëú¼Ÿé1Ì6îòsÜî°9X&xÜöãdc û-dþÄYùsìÖ=ìV&;ÛÕÞ,êj«DYI‘ß_ë:êö?Ò~ÿuþlæ…<ìΣ9Ç‘-_ó>\¿Àªûe¢b¶{‹…4ÏsH=P¡¬÷©æÑ#PWòiÍÛ¯½-|ÝSQòa¤ò ÎV.<\X?ã·gÃäkd¼þ„´# |È9¾F³ú·1O_ÕbG@6悯�Á™ONýIÔ½›ÍŸ¶·g¬xyÜ!6ÉÇ€¢ÌOO>pwÙq[ùÄÆK‡O|nüøøä¸€yÿèu•\ ƯSÇêí’&CÅÏÓóíáù“¾ì;U°›/¶ˆÈãËÔþTlœ_žp„¥~Þ£šä“ç5P–­k˜7+{�¯^D5l ÄçYÁói¯¯cÄœç=Ãröò’ì3¿Tt’¥ÿ-jºÉb ¾V÷Â割lŸ;6.ñ‘/úi½°]“ù¹^±å½­bõš% Þ¿.]Ú�2�t_Qòöï÷'ü&;É z2þöxÍ]ëÊ|Þü­Ã¨y‘K™õ§F{òú†äŸi�9nV9ïÍ;íaˆ=\–×·Ôè± ¾•÷ U ¸IoFý¶‘çÌú­‘é+“óõòÂ9«-€¸ÐÛ»ÆûTžLšºôƒCΦd�¿LgT>kŸ®®�ƒÊ Ò³Ñ ¼˜™°‹ØC^þÖ^F‹8FY¥gç&lZW^à·;ÝæÍ…=�mòO=—ᱎ"/n³,âò5ާ¾E¤ª£¶­›&<|HYªë¬¼Ò˜Cóv䵕äŸz¼�ÚvyYð2ròëü�•G ?Öר�ÒÍOA¡|©­f�}‹^öò�;tÓÐ5³Œïd6yz¾=¼^d8öòø´�ÉævÚþèe­L³|‚œdùÓ¿Í»c­ãŠ‹‡Òct~À³VÀ³—'c6ùâ!¾•¡ÜêpŸsí&q³;†ÐüûÝsLH|dÂ.bÞÆ6<òužmˆ¬˜Ù¾xu»Å“³3Dðe×-:_¼Å·×ç³{­±Õ£Qç,�.[^f¡ñ?¯ã÷½“Ii‹™Xˈß+÷Ó·I¥é1d‚A/ì¼{ãõÈôD6Æ‚¯ r ø ™©mW>¨½gyœôg¡¸så-üâ‚/éá+q[FåEŒ{3…[ O/öë‘NC·s}Î ·{@ »~ä »Hܶ®3îåkï«-SÁ—ß×½oÍ~:›¸ Ó-_xÜ<¿ÑÇK"Æ);¿ø%ì·�ù·ËŸã«­Þ$žãë†y]­¢~MU‚÷¯¢ªô½Ýªd­óBž·4˜„•¡ÏÊÍçÈÃèì³²Èj^W$Ö´¨‡cìžIõϱò�çNòÒ4ò¬ì´òJ5�æqÆ ÝϘõ…ו|›Góö[²Æþ$O± þEÍOÏ^oìåŽ×Ã`�¼¶ÊË8¤Íyà;€€@n @ð5ªüûE}µçåë—¢-àâk< ¾J+«Deeeø¿ éáC¾­�Ö_Z¹íG�71”[ø.›øÆ6!â*,UUIl–ù©¨¬�—Z固ê£Z”'¾‰¥&­…ì� OÏ·‡ç/Va]H {àÊãËÔþTlÂÒ ?ŸFiò¼²ÉßPk�±È+*5uõ¢©¹Y´H¸íí¢ÖßÊi„_cÅœç=Ã4S‘�Î/Õ�ä)g“n²˜MÁ‰;v¥W½R}�_‡FNðÅ…f{åV<ûiPÁ}bK /_é¾²aÈۿߟð›lÖÆ’ñþf�×¼ªÇð*û¸Ê¸§…lòâÅžvÊÛ“ìgGtÌq�áoGQ‘Ú’±Co§Óñ¼UIQ=ëD�·ˆÁD*jÎ7£~›ç9ã>„-…Ô >&ø7ü<ÍÈœ‡Dks½¨–ÞL ¼qšJñ\W:gSî�tËÃûèoªòÛ¡o§|\[ÌãŒÉ:Q#ê›DsK‹hmííÍÚ[—çÅÊøÈ|Ö8{+wˆr_an_ä… ýÌ–wwOnÚÆx%ÆöÏœ[FuJf€—»îGxÎ86þò<²:5>ž»¦­‰eÈmN÷8›zø°üó”9 ß^Î-ãvÌc·ó¸­6¥ß-±N±ü¢Ó)K¹i�·IøÊ™Úë‰Ý®ll²…åç2뫲”p‚çѯ7îU|¬Q÷éϗͱÇgÇëŒÅ›’öd™`¦<1’õ©_Ôx}x¬Ìy+¿Þ¸Ê1Ô¹cd¿ÊÕÞ»]zë墪fm ÏkɸÊÞ…yG­”ßÿ’‡O¼>Ê™þÖ5†‡§n…ä'¿m^–ÎC›þ±NòüŽ"¯$ùm¬4·¬n¶”T’𜙕Wõ€·ýLÆÛlÚ./ ¿íòÌp»ý±q™å ÏO¹ëUnhhHð–`Æ©Töñ42aÆIûþ@âéù¼x½Èpìåñej*6Fßc”kcÆyN%ñx$_7W<$®¸?üß½‹ÅªWãÛ7rñÍ¿A,}$I8çOˆÝ{CD^žØ‹‹„äx§ÅC{Īk½­ ÏÏîì}¯jÁŠÞþ� ©‚‚¯^ö›Œ{EÓ)ÄÚ*ûb¤[D[ˆa‚¯¾õ÷û÷'\@Å·tä絸‰Ûb÷ðe×-xÜ>)¬ò¼c&<@Ÿÿ�+†3·t �Ÿq�{sÛ%V]Íï·Î7W<.^{õ÷bsÓëb{óVÑöºö’æÛ(K’ÞÀ‚¶-~>¸è ø ™y[1îܵ]¬~z¹¸éû:³¿�"|͵{ |íܺÂ(‹³._$~þÜkâÅ�›Å¶nÛÚÄ2_Ô|­ KuøkV8"´Íuº=^÷t›¿Õ㘠¾2\×OÕOg3$öÒæ·?^ÉKRÙ>v˜ñ'~K6¶°ßØü™ÇÁíòïQøø*ûÓÑX—ã6„ËHËY[ñÖà¸}!ùRqZç…i„�2�æy¹ë¼±²È` Â›uŠÍ“»êý—kœþ·¸Úz¿“νƒJÇÊ‹ÏGm¬9Ï ëJ>Σ9ë°õÅŠÿe“žž½ÞØË%,¯‡~{vŒÍb�Œ—±­p8È |�j1pÁ׊ñåá‹»f•oYk#,­ ƒ|pļQ©çê�O`l"¾�SeóX=Ô/*׋ÊRv£A1QÛ�Û:Ñâù ˆâ¹Pÿo¥þƒgýÀ5ûS±‘ôôÃã&#ì¼¶6ôˆç•Mþ8—‚²ø›ÜÁ8Ö”xo�éü6²øxXžOËí+æY¤Éóc;ŽÎÏl#>["–sÙ¤k‰Î?¥è�3^¶HÀ®·µ+.³vÌ"æ‡ÉúÓÑs<›Æ–5¾ˆ«È{cлVõÑrÑ"¾xR#·ô<‘(Aœûv¡{mä~;«>$u½°•©\ÉÑ Fhlïïjõµ•:^É-VºÆ™7ð:¶�hûšR¿oðû,ÎFnKVÛp‘ªØ3/^~8¿ü¤¿¡:æ=ª²Y¨í½‡‰åÍÚG€[]Y�Ÿ~u«”V°‡òAû#×)i;/wÝ�ðL±ºÃçœ9ëk¢Æg”½u›iåI¯ÄgdÀ-Nû˜ç!ãzø°üó´9 ß^žf†ó·õ˜Çb—¬-òëìÇ,ÿ¼^È‹ý­÷dÛ÷Œgn›íÍÛíi鳜i&õ5›xÝôÒäç2ê«tVB�xýzã^ÍÓÍtœåa½|‹ú²¼JkES­îc•·âu® 7Ô`÷‡ìꓼөõÚ·ôà%_ô¨(ˆ�©úÍní9Sm7Ùζx­qÞ^÷ iÔ4X;HÆ5òýD*(ÎïqïÍÍé½ùÍË©J šŒñÄ.FSÉðüùÛq¦Ñ'´³±Ï¯�ø‚õpTyq›úÈ- ”õÕ©ŸÁ÷DzáÅï}YÝqŠÑý_Ôñ–—k¦m——-/#mWx¬¯±q»*¼7æì—†žMe_Tf¡ &»?��Ì<¹XÒzå¥4þ×[²|ñ-¥0h� žRó-~]‰§Òs¥s�çJ¶w.ÚÇ„H×/ÿ½X{ëùîüð뢡ÓK› ©_r;ÄÕÚ{UaÅz¡¶sôæý ù½™fG˜à«�ÅÇT\”ÅÏkFÌÎ_†·1Æ�ooÉù vîûä¿>öoßî6ÑÇDv\¤÷@È–ŽÜv'~ÎAn˸ªy—ÉIÙÆ¼§q›|_NßMâæå/‰ OÝà3'™÷—¥xOs6qÓ\wmÀv1O[Æyå…+É¿Þ>±qãkâÞ™ëÌÎv‰\ðê5l»¸Î³GÎíÖvÆÓzñÁ~|úögE«Å½=£§mm·±x_ìË®qóM Ä‹{užFSð•Í83æc˜7ä„�Wò|*›ŒyXà>ŒEo9L6_`¿…Ì�¸]þÜИw�𳠙Ǯ|¼Ý¾,iæQŽõ¾àµÈ4öåÇ<šsÝy�y×ß\í·w5ÞV¬3ù©oÙðJ5�6âά®ð¹]¾Ì£+uœ®à+›|ð°asöžÆJ¿Œ½6j†Óu‚×CïZ§Bð9s¦kd["–sÙ¤k‰Î?|‘WíH&®ú ^»�—7®åS Äœ4–jQÙY²ý{"°ÐÏÖiÁWÁƒ#âá+†<¬néۄ:ä€Ç«´šók¼-ù¹ÌÚ±Š;Óþ” ¬FzÌaY]ã{Œ‰’Òà¶�ìByèo÷+e%úæ¿Ú�ÜË#÷ÛYõ!©ë…µ¯Ìrlïïé]=!c~G�/ #wAŽ‹2ŠB¹8¾!Q[â‰Õ"UÜ»œ-ø‹{R˜æ¬ˆš«tùExÎeCÍ¢Ø}A…er{-Ï“ˆ¹%'‹2Éaöõ³‡y2+ªªëØ«5­&ÓÈuJ怗»îGxÖXÝác~Èx5>£ì«™·ß.beïÿá «zøŒÑü#eCÊD…Ë´-¦L‹/èòz!šÂ¼�m»˜DéÑ)=)Lôúš�M|lóÚˆQ_3é«Rƒ5Ú¤ßǹá¸-™Ž³<¬—Cð%ëq¼ï”oõ–è~VmsÔÔŒ|}’d¢ÜÒÊ ¿Oç èõîØ*ûhýrM©©Ø_H;à}S�«¬Yú%—LÚ3KÖzhÜ¿èmެ׺'ùCK§œäØTâ�M²­…8¿¾G4ymi�Û¢8 96Úž•­++ð øõBÚ’^Š·ÙZ­¢Ì J=T.5<^Šlx¥Q¢Ž·¼ýeÚvyYð2r«Œ*-]ý±¾Æ~Äí²ÇmÇϦ²/*³x™ÞÙë-Y ¾zÙ¶ˆRÌcŠo¸G‰‰LQ×v&Ü™wdzL´ÃÃIO\Rt”‰�Œ‹„ ñ·Uz‹Š¹}dìÆ•,m&¤²¾î]/z}ëü[ÄÒ;¼íÏkw˜vs;ˆyÉÒâ¤nñ²/:#Á…]\4ÅÏë°ÌNCðõ¿o^°t=Ë—g[›xx¾'¬1q:nïÚÄO.øò¶æ †ã×8[:rïa’CŸya7?r•owaÎq±˜,�xXé1Ì÷Ö&ó"·×ÜíÇ9~_÷6ìKkíZ+>íÕ/CØ•Žà«OliëÔ[6DX+oŸç3®Ø(ÓîlÐkT‘•'ÌÚ¹u•F­'Û_÷6ô%æƒoÏ(ã^Ë\^ÜxRo?yÝ’¥þºÜY·¯5âMÁW6ãÌèŽa|´L<ƒSÙ}ÜO6_`¿Yç_asÃì×=ÉÄÏ4Uyë1òÁò�{J˜yVÛº;Ò–læ…|N:‚óèÑ+ß�9cÔ¾F¿ä¨D_%µrwþ— />µÖ¡èu…·•|™Góõ…‚2ÛóDù¢JI‘(,.Å%ÎsÊlòÁƯÓëuhÛ:=ŸëózhÜËzym•·kà• Ç  ù@‚¯ˆ¥°ã¥eÂÛ’ñ?~ùGûÃȪõ5+E@ïåÿÅ>1à|b\Q'ùÂXhOyÏ ŠÊ;Ñv†Oä„´(Á³Š|FÀ<~P±Úz+þÇ'0Ö|óNòÆ·.øDCEÓ¾Æ]D*åîd¸¹Ú{ �D˜²ž? ò<ØË�1—ù+µìýÍÅc\ð%7N×Ì3°_e+%>Y7�¹½v�šŠßúÇË’MþL.ÁÇýbMi[  Qå (˜-,>ž6ϧžÄ²pcÆ<‹4y†,ÇÑù™õÀ*‚°¤ç�Ê&]/Û§\µí\)Î’eã½i»°ºÁ.È:°U”/Ð×QìnñfP¶¿Mü®¡^S‰ôƒ RÆÆÇ‹XY�%~û)Î4“ú%]øE¶‰Ûê¥Éí°ÕWuïÀû]þö|ñ³<îà¼Ì´%6|œUñ›aÝ^ÄVgÔņ‡Kþ¢ò¨Õ'•h{@È£ú=SàÔżg:ã¬lC±Ò@ý ÉS2®rôÑ‚™ŒÚ³²;ÙŸ)T¥¢JÑîݤZ‚õ4×°zª¶Ž�Tü>ÐÛFÛ.û²"wÜ")‚÷ïg% Á^½L[¶ ý»º§Õ£KnxÉ\…”Ÿ‘_¹- ·›ŠªŒq12¯4êAÔ9œÙþ2k»¼,xi&¬þ²qUÿ~dÚ¥Ë?’‡ãõ�×CcÍ!›5²d÷qý¢I­×É-^ëtHá  9$ÁWDøÃÝoŠÇ|ï]ҋ׊ߊæ¶÷Ä| Þk{[¼ôK&“×½Ò–8øy‚±(&„ ð‰q±€ 'ù|û#5/*¯­]Ò3Ö�ÜÊ¢½YT—é·3ÔÛ¸‰¦xgø„AÆ«â.«©—^CúE¿h­¯2Çý·šex>�á/jùDCè­UÜE¢¶±UôH›•ëàæuÕl]½ý‡¼¿¹JßHȉ]å¹µˆÌ«²§§KNbÖT0›äÝîúiX9èmL” 1QY×,ºT\-¢Ö÷2Ï»!øŠh¿Êj6¬.7‘æÃ‹2¹ýKG{«hIÇÇ2/KV¿šÙ›;TP&ê[»–-õ¢¢˜ypË¿¤ÚÛ"�ÙÈâÓåkæ“?pËóèiò%GçgòQì[ÛEks‹è >JLVd“®%:ÿ”'¶âÛ4ªvÖ‚‰%kêÄ+o½%^iX'–,½]¿9éÖ�Ÿ¾•èÝ«¥á>¿½šž¼v‰r+ØxûútñÝâñ—¥0lÇv±açvQÿVƒ¨Yõ ¸Ò¯¸é<ü–Ží:Ô)îð¿@¬v·‡LGð• C{’ºMø Cx¼Š;o“ý]­¢š/¤ÄÊ}ÏQóµ?µ1‡sáo ºeO%µ¾¨˜_j.4ÆëSƒh'@´qG�Þ‡¤®|Là}e4Î,=É­ ´J4¶´KŸrÜ–3;Z�¾ÝH?-Ú“‰|ðR\)šÛÕxÐ#Zk�ñXÕMßNËŠ|�W-çNZ¢±–�ÇÞ8Z"š,žÇLošñkËÖÙ”àFÉ[¿DãfFÅÝÄ;mQ湤&ð¦$z�âånŸ'ñ²ÔFÃÊGŽO´˜e_TáÔ™®ŽV±®šo1/¿ì�ü÷ˆ ¿މt·YÕÆeÌæfýHøf�c1;3j‹ ±N$› JO|Å^[“Ÿ¥r^×áÌëú{:D} <=Ñp ë×èõ+ºM|LÔm$b_eÍ•y’ç18/‹:Ϊ¬ù°Ö™¸=ý-5þÜIõ?åN_8Zõ)žæºò#Må]Ì� ‘x‹Ûïü?$OɸÊÙð( ¾dÌlk�x?._ ªªuÄ©ííí¢½µE4Õ׉Ê2í…Ò¹®H?¨j5ËÂãÜûàŽ–u¢´€µ·b>G1ÛiAIµ\`W÷«rL­¯IS¹X?W¼ÂÆVÂÎaO`[µ½‹wë’ ¯*ï¾ ¤_�ºv�MÛåe¡û N„Õ_ãž�_c?¶ö öKCϦ¶/Ú%êýAXž¢Ï¡£Ù¯€¥fVvfÛMw½Å&øšwíb±bé±<äßÒG–ˆ ;â»ø¶†ªZpÇbûNé•kïѹu½X~«çKõ97ˆí¾ði�x–{j’¢U¯nûd¸ÁÎíbóóKÄ_¼$qýS›Ò'1‘PPðup«' ‹ ÐEQ©_J äÙä}.z~«Å6Ó›Ö¼k—ˆ·wÈ-;ÛÄÛ/>näMÅ÷HäÂ-.óDR{™�ÌÃ×Á^S»l±hhj�;6‰——ò­ã\øÄX:½¸ Ë|É8>{‹x­y{|È�›Äòkµø�ÎY÷¼Õù{#¯7/]+:Õ¶‘»·Š†§³õO¯¬¿+6ìv½Á±²4_Òξ¦Ç�rXì”A~ ¾¶Õ?Ìlž'*Ö½-¶ííÛäÚþÏïÖÛ$:õÊØf‘‰³ !X|ëÃÖ�KY¼…âÞ§ÄÆ]ûD«Š{×nñâÓ°—"ç‰Õ»âáVj¡˜ZO¾÷¹Íb‹kϲ =rœð<|½²„ÙzÁ"±zk§“Öæ·^w^“¸[¼lC‚¸m÷À ÐÛ>ºe?w±ØðL6ª‚¯Q]�>„œîaãUô±#UŠÉÆ6…Ì�¸]ü^|$Ö=ì–w‰Jo^æŽ!Åå¢v�ŒÈuk5�ninuµ•¢Ø_ ˆ×Aîe?›y!O¤æÑœcnæu=¢šß«Ë—EÖ°7R²á•jµ®äç<ºßÜj>V"Ö4Éç‰r—uŸÅëdAEÜC]6ùàý…3¶H�×Þ³³þ®QÅ×éI{Pçáx}ãõÐXsèi2î3Z[ ¹Wí»§±ÂßÒòØgïp@@`„ @ð•Ð÷Wû^º<ñ–íó—õ;¬©x×ZLq2l€O fNò�Ev÷b>)à“|õsK­éÖ[8 ~V5ÙbN´Æ9ãMø`œñ �ë¶×�ŠÛÊ'6FJý-¢¬À[”HòYÄß–Û�ø[}% #oJŠ*ýäÂË¡]”§cƒŒÏyÛ�¿ÐÉþô õÍ�|ޥɽ—ùå <”ñsÍŒ7XYñóNƒL‹Em­éÝC¥[Õ¼Ëx@c«U¼˜õuì™+ï‘Ë™aL8ŒÌOªl_Æ[ò.¾…NBzÞ‰lÒõâ°|z‚/%¤z|óªe­º®ÜñÂV«‡.îÉ뢟֛×ìKÜT ãðës’´nZµÑŒCÚ©…cg$ø’w=VþÚŽ°ºßcxxhikäÆ)kûáQÅß‹œ—=‘úSeô¨Œ9 6&º <á¯q™ó¥KTêRƒh/PÄ~;zÂò!ðlõ"¼¯ŒÆ¹¿¥Ö²ðokk¦  ''ÝÃò>Ý&Žâa‹+kEE`ÁÐÛJÒ+92ê1Å)o‹G}qÊ£lë§ y ÀˆuŠ—»}žÄ†Ù\€·wV§"Ç'3ãyÔãåÆ�‹Šõí¼ìU¹ñùŠÍ£”ÁŠ}‰^oX]aùgQzM{Ç`.ÀlŠÚy^lÇֱ› Ê…B‹Ô�ñC•mIM³-êÐsÙÔ/Y ‘lâùäm$j_š9ï‡dó2Þî¬\“ÍtûñóÁãcuÆ3…oU¡î?Öu ‰ÑªO*M߃W,Þç™íF]Ñá�³q/r¬OR?«¿°<%ãÊû~ 'Ú¦J‘:Ñ.'åÐÿ¥;øý�|£9ðîWSu@f+ÿX©3›f´r/ض0ìœ1gÉ/žnHYx9 æ­Ø!H #ñJݯ;iGoy½dÌý2—oêÛïu{Œ±Äo»çÓù=»q™åKøÚ„åâ�S©ûe0 3é›ë-�¹¯7Ɔ”…Mð¥ëX .V¿¸Ý9½ýÔ-~_—,ìÒõ:Œ#&ê|],úlx~\—=$:Sˆ‘|qó¬•(hâB))N{„mèÄÏDZÒ×=M3²yïrmݾ*Qdå牱Tçâ‚¥¸°*Á—Þšñ âµÝž‡­n±ûyÓ‹W0½Wke‰|t<>OÆ}C…Œ7ø}髺¬R„[Xñ„x€m5éÄuÙ±o÷KzÍÃRo/ÿ.«w_/ïè ©åñÓ‡ä‡ç½ÊøäÛJAÕ–€èȸvÀ_Ù®ÝÖ …]Ý×ÀÒÜ.® ”{�›ÿý.~J•fŸXö#ï¾/y{ºôAnO›¸í‚ä×ûöÈùÜêθPÌÜÒ~¡X¶r1+›ø5ÎV’Œ-ç¤Ò¹rÙÛŒU<­‘|ñ{>c¼‹4Τ³..+[ĸ“VbùcØœz\ÍfÜ×÷~�pÆ–Ôs nWp.œî\7£gA `ºìY{,«M¼¿Œ6/”/\ŽÂ<šsÌÙ¼n(¸EºôÅî!¢ñJ]‡T‘Fª+y:�Nk}Aî\àïú�E>xá·]Vïù9îµ�‡3ê¿çbñ¨gA‘×Èxþ÷q¼ÞûU/ð  �|eÉýƒ¶7EmõcVá×cÕµbãŽîв|5³EOo{A{Br‚VäÞèUÉåïÄ¿~öFm‘e{Åž–:QZh¿IUocÔ·ÚbMLÇ?#'!þ6r+ŒFõF²EüUTZ�°MFO“öÄ•*ßuU¥ö‡Ó1ù&¶ô’hu¿ôRP. -¶¨‰V¬ XTÕ™ž8x9TñÙ´ÊìP»¨.µÝ|‰ù–@]™÷[©ž,ú�zD¦ö§fÓÏÞú¸‹íoeÁç!{Úû&ªÎ(·ÉâLû[ëDIAâ"ƒª3�Žƒ•.QU\`,6T6IÁW6õuŒ™;,²JÓ i|‰Æ/^¶®äíE'�Mº:óhw`KÆ +Å÷„ ¿. Ë—‰WÞï ˆ°üï;6.ñëÍ¥Km[C°L, MCÖËX<�ß±-!¹0í§þ¶’—‹ç÷ÇÓî9äù0óü•¡½?I݇Ó~×x‹Ä:齯¦”{gôÚ¨ô†Øœ(ŠšÙ9dÜŸzv�ø˜ãEì~j*ïl«¤ÀuêkcgUde/ϼßvâˆÔ‡¤®£1¶÷·×‹r&Òá‹êíãâ²*ÑÂRG}µ~(ÀŠÊ¤çнUšéíJò¬ÔÛ-ë´ä.=Qª¿®FÓ#(YÆ-¾5§ö<æá#»úi¾Õ ó.çÛ•y�Š<Ï#Ççæ¡]–}q�;‡tçW±Â9’žÞZªý¾¼¨Š/äÊ·T½¹@È‚>¢„ƒ¨õ&Ë6©'ož)uQÔ¶h&ø–j.Ø/=B½¹í9VX*ÖXÆ�@ _³­_"‚Mö±6nZ´¾*![ '’ÍË¢Ž³Ö|$©3q£ä›Ë%úžÎóZ9*õI%(‰ý{>YWŒEi—Rc…w?$Çä"˽j’<…sͲ=»¶%ûèï�Þ®ËKŒ­>õ8Ÿ[•ˆêº& š`|­NÿèÍÃøgL”TÖYÅÜÊ#UcÀ«ž—n©HõÈ-�½-XK]OÖ^º9á%=/ê{EKùzƹŸõƼ+fx(ÈœWêz “Ï|¼�Úv³î÷´Ñ GÍUZH˜°6‘pµýDjû¼p™3‹r`íë<²{3·?5›^o98ä·6?r•?_òÚ{²Os+Än±¯©VÜ<ßõœÅæá*ŽyW/’ž Ú|�˜)&jk¹ÁïSŒ4Ï‘[9J�PÁmÍð‘’ô(µÐM?QÐ%Q«=qÚù–m$¥˜ë2·ŸT‚#&vâiê8øv‚;œ°{DƒÅ³–ÊãÍK/öIoa^_z3ó`¶oýC~Y9ÇíØ%–_íõçW‰ Þ6™®½m/. ?ëy1‹_›ÿ]±B îúšôÇ‚GÖ‡”‰-/ÝB ¬¾.^ÞºI¬¸‘{oó쑞Ú^×b¯¸½²Œ+¸8Ë»V–ïòø¶’�¯>ä³pêÀü‡Ä¾Îõ~Yª­Ëc—XÁ¼ÄÅ~ø´×jC?Mñ–+`Ú»Y\éÕÙ‹—ŠmL””x½_]îÚ¹ýÚÖ�Ëýò»t‰éÝjgÛk⺋½ü³Ï nkwuêíçÞ,þÐëÚ§Df)ÒÜ=Ð'V/[,. l‘èµ§³.X(*žKTí–Þâþ›#yæ.?oØ.VÞîýÆí9(Z·®Å±Ø§¯Y,Ö¶)»;EÅ5æÖŽñ­$½<©Ï6q“oïôþ-õh4Ö‹’XÊ~êÍuÕ¢¤¨Ào�^{ð?ås›’òjÑ”d«¸Ìç…Ê„‘ŸG�fùf4¯ëXgÜwy÷yøÌy¥®C^ÜQÖÈòqíä§Gzײ®™“(.¯IxN5\¸U)½ÜÕ»(¹cP¬HT¶> ëg”íÉîõ"­­&¹ïgÏgmÏ’½º�O�±%0R‚¯ Êl91Ëøï®åƒN˜MÍ8l>88ÔGûû†èÀÁƒ4iÒQ4eæ š9eRR}ôQç÷âb¹ :þz»ß¥®®a¢)D“'O§£�›C³¦MÎÜò�×éÊéMËUÈ‚Jêyñ_h–<ìݳ‡ä–M*rš}ÜI4'JÜAk†{éÝw»HZíÄ;}úÑ4gÎ,Jeõ@o/õ|ðõ;y�~ôlš3kZ0ö´¾Hní’Û”)“i²LÿäUnÓü‹hš±.¦î==4e:ÑÐК�§@Ö¯Ýï¾CýSfÓ”¡~š|´,×Y&ýá�^�4yÚ,‰"WFä‚yViZÉÅOFæ7ÐMÝò± É2��q[�œ®%/ï‹!¢C‰¿ ÐûÝ4E_úé&'!¹Õ}õc攆ÖK"q³Æ”ÆÉˆu*�˜Çì’á�x©>gš;Øw¿r/wÁ¿:6HQ2ýKŒÏ�ºégŸ;Ž®©�ê{jé<þS:VgUoÒIÀ~͘·ãHmÑn{ülsA™fwwõô;ˆœÛ—ÙÜ6YòQQ›"öU©lO1/ËfœM•tÚ¿�x}J;åè¦à=âtCÊ1¨»‡úåx8$;8yç(ï÷¦Óq)ÇDÿ@o7u} ÆSÙ¦døãN–ãcª¡J–ÕžŽ.ÿ^õ¸“ä<.U•dÎyé|G=ŠÄ+ÝÄ"Œ·yÑvÓÍßh\�™2#êý�- Y�½í·Ù‘ú\c,�D.±Ú¿�ŸÉê¸wïn¶ž7�ŽžslzkŠÑ®½lMmÍ96õšZVÆF I\ûL£ ’ÝëÉߢ¯­¦‘6.È9�¨z«+VÐgœA3gΤ‰'Ò/øŠR’ãMð%�Ö0!‚/ëµ8  0î ôÓAÚ'ÔC¬ñû7‰&ЉŽ¿€å pØò8M?ëÛñœVQOíUŽÀüD1öY~‡¿çª»žê?ø ÕÕ^G'V ÐãWN§oÇ׸Hzþ‘‹\sü+†ß}š>õÑ/ѦXµ7ÝF'û¿à@@@Ž bp?‰áGFf³ÌåÀÛOÐÌO]�eþC´ï©+ògÞ?¼“–ýd)Õ·ü‰þÐs1­}êŸæÅ˾óºúqóxu;]÷Éc³$’?Á•ØK‰¾’ýõôÁp(¾’yDüÖK¿úö1ô½'ã™­hØGߘkЧJ¥×±SÆJíuD@G&AŽ0¦àË\ ;ÂP »  #H‚¯„™iT|IbÌÃW¦üp=€Àø!Ð-½| Ú¼|�“,'½{•�w¯q’-˜ ‡)�az÷õ´à¯ÐKn=H¦YÏ›l½C7L8•~êÚST±†î/þ<�(]Ð ì¡ý}ázWíE%Ô2ô�æ¿]>@+¥ìkòç‚ÊFzñ_>•7¹‚!    0f”—¯þ¹™›Å[ö˜‘ï Éyÿ†UTtþBzÙ5uDu&ô�uÝCz   p8سmmÛ#½ u�|Êô±gŽÙgy¦=ï´ÒîÎ}4å˜)´÷Ý>šyòitÖi'æ�÷…qæ‚€€€ÀK`|Îû1/>b+l¾f|`mzkõ9kô'Óg~,oE“ùŠv�€@&öl£ ÛöÈ GÑiŸü¼Úgׂ€„€à+Íèÿpä ¾FŸ-R�Ñ_9,U¾rIƒ€€€€€€€€€€€€€€€€À8$ÁW ‚¯ÂGÒ                 0 @ð•ÃBƒà+‡ð‘4€€€€€€€€€€€€€€€€ŒCy#ø*½bÊ8Ä—�É?ÿùÏ�¾ó�ïdBƒ€€€€€€€€€€€€€€€€îybÈÉç�‹¦f”ß+VÐgœA3gΤ‰'Ò!ÿ2ŠÁ½ØSœ}oþþ(ÁÇu˜ššÇþ¯}íkã:0@@@@@@@@@@@@@@@@@`l<¼z†“_cÃÛH‚/¾€€€€€€€€€€€€€€€€€¤ ÁW @£ù3_£Iqƒ€€€€€€€€€€€€€€€€ÀáG‚¯–)_9„�¤A@@@@@@@@@@@@@@@@`€à+‡…ÁWá#i‡ øÊa¡Að•CøH@@@@@@@@@@@@@@@@Æ!¾rXh|å>’7 &@IDAT�qH‚¯_9„�¤A@@@@@@@@@@@@@@@@`€à+‡…ÁWá#i‡ øÊa¡Að•CøH@@@@@@@@@@@@@@@@Æ!¾rXh|å>’�qH‚¯_9„�¤A@@@@@@@@@@@@@@@@`€à+‡…ÁWá#i‡ øÊa¡Að•CøH@@@@@@@@@@@@@@@@Æ!¾rXh|å>’�qH‚¯_9„�¤A@@@@@@@@@@@@@@@@`€à+‡…ÁWá#i‡ øÊa¡Að•CøH@@@@@@@@@@@@@@@@Æ!¾rXh|å>’�qH‚¯_9„�¤A@@@@@@@@@@@@@@@@`€à+‡…–/‚¯þ¡´eÏNjîØé|îéû ‡Tߤ�Ÿ1›Î:ñÏèÌ?Jg�t Í8jêá›Yä,ï ÉöÞN[Üv¿»woÞÛ< ³›A@@@@@@@@@@@@@òˆ_9,Œ||íîÙK·=_MRì1kÖlš9çXš: ‚„Ѩ¨·{/õõöМ³èÎ ÐG�9~4’Bœ �”@w¯l÷OPÛÞ=4sæ,§ÝO›>#iü�ÀÐ�A§Ý÷ö|àˆ½}þr:íøG‹ ¡@@@@@@@@@@@@@@@@ˆ*øZ¼x1�zê©4mÚ4š8q"Mò/ Ñ»–:Á¾7”àã:L>¾î{eÕ·m¥ÏÌŸO'ýÙŸ�kžãÅøÎ]ïÒ«¿ù �{Ò©tËßm¼˜ ;#�®ÿ-=·u�wÑEôÑO|â0ÊYþfeoçzåé§éÍ>žîùÇo毡° @@@@@@@@@@@@@@ ï @ð•Ã"ÊÁ×�»œ:& SÁW. �¦¶gVQë®AšõWŸ§Oþ݇¿�ׯïÓ†»¢¦·‰Î-½žbg““Œ¼òÌ34«ïýdþ·s’>=² ,~é—ÔÜ»‡þáò+@Úó&ýé׉N8›>uɹ4%áŠñx"?ÚýúµÏÓÀ»ôè%ß�a3€€€€€€€€€€€€€€@žˆ*øZ±b�qÆr7°™ððµ,ó[ðÕG¯~þzêe¢Óïù ]÷ùQ³9¶áÞ§ë^¥Î)Ÿ¤¿ùÜ© iÚö,]¦+¶øâOè'¿ú*MM¸jôO@ð5úŒ‘B8�d‚¯Á7ªè‡ÿ{‘ |ÝØý úø¬ðxòé—ÞmoЖºwèãW|‰NØœ/킯|ª1°@@@@@@@@@@@@@Æ/¾rXvù.øZÉ9´ü¢Øý¿¡âï�Á—/V™ûoTþÆ·iF°|»ÿD�žô5Ú$ÏÿíC¿¡oç&_| ßÇ’@RÁ×›ÕôÃs,͹�nê^B§ÄScigúiõÑKçžC¿|“èKÜHŸ?7à¹/OÚ=_é—(®'UðõÔSOÁÃW8Öô~9_ƒ{Þ£½ïí¡þ>¢£Ž™MÇ~üTš1- ��}ô^óÿPÿ¢IGM§Yþó‘chb È¡�>Úß½—öM™LS¦KÇœ8Ó¸ê�üic•ž/½Í-¥;ÿôÏ4{x�Ò$š2m²í¡Þ÷i_Ïdš#Ó±ý¥Ÿ‡a�±O›êØ{¨û=Ú³Cæ]æEåýø??•¦êd�¤ ø2pàËiÁWúmÆÍè¶{– ŸöÑ«_ÿkzJ T翸žþñüã�¶I“§ªîÂùˇvÁ—[þøÈŠ_YáË.ða%øêÝF/\{-Õ>±%Ê…?ÿ5]ü­sD\ï>ótÏ%÷$\Ot•öÜM'K¡XïÏÒoïøOzé™?$^÷ÅPéc×ÑÉsˆ†¶¬¤Ä~˜x�sæB¹5Ýwk:¹U¥ô\¦„!Eol¦¿›ËDcæaÐõ„ô¥çŸ£�½ùŸôàž¤oyŒb§±4Ü+ ø  Â×1%0b‚¯ ÛŒÊäH¶{¢>jøÖ9´,Øô\š§Kï„×9Þ ó£ÝCð5¦Õ‰�€€€€€€€€€€€€€ÀaK‚¯ía#øn¥§§Ï£µËy_¡‚¿"zûg¿¦wÝs±û-·…<×»‚ÞûÅ-tç•Z¥ñ· ¯&ÚýýÉv]MeC·“ÔqQ÷3etû%KÝpgÒé_<…hûZÚ*·nsþ®x˜*–ýÜR+_×»'ƒ¦àËÛªòR¹õ[�·õ[„ää£�6Ýz =Z®¼’]H7Iïb§Ì’‡ì‚/‡cN`$_·™Ql÷DïKÏ}ñ-/}µ‘ þîR[¼M–m_}æG»‡àK•þ@@@@@@@@@@@@@@²%ÁW¶³x¾ôVi´PzÛzøŸÌ­÷¼F÷œ|…ãéë3O½L—]rª!”úÖ–ú›Ó<1V0·­¤ïŸ©¶päÞ»˜ë‹wÑO~µ€¦&Di~dž­|}EŠº0E]ݯÑÏNº‚¶ÊëŠ6É­#Ï4·u„à+¡`pb d/øÊ¼ÍèöB4ÒíÞtm–žûÌöfþîyöË<ªˆt>2o÷|�a%GR              p€à+‡…{x¾Þ£çÎý;Z-·XœÿüzúÇÏ}(@T‹*b÷ÿFnë8—ö½ø3ºõî'šûºó�ëè˜@ˆà×ÁwÞ  +^¡�ÿ³�ÞßÝKÓfŸHÔóºÜþq‹¼4Dð5O ¾^HWð•y”�¾ðã‹?‘ⲯšâ²éÅlvÜ‹™±u¤›9¾\øÈ �ì_™·™Ñl÷vAGkzfžc6í‚/^&8ˆJ ªàë¿ø�qÆ4cÆ léþa!øn¥§§Ï£µÂüéÏw·bô¡h¡…'øj{p!Ýû"Ô —˜:Ÿ¹—]ò°>< ˆÆ|1F&‚¯yPf$M ‚¯`Iá{ÈZð¡ÍŒf»�$øŠ�U„Ù´{¾ò¨ÀÇ øÊaá‚/z�^�¾j¥‡¯¿}è9úfñ™¢ÚÃ×éÒÃ×uÊÃ×óÒÃ×|éáKz纩g �2-ÄûÚû=:ç+´I~?ýºŸÐ7~x!wâLš$¿÷üá1ºõs÷$ˆÆ’Š1œxµM{ÞÊ<*ª¤iAðåÐÆÿò“@Ö‚¯ºý’¥Îo±{–QÑçÅE_½Ûè…oþª}Fýt!ÝØ½„>>Kö¾)=w]ìxî":�®yã!úäÜøV�C{¶ÑÆgwÒÙßšG“Þ¬¦žûc'Þ‚ÿú ^6—¦ ÷Ñ»¿[AËæ/¢wÕ/�m!µ¨ä+tcÇôñ9Dûw½OS>r®ÃŒÁW2È'ßók*ýáÉôÂçå¶Ž/{WžI±/K›žùƒw‚>ó_utÙe§ùßÛ½�î½ö×þwš{ÅŽßK›^Þâœs¼ôœÙI¿œ>�^ÒWYŽ® Òž»édw[È¡-+鱺×�I§ÏÝB[åv“6¯>úœº\në˜a’ ¾˜¨ÍL'nÚ+ÏjøÞ7hÙ’¸p,í™ô¥Õ�Ñçÿá£ò«öôó�?n¤óÏ=F§œa|ÁWÀËX<ÂvzîÜÏÐê7Ϥâmµû˜ò2¤ÿ øÒ,p4ö²|}…nê~€N™–/í^zò{s%ý빞Ø3ÎôdÙ—,|ìŸé„ÉùÑî!øûºŽA@@@@@@@@@@@@@àp$ÁWK5¿_Á¨mÔ:hÊqÓh¨‡höGŽ¡‰É¢¤Þ=�4°˜&͘F3æOS§MN1ÔÛG$O’¾zôïÃthx2ML¸|˜zßyŸ&¦kC0µLó ŸÆw¾Ò€„KF�@2ÁW¤D3m3£Òî¥å½ïSwÿdš:<@‡fO³f%táÙË4á1…þÁW(ü              ��l_§Ÿ~:¶tÌ€uÂ¥‡¥à+!—8a#Á—� Î��|�•áã<¾ÆyÂ|È|å° òAðuûóOÐÿôwÓEW, ‰“úâÊ!©Ã+i!­}êôá‰Ó¨ü ß:¼2‡ÜŒ ÿþò¯¨±ãú§o~“&MÎÀ Ö¸È]þùâ¯~ESú¨òËÿ’¿FÂ2�¼'ÁW‹(_xç¿iñ‹+iöœãè¤?û(sü 4mÆŒR9|“ìï§½ïwRg{»ü|Ÿnüì—é‚Oœsøf9Ë[›v·ÒíÏWÓÌ£�¡“Nù3§ÝOŸ93oíφpÚýû»vQWGÿÝE4ÿÌ¿ÏY‚í              9&ÁW _*û ;[hÍÛ�´ñÝ4tp8‡Dÿ¤'OšDùá�ÓEgœKç}ì/ÿ #‡yK@‰¾~³¥�ÞhßFƒÃCykçá`Ø$é=ñì}Œ.üó¿¢yŸ˜{8d yÈ!�¨‚¯'žx‚N?ýtš)�¨�'ÈmêD”|ܵ|Ð ö½ùû£×aòEðåAýñ³èy>’»‰þbã:úcÛVšûáSé´ã>LŸ8îCô‰ã?Ls¦ÏJ/\ �W‡‡/^­Ý{è�½~Û/8-F_9ç<š:y Õ¾µžžûï×éÔcO”íý#ôñ9'Ê'Ñ)òûQ“&çU~` €€€€€€€€€€€€€€Œ¾FŠd„xòUð¥V‡Ä!RH¥ÄTêSýç:D$çS^çËsCü7ùý ü>¬>åuF8/¼û»s�:2Žƒiouõ÷P×þ^êîï¥c¦Í�"®ÓŸKQ‡r�~ÂGèè©3 ê*ÌÖÎw©åý]Î?% >@ÇϘMÇÉês¶ 3eâDš4qMv?'ÉOu<Ù97Iþ&�'¸Ÿ“äuÌë½kãáÜëT\2ÌdyýÄ œHþç«O÷»a4¾€@ލv.7É–ÚÖU»�·áø§ÓÖå¹C^»vÚ¬þM]ËÛºï ¼ßÌðñß>Ø/ÛzŸlûªÍ÷ÑàÁ!:å˜èIñ¦q}\‰8å¿S¦Ä¤0ìºv;‚0%ýùo§ÜîqÚ䣤às¦#ú™*.˜2ÅQq�„)ˆPáÔµZtå}—ŸRH1EЦޖ/O¨uœôÒ¥¼ùDùÛ?4(EcqNJ<Ö3¸ßžrò¬,ZÐçä|—Â3G¼",е)áš/PãáeÅX ãq\@H£„5êoŠ+,SùTôçäø÷„så5ú7ÅB XŽŸq4/·²;A ÙæÈïJt‚¿Ãƒ€ª)ª®vË:Û%Ûµ'|Ü'EQ^Û�·_Y7•˜’·sY'½ïêÝÎãÇÎ9§ž"%>ò„ˆ^ûæm]Õ)_ääœâȉ~Vm6~�#|R×Èï^¡ÃÇ…‘ÆoN|ñ6¯Ò˜=uº#ÎR"­ce›?Z~WýM”?%RU¬”XÔû×w`ÀoûŠAPœ°êvï TÑ[à¼jëJÜæüsËÀ;–ŸIûÕ¿Êüzý€‰zbSÞxýdü\¼ýOžÄÂÉ~Bma«Ä¬ª�œã~ª¾A…Á€€€€€€ü?öξŠêÚÿ?!¼QAQ¡‘‡ŠØˆ ^hŠ7Å ÄjjA-� Rsù£ Š7JKTn E¬ŒÝ$T¶·UÚV òšöÓëãÚÖßK~†’¢B@! „€B@! „€B@! „€B@œu"ø:ëÈ­ £ ¾”Åú§þö?Èìs+†víã{{3+G9ú®P¶±{qãjiëϧ†Ü+âÀ:Xñ{�~…_®~?¸æzŒ ažßmKë`ÑĤ:F`C駪pøg7ü¾ß¡{³NÌB@! „€B@! „€B@! „€B@�x ˆà+^bI Mðµã`9Îà[.oŸÄ\%©ï eûÈ·¶HbÁëiK¿úß•bŸ3åüœ<0)[q^×¶ã9c³zîø¢òTUâ†v]ÎÝBˆåB@! „€B@! „€B@! „€B@! ð+øúãÿˆ.]º iÓ¦¨W¯.ø–>~˜þú�'Õh ;î'ú9'šàëœ.œ/„€B@! „€B@! „€B@! „€B@! „@Ò ˆà+éHcOP_±³’�B@! „€B@! „€B@! „€B@! „€B@"øªÅV¯àëÛ .À·)õp¦~= Þµh¹d] \pú ”ÿë…ÎÔEóĦh¨Ÿ‘þ�’\�…ùÛ¬§Œ¡Ó¸àŒ/ç›±ä"a„€B@! „€B@! „€B@! „€B –ø|½úꫲ¥c¢u�àët£„7Dç•(öó>¾"øJ9þ =Døu®Töé†Ô¿›4 þ-ü\©³sÅÎúÁSH¡ÿå#„€B@! „€B@! „€B@! „€ç|Õb]Æ*øR„ §‘ä<ú„Ž”aó¶/¨D ЮÏ�¸²ùyT¸ºP”o¿EÃcÁsÚ»ÏþâB”~MB•¦mЧwG4N×Pe9>Ü^¦¶»ö½ú¡]³$$š`JßVÅ^ ¦“Hô“{?Ã'ŸWP Ðá†Ñ:°1(¸}¸ŠLéÒn}Ñù²Ú6(‘ÂÔ~Üz§N£AõÉÚ7ä¼² ˆ’Â�QA�´ÁÅÑ/Ðæ¼*�¦æÔÅûPÍ•öì¥\s\Ï•¾~®ØY3m"¸¿—jó˜Ž}ú¡ÍwjÚðÝ®{¥E+¨þKœõîs9ŸÚuM<×ÕÌhRwSugx.µósÉÖÚoîãZíÛ%! „€B@! „€u�€¾’T''�îÇžÒ2øº §O×GÆMpQë6èÜ©=šÐŒnŸX_Êo§š³U‹ÐìÚ\„­Û?Åž�ûqäD�’nŒÆ—´ÄÕ�»¢K�Þ¸¶g{4r˰�«þètî7Eµè‰�û0±Ë$Yw[×~¨-Â_Ö©×·÷N·j7 þ¾ §-]UCt2W2ÔÞÏ�+Ч¯UJû8?ÕX�ÚÙÅŠí©XS¶ ý’ Ϊ.Z€öƒ³U 9kvcr¿µ ç[Úžõ›‡PðÞvUÜtñU7àúnÑúB{6 ´òRš\†oëƒDÑl�;CÙ ²Hnô‡—�ÝŸÝ€µSoŒ/¡ódœŒ¯Ð‘C+^ÿêŠH®ÆN ºé퇠@‰ÈÅî‚ñ¨ÝÑ$vÓ%dí¨k÷!�F%Š6lVçN [Ë7ÜŠ@«”ˆ Ê‹6à3R<6¸¸nîבCGL*)kŒë¹Ò×Ï;“RÛá‰-HÇàluDF]˜ß…[Xƒg¾ãu¯�u­ÿó€‹k¹j°)Õ\Ò5ó\WsöÖÅ”=žKíü\²µ4�ó§ÿטb‚B@! „€B@�󜀾®àvø6ï9æ‘RSôù·¡èÜ"|),Áשf�p¦A}5í]«~ƒqça»GNæéž÷`韞Çà«kßmVõÛ°í_ÇѺ[/t`^zª·.BçÞ«&Ï(܇Ÿ]Mäb–.òAÕ?1â¢�ø‡ªgvMÄÅn1‚Ÿáɦ½±È¼6�Ï@‡óHð¥M|)¯sïS�¥™í1iµbyÖ•å£w̪¦jnÇñ—¢‡Ã3Xuñb´OÕ„†¹ëvc|ïÚ•h„š6ÄÑm Lñclâ¦*ü¾w+Lߪ°ˆ·Ž®Áõ võH‚/¯>¬ä^S>> �³K&÷‰9«ÄÇÉ*lßTŒ ZáÚë;%M<[94e‹×†GÏU(/‰×±w¿÷Š‘Ðùê"| >g_ÕåÅØRvmºô@ÇVçÙ�.¡Š¬©ÈÞí±®Ý‡T|V9‘–‡²üû#ˆ‰ÙÂóY<Ö×`&´Œe1qQiÖÎ?5f§7óÚ)¨{®ß�…q�º8ÇîG€G9Ü«6¦³Å‹' uŠÚKaÎïk¬OÄdRR�?í:‘ç:ÿ(ϯ¹�Ãs©ÿG°õüª+ÿm–Çt×x9B@! „€B@! „€N ÁWçÎ�ѬY3Ô«W|K?TýGm›©‡†÷½ÖãìÝüWü}·%öªß´%Z5**Žà´i]+Ü6b0.uxúŠEðuòâ&ÀàË·§£_Ú,3E †ŽŒÞW’PêÄ}°o¯ßÆ®ÄÊkÐÿ2vꬆðvVsŒù-à²pAGR_Á�1©é¼¡”5ýyìZ96|Á2¸3ûð¼*˜¡p=ŸÄÆÍÓÐ!\“wÖ‰%;Ôà)Ô§ÿϽ�ÇKí Ú¿—2)d¸g°º¶ÐþÍEMPõéïMñclâ¦*¼>¼Y¥À¸kŽ®@Ï_Ê«%å_Sz жû5¸Øì Þ}Xɽ¦>||ˆ�‰fI2ÆÉÐÞ7ѾÝHJ09b:ͲÚá謟†GOœÓÛ¼:ËÿGê÷<\òŽC(/Ù‰£Ê–޵E—vµ+�\®VO»™óÉYÎLî9¸\M˜@¤öX×îCja™0"@'çšò·`fZ;ìUæ‘„�ӵ•±A* áVEÂù(T²¢Ô��‘˜'Ëôd¤£lé¹sïQJŠæ1]»Àåw6ÉȦVÓð®‹sé~x—Ã?^WaD õ ÿVÆóüi×ìž÷yâç¦Å8ßæ>^ Ï¥þïeëùVW~Û¬=žë¸f"ß„€B@! „€B@! ÁW áLågxão[ôê£Û÷‡ g[]y:Œþ²ešž -¯½ w.µå“à«©Ç‚ÛHÄÔO1Q #æü¿~hehÉ~ýùz<Þåf¸î¿ü+ÖÎdËóì~Ù‡Ùäaé9V }±KÆ÷0³ç‚Ž| "Á×Z‡à+T†ÙCºà¹õº)ç±ØK)aý“§�râ»%øªØ0 ]‡çRé3°nï|ôfÎlêÚB»"è¬ÞVû‚/½7¸üñîÃ.�“vŠ�1 ¾’4N^;=îxšÊrÖ_Œž¬ýø/`íptÚÛðXœ>=þ9Kþ=R¿ý];³³RÈ%OZ^òïW$=ò©I‘Úc]»©¸0B9¡ª¾Òh;å|�í”ÙÂóYAÕ WΆʺ›_uRÞé°3Y´HÌk²IÚáΗº¨‰r¸ #j¨O„׌œ‰N€Ý3Κàë|›ûÔÃè5›œç[]%‡Šë¸–œ¤%! „€B@! „€Bà<# ‚¯*´ìƒUø@Wtµîõox�} èÌáb¬~¯M[_ŠÖß Ðþ"[n1 ¾Žü#.½]Û¦ÐËk•žrèó×ѾËhýÛƒX{ütwNú nø»+Ž¢Q£ÆhxaK´í@·^�ÂDdô;lØñ9¾:u M.퀆 �—$x»Jàýªþò.×àRÊïë/vãоñ؀њÝãáý©7âÔ©¦èÔ­=B|KÇ¢Jü¬g ¾Üº o+GõÉoаÙÔ£7úölÓÙÏÓë˜{ø |íÃïoëˆéëõÈ=§âýM3ÐÙÁÇžt»6}€­Ÿ”à±j„†hqE;\Ó3@,È»šãsøóÏpð¸Âª3]aëÚõ(þâШ=î5—Ú Ä—;¶cç§;qðØ7”¥ý½Žèѳ®dÛ_:² ¯!þ|¶ï*!ÆUPb¢Qs\yMoÜàØ‚.nÁWuŠ·cמƒ¨úFMÍ[vDÏú¸o¬@ÉîƒT÷MpU #yS ¢´ècl-ùR�ß°aK\è‰íÜë1T‰Â÷6`뇩-Ý–íлO_tiSŸ¶tlß–ŽÁJ”î;„­œ‚1³ TlóÞÚ„­ÈßÃeíÑ®EcØÚ öb| åÅâ£âíUS ’gŸÏðÙö¨Òê­e»èè�vqn•–lÁ—Õþ´¾zòÐn|òQöªíDk»=nì�+[Ú"BUû°§ô0ÕcSòð¥�Ñúp#•…öÏIò¶sÛvì*?€oH䪌)Wuí�k©ÿòp,ŠzøõçÿÄÚ÷‹p Ô·5Ä•�®CŸþ× ÑŽWÑ>0V ³à+ÑqG°ç˃Øö‡‡1ö™ jÞsÞ+R½$6h}1ãEì}0ޤîõ5&„ª¡äãOñ9ñGÆd{´¸¼ºôé†ÖÍ­ºŽOðBEéNïÞ…ƒôq¦as´ëÒ7:¶JUaÑ?¥%8HÓ&—tBÇ6§Q´a>-§ñ¯a; >­,S$o,Ÿmÿ %_R›¡nÔ°yKtèÜ=h¬à¤�´=ÿÆÐï#Ùuë Nøúà 5ùK:uA¯Ìõ±N ØäòNÔ×S°¿´_Qym¾)ýêŠRl)Ú�CÕŠX—¼Õ—ëÔ1”Æ×âÝ8Aç.¹ª#Ú4c@Ã\>•å¥8´3¦ §m?9z6M¾§BMЩ‹“u%…ÿDÑÖÏé~×H½ßµl}%º]Û�êÓ>¿qÉ*â)¥¾·mù { {CC¨éöö¸¯è)+JðÏáóÃÇ´ûµ‘+¯ê†î×vŒà½'žv[�Ò’Ñ4ö]‚@—6.eмQ(Ì•û\83G”Úc]»©%àÂ^¤ ù883ÍåþÍž=_q¶'Öw:Ñ|âty6|ð)ŽÐøÐ:Ð�.>sîï¼ðú1g“6{óïÅéý%ØüqÊɸ“'OâÂïõÄ [ûÙÆ8{Jñ´K{Lå¾P^¼ Ÿýk/©¢!^™WuCbd®¸�u¢Ž…ÔàМþ«ºFCbhË–¥qÖµ1âQˆæ¤;·Ðœ”îÍæ½í²«ÐµW¸í¡êý(ý×Wj?mÛU#ª÷—â__…ÔÞ{áU*oxvš%½‡«c»�jxýŒu_¹ŠÆGšýÒ¸ýqÑV|©Þ/µ1®gßhîé5NÇÑ&¢Ö…ÇýÈf}œuÄú£¯ù½-oýKÔr0öq>�¸ #êzýì 9PµÖü4k�¶�ºâÚŽm\ÆD·»œ‹³\níZM5¬~h›Ì� ¸”æT y뮸ñ¦~V›§ç­¢l$o¾Gè:µOznés#]gÈíÖú|ÖIæs�Ý eró3j|sgFöïñÎWâfrŸ�R1¶…¶_--Ú‚ÿ:Dc+Ý;šµEϾשãš2æí¦ùsƒ&— cÌ}"ÜÖØë*¹}Ò/›På~ò&ùÑhBÞ$Ý磕å%ØK.€4¹]:Ò‹Ç'Ö9±ë¸æ’–¯ç©8ú“š%sÂæh× Áí�ðr¦÷bÐÈ©ÝOŒ+Ú_­-)÷jÐÜÄåù†úDéνÏ?>Ç*šýÇ÷œkµ]å9°#½ó©¦¹à–OwáБjT‘í­¯  ï �Ï(gû>œÜ>c¯5ù&„€B@! „€u�€_Á×+¯¼‚ïø–ŽGñ÷?½�½ê¾�´eã(Ú²1ÎÚ�UðUýÑ"tî÷°–ú/V`ßì;#äÄž­»€K[ãŠË[¢Q _h8‚·gý'Æ<öšGü˜ñÎ2üì¶NÖõª�1⢚h«gvMÄÅÖUõ¨ú£Ⱦ)êñ÷abÿø}ïV˜Nž½Â?=ðÖÑB\SJeê­•iÆ;ïsoÇtu‹:GŒô<®˜ˆ+y1Al_=_‡ðÊðöxÌ̃Ä^Ç#‹½¾Þú&ï=Òô˜fˇ¾tÏÌÃK‹&¢ƒñ²œ< �!OloÓµ›ç¬ÀOJGâ!ÚÎRûØ·‡«Þñ& x§=ô©×ðÛéw…±ú'ž»{ ž_o¤ëü{–?�¡Ý4Os± ¾B(Zš‹Á“f;4¿gä,GÞäÛm[d/ÎDê”Õ&om~þ"9fë -[^žŒv¬Cå0©×p,³B™G9ó(þr–)K¥ayéí²PgF ƒê¢h?8›Ÿ2��mÌl í+ß C¶b¾ó“–KöŽ·Ù«©.Y�)ý3]mV®§e/Á SÓcöþ‘TÁ—­ý½‹g¯y·¤)žªÂ?O¼S‚‰·µ7/l�;CÑDNOR¾>z¾^mbÑÆ”;±¨hîìéGQ0÷çõˆÛXô æ¼t%<ð4¶“…± ¾'ù8f‚Ñø–´ñõÁª¨c¡Æ‘Ú–¯1áÖÍz÷>ö§Éæ÷¡¿|y3ïVïO± ¾B…È}`tݤ™–u��üMyHëÂ:e°™mS¡Ž¹ùøé¿21޶Ô>|{ÕJ¬žûKdæ¸õ|%t–¼€ô@l£¨ý~\Óˆv-ÈÆëƒVjî:¬ß[3Ùñoéª,ôó²z6�³ãh×ඃ5U » Æ«ý>‘1‘ZÞ�5£r]¥Ôl¬ü­0|¸v¯�d«ez5¤¶G¶2Œ†}佩ÀôÞTY¼¿LõÛ¹xuÎxt4îwaéy�Ø�3¦`Ül—2Q”Œœ|º¯¤Ùî+@´6BÞÊV¾Šñ;Ú2�»Ý’ “êа,wÝnŒïmowç¢ë°=Ÿ l:8]Ø}Ìf}‰Úi;ͺvRËÀ„9y¸ä�)˜¯ßËs×—~v.J[]šÙ^e»ˆ‹ü´'«ï¤!å0dŸdâí6þçØ±àEó;?HÖý�§i;fl�‘�y�Ï1Éuü"»7/DZG6.RBq·K–yEá <`ˆ5ÙyíÐ1s;]êd?y? ¨ÞOµØó6•á^>†;Ò�¥-+QüÔµ#+—¯•xwîS•£�¹.�–µ�æÉ#a,1-HÇàl­ÑæP_žL}ÙjS”1 ÷ÎV�¹©]‘£�‘ 7aþÈ.nÙÙÏÙîwo!¯sú�ʵ‡Ñ¿å¬Ü‚ÉÛÙ®ÅÛ&¢ÖŸ®÷##S?ud±‹~oäëüµêvÃ~ŸG&Ðóˆ6¯0ÇrŸ}¢’æúOÝŸ‰—]ï�J©Ò°pÍo1²ŸÑúœ%uûî¯\níZI�×ÏÊ‚lü5uÌ)Ë~Éæ½‚5Èè;F›¯°kJ9–oùnog¿±û}ÖIös�ej¼ìbŸûXy¸E›‹¸ÌWü<S;w›�"A[‚¥«ñ`ßLsŽÄ e/Y‰V­ËÅöœ®Æ³õ'x=†yjÒûdl¼ú¤Å‡µ?ö| ]�oNYðå£}ªFÄÛŸ4Ë­1'|ŽfÌÃ,ö£ÕY— S¿�çDZ>‘²ù¹o=_Y8�†ä¨‰rOžÇ*_Ϲ¬ŸÑ�g–ß° £&¹�º©ôûJØsìÙ¾'½ÏØ«T¾ ! „€B@! „@$ ‚/Ÿ•¢l縒¶sŒ¾¤ùØùÖóx›‰³}§Y·]¡¥ÆTÞÅøökÚöŒ ðfÖ`ìo5‰aV÷A=°ýð`òª5 W”X‚/ãºR¶ãú£jçðözëìÍs6â�É}¬‘ޏ½¦‡¯#xý¾+ðH¾ña¬=: Ý5M”qÒö÷ëM/ Ûma]½Ðs Æë|µ‹¾i…í9Ÿý'Z+g(ï1MàížtÌxj�ïÄš£+Гò<¹ãut^Ø”«Tî_¤á’Ž´IÜ·‡Ä}¦‡¤ÐnÌlÀóZ‚ê¿7g>ˆ«›GáÂ×TqŒvÉÊ+VÁWùêè•ÉÄ^�TŒ¾ájœ8ø!–­¶V<ÒòÖÑv`– ‚¿ˆ´Ì cô 8öùËX­/+×ÒHL‘oˆ)ª‹0¡ý`&œ `tÖP4ùòCÌ_Æ"(bql/’ƒ%+�Ñ_÷bcCžõPŒ�´ˆ7“ñøB»„B¸ÙëT(é·¥ô­Å›0”êmæ¿lHè*yDÙKQìË'V,~”TÁ‰3Ç�8ÓÙþººý®<†WóY»…ÕF{¶/¸·ý\_ÅÚ‡;7âÍ -0v¡U¢îéÒÖµM±óSÌÓ=°¨¤w^mÙJù ÑóS‚ñ6ÓXôG߉Uð•è8©ôË{©_þô[9è�îØ†Ôü"<}Ï5´ro¬Š:*ýŽ »^»·djõ¦X«Öuצ8¸‘ÆPÆqÄK…˜7¦b|…J1ãò¾`£R3Fãê&'ðáË˨7G¿¤EU<£öY#Œñ×ά¶ÐuSêÅ@Úh¨6ÁŽÙóÙ¢RK6¿ƒôÔEQûý�Ç#ÛUø&ö¥—+ [¾šûÒ¼bf%gv‚ªm¥oÊjúŸa‰…Ôåå´<”åߝЖ|�‰”n h™(Ù¦f`ôÕÇð2_”óô±�§Ú)—«±jÚ=c(wôÚÞ±ø«�ØôÎLt¡öWY¸€R˜X–Æÿ Co û�cl ä ¸`2Üü`¹dN§H4�DAÚ¼$5-m©OñûJ {% ¦Ô“¨ Ö]MÖÊÉÔŒ ¸áJ`ÇÛÔF¬ˆì•Ř:P·Æg»µ—}6œ‰ŽÆÔ�³HÄhHNòHDr¿C¦mþ‰Úëà}H5žú¯ÑžÓæm × Sê½\.êYoÁ—�)ޱ=¹÷Í„›ÿó Ôûͯ‚…äÝßõ‚ºÿ1Ø8ƶõÏÚRÿ\Æîÿ$ X³›¶Á4ôq>Û¥bHuñR´OµDoа>#ƒzÏ2>§beñŸ0PY<5ìT"“¸‰oéXY´�õ ä®ÙI"¾Èb•XڲߺVLŒô)Y1ýÇY‡Êúê&8ø!Í+Ù�1¯óïU*FÀ¸~P�é]¡ëÀ0aÉfÌL·„¢%+²(½‡“÷¶Ýä½Í¨ºHö‘²™4‡]c›°ýhÁG›ˆZtŸ3ú/íÛkÞ�”2ø­#ÎÓbá>_Ží~DM4†yz2žGb|yö ÷'иÏZŸúŒÐäÄAG_Ï@m°¦¶&—£¤–‹Òw­Ÿ@F÷€ÃNfL*]o븞¶�¼Ž4ŸY”:òõ¬SÏu†åñ³‹mîc¤ïþ×ç|5‘±Á/C>öóþŸ -êÇàdŒöl}ûg–€rfkÞ�6O¥zÒûdlxß3Ç[1Ùüˆ×‡�9±w^>Û'ÙÒ Çm±—¾8ß™8¯ïw£´'ˬåŘ~;{’p޹©ô#šUÚ�hŒt çfbHŽ6×ZHÏ`#éùÐ÷Xåã¬Úa´Ý°û~zиº,Â\ð¬ß‡�Lõw]‰ÞÇŒú�¿B@! „€B@!P7 ˆàËg½œÜ»«þ¾[�ݪÛ÷ѽÙ>lþd7Ž+ 0ãSÿBtêE[”unƒzÆ9ö7fÁm5ö{`™[R7ÿb&&ýxzuíŒKm[�± Øááµ3Ñ㎧õ3÷`ùž‘ú=ã-u-ù†=ðýúTž™Z_UEL“HÄô†rl ¨”/Ö'\ð¥yó9IÛ6vнx9E<Ž’ÒÍ¿| Ÿ¾ËÜòpϪ™0\·wy[îY̲€qÁWú"”­…¿NH%QÊ6=ÐÃ$¼š¥ ¯X,Çá>̦-ËžÓ#æ¼KH¾o ¯?ÓZÄ«FŠ«K1m( äÂ7ä1mu>F}_!™‚‹›+¼íu9ô©UxaúÓ»IõçkðX—tӫس…ø©îèðûT‡·êLh;ʵëÿ Ý�­ùBûðÊýñ˜.júb!–Œï�Ø_vYK 0=][@SЏãb† …XG ½õ¦S²”Ë&ËáôÂ/k ^ÊN7·5*%!Y_CHÆ K–Òbž¡HÍÁæe“MÏ1Aúuó#6Ï_†XD±&Ú§šÄíu±@x<§à+ÜÞYdo®–‰í…c%-v2 Ó²—cáTËÛYu默Òw”¹@”·®Œ„v/n–'UðE¾%sF»’w­|ò®¥‹CƒŸavÿÞf»Ö„]Z_ |EïÃvQä�XZ²ƒ¯6T”Uäyêaò<¥‹‘øØAvN";Õ1… <ººYCIyª~Â=9Ç= Ë{ßRÄ;NR'&O€­tO€vQœ’žŸ>¨Ä‹4úÈÖÛÈÖõJT×ůãÎnZ½)goý3Æõ¾G°=ˆ÷¿y�A\púŒrÙóS±qy4Òû@ of#`lIÚ�Å“ú/úIt”W@P}¬[.úo—ûÉóTÀô<5aÞ:<}oom¹PVå>`n]� ËiÛÍÛ‘ÂídcR°tî ï>†N*‡„’“ ¡¤[ymç"1÷_×¶,¾Pžé4�SÇ;b½‰\#}Ƭ19B@! „€B@�ºJÀ¯àëå—_þnoéxr? ¾Þ×_Ñ*·Që>øáÀÎÚKX8vÁ9–Ù»?k÷æ5‡%ÔóNŒ9ßt3úõé‰K›Óê˜íSE®Z™®žx�¶l»ÅhAíb‰9Å•¸»©z¸€Š‹6Xú\¼ÅE$ü¼S´Á¯ayÉZ«{É2Ó墫pá…ÌyÀíMŸŠ�í˜þÌ›f¨EåAÜ©è"|Nn}•„jcµäÁkyðºØ¾š<€u6<€‘�ú=¯ÞM‚°#$¹ÂÜ6ò>ò ôœâˆ}Nî ´zÚTîmTîKÙuåðë÷ƒn·NSÏvÿå_±væ õx컧 ç¥àت7‘úó¦^u•Ä$ø¢…©¹�äaÓ±mX},Å«œ\¸«}z GÛ+öÓµLü­òB¸¸`ªÃû ÉEb±2‹5³{\0~©©Cýc{)J/þ¬ÅÊ혽dU^2[•ж—Š$4 /+·×Ê7X²”~ñ®{Ú x;‰‘¾ÔkQI[u–£~d‘ÇšéÍk^I|‘Xéu+=¢o[jóÔ§pàíé¸.m–úÍ*_¼_¼ŸÚûp¾¯Ò†O¼WFcŠÓëà!¼@ÛFþj½’C,-ÿƒiåþ0µïzûVöwÐúŽÆø"Áe{S˜fÏ×ãþ7±qRI“3¼“¶Ÿ]cËE媟>¨Äóæ¨x÷ò9&S%UÜz_Ø=æËµ‹°l[ctéÐ ~ø}\ƒà«tõ\<ñÇM8¶z5ná””|èÃû¼]¤ZÏÚ³ÙF* ‘ÙiˆéyOõlgzÝce´µÿí©š¼Pµ7½PM !y ã‘o#™Äû»³ö¾36Ê5s `ísË;…ßv,%/;}u�¢n}®ºéí‡èãm5JBü.°¼´™"TZdÍ$±“áƒ,+3 Ic¨…cõì`^cc‡!ÒUL ¯[Éë–­Ðéò ‹ñÚöF¸æ{qó¿ Pdàµ0®$S¾zy±�¯£—à«Ù?ÄŠÌË1N��UK„s�Ý۠ܣ úm4rXÛ¨:êÂû~ä¿?ú½—éÅ�ð'R9ü?�¸Ö?ï»Æ8¥Opái^ÁAÜp´>º_,žýhÔ±:ö¾º8ç1.EOà9˵\”…­~l^„´ü éþ:D¿¿*mþàìtÖ�BäUiF©Ê„d<ëÔàs]ì"Í}\j‰�²Ï_⛯òöÏØ�C·v®–Æ¿-\x¹�æo#ó7îqIèÄüœîak¤ºª‘>iOã©'»w=.²ãnŒ;¾æÄ]lžü¬¼hŸ‰ô§¨s4‹@øoßô¾è+ë}Qyç¬oÇkijm%ΞŒ÷+ö9W|ïe|߃yÛ%C]ç‚ü™Jÿ�Pc~.Îç,Û8ïú,Âß[ïÙ”6j‰ó’v3*Gþ ! „€B@! „@�% ‚/ŸU.øª�¶Ý®C×¶— Qý Êw|‚OËŽ™©·¿1 7]ex¿ÑNÇ#øRcT•áÍŸÁØÇ O\fò¶ƒ¡¿ÈÔ©¢g[}qÕØjP żwÙb_®šŠ~ßWÏŽ QóÈCÔÙ|Ý—_L¨Nkì c;DG ð¯†àËu[EÅ“Ø*¼>s{éžÄö#i{;M$6ve ž&OaÚÚíIÚ^q‘zá¬9¾=s›båá5èïÐÕíZ2·èžÔ~§ ÓnsŠd”)ízzÚ>½›"™˜_a… ?a-8Ø_êò´á%öÒÓX ¢EIk›ˆ,ÚBkºµ…–‘5½TS·‡S¿Ûó4‚¸ÿµçç|m·w3 Rœ Ÿîñù/é³VîÄô�n <äéí’¾P— /@îFšgkNð¥ytêìX§òò4·à‹{ëù$¶M .*…üò SFicÊŒ�ûð3ê[çŽÄ�G"÷/n�Ñ–MhÑüŽ“jº¼Ç!45l2ÆúÎíŽ$øò?&"Ï�íMÏ�c_ü+&f¦¢u˜à×0±méhw?b/¼Maˆ’÷�Tò–²Jó¢b¤ÂMO/­wL M*AËWÑÂümaÞöÂßHÇõ/ÏÛ9^ðk.v)éÑî4ÚÆRËÕ)å#–6ã`Š+()ûã½)™q{¬¼ŠÐvŽÙšú kùÚî$|cÉ 3R1\w#dg¯¤ëýá69ãñE·Å 5U»—GÏ\©¾­-x¼Æù ”î â ›£IóæäéòS6î¿âÏ�‹72ÈËÜ|ÃË\xPë «/'%�}km«@íGú´½è–õHoçL­”]Žìu\×ïCj<øðþH{ö�Øy¼ÞoYÍMû"S¼í‰·Óp�bŠ•,O—f4yÞ‰õþîR�öSŒ Èëœ&\·‰<†8Âò¯,mÞ.‹É jªîÕ‹cEy9‚)�Ѽq4oÑÌîá‹¶i+ûCo<Ѷ¿é�o‚¾µ5Ï>ú±7ó;lÞÈÿQŽ!¾ô=V…Yår‚µQÛ¸ÁÎ{ŠCäµürcÞ¥=ã5]f‰¯¼æsö9¤õœÅ™Çüž�~”Y3}Æ…•œB@! „€B@�:EÀ¯àë™gžÁUW]…Æ�£^½z¸à[úø)Ù¯ÿxR�öаã~¢×Z»à«>º †ž—5²Ùshë;X¿ãˆv®iWÜ5LߎE·àËH=t»¶asÁ?ðþÚ?á�UÛŒ+¶¿Ïn,ÃOû“ ˆ‰�þ gß3òŒ¯*±"•‡³�wLøˆÄsÃtñœaÝÍ™"íö4ô¿¥/º_}…m‘²á±è[:jé„PZø7¬YWˆŸïÀç{�™cõZ(×BÙ^„s1†›àѶ˜E²‰¬lÚ6ØÙ‰¨ýo.^6ÒÏ[G[Fö6Šáo¤~Ï®¹Ù¥§j-D�À`ÉfÌL×Ä ¡ý«1(�©n‡ ­ÓÖ+[§)qø‹cA‡N'cŒqKí^ÀììõBxüá69ãñ±Í+_uÑ�¶½Ôô'–HÍ#;í4ñ1E»žã¼#ÎÔÅc‰šÿ²ß^?íÖHpó2à¾ÀbÅq?bmθïÕáû�ZÆÞΔ É9’é¹�•‘µÿDÚo§îbO–g¹º×!;ËØÐ>¶4g¹ßuβԳ�Äß.cãÈlT¹�´Å`Fj–haRs×aÕøXÆRGš|\w0�ÍFª3O.μ¬ï…$€¢ `�³©£1làÜ4 ®í.Àáö„ ¾(ºMh?ض͵hì��€Íù`% ß݈Cß9O¡áe×ãö~Šô�µE�6ÁÛ³½O)éÅß&ly:êÂV÷5ÐÝï Œ�Ó™ëßèñü<�¸Ö¿Ÿ>AÞd2; 3½âiEHÅè¬arëMèÓ÷Ú¨âC×bÓɤ•‹ÒâíË­~ì<ÊHÉnBߺn=¯Xç(@<Ï:5ú\G¶ÐÇ;Î(¼jéºþ›Ð|•µïxÆÞV=çLÏÆ<.ëÿ¶1÷-^÷<î‘×jC®<ùI[#ÖU�ôIŸõDeáýÄõ^ÃïF}P¹ãž{å•PûÔ*#Ñþä>Gã~ÌëØôªIÞJ3É[©òs—Üu;qËG¿@êúÆž×6Ò¶ëÃÔm×­ç^q�Uæ0èãÌÛ®GRûœcÎÓt øufncµFŠÚ£#žâMŸ3s�ËÚ1¿×HŸ ¯S9#„€B@! „€u‹€¾|Ö‡MðÕ²FÜq ê…¥u–¯Åõ|KÜr×à»Sù|9ò �à@I þú2±yÿzk�¿€îø“šÀJ<Ñ–réë÷gÒV‚O+‡0·#< ‚/.0Q3Wÿ‰Exa…6�¸½trij«�7uªÖÎD�;´²)aݶ»3Òà wÛ”�´í\=ÚvN�¤sæ¾<7VX9!„€B@! „€uŒ€_ÁײeËеkW4kÖL<|5ít †õu[Œ9�þô&ÊN+µÞƒHðu{7œ,ÁoS'¿XƒñÒñ¶~ò ÚFmbï=1 ¾ª?z�ûMQcÕ½ñØ„"¾M\LbÊ� x«,Q„V@û|9ìݺà~ ùùkføßWà®nNÏb° RÜmS’8‚Wn»�­WŽiKÇ£´¥csf³#o%”ò±‰;Ò§bÎðïá¤æäN àø÷\�»¼—¦ñö„³Ðпø8~pC\tqS4ip!RŽoÂ=�‘ØNAâ|Ùs•ugãÑ{£ó£I“&hB[ |üâHdª[‰Ù_êúzÅÌÅ3£\Æ_ïXF÷¿‘ãù²×)øJ˼aí¢Ô[Œ¸/ ­Xw³×)øŠ$È4ã?ãM{ãUõ÷B½ýñ~g´%Þ.y›÷ o(þÃ/.¢í>ÞšTûôN~ƒÖ©zýe¶¼Ôñɹï)E9¹õUtè=V�ÌíäI&rì:Nªv0†a¾üõAÅNOŽt�³G\c‚E t¤ [þù¼÷çåxná›Öýhèœ X2ùƶt b5m{•i®±�•÷(Ү/¢±@gN|ˆ‘ý5�WöEÖ÷Ü^„óådWVÞˆôŽÊ‚VW}A+›Ä©S-q*/K7cŒûK}û¯�½Y×n“3_4ñÊ—¤fXœÞ SToA[Ú9s¶ñ!‘mØÂÆù݇¼J¬ró¤DŠ ½º D›ª¨^à®I ÝZFT. A�²Ðd}òh+¬û[aYW½Žx[²ß3•¼>Ü™»Ççu…$Þ‡ÔR0öÎ6¢\çð�±_ÍBâ“¶˜¤¸e`íŸÛè^6%5÷öä—‹’¢òI4¾–ŠË¿Œ /«=$÷„fôÿã)çè¶›=oý·“¶,4]1ê—�­�\ãzžto‹Jpnc¼uí™�ãB¨²ŸlþëÞü3r_V›ý“FB¶|]ÈÝž òÛŠóóC"àÝä±Í66GÓ‹P?0œÖþypÞ­>å¿MP ¯!ÁWÍôGÎÂ~ì]ŽDžG\ë?¡>ByÉ'ø`í:üù­\¬Vï¼$ämfw>b¹=$½\do_nýÏ•3ߺnÝ£¬s0ž{LˆynNòs]"ì8#«2^‡¼ÝP˜øæ«¬}Ç36ð<ãeÈãÚòL‚-¶ô80&ú›wópŽc[c««äõIÛxêQF/›x?që{®iÛÊ㜘йæÅÓ¢0ñ´Ïdõ'÷r;ê:ìk«èsŒòŒ©o•ºgn:†äÐàJ½Ô-Ùǯœ5e˜Üy3R; W5ìó6aþ½]ÔT9—¸Æ*zŸæû9—s÷h3nóÛÌ×7·šº'³Ï„U¨œB@! „€B@�:F@_>+$tx+þ¼v‡»~ë>ø���]R:�W½‰=êšö…ø~úж‘,vÁW_Ú‡C‡SйÛVG\@0‡DMw·+Á˜‹h"0ÏSJR\”póœ�xc2m{A@ed€¼g]§{ÏŠI,âÈ‹Ç1ÒLÊ–Žae­Â›Za¬)šº+¬€²ë%ÿl_0·ý\Mxm9§Ø÷ÊðVxl•ÓmKGÚ:smøÖ™[i ¶!úlÏWá§ÝRxÖÞǼ0Kö¬ÂÐïÙö ö¾‰ÛÚÅ/øâ/ÍR³—cÙÔÛi{BûçÝi©5_ù¯µ0 „à/CÝ_b±—ÍF\.øòô¸SŽ©½ jÌŒx¦Ç»möo.ù±x¾ì¥ø|±;oÓAÜß%Æz³öM|áä'CøÞV®zm©-ðð;¨�]¬`b%�txçB*>fðþè|KÇôE([yŸéeÃf«Ëž×³…´�ëõá¢ËoOÇui³ÔØÜN—䨩ÇIUüÉ:_>û b 'Gºæ{L`%·†‚8°k Þ~å9<öŒ!þê�%åàß/ á‚ÓglÁm_øËlúuuþ–eHkç ˜',ûë{n/Âù$´h~�¶rMN/RJÀò/Ø57»€Š ³Ðu¸æ9*-o^NÛ…ËÉë—òɘW@ Š›ýÃY±týŽ1|¶y3ò£¿¥«¦¡ï˜ùê;{Èå�ÛäŒW¼8SÛ>…âyå«ðå[ì®)£En6®ºdIQH4AÛ§©Ú ¶5‹kXã$�ãyo ¤‹£}ª&NW·ªMÛp¶5¶j‹·Ýê™óú4ìQÿfЖoó[¾Ù¸|am.¬=Úí�ù¾Yƒ÷!µ¬üÎ6¢°3.é‹Ùzisi[é+òûk w¬ý'Òžx½ÆÃŨ€Dãé„ýel¼_ö:WûŸëÄ9žQ¿¬+“| ¾¨YKÖaDƒUHÍ4j- o‘@e€MÝVZÇ {¹¸W©DêÚ‘Il_éÞ¶¿tVÿÏlL™m¨¶È/^�4rŸÌÇP·öý5ò ÃÆvº¢=»•G·ú,àéÓ§Q¿Q3Ðo èø°öÏ‚ÛÆ)³Oñ¶g›°åéWxºÌžDê¨Æúgç(¯ÃxŸGx\³þ9ªœDúD°r?¶m\�Ù™SÌíY´Íót}›g^ùŽcn[RÊEéG«ž§ÉƒÙe]·žë|?ëpΞ÷nÏu–�¤ IàÕ샌�ç¡m.ï|5 cC¼ 9Öÿmc†í¼UrÞŽLF<=/[B%˜vyÝ#ªÕ†¬”=ŽxÚÌ&W;<’0N'Ò'}³¡Ìy›të[óJe”‘·©XçÄ^yñ´â|žâ¶'ÒŸÜËmÔŒ÷ßrò²ÙKõ²©x‹]ˆ-�]@};‡¼�NîG-ñ¼2¿_Øë=†å¨ .Ù¼—~ˆ£=“&e¬Š÷ìÑví¥%áV&ý@F�¢h[P6]æÿ9‹÷ wæl¼qÜOívißë3n)Ê9! „€B@! „€¨KDðå»6*i»Æ¿YÛ5Ž í�{:ž9Œuo¬¥ M”OkÜ6b .eab|5ÞMÞ¹úiÛ1’ÐÇÜÞ/‚Ý\@ Š7zÄ“ {c‘‡ÄI‡Wàú–á |4k†=¶A½ðð;¥˜F¬l‚/vì"a‡s�wÓŒ!þ_Z¼˜Ä"”@ð8–U„V ð#.Êp½”avï.xn«u*6~3˜ò`ÏS1`ÔójÃ3ŽÚü{äïqéíø‡r¢ç“ø¤hÕ0³Ù5oàËUÓÑo¸&d¹ùÙwi‹»ï›Iòƒ“UU¨ß¼¹%ˆà"ª‡=TL;¨Fݵd"ny@ÛÚmè‹…X2¾êŸNªƒ"cè"ø2…vqôAÅJoŽ Œ jñƒ$>�f—µtms46�ÒÇfEü{ß•)Q_¦gZDØK¢,gK,Yš…þ“4`iyÈ¿ßA±¾g,p°*¢^D‚qªçŒ­:lô/ámÆ-”ýË;ì…7»æjK‰°²hK-]Z6æõÿ“r–Q€T¬¤mì¶ba=^üûcøÂ|mS8¤ö+v+G.º¢Q‘BòÇ÷¶.G8â69ãÙEd–·[r•‘ÞihMFýU~qótf ȾЖ)Ó.ï«/º×wuÉ Œ›ò.¿º º ™Œñÿ²- zyO)4<PvY+‹1ýÆ–Gž¸Û­b3ó: ¤¹|3~R½È×aôì��Ö”˜îÖæÂÚ#�L°ÏNM݇Ô2°öìl#F«‹Hh7XÚQC ÿе�Y¿J¤=ùåbÚç“«ßó/c£Œoí¦--�¢)[˜ÑP·tTæ:$DÔÖýâO9ÇÔlšsLuÎ9ª±jÚ¼~¢ .oÒ =9](?SøHu²—<ä5¦¶½zÚÈTûTBˆga�¼Û2·‘{Ú²¥àgìP¢²"ˆæ­Z¸ÞÛ6ÌJÇð\uD¼Me¸·K³ˆ‹ð¡RÚ–´ïÝ´,lÞýc,êdˆ�ŽÖB²Í~Ï/Œ kÿ<8oÏfŸ¢vâ·MØ Îq…·?fO"uÄí�gœâ Ü�;G9yáqM{\bíÁêJê9ÍÑ¢™Ël¾bÒ»×î‡ Q6dØs±³ÜܶxŸ³x\³\”A´úñŠgØf]·Ä:¾ï1\€’äç:ËNE”îÿÕ샀ˆ™¯²öÍú"ÏŽ×�iW" íÜòŽš [è~v�¶(vtû|ÀjC¼œ®Ç¶º2a $»OÚÆÓxê‰l²·É2zoâx3VIcy¥RïPFÚ~æÄimyYýßû´Ûî¿?Y¶°JŠå�ýh(+/;¦d«s$.l/\�‰!Ù4s¢ç°¼nŸèï,lùj:y†Ö>¾Ç*j¾ïÁ¼íÒ½ËU@ÏÓ‡6LYìßsïîÌYwÜO“ßgb©` #„€B@! „€µI@_ Ð/û`>(S~4íp#†Ýp•-µýEïàý�G´s-¯Å]wl 1 ¾Zœaž¤(©ÌçñÉâ±híxñfd\½ãÏø÷À=ê¶~ʹE%•¸óêÆà ÿæv�F$å/yì™D^ÀÞPÏ Äòk�ªx¾âB#<ˆ÷¿¡myÞ‡ÖcLë˜[HzŠEt’š<ýÃ<Žq=)¾¬Í¹,~óºŽk§†îCjIX{6 ÃлөÞ>Õ~a\gí?‘ög?§qö¬¾¨—Pšo ]5¶64:g§!%‘ñ”‹JhÎ&~¬ ùFWe¾¡|&`óÁ™èÈ·Uãub[h¦^czÒÐl�üo„¶\CcGÉŠiè?Nód>'Õ¬åYÃ3!§ìýª³Ècl® yëh›ÖÞ-P±q.ºËÑ‹ŸM‹ÉSÍÅäÈL”«Œ gÍ"òöhö©DÚÏÓ9®°þkóB—@qûí<�B2Ž…f#„û_ÏÞ�íußóˆ=înz–!U¦¯>A?p™vG*T}¤G½*irÁ@ ã·Ì°bÛmKB¹(‡hõcÏSçÁ,³®3±Žï{ ¯Óä>×YváãAìϨö(0‡þ竌…GâugŽ ¶þ'C¯vÎÓLÀ–lzNŸj{Nß�¹é䘬 yð4O{ØjcÂç©5Ô'}�áTÞ&Ý~ ±qn&†å¨RoºáZÛ“û™ó¼ø8ì·}ÚÓ‹o,âuÄm1ë6¦æýÌ oŸã¸m¯È¢g�éìÙÃïX•È=˜·]²ÝÍ;¨}.¸„æ‚éH9Û÷áú ÜÇ‚(þìK(?½èÊkб•ñĬ,9B@! „€B@�:L@_‰TNÕnüiõfœÖÓhÚºn¼®#šà¾,.–2]ìE×;Ý’Ž¾mì>™b|5EõG‹Ð¹ßÃÌR½4ûpù¥´%\è¾Ú÷>\³�ý—æáI œù‰~îR=A…¾ø3Úw¸ÇLãáü ˜øï½Ô­Iª¾ÜŒcoÇóëõËãVÐ/–ïÔÅiv!ÅÍ¿xyӆአ�}EøG‰iq¹ð€‹0èI¬Yr?.9~Í;wBÊv*So­L\`bÈÅSNO;V ð£¨¾´(Õ;^Gçí¥n~j^Ÿ>D/3yšÐcŒ­MÅ[K&ãÚ˩СcøôÿæbXæ,#*í©Â�ßSTpÑ7”Ö‘÷¢{uïE Qɒ§‘Úë 4¢´÷|¸snm2»²O§·§E îÁPëï.ª?гsí2übøSä§ö0ÖÍE�ßFõðU²tyìÑ–Ïi¿ ¬ùÝXô Úšé¿û�4Û¿„Û©Gqý“ŒqRéÃÖV­$¨[¾?ÐJm?.ÙüˆÅÞ»7O± ¾œ/Nñ7&œÜñ*:Æê,îij«Çл E“º%Ãÿ\†‰iƸ@Þ!É ÛM)Á(¾ŠÉCLªÙ޳®ÁÃwö@ãÓUølؘIB$ý (({Õ FôE®ý²ÛØ"QI&#'Oüt Ú4o„ªŠR¼ójÆåêcè×Üé×Üj›±eêò%R¿GT!OÐî]P»’ýÖNL¥v`ûðÿlA'ú‚ãdÛÈ#m™§ÉhTÌÈÅ �ýWÑ6œÛ×/ưqº I7ÂZ$´Yåú…Û¤Œñë~w.=A÷âŽÑ‚Úßê¬Ë�°öIÍ¢{ÀÏé@[­R½o[ý"†°¼—l9ˆôØ*v¯:Àè¼å˜r×Mh:ˆ�KçÒ8odj-ö„ÊÉO¯1f9Ô6˜Fm�öV«Ú÷1^üÅ0˜úcCXC ‚¾Ûmy/ëª{/#±îòâU0Ö5ímÁÅË›i¥ó R{¬{÷!ÕzÖž#¶­êBÚªsˆ¹¥™—µå^é·=ñv꾘XS\�õçøÎØW²—¬ÁØÛµvY±íOøñ�IæØhމ´K‡×9&`ù‡pÓUÍqpûÌ}d Œ©Yj.m…4¾Ÿ·¸…Œ’‡«¶¦‡+ ‡Æ´ÉÎ1Í(œío$æ�|×µ- Ç—`ÉR´í?I?›†¼å�"­og´ Aàt° ÿÚüÆ�2îE©$†[…~¤í±/d[—�äp˜®L° V©­’€Ñð~æîIÍaœù•�ã¶öo°Í7Í>•P›ˆP-vÙ¼»Y~j¶?.Íl�Iš ;ðí>- nGÞå­�âûyĵþyßuÔ“{ŸhbÍÈôÔ¬y˜ñ“ÛÐùЍO[zVÙ…7ò&šÏE±Š'yÎr-Ùm¼ôŠgÔˆu�?cùÖ©©çºDØqFásƒ„û_ÿóUŸc™á›¡g;Ož-¹ù/àGôÃÆÐ‘-x-g8ru==ÂÓàËÛ�;O󬇭Þuu9þ2Úg’×'mÏûޱÁ°•ÛdŽátÑîÝ,óÖü?êq…2IÅ»ôc ‡Á¶Äô3'¶ú©"x´îk~Ûg²ú·Åàë_~OVãÐ5vÓŒè6®}lb.íTøœÅçX•È=˜·]ÝÔHsAÕñÀ6òl߇Y¿§Üã¹�U- O¾Ùjéôã€u›M½°òG! „€B@! ê<|%XEGw€·7—EL¥iû‘vÓU¨ç«àK‰¶gÕL þ´#…_I`õþ_¦¡3ûaÖö×&â¶L&s‹Þs*Öþ}ºÓZ¯ñùòmÚ†0Í8çÝþ>A‡&‡lÞÁ¬ÐOl܇1MWD|Y چò(mCÉl²Rsñ<ÉËÖŽµc-Ï]Ž ÎrÝ—_ˆçîé¡…ªÚ†G/ê‡Wqœ_Ç./ÂÓ#®ÑOÛ7žywcöxn½35Çw‡ç±­ FbÈÏßt²¾Þ÷â t]=ÓWYçpÏPöÂ]LÄ®‡ü׎Æ9ÛßÑÈÏïˆÌÌÛYe��Z†ö©šÇ)÷—|a‡õËòÑOU(9lKÚñ…Çs\rùÊ=?˜—ô2±`<ÄàÄŒ9ò –bVF_èk̤Ã2æa÷ü{­—a¬¦à‹NUïx? 0/mV°ð£Ì<.ž¨ ¨ŒËÑÛ_¼‚/»‡?#@éÃiÇXÇ¥9Eûp7sYv`íopÝÓ¬#Å*øR’ˆÕ3;·q’úÙmÎ~Ö3;Š&â ?}Pæ-ꊉMX^u Žð5&ñö´TŒ1<Ù… ?ñâFÚ:³‹"ø¢¨E‹31xб’žÖè¼|t{'ÊnæGÝÖ( ÿk,þÒâÉnÚNÌ|yoJWÏBßÌ\vÆýp^ÁnÜpKÁ=¼w¿ÿ þƒ]Vªöå$SrÝΆV|Hø¢oׯÊˈâÉÙ–ÍãŒe‘q”1: Ë^ÖÀóÅ'ãºç_Z¤0=’°@æ*ÕÅÈjŸªmeÉ®;',Ù„™éέ&�¡ìß‹Wd!uœ!ì²_3¾9½gÅ�,ÐÜÄØIÇ_»�ƒ¼c�Àhî£i+ÍÙŽ­4ùb›âýkgþýpHÿŒbØþz·ÇºwR gm$ZÛâ[é¨q�‹¥>ÛSô¾£ˆz2‘jT˜A<÷w#-·¿F_W¶Ý°sŽû¿¿v©o Gò¸yýTtT„±†�Š9lL2¬ãÛû)Bú·v¾Œ­¢+j#1o‹�d@|cmC9ƒ¶¡Ô½ÿö»ýÍÈ[GÞÖz«—x_5ÆÞJÚ†´“¹ éËgÚ·&#f–Ç@ZP_³ãûÅÒÃÙ}Â…µboϼO%Ò&þåÕþß¾ ]îG*ŸuÄí7xªé™ÿxÍïÍžžmŠ—Ã5¶÷óÈuã̱Á´×GŸèsìo¸£o¦)àt5C=I[Ü»xÄt Ïíp ©\S¨\šÞ,¥­~8cÏÈÞê/ÉzÖ©¡çºØÝÛ~Wä¹�Ã㯿ùªÿ±�ü�:® †�4=xhRU\ì²E½åaW›vy´/Ÿïe|߃çtÁÚ¦{Y,sAÓ[°^ü³|–®öÕg¼Û|X5Ê ! „€B@! „€¨ƒDð•„J©Úÿ>Üü)*޾¾ôDë7E§^7¢ogcË5{fñ¾”˜'}†¿,ù=þøØóævgö�›3ÆOî�ÞÖvbZÈ/7½Žßf�Æ«ë�1{`ì‹ÿ�)㹤BØúÚS¼Z±&‘Ô/¾¿ÿNÛ n§““GªiŠG*ýã&ÀP¶�?“àKóN£|ÿiO§š+ˆ?Oh�‡T/[ÒÖj/X[«‰»ý%OX�6Õ…Z$˜ÚE[5Z�Â#|4÷~ {ÄðBÔKË?Àà¶úX° ž¥x) ÉuOŸŠéÏü'wãûî‘àæ¾Vx$Ÿò‰šw –<‹'˜åðÌEq{’·_þ cî¹Ña;ÅYðFý\ÛÆÍ* …_þ,&Žèƒ¯?zwõk¥yç‹({…{�²bñ£`ù<ýÐpÌ/àgiÍptf<>½[UbiÖO1ée+€²�Nþ—_“ÔHƶ:ö‚X‘ÕÚzÿhì��€!B íÇŠÜ)7›+G(v K>�o=†áêOˆ³h»¢éÚ‚¦=q÷oÁÌz°¿õëc%TÚ<(Û® x©{ÕܪÉÙo0mÒìðÅ @*ryŽìç¨7w3•³ß\Üß^@¾ŒOpÞ~ùwXø»YøÇVã¤õ÷ætêß“†¿íÝ�uMñN­ý�$ÏvtÏv#^*ļ1šÀq‰AoÑÅ s¨?ÞÍú£W6úlõçëñÛ)ÿÏ¯ÚÆ�Q�o7�O‡ë¿çìßÀa‹¦ &‚ñy »·!&wѶuK[‰<=‚¶5�ñ“ð8ü ³ÜÏqád:�%+•±ÄGÔãríÚÇ>?cB½ö;Ì}fÞvi/Ý=ˆñOLÁÝ·iüb|Ñj 6,þ5†O1|Mà©}/™�Éé½QY´w¶<ÚhýëGøß ô+|e]’De$zô{«K7à7OLÃlm¥ÈÈ@ý«Œ9ONyýÚyŶ·¾xöûØí2«Ø0 ]‡k¢4O”_VÛþšHJ¼�TË[�೿pž}z^. U4}Q!�6�>þ(†4y‡¼ôŒSÍ̘· óïíb˜õ¯ÛÂ�mÌ–cÅ󊇵pqV - Oå<ŒÛ»Ä.Àã•nXŠgÿ{–Y·írêh,™ñ8Ò{‡ ,ʉCÞÓãˆOI9`BÞLÚSô¾CyÕ(W{)Íolû7ekÒgoÚ‹Ç&ŽÑºÍPªÇÂg&§%Þ.9ÏêR,ýͳ˜4[XíŸÑ9KðØCéh“¢Ÿ÷“¬XA¬švÆÌ×ü4†m‘d´E`®Ö¹�º¶gàö-ˆÂ 1{NNg%t€ÆŽ‡þßdÜ;°£¹„Ä¥ýuqé<šŸÞKã§å� È#áÀýŠ+0ÇÇ&´µ‰%m_IHå~,YAžÊŒñš¶U R?>Æ*£MxÕÅnÀ.÷#Ódu½?F˜ß›{x•ƒæéõ}>�¤?á¨j�>ûDp!>;9ºÀÚ^ŠFg?„ÉÝ‹Ž¶AÏÊùÍïs–k¹(q^?Z{·cëô�{»x]w®ù|Ö©¡ç:¿ìî'ExÔ¹�³¢ß㟯&26Pæ~z¶ó$Ø2ûYÌ¡y¡åÝ—æ`9�ãÑɃñÎz¾WoMŽç{CÛWO[ÝbÌS“ß'cª(Dî/†ÐsŒ­tŠ;%¬{åaT<ÿSÚžž&°ôã„Íëíï0â™Ûú±z_³÷ãøÛ' ‹>ÇØèï|,¼¾’èÌ&´fžËŒ(E èÇGÆ/‹">Sú«|Þƒÿp­&øRŒÌÈúŸ]ŠƒeVçPÍÏÈZˆœì‘ÖÜÌ(ÔY¾ûé3Az†m«¿×‹þ,`Lþ ! „€B@! „@]! ‚¯$ÖDèDŽŸ á ùòJiÔÍ›¸I®¬ c|… BÔè!T9†à‰ B¡9 OAJ“ÆhѲ% ?V6®G'«Ž ò¨¿EÛ+ îÊåZ? âðÁ#Rž))”ßå—Å–_ð¾5N�";/D³Æ1É–³y�Êýõ‘#¨:¢2­‹Z¢õeá_&…ªp`ïªCú¤¤ 1ñ¹¸es1K�x~y0ˆæ¦P]¤àÒËZ:ÂSû¨ ªé]üm}Ô?IFÇø©Ü_Ž` åOeN¹°Z8E(X�“¤k¬ß¨™ºhŒÉF ¬Ü�}GBhЀÚqã Ѧ•ýefÄÈžC¨¬¨BÚñôÔ©hÞ¢™ƒ‘gÄØ.„ª±?«7²»…�<¾¡í¿­ïôý§™pòÈ!Tžµ z9K›_Ò²öúN }¸úÈ>T~E-™ºº2>Äfo¾ØKí¿ÅI¡84‚ÀØj"B¨DÆÉ¾>tŒÆ+Z{¡öÓÌÙ'ãèƒÍ³ÅÀ~Æ¢p²ª UGé¾ �Ï�/¢±¤9Ë›Â4üú.øöÛÌØ¥`%Ê+hœ¡-)•q¦U«Ž>D|«OÒ`PŸêÌžK%âa5õý#Ô÷�6sa‹ ¶ñdô{û6_ñla±°q^ µ1œª�õ{f%yë4,GMÉX‹+YªÓÊÓÚ½¸Aãæî¬i쯬¬DU�2Vîw¶LÒ˜L Ô•8F÷&eÎÒ¸y ´j½Ý«ÉfòL§ÌuÈ´lÓ&ò\å,´ÛØ™'£=FÈ-I÷¡9$~©FÚS s�±ÔÕ4~éý¤qË6Ôž#Ìmm—T×ÖøÞ¢U«¤ÍÁb+n Ìk¤®iþS]�ªcVÙ_Øœæ¦ÑÇŽØÊU‹¡|·‰ê«X5TG^ÙE>¹µñ<f/ñª¦¹Õ1º‡hÔ˜æ:Íiž’Ècl�(WXA=Nø¼ÇÔÌsI�ý>£Æ2÷ñ@`œNþ|ÕHÙýoM1tÏ-ÚÙ´))ÍÃèùN»ÓU�7²®PwË%Á|y?MÆÓ;¢ÕU ôÉh¥�t=HóÚÊ8çµFz~æÄF\ç_?íÓwrf^¾û«â½ó-Inl�\]QAsAí™­y zwíq¶ïÃu¬ÏÔ…æ"6! „€B@! ÎW"øªÅš�EðjÚ§FXDªEû%ëºO 6�>u¿ç«…¡&Ô¿cUiž¯¤\g…À§Ï¨[:ž•ÌÎáL‚%ôëæþš×BWÏE5U¶P9–Î^Œ?ÿ†•ùãÍ-`´,ƒäQ¦­éU)fOS5e¯¤+„€B@!pÞ(߸¿û¿±mǸcÖJL`÷ÄÊ=¹m!|Þ‘ Á—€B@! „€B@!PWˆà«k"Á×·õêᛋ΃_²×"çïjÖõN�FÅ�|ê,�oë]ÅËø¶ŽuÖZ1ì\& Œʘ /!ì/Z‰qƒÇ¡@âË‹–WòQÏ—cÚ%½0_—‘»¿}+ZÑ/ÅCÁ ¼÷ò•mlë6�¶¹�û6·Qó–B@! „€B(_= ½2Í)–oúníÒJõîUQò.žè? æŒtÉfÌL·¶×~Bà¼$ ‚¯ó²Z¥PB@! „€B@�󉀾j±6c|)æ)€O@ò±¸àÌ·h@Û`ż}[¬ K¸¤8Ó >N5‹¼ýkÒ3•¿SêÓVÃ)'¾ùN•9öÂVcÅ„ög¬\éÙ+±~ê@}ëšØSK$äþ ³žkK" ¸¸Øv.{e1¦lc;'_„€B@! „@âöcnj9¶ég4#¥ÿØ'��â‚©�)c"‡ç'.øJæ6¦ç'-)•B@! „€B@Ô|Õt#ËX_Jø3)õ¡lï¨x’�ˆD þ7!Ô?qJÄ^‘ Õ±kgRê©¢Îoë׫c–‰9ç2Eð©Œʘ /•X�Ú Ùl+-; §¦¡™W”<¯l£óذIXí–G K^øÒ{Û·Öq *ç„€B@! „€/AÚjüéÇ0i¾ëŒ9K�óP:Ú¤øJ]" �s‹@uÒÛÖ¼@r±»`¹a±zƯŽÄwý'£}ko¼ôÁéÅ.ós @ �W>Ùëpÿ‡ñĶm±ï…Ñ´ÊЫ�Üw�žŸ›‹Î ÄÈÐPœê{/zª]�Žt> @€ @€ °Œ ¾Ë1øJÄ_fÑŸ½ùTlÞ¾3ö¼öÆ=wvgüJœ9{1þ¸5SÓ3 ÿæ1¢¹­%6vU£»{KìÛÝ�ÙßXÏ~*Æÿ®ÅÁ�¿¿ÇÊ  @àÁ Ž Å»g>Šý‡EµkÓÝÐù±Kñã—¿DTwÆîƒOGåÁÜJÃSnýüM|}b *»^�—�>kž¸x@íúõøö‹Óqüõ#±·{ûâú  @€ @€ °âê5øúÿÿ�:Ñ‚@IDATì� |Åõø�Èûᛂ(¢ …øÆW­Üþú°­4ý)ýÙZb­õg¬mÑX«5ÖŸ­±µ�­Jê¯FëO£­Ñ¿D[ÒVcÕøˆh| Jbˆ� �@I˜ÿ™½wwÏì�Ý{wîMn€s?ŸäîÝÝ™9ó�×™Ù³gøƒÏožÜe…úEÎ0ƒÐ{w�?ÿùÏVrss÷ô)xfΩpô‰'ÃYÙßVâêXõ/8â»�*çÔ“à�'î„k²VOïÿޞÿ8´mÞ—>òæ>œKÎ`L€ 0��K ¦q5ÜøÜÃð³gÃGN°ݵ¤~vö�x|.ÜÔöÿàØÑW~*YÇš%°ªò8ö»ß„#âdÞKôYxô‘hˆo/ù.˜>Šï×ã-6@å³epï%¹0cÒ‰ýš6'Ƙ`L€ 0&À˜`L€ 0&À˜`L€ ,¦öVóçχO<F�ƒ ‚Øà+|Á²ÁWxfûj_ƒ¯ú×=„Ùž7ßv)œØ½¶C7¬|ï xô�ÇÓåÏÀ%‡:¿÷å6øÚ—K—óƘ`{­Á׊RøÙé¿@ñ¿ ·´=㌧bÎvÀë§OƒçV|ó½eð¥Óã è×=p ÜûÓ—QøK0_÷g4_lð5ëËĘ`L€ 0&À˜`L€ 0&À˜`L 3Øà+3Ü­TÙà+ƒðXÒ‰ ¾f¢÷ó`ú�®à¾ò$œzËsÖ‰ o¾^º|²{±·>^Û›;{`Ȉ‘pÄÁ‡À‘cGÃ`÷먧w7ôôÇ]Û7ACË.2z$L{ �¥Õ¶a=¬Û´`È`9j |æ3‡Á¡x¿îÓÑÖ M[¶Â¶N€‘cFÂQGŽÇ{ãï¤éôBsc3lØ*Ó>&�(v† ¾|Ñð&À˜`ýB m_=;`[Ãؾ};j#`ôø#ÑcX¼ÑÍÔÎOÖ@Kóv€¡C`èˆCá £ÇÁèÑqìjÛ;Û; ·àÀ!ÃaägÆÁ0ª^ôô`´Û`áegÂ3ÿ¸øµwá«Ý]½ƒ‡Iµ'öé�Žæ-0èÐq0’†w.'Ÿ‡==» õ®!Ãeä=°mMlß,ó2FŒŸˆyöÆ_6tþfL€ 0&À˜`L€ 0&À˜`L€ 0&ÀØà+ƒu€ ¾2€%�Øàël¨^˜§�¤‚wÀŸr¯€›ÌBƒ¯gc_¾ý/˜ó“G�U¨Ÿ³fCuáåpú¡¶±V<’{9Ì…Ëás†@ö�qî¿÷©¿Â��Û ÷Ý:n{Ã9í̺ê6xrî pž{î\÷Ýý¸í×ë˜}óÍ¿*„_fŸHŒÍbéný,ºçX(¾´¼›V^ˆñÿ ã×9aƒ/›,3&À˜È �t|m|éaxìâß§Þ,ÌüÜôן±G:WÑ;ÚVÁ+yyPþÔ*oøÜÿ½ß¹r*ÚPm�¥óþUù�Á긻Ð÷Ø3/Bö¥xì€EWNƒ'žÒÜ„§N¸ï_pýÜéÖÅ]¶ç²ïþþðÄ·€Ú±‡ËÃXø¥iðÌ–|Èz*Te] oy’?áçÿ×þúKJô6ø¢4ø˜ 0&À˜`L€ 0&À˜`L€ 0&À˜ÀþM€ ¾2Xþlð•Aø,i3ƒ¯mp_î÷á6bðõaE1œú‹—b¹›—÷ÙTënÿxüÕÐ8Œµîè‚¿Þx9\gÐ5ªÞ¿2NýUôâô³fÂ&,[öTÕcà«  knV4�Þ ð?3®ƒßÇR¼w=õ†ct6ëæB4HÓÖG“îñÓA^~ú×Líî'þ ?ÍŠ7ùbƒ/43&À˜È �T ¾ÚþyÜq郎ð3®ÿÀÚ·áýÚÆ\—ÀM-÷ñ‡ÆnéZÿoÌW]©™—@õ†¦ê¿ÃjT"{ fã(¼¹ž2^�›0ý\8üp€åo¼;påªá¬)‹~ôYxâç´r 5øšù(|eض÷¡ó€Ffï^: žDobÎå›q ÀûO¹ò}s!n-yŽÞË|9äø€ 0&À˜`L€ 0&À˜`L€ 0&À˜À~O€ ¾2XØà+ƒðXÒ‰ ¾‚·tœuÛ(m>d2œ=^Æ@�Ìn¾gÜõ%´ “Ÿ]›àO·æÂM–ÍØt¨|ý.øÜAòMàîÿ}®?ÿhËXǺ÷áÒKï†*¼‹z-“¡ì|Ù$ø› 0&À˜@f¤dðE�·fþòË®‡ 1î¶×JàŽ¯Üieê„_•Áõ¿˜aúçá·?þ»u,½tÍB/]ƒ¬_¸Ý"n‹GM�ÑQµ>ý[ 4ŽžÓΟêlõ¸gÓ˜?áË`Ì5“l�…—F·tœ½°"hhµGîôˆZÉ ˜ƒ1ÇÃ|ý ¾,_y�^ŨÁ×7Ÿ¯„ÿøÊ+»V½gý·å•, ½‹åƼ‹IIè‡ ¾( >fL€ 0&À˜`L€ 0&À˜`L€ 0&°`ƒ¯ –?|eþK:±Á×$¸ûž+á tøÐ¶¹ ¿õø½³}âÙPõz>œÜòo8ⲇ0gh\…º>g» °òÚ…Û?^nmÿhm×8UzÎr ¯îxøq¸mõ&±ž¹ýÛpå xnYõ›oÁÙccOR­øì¸=#†Í•F]³o�Ž_œG¶nÄsmËá¬/ÞayúºúžbøÓ—ÆãI7ÝËo»J¾5ÙŽÌú~ë‘ÿ�/£»Ž¯ß[}¡»mdì.6øRpñ&À˜`ýN ƒ/Ç€ ¥¾rU=zÛR·nüè7ß�~õ^ýÜÞyŒŒ[!¢g¬g¤g¬k„¢¿3ö “íÜÂñxk G꽋aÍ~>*.RG^bðåœÃ»“˃ŒÖ5øšñ§Á÷r£[FÚ ®Á|Ï“ùþnÜ÷Ä7aˆ}�|³Á�Á‡L€ 0&À˜`L€ 0&À˜`L€ 0&Àös¦_O=õœp 0jÔ(4h ðcÂÒT“´Z6øh%’9y|ùÉv6<ý·á’c‡Cóûóá¸k¥/üà‰=Œþ_U¸õ£üè ¾xêi¸fªjÐÕøÆcpÂ�dß!ܪñîYŸƒÿŒœ“йƒV¸û²«¡·y¼ãáGÑhì°h"Î× ÌõØå|=€ÞÆ®±¼�9`ųó଻тì¬BóŸ/{7'û6ø²Ið7`L€ 0�ÌHÅàkÛk„Û¿rÚ§ÿ~½äz ææ27»–”ÂÏÎþ}nj{ŽÝ/žþ9xmÁ¿üÒ»�ý…q 2½Öý³V½»Z¡«}4„öækù;|Š!ý ¾–¡Á—W”gÊs:ÊC ¾ÂçAŠì|}{ÉpÁtÕ¸ÌñbæÙ:’f– ¾( >fL€ 0&À˜`L€ 0&À˜`L€ 0&°0µ·zôÑGáøã�‡‘#G²Á—ibƒ/Srû^¸d ¾.œy6X;"ŽÇ�›g�y*|åœÉphÌöjÉÓ¿…ó~ÿ^B8<õW4îR=|¹F`4ønx¯büèO[ºè•»Ñ¸ë§Ò¸«wüÏŒëà÷xñŽGÑKX܃R׸Kgð¥K—|mFƒ/))ý°Á¥ÁÇL€ 0&ÀúŸ@*_mÿ¼î¸ôA:~Û}mÜ8ïX¡Á×-hð5–ÀŸ½–cˆÙïé�²]kàÅó¾h‡9ç<£ÑØW£1×Ë/nGbð:–2œ5ør¶ŽôÈÎ_ ü“ 0&À˜`L€ 0&À˜`L€ 0&À˜À~L€ ¾2Xølð•Aø,éÄ_gCuu>œ>Ì_ðMèák¢ôðuÖÕèkVœg¬ø�®1–Îðʽ74¯[UoT•E/ÅN–U_ŸÖ ÷¡‡¯ÛÐÃ×å·ÍÃí'¹Á¬#×Ã×…7ß /].·o N— ¾<ù'`L€ 0�F ƒ¯ôð•/=|Á%pKûý0Qu0êzÔÒxøÊúÓ‹�›;Õ—Fã×À=?}¯Ÿ ß~é7pÆyGÃðÁhß³ªÐKésè@ôÛ¸uãÎÖ�ÁFX2!�ÁWø<Ș‚Óbƒ/Ɉ?L€ 0&À˜`L€ 0&À˜`L€ 0&À˜@²L ¾xKÇd ÜÇ_pö³KÉ|U-̇³Gúƒé¨ÿ7qÙCxÃ$xö…{aÖx{ÛE¿0Á†WºPngCT7­¡Ùö•ð•È/  #›{ÿŸá÷3Çâ‘FghÆ_:ò|Ž 0&À˜ÀÀ!�Ðà«=sy ¹lé»q‹ÄŸÊ-ñ3{!zì:GÝFq;óòßÁ«?‚_vÞG Þ /�ÏÈ]¦gþ~ûÊUq^Ád\ҠʾOݶQ^ÛˆÛBžcyþR=y¹FXºmeH�ÁWø<ȘܴTä56øŠràÿL€ 0&À˜`L€ 0&À˜`L€ 0&À˜@rL ¾æÏŸ'žx"Œ5Š·tLuü]lðÏd=“ŒÁW5|�`ð»ÖÃ�Ï› �JˆÇ^¼÷2ˆLŒmˆ¸«ÞúçxcìEp›et%o 2¼ê…÷ž}–M8 ¾uæ$8tXÔxìÃ7æÃ©7¢1° ¾ßx N¸Q>…˜uÃðÈ•§G½‹í\÷ýb.܆Þ4èýÁé°Á—äÅ&À˜`—@°Á×¹påÂ_ÁÄQ¸ós\†Àádž�™ ¯[×¾ ?Zõ8iJÔèkãKï/þ­u%ë¾AîÜéÖñ§¾~ûcé¹ à„Ÿ??¸ýë0Ú2(Û_{ZÆF kú`x Þ”*ÉôÁ-/Ýǃ]Í« úÖnÅhÙo|õ®‡«fÌiÚ%?ÓÏš‡m]U¸u£õ™}lýÅ ˆ:ïÀmsq[ÇE±kèalÖÌ1$M€«óüékGÇnHïXòôoá¼ß¿‡[Sþ·¦¼(nkÊ·ç?m›·À¥�¼i'ÈßL€ 0&À˜@?6ø d*ÜÔö"±ôaÈÿBÔ°KÞ=aæ—aÔ–—aµ­®Ààöö;`œí%¬cüåÐYð>‰ú„oœ ;þù|*ÏÍüüá•oÁÎÀ—>FîŠ?üÜ_+á;ß™»àzݲNLŸŠ–çh6ý7ð‡%s@š|i ¾ð|ÇÂ�yHàáËÙŽræo ð•9 ³ñß²aT>[÷^’ 3&�Ë1&À˜`L€ 0&À˜`L€ 0&À˜`û#6øÊ`©³ÁWá°¤|Í„ê…yÁ¾byúøíÁò¨µ�¢’ÍãgÂy—ÀçOŠj¹†W<õW¸fj̘ ÔÛ Ï<ø¸²ÄrÏ¥DsáwÑ‹ØÜÿ€‰QÇÑk¾÷O‡{ÿ÷Zøñù¶±—¼= ]¼Úüö|8î'OÃôïÞïül ަàügƒ/0&À˜Èsƒ¯Kà–¶ûA: Ýön9<óÃ`¹cäÍÊ ×ü¾}ÏU0ލ%òÊžMKà_׿ÃËÿŒzêr3~.|ó™_Á\:Á.XóD!Ìûobô5ýËðíû~çL­ƒŸóß |ì\ñ,üüôŸ¹ÑáÑ„ïæÃ5�^‹ÛIƒ¯o Øß¢F`öÍáòà—}û½epÁéêV–Û^ú#Ü~ñ}0áúÿƒŸßû%ÌKü‡ ¾â™ð&À˜`L€ 0&À˜`L€ 0&À˜`û+6øÊ`ɳÁWá°¤ý ¾ÌÅì…¶M­Ð5x ïÙ =ÃFÃØƒ††�®w7´µnƒŽÁ#`ø®Nèy0nÙܶ†ã=];ÆŽg°^5|©<ø`L€ 0�þ& 3ø2•aç¦�Ð�¦èCzº`ϘÃaôh¯©·swÛèhí€Þ!ƒaȈC`ÌXÜ_^½ gìêÁ“==0d´{}þ4XÇhë Ã’”Á›\Ø!à•ÿ›Ý{Á>ôZfeáÔ™`L€ ì§–®_×?[ ç|ù+0鳟ÝO)ô¶?Yý¼óïüÙ?„3&ßÿpŠL€ 0&À˜`L€ 0&À˜`L€ 0&À˜À€!À_, 6øÊ ü–tíüÿ…ÅOü?úX;i22nnS4r€I™9qvïÜ[74AKÃhû´ÎýÑÝ0õâïeN N™ 0&À˜À~L »·®{æáã-`ü±“à�#ÆÂ˜C…Aƒâ6WÜ�)¥'ë{öì�ö¶6غylX×Ç>ºl. ÕmM™ž$9&À˜`L€ 0&À˜`L€ 0&À˜`L`/ À_,$6øÊ ü�–4z®Zýò3°¦² 6®|>Üã�J`Ð�ƒaüôsáø‹¾“gþ§z‘1&À˜`ýJ`{×N(}ÿUx½~94oÛÒ¯iï�‰�?ø0ˆ Ì9ë pðˆQû#Î3`L€ 0&À˜`L€ 0&À˜`L€ 0&@°Á�Ñ߇lðÕßÄ÷Žôzwï‚›?…|�ÊŸ(�!#FÃÈ#Ž„‡ e$L€ 0&À˜À#о«6wlƒ6XO{É F¯i‡�:Ξ_Ó—#dL€ 0&À˜`L€ 0&À˜`L€ 0&°`ƒ¯ |e>'��ŠŸÏ†)_˜ '~õ»IÝÏ71&À˜`L` ر« ¾V|;¼ü“ß°ÁCª˜,`L€ 0&À˜`L€ 0&À˜`L€ 0&À`ƒ¯„ˆúî6øê;¶sêÚ>„ò}F�›—þ¹ ñƒÑÔ¡r L€ 0&À˜@F¬Ý²îy¥ >hn€SŽ:nþâ·`Òaã2" 'ʘ`L€ 0&À˜`L€ 0&À˜`L€ 0�T °ÁWªSÏ_)Àã }C@Øôáøø�°þýJ8ïGwCó²·`}Íkpü—.ƒÉ~Fö™¾I›ceL€ 0&À˜@šlí쀺 �ø÷ ¬h^k67Ã÷Ïù2|}ÚÙðÏåïÀ_Þ«„ãÇN€¬ ÇÂIã'ÂIãŽ�ƒGŒJSê `L€ 0&À˜`L€ 0&À˜`L€ 0&Àú–|õ-ßÀØÙà+_L@@ˆ= z{Aìé…=½=Öñ<–碿{ð[^�}ã=òwï®NèÚ¶%ö·¿[­ãζM°m}=zÜÉpì³`Òù_…acµ¤�Þ¾ÖUýÖ-| sä$~ð0üü;ø0;:ú`ô6  x :P~ão<¶¾žc¿ÀßÖ5üæ`L€ 0&°o¨+4"ß#ÿöàŸõ{�uÜ‹úK7ê$={ö@~w£îÒƒúI~wǾåïnÔ_ôçåýÑðÑx¢áººwÃ¦Ž­°±}+´àßÓÆO‚“�<¦y,œ<þ>d¨¸³{¬Dc0éñËþ“Ç�9>ƒcG#ðþÁ¨³ F=eê3ƒ Â߃aþvÏG¯ËßCPÿq‹ž—÷G¯Éx<`�%ß Œ�¬ãE¿ñ¿##0&À˜`L€ 0&À˜`L€ 0&À˜`LÀ�|ù‘é‡ólðÕ�÷‚$zwï‚­�AÛÚ:ØúÉjؽc;ôìÚ =]�ø'¿cö¹Ý] à%Hƒ©ða!þ³ §2 6: �ßÑcù=Xž�]LÎËû‡t2i*rÌ x߈@j;[7BÛºU°½éã¨l»¤<Ñ¿yÜ�øÝ#Ï9×vEÇÎíéíFñññ¯üÃ|à?K樜#`ðð‘Öß�á£bÇÑsCFŽ�C&ž‡M>eý¬&PX¾È˜`L€ $$ÐŽÆà¶·ÁFù×ÞfLuõì†Ý==°[eÅþváoûX~ïFìÝ=ÝÖ¹è}Òøªzq|—W¶SÔ¨ u4j’ÆN�ÆS¶a”4žrŒ­4FW¶A•eŒu < µ†Ï ¡Ö¸ƒ…ƒP—ûÙÖ¹ÃÊ{ ޵´oƒ]ÈÀ1B³ Ò0ÒXMæSk¤†×,C6dÓ 5jsÃI£7Ë ï�à ¼7j$' =p2:¿Ñ¸Lþ¡1ý0û8ö-¯ Åóòº}Ÿ4hû ßËü�C£ýñ†Ârãû™`L€ 0&À˜`L€ 0&À˜`L€ 0�þ'À_ýÏÜI‘ ¾ûß85â–‰k^}6â¶B‡L::j2zË:\ý“´ÐË6Ø4xÈ>Ïj>L¶�ƺ¶Kïcò=‘mµ½‘m†mhl¶u݇0þ”óàø/þuÖöy.œA&À˜`é"ÐŒãë{8Ž.ÃñTþíDoWãcBŸÁoéåj$�Sc"i\dYFHhhd!)FGÒHiz¡1:ŒHc¹¨11¶‹ÞQã;縧v¡!½ Ó‰^Τw3i´'�÷¤Ÿ4;uÂd8õèÉ0ã˜aâ¡c�äâ@L€ 0&À˜`L€ 0&À˜`L€ 0&À˜ÀÀ"À_,6øÊ ü &½=a,œ÷SØ…áNúÆUpÔ™ËSWEÚ+“–ÛV6-z VþãQ3n"œ÷“ß1ǽ²$Yh&À˜è/;ÑCè£Õ/ÂK«ÃÌã³à´£¦@ÖQÇY^ý%§Ó¿6£çØåMka)ö½±º>‡^R¯½àb#hý+9§Æ˜`L€ 0&À˜`L€ 0&À˜`L€ `ƒ¯ :}|� ¾úð�þƒ¿= ͵o×~ù8nÅxÀ•rïKn ùïüË`òfÉ]¾÷Î’2&À˜èg?ûû#–ç®[¾ô_0:ÁÎý,'׺Ðؼ×ÿk·l„âoÿáöšüaL€ 0&À˜`L€ 0&À˜`L€ 0&ÀöNlð•Árcƒ¯ ÂÏ`Òë߯9 >zJ¥Ø·’n[[�¸íã„Ó>¿oeŒsØ`L Mö �ôß–¾—žvú°Áyš°î•Ñ,À¾zÒY0|ÈнR~š 0&À˜`L€ 0&À˜`L€ 0&À˜`ƒ¯ Ö6øÊ |Nš 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ ì…Øà+ƒ…Æ_„?P’DÏ.€Þ{zð7@¯$  pà`8`0z¦`/% €ñe&À˜`ñPó€�¢ºaÈcÖ@âí gP[‚!0Fâö�ò›?L€ 0&À˜`L€ 0&À˜`L€ 0&À˜À¾A€ ¾2XŽlð•Aø!i4ðÚÓµ�¼ö iöN ‚AÃF :p¥fL€ 0&�; ÚEORæ$3I`4£@£yþ0&À˜`L€ 0&À˜`L€ 0&À˜`{=6øÊ`îÏ_]Ÿ®‚÷×lBúC`ÊŒsaÂðä âÓåïÀš­Ý£&ÀŒ3¦@ˆ É'Ò×w¢'¯=�íi5öêÚü,úh‹Åtòg…bÚ×ÙíÓø¥Ñ×ð1IyúêiûªW4XŒ&�~.3ºO%ë³ÈSi?¦BéÛ]¬zç}Ø„ÍqÈ!Sàܬ ¦Ñï�áº>…wÞ_ƒÞqÆN�SÇ&×í+õP_h~uB¾kŽ«ÌÆ}ú{ßY}ÛÚûòÁï=ºÐ£×V!{.þì�Bƒ¯‘hø•ø£ï·‡KÏŸ®��>Ù»1º¡¨óŸœuÌÞ©óâè�OWC¾ÿ±_êQ�lÔ‹+{:`MÝG°iÖÄ¡CaÂÄ“á˜$õ=5ö/.s›DF¿Ó^®Í 'Îô|檙XKÐ 80ÏîÏ|xnž¸Nö'£�T÷í5¬ÄåÎw¤‡Àþ1¿K«p±dvÞNÖ »yžD'zͤ¬MÂ$–$Ýw ¤1Ï7N�–§ž:Ž9Ä¿l—<ø 8ë–…VŒ¿{m-Ü<ãû>}|À�ápÀP6væ;ÿÆœyƒõ3\½³cßæíÇT~Ÿv×ñ|aÌyðºŒ6«Zk¯‡d[²©$)­OY…ÕP{˹I‰GÃíÍõP›Y¿:ás¾ÿë²Vê žôi[”ˆ“Þ· Èm7‰�°ìÕ÷`s�Í×�¡pð!GÂQÇM‚q{�^¹o—ZzswF7ö€a‰7wôé·Ó+�.¶xõžÙðÅŸÿƒ\ÌB�¿v¯ÔùI&4‡d Øõ( ŸS„S?Îÿz>}fõEPjb}OŸ’.s=¢>>Û7åÚÇBsôLÀ€�sÒ¹*Ï¿‚aîÏ|öç¼× ÷j2êÏ´Üê�h²Ï­aé³ÌgÓJ`šß¥\r‘elÞžœxÉßÅ󤄬LÊÚ$LBAÒÃ@óŒs·—°6ÎdL`À`ƒ/Ã"êjxþòï“=ø³0ç37Ÿs>I|ÑÁ íÉ-‚?þîzÈÀ–æƒx<þÍ1p•µòž 5íåpFF ¾:`ù;+`ÇбpZoc{vnCï^ò±«ül…?z|ý†âèÏ€ÿÙ?¾þð?WÁMž—?z-œvÃ|+ôý ×Âõ§í?_pzùyP¹è¥ŽåÁ˜S®³~Õ´Âõg àF�óöià%Ÿv×± ¾Î_fí00ËI\¤õ)»¨ʯ?#‰P4ÜÞ\µ™õ«]‹áŠg“2Pv1´—ÿd7¶ü¡+à”묳°Ï±Ðòžôi[ÞÛø÷>L û/Ë»Wû[0û  áí$©žŸ{/üú·?†“öÎ!3É\î_·%åå˧ßîkR=kž‚!ÇÏñ$“ µ�CVbÛ~O¸�ñ³ã“å°ÝxM˜zLQ¼C‘1€Œ�Cê�$áý5ÿë‚g¯ÿõg•CNI-üõûYêIí/¿¾�ä…Ë\K®oO¦Z®}+ÇÎÒI€Î9é\µÿ×Ò™«¾�kæ“©¹¹¿žÔ÷å6…þd”‰ºèW´?Ù?×mÂÖõ~?®ê]ýó+²ìkó»L0”µÃ7]¿uØþ©R¡SñÍð<)!Ì€5_®¬~øÉ™‰1/!ï°7”Oبø~&À˜€ 6ø2¡†aºÖ/„¿¼°2ùÐÃÑàë{†_t°H:Ål¨j)‡Ï�M:@¿Þ(ÝA×­G£'ÜÒñ蓦¡ƒ“Mž(ý¶àï/[ϧÿ€!G}oámLì�=;·G#íú~}É9ðË7=iL»²åöxM+àozëÙ×à…ºÇࢉêS¯ýÚà ñ ypÂm÷•E óöã©gIÿôkwènyUlC/1C>¦“k£v˜tÞýo¤õ‰.¢û‡ˆ^¡áö½Å2Ÿ:ADZ|½Æ_±Ú0ÀŒ˜Õ^¾žnýÝu oÚŽÎ÷á'#σçBef,Øø,œ3@õÊPYá›ñ”a níøñé·äá"#³rKá�?}7Äá£âL€ 0é2øBgEfŸ_ÿµKÈ¿½ñÓÓÓ#üþd~>}ï9ñðÃ[¥o®‹Ë¢}-î‚÷Dg�ÈAPXÀ"E¢¯www+�­M¢ª¬PàûÆÑûäwn™èôƵ×ÿn%Ùv³EM{f3ÔRYã�#j’…ÝÛ#z;Úðoµ¸ÿóv^¢ß×Üó”øh]c캼§MìÚ°Z¼ýä�n¹Ze|™X´!z=W›XZt™szøRâ°ïÙ—¿ÅžÞ„•¡½¶Øa„‹ ïçl«ÝÙRÙßFíМÂ7­O¸ˆžtL4Ü~S•q¬XØ]wmqÎ~Þ&vÛJºRó�Æú»ÿjßÓ-šwV‹Ù¶¾¹W¬ØÓ%ww(붬 Êî'Ù÷YzåÓbÞÛÌ{=ƒmX~<ýviMu¥¹Î¸P\›¬r�07¼¡IdEõüìâZ�d ˆ‹þbìb/øI8A?ÍÿºëD®Ýÿe—„žSû÷í$/\æý_÷R,×þ˜Sdæèœ3Ì\Õ_t–� 0�}ƒ€©½Õ3Ï<#–,Y">úè#Q__/�8úÓâÌ$­~ ³ãcxªôtFŠŸÁÇÂe?ø x7ØKzKGjœ`뇮UOÁˆ“ìmP²¡·<Žñ8ì„ϸõ«7ZaGŒ?ŽRt°.¨÷X¾t5´ÃpŒ:äÈ£á³Y'ñ4Þ"QW“qI=ö˜¬É(o¬[\+>\;vá7ìP˜0ýT83kb\eçgǦ�aÅâ•°©Ãêñ`‰§Â)Öý×òzèD¯³‡7Æ�î�¦U ø[Ö¯qدùׯ-k>„–XýšÃº_Æõñ†h?}ì”#á ôð%·u üÐ~;»:Ë¿=Ÿ®‚÷-†OpÑÕÕ{|ùKçÂØ€¨’î°Œ×4m�7u\õdT²Ü’*¸ÝwwÇO¥ãO¬zçmX¼ô#ØŽm[¯¥ãL;e:ê?úú“ü<(Mã+f¡í“5°ñÓwáºóæD·¿Î-�º[ÎÅüØý‘ús'z¿Üñ T/|/yÝ-]ú€¦2$]v±°)�/¡õP�о§’¯3V¹5¼ ']Ý ªê~c»»á £�‡ ¾mOØ·÷¸ž=Q2+s™Lø¹ºMzÆ7Ó6Bç� ïÖ±°­÷ÀâW_…ÚOZq®p \|ÙöEaÊ5옛Š\ñå’|]µÂš¬eÄ%jZ†qiNd"?1<§ÌËØpž�é§«Ýz²z®ê·–�7Ö.?À¹8.fÊe=©�úï)šy + Ö¡åKa%®=mh툭¡Mƒ¸¾¦ª‰¸~° ×°?µ×,Ü8bGN�ã1]E}Ä[LæaÂó‰ÊØ¿õÇ´LâÈ&;[¾×ä†ÀáÇáüÈóÜÏ�õ31¿87ŽcØËß\Ë×àóRÌÕèñSáü ÎuÛ ÎgW½ «p~b=‡Áç‘g��×ÕÆ=mŸâÎG[0†‘¸ó‘ºþh³kûd¬Ç-U†Œ$kžt�&¶¶Þ�pÍ¡ïêV�¤Ÿ‘%*ÿÁ‰ž#˜¤ûžD·ÿ0/C¶eMùhºg»ˆ�o:ÞËçöÃqmoÕâ%ðÑú�Ð!Þ£.ž…k�Yš�uÜ<&×G†ZGs$LVÏwàAßöÇ4¥dûp†�™À¾J€=|õ‰áÞnQó\Ô³—ôâUݨ;ÝÌ×ëE/z»(ŽØ^£"¢JºÃOmqvìmùlQ^Y;ŽÞ‡Û‹Do²þ·ŠòB×ã V|å^À·ªËj½ïŸ·ŠŠB÷müø0 ²óK-ÏdvB5E'ÞB�§¥î†J×£™'ýœÂQ˜“åäÅë᫽®Ü7¬”+» ,îíy— òª¯…?OÞ³ ECÌ!B{M‘#¿7¿*O;ÇäÛòðU'~7Í�ÎCo%å‘kók¿#é^ ^^çzùr=|�,î|è>1ÇÃΖ3ûögÅ6ËØ¶·c“XôÐ�$nW6;Üœ»<á6¿%²ci̼§\¼ýØuúð?x\ìèhóoº@{}æíåbWä í᫲J9Þâ<ùÍ.rÊÚ-¹nQS’¯ÍƒÍ(§°Âñ\ä† ß>ܰú#mûé¬uÊ#RT%ê*lïsž¼a™V6ÄElÔîðÍ…ˆ]ϲŠnpÀ˜¨�©sŠ 6�¯98ãOkm°®Ÿ•S$ê=}‚«ë£¬ó tޝ8Z“ñÑæoÛù!o1狪ŠBßr×éné•—váÊÎ IúÛ~ÓC©ÈÇáêLP¹�H4Ï ªÇѰ©•yØv€Åº”êøfZÃêü–°J+¥yv{’ß:•æ>ÙrMT÷5cnJrQ±tSêß’_Ë ©š–!�Ãï8ùñ“Å=Ÿj‡Ÿg§»Ýºy1›«j×0ÒV\KËuæu´}ÙÇÙ¢´:¶Àè !ZªKÝ5G/²Ã¨ówÑî3W$ñÑ~´°š®=šÌÿ‡ñã±ë�i™œ¡ݹy–(()ö][Í.ð¬{•kP¿lëIɈ߿eâ2ayºòÎKu*±ÌFw½ë94á˜Í·¶.*cŽI¤cš¸,Ò–šƒð뎉ûäDc}²Üsµóv,vç6Ø×j=ƶˆBÒŸç”Ö$1/±¥ ú×Þhî�£Òù�oŠJ}ÖýÂ2Œ¦fŒH®<Ó¯ã~^ÜHž©c}%í‡ÈÚ¼[OLtÄvQQ೦)••î*AkdnÙ&Ã/µy’Yp%ÔQ†•µU"/Nωê;e¸ÑY_æ£e‹Šu�BÛ¿+^¤LEÜÚ:¹/N¶¾¬a×£ËÌ$\ßc¡Tú�dûm·ÌÚ2Ý¥+Ñ3|7-·ž�(®(y¤ÿ¦m>’ïy®­ä1¸�4™—I Céù±,™µÅ0ý±ÍÎ$Œ–¿™À¾I ]¾öË-ýªDÇšWœ­}~…ßmÎ=¾7Øâsû‚î»Eä;|DT6E-”褔òØUÌ:EY®½0ýÎÊÎùùyŽ!I4l–�ŠŒý©+U "²"9"77Wd{§œw*�â œí+­|d‰Üü|‘—Q€Xq«[ztÖ•ª÷àáœ< ›ëQPóÊ•m9¨,. +óQyØF2­ˆÃÙ¾'Ë2þÈ+­³Ñè¿ÑàkÇâGˆ¬¸=ãfj|t¼VÙò†g–;†b®Á—-�ü>YÌùÁ÷E¶gr0óž—�pr›ÇµÏxŒ½¦] ®Áps.>™È‰sE¯»á6¼­ž¸³¿ƒéy¶ªt¹by[¬nci"OXƒ/W&}Y»í"ZŒ åc¯¬ˆUÏs²mÄ(÷ìbõ!¿IûÐW÷,­³NûÁ¶càyÚ�Õs¿É”«á˜›’\®´áëj4¬¾ÓÏo½óã2tÅö=ÊD~|…q.–q*ý[_´ÛX~L窴Î8k øÀÈ»'×ÃâÇ¢Aw[n¯¥/Éq5"rr¼óww]RyP©¬8…$è\Ù‘/›ÌÿLÂhùXâõsý1,—dø#šwG'‘몚õÝHyq˜Îõ“.×dô¤Dyèç2Aq(£hýÄyi¾;/Í+÷®¨DóÐ^ãG€\7I”5mZx2¥þÈ/ÑÄeAÛe\݈Dujû¼­[Û©õÝXc°îˆ¯¢‡^ �1➘«ŒÚŒO‹("ÜóÊÜ—Õdœt EÀ­É[qΑx^"C}³“yK4¿ JQŽÉè~f ÃŽ+I0ì÷bqÏ�5s:§ôéƒie·Oihô¼Ë.�ÇqD¬}[Ïú¼Ï¢×¼ú¥‡ú�¿87Ö2ÌÊÖèG¤Œh®g—ú>‹¤ºŽËŒÌé¸JËÚZ[O‚+ CâÒæ-Éú~=:±œT•Iø¾ÇâhÔoÇJ …¶ìèÓäÙ‡[®ú#šwÚV³Q§ö>_÷ê_Éô‘¦ó²Ðz>f¯úã(G=__|– ì;Øà+íe¹Y<�^½¢Þ»JÅ×.*.¥¾ñðÕ œ3ÙÎÛðÔRXY¹E¢®UþÖVÑ›iª�?ZŸ+oë£e?}³ß´T�beuô <|ØZK­ÛsE],-:�ÑA¼ŽD •7ô;ã<Ñ…]ô2C&;Þ7ÎÚë+”¬b⬮ÄõÈ!ÙHké2û®§†>N¾eqbÞ�‡4T–¸¢VO Á×¶wïsIWÒè*Ù¿�žü¾ö×Ëkð5ó¦Çņ­n¼z;Ìä11øŠ/kâ+B=V©oG嗹Ƌ²p›ªÈâ z¡ªqÚ½YûP+Lü/mûÁÁ\¥<"è��AtÖ‘¾!ö6b,jãvG' ¤m´TŽYy¢ºÅâé²DyÌ(µ¥Š†Éµ­¤v7‰bb@–]Lù·C³~ ÁxX *èÂ]üÛÔÉMp£À½‹eÉ×Có~.¾¹gª "±¶š%*bå“4îA´2±À›Z«]ƒkqÓ§N(‹û¤®hë²+šÏ‘Y»J¥.ô{Ûòɹ{Ú°OJ¡ŸpÓÖõ7_åmQí¢¹ú`ÜÖ5”þ ûëJåM»nQ­è¶q>(&}�—B¢…<4WÆå.Ï�àþËLVOžŸá ¾V‹[½2j,$=f=èxŒq×¢æ8�S͉QXä^±Ê2ÞZKâB£$ôdµŽuIÏXW�qlnÅZ'Þ7s½…I½ãü[Ÿ+ˆ'¯ê7»:G„x-Co]³iœ –9q6o_&n‰P=„m,¶n%1ÌÇø¢ò«ž¾ÊˆQØ]ÕQ+Þ ž¹²n¯nA9;�»×O[˜Vñ"÷zø¢y¸P<²¬‘\GY�rP™+ÆpYwˆ7‰G²7y,†¾¬°½¢½Vä™èØlÜ`}¥s–"¢¯£¶¥è19èÍÔÕ.Ðqz ¥}u~…kòEãÔσúf|•ͯ³ÖÕãu²�k3®!º[»Gws¬êúN^ã²Ka|1ÖC=ý[üOó:ã<`’åBô–ø4tg‚úvÓ2÷<&;W×ÉGÏ™ŽoæuÐXç�[´Gu¢µ½ÿho@óç9F=ÕZ×”«ñ˜›¹RèßÌ×2ÌËÐCUóÓ¼í™çG#†ç”q§Ð¿÷©Ùã~¦0WÕÍ¿¨^É/W=ww·ˆ²|{¾"§Ô6,hR<Èä•Ô¸F,ž0€ž¤­Ù½ß\‘d�Ε]�ÛdþgFgЮ¿ë�Y™�‡´nèÖFëÊèK�dÝ˸\éIÁ™èï2‘ÒPFvýT¼¢£Î ®ŠGóPIŒÂâ^¢óɦ.-¹NEõ]id™ìºŸO2Îé �•¶K]ݨ/'ëyÊ\¸ïÆ¥ü“]w¤k•I¯ ¢¸qEíÎøY†h©t_¾Ä—z«ìŠG×%èy+Aó§*hÞaØalt.¦Îï´I¹'“Ò±Lš�AåÙ—:nPº~ë­Æ:íÓQgÎ/¯#e‚óÓˆº†?Çuo÷æ#Îà û· Ï�½ s‹«]]§¥JyÖ(ûFú¼¨³¡Bi£tiCÛ¿+°Èœ‘ÎEiÙ�ó�\}Âxóÿl‚Œù$-|Ú«è4Ï2 þÏÈ‚Ç|?&Æ}O ý¶q[öa­­æÍ»=ÆÒÇbµ¥yîz'uâ�Ti:/3Ðó�Ç4“þØ$Œ>Ÿbû¥­@IDAT6øJs�n^ö¼ã¹kþ›��±|á›þË™^#„|Q³™PÞ&|«œØRD…ìTfÚ{A*9ÀÝQêb†öÀ‚J�|k$.Z ߀n^ ŠJDYy•cHE2{’,j´UJ¼ˆÙb¨ƒ¼kd¥N° 1¦øO+ñô‘•ïz¢Jd(¢±Ð�5l×4Š"ê×ŧì9ƒ_� \ã«ì"ÕÀ*‘á׎Årùlâ©K5øºQ¬�3"k�}ÇUÊïmmÔøjó»âwß¹LdKo^Ÿ¿S4êÂ]l‡ûšx{ƒmDÖ(s΃¸¡ê¥«wý b¦¬±¿'kmc¯XøÕO9oú(_†ò„6øBƒB÷Q ]F´¬Ýú…æé¸•(ZÕKo^Úp�Ä0†ÔÃöaKã÷­o?d2€ÌÏ4$’¦ WYwÌš·;ý¤RíKJ¤Kϧ¦0âÔ‹œ’èı¾¼ùf[“!�ì´�ª“IšoÂÞJS•%é~ Ã*ž�rÔ7q¢ÙiQ<«2y2ìù©,–i듾¦ÒÏyDP~R£-ú€Üy‹‘´cPrÊRŽ ­ßäÆç¼¾.+âÅÿ0jWæuÁë�EW?ÓÞ¶âs­ž1í“”q+L?¡&ÿ+|ñ�+×�:é¯máګ݇ºànQΪ¨H~« †v¦ô Ž·07}‹ÖïÍn÷nû(¨ÿÂkÄÈ,Œ¬vìºï8ƒ¯ìG£+Ç8É2RÚ*Êæ]îô×7‹ê˜‘ÕŠ7îvÏßðlÔ»•mØ„ßo–ºZ¶‡¬uˈzðÒQÕS`sžpd[·ŒxÓB£&êý+*35&»ÜÙ†Q‘“ÄçäsK%Ù¾Ñ5øjÞÓ(nwŒ™¦‹Ç×Ã-™ÏÝˈ�–ëå¬zÁÝâ¢ìYVœ·¼â¬ÙéÑ|ØÆeÑk›Å<ç%º°K+\£6×XŒÊ âÁ•QOjvzòûùBê!ÌÜàKW¯ÕqÉ6”O¥?Ð?H“u¹“zA^ö3 ZÏÛ©02v'š©ù7� éëŽé˜¯+Ð>@ß'Ó¹�¾ïäM¥ì祿ÇÊTêŒWŸÑÕ7]yGÏQ^Ý”^K¾Ì±˜ÍÕý…t®˜Œo©ÔAs�_õ¤™›È«¶“CràÑGÝrÅr1sS—+•ºJçHaÖ2R)CBT{˜‰ühQN¦RƉۭ¾ë§vKÆ;7ËþsUÝü‹>Œ/®Õ¬ê¡Þ]\P(JJËDU]tµ­³žxØ×É€ºxÄ™GæD=[zÚ ³´æ ®÷ðe2ÿ3 ƒrèøXóAã>¬þ˜” ÁhtHóÎü‰F…ë^„ƒc¸dZ®u°žDÓög¢MûÕúð_jlð´¡î:b¤eÏK½ù‰ÿMËÃ]77«Oñ±ÇŸ * zM¿&Ú¿kX^½Èž³Ó\ů;f¦ÎPv¶.oË™êXÜPNŒð%8|F”’9¥²¾‡Wƒd±eÒ§ÂίÝèSRÏ&Ö±ŒŽA ûRÇ J×;o±ÇVSQ™èÆwºÓŽóÞz­–¡ú+0I¬WöïÜX®A¸F’@¼cÙ¹ªvÖÄñùWÜ‹¨tguÍR߿۱ÊoÒ×Sc+Ÿñ6�«O%oaž‡¯G÷Az&©ô=„a¨çdB·eÖ´duÇ4ï€Ïí©Ë�èýäE@× ÝüØt^f¢ç÷kl؇ëøó9&°/`ƒ¯´–&õî5_¬Û¹‘Á¾EQZY)*+*D…õ‡Çø»¼´Hä8¦¢F6ùöVD(ø#…Äõ¶-"µzÆA^g0%om(s'Ñɽj,’W\)šÚ=“[; òM2gâJ;j\\°�ÕH0Ô´È[¹Ä¢™Z¥çûlí„õûp˜-P6º�QQ²0Mw;ª8¨Š›"³÷|-ºçkîƒÒ‡óðµáù뜰Y7=ëx£_ÊÖ‹Ä€ë£'Ý°Š‘¹GgpæÆý5±Hkð¥10Ûüº˜c/ð}þwb³7 ôf_#‹”O'OXƒ¯\çÍTZ@†eŠQ¸ušÖ³öA%Ò»iQO]Tv×› O•ygB–B»ÓN*±/qÜ×ú¶ãQ_ß Z¤—AÛÅ TwL”fGvë>šoÊ/÷k¸�c‘ëªZ÷�[&MËA•ÉÌ÷ŸÚçØoHÓÛõyJ¥Ÿ£±Çجü ç²ûVqìÚÛhaè<# ›øðÝ7H9)1|ÎS†ÎXàHàw`ЮR¨ êÐOmË/ë!λli» u+D^¥› ¾(Su¡ÛN©Î#ÅU¼ŶÚUtÿÅvºpšSó(è10su™5£¼åµ -O¸Td H2Îà .¾ò¢(«ø‡xÊúÃcüýxé½b¶G¯œK ˜pëB×˧íùËö€Õ,îŠØßîÖ…¯’­m#0j˜d+ñ¢áÖÎhœõÄàëŠRâ¥K_YÔ`Ê•ç¥y®±ÓÜ ýÖŒÔS5ª.s�Ö.šWåzÛÂôèÖ”4L\~ùbr�cj8*ÿÕâMâ½ÌŽSk,fo)õ-4„Ón¯©lÁijðE_x L×.RêÔ±•Ž ôÁ§ß¸,y\ÏtÜÕ̓úl|ET4íx]�öºrÔEf;|ŸÉ›RÙѼ„_RÑCIUÔ¦Rg´:®.í9ÊÂÓ·ÓÅ{íKXú2OE§ÕŠHO*í†ÎuåMúñ­Ïê L’èŒv�—§U},âz²ˆ^Lî?‰Û«§:ž¿´FÑèµú�R¦fr¥RWif-£/Ë0ùIXRÒ«h›Ñ¿¥Ô§ç(•¹ª;Gp×è @€žr*êš´/sR©jKrœu)¿q¹¥¡A44µˆÖÖöh|~m�DLë´«Ìÿ-ÃþÈ' zš¶=¯œôZ˜µÔ>k° ½î˜¡:CÙy¹¦Î ‹síy7îæ’ån/ š—Ô‚d¡u!î8%vþí&.�¸´¾ëu,s†&ãJ }–Ìé+Õº�8Ÿ�eGâ¥ú- FG¤:F¾²Û…[@Ôk¡š÷Ý•)>å0æÆ˜*o¾fË^ÚOº‹åNÖ]]I�Òpt,qÒùE|Ѽ…©®ŒþGnþÔ|Ó4½åï†qõSÙfÒ3G ¡¿ûg˽BÚœ’rž¶E7 þˆæ]‰�Ü^_Jõ [G£mFßGšÎËܺ "Y=¿ûc³>œ åC&°O`ƒ¯4ëö�^q¼{•¾¾&aÌf_®"o{NÒ}+.FQ: :oaQ •ÅvtÓž_ òóóÕ¿‚‘KþÙ ÕÄ0–%’“+ŠJÊEM½~¡ˆdŽbCEôf¿‘@ÅÄœh·Q¤ñAVŽ((ðÈŽy)ÈwF Æb”Mq­.U:xREÅï¼*qÜ/4øúà!w»Ã°ÆN~ÛAºFPèáÁëm+fl¥zs·ƒ”FT»Ö/ ú�¸õßGo_ˆ™Ÿ¿@dM;Ùú³ËÀÇàëâûĶ8ƒ.bð•ຎAXyÂ|…+ëh)v·Ö‹ò’"‘Ÿ›‹Þ¨""‰XjeRMê– eÒ>âêŒç­ïNû¡“Í['2 Z×2…vG'«Ž"‹ñ9ʸo;ödÈùÙ-ê«ËE¶ßÜôöEøfѾÇ6ް´Ãú5ÊX_W|x:yñ? å �[Ÿ'*SØ~Î_y…¦çz9tê.ȶ–Î$–¸�w5i}JbRJóäÖå`iåUG6Û¨¿Ç"¿ìÏÂŒq Ÿþj[‰Xw„ï“HY‡ÉK"y2Áeꦞðm:ן Ý¢Š¼eMë§OþeVé[IN_‰çéÂW^™k¬ÙÝTîx¬Ì²·¬‘%ü�òðŒJÿj «_Òñ_Éé•WWÅyñ¢ÆT×”­t ¢×?+NŠµÍ“nø‡Žn=X¸l³s¿mÐän9ÛEº†[ÔàK–LQ#3×C™>\— ^À#¬íUâ"§�™ëx7kÞÓ!žºazì!'zÿZïñþ…׫«ŸwÝy³¸bzûŠ\(NÊšûsy+iá6™Ž‡¯l²%%1£ œ°Ä€ |ÂYÞÊ"vº†_¾uë°ãé!f(’Ràÿ@€Žú±SÖz�<ò,y3W7¢q§w|UÓ¦ýI´�’>À‡1•Ýßgò¦TvfyQûº,AÝG?ÿÓÝIÏQNaëŒ"Õgh¾Ç„…·o§:Wˆ2÷z] §Çø ê\;¾Q¶fm&E�Ÿ¼¼åd"™ªÐr¥ç}ÊEF¯×HyÊEy†­«´�Ї%ò‘úHÓ S†­õÕ¢¬¬\”—{þÊ*D}¬Ó¸õ2Iš(—wü�gI­«ÏOB¹ÒUÆ>õƒÊm÷Õ}Ùn“a¬• Ó°Îü ½u8sxG÷‰ˆÜü"Q^Y£}©“Æ£/+YΞ-ÚÉmTnG>¼zþg†æËIŸÊíSdö>aiž�úcP&R†T>4ïÅîÖJ”Ú!ËU›w%EŸ4M®2¤V^Ó±㣌œú!"/ÑIïî ÌÔà ÎK›¿ -£“}Z¤ôÉ·)Ó pôš¾½¹Ò0ÖD üÇòwú¬d×3Tg(;§}DzFË8ÌX¬�AýÝ5~³ç|¹¢Ö]qn’ŹIw�;¿º¬KÈ{ŽÔ++†&ãJb†}£ã¦KˇôÁ4Œi»Õ‡SwÅðÖko)ÒßT¦øp¤¼Côo©Ô*›î˜Ê«cAÓÖmWê^§Ï“i„)S¿9*•3Žkšë‡Í)üz´ªç{åtY©_NÿæS'¤<éë£y4hË>¬mf~ß4ï¡ô/ªÏ$ÑGêêpT&¬ožy™"“öyy|nh˜°cšIl&^j>Ãö-lð•¶òÜ-Þ›ÿpÌàëQ±¢­'aÌi7øÊ’ 2Å¢ªÞq¿âÈ@~eRjßA$g�Çž(è¿Ý7äq+ÉbjLå½?[•×*oÒÀ‘G‘!_³Ýž–(<~“Ȥä�8žº²ñIÓO©ï7|Q£-�±“ÎË–}nók¿sÞ¤¤a©Á×ý cÛ5zŒ°6¿t›öšÇÞu¼ƒ­]p§sÞ5îò–£üícðõù_ ®Ó|È|šÈÖàË©wJAéë—¼¥¡¢0IFª�jgèö¡ˆ¤ù¡m?´žÒÉ O뺣X§Ðî´�¤â#BÙ‡è]ÀÝ2VW÷ÜsŽìVXÿ2SäKª_@£¡˜DÊ8¯BïóPËÓÎOÀ7 ¦R™‚Û©ÍÊíçı.Õ9ohǶf$¢LÚ�-wmFÔ•¶3i åOë¡Ïyš'= ?ÉC¶+š~Ⱥ ôõ4OD4Z¦NýTÒ 7¦‘¨}Íú$Ò^ÂäÅWŠØ%¯vý þ¶ë‘1_+iâeuÇëu1�ùt´"*§Oþe´­UN¯¼éF »èö¦ôÍ'§-ÄБò :�&UY}eð•u¡¸âÖÄ‚ÕÍzã,bØ‘{�-_}LodE ¾îZä'n¥x‹ÓF¯¯j<|éÃ)Ð|éÃIo]w8åíRY†VhØu«mØâöê˜Ì;‰Ù¶Œ¸%f=1ÊjFe·G‚ë¾Ý«iù#†_>áš÷4“í) ¾|Û ne³|kR>X u×¹ÌÄíü?“/Tyì´�Ö�54n»|‚¿“_iÚÎøà´OÒø0Ö…ï3yS*;³¼¨õ%½c%å¤+÷h1èëŒ"—OÙ8Åw@Xxûö´èëÁíÉ®»´]ʼnè=r|£líô‚¿I›I‡Î°àïÍšò›ÖqZ®~ç•À~ú)oC¹(ϰu•öú°D>RišÁeg×·hÖEœ1ÓÎ~)„Æ­—I‚Õ·=Óü$”+]eLë ©Tn§¯§iŒ‡$ú¸CÊ8ì\•†¥åÓÙP©¼àé-ßì¼"QÛê«Ðxò*šâdÔž L’`Iå3[W 9gD¡i¾œô“�[æW?‡ m0‰<;õã [&R†T>Ú¼{"Ôæ1 >´�8\1nzžæÝ“lüÏ$Ò”�´òšŽÅŸ?#4ìÊw½+Ùý¡ôÐé>¬.Á”“ÿèÓ2¯O‰R* z�–Ÿ'‘+ c�¯Ï-ôÌ™TDÃø´E™Zºë eç­ã´Œ½}®þ7ѧš&ºµ#Ž7~;ŸÉB¢‹?L‰]P»‰OJ=Cê•�Ž•ÃðcD Ã>ÔqÓõ)Æ´ÝêÃa;©v×̼õZ-Cõ•)>)oŸ6ª ŸZPåóþ¢ééXдƒ¯«ÏŠ…ó]'M¢¬ã¸&F'»"é×%#³õèà1_ËÄGvo9¥»ß–žã�žQ%)¯W~mÞ=7%Ìc}¤¾œeBñó2*S²z> £Ãìy¥ýMÇ´ðý±ÙÜÀ–2�}Œ|¥«@;>O<3ø*}St$¯‘ÁZëZ¦ÝÝ¢[ù N0‘‚¢,jËÉAq‰(..öÿ+Â7ýjT#ˆîÖQ]Q* rÝ-–hçîx€AQéà 6tPÌ*rÐ*Y#ÊQ6h|��/JJdÇ|—‹–ØZUB6t1€¤¤ø("{Hƒ¯…÷¹ ¥Ón�Ã,Û¸K÷ýòM';aç<ô–c´•ŒÁ×¶…ÄX¬(êákWÝãN|²¼²¾s›˜ÿüËbéâwÅGuËEãº:±ÀI³ï ¾LåéKƒ¯î†2•QN�(«¬µuu¢·)hjiåÎ⎪ÄÛŦ}Øaü¾i}wÚ­§!&FJÛÙî”°vš´û¼]Ÿ¯NQNÜ�daT&ªkjE]}½hhhMu®uò¢ï¬4¨,!û5ÊØY¬óN÷AWeòÜèùiÚçP™Âösâ~Ò½Ù­Å¡ö*Af²O(¬ŠöõΛX®r¡²*?käíAÊÜ®25Ÿó4On]ŽÏ÷DÒ튦².(}=Í‘Š–©ShšaÛ‰[whÞ'‘ö&/:!è9š×þâK_q{ØD·Q\OS9}ò/£u·3a{3�&Gøa>ˬW·©Ñ™ë!/&^‚/ŸgìHYV}Òq_h¨µB,íî�ÊŸ½UbÐ71RB�¬–ž®‰qÑb)1†JÎà«™,¬à–ŽÛ£éSïVzÃ-*K8ƒ/·j„Õ%Ö-{ÄÿsŸ¶¼•Q�`s+Öc¸­âqe,›.æ?-ž_´H¼¹z¥X´®Q,]éz?SÓ"òûni夾|Â5£÷°Âl{A%Ý_t»·Ø¶�´î†î|æX�“/ZEqÄΫ» %í£uc �;Ýã+MÛœæIúŸ>I¾ÏäM©ìÌò¢èi+)']¹G‹A_g¹|ÊÆ)ƸÂB™;ÊÉ5Ÿxue®ÈcЮâDŒ;AäÂø�o”m¸6“&�߇]\¶¼'h§qø�÷„×ë„�Ó6è'å¶®Òú¢Kä#õ‘¦¦ é¶ t­GÛFï4n½L’†¾í™çG¿åÈÕÇeLåvúzšfšÛ-ev®JÃÆ—O·h¨«¥E";b�§ô_°ˆ½IAãñ“!®ÞS&>í¥“xy‹—=ü†Xw´Ó†æËI? ¹eZ¦}„¶þØÂ㫳ɖ‰Äð@›wO\Ú<&Áǯ\ƒóîIœþL"My»V^Ó±ã bDׇ½OË%ç–*÷ÅÑüd #¥àøÑ§EútŸ6dÊ4(½æ´‹¨˜±ÿD®4Œ5JÔºJùû=?ðTÂ[kZž;¬Ÿé®3”�3>Ħef,Vån!;¡Äúk|ðï¼ôFn’…ܘ;¿ºŸLüR¯|ê{:†#üö­ŽëŸ.Ró)Æ´ÝêÃaßJÆjo½Ž/G÷Lp¸Äå­ ŸŽ:àJ¨Ñôt,hÚÁ×Õõ¾Dá|çŒI”u\y$F'»"é×Í×£ƒë�–‰�ìj)a¼5Eκ�»†kVŸ¤‘ñ3ª$åõʯͻç&Ó<&·n^FÃ%«çÓ0¦cZ˜þØFdÆËßL`_#À_i*Ñíuÿv¶sœ_ݘT¬F_>Öº‰L¤ àȨ¸CvßÛK³ÏõîN4ШÅùtáÍu_MG© ƒ¢o>D¾³µ›«,Ñm(ŠëÂIŸ� ] ŽŸâãCÄ=�_½›ßspÑÏ^$õóÈgðµ™l“ˆá[ÜìcðÕ蜧qè<‹QC±™·?+vhŒÏ^ø±mdÖ÷_¦òô¥Á­¯‘‚ ²m˜[¬yöÛ|n½t¯zŽ´ÏÝq?©O©ôs4ví1¾½’듲 «D“3Yr÷€o­¶'P¸ÐßÒ í¾8¶˜iÅKË’ÖCŸó”³ž…VZýÉ v•B]Púzš'"-S§.Ð<‡ÓHÔÚCÊ-\ŸDêV˜¼h¥ '3Á×N·ͲÇÓœ2<ÛI<‰×/y¿"gÀ"/Y¼Š([Èâ¢}%y“±¸NÈíí±<§¤Ö–*ÉoR�ý—™¬:!â ¾|· 2ôr¯­x…xÇ*^&ävŽ6�Ù�-"ÆP]âÕâYÎ5¿í½ÆIϧÑàË/Íê²¹Ž\ª–ÌçZbÀ6K¼ŠFq®Q×åŽ2k;Jj|ŠÇ×mUòoÝC¼¢©i¥Áà˯,w/רm$æýlÛž$FDÚ‡ùôJÿˆuØò²§´³pc¯¬³´£ã52°� â븺õŸíõ�öÑ4N;|_ޝ4mg|°6ÔÝúLޔʎôg>õE˂ֳ´�•î<4l�Ñê¸N¹%: ,¼}»a™«ãWøv•Hby=Ìøf\iy§¢óûÔ±„ù¤éÓ8”ºvÌ%åMãL(Œ{C_öoÞ~Úޥ͸ qFÕÞÞ.:;;É_;žsço™ÈšËÕÇe¬íß”4ÓÛnéXv®JÃêÆD·f¢VÝÚ$ªË‹ÝµBÔ'²ò+¬yuM±ÛÇ&û (™¾µ‰èÚ‰äAó?šzœ Œ–�R–éï#´õ‡ÊLŽƒÊ„Üft¨æ]ï‹J+«_ßJ¤ð+Wm|$œïa†ÊDeä5©ir×Hpü¯Å—´Ý‡Æ9Ú-ö|ó‡ôi%sL™…£×ôí’ÈEtó±&ˆ ^£åŸìº# ã«sbÔÚµ’?Ÿ±ž†£:¿ßy™Ãtð¡ÞÆíy¸üÖ­MÉH<%v~u90ÅØÅÄÜÓÁP‘$ÁáË�öƒ} ãú¦+…§i“úIÄi·´ïñ›CÑ—,i}WXj~P™âÃ%.o]ø´×"7MOÇ�² ¾®>+JN ßÂ{Í�”i2eǵëG¸õhµõÊ©e’RßcVŸÆaÛ²kR¥´‡jÞ}ô¯šbgÝÒe—8�¦ó2=?ím1A¬…iFŸd{'6øJK¹í5ÏÙÛ9>,ÞÛ¸;©X� ¾è ŸT*Ñ›)(èŒSä;ƒÜüñItŠöNïC¢NÑÚÒêkLQYq¤’ºè ¥d±I2ÄA?înp¬™D6”»†4Vðûtââ¤WúÄlÈàIÒô[<õKÛ9/ ¾Ð¨êí».p¸À´ÅG[Û´FZ®ÁÖ&ñòí$ÌÅê6ŠŠ¡Ô]/kã¢÷Ø[:Òs¾ë�9é*Æi—‰E›m9ÅcÇŒÖlÙ ®Ó-Måé/ƒ¯b{ §@ñ€ºiǺ[ã®wË‹¡Û�Zw¬m?éx€²Ý)J°Ý7Ã!@Ÿʻ†j¯+Å7†sDnn.n÷ZoMN³íþ ³|1Ô‹Ov15ªðkŸ2 y¿Fâ%½˜@Ø“”çÙF~èÈcbߥû6ísRéçtr¨çÈè%Ñ1Ö¥‹g­ÕÎbAI‘sœ”%ŸI�¾.«’é…mWæuAéëíz©SRÓ<ÑÇý¤ÜÂõI¤½„ÉKœÞàëˆ@ò„[ÊU×U8Þé ¯\ó»ëÃF©CØ œ¨bÕ…®Þ’_éÙ ãÈuú«QR˜Ë#¢Ru|ê�Vó›Ê®.‰tȪK }š©a’¯W(רË2T"žº”ßhLt…Ãã1¯ÐÞÎñBQ¶Q�C5¬ªŠ7†’il©çÛñe¹¨w«p¾\#³Ù¥Ë4iRïW T#¬¨üÕeW;úÚÜÇq¶s<éÎÕø�ëE¶ì¸Õã: ³7s㺨˜Ä|m'iÂÕâÍÝ*sYVõ‹päSƒ/Ÿñ\Ñì-S{e•¥ý]4U•«5µOÑí\³\�{´�¦qÚ‘ôåøJÓvÆ;aCÝ­ïäÍ@_Þ‡ce*uF©Û>ã¥SŒq}»a™§¢ÓƉçw"Äøf\QL‹ÎºLb™öÑGSsIyÊ•J]¥}Œ®SôX²–a\†~õ‡œÏD~HòúÔôªÄeLËÁíëSéSõٰϦ2Wõg;Û[Ek»wµ,–"¾`±uœœRìÉ„ å)ЭÁµ‹²¼‘�sþ\Ü2nÛgœ÷ëiU¸z¸Z§ÃÎÿ¤ìáÃhùd¤þ ô!Ë$VZÆ_4ï~ÛÓ{rKë¢iѾ5d¹êÛNYÈP™Ðü«õ3*s}Y®£wç—”8Û9fT&‘)õ}Z¦ý‘·îWPYÐkº|÷ûXc²î˜¡:CÙ¹ãC´R‹»ëénù¢¾•®wH�­êêj�,º:áœK‰�ÿüΉß÷ q}O�aø1—a븾éJv´&º( ¦Ý*:†ÝÏ+eD_²2_÷¶¥!ù IÓ<ÙáS«4öøcšžŽ¡¾Ÿvãq¯«ë}îy×C® �Z‰ÞEY$QÖ6'¾$Âèò¦”™C¨²«}Œ•fÀ32ÊÓ+'�ב'¥¾'qÿ¡•'•¶ìÃÚ) ŸšwýË}ÑÂÑ¿’X[ ú:Ý}KE³ŽFÃ%«ç§ÖÃ÷Ç&z¾’oþÁöAlð•–Bío–Ú_¥b�f¬Ó%3° ¾„ 8ýŒ¦*bÛÖEr …œ7Ô•æ9“Ù"ûuQOf©¢h¿@2g§ƒ.&éÜ]Sã1jð¥<àA%Dûе©"æ$" ¥‘IìCwWûªü& QpÔóz5‹s3øê]ÿ‚˜i/šÉïÏß(–®ß¤5Ôêíh/Üõ5‡µ|[çÁ…ª/j(@ ³l­åâÖi1- ?¿.š w¿'ÎÞŽfñÂMÄÈ Ã¹^ÅúÞà+Œ<ýeð_Ï;E…³µ]”o‰µšiÞ>œºâs�°ýÐɉƒÖuW±¦õ;d»óQdé"­N™¬t¶¿‘[†m‘>ìC#ï¯4ôt˜e[ÁEf·›¥òÇ·C“~M"£¬€<4vpbBery:wøиCõ9TÙÏù C.Pϲ�‘êDƒnÝe÷%QA�\|ê„ß„¾.¡4‡¦ãŽi]Púúþj[š|ÓS*7o‹ñï“ÌóBS×÷?_WêmÏ®»ò»HcÑEõ×Õ·—ì�rbõ_­êô g{ÓØ}–‡1¥_"ñ÷_é�Õ›|œ‡¯T ¾Ð èùy®Q•ä~’ä2ç‰xƒ§�/F¯YÜÜí©Ýö‘T™|Ñp@ Èì4—¾r·¢[é ¾š·WE ¹ì7,cå>o¥Çƒ5¾Â­2ë=_�ëžu�Ùâ|áv�óœíAÜ¢l1)�¿ÐCYÄî¯å·á–Ž(¯ÎøYi{¹®�¥yð@€zó“ÆõÞ®+;í郵„ãnޝ4mÕ`]¶NÒ„_úP^ó²3Ì e€õ,ÔüO" ú¤Pgüô– äÜk„EÜËäZ˜2ÇÈÍËÆ•,ÑQÒã›iL—ÎïÃ.Qþ‚ÊÕ|ÌM\¦ åJ¡®Ò>fÀÌ+2‘Ÿ„�…èË2¦å@ç…}Õnizaçªt¬´ê >˜Ë³u¿¶åyøe ÁXΩÏXš)Zìõ7yOž°vB§ñHCq¯}Æé…b¼v�6™ÿ™„‘Õ(ŽO¬nõký1-)kg‹¨­©5øWߤQ–bùÑ}ѼƒÔµÜE—ØíhÄh×,Ÿ²†X–«Œ”Öåx=I'¥{®_Ë$–,ed×OW"Öq}Ó•¼|Öai˜0í–†ÓéM•îVµ²£z�R|š4î¸ö@û}D o÷o}ØÏÐôt õý´›q÷:éñ²{×Y4FuU…®qPI”u×$Âèò¦¬U�ç¡Tö0ÏÈ$ÊÓ+§¯ë=À¼ïIÜ(òØõ)•¶ìÃÚ­ú#šw@ý8ÞׄGÿrŒyçÝx»»b„YG3Ñó Û¢IlƦßR_kéÉ5µõäù¢}•¿™ÀÞM€ ¾ÒQ~»Åü‡c_O¼.¶'ç@3ø¢ÛI…-§°\4´¢G,tCÝÚT'J l/rÁ&_ȹ}g]Il�GžËÅ5¢ ÃHÿí­¸ÐPQD•ˆãMƒdT©h(w ȲDqe�h•qµÔ‹rÇ‹†»¨ä>ìAï4y®·¹8Q^Ó ÚQöîÎVQWUJà‚ ièàNeq‹‘ žDÁ‘ŠO1yÈVPV#Zš/ªØ_èå«ñù; ¿h¾®¹ý>ñÂK¯‹j‹¾,æݦ,zɲ™SïÁ‹nÉ{àó·‰·ëÖŠ››ÅŽõËÅ“?&†[Óîb[7~ðÐe® $̆ڗÅý?°·r´™ƒ¸á±·bFi}cðe*O_|Õ•�º)Õ ­Vo©¯E¹´ÞE9å•F=P™¶·îé�ôí‡ÔS: QкN'dÆíÎG‘Uß2C£®â «/iµÚ±ûÆ£ãaGyûö•V[í¾³½EÔ”Ó>Ä®‡y¢Öyû8¸šôkQd Än]‘[,êšd¹·‹úšr¥?Ie‚®Ï1ïçH5ð?Tó(k¯ÁL5�tÊ~&«PP{/¿…¿óúºì/¢¼bÚ®ÌëBÚV0aÚ')ö�ýD‘”­ “Õ!¢qšóud¢r«^Êú{°äÜ=èn oÁÆú܆Hê--õU"?b÷3øM Xh4ª·ÑèýUJK ·'è¿Ò «7ñ¾0ø’†L–Þ!ÙÇþny£Qõ~e?ÑíñÞÈÍâùu�bÝέbÝöFñ|éÍNxÏ#ë:œ8¨áV_Í{V’í Ñmνâ¥ÕkŪ�«ÅOz2M­ÁמñÔ ÓÙ ën±ÂcÐÕ¼s‘ãýKÆ5·´J¬Šåí¥÷c7›Ó\ñêv;�ÄpËÇ�2 r.ZànI 0]ܵ Z,ÝØ,­|QÜBôT°<™|É<”áøk/ Õ%DÇÇk¤ ˜÷·êâ§:FÒmqdýÉG}¬Åj»R_¨.u½ýJY�‡�بþ£Æi·�¾_iÚ€:dMC“h¨«­Ö3RÓþ¯ïä5/;Ó¼àã*ãùŸ]~~ßæuÆOoñKI=Ô·›s2/Uº _É�o†u0E�¿ÄîÓ|t˜ ¼Y×|æ.òš¹~�¸LÊ%=çÚcCºû7"Ÿ²–aX†‰3#if ?‰ëË2¦}=�g÷]»5Ÿ«ÆÏ¿hÁ~òKDM}zöGý=ä·4Ô(kî A�¢ŒÖ۬ѺտõÇ´LPç©)rtÖ¬B›{âöáͻԥ¤Þb¯}u¶6ˆÒ¼ˆ·º`V®2MÚvâõ¤`¹û·L¢²øÕWRoߊ½k&îÍ�Gú´HÝð )SÚ&†i8oYÐkz]šÈÕOcMèuGÌc&ê eçå*ÇKÓgUÄ+9}ÑŃÉóê™%X–àbÎο_ NQ^%õʧ¾›24#|¶×*cXØuíD:®oºrNé£ßÒ0áÚm½ºžSdé­- ¢Ê3ç–cEºú™dÊ›æÉM×¼%ªƒ4=C}?íÆê^W ¾ÚÉö|òEÓ’êzKï’Ï?˼Ï?é´I”u\?“D]Þ”ò ýºùztð8ã²r þ%Ió¾'qÿAËשO©ÌW}X»5BDóné_ÙTÿª%TÿBC^wŠÄy´Æª¯'½Žf¢ç›µE“þØ$L”~»(ræ(h«îÝ}òY&0€°ÁW: £s�(µ ¾JßLÚ24ŒÁ—ó–*¸®�sòÂÓL?ˆGãª//p'ðr‚ïóWRkKÑ)ʉ·¿ûåùœâG`:�©ò4‰Âˆºjüø!í”;ëEA2asJ†‰ÙÐÅ 5Mê½Ì‘-«H‰ßÉ´}@ ¾ä¶‰�¯ýIy`æÄãÃþÖ'mƒ+ÛsWô{i‘ê,(žÇ®u=‰mx=ΠL û}±à™xôǯR¶tÜ3 s¶‚¤ñâ–ŽA×é–Ž½4œ–�^ž’•ÛlÂ¾ßÆeí5&ˆ“+W”—«o¸H†%èEͤ}øf vAß~T%Ïn¡4.šG‘µn0lw”‹§oª-¥†]ú6�_á¾kF÷Wë_4lnq¹(²òØücÛI$j‡áûµ(5ï[K:¹ìs*OJ=þ˜–ƒÚÿÙ÷ú÷9°Ÿ³cþv=xY‹pB§ô±¸µ:Vϳ¢†Žqùö«>çiÙéYè$6wdLfu!mK—mzŽò´Ûƒòí×'5 º�®Ÿ è�ûŸ¯->XÌ‹ÖɬØÄÍ}°dßã~'Ó?AV>–ºaÔ#R',îjß_´ Øý ="uYÕ¤mƒ/gëA4.Zå5\ ý›+Y<ô[ Z^µ¶/r·€Tê¬:N\S¦n¿H��ü ¾ �1b–x~»»µáŠ7T/^çXú³s]eÔ�Êö&¿iú2ü¥+c4zßKÅn\Þt¬pÅÏŠ»9cyFohõÔS—O™PT9½^¼T–¹\\ä,hDÙlí=~ì~Æ ë‰—–_Žª[˸Íúù@À}›5n\À…tgKUš¾ç8¯¬NÉ^âqoï«ñýœy‘³Ðò@Hú�eg€Ê®Œ¹}%¯qÙ¥�\²4žÿÙ ü¾ ëŒê}6üü›Öc§/°úöT8™·+?<ñç‰|V} ß ë ¹ÎOdói/ñùñœ±û5™7Mfcnä’bÖUÚGÄõ™Vö34¯ÈD~<Å­ûÙWeLËAé«QÓñP'?=g:WÕ­%tÖ—'¹&åñ°™L9£·lË»WLø† Õ@Ûé#ÉiŸ+tŒÉMæ&a‚ ú³þ˜–IP]¤õGw¬»4å"˧$æMȎǬ\1t ždÇîÿýÿÙ»ø¨Êsà?–°¯ #¡@5Ѝ h�,j±šÒ+¤Õh­@[ESþx ‹Ò’*7¢ˆ x¬¯€WäŠTQŒ"´,$Õ„€–Èÿ9Ûœ÷ÌœÙNCÂo>˜™³¼Ë÷=[ò>yßÓÙ&Z)T#÷knP‡¶X�ɳg˜_“Ð5n窣Þå>¦¥âùˆÐjšîõN̽&–öWï¨ùIJOèï¢ßëU#Ç} ‚«V/?ƒ”9‚Eî-QžwÔÚ§Ö˜œ­,z�ÂÿçÍ.¶óÆ=×èîú~žžI½Ý#"]³jô7RÛ…y¾U�ÉxÏ[çHq¡¿¸}Œý3»ãxwoH{i¤zøÅõûJOÇ€]¬pŸ¢F»'Ø×ñà߯«Ó~‡úZÏAúû@å­Ã´u¤ã2ÜϵÑê¦Ýoì�.”ò«ep}F÷ûhùk„ö·­œ_ZÛx»öD¿~¨êqìù\VmÂܣݎ5µî޶wñµFs4Ò‰^G}»Xž×%¯àߣÅôóiÐs¾—{šúO½ì£i„9® PþO�Z/À€¯SÑ„ÇJª^¯Ñ€/¥sãöyrYŠÿuh£=—5­b¸TíXY•�:j‘vÃ8æ1ù ¯à‘¿ª¬*=L‡P¯�cªæ­tþ€»E ™Ü£z|WU^¶ýà¸Ñõº½j‘üÅàÊG­u2?}HÕ¡ª•ó²ÝYÕK¦r”‘ƒ‚KÝæHU^ :hXÍ#[ª î¸K�ÒF'NØÁVV�ÔžMUoÏ–‘¼® ó�wqjÕ}SŸ¯ú׿w‡îk¦±í•ß™zUnßTµp‚2rWà!£jÉçJ°—¹oå–7«îsÉ{À��T­û·PVXõâ�Êa’Þ³k%àë×fyýLÕ«.Ö{éZ{T�_?ï²þãÀúô§>pÔËKyžÛ}l½ê´õ‘oVVÝ?0´}´sb½þ³sYÕ¼1A’ƹÿùîÜ´–»Ÿ?ò�w»Y¾ÛÝ�Á#[òå»}ž1 ™•¦ Ïÿy'Ç ãÕ ¾ ¤'v¬œWu»‹äš°È@S6—s÷9u„?ËZÎ[=O{•­wŽ&ë\‹á<Œÿºfmïš<׎ÚÛ•wØÓ:Þ¯MMã«:Ç¡‘Eü×¹‹Vµþ9e4;ù+¢�°ËÌ) ÌkJÈý$Ü1f¹û±Ki½ŸWñ 8·b ðvM’€¯ê\'b(×i÷5ËT¦ü5»6Bè›Ö#aÊü�œÛcÜ®O²ïýÏ­ =öƒÒQ§@µG:Ú(–¯1\¿ª[Vµ‡ªüUÚHTw˜ç02Ÿ™zP `Šõóæ÷Ü_~òØj×`¨@Z‡·W=ûÈ]�íÏyR¦‹Ò'V-(زÿŽ Ï¶lCiÈúÝ'÷W=xV»«êýÃvÀ—–ï¿Ö¼TuÇ@s”.óyõ¢ô{«žß°»êßÛ_ ¤}Ë‹Î@³@™OV=xÎí_µä{gúöv¥U‹žSGܲîeý«þ$£ciÛm]÷¼s´¯t­ $h.ÓÜ6L›ü»@-ç:§Á±BÝTŸNÓj[íëîÇK@ŸØXið‰)àë¸ý—½ÚôÌ߬_äú¬¯�r¯0ºø¯òì°È~ùAK÷ˆŒ0ñ¨{Py¯ôìªå[BKý¾kX~Jˆ÷çkÏHïn�ýÆý³š÷—*¯V—øÛ®šuñò ]]çᘩ:¾ÅþËöÛÝŸ«Õ,B>‡½¶WÓI2Š¿mBJqA|÷7/çŒ×gþèv+¦­Œ¡]ã¿çž‚rY÷p¬F¿¾Eø]†ž¯—6´ å=!õ‰R&Y]mñçlɳ¦Î[/?«†ûùëÈ®5U�)¸êó™öl=æÑyU;‚™¦q’‘²•Ÿ!Ï!èòØ¢ª]!¿³;^µÞe„-¿l)ýÐ7vðYö›öˆi�AñþÞÑË>á|´ªj¯ÓyüxiõXT;/�ÒGþß~»½jµÌ^°Èµ]e6—g-m oíêò{†E?�míø0йK™jo`ÕêÐGÓµ±W¹çýž£!¿÷³“wýî™õL¾×Ä÷{G£Ú§ó˜Ñr çj7B<÷b9”~ˆçô?"±S²>9v”Àƒèe±Rp�ß.†Ÿïܳ’¥Ñ�w{×x ­½¼ÜW"µgÍ>ã†m»0¿o­îy»Kÿ�™Ù?hþ.¤WúýÒ7'³_ìPûœleé†{[�Ú;òõÍË1®”ÆrÕÐíwŽëô–Ї${}PÀ¼$|ïéµ~_¤¼ËLëËʪ–g4~O%Œèÿ ÓÖZiú†ÙG­›û=7üÏÞ~mø„+§m%AåÁ}ÅR¿ø¯=ѯá�'�çrk­}"½Ô€¯çV¯¯Zä˜eË<6¤_­×¹ÓY±øòòz^y;â+›ºuMœ[ZúÕ¹&©å;ÕŸO·¯×òû*ÊQvP®OÚ�R®6ç$Ëùí¼õ¹$íÇÒ¬+ð‹'7éëdê8 ÿaÔ�\Ò±ÅvýòVV+ã݇“Ø_uܹ°Úßüx'ëjŒzj³ž’Lň¡±xø}8P^ŽŠ#úCŠÜSÛâñ<ëy(·ßgÜ?NH–�Í™=� LÒS“`2ü¦Wè3—ÿÛ·0ø‚áØ¢m5f1Šf º7Fîe»öúТeCynjˆs]îe•潬¹ã^”NÜ_ý8*UlÐPX3˸Ï\ßù@K;–Ü�óê5D34ˆ;um‡Š}òó�ÙfMå~ؾmôc¿F®rü”——áPàø9'¾Ÿ"Õ¾&î¯rL”û凪ãÇåg†–Q¦ŠT¼�u5Q^3“i»� Ø jê^©çP“ÇŒ]åSl×ve‡¸>ÖLÛx¼¿y9=?óÇÅäyãSqÏõœùi?V¥¤^Ú0Ö &¢>1”-m\3çí)þYUÚ«âÐ!<¢=k¿Kk*¿ãjý÷?r íÛkÿ.ðœí#ï#ùìÛ[øÝaÔí•6õòóŸ—}”,C>žÖã'Î6©ø|&Zö¹ŸZ�Uã¯){\ ´ß)–ÉïVõÇõ¦8ÿ‡Ò®‘ðÚ®§à9é´¶Iÿ·KqE—_@ÿIqÌ›8>'=òÏ ÒJȪSÐaË]ƒ÷š¸~ïhð´3±¸Ö �£Mb)‹c‡Ð/§Õ.4ûðK<Æ}�ˆd(ë¼ý^;|µk"åØèÔ~°~‡¢Ýš˜¿C)ÿèqœÓÿ?õŒ$Xã\~‡±5Y�Ç@ÄòÖàJŸô™”ÅÚg­5éê’·çßGW£œ§õÚ#嬱sYñÜ4û\ú»Wô%2�9Æ_!¿“”ç¯}eæsµüþ(´LI ž�òœæé÷hr^Åõœ¯•Éã¹÷õX²ò²O™,§U  îh‰L£ß2J F�A?7œV fF ÔNÿ·˜Ÿ3k¶­Ášƒ¿ÄÊ7ÇÃùæßÑ£ÍëœL)*Á¿C©�Ug©)�gÀϧD´ó¤@]`ÀW[’_ ÄOtÖU'qòÈ!äË}”¯D¯Vå_¯>êK¤;ê±ã²Vµ K P Ö øQòùBdöÉÄfÙ=ý5c‚ë}'p Jþ<³Ú/?¾ûüuü¾ïH|b¦n„¬jgå9�"<\¿ž7÷¿åÉ¥xdÌõ8Wþ2ÕïÛ‡�æ>€ÛîÕ\{/Ö›Ž ”«ü»ñ�i#q÷ßVÛœimRª]K'¢ï°§Í:ÜŠ�㺠Ûë# |¿uþœ’Ž×͵w/*ÀŒáò;G÷2“á(PçêÆý­Î5 +D P Nÿ× �Ô=SöJÇúCoB$‚¯Ó#à¯(Á’i™‘ó�‘a-ûàӣÄ\(@�3_à[dÕë‚'Í‚ÞþÔr<1æF´7‡òÞÜ?"í>3Ú ÷cÇñø‘ò;”3¿~,!Î,|�YíÁÒP 6 0à+�­Ç€¯⟠YË|B'�V2è«:m!A^õezIÔ÷6-Qu²æ¾ (p¶8ÿRÛªu¯GWâóÉ××®):ÌÂ’€¯J üòörŽxe¥qÑ#ÿÀŠÉÏ8�ïÞŸ†Ën|Ô*¦þ~Q¯K°e“1¥µâ�÷ ‘uýyúWǨeÖè�ÅocPò™öÛÌÝx¦wWüEŸ7Æ*ì%¸›�)(­E½ÆÖ “ñc™Î‘/ P€†@Ý»¿±e)@ œÕò [·ïZwÂ…?äˆ+§ãXpŒŽÈp –ïz?;ã~n�(@ „(y*οáaÇú^½zaÓ&Ç/8’¤Cˆ_(àM€_Þܸ(*À€¯P“Ó¶„_§�úÌÍHFúª:~T¦w<.�_§r‚¥3·Ê§¤dÚ<² ’P/© Gö:% L„  ”cæ¥çà>åw[é�¾‰¼Ééµf*G·º“‰+«N@{�o¼Ñrüwïó0Yñ¸é‘ÅxfòÐ3g*Ç  kÓ>4àn¼´\ÿÚëVîí?KÝ6èu;ÍÕߡ¸mÆe @t�ÏgBŸû>Ð7|lM¸šûÑÕ¸(à&À€/7•Ó´Œ_§ º¶d£Oï_—km©Ú©-§LÝÈéO-)S£(@�ˆû¾Þ„¯÷ɨœ�!¹sOü°ýø±áWÆò¥yìÜwX<’p^­ñðcß·ß`Oé$µNÂ�’Ãh–Ü ýȘþС#£#l*؉ÃǤŠmÎC� X+‚ûüûðMqo†¦Çàš¡{Ï´oÁQ½íË/ @@ ®ßßå P€ @Mè?7|�Jýç†dô¬%?7ÔÓ¤Ꚁów(ûK*Ñ<ùGî¿C©kUg}(pš|û¾Æ¿¾Þ'¹5Â�.»B¦O=M3 P Î 0à+�MÊ€¯â3k P€ (@ P€ (@ P€ (@ P€ (@ ÔB|%°Ñð•@|fM P€ (@ P€ (@ P€ (@ P€ (@�Z(À€¯6¾ˆÏ¬)@ P€ (@ P€ (@ P€ (@ P€ (P ð•ÀFcÀWñ™5(@ P€ (@ P€ (@ P€ (@ P€ j¡¾Øh øJ >³¦(@ P€ (@·¼@IDAT P€ (@ P€ (@ P€ @-8c¾þ0ôH-ä«^‘.\¨'�‘‘Q½„¸7(@ P€ (@ P€ (@ P€ (@ P€ (pV<óVS½žÝÞ8®új±J={öDóæÍQ¿~}Ô«’W\)˜[g¿rØËîµzŸE‹éå1bD­® O P€ (@ P€ (@ P€ (@ P€ (@ œ�g—5Ó3bÀ×éñvä€/¿P€ (@ P€ (@ P€ (@ P€ (@ P€Qð¨&W3à«&u™6(@ P€ (@ P€ (@ P€ (@ P€ êž¾ئ øJ >³¦(@ P€ (@ P€ (@ P€ (@ P€ @-`ÀW�_ ÄgÖ (@ P€ (@ P€ (@ P€ (@ P€¨… øJ`£1à+�øÌš (@ P€ (@ P€ (@ P€ (@ P€µP€_ l4|%ŸYS€ (@ P€ (@ P€ (@ P€ (@ P  0à+��Æ€¯â3k P€ (@ P€ (@ P€ (@ P€ (@ ÔB|%°Ñð•@|fM P€ (@ P€ (@ P€ (@ P€ (@�Z(À€¯6¾ˆÏ¬)@ P€ (@ P€ (@ P€ (@ P€ (P ð•ÀFcÀWñ™5(@ P€ (@ P€ (@ P€ (@ P€ j¡¾Øh øJ >³¦(@ P€ (@ P€ (@ P€ (@ P€ @-`ÀW�_ ÄgÖ (@ P€ (@ P€ (@ P€ (@ P€¨… øJ`£1à+�øÌš (@ P€ (@ P€ (@ P€ (@ P€µP€_ l4|%ŸYS€ (@ P€ (@ P€ (@ P€ (@ P  0à+��Æ€¯â3k P€ (@ P€ (@ P€ (@ P€ (@ ÔB|%°Ñð•@|fM P€ (@ P€ (@ P€ (@ P€ (@�Z(À€¯6¾ˆÏ¬)@ P€ (@ P€ (@ P€ (@ P€ (P ð•ÀFcÀWñ™5(@ P€ (@ P€ (@ P€ (@ P€ j¡¾Øh øJ >³¦(@ P€ (@ P€ (@ P€ (@ P€ @-`ÀW�_ ÄgÖ ꈀßweÛÿ¥ÿ+—÷#¥»ëHͪ_�†ÍZ¢m÷KqN÷Þ8÷Â>hÒ¶Cõe  (@ P€ (@ P€ (@ P€ ,À€¯6¾ˆÏ¬)@ Ô�Ã¥%ø$ç·¨Ü[Œf­Û¢Õ¹íѸy‹:P³SSÿ±c8TVŠŠï÷õêáÊ{sѱϠS“8S¡(@ P€ (@ P€ (@ P€ (� |%^Ë–_ ÄgÖ ê€Àçsþ„Ýkÿ�ënû-:v¿¨Ô¨fªpäÐ|0ÿ®¬DÚséÁ_5“S¥(@ P€ (@ P€ (@ P€ (Pó øªyã°90à+, WP€ @ Ÿüm ª~‡ŸŽù£ckù7xý›ðuÅ~ñƒï ФU t<¯ºt¹ý®è†ö »Ôù/«ßņoâçóÖ¡~Rã:__V� (@ P€ (@ P€ (@ P€¨» øJ`Û2à+�øÌš @ðU±õ-´»í…5ì‚§_zw÷ja›ºµŠ_u«=Y P€ (@ P€ (@ P€ (@ œÍ øJ`ë3à+�øÌš @ðµã´Ë˜-5삉“þ=�ÄAGÁ??Ä ~¨ù«o¾†_vnø^—?0à«.·.ëF P€ (@ P€ (@ P€ (@�³K€_ lo|%ŸYS€¨Ñ¾`Ýg÷ãeúƯÞ{½x]¯}ÿ‰¹Xqk7[âDvîEé?’š6C»Ömp^ûhho¡òŸ8¿¿š4n ÓEîÃ7{�"©E3$·?M¬¼ŽVà+IëÀqHZ�Ðî\I«mhZZ‚åeØõý~84kÙ çŸ×m]g]<ßÑhظ‘^&ÿÁ2|]"ûIÚ~tîˆVþAefÀW¿R€ (@ P€ (@ P€ (@ P€µV€_ l:|%ŸYS€¨Ñ¾®Âšül\ÞL­lžs&¬†JÀ×b3àë«OÞBæ=/`³º©ö¹ï-XóØ­¸¼­IåÃócnޏK3“�žõ÷À¹ ^Æ.l��¾�ey`\…ÅoNÀPkT±ÃÅxbÚaÒÛö¨cÖ¶§<†?§÷t›U˜#—M›ó$®Øñ6~6}…µ¹ù~‰¤ÿ�¤ß$h9À€¯. (@ P€ (@ P€ (@ P€ j©¾Øp øJ >³¦(P¼|ÀcFa’ðõÕòçÐû!+xª n½íR4۵ўþ±û](Z8íu3^κw x VçOÅU�¿Áè+ïÇ«újIëI«´PÒ2BÉ–®\ŒÁZð؉=˜|åï0ÝJ¦ïÜÛXµàÃ@ÐÙЉ�I@š,4_VÀ—õ]{ï?`°ëC¬Þa.í{vÏжêFò™_A üJ P€ (@ P€ (@ P€ (@ ÔZ|%°éð•@|fM P DøŠ<¥ãÐIObñÍ'0:u‚ 5ôw“ðÜ�W¢½9˜WÑgo ÇXc¯ç¾Š;ºk#g©_ƒ±òíѸ¶cÊË+дmkøÍQ¸€K°òƒ©¸¶•í?¼k¿<„ÞWvC Y¤™M|üIL½±‹±áÑ}xæÁ1˜ ”9Óp| ¸ IÃ�[i…õá­§ÿŠáó´ 2·QÍðeàò P€ (@ P€ (@ P€ (@ P .0à+�­È€¯â3k P€u@ zÀWL{|$®h ”—–ãó�—bz`úÄ«°úƒl¤ì}í2f‹†WÉ]×:¦ôÉô�·êÓ?ZÓ5ª_Ï™�IWJâÊË÷ïÕhó3ô%ÿúþspO´°fƒ l'ÓBÊ(a÷jA]·<€Š‡®qL݈òMè{ÃÃúH_w=þž¹±£¾§ð5@¦ª¼ß9UåÁM<ða¬–-Ÿÿ_ N»À9­#Gø àó(@ P€ (@ P€ (@ P€ (PËð•ÀdÀWñ™5(@�: =à+\%¯Â«ÿ›…_JPÔîÏ¢ëXcFt¿ýÛ¨ûlÆj™úQ{¹|=½àUÜ}¡3° ؇‰WŒÁÓÆnúÿ·ÞöÜrÓ5øY¯Žf`W¦eÜ…GeÆ‡ç¼ Acç([k퀰¡seZÇnúú@À×€{Q:ãz}¤°ÀŽGwbô5ÆHevYk9¥£MÁO (@ P€ (@ P€ (@ P€ @-`ÀW�_ ÄgÖ ê€@,_ý\}VÅæMÑõ]зOo î× mÍQ·¾x5×LÿgT�§¼,Á]ÚdŒö”Žn�UZBþ}ÛðøS/ãÑ·µ)•—LÃXø_Cqö`ò•¿ÃtYõð 2JØåÎQÂÔ<\¾úŽCéÜ›ð¥Ðò#(@ P€ (@ P€ (@ P€ (pö0à+�mÍ€¯â3k P€u@ zÀ×UX³&—7_Ù}2ÂWgm„¯¾wa÷Ü¡h~SsMô€/+ ßÁ2lܼ‹æÏÀÓæHa·NyóÒ›á ák’Œðuë¤'1oxk—@Ö”�ýe„¯Á#|1à+È‹_)@ P€ (@ P€ (@ P€ (@�³I€_ lm|%ŸYS€¨±|­ÎÏÆUÍÂW60M"º`ñÛ¹ÚÑú+ì.±|ÙIØû#v%ãå¬[q÷‡²…[ ÙÁ øVËê{gÌÅôíõ¤eeÀ—MËO (@ P€ (@ P€ (@ P€ ÀY'À€¯69¾ˆÏ¬)@ Ô�X¾ÖHÀ×å¾p´¸æ^¼ ytÿ9þ‘›���µ©åu´ÿß|Øþ&L2ƒ®Ôé]§t,/À´WŠ�6âZôêØ µtcÚý÷âQåËš¢±èÃÑ#ëÿ´µzßÃx~äåÆèb²íÝ‹IZ0®‚°Æ€/Í„/ P€ (@ P€ (@ P€ (@ Pàl`ÀW�|%ŸYS€¨§$àKv¾÷"R0‚¯t–¾WahóÃxëÃͦÒ`løìwø±>ø—=Z—[À×WËŸDï‡ôh- ë‚þmZbõ:+àÕ7_Ã/;7’tËðÄ™ÖÑœê2ÂØÐ-•<�»þú4žIëd–ˆðux'†§NÀ[²µ[¹ V¿‹ +ÞÄÏç­Cý¤s\rã P€ (@ P€ (@ P€ (@ P€g¦¾Ø. øJ >³¦(P¢| Àšüû#�ðe:ìüä-Œ»ç}EM÷xúþ_⎟tA}…ðõô‚—q÷…æh`æNû6­ÆOÏÀ«�@.+µKðô ãq÷åÆôŒúÒexíÙ¿cä<3@ÌÚ— wÖXüá'v°—¶*ð5`JgÜ„ œ1-c Ý¡MMù¸LM©•Ù/|ÙüD P€ (@ P€ (@ P€ (@ Ôn|%°ýð•@|fM P „ øò^µ(ßW_Öhâ? ãhßÊ8kھðïà 4iÖ¾Ã'оã9fÀ˜K 2uäîòch"yù*�öíÍ© ]6õºˆ_^å¸(@ P€ (@ P€ (@ P€ (p¦ 0à+�-€¯â3k P€u@àÔ|Õ”0U`ÀW.¦(@ P€ (@ P€ (@ P€ j�¾Ød øJ >³¦(P>�þ;TmÅ�ñBý† ë@�j® ë–¾†íŸåãçó?Gý´ª9i¦L P€ (@ P€ (@ P€ (@ Ô´¾jZ8Bú øŠ€ÃU (U`Ïbí÷¢U»à]{ MÇóѤe«¨û�-ø�Å�½%ø¾ø|W¸\?½GO>[ªÏzR€ (@ P€ (@ P€ (@ P€uT€_ lX|%ŸYS€¨#{7æ£ð½×°oóœ8v´ŽÔêV£^=´íz1ο& Ýg¢^ƒ§0q&E P€ (@ P€ (@ P€ (@ Pàô 0àëô›rdÀW€‚(@ P šU'NàHÙw8~ø`5Sª;»7HjŒ¦çvDƒÆMëN¥X P€ (@ P€ (@ P€ (@ Pà¬`ÀW|%ŸYS€ @� lΛŽG£÷�®±<˜0(@ P€ (@ P€ (@ P€ (@�³U€_ ly|%ŸYS€ @�«Ø�åã®ÓÓþÙ³¢q«sj$&J P€ (@ P€ (@ P€ (@ Pàl`ÀW[ž_ ÄgÖ (pJ*vÿÅŸ,Cñšåè~óHÔo˜„mo>�N?¹�®Š»œÒü˜(@ P€ (@ P€ (@ P€ (@�³U€_ ly|%ŸYS€8KªªN¢ê¤ü;qBÞÍ'üúç“Ú² å'µmdÙÉãGqìÐ~=T†£Ëpì`¹ñù@*v¢I›Hî7ÉWýÍÚ%ëºG¾ß�]Ÿ¾ƒ]kß‘íËÐâ¼ ô¿ɨ_�[�+ÿÚBûܨE4Hj„zõ ^í_Cýs}í³¶ÌZ^¿!Œeõe™¶M} ^½³´%Ym P€ (@ P€ (@ P€ (@ Pàl`ÀW[ž_ ÄgÖ j¹€„UñÝ78øÍW8X¼ÚTŠ'Ž�_þiï�ϾÃ8qÌ'ÿŽêïZÀW=-Hªž4¥S՗Ѹ¡A£Æò¯ êKà•ö®OjŒúÚò$í{#Yç\žÔ¬Zžß ­:÷@R³–E�UÀÁ¢í¨(Ù‰ã‡+pâ¸O"3Êu'­2J`™¶ì¤¬·Ê|òø1½ì'ýÇ$0­ VÐPe”]+sc)[ãfhظ©¼7EÃ&ÍŒwý{3aì‡hÝåB½¬ ›¶ˆXV®¤(@ P€ (@ P€ (@ P€ (p& 0à+�­Ã€¯â3k P€µT |ÇF|»z ö|þš¶;­:õ0GÍj‹Æ-eä¬Ö2bVKù,#gi�OÚÈYZ@W] KµL lÓG"«<¨�(¦�DfŒFf¼Þ· û ô ¯Î©éH¾ú&1¬a-=Xl P€ (@ P€ (@ P€ (@ Pàl`ÀW[ž_ ÄgÖ j¡À¶%s°{ýûèvÓíúÔ‰ÚH\|Å/P¶í ü{åB)ß‹«îJF'ãˆ_ñ+r P€ (@ P€ (@ P€ (@ P Q øJ”¼äË€¯â3k P€µL`ßæO±qþ_0ð¯‹ô‘»jYñÏÈân|iš^®KGN:#ËÇBQ€ (@ P€ (@ P€ (@ P€p`À—›ÊiZÆ€¯ÓÍl(@ Ô�ò¯7¡ê„çô¼¼ÔæÌ¨‚oÿ>|¿eο&íÌ(KA P€ (@ P€ (@ P€ (@ P |Å€TS›0૦d™.(@ P€ (@ P€ (@ P€ (@ P€ ê¦¾Ø® øJ >³¦(Pê×ôu .5]…*Éà¤üwBûÀ(@ P€ (@ P€ (@ P€ (@�Z,À€¯6¾ˆÏ¬)@ Ôb�èÕ´a=hï|Å'P%_>‰ú:v2¾ý¸5(@ P€ (@ P€ (@ P€ (@�3E€_ l |%ŸYS€¨¥Iõ�fìÅWõ´€¯#~÷U=EîM P€ (@ P€ (@ P€ (@ $B€_‰P7ódÀ×)Â÷W¢pÛ|ø8�”„Žçÿ�Ú59E‰×Ždüû‹ñÙ–")l:_Ú�š×ŽrŸ ¥ô•nÇÛKu»®—÷EÇZ}èø°}Ý(ÕN…Ö]Ñ7¥ã™@Ì2œBmúÆIõp*ý|¥Û°nÛ÷ú9Ð튾H®Õç@|؇%àëø>Ò—o�\£ OÍ5êT¦eI×DšVÚ|¯•{ ±£ø{È­IÍ:âÇ)�àõ2âýxâý/ÒÑâÝ5Rª\G P€ (@ P€ (@ P€ @"ðu ôýßãÛo‹±·üŽ;4h€¦M[£Ãù�ðÃäsÑ0LÕ øªÄ†ÕŸê�Zòí.¾½kw¤J¥È‹ý{VcdÊ0,W6K™²ùãû*KêþÇÊ sÐyP¶^Ñ)+vb|ß6u¿Ò§¨†æ¤cPv~ݰ«\‡ô΃¡×&%;óÇ‚GB¤e¿\G×®£ÍÎë�kRÚEÚÁ\çCÁê�±[‹n�WR»£ïNÆ—þ¿©ÌáØ¨Ah&åEÛðÅÆ�X¿©ûË}8"›4mÛ?ìÖ—]Ö ½{†ÀøâÙŸ£ïÆ9ð·U…˜xåÙsÔœ”¾?ŽâuŸà«ÇOk[†¶¢û’Sy�:•iY¥­‰4­´ù~¦ ø±zæH ›âx Ê¢|ôõxîùxâý/âÁâÙ5bª\I P€ (@ P€ (@ P€ @"ðU-ý“(Zÿ!>Ý©�¼æÕ ®¾q:·’9¸‚^Õ øòm_€ä~÷Ø)fÌGÉìtÏ#*Ø �îO•(X·‡“ÎÅ%½»ÆY~–f%cÔKÎ2gÌÊÇìÛRœ ëÈ·Êâl,:ŒŽ=.AWe³Ê‚yèœ:A¯eΪ�Ûûì Ø¨nÓÌ‡Ô ë†]å øÄ€¯X 5@@ßg6–MCÔЭ=ËqNJ¦�Ëi ®k)£{i£|Y¯òm+1õ¾áxê#kI¸÷4<»ì¯; kÈ›^‹Ëî3Î�ù…ÙÙuý¨8^�g¯íŒì¡9�mÒaœÊ@�ðiy¿‡O3L…¸¸Îø £CŸ1Aõ‰ü’Hñ8Ä—çãÉ·ã’A¿’¥å¢(o4<Ɯէv} ÷œèÙµvUŸ¥¥(@ P€ (@ P€ (@ œU øªFs_ðÞÿ²<�B³vÉ2•`+ø+˱«è; ¬i‡ëo„sƒb¾¼|ù±rÒ@Œ˜­õN[¯T,Ù¶ýcœÆÚå x÷KàD=p"UF„X爕˜—Ùô�%R07 †Ç4:ÏPqOEðcù¤Èœ-1 A£˜1à˨¾S� ø‚ÅÛ·á 6¥c«dôètvîÄ}¨æÎ±LªÇŒ¾Ûi .hÝÈŽöúzÙtôüÕ´�j’¦­m\¶›‚ÖøÓb¼ýà ŽàÚ³=à«Ò_�¿ßÚ÷h÷’ÓØ–AMö«6eï¶’ƒ²> É={ M¸aCæ`¯—VuîÅáÒ´s姺* >{¤Œœ‹·¦¯Öñ©9y>žÔëyª|-=¾Â?'zv­«/ëE P€ (@ P€ (@ P€¨ øòÚˆþ=øÇá�¹·«ÓЧs ;µ“ûñé[ï¢ÈŒúj{ñõ¸1å\{½|òð%£ÒdÊ´m˵A¬”˜¯´Ü|ä�ÖÖžWéj X–#ÎÀª’ÙèψþíÈêÐú_i³P’w›#ˆ¡ö(ÄZÒ=˜žš‚ióà¶V;]c X‰5dza;5x‡vgC‹+uT´ÅÚå³öNK ;/PŒ©ç\ŠV2Ú>眾à+à«ü³9h7èA«ÀÅ£°dÎxüô)1äǾ�Ÿaþ´ÿ‡ÿǾY¤?õÞ¸«w`_|�Ù_�†ªÁÕº×`¹˜ô™-°}qú�ÑŸÂ�›_‚Ñ^‡õ:ÕT¯çgmÀWøçÄSAÌ4(@ P€ (@ P€ (@ P€8³ðåµ=Ž|ƒ¥oýÓū典åÏz…)úo}Z¤çÐì‚k1äÊdGn^¾Ô¶ìùóQþø(ƒ}eÉtd“]§#óWîAá7e8Ž¦è–¢M�X‰í6bGÉ>T–Z´EÊ}�iD ÊRl)ÀŽïEÅ1ÙG^-ÚvE¯+/wL/¨¤¯Ûwî äy¢xVú%´ì~�ÒÝZŸÄ¦W&`ÔŒ|}—YËÖâ¡,©}gtj9òkq!ö}€~CŒi �qX¶ön´;îGËä®èØdø¼/Œ‚Fó•nÇ??Ù€¯¿?„Æ�£‘xœßåB\tq×ÐÑ*”zuËæbY°æS~M¥Åz⪫û¢£5—�?6|²Û‹Ëe}#´ít.¿JÖG®b€Qû ×wÏzL<Ƙ®oä,¬%Žû¥={t uJGét›ÒÅŸáó‚]z[5j$õIé…+S:…§vF>ê+|µe;¾«Ðjb”µWÊ%2r]…µ qò¡pÃØ´=Z™üس½eÇåh=§ º ­„å=�v:të·âùdTœÍ¿BÉÞïÄ@êòƒóqaïÐc5zÀ—W?J ·¡`çìý®B?6äÀB§½pU˜éKK ·cï­ÞݤÞ'°aõj|)Ç uÂàaýÑ.È£X8>Š]¡ØIn#|ùåÞ¶QÎá]{%ÍF²gڴ—ö”ãÕ=ñxöñïß##•IºMe$"—sGÖì/ÞŽ‚,©iôèê6$¡WoDl_¬-hK‹‡ÒßÓd´Á¼°£ Vn�éSY×3›àà‚Àñi\o×>—ëOl…5¶2¾ŠñP‹^ø›µã¯Ÿ@Ñ�F²õ=äÝ�÷gü?�¬‡(kSñî¿ÿ×›üjÀ׳kwcìÅ~lýìs|QXŒcǎ‡–¸ì'ѯ›[{™™U”b“ܶ:ï—õ»?r=AK±õkãþÐU®³-P�MŸ¬Åæ�æu´cO\#×Ñd+ŽZ®£_|¼[‹Œëè9�/@Ÿ~²>Ü¥)Žò8FøJÍÁÎ¥c¡Ž�Ï9BX ×E8"wD4 wìë׿öÙ¸¾7TîßnçU<åSŸô´Äµp÷>Ï÷b­”!i:.%æup«\+�ËNRó6HîÖwíá~¤¥îå5Mï×í~òÕ–¯°}—Ÿr{Ôž.èÞ —È=Õí´¯åÆ=ÌWZˆ/6lÂ.ý^`Ü�zõ¹RžuXá*ì²<þû‹‘ˆW» "È5®pw9Ö<Ö÷,4Ö�œµ ãå!Îïo‰®=”¶�óÙ1ìñíºÚm—=¥£yMn í¶³äˆ^ÀsäY!ìs—™¶¶aÓÝbzæ±Û8úý:®gL©ÓË3P´çİ×ÅÕx¦�õYÍhwãïç–š ?S€ (@ P€ (@ P€ (Ÿ¾âó l}òà,yç œ�% ~p9†õqdçj¼µþ;}ŸSðeÿõ¾Œó„ü½y80#Cròõ|¦¬Ø‰ñ}Õ®j£Èó2‘jÌ}ˆÜEyØþçL3HÌXoýŸš5Ÿœîèì–î\lX�ƒA÷Æ´±6¼gLY„Üñ7Hð“ý²óLCÞ’!ÈvO`å…c‡­sž |W?OW¨®3>WbNjgdÛÖ86ÑöŸÛr†Yßм�éïÇò™"sŠÙcéHIû"#j-ycûw ¬±ë%Óhægã©C ³,†¼æ¯/Á`¬@FŸQF�–c‹4,ÚønèäÖUìØP¾DªoЧäã¢o$%ÕBÉY² ˜3ÙVl‡š\Z6¾4�‚ú˜+·/Ç„~™§�–=ÏL >.Ô„C?«NËÖÿ ŸÝ—Š)ÆaêÜ8mŠ”i¼]¦Ê Hï<È0K‘à‹|gð…¶så†9t“­§zÌïÁâ©0f†€Œ%7%OŽÕ´À±)àË«‹¿trî 3–ÑY_ý[òÖæ"­‡rÆø �™œ ­Ô©9yøÍ7™8°bœòT˜Ò“ÝìöcåÌG0bŠ1‹K��–5OM;¤'þ}6ÌIÇ lóZ´J®E½ƒ¯EʱìÒ¶^½ÝêÓ2+à+hã‘ó×cFº}ÎÛ«�ÓéêñaÚÊ €/ûØ�vý±SŽõ“ðµïÃéè8ÄšÊqþU:½¢^JöcfZWd}dä4àOoãý¯Ñ¿Ø_)xdöo±mÜ‘çR t™òe™ÒŠÁ26ñã‹W¦¡ï¸ð÷‡Ì©‹ñl–s¿M/܆ËîÓ�v¼»vÞêw3žrÉsáÆÝ‚wpó¥£ðaÈú4¼½åEÜÔY­|üåQ¾R²—!¢á"á‰Λ�B ÔsSîÝ«JòÜG´T®Z`Þ*™ê¯„;¯â/_ð9z^ \KƒKî¼W¯µ¿§i�÷ûå¾òÈèL¼æ^­=ÃÌ]ñ†÷µ¯:vªîŸ¼¦éýÚí! óóŸAzŠr­SÚ05gr»ç£ßm$ÓÐ×”%1¾§Ð–xº¿Hz^íÜŠ¢ÞƒC×Ï%}›{{v wŽ6Žt¿Žvü„>cÊއg ¤ÏÅF{$…¹ŽØ®©ˆëYÍÄð~n4ù� (@ P€ (@ P€ (@� øòÇ”Ž?ÀOGô ’îX�w¾0¾º]‡!}::ró2—ct™qÆÔcþ‚HN5ƒ©2æ¢döð�'Ô »)H˸ؼË•ÙÔœÒ)Ö7°Yñò©¸4SéÌOIÅÈ+„#{?ÃBeÇ´ÜU2¥¤ÝIæž§‘ìOþø'Ôâ/A�P)^U€þs×bÚð�üC?TbqÖ­ó’3z(EÊ…‚|ôŸ¿·Ÿ+_îáKv§_)æeö„§g“š1Wžl}g¶Ã${I&ö7Úϵ^)i)”/-t2Bª¬—áwëÓ¤­òBÛÊ­¾K'ÝŠQ³ƒê+Ó;”õÇÚ÷¦!y§ðeŒ‘WâÐ×/a¹²«]cKßöÅHî7ÆÞMZ!cÜM8çÈVÌ~I©�o%2Õ�Z¡ìòÑÕIKÛ¥LiÒ›guĪA8i2U^Þè@p–•Iø),+±`\çÀˆ#Úö©i2òÑfDZš’½D‚:úëÉ©åT§tôìâ/ÄÔ}ì)ÿ´2dŒÄ�šÁg/-Tfa• Iª·ó%õΔ`­à©ZõBj"ê¶ÆÂÐÿÃØm_–~i/ðø»xÿ÷öýáÛe�¢ë¯”ûÃÅ©¸»_wþîŸÈ[f\‘¦‘ ¤~qîî<ÿ?Êu'°R>\'ëåúìX?äyT¾f_G½”§Ò_…íïÎÁÌ·¶¢ëàñ/�qÚËË9 ïèúŸ3X0{É6¹§„a(]3=‡L1R0ïñÛæÙÇ“z�òR¾àstd³÷�!×å!yÇz/6ŠœæX-ÐSbÆI«rÕѯýM�ìuÞe:ç|™Î9¦™=¦éýÚâÃÒ¬d˜q@zeSÒF⦠›bë yF0ª¯{Í_ÿÒ»šwGë:¡�–ö)ýº›|(¨þ1^Û­¼<ß_Nm{h¦7Êq£TOwH•ǰü²›ä¹d2š®ªþ³£z¼«Ç™Åa½ëÏ5#e¬W¹‡êÇœuMÞ³©)#Ìr†w¿< v < jÁú�¶´2~�é~ííÊ})ø>i#ô( Ñž�¿ê~qw�áYM ãýܲjÂw P€ (@ P€ (@ P€ ª#À€/Ïz'ñժױ±ÔH ñ.Æõ?IA‹†Æ÷Š=xÿ£/�)Ñ—ß4 Ý[9Ç‹?àËÙù˜»ª£õh‘=˜)Á?Sôž·,Ú–�‚ú‘ƒ;tô‘¼²eÄ&³¼‹'!50œ�ÚY*i÷4Ó²æçcrº\°gÍ<¤¦UÌ�QKfF-±G 0LRFæ`ÞC¿B²äÙ E4iX)�l�ÍN65ÏÅêpÓ6·:÷Ì]£ç ”®žŽžÃ¬Q72°dã“èqË�u &bð=ƈRóÀt™Ûd¡_`902w¦�îkLMUºãzQ:¹�f¾â•ȸt„Ù¹_�}2mc²9Š—#@Jê¬vþéYóñ¢´¯5`áòéè“iÖÕ1eÙ~ÌIïs ¤e/Â܉öHm•…+1¡Ïˆ@}ìc΄Žðì¤sÎ2M•2™�"jû©��êr%/µ¾j‡°£MSÆaÅ’‡ÑלN®´`)îLµF[KA^ÁHëØê¹a§åÝ¥t�WCLë”,ä¿•�ëD“@Ñy÷¤ÀŠELËÍ— Ió| �‘?Íï®Ö&êk€6Ícµsµ“ó,]Î3=¢#ó×þé=ìÑhœ.#±vï ôÐÎ͸÷‘؆0�)vÓ)_޶õîm§íá“â•1k~{èq 6‡Æ›+�þí3i5øuVþF´˜y)FiÑŽºhöˆŠÚ®¡×>3Ao­Uâ¥_uÆ�2�Ÿd옚1jrþmøc›~æHZiødÏôkð5`Â|¼6ùhoÞ¶.yßnue`]é\®Ž¥˜Þ¯4Â|åcüu˜}(ùDQÿÑ,–ºŸÕ¾’…‹ÇÍùî§ÞŬ»ìëèo.¸Ù1ʘš¶¯h%n¾h¸9âWÖI=.—zÈUÝSy´€/ÿÉ@QÌÞÎ�àTÔïŽQ‘FÎÇ^�Ó$67sÞã­ë‘ûyå­|aӪƽØ-Mµ®©Yy2rhšï/ÅÒœ;Ó9gÌ]�ÙÃ� ;Õ+ø³·4½_[ö¯›ƒnƒ�‘$µÑÈ­Ÿ‹ºZº•2úÛ5Q»ÈK½H`Z–»YOÚy:?ÿEÌ|0ómÇôû!ÇŒ–²ÚÙH(òÿ^ï/Þì"—E[«^ërä™tl ‚¹:ÏŽá“¢\WýB¾d„ÔÅnÅ;»Z—JPXO3(Ìñ|¡þ1ܯÏ#Øë3¦#àK=®”â„{ŠôœèvžjIz~V“kêùQ©*?R€ (@ P€ (@ P€ (A€_p¢®òïÃÇo€’£ö–�›5ŽÆQm®GóÕùòëqu÷s­¯�÷¸¾JW#½ç03X([Fwšk̰ÂÅ2Í£{ÑDbæ¦vôȼ4 ÎI„œ##¦É“ŽÉ™÷çbí¡ÍX~(KÇò4’öɈ=ÉÆˆ=Ò!ºBF!êkö‡:F#“<×î�&�$�êË%ø#h_u«°Ÿ•` ­³uçÒÑ�å˜òVF‚š²L¦Ÿ»Æ‚1òtvfÍZ[‚Ûz4‘�KìÀ+·ÑÖÍLÇà)zt�Dƒwê«£¼Äð¥vðE øJ�âÒNΩ@­Ñ¢|Ûet¸~÷Õ•ý¶IûÅ b¿Œ8ÓÍq&%KFÆšlŒŒ¶]̧9^óíãÕØD-“ I° vìµk‘´«ÕÅnå©Zظ>éØMtìZíeí£½o�¶d¶MƬµ2šU× ¥ê¸.Ÿ‰?½²‡–/ÇuÊÈpV9Tg;:G)#Ý͈8Ò�•¢òîfguLk›¥ÍÂÞ¼Û‚‚L€âÕóðê–Æøñ»â'?½íŽÚ#Yż�œÛêuÆn¥|ê9¯tdWÇ[M=îÏŠWZîZ¼”¶RFéɤÊÔ~KSûi‹ÔöÉÒ¯¿ï[×>¥.ږѯ?ÚVÞ^­íÂ_úõŸõ +gUô}Êè`ðU,_rÙsŽðe�üe§çÃK2ªØ�æ¨b3Vbü•²£o¦ß“‹Oäþ°ôà¯P´|¼Œ¦§¾d¿_É~zpš`¦máûrš÷3ƒÁ†<�¯�vL¹vÆÏñ“ÉæuôÎù8:óÊqëÇ;ÿ97?£EÌ(_Ëãðåå¼qÜßTó³ŒÎ4IFÿ›­u¹þW®“ä›#GÙAÆ®ç•Çò¹¦¥ž—îÅniª�@¹ù{1:%G,æÍø?4îzºöþ ®é|ç õó’¦÷k‹ó~2eÙ6yF.£5¥÷4§*–`û‚pƒ;Ÿmu„P«V{VNEÊ#ˆÒí™ÍÚ.øÝëýÅ‹]pÞnßÝÚ^߮ώáÒŒz]U®çjžÛ¨yêѸ]žŸû™ÏÏãò6bZšó騭ÞÎû�<ê…ܯƒž©ãxÆôþ ä þw>_„¿?«Ï$ˆãYÍû¹å.Ê¥ (@ P€ (@ P€ (@ Ä/À€¯øÍ{ìßù1Þ•‘`¾$ãúôkq®Ú»dnoÀWÁõàc4 uê5=¹ýk�Þmˆ 6ë%¸ª«’§Ú�Ü d•Ý4¦N±gmæÝNÛÙ�­å¤N‘i"Ç÷ JÁðe!mþk˜Î=m‡¨y˾úôyzêvÇzpfÅË'Ét–F÷|†ŒÆ4[FcRÓÎ’ÎÁÉA�ƒ¶œS¶ÛÑé¥lâúQÍ7¸ Õu#e´”!£¥¸[«#;dÉc“]¦$Há3H!ÖÑ/¤Î2¹/9ˌЮŒšv °È1ÝW–œ“瀾¯¯…»}hÙ²š¶h�æMÜGøªIµ3×ÙŽªG*–í\Š�D Ü»«]©ŒÂÑ30ŠÛ¸Ü%Ÿñtl®\ BÒó²Oøe;y¥ŽJ�T�zÛ™‡~R¼Òrd´µ±ÉÀÑÍ à)SÍÍL5ç/^Ž—fêiíöc¡0Ù¡P©‹¶�z|º_ûB‹ë’ÖÇ6â—b©¹ÃÛÿ.ÇMÁq(aÛƒ‡Z\„¿éëS°dˇøy熎€¯à©­¤¾^2 =oNÿšþøxã÷½­Ußí`2%0Kö¨�€¯ÖfÀ׃¯mÂ_‡8ƒ,ìý€¿I€ÙD-ÀLymze,.§Ý�é*›¸~´Óµ÷s ø’ÑÂâ?o\³t,\73S‚�ɳ$ t²9U°¶‘#H¹«÷”ÀõÎcùÜÓRÎKñŒ÷^ì–æþu(àÜ.îoŽkš=U²»XòvkûXöÓ¶±÷usörÀ>Þc¸®*uW¾hxÖÐ ªö;˹j»Ü¯¥,^Ÿ1ÕgG=”©÷˜pFÁÇU,®¡�kZ¦j]í?ìð|n)õàG P€ (@ P€ (@ P€ ª'À€¯jø•¬ÿ>ÞyH›m �½Úuî‰ÎZÊÐ%‡PT¸ ¥‡­Ä›áª´4tiQ�)‹1õœKaŽáIËÊeõÔt ›‘¯ �Bíè 7-Ÿú×úÁEþý…x÷íX÷ÙVlÝû5IµËÊÊô¼ Ìy‰‚:ŠR�ŽP«´Ú»³)ÞNæH�bQóV;ÓrQ”:Š”VB75íÜ|™V3Å9þ”jíœâHK1|'§±6üÿj¾Áí£®s+S8kµ¬HÉ@ö/·Ïç,C”!g†59Uì¢^Ë©]­’©i:;ÕVɪHF²r¶Œµ·ó]5°ÒR—ysñ£pÝ»X±j¶~½_— œ/rÀ:eœí¨œqÖ9j£×JÒº9dbNUhmŸš1CúÆÕ×\Ž‹»†bxÙGu³,­üŒwµŽrÞ™£·©ûyóvæó7ÅËj‹B àècpdKäD3rƒÒ ­é@�Êè†��Ñ k-oÇñéz틹„!¶>¹¿iw­9Ý¡sÔ¬��CT`ŽLùûÀt�oàz™÷Õ‚ž•kÚØËôù{û¶-@ó+þ / øÒîËßZ�Oÿ¹ßíÀ�ƒöýaÓ—öýÁžzÑðõìZÉóbgžj™fH™Æ•É^onYŽ·<î_€—sÀ*C¸wábtè3ÆX-#@–È´ŽÆd­êÔsrŒmüi�Œ LõüPÏ+/åsOK9/ƒîãáê¡.wMS‚Ð3%Ým³¶NÅȬ!<àj\Þçâ(A§Ö>Ê»‡4Õ²Åum�2Ê¡!#+rwT #›ÈÝñͼdâi¹`5Z „T<Ã<_¨×ëÚãL<Ò7÷v‘J`­S}ÕcÓZïåÙ1\šª™\gå$ïÊõ<8Pʾ~Ë·ó×cZº1…¨Ïr LÉ”»²L½;n>˜vCŒA‰J»Ý¯Õ²„9´’»=cFª‡¶�örX¬’@ÃÞF@¬º<ø¸ŠÅõLy~4jÉÿ)@ P€ (@ P€ (@ P€ˆ&À€¯hBaÖŸÜ_€×ßÕçÔ’-Z⪛£K+g@W‘„}ª„i¯¶—â– u‹xFørŒÎ ÉedOÁ� Î%Ùÿš2Åî\͘‹’ÙÃÍŽd5ÈÈ9b‚^6ó¿ýk¦ËÔ}9ú7õ¯ü‹WÎÄ¥#¦¨›†ùì R;žÜ:�¢:™#uŠEÍ[íŒ ÖP+çf-íp�jVºöz§—µ>Ü»šopGžº.k»,ár ^ž*Á†KÓv¯U¿{-S¤vµÒwM[mShSîMš~ÔÚÛù®Xvê2çÖá¾).2šÈÌÿècŽn{c¹³•äÄST ǵ«çecØ+p/8•4ää=„»ÒR”Îîø÷QÝ,KgNJ•ò©û9·÷Mñ·I,˯@[¨£%Êu´H®£Í¡ÜÚÆ½.Z¶®Çg,å‰a›Ö�*ešÄÎ�iÕ ªè»ïÇÌ´®ÈúHÛÒ”²ƒ§€ù2]ãeÎÑ´´­Ë?™Žvƒ§iq÷‹2jFOýó·ïÍD×aÖ?GþÏÎOÛNáË-Ïhe²×;ÓõRžp_ŽáἉ¬™kfªL¨ Ù£åÈܹö(�rn¨S«ç‡ó¼Š¿|îi)Dz‡{±{š¢W¼Ù¿ˆ –I—ƒ‡¸ )m"�6èÜ+Þ4Õ²9S ÷ͼ¶4Ø€qɃ`Œ©n[çr{4?ÅS¹Î©[«×ˆÀµGÝ ÜgÏ÷—šiÕ×ylÊTÁŸÃ¥©šç¥s)×óà€/H`WªØ%@Ëqpv ×Jî ʶ‘Ê¢læöŒéùHÒU�‚�+Ï®j£r}PÓSªáã)ºoGÈ�«(@ P€ (@ P€ (@ P€g›¾<¶øžõËðÑÎÃúÞí.þ)¥„v�ãä÷XõúûÒ½«½šáÚô!Hn¬Ñÿ‹=àˇÅã’1&žžG¤`QA>nèhä§v̸v”Éf•æ ó l}k¤ ñR™Æl”‘ˆüŸ’‘�n„îçµFÓ¦MÑT¦Äûâ¹áÈœ¡õ^;˜ÔŽ'÷<•³ }Fú¡C-jÞöU³t3‰–v4k{½ÓKÍ×í³šopGžº.k»,’cZfÉ´jG•8Âàr“ª[îHƒ õåµL±tvªÓaêëhÓ ˜ —³2¤Üª�•–º,>–g%#3W•‚¬Ü�vEw´n%çKRK4<ò†÷3Fq¶£r>„ )|ð‡�=‚–µ™1þµþS¬zë ä¼ä{GÛ&-g…Lkèœz5ž}T7ËÒÊÛxw¯£º_|ÞÎÔãþ¦xÙmáÇòI‘9[ó‹væãÚoæ Ù¼6f-’i\oЦt¯‹V†èÇ~Ü% ì |Ù£t�,Û‚? 0/ô�­Â|(]‰Ë.ŽMúê ü«tzÉðRvðTø€¯ŠÍAëÔõ=­iýEo¢ñE£™õúõ$L¾czž× Íš6“{DC¬ú Ë5îjpZM|y-Oø€/£jñœŒS¡-’iåF­Ž,7N¦ ž¦L¬žnçU<åsOK9–=Ü‹ÝÓ´ü(Þþ/|úþ*¼±,Ëó­åÖ»½í̃>¢µ(ê{ìiªe‹ëÚâw|eå΂Ü×ì˜Ü¯¾i½µ‰Ï0×rõa_{Â'o¬©ÎýÅJ;v;k�H絛zlVçÙ1\šª™šW |Êõ<$àKmÙaþú½Hï*°�àËl ŸS�¸‘_”6ŽX–@‰]Ÿ»=?I²ªQðqåÙÕag?·ªéÅunÅðüh ñ(@ P€ (@ P€ (@ P€‘ðI'º=2z×Gæè]Ý®KGŸŽJ$W`¿ |¼h9Jôïí0ð–Ah¯ ñsÀמ•22Á}Ê ¹ÂÈqýÑ4�‡óCÙæÕX˜¯u®kÁ2½ÐXmz¡à¾dú¬Þ¡“ÝUn˜'_ôí­}Õ�ÔìEX8ñ†À¨aú†òßÊI©¡GØAÚ:µãɵs.L'’•nÔ÷jQó®T¦kr�ÁÌ\M'U<—ЧºÌ­^ªYäõN¯hõUóµÚÇÚG]ç–§£ZéÐW§9Ê]»£{œºž8¯eŠ¥³sÏêéHfŒF¨¯Ú¦Ê–Q¸w·öò좓H•iÙÊ´lÆ„m�ü•‘Fœí¥9�@„jþa {û}ØS¸Ëÿg&̰‚¿¬é ÃQöq³ ä§؃é©)ÈÑ.QJù<{;�ÿ›â¥¶…è9n~>~öÕƒ–£Eªd`UÉlôÖ›4|{E?öã/ªµGëFõ°õ•±¸xœ|Ý(]>m­ "¼«�]ò<*_3F�T—»MŸ¨%©hYS:ªû øÓb¼ý`èýá�ÿ¼7?sz¾¼–'ZÀ—ƒ4Ê9àØ6Ü—ÒÕHí9̸§gÌGÙìÁ˜—™Œ úi¨Œúeîý¼R2ŠR><ùpø@IDAT÷´”cY¹?(©Fü螦û.¾ý{°yÍrÌÈœ‘4%K¦Ò›ëTz¡éFJóËÀT¬2‚S<÷8õ~"Sï•)‚Ã\C ¤>Û(×9uCõ¡^{ÔmB>+×+¹€Æy IM_É.–ú†k{uy¼ÏŽê¾�û»”V5S—j¦ú¸¸—ÊsCOó¹!-w-^JÛ�2ê—öʘ•�Ù·¥’ŠþA9g\ò’H.dvdãq>cz~’B«FÁÇ•gWõxV® »oGonA P€ (@ P€ (@ P€8kð屩Kd„¯�;:_=Wwv Á:‚Ï–¾…ëƒB4ÃÕ2ÂWg%.,Ö€/µSÅ : [lÁ%µ§6ë÷NCWéµS;zìi‡œ©ÌËDªÑã kJGu¿ÜüŒN ^ñÈ´G©æ´Gj0„³ãɵs.L'’³T¾EèÜS;½\óöoǤý0[O>ü#ëf¦cð-ÐÈZ"#±ôïèèPsK[5‹¼>ñ_Å˧âÒÌzýR§,ÃÒñ×蟃ÿóUV¢aóæqtxW£ýÕv•Žö"éhO\3=CôeŠR™êjR‡>f›¦bÙÎ¥¸&hˆ¯Êí‹1fÂ{è𣦸pðxŒ•éíÜÚ˳‹”=S¦3â6f¡DÊtÆ@Ý'-7y£­Næ(ÈÁ�âö]µstBû°¿Ô‡íÚ¸¶ájñ4š€Yk‹p[M<þ}TK×é±ö¯–ië†A?£”òyöv3ˆg™âåìW¦pLIAJA�œ£¦äK`Šñ ß^Q¯?ñ”1h[-àK›þïúN7ãCsÝ}¯}Ž'†t Ú2èë¾ÇðÀ>ê4ŠŽ@©©ïâý,ç(oZJê6Ö”Žê²g×îÆØ‹ƒŽv¹?ü¦ÝµÈÓ‹’�u2¢Øåæ&j™Z«ÔjÚ‘×ÛS:ªûÄSžð_ñŸVù#¿+ÇFbÅÚ¡x´ßã¼—‡½ÓÒç©z^9ï)ñ—Ï=-µ<ñÝ—´zº§)W�Êýri�6Í]B‡$è-]‚ÞôkA`êÔÈjÚÚxÓ,÷|�S®\åv?1JëC¥¯!šËh§öKñT®sözçýÑyíQ· ú\­ûKüvÁ÷Ý Òè_õ½º<ÞgGu_õx�z]U®çj@q ÜòÜ—%Ï}úœiÙ˜ÕïkÜ3E œMÅ’mKÑ_œ-æW”6®Æ3¦#à+žg )»j|\yv 󬞰ûvÌmÄ )@ P€ (@ P€ (@ P€u_€_Ûøû‚UxÿKc²F´ì‰ôŸõ†Ë¥§êß³o|´ÍÈ¡A2nú�kÑJÉ/¦€/µƒJF÷Ê+øiÕŽE%Aý£Ò %ß§,Û†ñ×´stÈB:˜óKfÀ»%�›©—BŸ™Qö›¿¾D¦»iâØ/gUðÈ`>¬œš�3ô.[=÷YkK$XÄèÑW;žÔN;}Cý?µ¬R¦ÙAe²·tý¡s/zÞ€äbMaéÈGFh'#4ãèØ‚ÑÒשf¥m¯�¯c]Í×(äìä‹n­ä+�#é݆�î2rÃ’my¡�ž�æR1%ï)Œ— ©X^jyã*“Ú©-ÇêÚ½3àxL2%PÀ“JM[ s›žpõÔT 3ò‘ó×cFº{À—PãÉEÕCF+’i%ÕNsñrüÇ¥™¦·(J CÉlc”%iE,ÈìŒ{´Š… ˆêîrN”,ž„~cŒÐÆÐsØHQ öÔµR þ÷>£Sš;®s×böðŽ"¯™™‰!SÌ–SëèÕÛL½´°»’Z¡{JW‡¹£Á_¯H�ãÖnÎ ¶ðííØWËûc)oP˜”•�ë»ð%kògü&Û×Þ_ù� Kq Y Tì\‰;.Ž¥Ö‚!ÏàÀk·I(ŽñR¥´QÌÔÀ,c‹b<Ô¯þö¥ñmá–}¸¥sCGXèÈ`>¼óç¸Y‚­×‹ŸïÆÈžFmk:à+žò¸|m÷pÞhç@¬¯=+§"e„l«î“³b'ÆÍohß3ìW¯åsKËqí‘ö�÷^’æ�K0éÆTèªç¹ZQõ:&¨EÝ<è)Íj\[Ô€ïpÑ+åž2Bî)©SðÔ“ã!�Mò m°ê¤^#‚¯=Ö6!ï^ï/^íB º ¤í{QÖÎåñ=;:÷•óÁLS5Sïû�R)×óp÷Ðu2âÛàlëéA3W÷á@jQ>Doc¯Ï˜ZÀW p<Îg Õ(ø9ѳ«z<+#|y~N2e«sŒÒ8\M P€ (@ P€ (@ P€8kð嵩�–`ÙÒ�qØÜ¿q»n¸ªO Úµ�°¯“GQ¾kÖüsôÁ½d›–=¯ÃÏzwtäKÀ—: bé•û˜Y;ç�“Ñ»ŒÐ%½2ºÁŠÇîÆ%í¤wÒ·ÿûø}¸g¶Õ1Ÿ�‚²‰ÐJ»}Á8ô»ÇÜ/UöyÖØ§b÷f¼>ó~d¿dLiUlÜÜ|L®u¡Å„4O\ÌAÅ�=F_u.Éäd];ÆÐq¡sOíôrí”òù‹—¢Ã¥£´¢ê¯¬¹+poÚ%hÒ@¦/Ûýž»o±l#eÔ•ƨ+ÑÒשfåc¯W¯¬•ÞÕ|!m±êÙ;pî‘#hѵ+’¶Étœ©ÆtœîõU:'Õ;øeJÎ�攜ZæÈ[õ'ô¿¸#û+PøÅ{È2Æ zÆåmÄ´´NJi¯RË_™*ez3û¸H7Oý1 çItÊîÍ+ñØàQ�òh¹©ALþBiÓ>£…™»~y5Zø÷bÍ‚™Èœ¢�í!ëíQÝìö°ƒ)äèðæ"ëöˆw2*œvL •cêD¾Zý:þ�)çV tÚ‡qÈ/z)ú8J… ’pìëòÅåœh°}’ûÝcnœ†ÜE ­Ow´‘ý„¯߬cFXåJÅ í’}ñï£Å¨¨ÓÂj£¦ÌZñ~qÉyÚ …• Ã(}4«(¹2zÛh38Ë£·žT%æ¤vF¶›‚EùèÃåCßUñ º:ê! FùÆuѨAøöŠ|ì«å±—W2¶¾ä†é?ï…?2J£ÿÝ(<;v(®JéŒV å^P´ï¾þþü¢à �ãŸÏA?#.CßÍð%‹®›„OæÞ�ÞíµûC)ÞÈùnƼ?\üö¬�ö²™sjI{ŸC%›ñê“÷!ëEçÑ~ß‹㉠ãþP_^ËãðåópÞÅié¶aÿSƒw´�ôÃÌ•SÝÏíåµ|niiJê57Þ{qhšIvðªT$5k¦Þ~=ºŸ× Nœ@Eù¼žû‡ÀóC¸QGUGU\iz¿¶øeú]kÊ?­,Sòð§ßôGGyΫ(-Ä{/çbLÎB³˜Yظw2:Éyç(k˜k¹z�¹ö˜)†¼y¾¿­�ö0JÚöÆ…¥:ÏŽáÒTÍ\Ÿ)”ëy¸€/-躃]«¯lùȉò‡ñ½Â_ÿ­t¼>cŸ�ñ<©FÁω%/Û?¨~ê>êr«Žãù”=?Vï>h—�Ÿ(@ P€ (@ P€ (@ P€g·¾ªÑþw~ŠwÖEO¡Ù¸iÈ•ŽÑ½´�¢|í—NØnv@”L)8Q¦Œúr¬Ëò{œ_É]µ£Í$‚™2Ê•.àÜu$òòº"3sŠc±6-Ü/Ž/Œ„¤MeO#H %;óÇB‰G¬r|PË&�ª;—Žì½ËH©`qRÇXA@ŽÔí/)YÈg²å‹¢¥­ÖÉ­óÌîÌ” £¢¼Øƒ=¤3ÓõÁ.Þæ®foD±V;ôƒòõbzF˜3$Ú ʘ…�³o ¯þÍÉÙ©é,S±Œ~s©Ëè7Áyhß­Qì¬u±´iÖ¢�˜|ƒ¸¶½<ºl�cz�ÅhJy™›‡ ßË„2ȈDÌEÑì4¼©Œð¥ÏÊî‘?ºž>,Ÿz#2­áû"¤�‘» ³G÷–-¼ì£%¬Nƒ!#mUêl[:�nv�ÞÁÇÑ*9§zÇðe�S¡AJ‡¾7cV>fßf+5SΩ¸®?Ê~Zàa<×É8ð¥¿/ýñÜXe”Ïåÿë²ð¯WF¯ ‹ë¦nÃe÷…¿Ê«)½˜_ˆ‘—™ TlÀ/;´GS7Ô?�’׺bدþìXóâçE¸åø"´î÷G}¹û”�v™Ü×�•2kÁ6iødÏôÓ†+óXžçþY„_u>h¼žŽªFøâÇr ¶Íœ]™52k(RsV`éØÐé4í{†”ê­|îiUï^ì–¦¯p9nì“àêÆ!SAÍŽéœõœ¦çk P¸|:údæ¸ܱlVþNÜ–b�Xʵ#èÚ`í¤ÞC¯=ÖV¡ï^ï/;þ³9ÒOq{h¥ {ÿTïE¡Õ�%áŸ/ËŸx^UŸ¡T3uy y5Ï0îÎà%mO—QD Fú½�µ½cyAÐ3¦¶Ÿçg ω7nzЛ«# 4èžåùܪÞ}P3â‹ (@ P€ (@ P€ (@€_Õ< Ž~ÿ Ö}±%å‡CSjÐ É=.Aß^]B¦{Ô6Žð¥ŽV #­Ý;Í9µ]hŽ�%ëdê´ÁæÔiY2*Ó-{þèèÉ]¶ çæ?‡Q�‘)ÌÝR20÷É)Þ×Tæ+^�G? �ÀÌÍSGNÁԇƣw»ýX�õÜó’5B M}–�7%ÉYÈ9Z ˜W²Óïê‡5Ö Æ‘Ì �m“:ôÃl-9 F*’`$«Ë¾²`Aô¼Íb¯[ŒÜGÇ@)¾¹&ãr§á�ÑýANjÚ³¤ž·Y‘`æ^Û%ˆ¬ŸD¦¾ÝÖÃ*•±�½>öŽn3i×ÎçØ¬}Xœ• £XnSzVbõ‚'0éž¡ô)2•ãýã®á}¾Vy"½«Nîí©L~lXœƒAcB§<Ë’Qäþxõ7¸IFéÐÆÒŽïÉA£Ž®^€Çþë,´I£¨©#1êCHï3‚Ý@h{zq‘}æýÃ&èG¦B$Žó§b|zoìß°CÝc[ëÇü/ðæ8™ÒQ‹a :ž•D"”ó)+¹ôF=ˆl¸Ùf>¬[<3äü^îtIO/E\~ÿÿÆã¶þêt�^ö‘¤Òuȹo0f¨ç´–KjVýýÞÿÏÞyFQåü I ôšt ‚X8ˆÞ�Šb¬‡Šx¶#V޳€íÄò=Dô”ã<6,`áNDA@©Ai!ôHH¤g“ùÿÞÌÎÎìfw³»Ùd“ð]æÍÌ«Ÿ÷fÞ›yßü2^ý³± ¬Lr¯[ú8ºéqÌb…Æ{¾pKRÜ䩨xDOQ,æLì0LçUVÐe·–h-éjæT¸êK öLÖrÅïóG„f8•_YÊv€±Ê¡µWÓzuPÇãú¾�KðÎ[ozXò²<�¸a"ÆÝ|®ÑËëò‘©_LA¯±³$Àh,KyGþõ4FO×�Z‘ȵ/ÖOýLQ‹q©`ÿrLIº3í–ÆäÒˆÛŸÂô'îÇ@éÞ¾ÿf¥Y7ãëò\¼Idb͆ޫGò–ßr¦RlYÛ¶�'âÌÛçê'”@ì–^¾®Ë”i³1Ðy9”üÌX)ñ÷qN9 í°Jáß•½i6º_8ÙéI–lN–%› Qn}?£‚ϟϸ*Ðûг m-þ=mþþ¶çÃ@¯/n™|î¿g ºyCïFÀ:=ÎPž-Fº¹»—ã¥Ç¦È3­ìÃS�ƒž˜tw´Âv�ûx–¤ÌË‹IzÞž=V‰=]¡ö/cU õ±{áœ}«Ñ×yöŸ¡Ž‡myÌCÙÆXþŸ«ÂÉgÿçÎÐn70ërîá�£òëØ ìÓúÈ›HQ�ÁBæ*ðð�müBèM¶Ü“ � � � � � � � � � �À©N€‚¯pµYÆ1'¯G)P·.¢cê£qYÞÑÏV®àËOØ`/¹[àØ�;• œ‚\ddŸD�Ã�èØÆhݺ9Ü´‰d§@AtcD; ݤ5šëËÐYž_a U¿býEdqºÈÎÈAL ¸8�›7ò›�2ÁÃt¢ 7Ù' ¤c4Z´k�"†)¥ FS ù,‰Q°#õÖ(8Øþwä"--K4”-:±±MÐ'sè-ºœc"(K€‚¯²LªìLM|�LÛ‡ÿM�œ£ѨYK4iÕõ5®2fÕ=!GQNKGNVêԉ…�þ‡ü¾ºg›ù# ‘@Qq)ÆNY‚?ìFãFõѺeS4oÚHú€:!ÆÈ`5�@n^!ŽeGæñ\tißÿû×(tíФ¦‹ù'         ðB ¤¨Kÿ/ û^"óæMdþ< ›5ç<�“UiI‰Ì�g"GæÐ‹ óÿ§{qö­“½�ä) �` Pð,±0ú¯‰‚¯å/Þ‡ý«þ‹ßÝ”„¶Ý{…‘FíŠ*ïx–¾ý:ŠŠ¸þ½ µ«p, � �€‹À‡ÿ݉[û�€KºÎÓA)»cÎGßãꋺ`îÓ � � � � � � � � � �@-$�²ø#¬|yúÿñ œ9â’ZXÂðI ¿Vúö&¯Ã•¯}‡]{‡'bÆB§0 ¾"Xù5QðõßGþ„Òœ üþŽÜÈ9²öâÓÿnFjN6ò ŠPpˆmÚíÚ·F—.]1tPwÄE¹©õ¿þ°›—|�[¾Ü‹:uO±Â×úÚeI€HÀ 0ãÝd<2s5þoòM¨_ÏûÒ}9Vâן—a÷žœÈ?�ØíЦçïÐgðïѵ}\­@™“ú¾\ð%êu½#¯…†/U:6|4 É�A£E|ÇÉÑksÿ‹Žquñ­XùâF$@$@$@$@$@$@$@$@$@$Pû$ô Ö¿ó®j&êFÙç„KðëO+±,% i'dþ¼°H _-⚣S›¶èׯv:µVÒÊØ¿‹gOÇŸ~§ QûKDUL€‚¯*nO®6 ¾r¶}…ÖcÞ´ÏÃݯ¾ýÆÅ7ó8_{)øª½uË’‘ �€IÀ¿à+ Þ�7ç/7½—Ù÷¼éSÜuý(Ô/s¥&�(À†×šáÍÿy¾áÕcÖ¥ò_RsÿŒm›v¡Ëˆ×À�WéáÏpÿ�7'‡¾�é�þ9"Œ)ør¯‘ � � � � � � � � �@m#à[ðU€×’nĤµ¾KÜïÚñøòÑ‹ÐÞ·—Zu…‚¯ZU�,L5 @ÁW+¡V ¾vþ­GÿKhvÁƒS®A¯â8�bl‹&o.Ûë¢üÁ‚�pu§z®ãÚì à«6×.ËF$@ß‚/¶¼3¯ÏÿÕ‰ª.¿çQôèܙ۾Å{s_u!ìpÓñÈõ¢®ëLÍsìùòZüã�¯$ãcððGsÐÉC€þå`éý­0pÕŒ4ü¡‡‡¯œ•˜=æ"l–„‡Ü³·\™å6)ø Í3F         ¨Nü ¾Þ�x#Æ-ú]v#¼ f9û1oÖ·0gpíCÈ~ô<ÄV§BUR^(øª$°Œö”%@ÁW«¾v ¾F`í/ÐÏf­rûwïaÀCŸê¤‡?8ßÞØÝ¢^’ƒ]»�"#ß�˜ ѺYs´�kŒhˇîr”ÁáˆBlý(Y.2{�"¦qCtˆk‰XgZYi°'=ˆ‰FÃFMЦMK´ÿÞ¶œ¬L<–�ãù@Ã& qZûvâ×›Ï1¯Y‚èúõô<9Nd"õ�„“¾X…ëÚ©{O|yãÉs$@$P»ø|•þP,LÝb6þI<þØ´µ‹ ŽÿŒnþV:qÜñf.Æ™½ŸÅEDÕ‹X2ïEqI4b›Ÿ†f�í¯|䤧"+Sú¾ØD!±MZ¢Q³8xïþ(ÌÉB®,+Y⢢Šßö²¥g�ØÓ‡,å|éGÒ ]5ê5jŠVí{x‰_ò’™Žº�Û£¡-¾Ò¢”xFo;6Êh;�ò¨2�,¬x¾#>\\þüŒì§3CT,bœýri~:²ó£Ñ²¥‡ÌLNÆ Ç�ĉ¼ã’GaÑâ4Äyõ # ¾LØÜ“ � � � � � � � � �@í$ˆàkÔ”—1ÿº.€¼½xüÖ xq§:u–¯˜ŒsZ—³ÒÓ°'MÌ«ÄÔG³F }Ì{Û籋°ÿQäÉ\BÓ–-Ѿ©óC}a¶Ë\¼šÛŽiP­[É\|‹²sñzÊ%8|(i¹ybÖ¥¾øm…î2o_v³§ 3NÁWYš…£Ë>G_Û¼º™®Joþ‚I2¿mýõööŸ>—yûw¼ÎÛ/öFœgÎÛË×÷ ÌŸSðeÕ]$|…ƒbˆqœ:‚¯ãx)éVLY ˜‚¯í‹faÀ£¦xª nÓ &[Ë?JG´_:¢8�mLs—î¨û‰Úùi4ûîe ø»¡öê7x.qô¦M˰\)¢o›Š‚ññF°’4<>än¼hF"~Ç÷~˜·ÌÕy�zpšÒä¤s3;,óXí‡�tƯN ¾‡ÿ= žöC(øRp¸‘ �@í&à]ð•ƒÕ"6zO µ?Å+åc¹Æt|wG|±GüÅOÇ ÏÞ'v¦,�‘8ݶ·®Æ”kâxòsxô±§\×z&üm�†£{¾BÊã´KH¥¦âÓľøÁ¢C×áhÕؼy¹ó pëìãÜÞ/›'×Eqô:82Ï¿=¿ÊŸ+Lü?¥ãŒr¤þ“&N²G#n%,sªÆU/ÊrŒg¨4Ð<k_k†¹ÿóˆÖyh|™uàÎÈüùq<ñÌ ®†$Ž—²ý€_Ö˜ùƒ¿Í›ƒ®N=›«l®åó0½Rðe’àžH€H€H€H€H€H€H€H€H€j'�P_Y>Gû;”¡§…¯¨¸÷¼ñP0µéóÞ½êË\¶µüãsoÏÅ_ã�¿0÷6�­‡{`:ÖŽ�ÂmC&à=&™‹¿Væâ3vË\¼ñ|á’ù¸Øi|eÿ²÷Ðs¢±Z—ò~ã˜+d.<,3 ¨ŒÀò¥pNS=2—àË82þ tþœ‚/;5ºI â(øª8Ã�c¨�‚/ÿK:êæ*/+ÁmÃ&ę́»§`ÖíC`Š‚÷ÿò9zÞiXðzããpóéjòÙ.øºK¾¹ ´‹AVVÈ:ŒŸ8×>þÀ³øö–¾Îú(ÁþmÛq¸ywœÓΘÀ¶‹Ì|áe<ý§ÙÌÂt¼öH&éš±~X²ôi\à­Ãq6=5g4U æ|õ곸nŽêmªkgêjGÁ— �$@$PK x|mÇ×õ×—krÏ:Ür©9yßöÿ÷ZL{ý+`è?1ýÑqºõ.»Àè‚{¾Ç5¼1EYÈCYF8Õ7ðLœ;=ZšV&e™ÃgÛéV­sV“G ]Êj,éxÝ‹� ¢±R}íÈhÔÕÓ³Dwn,Š~~gKiÊR›S&OA§°+3ùŸxâ1C æÍâš'@º_ù‡‚/“÷$@$@$@$@$@$@$@$@$@$P; $øò\Ò±ð¿y¼kIÇU«&#æË—1ø95a-¸>¾£Nw.bŸË13.‚ú¬m|Ý1åYL»º/be Ç,4@ƒCß¡õè‰/÷¹oG^:Öüv†t×ã�¿æ‘ÙCd6øF¬ýÇhôsΓïÿå+™·7ägÃï–yøqÆ<¼=]9NÁWí¼XªÈ à+rìQ;_]ðÜ ·`�ô?YYX¿r!^t™œuòÒÉè{ôV#º.PæL\[�,ÿx£¾ü£¾\coÕ]Y‚¯'fÏÅ”!öu±ŠðÑc×ã–oÄ›,¹üÙëĤ¤9ñíŠT�ã †�W}äµ!çÑóÜ–nDÖf þýºÍ‘;^˜…×þÐNluX#d©Ê îKUžØŒ‹ž€šö~ã3§uuO—‚/!ÿ! �ZMÀ«à«$ åÅJ·cyÉ—øç½ûdpè¿·á¹×çÉõQø›¨ºŠ€Ê%žêú$žeŠñÒåŒÁuMŽÇ¾~çv´÷=>DN>SwÈòˆ�ôå-ËX¶ô1FD]s\¢.=šœ0sÌ¥úÒ�c_—e#;j)W¾Ü_ž ["-uåV ?ØÞÓ§uì=�J|fYð:&ËB:U[®€öëÎe#åš+Ÿâ¾uv®X53Äof°ý¯¼¯zöñxü󠭈Ǭ0�ó0ã£àË$Á= � � � � � � � � � ÔN�¾ú]{þqY�ÈÁ‘C©x÷ÅOõ9fEÄX�ª3̹ì~wOÃÚqÖŠTÊOÎ6YþqŒˆ¯ß%+O]¢¯<åšÇ>ýFY9k´så,å[f×÷,GókfèîŸ�†‡/î%P®ºýãŠCξ½`>®ïäîié�ãÒYÊÊØôËí8C.[a‚Ÿ?§àË ?H Â(øª0ÂÐ#¨�‚/_<ÎÁŸMÄÕ"Š:üËÇèv§a@§÷Ãðæö0¿bùZãØ›àëÕy`\oûä6°Ù[bfòK+Yªñ¹Q઄Aè®[ãR—2ñÜè;0U–y|bö›"kiù×]®NÔ\vR�vuX6µ´+`á.Üvža©ÌÊ«ë*-|Y(è" �ZKÀ«àK¬X;þ\l–RÇ�[�;¯è³ü.ÁW×çðì+“ $Í.�‘Íê—AΖéxä‘)rø¦.|î½™w‘“6{~þ [·%㨘m.ÈoЦÒÿîþß<^_Cß«cvZëræ hÞ¾î\ü"‡vËY®<û|9°ã£‘N1pñßS�8Ȱ(æŒYv�çQùµ_– Ë—·ë®å0EL÷¬ˆéìr¶0õ Y†ò>qyàÁÃÌ_& îI€H€H€H€H€H€H€H€H€H vDðå«ä£n›‚¹ã‡È~[sÙÊïðÁýÜ‚,_k,Ũ_"øRmÍc˹Æ9+P:”„W­²TãŸqí%çáÒøv.Ã(®y{�íÑX{›åÌÙ&†\Æ(KaÎe'Å�‹•®em̬œùs ¾\¤è �° à+,C‹¤¶ ¾†�8º¥ÇF Эm >{.ÚÎe€±áƒÿÃy/þ\.´Wç½+â.Õ]Y¾¼ «€"ü¼è Üó躅.{Äω¸ë¯JÜU’†Ç‡Ü�åâoŠ•°�žS¼V^_¶ÎÓ9-|¹HÑA$@µ–€WÁ—L^úh;ÌÅW‡ë¾Ä”?û¶ðå²(eJùOíÿR–€|C-éEŒåK%KL.ú[|½Çw5\þÌŒìo¼ÊùK! ¾ÒúžzÞxµŒ÷£ˆàÎqÏL�y Uð•ùóãxâ™$íçðüÂInÖÓT†\e·-Yé:g«#Wæ}ð0¯Sðe’àžH€H€H€H€H€H€H€H€H€j'�@_£.俣I불?£.��íÔ\¸ly;pݰ‡!_ÿýo#,q—Kxåm[bq¤ïÀ 3ßÅÔoœb13fY†q÷?F¡½XëÚ¿ì=1¬ò©\ù3ö¯¿ÚÍJ˜òîJC_«VLÖWÃr�ó–n9óç|™•À= „‡_ááR,µSð%{Ycx`}ßHÒÅÂW'eákðbrr”nrÒ·ouÅcy|™¡‹pxÏ,_¶·ÌÔÒ’ cÓª»qFýL¼$¾¦ˆ…¯e�ä9×u19÷–…¯áNÇ·7v×ÏW¤Ã¢àË1I€H ð.ø²¬OA–Eœ2:ÔóRø’íøàêþX©.%ˆ€ë¯†5-#—`É«…*+]»õ-—H ÃqÃ3ÿÄ Þ]%K–Âò§zê´fÃ0粈þÒEðeYÍRå|[Êyƒ»Õ09lC|å$?‡G{JR”å¥^:yÔ‹«ìÞ,|Qð%ܸ‘ � � � � � � � � � Ø "ø%óÓóËÌOÛc±æ²Ÿ{û]ü5Þ)³{ñpû�Ƕù-8‘‰ä_Å'sgàյƅÿþ*æ$v„kÞ²<㪠eæø]ix³ðEÁ—�2�$|E†»žjm|-uï9bÎÑ×fu ]0ÿ›éÕÎ}-à²á|Y!­4Ló’V^…f'¶àâ„Gõµ’ÇÏø7^§GæŠ'„‹‚/«>è" �ÚJÀ»àKvY’’åoý/¸æÂ2öü÷6üãõyúùËŸ?€‘}�¾Ç%:ò"0r]“Pc_?Žs;Ú–9ÎY‰™c.BŠ\³_9Xñl+|¸Æ}ÙF#3‡±èþ®ºå/Ë¿ÍÊ•—ôƒ|ÿ3o¾TÏ“Z†òÉÏŸF\™n?ø<Ú_7¼*bµ.ž/¿ÞÅoÅ{ßÀÄñ÷éÅ¿îEY òŒ ç¿©Ÿý3æ.—#+¯.æAð0#¥…/“÷$@$@$@$@$@$@$@$@$@$P; $øƒ#ó�G¼S°æ²û�™‚µâÝ›í¬ßyl›?Ëi¥a®xU°óh>Z-ÙL¡Ù½B³•o?ŽßÏT®Ŗ_Æ¢»|ß÷›.-|é,ù T ¾ªŠ´—tj«àË4çè¥ÈƩ¸÷¼ñxS�~þ;}4:9'j s°òË/°,îLqŠ®ü[ø*ÁÏó?ŦƒqÝÙ]Т¾1‹¼}ÙÇ0Q¬ˆÙÔÆû—½%&)¿Ôó0ê�'ðÆ- ëbyðÒ£ã1e™ºd Ätoê°(ø2ò_ ¨Í| ¾P’ŠO¯î‹œ…�¿ém\sé(´j‹’œ½ØôÙC˜;ß4Îü$ž]8æbÃ~F6Q—²Ruç«Ï¡wû&È;ú ¾›u)~�e$Õf ¸,áº>„‡Ÿ~�$…™¿bÕÜ[0©aÊÙ.šò›¾�% ½†)JÅ¿õÅ·{TކãÎ×?Æ™mbP\¢Ž�­n½Æˆ‰ >�Jðe نܳ·\:PVxÎÂñ¢hÖX‰à¬8-rÚ­^FážÙÿAßö†èëÈúéxúïSôŒÅ�[-ËNJœ²y-›~EþñÁüLÁ—I‚{         ¨�Â#ø¶/š…�«XÝ1e*ž¹:-œ@�µ3^zg'n{äj]t¥Hú^emÁsïíÇÈ?]€xY6RÖü�e#๠ã1U¬|™‚/”¤áÁ!wãUu]æÉ.�‹�óöÛúî{G¿âò/G~Ó¥àKçÅH ªPðUU¤½¤sÊ ¾„Å®ïÞB߇ ñ•Žfð9Õ(_-3×–¥‘¥õNÌR—YÒ±än2JÚ¥¶~ƒû¡eö¯X.K7êÛµS�ýèöOÄf’,ë(�˜±uÁ¨Mliw<û*^ÙÑôà¿ÃÊÛ%k)OÒ×R.“/‰�‚/F:H€H Öð)ø’þ /Þy-ù-ý(Ü?÷#ôj©¿né>ý ŒÄ‡e…ÊwÄv‘SæÏÃϯk¾B\0)7Ž8£üôó7`öõçBéÊìixËsaê?1iâ$_Iêç¯+[+[ÁæÑ.èÒ#êÚØ#cˆ®ÿÄôWÆÉ’‘>_â9gËt<òˆ!ìRa;Ä�B£“_!e�:RÛx<>ÿhë\îÑ[Ù ò¯æu ¾LÜ“ � � � � � � � � �@í$ˆàk¸XøúÖ¯…/aã&¾R¬Ô\v[œ8ø³kîûÆggaÎÈv:H«í‹^ñ˜níD °tÁðæM°|­9|°à#\ÝÉøž¾ástºÃv©ˆûɼ}Ël+Mà lZu;Ψ¯'[¡ùóŒý»±xötüñé÷qÚ F„ü—H d|…Œ®âk§àKÖ÷]!ëûúYÒÑ$·ë§¯p×}oêË(šçôýé#ðê„«qóù]œB-Kðõê¼w1®·Ó˜ò\’‰�^·ÌqvX¶ˆ†�+bã/B'gç£_ò鿦ÿóNÜ{¾%öRþ]刻�1ãØR–«éxnt¦îTKS¾ KS:g†õ„(ørbàŽH€j5‚/UðÒã°ü“g0áWe8 ¹î \ö§?#®�û%—Àh¨ˆ—Uâ%ÏÍ�#ëçà‹¹÷aóçµ®Ãqù•7£øûqøVÔXv1–²”™ºä1̘i}u…þ2C;&câ­×«àËkúûdÈž² d?ÜùæJÄÇ’joy.>ð!&Þs‹gæÝŽ-ËbÁåQE’·÷<4~œ[|žÃ¸&ɲ‘–àë†iÖÃ}éÆãÛ?ć¯ÝbñsÆÒó’é¸áöûÐÖV'ÞÊf%ê�‡y�‚/“÷$@$@$@$@$@$@$@$@$@$P; "øzðŸÿÆÓçÇ•@¬p½6c6&}j‰³Ì@7Þv&�½ýZsÒþæ±Ó7/ÇC¯ÎÀ.C(f,ýðê›÷cÜ@÷¼ÿ㟞�¯L£*NïッN…3lsÿþÒ-oþœ‚/³¸'�ð à+<CŠ¥6 ¾B *AVz& ¢› Ö‘Gýƈkê.œ (î’"deGNtÄæÃѰÚû‹G–Ž<œU„XñS� ÄÅ9MY”X`žhá+0NôE$@5™@y‚/WÙŠr�““‰"µœaT4jç*Ä./¡8JKz°ºQÊBXºˆ±:ŠËSð匹¤…*} Ó 1ê:O«8ŒðΑܛÇütdE#V•6ˆCã–¥´@Š‘wü0ŠE^bøòÒ à«z#NØ�ËÆOk áUôF°**%éŸ?»6¬Á- ÷uêTJŒ”H€H ²^�·{i¾ç*´�k^%™)>,K%Þég©D¯K1VIÖ˜ˆ�@Ii)^œõâ{4Å7¯]f»B' � � � � � � � � � �@m!ðëü×±vÎs5ñI4iå¾Tbm)c¸Ê±oóz¬üè-\òì‡hÖ°pEËxHà”%@ÁW«¾& ¾ö­ú/¾všÆµEÛn½Ð¼]Ä6nAŠÕ+iGa!²�ı{qtw ú\q†ÞõtõÊ$sC$@$6‡Óó0x̧((,EïÓ;¢}ÛhÕ¢‰è|+Oè[’½J^ˆžÅÖÔíåŠÁ£' ß Á¨o®×èჇ•O '7‡Žd!uÏaÉ8ŽOþq1®ѵòf $@$@$@$@$@$@$@$@$@$@UN 7ý Ž¿(-A‡^}Ѽm4nÙšAœ5QZR‚“G�uøíø Í:õÂåÓ"ª^ý*¯+&Hµ�_¬Ñš(øR¸ü²Û¿~‡6®@Iqa VÓ¤e’¿uÏèqá5è=êÔ©KKhÕ´¦˜-  �”}Ç1ý�MørÙ^ddå‡%N_‘8ì´b@+•3%ò“¾¦®ûËt´ÃªZwýzQøýÐŽHº¶Fë\µ‰35          �*%p| ~ýô_Ø¿f1 NdViÚ5%±&m;¡ó—!þO÷"¶iËš’m擪5 ¾"X=5Uðe"+u8�wì0ŠrO˜§Nù}T½X4Šë€èú Ny@$@§MÒEðuäX>JÕ·S’@óÆõСM#ÄDÓÌÚ)ÙXh         �S—€Ì äggÈ/]þ`›óª!Ô‰ŠFÖmQ¿IóS·]°ä$PI(øª$°�D[Ó_�”±ªü¬œù7Iª.xàŪJ’é� � � xXðÃŒ{j)v/‹F hcÌI€H€H€H€H€H€H€H€H€H€H JZ¿ ?½ú0®›³ºJÒc"$@UO€‚¯ªgîJ‘‚/Š�…'³�üÑ«øíóëqô»æ.ô¿~<ê5nrœ H$@$@$�ƒGsñÓÆ4¬”ߪMGt‘×°Aí1ï›ôíÞçŸÕçh‹Ág¶AÃX À£J_$@$@$@$@$@$@$@$@$@$@$Pb]lñ“7ãລùÂgh{æ9ˆŒAI€ª+ ¾"X3|_+-Á‰C»‘µ{+2woÁ±Ô_‘¾uº_x ú�¾O¬bj"þz»—-Ð;­–=ú¡e÷3Ѳ[_4i×Y €Õ .Aú&ä‚°@IDAT  �S�@±£Yúò”j‰Êtq«ã£âÎp§eä!uÿ ÄÄÔÅïDàeþútk¡w·¹ù¬Ù|?®?¬ÿÖoMG\‹èzZ´‘}kùŵˆE\KÙ7�u;nѤ>»ìS°Ý±È$@$@$@$@$@$@$@$@$@$@#PœŸ‹½+¿FÊâ�Шu{œ1òf¨•²: �]‹¸3V,†&¨V(øŠ`uTgÁ—¦•B+-Õ×V{ëX¹5”:ŠQZâ0ö´9–}©Ú—”èç5óºÛÞéGù•8¼ù1Î9à(ÌC^æQäg‘ý?†Æm:Šˆ«Z�.b.tµ>½k^ÊêWFJ2ŽíÜŒÌÔÍú^…oТ­¬,FZµwDÕ‹EÝèhÔ�Šqî£Q'ZܲŽp]ûÞÍOŒø±‡1Ã:÷r­Ž+>ñ[7J~ud⺮ìëŠèLöê%?ù�3Ú¼™4 �@­# Ý“ÞGÉÎØ+‡î.{Þ›_u®Tõq¥šô�²wI‰±W]¢û±\S~ÌŸ¿*.~K$r3~Ÿ?¿¥Aøõoaa rò‹‘“gürÅ­ÄYêX¹sòP‚¯V"ÂjÓRý¢m«²·~m•[εo­®54 —ó¯ŠsZŽdæãè1ù‰pLßgæáh¦ˆÉdD�—ë*/ÊX£†1h¬~ btËaú±¸7ŒFCÙ׋®‹ºÒÇFÉOíõŸˆ»£¢Ä-{Õíª½uìî·ŽÛµ²~Ýâ.ǯêë]ùp¦%ð–Ïx•»_3.•?ùßùÓG âöNUƒîÇÜSë^NËäe         ˆ}>¢DæËå'†OÔ»VªæÒÕÜ»:¶ö†[]+�£ OæÍ3P���|ù™ûÜôCâNG§s/A÷W¢MŸÁúæ¢Ü"ûF7š’µo;šwê)såqˆmÞ±ÍZ£AóVú>¶YKÔ�©'ßµÕ|w”>g^GÍ›‹[ß«yoÛ±šׯɞ �@dPðîzª|•B¨ciº*/CöYGõ|©£êzi±aÉ^„Uú±~^�“_q!JÔ^w;ýëÇâ–½šV4JÆÞ]°$“¨‚(»ÈÉQ©ŽÀC8¥ÛÄR‡w?†è*ª~¬´ q–)ÒR醲•èâ±<á•/œò³Ò…I¡”ß&VSå÷&NSm‚6ͶyÛÛã“0ªsVýî‚9%¦3ΩN°nt=D©ÎS15Ý16·œ�’óz«Üʯü¢”ÿ˜úˆ®ß@çÔ°u;³9Â-TV¡ðe �šK °ÈåŠÐÇåŠàæ¤S¤ÎÙ¯‹8I½„ˆJ Š” J ”ôŸóœ/ùº&zbŸ×Lq•·8õk’Ž)ˆ²§g†SµàMìbˆfTÏæ¼îGDc…Tßgˆ†,±PYA�Kàãů7�/Q’ݯ›ÈK¼um""O¿®üH�=ED¦ßúõ£œ*K8¥UJDÕHVÅèb+Å,R›£¤T¡©v˜[`ŠÑº Í¥åI»,™ÙÞ™~LA�°›mÇÜYÇV[ÓÕã×MÔ§¿¤í<�xÍûÅôkÆ¥ò'ÿ;â– )3Ý�s¯ŽMÑ›jgª=«v¢ÿÄ­îã\ÙkþÂé÷‰Wpá\m]ò#‚=ÕîtAŸMÜg¶Å&�œb?çµØzüh ê“ � � � � � � � � �@õ# æ‚OÜ…Ì]¿é«UœÈÒ�›8 òá«[Å"ÒräêsùŽB9WX Ï×ËGZ™�!•nÆLDïËÿ¬›sŒ`v™t &PRTˆä�_Õ;Í+^þF·Wƒ‹Ã¬“ xP–zžkÞ^¸]„§á¢¡§éû¸±>yH$@µ—À‰Ü"ü¸î0–ˆèõ{ù�Ó¯ f>|Ô¯½1W{k“%#        �êK (ç8>ýË0\ö�/Ьc�ê›Ñjž³ôíðý3wàº7WÉÒ”õ«yn™=¨~(øŠ`�”'ø:ºu­¾þmÛ3ω`.™tm"°Íb4íÐU,Äõ¬MÅbYHà”'�)Vm>ûnþrMŸSž� �€Ià³%»Ð¿g+œ.–¹‘ � � � � � � � � �@¸äeÁ‘_× ÛðÄpEyÊÆ£,}u>÷ÔkÌ︧l#`ÁC&@ÁWÈè*°<ÁWÅS` $@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@µ‰_¬M ¾"ŸI“ � � � � � � � � � � � � � � � �@ $@ÁW+-hÁWi ´ {Yë1‚9gÒ5‚@�º@Ý(Ô‰Ž”› �À)C T ‹G‰†é2¸‘ �@m'PW†:1QuPO†=QöÔöêfùH€H€H€H€H€H€H€H€H z�¹{}_ÍåsßwÝÈܵ>¥æ¯ëøöÇ+$@ à+ L•ã)Á—V”­¸°r2ÂXk=�:õ NLýZ_N�HÀz�ÈÓ ‰è‹ � œjÔ'‚F ê !‡=§ZÕ³¼$@$@$@$@$@$@$@$@$š£j.Ÿ3Aà±W�ú QG ¿¸‘ „L€‚¯�ÑU<` ‚/­0ª£àV; úm-vS< ÛaðYÝ[IŬS/VD_�Ä^€m«Aºd)¦yœß¡’rT^´ì[¿ {s#��òòéq½àVÿ’ Á‡¸ÞCÐ;Î`^ph~IM—³1è1ä\t¤*<¢æaÅäJÅŽ}éPOÓz�: o|ç Ýoެ}Xõë^‰-]ž‹Î�+–¿p„VV½ŽçRé–ÞâÈMKEê� ýþŽiØgôí jJ¼‘â¹S•@aÆ6lLQ}]=y.E;g_W˜&çw—=_™œÅÖA#öµ@Êx0”0ÈbˆA«cÿbQ V�.cÐmU5­mÀ¸ÐÛFU—»*Ó«Ê´|Õ Ï×v‡6¯Fj¶¼ÈÈ;Ú�A=|G«Yß By‡þLªx‹ ÿ÷‹šU_'È'À¶8+ú$�êBÀûø0”¾®º”ˆù°ð^¿vÞܵ­þÃ?òF-<çjR^ÃSâê‹.ö’¹üÚ¶UÙüul£j)ú ùþò1O\ÛÚËS}Pð†º(É=†”ÔLËDn�‡±­:¡ÿ€³Ð±¹oUj ‚/­¤Z�(^ÌÍ‘�m’±aûV¤¦AfA�\‰EƒÍÑ«{Oô>3Îìà23Ò¸¯5rðÊÐN˜ø›ªƒaø)íK ­DÑHÝMt3™~kÏøªt ZCÚ€'#ó8ä¶QÕå®Êôª2-³"¸?ÅØÞû‘ ïh?øŽf Ñï�UW(Ïâ�ŸI�eɯ¯Pòë7BÔ¬úò_^ /¶�ðò¬âØrRñýŠç»Ñpy7òý¾^Å9cr•IÀÇø0ü}Ge‚qû$à£~}úw^¨mõ_“ÊS“òZ^;ŠÌõ@¿ýùÉ�L̔柰,{qþÚ,—êÔE݆2�êµ¼c¨÷—ý]Î>Oì£ô˜ŽKºGjZå.›Ù†¼˜VàÅjUÎþ-ظ?í{õC�ÖÁ™_¨YüÖ”Îéíë;áö¯•¿‘X›6+±ÚÔ²ŽjyG¿[Îz|�]…‚/i+«En½8œåö×¼9˜{eܦô‰³prÁ]¨D4~‘s1gó¿Ð¤ÿÝz�Ä™ë°àþAº;Ô�A0i‡ËoÎ¾ÍØ ¦Õ:ô> =œÊÂw$âq¤ÎCÌé7y$�„äüÙˆàñ㋇½®g®ËÄýƒÊÜxd!̇y²êoN¾¥öÊÝý=ž¿ÿø÷Šr–„YONÁ5ƒ;—ã±*.ç`ëÚߤïh�~z„UˆR‘Ü;v€Ó•mCKÿ }hCIÛWØÜM¯ {ÂýrŸ§VaéýC}yužÏÁ4Åc[Ôa¾Ùÿ}Pbµ”E/bܘ‡±µœTÐ÷&|øÞ,\Ø- Öãægã=a ã°P„-Þù_J_i«U‡þÛ3çá>Þü¯›Ñÿn½&®òú¡Êß#ÂK+ä¶QÕå®Êôª2­ðVgØcóÙîõ”|?sž‘Z¡í½‰Xwr4Œ´… ´ŸŠ ;ßÏbßm'ägRÊþï©/ߌÂPTFQe|ÕcEÚF•ež ù `ŸÌt½é~}Õ·�ˆxºfð1>ôÝ×Õ¬â�ò¹ ñ½¾¶ÕøÇB•ײjR^+�Bb¶}ÓóûíÏOZq¡±”£øáüµPå\Ò—vŒ–�¹Õh õþ²¿ËÙ牫Qј•ZF€‚¯ Tè±ä…øtušCtc´k×…Äê…uºã¹Wá²þm¬NW ‚¯Ò¼ãº*xßwSÑíª¶8ú"ñö8»ƒL¤ågaÝÏ˰ðG}×ég–íùÃZÛ‚T¡Óqxê÷#)z³ZåÀ—Çáª×Ä€ÔÓ‹±qâà€sVÓ8”_°T¥à u£ [ùò›11§¾m+t#0Í:¢wgc²Öo� \tZˆ˜Ó®”<'>m}DðõCÍ|©å¶�ûY¬ÔtìÓ-¢+­Rƒ:°pb ®|YîO›…²JM²’#·®â“ÞÇ²×ÆÁß7{¼áš@­Šy Ôz•²Xþ"ξòaãÀöïùÃâñSf+ôÙ²´Œp'in ž¾2²GÚBœÖç*Éqð‚$[1ÃîÌÝ2Ý/0„œ}n}_¼x#šGø¶çé’ç×â�; q©ïÂçàÃ1MñÀ"å#‹÷�þM¦I{Z2g_÷¼-êx\rëE8«CKƒdbã/ßã+ìrô,LùCÃ0ñ% ²e{MÁÐ1Vþž¿ý}u0ÚsYun;³@S½äùeÒ†~¨wŸþìiÛ_Žì}H9dô�í{õ®²ûGY÷RV¾BÞl:Í—s¯Ï~›¿ÀÓ fR;ðXÃæÓ^¦@Ça¡„ [†Ý#ò=¾¤à«âußc# jß#Ük½âG^ï­êrWezU™V@°#äÉ_»—–ïó�6BÙ­QÉÚÞûC|ÚOE�‹¯IPm'ôgRÅ þï¶z²¾ü1ªxICUð]�¡·�ªÊ;ÓñMÀ×sÊw}ûŽ‹WjïãC_}]M*ó*B|¯¯mõþ±Påµ®š”×Ê£P�˜mmÞï·??I¨UºÔj]œ¿ö)€KuDì¥D_Õi õþ²�‘ÌvU�ÊżÔ>|…Z§ÅðÙœo�á ß⌠qÕˆž"å06wË_-pÙmBGó¢ÓO@‚¯ÜldmÁŸ[_Ã^pÓ 03ixÁBÖ®åx ÿ•.ñ“`ãSÃ�©Uí.}Ù‹hwùs’èh¬Í˜��nPÒðÌÐ>xR–1Lœ¹ŸßÑ7°ÌÕ@嬪_b³AÓò³U…>Ò¿K¿W–2Æb]þ»äj+î}2EðU¹Ò³ðºæwä‡ðtÿÓð„h7g%cÁ]á±úº¡Å²mÞ�èsÓ¿õÀ³’óqW f½\Iùæa¯ëê øÊÎÕP$«õån™+â¤Û]%�^ÿYüw\tV4r‰” p`Ó·xùž«ð®K+�w6¯Ã%]žlqT�3cùÓ8óÊ'%±›°øð»èïzTMú¾RI™†�3ÚÐ +ópKßÈg¬Ê_›qoû˜ï„sÝóßáÙ;.*#ØÉ‹r�úƒË_Ÿ‰ßaéùBðy_"3‚Kž1šj3Æv*[ö2Ø™=ñÍÜ{ž,Cè0¯ª½»~Á§ÓïÃÔ�-¡Þ¬5'pM¯U€öèln{ÚvÁ—ÍK•:£ê­šV±à+~®ÿ+ZºC÷RîhÄÆFîyë%Cî§l¼èÄl(aÜS Û‘ïñ%_|ù…­#QuÛE“õJÀ»÷÷ÌñOÚØÞû+ øªîß |M‚úk;µë™d«gWS_þÙ�Õœ€ïz ½mTó"ŸÙóõœò]ß§–S¶�¾úºSHM-xˆïõ¬ÿšZáÌ·]äh s|õo¾hij¥®Üä7�ï«<Öùª�¿®Ž‚/‹Ep.{2ÛUp1Ð7 G€‚¯àx¹|X�w¾qÎ’7î‹?�Ïéßß¾y +3l]/¼÷TëÏZ[À‚¯ìU¸¨ãeX¦‚^þŽt›Ï¥í»æ£~ÿqÎDnÅÆŒe–,+È>€M›¶ãÀ‘#È)ª‡–íNCß³ú]Z± c~Z‘Œ”c'[¿>ê5n�N]{ãÌ~ÝÜ…gÙH=tßž„ÑÓWèùxëÛ5º¥±˜6�ÑääaI[‡{.g”çö×ðÛ„Á(v4DÏ^Ë0tÄØ…‰Cú®HËw aËÎèѾ1 2vcíÆdìOËE Ag—ù–ìÛ±y2AŠè6èÝÝ·É=n½Ê=Ê#k6¯Yº ÷füZtÄÀAƒÐ»}´Xøj_Î’Ž*ýíØº%i9Ê|�ä±SW 8³:{[³ ÛR�¢ ÐóÌnpìß„Vý†L ÚîìK1rpw7¬e8”ºÇòŠãÕ—é©[±ù·í’É�Xج׸%:öì�þ=: à©Ë‚,¤<‚ oÞ�?ýßR=s–oÅïâÄVÛ®èÜÂa-é(óEð�³«Vü,u•㬫N8kèyâ×wªbYk˯[°mŠ„�Êk÷3ÎÂYñ�ý··²`ÜÎd¥®Æ¢7â„Ä+:w„sÎí�ØmsÓç6ݯ½#wäÂÎÝǤ^Š…¯Ö}S�Žm)iúùžñ=àØ·ß˽fÔ×å¸4^€¸6i Û¶Hy¶Ym¡sw)ËYè\ÎÒ‹ŠÃÆ [p -Íyßw™gq[²1k_*ŽZƒ»Ï» KUšIs°õ¡sQ\,í¹·;¯‚ômøiÙzìȱ±:×NÝÏD¿þ¶²¹ò i3’giS [õD�¬ÿþ{$ïË” éŒËG_„8ßUh‹Åpœ¶°M=x ?þ½n{Ï›4g9’FV\ܧ÷öß^Ëãá°/ %B²û㣱oó*ü¼y¿0–§I½–è$usž´5ßÅ ½N=Á‚¯,¼qE+<¶ÂyuØ4¬ùüAtõ™�}x튮˜júùöÍ»µÌRŠ…b�gûÖ­Øyð°q5j‰.=ÏB¿¾�ËøU)gìÞ†ô|y µì†®í‹åËTlÜ´�œ”{·>Z´í(íïÆô�ŒØ?ˆ†²¬”ä9à±€´—Í¿nÆvy~¨¾Fm�[öÀÀóÜûtWalqw“q†Œ|‘ºþlØVN_e/“ŒÃ¼YZÕûvÇ£i·>è�l-é -ã�”F½µ’±b?õ¦¨­¡Ô[yãWù<åŽ/cÝ—t ±ÿ÷ø2¸qRpc‡r?¼ѦÊÅÊ]îÿ=Bn—�Ç�Ýd )-8=¿¬Ûðû€C=c7È=#ïú‹‹z—jÛ ½J›mì>°ßß3ƒjÞËmÿ«q¾´>l[¿;È{¸ìË{Iü9C´EeïéY·C˜Þ×ô}¤ê³Åʤ—•žz¨ååsmÆä8’™#å�¶S<†žo½O™1ÙòTþ{•´Åßý¶û®MpÐÇ;miý(ä”蹫¬ç_ŽÜÖý†#Îïå=w°þî!Ïz“æÉŸ$¶êvz™¶®2ì½hb–�ضú'¬ß¸'ä=PÞå›’¼[öï'÷¨—1¯Б…Õß-ÁÆ=Æû£|�4øôî-ïý p›êl+ øªòïA<;UÉÊ<‹åïý O¥Òö¶•×ï´(ðñýÂYŽŒ'6à·]GäýN}gé(ßfëßfÔs:%MZ_ÃV8Ýõ�È]ÔP}Ч»²ãËa{.5r‹/À6ï&[wË·µ2ú,·hä –ºÍ¸.ll,_Y‡Rqà˜';ëz(®`úA{ü¡?#챈»ÜzŒÌ·¿òîû7ª@û �’—äsDÜ�¿3ȳ:¨ï‡¶¸ƒ¹WÜÆNë2q϶rÁ„˜÷xƒ,¿+°„Û¼[v@šŒ;Œïzgbˆ>Žsyòp„–V(÷f(aÔ|éßñSä;¾þ=]²_¯1:÷ˆó©ñiÙ­üûïÙçÊôuƒH;Ü#ãõÒØ½{øþÎ¥§© ò�ÌótÙÚÏT¤|�¾_¨:®¤rØÚ{ùã×ÐÚZÐm €oö0Ýöú7þàÚ!cÆŸ±~×>ù–\ O¥¦8ëwĹeÚ�´§m2%ßzí?%§´“ï ®i×yi7>æU¬öh}%²¿ËùšË æyirRûŠŒáíñ˜nŸyÕ=„ònL˜ ÔŸYÙ‡ÖדO[bžÎ@¿ýy†³낯c?†e¿¶Ï_[åë.óólXö#’÷gIßÔQæ ÿ€6�ÚÈús†XÿAŽ¿üß_@°óÄþJÄk$Pá|A q{æÝMýjÚvdÝmöìÙúï;Nx;ãÈ:—ŸÙŸ®ÓŠ<|™á=N»–ädiÇW¼¤I%¿{çiêœïßamÇš•ÚŽ”-7;ÝÃßVí½I#­¸Ì8�û›žž§/÷ní‹§Gû ôÕf|½Þ•ÎñÏûôÿôBmÆ™Îrx¤­âù)Í_¹ÂÄ!c¥–èL{Ä ßh¿}1Åg~Ÿÿz³Q®Œ¥ÚW~Gjk}å3{½&R;g|Ã\å)ܺ@»ÉuÞ¼nìozú5íùú:Ô�ûøúy>ê6‘øØ\-ãÎ6Î4ëx¤öÅׯ¹•/þÙïÜڗ׃üuZ‚™ßø™Z¦ÍS¦”%)Þ½ ®¶©‡IÔÞ_uÔ·ó亙ny³Ç#K JÀ“ÚœDgZcgiËMóéÚ’½^ÊÔLë3Œ|LÖ>I¶—ÎK^OåkKfúŠ7I›3gª&6±ôtEðåŠaÝÌW^¦­³ÒMž•è<Ÿ¨-X2ÇåGñ08QœöcÍzñ²Oœú‰[]¹ÖjïO6Ó([wc§-Òj;©ÍôY·ñÚ*Óø+�k¼6sÉN=F×?ùÉ®û.aæíý ö|$Øâv…ðá.mmL¬,'ÝòyœLžåª¯™K–k3ÍöêY?‰3µ½Åe‹z�–�K�ÉÊ)Õ¶/~Ù•'YQ[¸»T;’åÿwpó'z˜K½³x�‡ÿcÚ;OÝd‹Ó^wÊ�¨ýgå1÷0‡7i—8œÿü2mÅü§|†b�‘Þ®¥ö|»§Ñç©U¶ø+šŸ/´YwÛãOоÙï›�¿|©6d†Ý¾ò í:Ïz·÷ý²¶æ°{:K_2ïËDí�o¹1r/³{8³>w­´ÚŸ,éhcäÝÿ‘¬ÚÌ‘fÙµÅ~Êm¦¡ö»–Zéàî/ÊI'O[³r“¶fëm_zQ9~}åÓýüÒ—¬ö'£\qþ¶Ø–/a�4w‹ëš=ÿ–»¼¶¯=³ Å=·¶ì¯í”·—ûD¿/‹´Å¯=âV÷ö¾P¹¯{j‘¶«œ{Ø*£ÁÎ3OêØÞÆÏj™[ùCk×Þëkñó ®r>a«G•‡ß¿¯�o»_Üܤ½³æ„ž¯¥¶8Dœæ–W{ÙÖÌMr¥ÕwêZïÌ€ÏÕ¦9ûF³O·žý‰Úº|gD2vrõÑ ³œýjÀ‰h��еus&»ÊæÎɸ·ÇN[T&m+îmùÎdmZ‚ùðØ'Nsï«Ê)ÓÁ%SÝò2g« ¼„I¶�lã"O:;?±ê-~š5~òôWÞ±¿¾ßWYu³Û—7 a|Ä8)”±Cò,kÜ*ImƒmSå��TH0ïg�÷ˆŠ�!—k[¹·;û}Pö} S[4ÍjWv¿¦;qòûšýÍ%ä¶á£ÜÖýmÖ¢Úcí„ɾÆñ¶ê²;}¤§¼„ó}MOÒGZVÙ‚|¶ØËáÍmO/i޶hηg�Ywjœëù.gåÉÿ{UùmÑ~ûo÷ßÿèû�¶gâ WÞÃÿü;©-šjŽ%=žç Sµ%K¬qRÙ´Ë{ŽyyŸsÖUf²ÿwÒø±3µ�fßh«ßâ½K¬~Ò|F8÷c§ÍѦ��w²’¾ÕõÞi‹À«3Rß ‚}v™÷|W~åšq2€~Ç×÷ Aþή÷{ëž4ÚáÔO–h³ÆšmÒ^ŸÁ×W Œü”R¿d=B{VÓæ‹÷ïÕ:“ ‹Êd-«ý{�·ï ™¶o2‰Z²—{©L¤~OßÑ…þŒð–�òë1ø¶ážNyùµ?Ó�!¸cá%n÷Ìù8 õ9b>÷ý÷s¡�͸ƒ»W¬±S‚¶DUå×·$¶Ó½oC)¿Jþèª÷­q¬G_%«Rh ÔûŽÇZZ¡Ü›¡„Ѵ⣫´É æ3ÙÛÞK¹¹?ìã5ۘ߳¯s{7�ï‡>ûøâ�Z’‹¹·ç£xçaÅËàû…½¼a.‡ÕÞÃ_+L¡1 íû†UÿñÚÔ9³|Žý§z|·8éïÒ¨lû³eÚ*ë�¶\~ní9Àúv¶/_c!+Íàž—Î’T` ï̘—�¯¼†ònt˜ ÔŸQ”úq t>½p³NøíÏ PÆUš2<óøµ}þÚ­|ó´÷îµ÷MôU¹eØz;Zý‡6þòuÉ[QHóÄÞÊÃs$¡ê­>úè#mÆ ÚŽ;´�;wj§œàkÏ�ï»Ä\?îññ^´G{ß) ›ýö�ZŽG�*ø*I[lû˜ÒW{kEŠK`å[øå)žÚ¯½uƒýá mÄ壵›.7ÅFƵøÇØâNÑ^¿Ü#Ì wk�Lº[Kôn=õõV=\îú7lâ(3l_]óÀ[?hß;ÌõÑÓü0ÿ;ÉÙwk¿exæÙã8Ò–,=òÿ»ÑÚ¸L¡”™oS€•®}3ÉâôÀGN!˜‡ÐÊM˜wû\­P]—ôÜÅ^}µq“&jÜàÁAÏ�™žQnÅÒddìûj7Ý+ao÷ȧˆsmyÙ8Ó·@oÄ‹Ë=Z¡—Cy‰qMZ&Ú&-e€ì:¯¿„Åkc“’´¤±æG“ÛØ€>Låoõö"¯·• ïo•ŒÙ>ú¸^ú$�„±^ÒLôïäkŸ$™ù1öñ‰IÚäÉl÷’:¯}âí‹´,æ©u¶I3U/f¼ ^&pÌÉaÖzé‘ÉEÛd›ý¼{}C3?Î+Vîׄý„ÉÚ„$öÈ0þ C×ÇVƒCBâXml¢ùAÝÉfê tRûdB‚G:R¾ñ?AÛªG|T›å!jJ;ÁàêQþ©KZ‘6¥ -=üeòóÂoÅ ®àÓVÜLñ�Å/^KÐË4ÙY&·Dlåó°>l�4Œû"1Á~ΪK3�ÐëÔŒ¡ì^ ¾¾yÊjçOqoØ�¹ó´ÿÜê^Ž>#“´û'>àt™eþÏú^;˜Ü}ÑVˆˆË]d'~ú&hIÑ’nõ(kßiÚ&›pÇ.Êq�š?1‹™×ª|Ù¿ÊVß2¸ôˆU×¶ò˜ù ÷ÞÎÉ|m_ê.�KzcS9y:¢½à»õxþ茶ìÑN^pÀŠ+ ¶b»vëæyˆ½¤íÜ|k’vÝH÷gô%/ù7yãí�™7êÜo pµïó§|ç*{8ÚµY_*_yÚµÒ½.Õþu£oò¸ï´O·Š€pë"ÛùG´u^Ûß1·º~kC^Ù‡ePgòE02AKJš -Øi|àW“œÔøgÂ4«±��B|�uÕƒçóÀ ì]à!öŠ—g�äóOOœå.–ò>ÎðÞWÙÇ-ÞÄ[&ºÌu–�@åw¦)ö÷Æáà"[_—mïHÞî{8ëÓúñàë+F®|ùpØËa=¼÷ùî÷ŠŒN‚nó{µÉ..SËŒy’ç¸÷K3í0•ÿÌå–Ø$éÍËߌù(¥÷Ó¡ôƒ¡|wñžºu¶üz ¾mØbíÛ_÷€šÄ«¬ïŠáxŽXíÙ½Ÿ ÇxÑŠ;€{%§6s‚z7š©¿•_ßVíùrUä¾ µü'“í‚LÅ4AÆcmý¸qnÉAëÎ 5­PîÍPÂh"¢²žIÎv2Vê*ɳ\}o ÷‡9^SÏ<c_ã½£X[4Ùú¾1a�÷·Á“ö÷Ë@Ÿ¡–ÏìÇÊŒ5½Ï7ï•WïíÝY_Î?˜ µ­U¤ ¸ÆnA|ßð^çsă·Û»��ödFØßÓìï´ÞÓ´ñ ©¾�”íq—ŸfÏK‰6ô1¼�FY·×¼†ònR˜uÖXßö<°çÒWý…Ü׆’O{†Ê¸üöW&œuB ¾Â2�_Ûç¯3¼ÏÏc™Dðbý‡cüe„:OlµºH ¼(ø ‘ç¡U»_KS=¥\ÎHów¸üÌ~ÿG!†æºæ/ † k·6ãwÆ@Å|éqïSÚ7?¬ÔÒ¶ ´<R6PÚ×6KV"®úi�.mÍ\›H«¯öEŠaÌ- Fk‹·ZaJrÒµŸþu«íÝDm·+½ý6¡˜»ˆI•'wÍK®p‰/, (ÿáâP" bË —b:Lûx�M@—±F{Ê&›±b·SÈf³”õ»—ÊXÕRù[l…ÍøÁ÷Û¿lâ«ß=¥í°‰ÚrËXþ²³r¯óÄÇæ»Y_;ž<ßMHöúŠý.Ž–…/£ÍÄßþ¼öÛžÝÚñ»µÜÇý57ãš}�mÔÛÿ’"aòwkRÅGµO&'¸êuìûž|¦zÒ6Áçñ‚Yæ®ü÷:ÛßàŸÜªMµ½,Ø?–¹˜KÔ9'i�lÈ_CÛ-ÙÊè3›æ�ÁÄÔEöÕ²ŠnûC¯o‰×ú«g}%ÉG’£™ÚÉLù¬G�¿òL0®©ûßó¯`Nî\d ªåú,ÛL×Q»õ m­:jÉÁŽ&b}LáÛçG‹|Û$¨=ÿ �[|ò×mKöZñÉß i«æØ­(Ø&u˼\‰hdÑV-óäIùÙã0A—݇œ¶Deg<ÓÆ§l*eÏøãaYQu£¬3µ¾ýh;جP$Ø­å…^§esh�ÉÊ9á&txf©aǗУ¼óî‚�DíÃõöøNhÚ- ›eY!«H7 ³¿RÊþ³Ò&:¼E{Ø&²±D!öü—µ@r~ÊÐÄ’Óü-Úöý'ägªy�˜“,ñ–;×ne¹N,ší³Ås0e•‹ûç[b"Ë—ÁªÏ­/k+RŽi»vûöμŠêÜû¯  *ÖK­ýjµ¨¤=ÚÖöXZÒžVËQé祴Jl½|æÔzŠ m5ÔÚCÔ*œ�>/UÔ¼D«ñU  ¦Tƒj"0Ü �XßZ{ï™õ®Ùkö왽wvþûy’={fÖí·îkþó.iË´reË«n|µl·�âù)iÒÜÓs—‹÷Ö¦ÇÏÿtÏq¡Ð´¥{Dƒáé²EâòAb/%jâVæÆ‹çWòxï³gð¶‹ ‰Ò(;‘ËeËfq+«3Ó±|6ÔŒs=âRñãÌtý²—©åÌŸfR®í¾ìqúÄ`P<ã-ÑàÔŸÆÍâO“ u^_;G^Û!ÊÇé²hMÛj& u�¨Û¾O7’¹<òŒ�˜þ ­Py?¥ÊwAÒX@¿m¨®—Tj�Š  a//EÚò˜¼VkôͶ¾Š Éø˜È“&ç}ööºJãÁÇT�À;ya¸UT0ñ9_qála¢0£¿tïy�j|™,êI·ÿÎÙø2­qRô±ƒ} ½L¥‚/Vž"�ãäØ[¿í¯ê¿²êÄæížù€ûR…,…N{!ÝÔšµÒ‹ÚÄø-òØÎ§¾pöªîÆ,y±±âŠ n½Ê;JQì}ÂËÉ|Í'¬ÈmKŠdÅ.ñð$³¤TÿÀR鯴v×ëqS\xåËÌLû+Ýžç,°�q·6tÜn�,øÊ”ƒŠ7� Ç2™7õ½þÅI.‹±eKBªÕâ.W&EqµÎÛ–2!™#~[mõž\‘ÌÝÕiÁ×Îe\`6El’ñâqTÇM¯ëØ7jËl†¥1’–Ó¶1·»¢ ¾ø¤|›$:e_¾YS^:U̬¨‹jÙƒçºõ›/ìx­tñk$ ‹Q ¿øb”^Èn7,N]d‹‹ìà �2ê]ˆ³F4vrË"½GEÆ"wÜÕc!\ÇÉœô¸éÈx‹‰¤%-ZsB9U. %šY¼ J”µ.õ19ÌŒ›èŠ_Jü¯™ê,F’(šPÀà<þ±JöÀvê"ÛÝ\ðÐaš–;ŠcÜŒ¨ü�e!rØþì�]öçáy`,^èÇŽÏ|‘X/vGÏSÇ_û·|ñ-ûœíS Cü¯í2„·Îf‚-G�¡+£t=zZYà‰]ãñ aXLJ¸]þœ¶ltîtGèÂÝ�u·KŒû™I|L‹?—»Ãì»XEZ&ãÖ‰¤¯]6Úï5|›Íq® ÌØ*‘®‹Óyñ¸uŸàkŸh¨�Ǭ|9yžø>m¬(ž|�xbö[â½õNÐéçqŽrÌÙO˜~��1A[LªxÈrÅDB·ÎÖÛBêø˜¢¶²¥Ž ,¨ìdP.¥ðñViÉê\eÍk”iý-¯]‘ë3g6m‰“–ägOrœÏ_QqH_{­½ÄoJþgm¾æVä¶%95æžÌ?[›Ðέp0‘h`[ê™…©Ç¼l˜s$}^NÍ6'íŸá§mNÊ­I†:¾Ñë¢Á\Zð²Í[¹5$7^[Œ——*,Öµùœ^mïöCfɰüâÜíí÷[sÈ =Ï íäí�Û§(;±’©¿² J:ÜïØãk>(©°¬1TOÕí�™ŸQó‹»3ëWR²,'¢¶UQË<mqá£+ HŒ¡Ô8ŠXû¥¢¾È]ŸQkT–Ä„9©ŒÞFG-U>òkÝT—Ç^´A02hG‚ú¹LÆ‹QëŠ=¹ ùêT9‹»mM�ç¹î#Uºƒûˆtƾº¯ã}‡|á¸Þ3ì¬e¢qöò0ËÛaôôñòios¬ó C¬™½tä²^GfÄÇãl^oË~Ž�ˆly)×-Øú¾+îK#<>×eKŽÂ¹u8Ëssœ&¿ýŸ'ðºf�%úžS¶söŸ(Ïò¢¸ñkxLíù½¯�O¡Ç_x~ÍŸaÛŸ_¯eÆbH\ó¨Ò"èç×é¾"åã/[ý ¬Ï²Ïà/L™ýl ¼I‚¯¨Å m•xÜÙ®Q~Ï«m2|êÚ±J<Ï®?øÈk ¾b�Þ¦•âÙÛ®pÅH±¾X�8{Ý]â­ÕL\$­Zém'‰U\ä4¦M«Åª+Å&e ªIŠ™ÓŠ1?“nx�Fxí3׺ñ¸¨J‹˜7™¾2âK+�Û¦*ÁÂÏÙª'5û±ÓæQÓßïr9¸V˵r‚¡�{„eìÍê=f=íæW™2'¿bßËÄõ‰<§oÞåZã|GßfÆso‚/¾p¥¶ø›SÛ`}xbT„À|’å]Üå×’…PÊk>Àv;Mþæ†|°i›à+·õ•ú�zw‚¡.¤øÔ”éÅKÛÃå”Ü8yÎ;ou?ðNMÞÊ…¿5R2ß/5ub¢SœECÉÁµ²!'Yužù´ [´o‘{òÖ‹-Ê¢XÜœ˜5x�mû Ç6i‹ù(ê«4×¢rç�{ž—r{Û‚¸sûÿŒÂ6ó„³·fžåùcð�·ñkÅV«v<ݺ|GÎS3jI¿¼‚/µU¢+œ°‘R^ãVºN›"Þóq_ó˜Þîö¹Ž�† ·Š­B¦uK´5šsïr¶«ãî<¾²ŸBñÒÚð\lbÅ�[érÄ2I\W³Å+m©‰ ¶ÎžR:¯¸{Í0UÚRðõÉ_#-ë?š¢E~c�s¯½GZõ~¦.gŸf¡x°ÖeI¿³-c¬íbÖ»áåd¾æ/¡Ú� ûÏOüc<Ôí�“µ-Í s¿“ó‰—S³¾¨­t²Ýþñ9i‰aqZ#å–2ÜøJ¶Qçs|QÝol¦5aµ�?¤ö�“òxyøé$YŽ8÷ž±^ "©ë½™}ž·Å< æýÊ/^îÂÌ7•ÛÔ®½ß±Æ—ç§\kI±ÊP�­œyšx˜!òË#ŠK_'`2dÖð\@<^º=‰^æ«ÝzVP2G‡Rãl‰Z$…ÆÎ± Ï]a‚)ªô[ùq= <ˆÐfÐFF'e>ò<Q62hÓÇ^ùL#è]ÿx2Û[?—Éx1j]±§…ç©™ûýæÙ¨q‰š~¾Ýª_·¥¾^Ô7lÍÍ­±µð¨aÉWa"ŒQ£¸1™Z±1—;VˆÝÈóÏÞG¤3öåë¯u•z-i¬gsnáÇŒ‡5ÖéŸL+}aæRD—ƒtðòžízË�;OlnäŸn»”Õ¸ëíuìyŒ›ßi„Ç9ñ²ÅÏÛø™í}¸üæéñ 3Ì<(òÞJÒéò�ߦ¹î IËYZÀÕ(f_çäƒÞS‰æ4C?îöí/ß)c[Až>NL¹e’¸ùFóoÊ�Z€F¤9óø;[Kº3| ù¦°^ –o#ÆžŠâ’2Q5¿&­‡(ž* òI¤Ù‘×ÒØÿÛí4ù"¤ŒcQI©())1ÿJKE1ÛÒoâ�/ï¤ËW8&0Ì»øÖ�“¼…»u¶Š{k×&<ãH”–zÒ"ÓVZ¢'Îî[´r²äæ—|kÌ[3îê��¿1x÷Éåž¿Q¨Ý³|viêæt?|â:löéïËC:æ×ìå�¥›=°Šœ§6_ZX䃤õÛÙÊ.VÏI\2iŠ˜0éfóoòqùiR’@IDATN[ …%Ó-­1l«G&R±‹•R’²¹Å›Í W“tD,Ó–ð-/¹˜G¦Ëµ0¥*œ�Ëqw©�¹ûn|9ù׸U,^0O”Ý5E\¢¬S%ʈ÷{Ú\›U¸Ôi²ågª5¬b‘RÜ(_—8î|Ê£ wÝÒGÝ´hž¬LÚÊNFå2΢aíjñÄŒ{Ä„+Š¥µ¯Bqö¨Bqêi±?Í4ºàKû¡ëjò¹b1{µ¶ÎÆ™‡-×Üm àkº|ù‡“\fæÞ¥Å×Å�­vÅ’ µ/ §ŒœÛr_~,|9å-è»@oõËûÛXÀiþ;›ëDÕÌ2QR\,Åd…¢°°PÄþt¾šã)îw˜¾Êè÷å6zE…º –Ùo 7ž…ac1¤R i:ªÜ-" Ü-RœGý¶÷¿Žo‘˜äp|)GÚB›Ï8)“±wËÇ ŠG¦eJ�õtù˜Í)ü\èqcãã–ç'�O5{Qé…EÅ¢lf•¨©³¿¸ÂýŠ\_œtK$œ=ßv=A+öe;ó;,Çœ) /'ó5Ÿ°"³²$Ç8ÅÃóÉóX�q­h��“µ-Í s¿y9‹Ç�•S6æwÒ•íöÏ(W>sRþƱß´ØÚçsé„iÍ#Ì™>sÒ¨[1î>eÅšo”'O£´�œ¡n‹Y,e‡Ç?T›äDÔ÷›…›F¿ãÆ×ÈÏrŸüäÖÔù˜„…&¿xiaä›ÄÄ…¨ y~ÙÙ«dš’Ú"–NÒ–UÝ>IòÞÂÊàTGñ%­¨&ÆŽ^1DPý®»a²1iÊ~0­üµ·~qÐç9^.ÔìZ˜²Á8ª~>ÜÚ ÓV2ò[§:ÕQ”v„—g[?ÇËm¨õC• lmÒ^æ³ÀºæÞdJQã5ýÜ�=íÉqän²]7eðQÜÄcÝ)ꪫD™\K..’Ö¾Øü±€¯‹ó;–¶ú¡<æí‹r.nß¡î—VÒÜ5ji…I¿”Ü)æLtÖ•¤Õ,c+\å0è“aú´9**9H/ïÙ®×qzùäoPnðü5÷I#<ƒS�«–6Ú.¿È}ŒL,O/Ï<.ö6ƒÕ!Ö^rÿìîLëèî>¼_\£<Ë‹â&jþeÒ×F‰g3¹Å|9ÏÙñüÚ]k×ϯÙóyfÄÄy~�Ž…¯LÖ=¢Œ¿xÝuÚ~ί>ó¶"L}ΤÂíþM‚¯Œò‡¨~^й¸%/vüÈó¯Šg•ØK�«øGÒöoŽ»TQpºTß»›ÖеKçŠGo»‚5 ê¡Ìâ�&)¤âÂ#š$Ö;Nªoîæ›þ‚¯¦×'»ajó‹¬ÑfB$' \�”‘àËÿ@±ûYÜ|Òå?)ìºÑv‘¸ëï‰m.¹5.¨ã }¹³ø0V†à‹-Î8+’¿G¹[gòøß½Ø³g&‚/YPÛëçB)o<ÆN,+šƒßž×eÞ>Ž_gרäQ»5$ÜN“2Ób'-qX,kñpœcÞ‘OœcçÒ¯#çn���ò—ßÏÏÛÂôò¶ÿ.Œoådp(±láä„`~óø¸LÕ-Ü?ŸüP·5/*uÛý– ËKŸÉ´rëûÉ(lÿ šoxì‚/y¿fË;cRé3Á³ç¡~¨¿žÈS/Û¡|M£Ý–/ËÀÊɤY�´•*.’É’à+[ñI!ø±‰�œsaD,Žý½YÜä2, 6Æ,\°Å…1Ú]²Ð…_ãîµ@)•–/²<¦I9â®4¾6n5KªEY’õ/�Vï°Çœ=Ñxñt¬\"nbbC’Ûi.÷‹+/;£ìåQÅéÃÙz›d½í'cf+;Üo7�u´Õo]Oö‰šçØö„)݇Ë/“™|ÎS,nla’’»÷/›öríçÖvžŸ+~îW¸XF˜°‹˜�[ sdù²ðU4q¢˜˜ò¯XL,›ïÎ ‚ûi™tNúå…[¿ö›õѬ¯rû}ö À)Ó…ž·²Ý>)UÍ„]| #þF½ß"‰ëÚ>iJ¸�Ä„§-e}Õu.Ýñ¥1^ð'ñq¤“©¿õØ�»åã•l”)c¬¨ørNÎxÑvÎ’—�cHÇ?�[žŸf|ÚÅürþR„Λ8»±¢¬j…a±˜ûÅYé }Ê–OýØkÿüÆÎü˱OxêάÏ×|ŠÌÊ’ã”OxÆ=Ò:F©[å›ú‰}tãÄývÝ{Ë…ùÛ©ÇÜo³œ©˜ù” 'ÒYnÿÒ*WÕzNæÆ—§ß§>©(Ûêb:a*«%<_V¨|áaJ _ö]êø9“¾™;ŸôXó͈“™ß~íªST¢¶�v†, ¼N¤•Ç?T›”ÄÊ{‚…›F¿ã†ÍÙù0W–;§ºc.ìaaú¸åéuËmPýò&Íó›ûé¦Ã¸‡Å‹å�=¿ ‡ò‡¥Ì˳µ3‹k"Î֌ښi¼,µº~œ²Å·ÍÞx(d?˜VþÚÛ/™äßvÎñûص0eƒÇ7d›n´Û¶:�‘ßÉ©÷ž‰ÚŽ•g^nýÚ3ó¼/ùm0cuÅ›¶¤< ¼7Ù‡¨q‰š~înbšû©r7&S¿~E³–�cè1j$7ÒÊèÔB¿ø˜çu›«òƒÕI[ýP·ð:Âê-çb¶¹RØUâ»H¸bWiáÇÝ�"ÄËÊ* ʲhÆécq�ù™øÇË É&ûéàa™Ìâ‘áLC—µ¨Œ|ò—3²ó¸ÚÒ¢ÜØÆ™~則áÇÉï¼vËÊsÈüöKO¨0Yè矎«äcÃó|ŽýüŽ27 í&�òbeÆÝ…îÇe3”õç”>pÓ×ã}¯´"æ]\žºÈ2vân’Ænl, Ë|eìµn¶}³‚á¤;ú7Ëä¡üŒÄ„§MÆ?›ãK#’¸Å)DJçÜ­S²U¦Œ±¢Š*çä¤Åv.ž,ãÔ1$ÏϤøÈ:›ëEõœ QZ¬­òòÌ-©p¿VF$ù0¿úâ¤[:´±7ý“¹o;{ïòüdšÅùšOX‘Yy’’ôÓ'<ó¾fQ^茭äÖ� SÆ�qâ~‡¬ÇÜïär–ºÍ1êxÚ¿´ÊkûÝøòô³rj²µ—ÉtÂTBŸ¤|áa2Ë–f˜AüÌ»õ/æÎ'=Ö|ãq Y2i;í Yx›’H$�¨6ICò9báú°³Æ—³óq§Ê{ùX§~ò>88Lž^·Üúµ»>)óžæ~†ahM¿×s[™—÷´×U¸ã¦’ùr¼ÔºÈµÞ匟\k=r­F5a‹J nŠEL,™Vôi÷ƒi寽�ŽËÿ¤²Î®ù”+ž�nÙàñ Y—U9�é”S[˜ù�šF&íç`+ϼ܆Z?”QòÛ`–”‡Þ43¾�÷zÝF�KÔôsw~k½ÞXr7aY;~¥]7ò;}7í¢ªØi‹Õw�œ¿TŠê𢶮NÔ×o µÚÒ²[¯ba±ü³Õu¯#ìÎÅ[Fùz9WÆ^ºàIKÒÛÅ¢(gܹL¯&™t¶îŸy:‚Ë;g®¬eÀÈ'ãìýÿó¸zóßqe�û¤^;Ûr¿y^ñóNxFÛÅʪ¾næÏo¿ô„ “µ�~þ¥~�í8µßQæ†!ÜDÍ?î.t?îPOÇI޾Ó|ñçÂûïók¦°dIWðÏÆôó?“ñ—­~ñs~cÞ_ð¶%GEÞ‚€€à+‡…`φj×ú×#¯¾+º©Ä/ê¦pÌ‚éúá±cQ(Ù/nyÍgKÇ[Ó·nää…¹â*ÎF\<÷§¿µåñáê�Åâ¥éY`â¬Ê–2�–ï�ßÜ?Î^¥mÝRý0E=¼?÷®…É�²ão዗ɳï²lOjclø®žðt�=yŽXgáòôµŽÈÆS,÷ò¼æ~ß¾ |dR®Í°u¹¶�ŸËêO8Á×>ñ^•ÛŸ;ý}¹Xý¢Û÷^2c¹[ò"ø’c½Á€µ¹N:ÔŸð1Daé¹¼�üÑ[að‡«Ñû*c_-¾UÖˆUzŒ£¶�^äM(_°³ŒÝ¸õбåµBmçèoŠf®HNTä3öþ×ñ.ˆ·¤¦:ý·1ÉîøÒÏÂMÅ;“±/?Îx…ŸË¤LyÇFF¹qÒb°K!Üg‹øaÆ�†ûå°rœÆ¿-eC]ð)ûœs™£J2=”‚¯r·ÆßqëžsÙû�Ñ|Í'¬È¬¼‘óþö ϼM ‹œõ²ŽV§+ø2Êb¸zÌÓ›œO>å‚E:›í/W~–€ê*'&—+#ýáêâŠr]güÂTmYR¾ðüô�CÖ‹«E(Ðzȸ;í�ç>k¾•Î>lÛÉÝêö…¥ÁéoXxüµvƒ­¿â—}�Y¸>ì¬ñM'?;kÅD9nˆ÷ï|L&O¯®gÌ�…‘o¸ŸaF.ó*\iQÅaP0u‘hp…½…îØ©¹ºÌeT½¥^[EKˆ ‚Òùzª~ШáÚˆàø¤ÊGvͧ<ò|tˆßpu9pì•‘ß©iðº¶álå9“ñb�ß³ÀºÈò4ðÞd^Qã5ý5¬�ó{hë�eÔ°¼þ¸¿SÕM÷&ÏA*7¼½¦BQUo™A2 ¤n½ŠÁòϧN¦7öõNt['ËÅŠÎN&Ú* 'vÍqúx4Ù(@YL‡ô�‡•Õz� #îÖ¯ ÄÊŠù�·o¾s6çsÙ¦^Ã|m½–s âg´]>iá~¸q’I3Ó£Ë3¿ŸÇEÓ`uˆµ�Ü?¿ñ´u ¯=ö=â~Ûã¤�F™¦t5ÿrÐצŒ§F�“£¸à ϯÝ€ÿw6_fV¦Ê^GÂŽ¿¸[§~ñsaŸ›±Æ/Ⱦ2`Ù.·ÏÚ¼þcññf¯í®¸§«^{Ü|-ø8ùž´_|»@×ì¡]èå4¢\,ül[&®w\F‰…Ÿ$»ß¾ìa1ö›ãÄ5W]!î~f™Ø»m)s3F¼aq£Â{ã¶QîBâͯ:‚4ÖhgËÂW68ÄDR,n±JLÙ,�­zò �æfˆñ ¶·T™Â,.š#�,!ØÚ];ËõKïcÜ"Ö>3É=?ú¶Ù¦¿ ·*®;7­�YsòÞÿl ¾Ú[›Es«�èhË|÷­E*ª�K�é|ìà¸Kv-Ô€\.»å]/¨%Ǧ]´¶û¤%ùæØ¾èWTn{0)'«�ôÒÂUY�ë8u1h’PÏ®ÊÅB¿O{k«)nc‹Œ$'÷IeUصÒJ[‘(..–[ÚÔżæñáñž…Ûj=Ï1¢T=µÐ-»%ó�M;‚óÒðÄû#£°ý'hÞ`l¿}yÈ›ù5ž§Ú–n6Á‹œ§Úcë‘|m޸ܰztî‹Æ#©™u³›gê~|ËÁ�ÅV�^Zë'ðÚ%ÖlTÖuøu&ܲ‰dä½\\“–à«%·ñ1ãÏÓ?¶‰U”›¥�]ï²;÷®j‡„?kг–§iËCœ�WÈŸØu�u©²¥©·ðœ;}¼W’">«5,#eü�òT(f'¬“¥ŠßÜ»ôÁHéòÄÁ�½‡åÏiá�z°Tå‚'.‹í/3Eµ<”Ä1^±9iuÑ|øTm SžjÖVŒ¨ 4¾}#�#û'[ÖY¯Å¿j.â£�´„ɸ‡j¢—^§Ã¶�Ü­n_X,içåN»á(R»çwšÇÌ�;k|�ü”uϲœÂE¬f~‡ÉÓ«ësgad¦+ù÷3 ÃÈe>¶å—´è튌ù‹xÍÕn;V:³Ì=žXUŸœˆÈgBöƒ´ÁQL•�ìšOyäù¨ËFôºl´ÛÖ03ñ;5 ^·Â¶#œƒ­^c÷ðòm+£u•:Ì’™3Ýí Jç'„Tgrœ>^u›£#”µtH/yX6f‘ËZ&Œ|òW°ñü÷Ÿû8krýÎÇòðdyuæR<”ElîÆ9ñ3Ú.VV¹ßÜžß<=‘Ãdm`ä1<�¬Ï±_\£Ì C»‰œ™õµ¡ãéÃ.[§÷µüÓ}N¬·/L~ÏŸã&=Ç�=÷íëϯS§/] _aóŸ×‘°ã/îÖi Œúlô¡N‰òNìÜ�oÈ6¾¢mÿH<îl×øà«¢ÉãÏž ÿrÅ^>X%6{Í{ÉûÓ|É-ÿî?�ôCÚOë[÷ñÎÁ9Þ¾ì1Qà.~’xvÅÆ˜Xhá-Z˜5vÚÜ$ÑÜOsøæI)ø’�Ë\îÆÝ®‘uRRÐäˆ�T'6÷cçk´-B'CPU¶$).NZÌïìp0¶PŒ(øÚ»in|1ƵÌÏŸG—ÅYëxs$Œí¢-Θ ¾ö~2[Œvóq cë0–ß«ŸKäõ(q—é%üä|³&ø’':oÝú Ž�…wŸÁ¹§šÈŸl™´Ì®ù„é7 ç¢#?‘ÔœÄÖG…ESE{0šG}†‡ç.bëËò%Ÿ9Zô&ó/+“¾p.' Ö¢2Üx½/SÂ-->âÛÕ8Qžïnÿ$'Y•Á—g°ÂŒ�-×b6Ç?i¢À�¬+‘™Žkp^º~øD;‹‚/^œÁž}–n6Á3†„ÌSÓóWLð%Å2\X³z4eް[sÚ#!<ÓÂ�\Æ'•xF]ãL ÍêyâT·­ÖÛ5rÿ¸ÛS'ÏsÅH ¾ZÌ-<é´ëÅ\1SÍl½]¡*7Ív¶ßLðݸY,Xð–˜+ÿ–®æâ#n�LöuãÊÅòF�'<�êxÍÒJÆCmµ§ýzoÙò˜ÿs—¬¶Z³òúåüæü öL6›‰ÌTú¦y,¦=?Y?Ô×Û5²tHK]—¸ùÈCÁe9j¹4ÓåµÂµKnϪã¬Ò$èsx©oÓome‹ß“ò8ƒrí¶õ¼ ÇCʶ0IŒ·z+OÒb¡§ìyó=VÇUå«ióf±¢¦FÔÈ¿º-ivöfÓšÞ/¾Àå3fIåQPb..x—?ÛÅw ø˜tf­Nk�ßæXŒ=h÷K“!('a,äú¹a‰w·0JÔ¹ØøE¾( c,onߢó­Á›^æ™ï!ï“Q™äj|iä�_ùÉ`ü¶$×=µäõ1Üš�´ÏAª|d×|Ê#ÏG]6¢×åtÆ^QÛ îi³nEƒYËsãEÎØê·Ñ×µ7,O»³ÞFM?�YÎK“^pÝ⬹ªz:QÄv¦�V”ºÅ�ZŸuÅñRlê-iJl]k§m¶1cùçS'ýÆüfùvú:·øËª—»²ñ¯j#ùü•Ýí˜ãôñúÀÛ7BÙJ‡ô�‡e­{ËZFe€�ÇýÊ€ Cðü'Y÷ù‹hñ» ç[©ü)šZ%ꛥ,i.º¹¡VT”ê·IˆJ„3¿pbåÿ]ïšæWþ—‹Ú†fÑÞÞ*êjª˜Ø)^7xœÌAE˜‰‰|;t¢f«&LU5õ¢U¦¥³½YÔ.ª0Âåo„vÖUe¬¸|NŒCó–:Q5U¿U¥b� Δ KEM}ƒ¨¯­ÍræÝ뺤¢ZZ|“e@–ƒ-u‹DI!kŠ«˜E…à¼ôg¿=ìì ¾¼<8+>ñÓiaéf)Å/)4{ÄW0Ž£n³Wnë6îëÖo³æÖÓ¤j¥¶†Æø ™‚âµy}µÞÖ1–ÏbB,ŸßK—½/fWUŠ›®(4Ú’‚¯u¯5 ´ ìÔ)¦¥²5 ôVS±þN>ˆ¸uÆ‹B ·–×~"–¯\-Ì�'¦MæmŠd2®’ ovˆÛOs8¥g)ÌI»U(ÄÄ^ñû䶤<dŸ®Õ¬Všmᄇ«Å‡ëeÉ|zoÙB1�×…+^d[˜—å¨årñ VFM‘åfk">Õâö+x›çVü°Þ¦Ðaã÷�3&xKâ½\û…m?¿Kü‰ç›->½äc±fýV±tn¥¸Ü-3$ζXÐkXù¢Y¶eðŠëé²]0ÕÇ"IrsþLÄQ'  þ¤v&·È¾¹º^�=Tß[mŒ¿âu”ÄÄ m…4Èoã�ï«R¤©Ý3¾˜º(ñt2…'­¦%—xù.uÜ'nju·>’c­Hù–j|™Æ¢º1îÕ´r7¾dãŸEèLƶ1h¶Ê”wlä÷ð'ú8.˜ /ãÎØ»½v&kÆŠò95¢AÎT½im–‹¼sʘx¥Ð:5¶ó)ûœ}¬~JËvNýmo®3'²x&,"9•%Õ·5<ÆJ¶‡Y›¯YÊ^�R%+v�‡'Ó¡¸•Vê9G}õL–wR@äZN'N²&±­d•ßéÎy9K*÷²ÍÐ[ªøò9­Nq:퟾;Õ‘Þ.N¥¡ ¨,67o–ÛÂ-ªà[ïÆù9õBù½.òm—¤¿…%²,o‰Õ©öÖ-rmÌ ·’M°ë«´Sm¡Z>¿V4«º›“²þ-–ߺÍME ~�•yŸ¶“ç›Á!b9Ȥíäí�n_R—톓a xÎo±3w>ììñ›ŸeU²}•Öëkç‹Rw«UYFbóy~‡ÉÓ«ó+5#kòØIîg8†ÑË|,xã}¼.–9‹.‰øUOÕc}DÁTf9µU”¹‚ˆwëZ–´”‡QûÁèmDÊèÈ‹©ò1jÙˆÞ¦«øÌtÊ«OˆÚ_‘Ȥ .ÏÑך‚ýfÌÛ›TùD(�þÜ/.QÓß.*‹ãõ4^'Š9+享Ü墮ºR»uQŽ¯Êœ9e´°¢ÔÍ(n„| ^ëWã銭ßʾWõÙ5U|ì¤{¢XáîèÁøúÔ¿1¿_ß¡sÝËM†o´}úΔG9N¯º?â1ÊR:¤—<,{?å +Íç™0âãq¿2Àq$ŽyþÇê[»ho®|îcä»ÙfN¬�/쩹›|Þ"ë /ËÊ_.ºæ\ž¹<¿yzxÞðûùy�„…i´—ÑÇðÚoûQr\yÒ�Fq£â=ÿ¢õµQã)cšñZ“�¿:«¶tÌÆsü¾ÿü:CÁÃÉö Ýu�LÆ_ÉõKåxôçĪÎèq¾\�òêÏ”÷ø€@|E€æ8ÙÓ´Üv9.þýÈ«ËÅÇ�çÛ¹ÏsÚøéˆ‡V=3™-;ƒñßRHõ^³%ÅGïÙ¯�|ž÷>c–T~ö'|lf-7Å¢ª*¹¼¨mêý6çX_Åô¤‰o}¢DÅ‹¶Hex€›86&Hä›÷ ^ç¨ùæ?¾LgìÅ,™€ÜŒ/ k·ìD;pî8ˆçUÈ2•jl”ª Ddz±—¹ý(³dëöO–´•k«µÜ/—•›êÀ§lpž,ùø?UÔµrö¦º¤í‡Ox9™¯ù„™•-=üœlOcuØÃU_vcÍ9bpœâEªÇ¼�gåÈ�#±­9ÝøÆæ´‡Å%búÓªïr»â˜u/'ޑŠR7£¸¢Æ66a}Wqy•(s„�ÎyiéKÎ A¤uÕœ—cÖó|··¹ªiÕstÕïWÄwœp°¦û�Ëôñ8šm³Ž¿'“tpü˜E­×‘ùä¯N½ýˆç¿;¦qÊ–ç{¦gîS?Ç|y •{÷…3�`~Áå™ûÁóÛo,Äï·ç™{™ÉÞN=~Ö×(sÃ(nT ¢æŸr¥�Ožw<¯U<2ý(Á—z.Œç×–¹žñü:õóù@ _2£"å?o×<íQ¼½I5�Ó/)ñ:õ9±wœo<3Ì´ Âý~M‚¯ ³¿}s­xµâmé˵ìU!æÕ|ì+öRÁ†|©ÎbçÇKÅ“·]˶úKn9n×þýaq�Í�´Xu}Y•!6rÜìmZ*¦ð­(U#zÞ ±=!J²u|÷/�[sýHÜëý�Ù¡ü8ÁMv4N|x;—=ìŠ$Æ?à·åd­˜âné8J,üÄ�qÿön«OÞ8ÆõÓ°ž>N<»t¥Ü:Ó¹6I¬J²r¶^Ì}`’]huº´ô&­®yÓ°}é 7¬$¦»¶—øöZ½�›èi'í Õb*[®hÈG³ô±ëݶ¦l‰7½’ÙÆ�¥Å3» èÔ17‹§-Œ×,yÔõsšÍOŸ¸XãºññÄô›ÅÙ†àI×ù³Ç\/Ê«Þg–«Ì|^Çâbä‹ÃºÕÒªÛ”ëSŠËΧÂYÎ,{9á°2ArëKwûOçºÿ÷âš«•=‹ãæÕ ÙÖŒ$N�¤·ÐTÜjæV$[¶‹•3ÙMŸgt±xû”e'?—Ë}bÝÊy¢˜[K”yU¯æ®VL¶Š2�…¶tÊJ(fœŸ÷8B¹^Ì„u<¿üÎÇø­_-Ê&1‹g ª½º|JeÊmD߫ҢԳ=Öé”ߟTëzf'ØÚÒHçäÛ³ÅN¼‹ìc–Tþ÷'rA£~¾˜X¨ëµÓž«ñL¼+o3‹ ÝvE]W}w°ß>}UŠñ`<-òMø‰ºo((™/#é?†äéçÛÙ¬Âòñ]äE8ßñ¥•޽|˜$‘ýñe˜qRø±ƒß4j™RüÆFAe ü8.˜ //f=W¹§2á�Y ä8xæ|óSä²áSöùÂ{ù¢QiXNħ HTT7ð*|ìžr˜õùšOX‘Y¥Î|©6µ¨\Ô¨·ú]ñˆÎâ’ Ñ�ØÆñ28NÎ�²ˆ0Oô-÷ÊÛmŽUnÝ0_¿”dkÿø½AÇ ±9Y¢N0*;QTÊšÚëôX»h¦W€%Ê„žÏ%bÓ.­3”걙ө%bN­õ±°2Ã#*J,sYþ+¥•ù¥ÎµóazJ™´q�£”ƒ¨m§_[œªì—éÔý•?¾`v¾ñUžªü”å@oó©ê¦\ �–ÕeéÎ:Ž|�a…»GIp˜¾íyšõË–ÞŒF-ó225åúáyª±¸6'¶6Sí]bܦÓÐÊ8†{©Rû¾tÜFn#lß¾ù˜AÙH„¾.‡é$!¼ßŽKÿï¨íHpyv ?^ ö;d{ã›ßNý¿3�KøôÇbÓ*­¯–°z›¨›ª~O­LwÄS%¬(u3Š·r½ªûl¹†,­‘ªOs�i95Ýõx¿1ʾ#Lþo¥îØ®P,ò:¸·ûä.}¾ý‘—ì¤#¸¼;�F)kÉú«×7”0½�^/‹ä.•Öú$-”YÇ‹�¢Æc1Ö)³%Ò‚y«Ü†Ôw”Té׃ù·÷~ùíWžƒÃLÝ^f2†÷Ë ¿¸F™Fq#‡‘òÏIO”¾6Jûví�ÓŠ}ž«]Ô¶­�ÚÛ;¨³«‹º¨õ4�Ž:”öóÜêó³m[íh툹4d( :ÐçN}º£m5+72L’aqì148ex]ÔÒÔFý¥×�]ýhÈÐÁÒûtl£y^z(ïLƒÓ�¼ëEæ\¯Bt­ŸC_9õ2Z©Ü]5‹vß;ÆL›Å¿Žm›¨¡Y¦µ¿Ê¯ÁtÜQƒ-wùœêj£ ·Éü’Ÿ~ýh�t?ÌËÓÇ)?}ÀAýèÉ:ãOWµµ¶ÒŽöv™}*>ƒhȰai—¿äðeYil¥þƒdYéì/ýò”•d¡Î´µl fÉžú+|ƒè°#†E(oÞ ;hú™'ý¥Ÿý¤ŸÇI?½÷äà·* šYY8Œ†¥É«­¥QÖ{™g²´r –"Â-²~J`��2_†Xyu´µPóUmÂq’�QÉs�þ„—Ýv<"§6ƒ<åaÊÝ5©=Þ¥òÓñcYg·mk¦ŽŽDŸ1p�lC†Ñ€ùµsÛjiÑõhˆthèv;9jÉgºh[“lb}GìÓÖu_|’cè{&Á¹Mr¦NÙÞÈzvL˜¶Þ×ãô/ìÞÖH-D%?9,‘}o¶ó©‹vnk¥öŽxÝ��A"”§ôS”ý;w˶«¥M·]ÃŽ9Ž QRÅ(J¹Ü¶iuôBýºÚ©ßà£i¨§!íêh£Ý²Hõ“ýw˜:›*ž¡®uW¹–maSÓê�}Šê«‡5< ½]ôÚä/ÓOÊc£1’[¦ÒŸ63R¹hØàB%·§ßܲaµ÷Bý;ey9ìh™>3ͪ¼¨&H•—œ4Ñꢗ&�I?¸'žorÛ/ºä3fTmËî¥!_¾ž ËjèïÎŒjo_¦™Ô,�Th‘ËTc£îÇu´µQëŽÔžh_6DÖ�ãà4³!è¶•\N_¼öÉØmrëšp¦œ‡É:ÚØœˆ‹c=|Xà<2(ëõ¬Ï׬¡dÿdÇ2º|З)F­°œZÿþ3R³×¶ÆF’ÛªÉ 9B¶}YjàBÏS–û 6'½ö/,Ô.5à“\Ô”l`‚KË?¦Ñߺ)æ•ÿÒÏ ìk‘ë¢,_--ÍÔÚžóv7ÜOO‡œ—ë5‘ÃÒrÃÝçê8t9�‰ÜvZTv¬ŽzÀÉ®Ø|£_¿ØÀ#Ñ–5Ò´oM7-�Ñ+ëpU¼gÙ<3ŠXæ3Kw Ýûí#èúc©ºµŠ¾\Å|ƒ‹ÚFn#|c’Û|ŒR—}£ê¹� ¿³ÛŽx"¬~fq¼hñ=�S¹ÍïÀDM¿t׸E��8zxð¼*bXQêfh7rì²nK»|VÕ_Ž…ûYÆžòùJ[|,1X-$åøÓµî%:óÄÄŸ©WQçƒc3 ç)}YOGºÜ£”µ<1Š%IÎ}64Ëç±!ã :þ3²>¥J«ìo·4»ó¶´ê_*ÿzðµLÆð¡“enÑM&ù©¯ Ïì¬5%ç€Ø½‹D×Ï<¿N^íó òü< ÿ:à`ù�8ÝOÈüWÞfü•§çÄé2Â}û �¨z«gŸ}–N9å:ôÐCéÀ¤ý^ð¥Ä¤#ø{ÚItú=Á�*ÜdN �žú'PÑÓqŸ]ºž~zz+/™G(mTg©:M|@ú�=R`´mg$íu߃��ôy»W=FŸùÚUñtŽy”Ö̺‚õ¤zð è {ˆ®Œk In;�²gðÁ�L¬ûÇct÷_ªé�ùÕ4fÆ|úõ7=¥o¥ì翘èç¥h³YŠ6ÑòE#ÞµAŠ"Ž—¢ˆ‚RjXñ[Âh(G¸èIÚhÖåCh|bŒ"wa +|Dé=)ÖÉqé+éHNÎä�Æð9„›®×¹[k{;IH£0=ãÓ{Ÿ_¨Œ•H£%ø€„'ÁWxfYs‘ŽàKY÷’æ ¥•/<ÄÏø <êjÛDUÿ{ �ûãâ¸/çÍ íÏ\fyP•A ¹r*•™ʷȉú–¥‹\á‚¿ Ð lk´G¾5…€ô]]´iy%][8žÞH$RnuI?=Íßt ÑC 0ìé!E¡‹6,{–Æy<-HÄÈÏêL×G³¨ÿçÇË»ÆR�´h¡Œ"ὑ_r­O ¾ÒoÿÒ#¶Ž&p"Ý“¸¹¨lM/þ. —Ö½º:iÞC7ИëORi"ÕuÞM'aÍ<=´¸+�Àº—&щ?pKÍ©�Nß1M¬¬£»/9)ÐOÜ`#ÐAÏIáæeU.,—ÖNÕÚ©Íoœ�î'ÐÕ¶�^üýxúá� â�û¾üÓýq b_IG˜4ãÞlÀ>[$£ú“뵦}Ò¢íÍÞüüú€ƒúËÝ©¼¯òFÍm¸�ý�_yÌó´_2~=KœG`y ºcÕ,:ôÌë<1E³W¿@çÛ VOåÓΘ:úÀ �F=IÄO�^E`ŸÜ¸YоÔ7>  з´Ñ_þë0ºöY3U§NžGó~õc%ò*·rì�a� +/¿Ì·Ÿ�(”Χe¿5ó͹FR°ðÁêMD‡šF|vA\.8èu øŠ�e\ð•Õíà"Ä%c'Ú¿4ÃÜð·Ûèøÿ¸Õ¸»  €V®Œo—ë\€•D‡¾³G`Mûâñt“QÔ H–¾øö\N@°Jå�ˆüݲîúd;Ñ1'��‚ÎÈÞÀ!€ä•€aáÔ�I!Íi˜Kß?® }žÀ>irg» vï¶ñ}>åH €@ß&ÐBãHºå}�Ês'¿Hå¿klå8 ?‘ÚÊQYøÂ§'h¡{¿x]Ï �-­¢ŠßŽír{BÄ¡×Xvï·éË×/ˆÅju3ýúë0ffÛ2úö�/Ç-”QóŠ ½x;¸Ü¶jk½_|ëJzɵ ˆ*›N—œin·g»ç@ 4�¹­hÉ/èÊ{¬¥�ЦVÒÔ.¡^ô?48H�@Û²{iÈ—¯g7�¥ªÚ ;¢ç?Sa‘¦¾’ž&ç‡ÆðùáÞm¡Ê�º„|Ž/ºº÷ÁL¯~~ÝÐ_¾Ý±W·SÔ7 @ð•Ç| %ørâ)ÕÁB™nɃJ؉Â~ù-Õß+k×Ò.ÙO÷?ü:eÄgzøC*µ…‘4o¡,z¡£Ü/‹, j'஽DJ†]�Q@ú�Æ�VÒÚ­;å`ì`:öӧРËÄrÈs�ú“Þå7>=‹€Ê·�e¾|0wÂ)ô'ßzV4È:�ŽÆ�è��¥¿ÓIÿv&,´¤E¸ƒ>Zö5Êy÷ÁCO¢3åVq½ù“ûö¯‹×ÕÓ¦¦ír�¢?mÛ°“=î$:õ¤ø{½™âÞó tµ5Rý'ëi{ç!tHç6Ú&%ø'�r* Ü{,¶ô|ʈ!€ôrê™ÊûÑÎØØî¸^ðLŇw_I‡Oòpº» ` ßÝÄ»=<õ0Fì•�ñå7©¿zãókiÕ+f¤ϯs\8àýþB‚¯<æt$ÁWã‹ A@@@@@@@@@@@@@@@@òK‚¯<ò‡à+�ð4€€€€€€€€€€€€€€€€ôB|å1Ó øÊ#|                 ½�_yÌ4¾òAƒ€€€€€€€€€€€€€€€€@/$ÁW3 ‚¯<ÂGÐ                 Ð ôÁ×Ä »z!¾Ì¢\QQó`üøñ™y×                 û�{^èKçoŠ„Jï³Ï>K§œr zè¡tà�ÒB~Bù�¸ÙQœýü¼]Qœ÷j7•••±øÿð‡?ìÕé@äA@@@@@@@@@@@@@@@@º‡Àý¯ ‚¯îám„Á—�?@@@@@@@@@@@@@@@@@@ð(——!øÊ%]ø                 }�_yÌS¾òAƒ€€€€€€€€€€€€€€€€@/$ÁW3 ‚¯<ÂGÐ                 Ð @ð•ÇLƒà+�ð4€€€€€€€€€€€€€€€€ôB|å1Ó øÊ#|                 ½�_yÌ4¾òAƒ€€€€€€€€€€€€€€€€@/$ÁW3 ‚¯<ÂGÐ                 Ð @ð•ÇLƒà+�ð4€€€€€€€€€€€€€€€€ôB|å1Ó øÊ#|                 ½�_yÌ4¾òAƒ€€€€€€€€€€€€€€€€@/$ÁW3 ‚¯<ÂGÐ                 Ð @ð•ÇLƒà+�ð4€€€€€€€€€€€€€€€€ôB|å1Ó øÊ#|                 ½�_yÌ4¾òAƒ€€€€€€€€€€€€€€€€@/$ÁW3 ‚¯<ÂGÐ                 Ð @ð•ÇLƒà+�ð4€€€€€€€f‰+@IDAT€€€€€€€€€ôB|å1Ó øÊ#|                 ½�_yÌ4¾òAƒ€€€€€€€€€€€€€€€€@/$ÁW3 ‚¯<ÂGÐ                 Ð @ð•ÇLƒà+�ð4€@Œ@ÛîvzËzú`Ë'TÛØ@Û:v‚L3x(�þiq´ü~< è×?¡ÀKˆN`¯œ4¯~Gþ-§æUoS{Ó†èžõ1—ý ¦aŸÿ" ;ùKtä)gÒ #�éc)Drz"�Ž®=T+çêñùú'Ô¸sGOŒf¯�Ó²~Ÿ›«šN;ú:äà½>MH€Ø _±QÉþ¹#[ÿ=U®ŸŠ~%û€á#€€€€A‚/G÷þ€à«{y#4“ÀG[7ÑïæÍ¢¶Ý4xÈa4xØPê�…MR–~u´ï¢�-ÛhçÎ6:aèpºíœËh˜\TÆ@@@@z�öæÍôÆ�WSÛ¦utÈaCiÈQGÓÀC1^uò¦kÏjmn¢6ù§>_þù]tÜYç8—ñ Y'°¥m;Ýòzmnm¡C‰Í× ”õpà!ѹ&Ò¦æëm­4TÎÓo—óõO~Ѐ€@Ÿ"°¹m[¬_ÙÒº�Ë~åP¹Œ~%7YÌûµþ{Û9ãe¿rdnƒ¯   û=¾òX øÊ#|  @7Ïy‚>nÛJß;–†5Dº�@Ú5ôÏ×^£1§œA×àQ7G    éxç‘)ôÉâ—hÔ¥WÓq§œžŽ“ýòžŽ¶´àñû©mÛ6óà:àÀ÷KHtî Ü#ëãâuÐÙÿy}ê„r B ­›6Ñâ—_¦i‘å·ÿñ#�>EàîTÑ’õ¢_éÆ\mÚ¸‘–¼ò2}ñèÏÐ-ß×�!#(�ý‰_yÌm¾òAƒPñ_î§�Ç}оö½ïyhtÑú—_¤ú�»ið—¾KÿöµOy®÷ΟmoϦWî™Ký Σ1¿ü.’§d¼þÔ,:mðpº©ðâ<ÅÁ‚€€€€€IàŸ¸Ž:ëéÜke\èj©§çÿº’>’V!Ú;öP‡ÜQnàaƒé˜c�¢Oü,}íÌÏÑðƒ '}þLJoü�–Íþ �÷p5©­ñ�\¸õõYÔ@»é;{ç�}s¾N´•Þ¹c­XEtFÉõT0âð\` ôsñ«¯ÐÀít÷ùWÞ‹@@ 7ø­´¹ñ€NúöEy¢�~Å$«?KÁ× ¶Ý4ý¼«²ê/<‡_‰<|Cð•è@À%à/øÚI‹¿{:=³�èä;_¡ ¿éºéÑ[éãE‹©©ÿ¿ÑW¾}¢'ª»é�Ÿ�y8~úGo¿G£Fê¹§{~BðÕ=œ €€€€@úü_m¼BG]öH �N¤ûŸB×äGœ‘"b9»ÁWÎÐÂcFÀ_ðÕçëDû>šM×�øyœÀ ?üåÀxt×!_ÝEá€t7Áú•\æ_¹¤ ¿A@@¾òX øÊ#|  �ÂÂ×NZzÑéôäËDÓ_¡â_ôÁ×î·gÒ/ÏšB4òw4õí+“,x}|ß5ôÇæÊœ¿�~Ýr7��§—ñ!øBåèi|_u¯ÑQã�Ñ=‘~5ù":¥sí Nzÿ_ é‘…õn2žªz†.<á`÷w_>€à«/çnÏI[*ÁW_œ¯SË›ôÐÑ?¤•2 ¾:ãúIq~Ö! øê9u1È.�T‚/ô+ÙeÍ}ƒà‹ÓÀ1€€€@.@ð• ªiú ÁWš p€@N¤²ðe¢¿»q3mÛÜHí;‰>| ýì‰tÈÀQïØN›k×Pû¢ƒDƒ�9–?öp:Ðãd_ÇNÚÕ²�:vuõïGý ¥Ã‡›Ö¹öÉK»jfRÉ(%ø*¡Ûßü/Òµ›öÒAÔ`¿„�]Ô¶q+8ìS¾ñJ7 û”ß]Žß]´ý£zÚÑ$÷·‘étÌ tÔ±füx’ øâ4p     Ð ¾FÓ[oN¤‘lûÆç=I_úõó±èëW¤×/ýœNÊÞ6Z³v 5µwÉñû!tÔáCéØáƒÉ™;7víÝC]r\=pÀAr»ÈFªß²›ú>„Ž~ tÂÚÝFJ¿¶wÊéÀ ƒé¨#¥_Ã’ýŠù¹·ƒ6nh¢M;wIYÚyï‘ô9nòg/uìÞKý‹S׎fúhöX‡ 9„>{Â14Ø ßã‚/üÌ �l ¾Ò�뺉éöùº´òÕ¶•¶·ö£ar]ÀöI? ]ÔÙ!Wˆ­/ìkÙL�˵ ¹ö Ö*Žüü‰4ÀÛ%„àËFç@ú�l ¾Òo“ôö×~[:ö…êƒ4€€€@�&ÁW³‚¯<ÂGÐ Ù³ðÕöÍ»î:ªšõAÕïýé:ÿ§g$‰¸6¼ü ÝyÑ�I÷]F%­¿§ã¤P¬ííÙôÚmOЂ—ÿ™|ß7PÉ#è¸aD�}眓bñÛýÁﳤõ¬:mËktÔ¸ä9)Ð’º¾alÿØ!·¼4¶ý£³]#|Ýúàc4ù«¦uÜŽ�ÑЋñ«;¦ÒMçœBƒõ®Œ.3n­ëñªçèG'˜7-xø·ôýr%຀–¿y}A^ÖnFË­*'š[UîXIçÞJ‹¤‹‡ÿ"ÅiŸUâ4ý�àK³ÀQîd.ø ?×uçÌ2YÝ=_çólmá+|TŽèt\(E]w›¢®–7èÞ£/‹½¤U´Rn9ÂÜÖ‚¯Ü•iø  �_™ ¾Â·Éº=Þ�û¾ò[ð:€€ì øÊc&Cð•Gø@ ‚¯Íô×3¾F¯Êg'ç½¾”¾ÿíOy¨ê…ÇÚÕö¿ßK·œ3]>º�n{™�t<ÎåÏÝëÞ¦wžý}²f-mÝÔF‡ÈÍ_Z—Éí?�W}_† Kûé.2×ç�/Dÿèí÷hÔHs�xÃC“èÎë^�Ì<[G&¢Á—Î�€€€ô Á‚/¿xžEOýe](EQß|–þÏÅ7`¤Ï�¤o ånÞ¥EoÅÛ_÷ÍzŠ®a «ˆéWgÓ}Ì›K/û ]|î¿Ó÷ Ž!çÕ7ÜÏ_JkŸGDzûÕaÛRˆv™¢IaÚâ:K Ñ\Á×è_PÓÝ߉[ sÜí^CWþ{ÜR™Ž«s¾4 å’@悯ðsÝ|Î×ù<[ ¾Â§Aå‰;÷¿àòe°K\ëÞ±üê�VLJĭŽëptNBð¥Yà@ oÈ\ð¾MF¿B´‚¯¾U‘�è� øÊc¦@ð•Gø@ sÁWW=½4h4Í•,Ïû{ }Tb+F—íNZzÑéô¤ÜÖÑ|­¿ïšvƒtác…Ëu*š^žFS.ºŸŸ2�=¢1wQ×ti'ÖëÒ`_ˆÖápÁß:Ò¹‚/‡¾A@@@z �t_ß}ÅvJL'x_âw|h{›v!­”¿OžðúÑ/¿GG ?”Ô³¤Ö>B·|ûÎ$ÑXÊE]éÎ~=|¬ ÑN¼å7_ A@@@z�`Á×YT]]Bg ðON£´ðu‚²ðõ•«iãCçÓ0ÿ[W‚_Ž;šiÅ»ïRåcwÓ} Ka—þÏ}4sì§É —äöŒÕr{FO]q—ÍÂ_b|÷0 ¾zÙ|Ý>ÏŽ2_÷›û'2‚¯VÒ�î"�±à ýJl7‡¤—{ƒúXøê®"Žp@@@`¿%ÁW³‚¯<ÂGÐ é ¾¤�«8IÈåÀÓ¼hôïhê¼+I?-oÒ½Gÿ�VË3…YB_p¼]És?�VÁ¾›d,îÜgY„aÛ_Ÿ&EcÒò—Ç’—ëÆ¶mƒôÖ½n¸ ŸûBt<Þê?_šŽ@@@@z�t_Îvˆ~)Òªé¹Ù¤ó�I˜þòs�†…¯d§Z$vþ¯þHÏ]ú9ê¨{�†ŽS[6ýññ?ÓuÊz˜þ,yü·ôeÊBØÅôþ›Eô9-7®|iP8êQÒ|õ¡ùº}že¾î7÷OdoЃùW_¡�;Úéîó¯îQå‘�L ¤%øB¿’´–­¸Û×”9Ô¯@ð•iÑ…{�|Êåe¾rI~ƒ(þËý4ð¸OÑ×¾÷=Ï­zQõä›ÊèGWޤ½í�ž{ˆ:ò:ø­?Ò­=»VpçãTôËÑqÑWÛG4ï'ÿAUr;GeÍëÆ–‡é³ê¹KÛ»Òr×ù1Ë]D_§«ßžAÿ62¾dgãG´|ö'tÚOGÓAïVÐ/ÏøMÌßÂ?¿Bc<’úwí¤ {–?o mPW<ÛBº“oº�nÜr7}Všصq+õ?öHê/ow¯‚/¢–—KÃ¥�4Ÿ‹ÿµœ Ï8<Oç_ |ƒ€€€ô龪K _ÆžÔíþ„®û÷_Ð#êôç/ ¿þqž�_ín£%/¿H ‡ŸK“G;›.jñ–uKÇ–÷é÷O®§1?ü3˜ú)w}B¿Ÿø *•V¾ÁíÝD¿úêµtŸº.­x½Tõ :'î‡o¼@_úï'bWÜûå/¾bHð¯HGðÕ—æëvÁW”ùºÿÜ?–ÝAæ!øêÁµQÈ„@:‚/ô+–µl ÝoM9–Aý _™[¸Hƒ_i@ÊÕ-|åŠ,üH‡@:‚¯Tþwç TòËãhÞwå¶Ž �;GPÁCiåËÿtNÐ7þ<Ÿ~üã“ÜßëšDÓ®{ÁýM#¿NGn£• ?ˆ�ûÑÛïѨMôü Ñ´@ße9ºŒJZOÇ%¶…ìüà9º¡à—‰ûFÐÉ#? ÕòE~G”å?9—ÛD„JCjÁ×úû®¡i7Ì�Y ›:o¼iõLÆîõ§fÑiƒ‡ÓM…[Ò„S     Ðý²"ø’Ñ^3ïQ:í×±·>â‰øÊYtþ¡»è•…Ê–úœCËß¼–¾3þ•Zðõáœ{èK¿IL4>"}kèZô–ãÑSUÏÐ…'óµñíè„«ãÂ.ub¤ ÷ˆmÿ¢Eu±Ëòß´¼ú*úBb»Ç”‚¯]kè’Q7Ò+Ò•Mˆöá£e³ÿBç=\Mý™ÖÄœÐð ™HGð•*ŒÞ6_÷|‘ÚB,Ô|=àÁ<{ ÍY+àCðÅqà@ HGð•*¹èWä‹Éž—ˆc¼‚ú¾R+\Ⱦ²1ª|E%w Ù �©àë«3^¡Ÿ�$êÚLoýÏ]ôøT&âŠEðëtñ«wPá9Zì�w}üôtzêòûã–ºXbN¾¬„.¹çj:nX?êÜø&½tùi�+&#*˜p]tÇÿ¥ÆßœN÷ß{Ý"_ŸJ¾ˆ¶Ó[?ÿ=þp\8÷výàÕGè»ç°í$=–Áb÷…Jƒ|ýHZøå±ðµýõ{å–“Óé¸ ¢›þø]:�¥OBð傟    y',øMÕ‹'¦¶ð•HÅš7^¡Ÿý÷#´È›ªÏ�¦û&^H—Ÿ}"ŇðZðu߬?Ó5#LñTãÊEôëû¤5/ó3’î{d]s†c),~u£¼ÿ·ÝM¯¸"¯øùo]|5Ý7é|ú³Næ ¾FÿŒšî>—“P�&2‚¯\–jø  �O™ ¾Ð¯HÁW”~‚¯|{„   û¾ò˜Í|å>‚ ÁWD8Ûiû–êÄ@êl%rìáIb'Ãç®ÝÔÖØD»ºè CÒ!ÃŽ¤cµ·u¶í$µË>À®wѾ®~t`Òí]Ô¶n+˜nŒ�ä�°iðºOã7_i@Â-    ÝJÀOð={©¥±™:ú ¡�]»¨kÀ`~˜)œJ×ïŽ]Û©qÇ^xÈArî°—†sDB0f÷¡¥E†KËp÷Pס‡Ópé.›¾²I~ùð|ù¹8v®»ŸÎ×!ø (G¸  Ðk ø ¾"& ýJZàCð•'Ü   �_ÑÙe삯ŒÂ� d]ð•A\ö'§|íO¹�´‚€€€@ï �}ÁWïHw”XBð…Ü„%�uÁWØì§÷CðµŸf<’ û�¬ ¾öfÙH"_Ù ?@@@R€à+�_ƒà+Ç€á=€@J×¾øuHß¾ð¢”÷ábötuvÒœ?ÿ™¾|ô‰ô«ÑfÏcø    Xz÷ÚñÑr:âoé ~ý3ð©ï;]öêsôaõ:ÿÑ7é ƒÝýåû~‘Ân%0eÞÓ´ª­‰¾Ùx:ð ìZ©ëÖ„ô¢À„4ïÙgè(ÑŸþpÞ•½(æˆ*€øŸ¹OQÝ®f:÷ÒËЯãÊʱ~å™ghøÓÿþçYñž€€€€€—_^"Ýø‚¯n„� @’¼Rû&=ü¯×鈣�¦#�=–†y<,’@eáDûÎ�´}kmY¿žvîØA·�3žFsb|†     �9�-+ß N»–9œ>õ¹“iè1ÇÓ !‡gîqñ¡kÏnÚ¾y#57ÔÓ¦5«è3ßú¿tÆ5¥}$uHFO$ðæúÕtÇßž¥!ÆÑðã?MC�:JnkzHOŒj¯�ÓîŽvÚÞ´•h›œ·O5–¾}RA¯O œÀÒõ«èοUÊ~å:úÓÇÓárý '”½ãÝíí±þ¤)Ö¯l¥Ißü~ndö€O    À@ðÅ`t÷!_ÝMá�x ,\ó.Í­[Nïm^Gûöíó^Æï, -%œqüItþˆ¯PÄ^Y$ ¯@@@@²A ñÝjZ;÷iR⯽{:²áeßòã€hègO¥ã¿>†>÷ý"i£_ßJRÓãÔ4|Ds>¬¡åÖÒž½]=.~})Bý<ˆ Ž=‘Î9ù :ûÄ})iH €¸j>©£Ù«–Åú•Nô+.—\¨~å‹Ç~Vö+ÿFÿŽ~%ˆá'€€€@‚_y, |å>‚0tîÝKM»vPGçã<~d‡ÀàƒèˆCÓA˜á €€€€䈀�sƒö–ÍÔ¹sGŽBè}ÞÔ :ò:HŽëñ�î&°W죭;[i'„˜9A?HÖï£Bêá<>  °?Ø+_úݺ ýÊÿgïmà³(®ýñ¯ÞQQA%QA�¶…¦P.-š^˵h­B«`óó�ªå–Hý ¾PhkƒUðš›+"Qˆb£‰À€ &©$B �û?³¯g÷Ù}^öy€æÑ°»³óræ;3gæœ=sæxµµœW޲2_‰€D@" �HÜ�_n¨œ 0iðu‚€–ÅH$§$�ggÐܾ¸=é¦S²~²R‰€D@" �H$�Ó�¢·žCcí\;õ¿Ow(dý%­ �7¬†ðó`òO[Ý’X‰€D@" h™¼¸á=èé7Žo™Jª$‰€D@" �œ$¤Á×I^+ ¾N"ø²h‰€D Õ"°¿é ÞØ¸ïÑÑâ÷›ë„ŸÐ1‰Ò{V«mRI¸D@" �H$‰€D áaì½©ÚæŽ±‹Ö¡c÷ó‚âȉ€D e!pðHVÒ±°oÓŸøM<·]u:“-ù“H$‰@´ˆ#�ß¡cÇ—½^MzÇÕ#ñsš[ÚË£µ£…RÆ—H$‰€DàE@|�Ć•_'|Y´D@"ÐjØKGM~·wJkvcûÞJlÝÀ¨K“�JJãÚC x­`Êk«põ…ýp)³ré¹¢ß9 cB»VSGI¨D@" �H$‰€D@" !аëߨñÙ{|¶ —Ž�Œ„ÎgâÛÿy�ø úÜ8]{õ“PI$-�ªú}(£#`ËH^/%¹ý›ÝßcÄ%W�¼žŒ3Î8ÿ*\�Ïÿý-÷¼D•×ûŸÓýI^?‡ÆµüI$‰€DÀ‰€0óÉw5»°½º…•eH¢9äÎkG«Q_ÿ*›i­8„ÖƒH,ôÀbnéÔ®½3+ù,�H$‰€Dà´@@|�Äf–_'|Y´D@"à‰€BoEÁ1r“}Œ®â^ü'îÅßÑcGÑ|ì]�ÑUÜ5ïÕ0J×|T„Ñ;ºW¯G)L±Ç;¢§3òÓò:†ý� Ø{ð€úWs°]ÚwÀe$¼_Öƒþè:°G/tíÐÉFÿ®u(®Þ‰Rl¯®P�Ã:¶k‡sI‰|nçnêU€µmÓ mÚªÖ½ÖV 7î­x ”ÆëÏC(³Û¨mpý'îE˜úg£V>H$‰€D@" �HZ? ­õ’ Zû+´¶WÿÈ ƒ¸3ÂÌk3މ8ô|¬ù0ï¯EÓ�íº¿F½oÚWƒúÊrt8ë\\4| z]?�Ï»Hê“Tä­ÁÎÏ× ±nΤ�|º�ƒöô'®êý™g£=ýµ¥~gÐÚþ ZÇŸAÞÔû¶mцݟÑ&�žõ8t/âÒ½õ7ЬÁ)�@(Y]Èíšœ®Ëë†,®ÊîZ˜!s Ü�çÅñX¶tôΔ÷I†×d{Mž?BãwÉëBN¯!™½æP=º‘l.>¶«›¯èƒûe$¯ŸÕ±³­Dšb’ÓÅF.ññ^läj$> Œ¾„Ì~N§®èÖ± É醮Éàš¼m„µÕäù3´«x׎ƹ!«[WG|Š×–Òˆ¼Ûˆ?!£‹ÿèjÈìª/Ç¿­ÍäƒD@"pz!`Ì/š>ØÐ[za1/pý¯ý^Óýz^>×XéÄÜbÍ/Z\m.:xä°:§TÓ†_1·ˆ¹¦?mèúߤ Øã"ôèÒÍÖ ÕäöÛ=B\¡Î/¥dÖ¾m;Šg× °¥»Õïiý—pÍê58L�Oô÷â4‰vO›c´¹DÍ�æCç«é‚õyEŸ_lÄʉ€D@" �H$Çiðuœ•½4ø …Ž|'�„C ¾éªIB®ð‚UÝp ‡UZÇGŽ5«ŠÚ#ôÑEÕj…«÷â�G ×Þkñ„p¯)?ue¨®5XoE*¢u#)C@&Åj‚®˜5 ®4C*-ž¦¨ŠÙ68³CgMé«+ýìÐu¨c†c€¬©ùˆªÔÊmw%„¡xЮš""8ÌPŒ‹÷Ö=}è¢25£8º× äD˜øŠåvô!I( Dýŵ}põõ¬½K@'2V;—”B~]…¢C(Äå'©p£D¾—H$‰€D@" ‡€0Ú^µö}ÿ-öJp¸¾GIÖh¦?q5ïâ(ÉG7©Wað%ä²–ÒŒª„ÛÖ–6l´mß‘îÛ«Wa€¥>‹pý}›v)ŒÂéÚ†ÂÛÑ:÷Ì‹.E·Þ—¡�㣞“~qÔãþÛq€þŽ�áÉ1òqôˆAWŽ éã¡Aë1ãÅ;¦Ó.ŒÎ”cb­®­Ñ–2£ "‚ÆDÉ$ dÈÒ–þÌ+±ˆð®=/F·‹/ÇYDªÈŸD€# äN!Š�ÖB^÷uä™ZÈ媌nÈäÆU|×esM.2(Å›¦Ä•½§KFJ4ÞÄXrºø£ÿŒ{MÆÖ?HSXðS-ü˜>iÏBGlÌ9bn:FüW�SŒùE�[,½°˜ï3æû½S·kFi:OkŽÑÂEZ&æÕø—æa°åGß)x¹Ðó¹×Ð[ú]C�k¯±¹EàAkBmÓ²v¯$�ueEd¤Ö}’'�G²±ª�Û©ÚWd½¼GŠc …«bò6" ˜„!”�ÏÏQ=�h¬´ ?–nÈãê‡o]6×dvÝ€ˆŒ«ćañ±X¯Xz“"ßÄ€€0¢°Œ%,CÍ BßDÇŒïLC cƒ½k:r„¼ž‰MyÂÐOÛ”' 3.9û|Uvòû� ûy@‹�l™T" 8żi[Õuž×m{v¨5ÖôÁÚ†Pqß™Öh¦ªjˆªëƒU½¯nT$îÙ³5¿$Hc¢8ö£àùDq =¯Ðk÷æb<ëïDxSs3jɃ¦Ðÿîiا^÷Ѧ 1— :¿·úwu¯þÔæâHµÌJ" �H$�ÖŒ€4ø:‰­' ¾N"ø²h‰@+B °²ÿòÕ˜çºÞt—ֽнS—VT Ij¼Þ¾¥� Â…ù—ä‰AÁy/{3¸ç%ñ.Jæ'�H$‰€D@"pŠ!Pò¯`gÞû¸tìdõèDáÉJþ¢G vû&”­} éìð´çÃz'‹¾™¢¥" ½^Í_‹J:šôú>q99u=u!HÊ-T-µÕN<]âYí.:v¬R5ØØTYŽ”Ë‡bRÒòŽF´ò'�H<(®Þ‰%yÙê‰ÃÅùê®a¯x2\" �H$‰€DàôF`ï¶l\úFýyyî’›HâѶdÉÂÕöů†ÞÚRÈ’tH$‰€D@"p’�_' xQ¬4ø:‰àË¢%­��¥èNaú�sA+¡X’y2 ¡CG#Izù:™Í Ë–H$‰€D@"Т¨+û†Œ“qîC[4�­‰¸¦}{±gËçè}Ó¸ÖD¶¤Õ'ÂÆð¶qåûÌA&;Ýxwë—3ð´§£×äO" �8ØFóÌ1:b:ñ‚>ÎWòY" "Pw¨_U|' e�H$‰€DÒàë$viðuÁ—EKZ9ÊtH„<'¢•·bŒä+ÔúGþ$‰€D@" �H$q@@ˆBÌ�¿Ðˆ¸\†‡Æè´}KH‘cè´m~¯ŠŸqLÊí^ØÈp‰€D Jä<%`§Nt9—œ:m)k"�H$�x# ¾â�hùIƒ¯(À’Q%(mÎÀÑŽíp¬][R"K-²ìôAŽÇmŽEÛÆ#ÒøKv‰€D@" �H$�¨RE‡¶g ]€Ä ù‹a¾Ñ| h:ª€þ—¿Ó’Í›;&�œž Êì§3²îÞ´!†Ñ¶éˆ*¿{Ç’o$‰€ ržqå4 ¢õf›æ£H:ࣴ•?‰€D@" �H$:Òàë$viðuÁ—EKZÇÚàH—rË}+k·E®ðôÕ®¾I ü' pYŽD@" �H$�SaàÕ%á ièc[jVpX~w‹ÅÖ™\i«Éébs–üI"A íáf$<ITG" �@Î3²¸!�pè07»½’a‰€D@" �œ†Hƒ¯“Øè-Éૹn¾Ü 4Ú¡ÏUÃлËI&ª¢Q’¿ÕGˆò³úaXbO=µWxT™Ÿò‘wå£l�×¹'®ÒÕKìZZà åñ‘3;¶z¯^͵lùžàm‡Þ×\�‹º¶4¤[7=ÂÛWû�Çù|™fì(ü�ƒNžÛò±k¬.ÁÆ’jµÿõ»fzj ^á'§Fîü·5Ðxrðj�¥¶Î5—{ßl�-pò¨nÜE|¨,˜�ŠZ/?wÃË‹Oº‡Ëþì†áéæ¿/¸ËQ­Å®íÎ9÷ŠÛ¯±ºùÅ{)¿vèí0ôÒ×[q+ gTäÄ{úrŸW¼úµWx, ¶®¹Ä}Nˆ¡þ4v 9½ ¹Ç;¥~ÍØùUv4ÐHîÞ×&]xJÕ®%T&áÐÕÛW4´4ì*Ãö{A<´#Þ剽u^4¹Ä+îñà'ñ¢íTÌÇï¸ó´˜¡s§3ælOç Ôy¦Sü¼G6×£|k jŠ)ípAŸA¸è<ÿ‹µÖ¤çmªø_§Éâ}¯»ø¯v‹é‘íêÉã—ÜqÐbD"�H$�“ˆ€4ø ÿöü»ûŽÐb©Mg\Ô¿:ÅqÐb9Pþ=ví®Fýá£@Û¶èÚ¥zö½}Îõ¶hˆÌà«…ë?W šÎê?ÃúuGs] >+øž„üv¸ü†‘èZ•�‚Ò}¢"{ìqù BÖ] …‹Ñgô,5ÑœìRÌÖ=² Nh,R&æ†oÉ@©]�Ë1rHo !úŒA® #1¥¹S¡Rî~Bémé…5`qrÌ*t&#;�…aÂÐOb×⮹s{ì|…/¶×i´u¾7ß|9BQZ@î§[‰O´G¿ë“Ñ÷ì�±Cå·w _ý— {HÍïÑ •¸øÙqÉ»á»/tlÚcàMÉdHæ]×ò¼�PV'vÓF»ó†"ùÚSKy-ŽˆÊãã÷c|ƒóÜãW �œ]æ Ê¥pñŒž¥ÎàóœW¸�‚cOâÁ[�±WþôÉ¡u¬¹íáÑ7±äcZÔXFkàçae¯½°u —ý™!ÍmÉ¥ª\Ꙋ>�uÖ…è}IôìÞ ¾¢øî lüp9ʘ–ù¢C[ £‹µWm 7mBÁæ"ÔÕ6â‘ßé잸¸ÿ\}u† ô62ØøâO1ìam½õTNf^×õ ǧ=ıŽÂèëDþ¢âq¾û{¨±±Ðbe‹~W¼¬×QßíÐÍ�ÚYéšk±½ ›·~ƒòâ]¨=D›qÈ$§ã9gãÒËbÀà!¸2©Èow ÿÕãoCzà±ÍDfÒl+¼gÅ…âZl^÷¥¶aó¼A$‹÷ñε¾”ôÛqDÀ[Orþ˜Q¸¨L+Þr¼!VÑ~ÿ!OÝáÍXÿüLœ³šEM$^®¦Ãc¡'ìö¸ð“F}ë+Èïxó´˜�ñ 3æ|Oã Žv¤y†þ‚õÄO?3×å=’F")Œ•}sÅGøMïc ËlÐüõX7ózÝíñÒóFGEd±7??c~¿^�O�td¥ŸXâXGuãoˆìvâóo…¡ÛYzË0tOhF}_+åß×B¤—¯$‰€D@" hHƒ/ÞNM{ðeÎ'(?@F[ê¯n˜0}Bhcíڌ՟lƒ‘‚g'î;\p%ÆŽLtUèDdðÅ„¥Ä9ÙÈ�1 ÕžÆÀqéjQâ£õ-¿2?b;Ë÷läÙPô*ú$k†é9¥˜:¤%*f]”‰�…˜Ök4ÞMY€@ÆÝP�“y…‡ä´z߀å“ûàUg”‚œ@†¨_…dD7:؈î$aÓ°£›È�Pσѯǩ¤á‹Ц³:aó cMÁT¤œŸ_‰_]ëm0uò„îzlÍ+¡v=påµým¼¯aóR\6dºZñ¹DÿoBÐ9:@¤Bûö·gâæÛ_0³žžY„Ùú›Ï§Â�êå‹DZþ¼ÇãœçÆZ`\ӻ̔ѫÓ�ü�:[€Ïs^ááIj@QþVlw.›ç ÃcîòOcÈÒü½ô Ñ_f'&•w>žå{÷�Ö±ær`ÓвÖêZÍãÉù(ãÕ[?�¼i½ø¤k¸ìÏ‘Ëc2¹”{Ý'OIÇSšŠÄ–(VDûî lü€ÉQF¾'üê5ÎCâôîU[¼s¼ Ï}: ÞxqÕŸ1õ–~A7ÿ}*®~P[o-Ì-ÃŒ«[r"?æ€dðENwOØÏu^ñZ«y…G@­÷ZŠ�…+Xt�¬×Qߩ޽èHGñÛžõ î›8[Ãå’t–ÿÏ }©÷æÐpYÄë}Ã÷[°åßqÁW¡¯ÍÃK=ޜؿϢ’&¼€í™÷jz¶X ®ÿ“º�Äg"ŸP†d�ßâñÎC°Ô,o&6œ‹¾§˜:Hë(Žw ÷k.[‰ó‡Þçˆ6¹ ‘x²0 9ú›“<cÀÅïxó´HA÷œ<èŒ4ßÖϳîljx>Ïð"š¶½Ž¾‰÷ZA“ß@ùë?³é`­—â®ïNëŽ{—ØC'½’�Ew ¶Fñt¼ô¼Q�qÔHuÇ‘fè=‡FšC|â ƒ/aøåõ³ÖŠÆfÿj<}Î@¨_[�±¾W½d¸D@" �H$v¤Á—ŽÇÞÒ|\Pê0Üꌛ&ŒC/ƒ¯cû·#sÍF–¦ξ ;Ú¬Cõ�&齆bÂMÁF|1¥\Jz2¦�óCáÍ_ÝO±ùN/³è°7) r‘qwbPž-ÕàË4P2”‰ $“ÁW–‹Á‹Èé�)gm*È;NI1ö ïÎÝza@ï“©¤oÆêÙçcòËäÀM7x<�ZHÔUçx¸['l]|7nýí"ñ-ô7ùÇæâ"ºsû�,¡»¹â]ôé}‘4«ögãZ¦Ç>^4YØ^†dåY�aÄħM¨^]‚´±!v›1[ßM‡}dðÑNa¯º…wŒo´XÞÊh4æ ªª—2Ô+Ü #¼y×jœŸ8™ ¥‰ñ&†«Çœæ—Æ(ñNêA£w‚“ý&T>~´…êÎu\Ë\s9±iIk'm­çYçY\±Ÿn‡^ÐîÚãO»w_d¼²ÅòóÈññâ“îá²?GŽ,‹Éù? }›‚UÅÑ#t¬“÷Öo_`ãÇ&G�œšx�óÐôtkŒÓ¿[E›Ê~1/(Á-ãR@~µ±iÕjg?üwË£+ñÞ#?°)vº|54+8‘'ë¸Î+|¬rþîÎÕõ>ÔZŠ�^–k>'?Ð}NðOWÓY�!ÑÎ5�aXŠ%k ™}ì}£1ä"Ú u¨…Ÿç`ÍGB†7~#‘¹;ÃÏ3žOƵkÒºâ®ç€`/Ìàk|­‹“ÁWãF<ÐyÞÕõ2$k,żá‰xÁ`8I�cCÁlô=k¦Ý ‘zçæ²Câ”%x÷éÛNÈ24Þó§ß9)ty­ÿml¸¸ãožÊ¡æw:#Ë·5Ä U÷ãCSwšg‚~ÍÈI»¿|Î>¯¬ y%Ùs^©Ç?È�÷Â�—æ¨ WãgIž‘ƒJô 8^z^¯òb ÇO–ìØGY�,>èrœÓ¼j�…ÊèÓ¶khB›#^®(¸.ÔØ¤ÂÖnLg}É2…D@" �H$- ið…c(ýô]TXZjÑñ8Êàë¾ýðmlªÕš³ÃWáG#/7�lÚS„U}£ƒµÅ5c'â²nÚÎ?£ÄËàkê•]ÑØlß–@»¼¾|>ãæäªÅÍYU„tœB£=:vT�…ã îùÄ µe\]¤^JK¯ð–Q‘Bó|¨pežNND:;i'ºÇ;uCƒ ¾¬ºŽ}v–Í¸Æ `w'KèÞ»nÿðI¢äd|IlÇéñ¢)œÁ×Î5óH/hÒ~§¢g/£nâ»ÁW¨qÇø}Ô)%#Û“iÊëmÝ3™òÂKênåç~W½ž>ŒN{âR‘Sñ2†°¾îž"‚P�¹Ë/�”}�-³ðj…êÏ<^|ïCõ�Ö±æŠ/2·“‡€w_d¼²ÅòóÈqóâ“^á‘ç,cšØø:г¦¢»Cm®¯ÆÆõoaæ]s ž/OY†Š…lFAfž­ö†�Ÿ Gy�óÐ_µ_.F�Ñ�X‘¯¼ ™‹gàGƒû¡£ù1¬{J¿Ä²yÿù—Ùº˜ðÜGxçž!fÚÓÝàë |ñv²`ât\olc5›âB­¥ØXhsI¼çõC|ã2b¦1QÃNzö}üùw£‚>$ïûî#üqÀ�Íxƒyëæ�:®]!tæ•XH^ŠÿB†Uc_ÊDz©ÜËÝàk|ÅåHGnðåfHÖÀÂ1ð—�tÊOac/QöMÍH8tX¯¬÷¥de†ß÷šaAnî>in½¼iäoüÎI<�Sñþxàožî¡æ„Èrh½±N|Ý] ¾È[â]ä-qM!iÇÒm0/gH7‹‡ÛÁë"hÂR”gÞÂKæöxéyÃÛ^‡šCO,y1|µ‚µÛ‰ES–&�H$�Ö‹€4øB Ve¡ô 5bÛ¸á‡CQ÷ŇØV+,ãC|5°*ësˆdÀøÑí#ƒ>zï-ÊÁºoªÕ�ûß„qC{©÷Æ?|‘;äÉt¼žðßåæákIAnëçþ•Ù.øè˜Fõ°C£xÛÕöñ‘S°£èK|U´õ‡£}û³qQb®Kì­ˆÙ›�äê[|»µ»ë…Ò¢=ÎîÝI‰ƒÑÛvŸˆÀ!� ©„ó1 Ÿ÷–ïê²T©Fj�ÐÀÙøãÂät24 � qWfš•¡¢³h ¾ýwv×Öë\�kIñÍ£ÙîQ’ÿ 7‡:�ðD\p®¸rúõ mÑX]‚/>+Äw{ ¥mß•0¿ä º²_ðî½Æj””V‚„ Ñs”Îc_ÿù7¨%Ø/¸z ~�È0m®CþÇë±ùû½Z¾g÷Æ�k†b@϶t¤c¯à#ÑŒ]ee¨9tÄîá‹•y •Ù…ð)+܈Í%Qô‘†jm-Âöò*µ_ 躞ÝI×]t\cÝŽ2ìÙU€‡ÆÜ§/9eòf\‡#Í¢/ôv´A¤}ÏÖXG±fyyñI÷ðpý™2Œ²|Ä¥ ©�ú�="“¿Â">Ÿ£˜Aµ[ÂÆ’•è5Ü8~*Ùttü0�u«òÉ�hÓ¯çQ®_�ovÐ.ªö½1fâHÛÜá¯EÉ[Üä£RQËQFBq�’çøéCaÇyèQ¨|íÀ»&á)ƒôÿ|�¿Ý�^Æsеëþ ?zÌð0žŒÊÿ·êâ'7øz1¯S¯lƶ/¿ÂƲÄ#š•3qõ�£0¼?“W�e�áàf’‹Ëì2ãÕïÁ¥6½‚ž�°Ûö�&÷#Ù¹+ê±ù³ÍGE¥&ó ½Áà뇓œÅZ(¤ÁW%þvk?<ö‘N{ÒL|’7—9ðÑßê—èô{¿ûUiþ9÷2ª›×}„¢ïiþéÐ?¼}εU¥;·mEñ7Ũ: 8I{t¿¸']…‹lÇ_Ú)µÉÞï¶aëöÂX`E¿]qÑåCpݵým2Xƒ/ê�e•µØ08ÐNÊÅ”E«0ƒÜf67Ÿ‰~6™Ï¿î*¬NÑYEõÙe-ñœÍ<íZ¸G ¿uTT:Üã5W³|ÝÛ£»«ž–ó4Íð(é¤ PX®Í¹$™#iÄ( Ò»û“­ÂÏ .ýÂÑZËÕz:¿üÞ(6^²\øº%Šk”ã‘'uÜ»|mã~Ü<ùïj̇W¼�Ú'ïÀRÕðËý$•çÿ{-n¾eºžûtdýç’~åÌÞ—âÆÇö”bËWEØSOßl„',ÒW^¥êhQ¾y;}Ëi‡súQš®ÃŒ]Ï9Ï4 ±x¹6ï5Í_Uv~j®¯DyÙ^U§ÝkP°~·™ô®%IïJúZU¡!äþóûbÀ5W˜õ4„ŸC JOLÝÂ|.žŒÑ³Ô/‹È!™lH¶v›r*nÌ1ð—W‰€D@" �œ^ÄËà‹N�ò÷ûï×ñWSSs’þ*•œe‹•eÿ·AÙ©ÒP©|ðúbeñbñ÷º²¥Ò�®Ò ™zœÅÊëk¶¸Ó¾s£²L͇òZ¶FùÞQG­ŒÅîi͸ÅÊœD(Ô-2øRãr¨Ïd¦äT¸Ó'ðÌ]�ªÇƒB^»B–cåIq3W)é)Z™¢\Û_Jº²©*¸Ì@^†’êŒËžSf-SJ�:Uä(Éæ;ªC 8?µ?T(SÌxÉJv  ,ÒéJœµJ«åe–›¼@ °2\Ã�÷a®ÅÙK� �ªdä‚ð,Í �AbjºRàÚ^¥JÆ«­lx«õO¤6)°•—» Å왋lmDGšq«6eZø˜XjõI�³H™“šhæc¶oŸÄt³Ý¬2“•U¹Êœd'.úsÊ—>R¥ä,J³Ñé¬gêœVûÕ”t½ß;ãÑáŽÔ¬>Uß ÓîœùiÏØ0²êÄéØ[W«TkTÖ½t‡Žß=Êü—¦[XŽZ l£÷"ÿÛ^ø‚‡Ž9´½ñ¶®T&9úÇzÐäʆƒö<×½4^Ïs¼²ìÃ¥fþ"Ýå3fØžmyÍ_¯–o£éõÊÜ }hÂ%ÿ°½l^7ç½… ^×-, =÷®( ÂÁžW¥²l¾�³mƒ•¹Ùò… �Áâ†Ë{¼²´0¸�*�Õ+Ù¯ÌôÄVÔkÒü,e;kÿšÚZ“ð¾þ>’qgña¤.PV­˜ãIÛœÌMAtD5^9/ó÷¶ºD2WÐØ÷š½Âme0ÞÈI÷¬³�ÿg+i^|R{.s‰ÇœšÆMv~œº„ñRw¾bÔ­*VSg)‹<ç¯%£ x®¬©‰~Ϋ °u›—Œzˆ+o—9ÙbÍI��–tôr:8÷Fÿ8¡k.½ïZóµKˆuÇÔvÏÇ££ Ji 8Åsμ4EY’]lãQ§ñÕ¬ö�Š÷˜ã½TY1gŠçxmš’¶D)6ã[åÙ°cïsÒ“Íüæ°µ¹Õ>~ÖXîå†ï‹±ñóðc9EY–ZþpÇ)Ú5£V/>é¢?×Ôø-ßX›ûkC?²‡¿~íÞ_ÜÛÂ×cŽrOP˜s aR¬çU‘«¤¨s ”äô eÉ4¾ÞòžQf8ÞëÞ¿¢æ-!ú‚/9Jï~ÚÆ?Î <ݯÍõµÊ®U³M¾Ü¥|]]«¥ðÐeÊ›­¶»åÑ÷Ìø_?gȵ‰Ê/?£LÖÛÛ9'Nxt¥²/¨œ=JþË¡eÆÉsƒÓ}ýœ5þ>È{OyУ̷6U* ›–)·¸¾OQÞÛZiÖC«ôô¨sÇZŒ“**ÛÄaÚ Û¼(ÞWäq¹ž�#ÏR&#§(¹¤[p�W¼ÆªW8›§ìã9’µTls‰¿µ(ç#«”¼³,\më”G\ç³þѯ©…,¹=ŸÉœ®dòŸ›<[§l(ÌW6ì(å‡ëqÃÉ‹Á²håþ Ê�F�“<ôù†þÊ£„¼Y­ÌM²Æ¯Ù'Õ|+«ö º«•g Y}ò Jæêyž?úa‰£nõÖÃn°t£^`2l@™o”§Ò1SùÄ¡‹°Ëí>ôó•±:V7>»RyñAŽÁH½Þ�Û‹BëJÆ>ñ†«&°{½2}Ï×y‡²¬¨ÚÄ«êP}àc0�çz±ØtWñ“ BÑkÈAQÏÓæø4ø ûÕÏ:*6Ü"_ïE‚‹µðh�õŠÅÓ•Y‹xêSfq}+aèK¶Š`Nð Së×áÖvÁºïÛº1:~/d•øÉrÔ]ï«~ú÷Î{'ï«1ÒäÑŸç|8χbé-«•åO:_ïõ¸²âCk®»ñÙ &‹EÏ-ÏT±°ñòµÊ'«7ënŸÏhÎsÌOÙÏ2œlzòJeùü{<óùŽ}ä5e‹ªw …§1‡6*'²nÕö…œKJ³çèu3ôª–œf|ktö;ùì>×H\$.²È> û€ì-¹öVÑZk½ùæ›ÊÆ�•ââbeûöíÊ"ZEýûó?µ£7Nó•uñHpŒ|î·1Ž[lB!yü*VÉñöðUQ° ŸªnÁ€¾7ŒÇu}:¹Pr_f½‹rµŠ�qÄqèÃ\¸Däá‹v…¬}þI¼[Œ™ñG¤ô#¿Je«ñäóÙ8Ô©~÷ø ðØñÆwú„;¦‘{›°*’ˆÔ)×áÀw¯au®šœžƒ¬©CÌûnLé¦�Å9‡¶áå׌�¿<-óRh·3ÖÎ…Û©yLËØ„y)½Õ{þOCá«è3ú!-ˆvTÑQ �µ‹ñü»ÛÐoÌ ÌHéG›f 1­×h¨›Ýbܽj”ÝP´}’0隌ÔÔ^ØòÖ[ÖÑ$–Yô?ÙSÛÑR—¿ýÇ̲Ò$&cÚØë€‰t¼Iî ô4cVãÕÉñƒ)9u®»ضæe¬Ö RcÏÊ,ÂÌ‘ZJÞ¶fVú�Ù>äny‡Ó7ÒÛDLI‹N;¿ÄËo±M¤WEÆ9îtÏ1e»÷ÝËtï#†7:�$ìX=WM^h<)ɘrÝ¥8Tõ%Þb•LY�ƒŒ»Eßj@Öì;p×ËŒN M¤ã‹jF"ïÃyj¿�¾ïY$„ºóÛž±`äEO°‡¯;h'ð3øò'âi©î]Q„''õ·eaÛe•_‰ß\kyìÚ—÷W\1B["UÒHÜ;n8õ×­Xºä]+Ÿ¤yøºðÿ‘CíÇ=iY‘´»f=�6éÒv›/c¶ 9£OÞq¹Í×…¼”Mºo8ê‹ÿŽ5Y¡¤@ÀÛÇUZ±´;N|©uÝ÷Õë¸bؽfÔ{3ò‰†ÁæsðÍücbü!ËzsãäéÚ(^õÖ¨»å´wX†´[/TxÙVJíΪC#Þ�Ö÷.±b šp~˜ØÅOQÞf0yl+ÉÅøK-¦¾3ë1 ›ø´C´Õ�#àà®<¼�µÅ ûï9U;ÞÓÿ‘Ž‘Œ;¶Ì,�n’S1¥×¼öcftÄ÷èýx�ã\A$òñÉçD¯p^=~/ê‘J^K܉8lF.ÉüÛÐÆî2Ì=(×#ˆ¦àÒN´.x�Ï%Œ÷ŠB8ÿesš7�uxuZd•©Ý9Ëp¾WŸyßämÐXDë°dÛZC¬;ªrðƒTäÒѧê 4¾Ò°õ/ŸËqåcÜ/f%+§Ññ9Æàkêã—vBÕ—´.fë³ÔE¹xù—b@„ÿñvà4òp+÷>á\cYñíwáûb/ËÃOJõ ÇÏÅ®õ¬´^¸K;]HM�˜2c¯è„m iýjæ—ˆeb‚‡7b3»‰~ͨ%æzak†{õgÊ*å[Õ‰¬ ýÈ~ûµE›�;Ž›£ÜsªÆÜsêó “›(�É$»­vÌ!ZÆœè³Å“·ø•£¨"~Û†÷a ÓÐ}(ü8§5Iˆ_·öMø×o.ÄýK‹4á¹OéxÆÈø™ýÈ4”Õ?Ž‹)îáË*:“}=ä-CÖ7Vè-ùë~7Ì ø~Õ“è÷ ¶zº2÷¿ w�ŒUã uŒ¤™Ù•)¸—Ž:Zú/‹#™ïÄÍÍôždnÛûqKÑðæm¦wB?ô„ôð…4.®ÒÇÅ,lª™ ®)Z> Ɇ"1=›<ÒZ‹(r]ºú�Ó½_kú‘âW)�¾tåq|¬F5†HÇW6ð½^6¼à;øˆ×ZTóf!êã-¸¾ÖÔªçãh-µ„Áx65~qíyêSäÿø“EÁ=fyx Ö ´Ã»i?ǽÏi^¹ �Œ­{G“W­§É«óðeD×Qwà΋àõ ¦3Àx¬Ú¿׺8ãIÕ{N¯y¤c-Þ¼óBü>È=ëö?�A!òó¥Ï ²ïê<"è4­ÔñȦ:$Q™MÛÞDßÄ)1t%}Ń)¤ßtèJ\‰ò…ã-�]Í¥˜×>/°”7N¾—v9ˆü%o�wvãg•Î×àñ?$¹Óâ~"�D$ÓÚÜš±¤{ çmñ§‹tŸs4ýÊmÃÉÉã�D/7°…¸úYG�H�_$suØö .iê¾™,äžN_;8d–äôlÒåës.ŸX~æ`Ù*ù^2[ôrµJK ü>¾²\$ó!Í$¾¿ päí÷N_ _-ÅeÃtO]ććŽn~}‡èúÏɯ¡üõ_X¼‰<6¾3íçøÝÏ'Ý"6¯G2�‚ð$�‚°yñmó[ÆÛ¿HüžëˆuÒÆ’¾v™®¯åsŒEyz^ˆèæ2?¼]¤åú[Cw,·¿q7yL{Cܪ?5¯��Qµ�ôÔL<é•|,º«oø94!úù@-ØgÝÂyøj,[Kß©mû�Ág¤¨'¶hßYß×ôºË‹D@" �H$­éá+h·yüŠÀÃWÑËu_Ë”üャC{ ‹Ì×WÞáí�>Ñyø¢î¬$§-SŠ™'¯‚ ¶k2Ùòú$v̤›»·ÉÓ�c×P `…m‡Ñ‚ÍÛ‡m÷*yæ2½±öÈL3¼Oýª·—:{íRõ gù»[b™ÕÓå(UFšªbeYšå™´+W{W¤Ìbž-RÓW)FºŠ]«$›+"?ñ—¶¢ÈÜyQœÉp%Ïa™›*ÌwÂÃ@ö"îY"MÙ¤çkíþÒòLœ’®ä—*�ÒR¥Bo·¼EÆîjŠ“<Çæ]¬"Èó—±Ëƒ0öÀ.ÏF‹[a»±¹·µËK�Zÿe¹¬Ž5JÑ*kÇ)îµ®Âôfgy¸³ÚÍ_ß³Ò»ô'_ÿíé#/Zj”`_ã•l±Ûµü ³Oã•̽|í4öôðÅwƒ‘w¨g×*åÌ;”Ø…t'ë¯ÓW—™;·,oVZ¿tßå“Ý•Êö½•´CY”_Ívæ�êî`‹.N“è 7>ò†²…yòÚ�Évfyx. ÞÝÆ½ŸA™_T¯Š^cØ@¹ó•|³néEØ–YÙ¸CYQ^ÇÒÔ+«^ỽf*ù:fá1¡ÝÇx¯,/±võ Ì–s¯bŽ�Î�š;÷ L_a¯Ç×[;ì@4«ý‚èòïáK뇡ÇÛůö“deYóÜȳñC‹wû¯q›+hl{͉^á¡yíˆ3=a2þ©óèâUŒ·'¦)¹¥Uß«*R¤jcHŒƒ”Œ'zð_w+”ŒiÖ<)ø|‘^~hÚµvŽ �FÈå} WIcs"¯Ÿß9Ïk^âõ´yÍbž“B÷goÞ+òöM/y Õ?8­¢ï5—¨K$ëŽgнGßä;Ö“Ó2ìë9Ǻ)u‰æ­ÔOÿ}Àïâ¸w¢eyvOUŹ˘'Ø)J[3aÇÆ¥ûX®QŽÇúA£#T_ôËÏk”Òlîé0EYaóæ Ýô| Ê<ð2,Üqò¿fôÂÖ5Ü£?×İfõ߆~d¿ý:4Ïso–Æ7ÇlãMl=�byî"�ª‡/sž o+ò”Ròä\Ðä ¿ý+ž¼Å·åS6ØûïC¡Æ¹[ÛXaÍõå•qÆš$Yù <œg/ö¾.�yÒJQ>Û¥½³<|iùÞòÐ2ey,6<†}óO&3’ì—oz+QžºÒ Ê#ÿüÔL#Ò²Ÿaë{ž®Vùæå»Ø;òêûÜJ“á=¬ü½ /c<+•[ÔõŒ(;EÉ×ëq´Þ=¡<|‰v^5ËÐ'$*+ŠØú�æÛ¹X¨ëƒtËs·Hkyh =E†æI7*Õ¶úIèµ”“îHeZgù^/çÚô+´ó„xãƒó”åò•-{¹LiÉÅN™Ô¯,Zéé1Ë*‹ËàÜv9ÓÐÇ{&ûjr½éáKí�#•¥ù+ÎþBæa†¼l«žÃ¬2�õ3Ÿ9½–*�cuÊÒû3ì¦éÌ´¦Î§>ƒ¼¡©¾Lùš<¦­.T¶í¯¦?£�ìm9ö »'íí%Y–‡2Âe~¾%×où˜é’f*ëö2n‡Ë”ù“­>2ö%M®çᢗù:>]שjïüë®xž‚߸é�ò]¯žüÄ{Nò5O›ë ‹'Ùéñ³Žò�Ûñš«Ã¶‡Þœ§¹É•yËìs®©oõÈ�cËeV2(6õ!ç�|}ËÕäákŠÊƒŒñ)¿?>²\Èº×øïWwç½� ži`ÁyP™bé+Ëw»ðc⿆—CØôŽ—ófÂ{z&;AðûQV™¢Ÿñ9ƒÏ1â]¤z^?‘á²oÈ> û€ì²´î> =|ÑjÔþ‹ÌÃWàËUø¼ü %õö&òåñüyø²SÍßécîöôÈ€ïÜ¡�Æ(Êâ^¨D¢]xš¼+¥«[ËŒÝ×bórôþ€–+¥+¦t=eÔmxýÇÍQCÓ2‘ûí"A5žOˆ9j~‰ÈØôRzkÞ²ÔˆÍ%H;84Çi´ûõ1ÛîW5Žø‡ïJŠi÷ª–ccÙJôzŸö�º/[;|ÕÀ†|Lè3F÷ì’Š<òVѧ”00<‚‘¯Ròàe:3ÑrBíòécx3ó%O9ÓúÀØÄ;gU)fŒp¦¬Ãâ ý1Kw%³(¯¿$—n6ïg˜†¼*òxÅàø.ž0ÐL·¤ ·9¼+T¯'¦ëZmê…i#yOé¥{OAâ,òT6“y*Ùð>’Jç¿LçÂSpc žÿý䨂ÕR]úV#y˜è…ÔÍ×v�@¼_:=Zøï{z•=.�äáÍ_{RUýbäA‹öðeí ýêùÛ0î÷´KGüî{å/ÿÌÜÅÅwYñ�KM|çyðÚF¼ÎÒr0ÿm `—ÀØî0ÛN2LÇ'‡i÷¯­ßñ�À�FÆœ&Œ"ïaë,ïaZœJ,ÒQwPY;_�ô^W¾KkúKäáè·Y^³&¬Deæx¯¤z8Ñ}gsWñ£Wâþ›-�hZ¤Zü�¼z=ö‘öôlQ~q�E¾»Î“F¼sgwüNß±üèÇÊÛ¹ã{þzkü·š÷`,ßñ9F÷"`¿Å_ï} _ØŒ5ûé‚W#ޜؿW½’Yxû÷ð¥Õ-Ô¸;ý—O&¾¥;KàžµÔÄ}o1Æ­ÿñ§¹‚ˆóš½Â�ú¸_9v¾%â—­~�þ3V¯ÆÍÌ;£‘çFê;�9ÍNcS‰¹nx~2ÆÍÑ‚xrÁG3ÑÏ6�Òܯq¡‘²vóÒioït”fM¥yÑÿœç5/ñšñ~Ë×<<܆5Oìz½¶qÜ?8M'fÍE#—{Mu]7¸‚`zöÍÉäYDë‡ r«pw¢£’'¹Wþ:ôë‹~CnĈ=h,FŸÆo°÷Å(Ö©Ænr�@Ê"TeüŽšaÇúWñÆÖ¸üâ~¸ñG#ÐÃÁBϼ³�eòÜ2D[÷qžÕËÌÙë&¯âï€Hù9MNX9­ çgsVÓúÕ¹ú'ÞMëÐ9¹‚®D¬(ú?нâzQª†Ç°fôÂÖ5Ü£?DzfõÛ†¾d�€_ù+$úá_rÜh\Tи°|’òä�X¿ø÷˜8ë-=0 U�ésyÑ™Lž)õék yÆ\(ƒ¢.Ýшñö�ïÈ€ÖÍ¥Þ—g=ƒ9¯|†tÊC2󮾤š¨úêí`àÎבÖÞoùúÑ¿îêxÉ¡æ$_ó´‚ÇÕ×:Ê·÷øÍÕaÛïó¾¸éÎIßJëvCïlzŽôÈ�ÃÌyÄòµk¾ñ’«£à÷|N�£,Ç1q·±è’9îÎ{cžQÃ÷|„IüX?Yáq|}l¶y"Cù÷cÄä¿«ÑȨ”NlÏŠó_š/¶­»×Ôï%¾6Xçk`:`3ƒÚO1éܘ':CGääXŠr¯ð`´yˆ�ßñ£bx,Ï{6G©qY8Ø:N㢼Fl}Ôœ?É䊎ʛ§•çY �ŒOÅ|f÷ò"lsžþñ¹-Ÿs¢›ó¼æ%^$翼}y¸­<±Û½mŽŒ’^Ç|è윦µæâeº®Ü0àa¬?ð¾É?\#qV¼:· è¤$åYùIã·øç=vƒ�i 21#õFôìâüHËkþž�e¯~¯õƒFM(^ÅßEÎÏÉ*itŒ§ºú'cÓâÜ™A›=DÙ;²hýz—¶~5?.…‡(l CûšÑ �€Ç{ôç°…S«{ù|ŒEÓ†~d�²ä¯Hêè‡ãFüIæ/qþ‘#8¢&h‡víh­Xµÿûì,¼¥nêÑrJ#ÃçÇôcé)3OƪÒ,Øö»ÄпâÆ[b�£üóœX䎩½_z¶¥þ¢ÛáMøyÏQ0N4¯¼cÝÄy׌vá�]á)õ]"2·~ŒŸöI°|9�^4²ù.s6þ×Kêã„¿|„w~7Äxòj“1Ã,JQO_gé_�¼¹ÇJ´¡=Ef3…�ûmþçT\=M(ÚóeQ\oÝè gðE;ÁȰkŒjØ•˜¶‚6Ãý@Í»¡�6ˆ�žE÷©X–q îš,îi e�Í6AÐ&³bÚd&šÊâIŒ÷ñ±ÊÖ“‘Ì¥*1Ž8 ^KñþÅ\â(Ãõ‘ÕÃ^./s m~[èØüæ.�ˆ28^ñXSÛ>Ä×ðîKOáÞ?hÜ]ëD�c\€‡fÞƒ¤^º|ƒ,zb ¾Ü6z¹0yÕÙ 7 è¸U¨›¼Ì7êÍ��dáÍycB®#ýë3¸®b$2÷fÃ)ro_v?nþµÖ~Ó? `ö­Î�Z‚LÒÁ´Ñu0£�ÑÄý¦Ñ„½6Ž'£îlÄjð/ÝUT_“›¼Ô#?Ž/§ÉKn1ó3ºåKa–î9¹:~|d9މ³î±ŒG>·+Ÿg¶.»·þú 5šv¼ 3ê²eMÇÚ Û—‹®Œ‘‡/l'ƒ/±G[ü6Ófâ1úfâé«K0{l°ž8wö0ÜþÔ5¾ÁÃÄ׉ÆSÏËç7^­úhã+mØU¯÷ÐFdÚ°ÌëI4¹Ø Z-ý)`éÉ÷ÐæÞ>ææÞ{_z÷ONÆAÆÙ"ëÇëm§ÏŠãyÇÚžÖ_ݤÁ—'Òò…D@" �HN+¤ÁWPsGbðÕŒ¢ßÁ7µ"qh_» ÞÇ'¥\ãµTƒ¯¹òÐ`,û €¸RÍÚ¹p‰ÄTÌú�‹ÐØh¤Ñ®Qƒô…šQ˜PZš>™²S|°. /Ušw’f¬�= ·¿,¾�÷/ò �Â-åxön¤xïÎÓºÜóú¸ãœ(²4„ŸéÍËúø=­×h¨{ßS �q·)lñRøNqC äB¦ëG4^ÚÍ øÎ ‡WÉS�¶Ãžµ OËļLwlÜûˆQ—æº2|ð^6ò¿Ü†mUßá r©¾.*2¾ 1:è /Ó¨»‘Ç=ê¾gdâråùº×S$riO˜Óëž64F.ä¸zø2 ¾(Á>òÆu…á�‹y˜â§%ÈÚÜù…ÕøU’ØÂîü‘�iz¼²ŒqËÇUÔã5s¡Éià K¯p³\o"ËÍ(ËÿÙ9ùØöÝ6|WqÀäyD ¶g`¤ãÁ9�‰©)(zËðÿ`ç™®¤† Œ‘F�>àÊ#ÉàËïœÉœÎûo_nÃ:$.ô’·…g=)ótjåºpš¢™+x?ˆvñ2]× ÑàÁÖ¨Û€ÉýÇÙ=’ SÒÆaÌ-7àš¡WIùIÃÛƒ—Ïè¶ÕQ7ꌳüÅ“1f–1Ö´‚’S§`ÜÈ1¸aÄ5¸²_hÃ6FšyËéñê§Ñô 3cÏ›P}‘½óèãS³ÛŒaÈ4!mI;ÿ´úÿßt¼¦/ï¼>@y‘ígÍè…­kx˜þä§|ŽU4mÈésOŒO-/Î-ŠŽ[„ɦ,ÈÆÓwcïY¿c�Ììbé_ñâ-¼žQÊQ±´�ß>¤Î¹¦÷ÕèÖÝŽmÅ”7AsDk÷še¶‰çM=ÿ¢~§zÜJÆåïàVruhA/’^aêÕÁ²Fcñrt¹ö~5g§Á—«ßÍÆç_lCÑîíØGë^CfÜü�%3šž¸(nðõ"ÆO½Ò^&§i!Ñ4ÃA“õ>Øà+ZzÂ|ÙŒÉkv�æ5Ûœsh\¿qÔ½}ÍÉ&/àÃÈ@­z=& œ¨zç›åxŸ3çÞ‡ùœéîÙÆÚ Þ7͹ÀLÃÆt4s‰™ÞÇZ”ce™¯x¬©ù‡x«JµØ¾©¹Ÿá“uÿƒ·³ yÍŒ¡ÞÌßÀ¯†“AQ ²¨-­ã¾QšM^ͧ�E×j‹x¸!ÛilÔ=äãÐé­œlw¼®Id¨`ʲV¬I¯lÀ¢»,YØz£ÝqÙß]§ â¹é3˜®ÁÃP‹ç�¤;ððm½qÈ)º“~ó/OF}– ®Q׌ò¼÷ñavŠ‹·â»�ûM¹Ø‚­†¼ÿ,Éû3®Aì_ÓÈÓ®æMÓ{ AcÔ©‹tè®â*ðñÉõ¿ ?ó´¬ç¿|L{c`OYšð¸¹—Çx¢­þ^ámœÏº¶‡ÿ¶Õ%‡tùê1 öúºÊ«ùñ”6šØ†94'¸åËÃ/¾Ê½€ñ9ƒÏîiïezK�îèx¦–†ååüÄëÉõä¶Ó3´Bpãä{�òƒ ¿y(]z!“e´¼Þ=9]N\ݤÁ—…º¼“H$‰À錀4ø jýH ¾èðºB2ä*&‹•�_MØü~¶‰h.ñZªÁ—©(´aã.œr�ÆÝó!Ù�, S­�Ȱk.v-Ô·¦2“vvO#Ïš!”—±’^ã Ìäõ™FG,Ì3ŽXð¬�]¨sÇN$®ÆÓç DºšÏòƲ�LÙØÇoN»£¬º OÓ‘˜zJýØ.dº–Éq!_Et$fOG¾žxZFWØ2¹ nSl�—‡µÏãªÛçQ`ÿHÁËt*x[çãÂûžÛ{-Œç늭Í¥=»ýÜÓº�#ojÜ�t4 {´tt IÚ ¸ë9M‘|ãüµäyë&Û.+.Èz ¸vö`a›>ø‹xÖü+‰ú1_a_Œ?pÚÜÆ-W<®÷=¯q˜+¨ NŸ^áÞ´‰7aÆ2y¸zþçCõãÌBçdãmü—Ó¨æ–HÿªS'÷üºœ ·q¦Ñž¿�GæÑœ7 †9Ïf|A¿ãíëÖí´zdlZ0J2®)HÏø#îII R1œWNo{7ÚíiÝû„=ŽÛS¨tì]ãÊäU¼-ÜŠt sõTàOù]3zaëÎë਻ßòý¶!§Ï�ìá£#ØâŽÑ=rÜB¥L$£Ï±?Cêý #úÙ=)Ùø£Û‡»HË`åóþÞb£!:9Š·'#1Ä­Õ6~û� S‡ ¢`õU·ö ømýZ?&‘Q…KK_îñ|J?¤}"bZ†R–ñ°0—Žk¼ÚÙhãÂgO£Ç˜yj÷¾’‡—Sª÷ßø<úMü“zú«<�|¹•Ž&ë½=_?ô„7øJ–O#/éBÛaÍX‡ÅúcV.9DW½w¢ç>ìy˜íÈtndÀûœ9¯ð>ÌyœWxh°m›šÌ¹ÀLãs.éý®Eù:œ×Ϥ‰FóÂÃiæx©Ñc\S[âYáŽÛæÆZì.)Aîû¯á÷6ï_ºœ��x ó¼-Ò9>Âó¬ÜdÑbðåA—ƒÝ?vsêõ{‡lƒé*<ŒxÞFy¡¯#±j6®6¦ä%ý¯cñß…N!ÞxÅÓàËÿAÅÛå2U‘î*(#{€'?a<ÁeNŠzž¶—ôÄÇ´ŸuTüqóª¿W¸V%γ\iòÀ›×ß5eï*¯zäÇö¢‰‡sþª¦uË×-Œ¤ß»Ò¿?²\¨ºGÒ®ßh<†úó̾<:Nv„¥œôÄ<\Ê7ÝtìˆÂ?̶ŽvÍÈù¯ƒ¯sÞçÅW÷å‘>t„¦5x˜ ›ÏîiïezK?,Ú)gð•’†Et|B“zÔe°jÀa2;štg hó¯ú³�q?eªN aôy 7G}ŸFFW�…2ºò½Âµb=ÿåši€æ[{ÁÓx ØB!þ*)q"%®8¦A=‹{;ñPTŠØÖñ¤J×]ts!ÓµL^ÿÄt”æNE°ªÝCáÀÓ2ºÂ–Éq¦ØiÞ‘…ó¯ºKTEý%¦ÎÂÿ�Ë.<‹uB§Ž ØøÒm˜¬þù4øòÑ÷ zœWßíéÜ%ÉvÀYex`nEº y¤£»þ ÜÕm¤)Ø¿XÒˆŸYŠ>‰ÓÕ\èöp�Ìĵÿ¸õBüá#qOG:î§#I‰ÉZž§ˆ¥ý˜pÊyým¬é�RœW{�ªiײ¾«¿ö ©ô]ú@,˜Ô7×íÀן#çÝw�þšÝã—ˆÃ=­i¼®œÞöáÛǽOx•c…‡JÇÞ±õž•ÖÞWÍñÃÛ‚"§-XDóZ¨Å?­þo˜„”!=xÖ®÷±¬½°u çu`u�¥|¿mÈéó#{DË \��4І›>÷47ÓþuþK@‚.çñPë>L¿ãeP"ý+FÞÂiˆRŽâímÛøíCáæ ûà;aðµÄôÒ<±j+½%x›PpJ ©^‹«ûÞ¦ŸÊ–Н««GÀ[ÆSÞ_õ_/ÆYÉ�¨ÙÇ>6þÝe•ôŸ³ñØ�£1ðÂnèÜI[÷¼0 ‹w»aÖñ0øòKO$_�e+Ñkè}j]Ó2‹ñØÐLè3NõÞ5gU1fŒèÓ3 ­ó´ÎÛ4wÆ-“«¾yLÿ@Ìûœ9¯ð>Ìx\$ë)³Ø ï›æ\`¾3¦)ž{úÖ¢|�ÅëgÒäU¦]ˆÇšÚøÏŠyÛô}6¦ö�`Êí�’×ìû‡”Gdðå&‹FbðÅ�¶â2<—cùq­L®�òƒzH¸lìÈwóâ»1æ·o˜É_,ªÆÏ®Ðåz3ÔׇE¡[7}Fø:q½&Ìij/£ß¼?»g<ÎMhÄšiÝq׃ŠÁ$÷ÿ?¾nº�EüKÈópGâmª7rïcð墋ŒHweÔÅãêÅgøødzA{.QÌÓö„AOœúYG™|3(g¿¸1žh«¿W¸V0ç“®4yàÍë²w•W=òã0¸ÉVâ=§5hNpË×-Œ¤ß»ÒÉûS”üÞ("ž²\¨ºGÒ®ßÔ ñµÁWmžiÄ;wvÇï4—¬Á‘\CcùŽ|Œî¥¿ Á9ïóâ«^swOËx¯©'öÇ3µš°üóˆ§Éà·â]¸z6×°é‹Ïðñ;+ð—%ïٙױϮ'ïŒ×«Ï^eCC?ó�Vˆ¿ºIƒ/³‰ä�D@" �HNk¤ÁWPóÛ�´n"#­^ÌHˈnÕô¸êG}y°9 šwáýw>�êà‹üÊÜ:i$Îmcäœ _…tÜÍhý¸›yU¸{@H ¿UyónžONÄÝSInÕkø÷Ìóõå©ä ëe$†Úíâ%8z…›åºß¾JõÑÎ8DäÊ‚ÉäF]ûÈwÛÚK°Ÿ˜ÈÀ0òv2Y?ª�,¹<�täerz²¦± Ø®B=¯¿gÞ;07ù*hÖØiž– Ôœ×2¹ Î\èMžµoÍüœMºvv²~„'£ƒäe: ±÷={ OEÔ|µgDJ³ÐJƒ~�Èà‹ìÌš‰a_Ð’’ÐûÉsÝpó�)ê3º·.¾ ·þV\ÝÝm‹$õøÇÄøC–¸·\…s�–ç)bi?&œš‚¼ñŽÚ3FaVNö»PB{Ó¶7Ñ7QÃA¤ûìZÐo²gÀ�]ôØí+púo¤cÞ¦cx˜+&¶¼—"�y§¹#ÌNDð¯×�OdaùccàœŽr҆ᗪw·–mðûx�q® x9/â<Ì+<¸ExHˆ±Ìy(m—±é-¤ôvp½]«‘œèÏà ɳ�óÜdÓGÐtuî4¼A ㆾ?4Ú ´ãëœÉÊ]ëŸFâÄt• Þ¾¡æ;ÍŽ'~¬˜çnÎ ÕÝÚŸ�oÿ9WN{K‹vó3¨^}7´ßB¥¤“Øþ>W?¨§· oÞ¦Êx<ÜíøD‘+7Ð2Žtäényt%Þ{$Xf\ó‡›ð“¿žƒ/¿ôDbð%<[Í>(^&,ç¬ÂÊ[6!qô,zJƪÒ,Œ ÕR]þbô#ÂÈ`ºx>>›x•¦3Ñ7É|—ó-“÷ð>Ìù»W8•êÇû¦9˜ ÂŒiŠçšžÓíz™óS^?“&�2é=Ç+kjíC|3öí©Äž½ ¸ìŠ î·\Æ{–Œš~Ñ»„6o�ÐŒÀ¢”E#1øÚMÞ³®þ¡æ•…Ë«\ŽåÄ5ª™\åu÷Zë¡Üà ¨®õxwZÜkM�Gæî•§^òŸ}Fø:m~þ6Œù½®+)ªÇ¯®0F§Àåž× #±¬< c/vÈïâÖÞñ6ø:žº+—zò >†mã�ñ¦äI�÷!çigddzŸuÔÉÑù…Æ…óI“—óºzàÍyZ:é8ÕåHGž·ÉÃ=òãEºÉVâ½k~FB·|mk»ètß¶5Ž­Ÿ†¡ÇЦÝÅ(Ë…ª{,ýÊI&V癊lâTƒQ`0î|pt�^ÝHSS˜ƒ·?Ú¢>Úx;çS¾Îç%/=qùÛ31âvMçÌóås Ÿc zÔ#vI¿ü{]¿¬žX‘À<[FÁ3µ<ÃórN§•×Ó�V‹jP_Ù½}Öüã/øÃSÚ¼ °_¶ãsŒí•`Óó2lóò ª›4øbí&o%‰€D@"p# ¾‚?2ƒ¯cuExûƒo´Ôg^�Ÿý8)ècGSE²>-Uã´½àü|äe¶ÒNƒ¯«çâªÉ Õz%“²2kÆ[�‡Æ†$té„‘x_–•†¡wi®PÒ-ÂÎP�sLœ•‰Ü™#�,ܯn¤ˆéîž‹Z–5›hªWR·Î¢úÌtÖ§Y³›‡:áüNWàw�OEB¶•ÆÓËCÝLè¯íÚEâ,åÎDÏæRôW½ª"·”ŒÀ\ìóŸŸ€1srUšÒ2ÉãÙÈž6ÛUÀjò(æf8×¼c5yÞš¬æ+ÊÏ!#4U7à�l]ËäŠW–W@,È­ÀÝN >~„§ð~FF~CtÝ/ÓTLèÇ£ïéYÙ.¼DÕž” §7Œl8"5øRw±N$¯\ª JŒ­›5!Ÿ ²v!ÝÚ�d+¶öSL:÷øL&=NG!ÎV�BäB3ÏÓJËïbð%hÛ½†”Ü)š’[<ßKãèIò¸gþš¿Åãí‡`©@n{WâZ—/]_==ãþ°^�5ýCúPC^ÐÂcÀ¼6 ©EF"so6†»ä-v�54&  y¼3~\1¿°¿Jr(�·Ðnðaº3òÄv�<±Q”–x¤c<ÆkLs�ÊyŸ^áF;¸_C(l‰‡Nî5Z3rIY„ 2†p´å“FGùhó^Ê‚\dÜ-| ÐσÿÚhÌ%EnbO4£È{¢nóÃ#„–Q˜ãE#û0i+‘׃#|�vf=F›èžV ¿qþZ¼=Ó±QL'«©¾m»vµÖ‡T¯»èXÎ5â=µC9µƒs£Ööe÷ãæ_kÇ…�})˦F¬¾ø"þº+½²^O~Âx‚Ëœõ<íU¾Î1ˆtå[‡Ker~Íz/Ü\6_¼9OãG\sØxœ)Kò°ð¶v½C²•È—Ó4'¸Ñ/¹ÚX§ñÊ…¤'þ²\¨ºó¾íxtTÉö( ¾ø¼al>µEâ{È8ìÃ8l:ñЧ5‚ÿrCÚI…XtÇåð9ÆÊ€ñ^COL_~x¦–'Ë/Êù‰ëXí´6’áö!t9ïl‹¯[@.Í£·ëó¨j¨MÞ'y½ms¨Ïù –ºIƒ/ÖXòV" �H$§1ñ2ø‚âó÷߯7*⯦¦¦…üU+/_¬,^,þ–+EÕ^t}¯¼÷7#Þbåƒ-;ô—+ï-³Þ¯ z_£—±Ø‘Ϋ¼èÃs¤*Ô·Õ?DC–È]&n@Y”¢åEZI%' ÓSºJIÖËá™Å.t­PèS6埬ÌÉ(¦#�­¤ˆ÷‰FþÚuQ^Ep\g?©ÈQR�ò“(ã½W¸ñÞëZœi«Ov©£>ÅF]�Ó”‚*zOi´ú‰°T Vo 2d3ë•9+ÙÄ�Žk4ÃÍñ`õ#ü |£k/(t4fPÞ¼l[›z`]™Váu§g:*”i¢¿òvçe’Q„=m<úk#óÚ“Óë>æ<Æ‘zØÞºZ¥òX£²î¥;ô¾2^ÉÞߨ†‰pþ(_© RÇÃ`³_ LI�µâí~_�#úë®yYeAôÄûfÚí…/˜ùÚò4é¨Vž� �_‘÷ºƒvú¢Kï]O^g;6Žºšt5*«žoÒ.0™Ï1¡x+ži¾§ãÍ:›eíß LR±õ©¬Ø­Õ-|�¨ìùVÞ¤8ΛÊ_þˆÖf7Nž§lÐqãí07¿Ú‘®ŽÒXùŠ:=[T§Æ©©­UÇJqA®’““£ääX¼1D_3ÆïÇA㮆õaÎsY¾¶ôé:_‹Çx�e® úì¼Èš½Â <ܯ âû¹l® ¾­Îi¢¿$§a_µ)ƒÍ3'u‰RaàçÁ½h,X6Íì·‚�¯rÎYF¾Îk¼h¤:¦:y3•U´"Í¢kJ†R¥—Ïç�hæ¼ÂÅÄS”<1÷ò:ß¶ÞCáü×Ö]hµåÃó¤{ßôòqâì”/§‰ÓjÑÂû—5ŸÖÄ0ŽÂ—éÀÔ�…hƒ õVE®2ÍX»yð[Û¥,R~ÒZüöŸ˜å-±ÆVðÚEÃ*wAŠÙÏÉë½O:ñÓŸ½Ærøöñèå¸÷%¯âýÔ£ý8]ôAǬcökíF>Ìp«ÜZß%ªø$§ÎQ 8� A³'¦¡×Œö´ax¼[&ºìyDW>Ç*ªqíGöðÙ¯Õö©(VrÅÚ€þ Š#�µx{yàÆÛ=ü=ëËýÎWÿŠ�·ñ6>6hž‹JŽŠ¡m|÷!½Îqš·7××*Géïã¹ú‡Îå@IDATÖ˜kÊGþù©Ò¤¿ïùß¾M+• b�cü�û«²�Åùú9K!dãüj{ú£õ›•G®´Ò¿µu�š?OGžÁle­¯TÞ{ÈNã+_Ušqöå=cÒC]f¸A·=ïPïS”ü]½ö4‘Ós .4æÆ)ΜeÒl`Ië?-UÒ“-œ´8ÉÊ ‡¾ÅηtÞç5V½Âù8w¹ç}3n²A,kQÞç=øˆ�f6¹âEuö»¦®GùYòsåk:ã"WGÁï�—,ÇÛ)h>Œ¡_Ùú´£ÏW.Tî4ùÒ`eÙŽz¿vÎ9Œ×QºG?hñCð_ÎÏiÓ¯ò5ç¹tÿõ‡ólk2p2iàiÃë‰u=¯Ož©ñbV?�y„ÓÄiµëX5=ù'Óͺë]5l×½dé“ÉšZw[|= u«>°O×\lêý)T_“ïÂÌ{ˈÖ,²É~$û€ì²œ¼>`Ø[Ek®õæ›o*7nTŠ‹‹•íÛ·+­×૲DÙðñÇJnn®ú·!÷åoª±—f¬•™“«lÐß}üq®Rô}µ9¹•‘im-^ü7å½Ü�Jé÷ß+¥EùÊÿ½n{-þÛå{—E�fTÖÊ ¾jª”Ó´:š2UÉÈÙ¤ªª”ªŠR%oÕë! ´#ÕÄÏøÎ?Ç0ŽÂ—iÕÛ¢ƒ…¹® 8�P’Ó)9EdÔ%Ö?¥xSŽmž×>dûI#èðÛü­*ò1¾�¢,X‘£•Š>Gë¨R2˜YÁÇr²´AÀƒ×z�åðíÃq³ÖX®me+ÛŽ›½/²<¿áyrº¸ÁWUQÇ ?çd(›Ÿ*Zÿ—å)Kf±µÒ”MN#M�V?‹eÍè…­k¸k®Qb)Ÿcݸö'{ø•¿9éfÛ%ÚŒK¬và}Àvï�›-ŽGÛZqÂ÷;ý‹åKsAdüˆêìQ§ÿŸ½3Œ¢<ÿÿH8Ã¥ @‰Š·%Þ¥ÒXE©H<е…ZѨµŠU-"^Qøð€­�( ¢‘Ê!“AÀ�“@²I6yÿÏÌî̼³;³Çd“Íñ s½çç=gæ»Ïëø9ªQûi9�r?¨�.WMðUW¶Uüóbm^âÝ_|»xíž³nZÏýùzñÍG Å“wBWÏt‚øf¯YÐ% ¥T7?"¾ÉÝ%*‹ EåÞ­â�{%áÖiOŠ^±Ø¯Ký†äç@ögböþÏŒ÷ÏÿZv5†àËizB|™EÜæÏ®4ĪJ›Yù„o‹w$áôqvõÝhŸÖõEîß"ölÐ�ùr#¾J”÷@æÔÊówþãGQžvÁB ù[rÄ÷{w‰ïwçˆÕYŸˆ´'ïÔû_ÕݤwUÑ�†ÓgQ_ÁÙE÷¿)²ó3c±ÈÊz×WyçÈòÇlù9–øYsåî]bCNŽÈSŸE�P÷|�×Þøìdù9ošX]ôä ýù»°ÞéûŒàyRÂ^|¿üœ=Q,ܰCäós{ÁÑBñÕš7ML§,ßáRl0]Wß%x߯¬\>Ë$òóÔ‘©bõ‘І ¾xÌYäð]¤Ü®­ç-Öý�Þ_ØŒŸ¾svcî™'ýˆ8Œq:è¼ÂÙ<ªñ¸9«ƒ–‡ oy Pë–ôÎuÿOÙbîÝÒ˜kCÌs‡ˆ=_Û¤³!ÏÕú�ÏÃx^i¬g9¹œüÇCçíQoWõ}Ûç�ýaÒXÀ:ûê±4¨{;?7-mIǓЙJ6ÆÒJ^þïÍV¼k=?álò®jã—Oý„Wè§×oö,Q _ôÈf‘•+·ÍÝÈf¦ƒ,%¡8”—Ü`óÎ?­˜ì ßîºâ'ØV™CÓŒ¦7¹ãe7~ù �¬™–Ňw÷ÂõôL›Ï–¶œ÷¦Ó蔀±±^k:­ûôoÄ«x©›Ì‹_ÎÐ]gX¬I襤ä] RŠÑêP*SvÁã¬$Ë:"‡g5/÷µhÑÉ4iÒ¦»êòHò�¥¤»O¬ü‰îSÖ¿Œ@Ý“‚5–§cFFÌ~GVK:~t„—Œ÷sê½ /!è¹ÄÝôGy�Šm4£û9ô¶]ÞëS–m¡™ã SÞ²Éj¿0½~dSàzð ³(o˽»u >cªzÙÚ¿l&œ—V ˜O=t²7Ëm¸Q�ܼDÄÙòwÒê#¯Òp/ËÜwï¥Ë&y–Yðñiœ&,îHK=ÃIýrÔ·ØÕ§ÏQJŽ#P6áÖ!ûvî]Т$”Kê’ŽÚ=÷zó/ãéŽùÁû=ÕËÅÓéûw§Ÿæ½õß7Ó™÷Ë-ÿýüu»è¶3½Tl¡ëú&’wuzÇt;-_r2ýþ7Ý›¿©€Æ×.£çÿE½n½d£‘&ëûwqš—²ÿ±ôÍ�Åt¾òlà0=éÿ+ ? Ö^”˜’êsRFoðó©¼µgJ%=�{]–mx‰]õ;`99dÕf-Ç»zmwÝ'e~§rÛ—n6ôÙÀñ\ôõ±”ápü’ÛŠ_;s0§V–ÚR¶PŸõt|‰�ÓW?Bƒ¥•K�<‹*áíã÷DçŒ}^:Ð[z¡{/îãq"/;%yz,«�î=?Ž–ü¾7MS$/™•·z õ�Ü(‡òs0P§…÷�òqaq*Çi®æË7_·,Ú@ÏMé¹íè}†y0«<©�»~¢Ù¿AÏ}©¥Äf?iå½}‹Îeë7ÐU÷|hã˜è–ô÷hhæ ô7¹“›8Ÿ ^ý½ß2œ¾�¬·¡Ì!8@ßw‘Áçž¾©ð9ПÈéÕ}ñsPîÛi|˜Ï ºÿ@¡0ð�G…â‡ã Ÿ›ý|ÏŽ‹òþ èó¡ oË0mX½ÂïŽo–Þ;¶’–ä•âRÇ„á{h’Åû Å™³çêàóF¹.ãdã<ËQÀñ�ç3ë•„Ñç°ŒæÝ>ˆòö3>ßEÓ/ëçãÆâÔý#Íèp†÷�ïHZ¸÷[ººûVãý¢EÿûËW/ÐÈ1æw‹rÈãSÆÑæzú8¹Ï—Ç‚pÞó:ê3'½Iùo_C:Ÿ¬ß»èÓGFÓíÿÜ&g×òx|z½r—w¬“Ç3ɵ2†^òý”ðǃäͳ¤ãÓ;`Ów;)}8h½Úü’ŽE?®‘¬tIV¹$+_š%.eÿÙ¶BÝR…G¥W$¶¬ù@,´pÿöÒOEÎ>Ã"˜¯ªO ×÷z¤Î×ϽMÿ•B°¥f Ö– ¬Ýîsõ_ŽÝf^¾JU³ˆå¯L7Yõàfã‰/åÈ–«ôå-Õï9"U·F3:ôe©ö¯·iñð²Xzv×-ã¶Pœl¯L—~e¬ÅÁûÛžX(r¬,ìç_O¥Ìõü³Ÿc§‹eëͿؕË9{å\q›lÍK�o„¸{Örñ“Oºƒ——7OE9bîtŸ_+a�˜ ²å²å©Ú½éžå)•xlØ�Ó¾ŽìÏ^.î¶ÈßèÛž_¨ËRü$^¹Múå§Q«‡¥êõXcªÝó0lhݳ(•CøåÙFr}��áåù”_1}5_ûEð�~K%j¿âÒöùä_(ñò…^“ÓÚ}ut[–ÒÂô¶Uo½žô Xœã1o-ûÉßb„k¦bõêè1C^ÖB Óû+´àþË$+\Áó©¥Í`ÃËZåUI—öwp•é×·ÃþĸÇn6d½)nI4óðÔ»‘bJú'æå$Ø}ð<qçïøDLM’1lÄsQÊ3lÁËc MO+‡¿{÷'bŠEz÷+Õe% Å‹)æ¥g}­,CU æNз^jV®g¾Çö펱ª…;�—góé›”pö¯Ÿ«·Ù ¯û1üyê~¶Òú„eýVò6bômâ•åK•hwvm9xùØÏ±ô2²‹×¶.6´?gku—‹écý-ï(|”9ÞÊlßeƒÔ3¥>9œ3Ú±µ¼¨>;Œ¿ÁeèäÙÃA½Þ/=óù�ÑAʇ-òÜæígÉf´>ršƒÍ#´0œÔ¯°û–u¡ÄÉs”ÞÃïsT‡lÛyà2Õ-|IK2îZ÷ž…%/£osÓtñÎGëE¥äG[:QÙoçïŸËéQŽ˜»qS û¼¥wIGÅŸ“ô¼øMèýÞ³$6cgù=ó—ü´RZrËx>ÖÚˆ²«� Tßõºk]gìçRÁÛ´ý³�ùhýˆ]œ–¼¤¼‡;§.¬3žõvdËÍiSÍK÷i}¦wѤ©âµÏ7è–½äç>å8ÜgQ�ÿ ±Ò‹2Oe Ðù¼œàpoüS5‹T—â7k¹d9ÆëÆóœÏT&yÛ=/©hµ¤ãnÉ ×øùKÓ¾ùñ;g«.úÒd6áÊ~>zq¢Þv‰Fš,t†ý>#xžŒ¸‹Å²ùêÜb‹ã -ßcój–ï£�?[ÙŽ 6éÔÊ.üçꆌ1‘–Sòa›w­^:¨W¿=[LÓ—Á¥©þËözûr£ï2Ƥ�ÒÆéý§Ú÷óÒ�º/›þ÷{õ}¨÷�e‚§Ïž4UÌÛ« ì0,/ŽŸ¿E�ü�¨Ý{^}¦ún9x_n7>}µÈxn~w\Æ«]<#®öæÙ追 ï/~î]ÂWbh {mÁM••lé´}{®ÒOüÓ‹ìÝ¥±²ø•zǽN½úRïžæ:j•hGc÷YÅÅeá�ËJä¨Ïá§7Hý°‚Î5‡í(œ(ÂrËeSÉsár—Òw*s@îßzö4�ç¾:ôã¨(q;d檬¤Šrc>Ø©[<Ïa¢Ôf}†tÞ¸u±’癥<ÏÔÆµn\î–sµ�ÒêqäxÎF�œF-~®£á?{8{þ ”ÿætÏQýrÒ·ØdºAÏQû›¤¹~;ïC±v�̰”Ÿi«ø�[7Ïë;Q÷ž½Ég $MÞÛg¡ßá÷ªʸÞzÇÜ~'s‰ËÂѳUÆ„ðŸ«CϾ•ˈ?Ë…’÷µÇg„ß8c•ËÈ]sóó¼ÒGÕqêè�hf `üÀXL·&4ô½±7½aô™MñάšßgT‘žû»s¿`Öh m¢¼u8RE1­vò¹z��@@@ µˆ”…¯»¤c4 ¸U ¾­¤÷î@)K=žùk¼ôKh)GÑÁ´0îNqTÇØ@ �XW-µç?es`!íÒòò9뤾Á<7ûû+š}!�   -†@ëTºØ*¾ZL6šMBù·Tén­j¯fƒ¹Y%¤®C,¹»thViBbZ~‰NÊGzÕ~LËH2R  M2θ hɳsiãöõ´¡üZZ¶ü^:Ö”W-¹¥'M[ä¹h½t£ÉNšˆ@;wÅUð�H±�€€´y|E± @ð¥Z8@¿�B·Ï^ç)‰±¯PÁ¢› r¯(VLDÝüð/ïkº±•¯vv?Áo~IFŠšž@L]=uP~-¬~grÑŠ»ûÓí,¤=ë Z1ùŒ¦OPcÄXA˜ @@@¼º²à+Ö×@è„M@™~WÔ¶bë^ai;jÙòG=QÛ)ðå4îh µ‹¤u¯¥ Á€4?�?ÎÐãí†Ð`p ªØ«¶kÇ&7å ô-ƒ€ò€ÇKÊf¼Ëöî ýGˆŽ4„z°@Þœsˆ±¢9—Ò   ÐÒ (?'éhiÇ–žÁ&H¿"ö:Ê–½ _ØÚCn~N‡è«í•½ÓÇV±Uîj�Un§aÀ€@Û!ÐãÌÁÕÏЙWÌ4Až0’r·n3]›ñù.š~Y?Ó5œD�[‰Œ«dá0[øÂ    ¾¢XÚ²à«rË4àÒT‰þXZ´~.�Û^‚€™‘QÌy×ǶW…_ÊC?¶¶K@YBz)øí«Ý­ÆŠVY¬È€€€@3#Ð�­|Ų5áöüx£ÂÁ Gy)êø º^O˱µqêszžÓÛx5°É¾ vÜY(ÏîíÙª¬±Ø`Âe�€{œÙ·îmztÌúÔ* iÞ‚çhܨ>Vwq­ ÄðrÊøÿ0PÇžb�_‰(ìÛ²à‹\Å”óãn:Ê?j‹ëÑ—9Ë8F¡"JhÖ0V4ëâAâ@@@@@@@@Z7ï- ¢_ŽP\÷8:|à(ué{ =¹7a=–ÖP¾È€€€@k%ÁWK¶M ¾¢ÈQƒ€€€€€€€€€€€€€€€€@K%ÁWK‚¯(ÂGÔ                 Ð @ðÅBƒà+Šð5€€€€€€€€€€€€€€€€´@|E±Ð øŠ"|D                 -�@³|Ý;®ªâkX’—.]ª0a„†ß                 m‚À«vVóùhrǰò«h•†J]»v¥víÚQŒà-¬¼ŽŸ~§ÚQœÄÕÜüÌ�;WMRJJJsKÒ                 Ð 8Õ[Að�„à+€€€€€€€€€€€€€€€€´!|E±°!øŠ"|D                 -�_Q,4¾¢Qƒ€€€€€€€€€€€€€€€€@ $ÁW ‚¯(ÂGÔ                 Ð @ðÅBƒà+Šð5€€€€€€€€€€€€€€€€´@|E±Ð øŠ"|D                 -�_Q,4¾¢Qƒ€€€€€€€€€€€€€€€€@ $ÁW ‚¯(ÂGÔ                 Ð @ðÅBƒà+Šð5€€€€€€€€€€€€€€€€´@|E±Ð øŠ"|D                 -�_Q,4¾¢Qƒ€€€€€€€€€€€€€€€€@ $ÁW ‚¯(ÂGÔ                 Ð @ðÅBƒà+Šð5€€€€€€€€€€€€€€€€´@|E±Ð øŠ"|D                 -�_Q,4¾¢Qƒ€€€€€€€€€€€€€€€€@ $ÁW ‚¯(ÂGÔ                 Ð @ðÅBƒà+Šð5€€€€€€€€€€€€€€€€´@|E±Ð øŠ"|D                 -�_Q,4¾¢Qƒ€€€€€€€€€€€€€€€€@ $ÁW ‚¯(ÂGÔ                 Ð @ðÅBƒà+Šð5€@HÊöl§¢Ü ü÷ý’¿•êݵ!ùkíŽbbb¨ÇÀ¡tÜðsøïl:vÈÔ®}lkÏ6ò�J ¤²œ¶ìÿ‰~(ÜCÛø¯¼úh£Æjà];t¢ÓúžH#û�D§ÿêdêß#T¯p            �B‚¯FÁZ |…Æ ®@¢C`Ó[ÏQö’—(¶c'êvìqßë5µ�NbšY¬B:z¸ŒÊ9DÕ,R9áœKéÒGçQ{†`ŸÀ†Ÿ·SêŠT[_GÝzô ®ü×!ü€Á‡›…®•e‡©âÈajG1ô÷±ÉtÉà‘�‚�Ð@ð§FqÁW£`E    XöZþ§Ëh`ÂYtáø[©],¬WÙaÍYûmY™A¿¾ÿyrÕD;g¸ €À�󟦪v‚.Nº–ºvïÀeôn¹*+iíŠ䮨¤ïžIíØÒ6ˆ¾¢AÝ'_Q„�¨AØÿýW´òщtÅ”¿PŸInëhÛ7_ÓšèÀ‘rU×ð½Ô«OOpÜñ4räp5 ^rßúk_ÿ÷·©4*ù¯tÆÄi­?ÃÈ!4�K_zˆ†ž5Š.¸Ð't7|°œöVSüWЙçïs¿iOÜ´‰¶p¸òÏÏR§Ø¸¦�±�€€€€€€€€€€€€€—_Q¬ |E>¢HÀ^ðå¢WS&Òì½�?•>xô2êgï¤UÝ�à«U'2%ö‚¯JZwÅi´d Ñ�g?¤ûþÝ¥!øŠRA´            &|™p4í _M˱�„N �àëíéi ‹/Fþv"=øë´¯¬–¨¢€§¯¤mZãgPÙ£R'í¼ï!øjÅ…‹¬5�@‚¯õןFï|@”ð‡”2‚¯&+D            Ðl @ðÅ¢�à+Šð5€@@¡¾Æ=ò"½wÉF8G÷ÐßnŸFÏç+—ΣµëRé¼.ÆíÒCh÷�#TבztíBÇw õêØÞp Õñ2‘uÛ±ÅR ÑѺXê~Ì1Ô¯{�Ûê úqWf�Y\çÔûØžÔ¯W<»·Øê\T¸¿˜T¥ZêÈn�¥A}¬—œt×Õ�ÛÝž:©iª£Â‚B:Pv”#áô{<û³–¯AðeÁ—@ L|¹+éðžtäȪ£Îß·õî×#`ŠŽþ¼“Š �ð µqÔ¡s/ê~Âñïß«ÀÂW@Œ¸             ÐD øj"ÐVÑ@ðeE×@š��_΢÷&2%·bë‡Ôû¶óµó(‹_£Á×ѽôê3ÿ¢>Þcr«œL}z=?Ö£"ÿSê=áuzü¹Ç©ÓG3é¶$¦nƒï¤â¥ã¨hÍû4bú[Þ‹òîMúó[†Õ1Íù9ãiíÓé¼>²ØÌEóx©Ê©e·Ò†çN¢ôëg’’ y»dò#ôߩ璯\ ‚/™ŽAÀ�H ¾®|ƒæ_ó,í÷MƘ?Ñoÿ…Nêç#â*ͣϧM£ŒÅy¾>è×ÿïºé¶a¦ë|™pà@@@@@@@@@@@@ J øŠx%Z¾¢Qƒ$àTðUºù}êw§"ÈòZøj¿—î½pª.žyκthGúb±±üã3o.¤¿$x¬ïh‚/ßÄ�¼mHnO“Ï�Fïª7O¤‰ãO§.Å»èßk< I®Xõ]ÕË#â*Xó ™þ=˜‰7ÿŽh_6½»F��¡µ_N£óºkN\¤-U©]¡Á#iâP¢w?Öª¤gÞ|›Ój–|Að¥Ã8& ÁWéÏÑã׿¦§áÜûî Úõ }÷�&溎(šM'õò:qåÑÿuû }­ùs%r›ß—õ>íàfŸøß¯iüï~¥ÝU÷|™pà@@@@@@@@@@@@ J øŠx%Z¾¢Qƒ$’àËwIÇê½ô·[¦êK:fe¥RÜ/Ò9Ï(fºØ×Ò?ѸÁÞeժѫ§ÐÊ­1S©xöeªå,Yðuç#OSÚu#¨/áXÊ˲uÞÿ¹jý‹h$­úò)úµW¬å>zˆÖÿPNgœ;Èc}«z‹Ì¦yDfçL¤ ÿš@#½n ¾û�†Üå±ÝuÉ=OÓÊ)#¼Ì‚¯g^y™î»èu™ÈŠÝßÑõ×?CkÙå8 «f|yb Ð`Á—,ÞóJ]võ÷ »J¿X@�_õ¤šº!O,£û=W=Þ?w:={ïûêñ•K>¡q×£vê™›*v²8ôW§P¼ÏJ®|©€ð€€€€€€€€€€€€@” @ðÅ€à+Šð5€@@¡¾FŽ¿“þõÛ©æHÜ¿“Þ~þ?ª(J x܃i¼Üã@š7�—IdQ×È{ÒhÃ6�#my¼üãÍ,¾:çn*œ{5)Ú ]ð5x",�@}$÷®Ýk©çõ³Õ+>�F]5”âåU½nõ0øüÍŒ÷èÌŽ¾œ÷7úMºbµëw´å»;èTõ¶!øšøÈ,Zpà ohžÝ×ìçrÅÏo§SÙ?.!YÁ— N@À�† ¾ª·-¢¿ŽzT�û¶¼|:çóÒ�ÛŸ¾‰^~â[¾=Võ8[Ië®?�–|À—¦¼Fs^û­Wì8ù|惻            MC‚¯¦ál _–Xp@ Eðe—Ìq“¡…SÏek[%ôÌ„;if¾Çå%çŒ4yY»Á»T" ¾ŠYð¥,”¨‹µÆðµÙžk†§CôàY)ô²q�&Þ|+�¿úBúMB_Õ—r«ð»¥tò]¼ð#‹Æv±h¬Ÿä^9¬Èû”…f¯ó‘wÙÉ.ÊUCðõòÒwiÊ`YÒE´í=¯¥2Iœ¦øR6¾<ð/4„@C_‡¿x‰»êV—þ…þ±ù>òÚÔ“T½™aç)‚°+é�ÒytRü>údÔ¯é#\¹ž’.=^w肯@tp@@@@@@@@@@@@ ©@ðÕT¤-â�àË .�4 ¡ ¾Æýv Qeuë}<%œ:œ.�@£ú*Ò-ÞŽn§F?DzÎìÿ•Ä]ºàK�É݇¶ÓssÞ¦™{ÅbÚÍ1wÒ®�£~l­«`Í;4dúøÎ­T°é:“•0Ź ¾²Ö¥Ò(Á׬Åoӽüyð†/ ¾4qš÷_ìA *ø*ýà9züú×8©ôlí]žå]¥ôÀ®¤,ø@›in¯ëh+»ÿ¿-”8ÊW"&y–!ø’`à@@@@@@@@@@@@ j øŠz"¾¢Qƒ$ŠàkÜ#/Ò{7œ œz�-|=¾žyómúK‚YDeåQcÙ¾4?®#%”½m-[8›^Þà¹:ñ‰—iAÒ tˆ-| P,|ÑÊÊšF£:j¾<{= _|™yá š‚@C_lá+U±ðE×ÑŒòÙ4Àl¤�dÁ—¯…¯„W?¡””a!e‚¯�0Á€€€€€€€€€€€€@#€à«‘ ‚¯@tp@ šB|=8‹Þ›8(@2�eGÞümøë¹Üznéb¬ ‚/# #ŽqÞô¸ò?¥ž”%‰f±Ðì^¡Ù×oþ�.Ÿ£XO9ß%Ó ¶ &/éÁ—Â4-��_„YµÛÑ_F)K6rË^Ç»Î7[ìÚù¯›èÅÔoùîŸèïU3¨wl%­»þ4Zò_ówzöóÉ~VÁ”°|7¾|‰à@@@@@@@@@@@@  øŠuoœ|E>¢H 2‚/¢3ÓéŒGWªqÝùÈLúÇu ÔKX•l¥ÞʧÉ_ç]IË-Z ¾Jsè™w hì�¿¦^62V õè^zfÚTšÉV¾4ÁÕ Ͻ‡^Vc=�VdL¥«x¬‹ýøÍûtÆŸßRïèîÕ3C8Á— ÿ€@“Eð5ä¡9ô‡É#©®ªÖ/mí{Z7h,}©Þ¹’þ”÷/~ŠGôupåô�kžUï$¼ð!¥L©ïŸ;…ž½÷3õxÈC¯Ñ�ý–âUË`Õtð‹O¨¨O"%Œ4 Ç øRqá�(€à+ŠÁWá#j�€B|]µV´ðÅQ˜ÄWJ”'Ò¸1ÇÓ‘}ÿ£µ¼Ô£²M|:�Œí«²ðõcæ‹,[£º£Á'Ò%=»ÑÚ Š¥.Ïönƺn@õäÐæ÷iÀ�a—raä9çÑ1eFœD¿£-YwЩúr��_›ß}–.|þD,D+œ{5õòD©þ+„ ÿûÛT•üW:câ4éAB%Šà+PXýŸ}Ÿ¦^ð?J½Ô#ìRÜös%uýå3Ú¡wwÐcå�ÓñÚr�Ûè­^ãè;)à!¿»€*?ø–ö+ׯü‹þõù ¤w| ‚/ A@@@@@@@@@@@¢F‚¯¨¡'‚à+Šð5€@@¡¾|e.=uQŸ€á¨7٠׫³ß þ£«.t?'ßM$_J#{y„ZºàkÌÝT<ûjÓk‡¶®¥/ϦwÙš—yI/ÿû>š2Êœ–Bv?õ©Ùô¡WX¦ù¹dü�ôòôqtj튲7_//~›¦ óXÓ\~³”Nþó»¤,Mù-/M©ZóÞ„àK£„=8'ÐPÁ×¹¯~H·¦Œ¤Ãë3hÉÝ÷ÓVŸîfÈ”¿Óž›LÇ››6ÕÚLÞ•JŸ}�ç“ø èÚ%OÐe×£vÒ¾$8ˆ¾¢†‚¯(¢GÔ AØ ¾‚x pÛ]]A…¥5Ô«{*¯¬£^Çô NÞåxó»å:z˜©£N]Ú“ëhõé{ i{üó…ÒÒ–su NîrwíA}Ø_$7¾"IaµUö‚/gDŽ:HµÜ3Ĺ]TßíXŠ�—ešþaÖ–þB%TKq�{R·>]MB/Í_ ìA@@@@@@@@@@@¢I‚¯(Ò‡…¯(ÂGÔ  4†à+`„-ø&_-¸ð�ôfC Ò‚¯ÆÊ_�Eá‚€€€€€€€€€€€„C‚¯phEØ-_Šà@"FàÀÖ,úäáé¢o§Ï8'bá¶Æ€*Ø2гþNgÝö0�>áÏ­1‹È4:�+^I¥~§ ¢ó¯¼ªÑãjH›Ö¬¡ü­Ù´jê?)®}`«a ‰~A@@@@@@@@@@@@ ¾Ñiä{|52` à˜@]m }ü×k©lOõzõìû+êÞ§/µkÙå'0Ú…àåߊ©ìà~Ú¿=‡(¦ýî¥O(þøÑNâ�I ý«éÝ�_RŸþý阾}©ç±ÇRl\‡f‘wm-.ù…JQÑÞºfäù4㊛EÚ��¶I‚¯(–;_Q„�¨A‚¨./¥­K_¥=ß|Lå~ê¾-:èØ½ <ïJ:müÝÔsàжˆy�ˆ¨geFö7ôiÞ&ÊåþFY*µ9m1CCŽÿ]yê(æhŠmñks*¤@@@@@@@@@@@Ú¾¢Xâ|E>¢‹@uy-9H¢Î–¿Vë8&†:÷ìýٺWL«Í&2Ñ Pí®¥ƒÜç(ûæ°uä¥�ëÖ“:5‹cÍ� Ò            ]|E‘?_Q„�¨AZ$�º½}Ý`ºíßYgÕ®Eæ‰h:·½ý/úãE¿¡‹OÙt‘"&hd|52à@ÁCðˆî�€€?�ì%/Ѧ·ž£óRž¤×ÞéïW@@ÀK@±vã¿ÿA�<‚þyíà            ­†_Q,J¾¢Qƒ´îê**X¿’~úr9ÕT¡ îþ}óò êÚ§? J¼ŽN8÷rj×bòƒ„‚4.�Úº:ú,o-Ú°šnu1}þãfuIƛϾ”s¿� @@@@@@@@@@@@Z:¾¢X‚|E>¢ˆ<!¨¾¾ŽD}=‰:7ï먞…ʱz]Ù{ÏM÷øº"är•ýB®Ãüw„ÿÊŠù¸„*í§ª²C,꺌Núõ5Ô÷Œ_S»ö±Tﮥ}›ÖÐî¯> ý›×Rüq'P—cûR§ž½©Såïê¬ó_l§®ì§=Ű?ußλWÏcùz{5̘ví¼{Å-ÿaÉÈÈׄ!¨õ䮫§:QGnîOÜÜo¸¹?©ã?õ\Ù{¯•UUСŠ#tˆ­yª8LŠU¯]¿  NF7°Øë”Þý¨–û˜Õ۷з|M•, =éØã©w×Ô§[Oêß�úðq—Ž�(¶]{þk§îÛ+ÇÜhçʽö|O¹Þ.&&„\À €€€€€€€€€€€€4¾�mÐ�!ø Š@¢DÀu¤„JwåRÉ®ª8ð3)V¶Ü®£ê_­wï®VΫ¨®ÚEîÕ×V«¤T¡T ‹"bÚŰ€*ŽÚ³�¢}å¯#Ū{ϱr-V¿ÇÇ^7ª[¾ÞíøÔóÄaÔ­ßÀ€â«zsÙ÷•îΣ£Å…jZêjª©ŽÓ¤ü¹9}žãjÏ=ï¹»†Ó®¸ó¦_ª±JM¥){%JšÕtvê±.§ì;v¦ØÎ]õsE`vÌ Ô‹—�SÒ¬0À `&PãvS^QmÝ·‹”—R%·ÍJn{Êþ(·C帪¶†\Ü�°d”EU,®RþXdÕ9®uŠë¨î=ÇÊyêÂ×”½ò§\ïÂ}È`x ë;�:ÙXý+bAØ…{XVªÆç‰S‰·Æ¿[ÙWçjšjX|Æ}÷u,lÕҤįźr¼]¹¯PâWŽ�ïÞ‹Nï2 ;þŠca)6ˆ4¾"M4Œð ø œ‚4:�¶Ž³sõhçÿQ­k;8A]6±S÷cÙbÿõôîù¸C|jÏbE°¥£ZõÆ�:}Ô±¤¶ª’ªÙ Y•b‰LµBæÙW•¢’Ÿ~ š£4hL ¾ò&êÞÿ¤V�™�P(¸–l\CŸän¤!¼œâ‰l]ë¸xŲ[Øòþuå~Dl)"¯–´Õ±LŠ•³øU±2VÌ}hQEï�Ðî’ƒ”Ï ¯~6M8ë:¦K·–”5¤@@@@@@@@@@@@ ™€à+ŠÁWá#j�Ã{wÒOOá¥/§!Wý�zœ0Øt'¡P,£)¢¹?z‹Îýãã4àü+CóW Ð f�äÔe¯Ñå§žI7Žº„-`ul…¹´Ï’b¹ì½ï¿¢•y›è¥ñ÷Ð1]!ú²§…;            á€à+Zv ÁW„�"8ÇVÜ÷9þn¶Nõ{ÇaÀ£AàðÞ|úø¯×ÑõóÖRÇn½Œ8�6Dà•µ+T«]ºx\ʵVÿ�õ)•²õ¿¿^>Þÿ&®€€€€€€€€€€€€€€|9€)/|EŠ$ÂhQ_G¹,¤×ÞÙ�`àׇÀî¯> >ÃÏ¡®½ûùÜÁ)´ kó·ÒÐãN ¾ÝÛ¶èñ/õ¸mÿnºtèm£à‘K�F'ÁW£#¶�‚/{6¸                 àO‚/&Mv‚¯&C�ˆ@Â% êI±üEÊŸ×ssÃù�iÇÿǵkׯ2�ì‚@è”®¤–êùO¨ÿ…î³å¸Œ¡ŠSÿ¸Oh9ÉFJA@@@@@@@@@@@Z¾¢X`|E>¢°& XˆQSEÂ]c}WhKí:tfáWûÀîpÚ�Jª£ án3úQEìK] }A«êÈ.€€€€€€€€€€€4 ¾š³u$|YsÁU�(`±W}U9[ôª�RZK´1Ô®s¡z 1ü&r&ª+Ù²—’‹Hm.Êûn3s�q=N¦óOë©€›8¼´c»ÎÝ›:#”BÇm'Bñ{‚áúöíwtH©oaŒwîÒŸ)kÛ"ŽNu d­^ëÞœqrʤŠ-{fË^mi«>ô#}ŸWÌYŽ£“Î=�†tŽ¥.!XújCfÑ„@IDAT-uÑuˆÇÒ<ci[ª$ ÌkÓ2nÚ>ÃMtÒP±'mÿù)6O;tíO#RËœáYS ç*X„C nA@@@@@@@@@ i@ðåÇ¹Ž wì ’š:¢öñtÒ°y9žÀ[]y!íø¹„?iuîs :.˜Ox¡¾Jw~Këw”N€ÍÝãFŒ¦³½tz7º+;J˜C%Ù÷Q/÷¸ á¨àº¹.HÝìе'õï?�N:¥‹ø@¶é¥Kéìû¿T1¤e•ÐŒ Bk-›^¢ng߯úKHˢ섃²y¸­¯óX÷òIMiÁvÚœ�M·æPY©‹ªø~ç^}ià !tæ™ tÆÐì˶b]Ö÷JZ£„yÚ?©xý]mªÿ‰éØ…b\´zÝþXÜ�FŒ¾„ÅD±>„[ǩӶÑÜW|K—v»�¾T c¼“Ûo8í>¢ioÊÀrršÄC¢†çGB÷~xÿ�´uÃ÷”÷ãN**­"W•‹:uîD=NJƒO:•Fžw:ýªWË–Tl}é*ºjÚZ5Ï�eÒÔó�¡ãb:è ìZK]lý�äVr½I7qŸaYDMž7­~n<]þÐ )9 ”UžM´zQ°”eõ,|‰à@@@@@@@@@š ¾ä’pÒš2éÇRÍE'ºâÖ[iP€ïŽ…?¬¡Ì¯$ÍGì)WЗ’Cµ=Eð%б Èæ†Gx2’^Û�&+ß+’Ò©<ãnjsß)lø´žË´õÛmTÙ¡�yÖ)öâ›g8¼º™Hs2^¢û’"œŠÈ'ç)áGÅÖשÛé÷¨‰Iš³‘2î;+² 3´ŠŸ·Òf6ëר™tJˆÖÆDm5‰EÎåÙJ·¯¢§î¿�æ|¥]±Û�¥×>zšîs²¿×ºµw"-Rî\ó^2¹Mõ?1±qTùÿu1`8uÊfó¾â´íD4W®MtKç³é%Ð0Æ;¹ýÎÙXB÷�šÐ3¢ioÊÀ*6±0îì°…qN’èf¡W1 ¾Ô­âGzõžIô�EÛ‚5>m¥=xUPÁ}Ѐ¢ä ÷�ÉtÙ=缾?µ¡�þÈuêX|ÅQLÀµ–º¸õõ[èô{Ô–Hm¢M,ÕÆ¹ÙŒmçMØgØÒrؿۆä†{çbŠ<ÉÇU eW½A ž }<´ŠÓÖÉ":ÏNV¶ÝY9Æ5ð!Á—HQÞ:úpmŽ.Üò\ާ«o½™N´z±_[Dë>ø�rŠ5©—×Ç©WÓÍcNôÁl}Šàkëë×òG3ù×åÖaY]MJϦŒ»O6_‰,øú‚/+V-ùš{ÿ ŠûÕµœ…D¶<ðE“Y�?6†Ê/iÎZC]ªó&w§,§•»÷0ÇG' F½B4Æ$¤�¾àËM+¦Çѵ/²‘£0¬�‰‰Z—Ê|çGÏÓÐ?<ãÇÌ5c龚ýQ&)FåmÌcïÑÇ_nÊ‚¯‹Yð•ÙÆ_íc©rÇ;º°5 œ¶¹5øX„1ÞÉí·5—‘Á——zÎË¥ÃêR«'а��'p«¡z*‘»€žé0„^6ÁCÖ8šrÁYÔ«3Qé¾M´n+Ý¿(mýçÁ_KWZΡ•à똘8¶ó×.`&ZK]”çm£M,ÖF¹yÆ�æM×gØÂrؿۆä†ÜRÑšWoyN$èw»5²ˆÖ³“ájwþ®q@@@@@@@@@| @ðÅ å­\Dkw{„: Eèá¶|Õ•ý@‹–~M>>T¯ñ|‘ÛM.þ“·X e=7–.yèKõrÚÚ}4ãÂcØ�ìŠ(¶S'Š¥ “à«„_�÷i×?Κ†À¡ÕOÑq—?Α%ÓÆª·é,+�b#$Eþؘ¶¶ˆf\ÜK©®Ò榢üïè�§ï¥‡Þ1äA‹rËéæa­ËΜü1,ú‚¯ýôÔ鿢ǹGôšU5MðUúÝÔûÒ‡�r<ívZþÆ}tåÈ“©“.€sÓ¡Ÿ¾£…Ïü•þ¿ÝmÒœ/éý;ÏÐÏÉGðUÌ‚¯¶ÔÿÄ´!Á—QèQ½�»”Ö½öºqšæn$-ÞËËtö×;žÈ&®Cƒà ¾±z©AËs°Èô[Îæ��O=|‡ý»î?̃¼ÅwÑðIsU_éÙUtw[3ë%ñj�,¢õì$aõ6óvçŸ`\hf øbÙÖºÅoQN—Ll_ºâúKè—Õÿ¥Íªå.kÁ—kÏ:zëS�È¡ïéWÓ%'ÑÒ�7«EqÁ—M…1è)ç%¨ì4fÁW ¾b+~¦¬uÿ£‚TÃö&Žé;€Î<ÿBÀœ‘‹-ålË¡¼‚Të3uˆ?†�z&�™0ÐlÑÇ&½¾—íÌ£Gk©Ë±Cè”þnÚ´z5eÿ\¤k&\F½Ê÷³¥¥_Ø[¶´tŠå¯êKΣ½l¢$®K_vJ= #ì“9ìxrÚIßmÜV~õÀ|Ü¥ÎÒ宨Où»~!Î1 IP–]¬ ¼M›iûÞƒTQÂ@™gÂyçSB8–V\¥´sßAÚüï{èÆg¿TSº`m.]Ì(âŽ?‰ËÓ¬ürÊ£oÖl¢íÅG¨‹•20è4yº5_Ÿ¬û�†SßuMšë}%ò’‡_x—<4Êʺô1}çw±Uš®‡\w*”%¸îÄuðL`ÙBwÅ!Êݼ•~äºK:xü2 5œúÇ›" ¹œ¬ê]éÎo)ó«ï‰ R'kà ³è¼ †Q§¼…7|²ÊÈNðn2Ø„^�KÞI÷¯§{.œäY®-eåθ€jk¹Þ ÜV=‚¯|z4>�þ©•öM/PÁÿ›Lýµs¿½›VϾ•®ü[¦÷Îhúl÷tYoï©,øºæUª\r3¹ ·Óÿ6eSAi ¹ª«©û‰ tEâ9d.k9"E\¶�¶þ´ƒ¨ä>‹·]iÀÐÓé¢3Y„&;õ+îT¹©Ë1é”~ñTQ˜C_¯ÏñÔö;ìÌóéü¡}uŸ¥?m¡uvP wn:ô¢AgžË÷µLèμ¡§'¸à‹ÃÚ™K[ø‘Óæ©žJ»ˆR¬å5ôá¹Tw<¬?•Íó™ðÊÕ£ò¯SFvG!?„À¢K4E+Ï«Ã}þ1Úeðg„Ðóγ“³2µ/ Þî4”�4WÔ‚Ç@@@@@@@@@ Eˆ”à‹„Ãío»„ò½­Jd½ù†xóÓ-¢BMD•øjÑâ�7”¿Ebw•ʪ ¾Rïm)ðø¨QÏ=~}¹Û߃ÍOoØÜ |9;=YpÍSÿøCOÇåbA’Ç%§‹µ™iº?Í¿¶O[µÇ"œ‘‘fÄ¥¹5öIbYv ø-‚¬ÊIÞ´'ÎÉ‹¦yÓ§^KYåBlœ“¨§3Í2åbN‚×_¡§ÀöZ‘›9SÇH³ÇŸu~-Ò+]rš®ìô$=é™bš–v/-m‰©ËŒ¼HñZ–oœ£‡©ù×ö¼”Ÿä%X&ˆ9«ò%÷¡†^…�Óš˜¶Ö�©¬¬ë�–’òÜ ‘ìÃJË«²OšiÅ­Dd¦¥Ø2Rý¥.EZ$¼·/ß*±jŽ];H ÌlGK�‹_RˆÊa0þmÈÄ&Ôz,µ ?V j»òI˜é´¾ºJøè‰×íâûâRQWìo—˜}±·-r¼cûØðSü¥˜¤¥å¦GÄü§&Há~ˆÆŠåÙ†?oœÕ»?KaËeî9ž –oòñWüµÞ¿Œy.C|3ÿë8ïX(*+ ÅÒF[ÞóX†¨öÉ{¸é©¯*åÙéÞðÅ*©²•p�N±éM™–NŒ2"î ׊9Ú˜©§ßwÒ±§Vòè=tÒ?e®Gã ÿÐýÚÈe#�ŸFšÅÚül‘fÇ?)Í’ƒUlÕ¢NÖ‹4�éH±pw_sÙþí>˜#VæäˆmGÊD�Ÿ»B±0m¢©ŽjuÛ³'æm)´ ;oË{b¼o™JçÃ'ÍYGÍéZùâ%z\�m° ·X<¥µã„Y"Ï›ÞÕéFŸòúSXÛV�µeŒ w¬ –c~� f.H7Ú¥Ä[)¯¤™þý‘¶“6åI“ƒö"õA‰sBoƒðÜ7Ú”Mßê ÆI~ ÆÜo™æÉáÖƒæ¾}†|î w6/òïß³¥gþ1�m¡ä/3æ‚ iöî”äùª¹oQÆžK þ £%ÄI¹ªip4çÕb ´Ö>ÌÏAYø ÁV1m€DXÏ?¦vi=ïðĹ<ÉÏNÎÊ.œ¾4„vÇlœ¹¢UIက€€€€€€€@K%àToµdɱyóf±}ûv‘ŸŸ/Z°à‹‹Îí–Ê�`A_ŠcÙ‹GÖ_ò‡¶Äd‘’lˆ�<5’|D!UbYŠù#{BRŠHM�¦ *<þIJ|»¯ùZí�?©‚/í#©œ.åÃ@°ÿ�¥" Ù’¤ûåÖa'ØäWh¡Û;M—ìÏø€” ’’“E’‡Ä9²XË>EU¹‹$A…VN ªðhÚ¢\¯Ç"‘®h÷¸ILžæ)CŸxg®Úg™Å9Oæ��þŽ‹VMÓ?š'Î\åqB=P*ù4˜y>¸%OKÓR|êï´ !×ÂÜEf�–ZRRüx'/ÈÖl—§�’ÀRI‹Ö}*÷Ì‚/‡mÈQ=.˦%ú°â´&&J˜&re8zŽ�ƒúêRñÎMZ=RòñµŸËNüUüÅ?¥x§‹]šPJ|�f„«ò»x‚˜rÓXÉ�r¬øf¯$.+Û$xaI“›17Ý.¦Ü1A×yêÅX±á€äïÀ—žþÅ'Î$ö›@<–tß÷ñ3_“9H�"øUùbδ‘2mŽQü!S&©yLÉ\7ýûäd‘¤ÜŒbO†�Ø+!Q¤p¸ÉI\$–IéæÞr½—Ý)ÇêGôÚª†§?¨™ÓŒxgÊj7)ÑEk%2·aUOU›/R¥ôªéHf>)É>eï/ôà8�:W‡‚/#ÿž2IJ4×A_Q�ÓþIæeÄé‰ËˆÃaÿ¡±9�9Iã§uš¬9˜û9›xø²Gðå+_§×Áá÷¿)¶ù ¹ÌB+kAX™˜ç3'žt§˜úðTqµ©¾Œóv”™D_yY³ôøUÞ —ˆ)?(¦¤éò\F|/¥ÍJ¸eN[±xQc“^ù|õº Œzâáï´ý;+íKÜs'`]ò7}ç£ý»Ór’Ó õïû2¥1!UXýlE—Éóà`Ï+Jyh~¹ &ªs©T‘[jýœáqkŒINËÕ©¿à52üç� ,B˜ŸÈõTæôù‡Ë;س¢àŸlÈe«„ìGÉS¢i¼PÚ£ùÙÉi„×—†Òîg®¼®À€€€€€€€€€@K"Á—_i…&ø’½µ,ÁW¢X¶Q²Sž+fJßædé¶²DI–lA*IdæË?å.g‹’ Fûø"ƒ±;öû¸Æ¿(ÏÌ%ååüçùz  �?dAJ‚/9nR¤˜^äs~³¥üVùä×dÁÝîÈiºdê Å’—d)&{‘!ˆ"¯èÍ. æëåÒÇãC“æ¦h•lá,Y¬Ú#�©Y «DvË´ÐÌ{9OÖed¸ß'YZÓ?R‡P”us Á…¯5�òüLCàÁåž®+ø˜‹î�ë@®Q¯•Te/“>ø¤ˆ\oYXæÉGœ33Sþ¤èoùKB8nC ¨ÇUºE)E´eö%âT_}HÌ¿Fc=Z|¶[Qi.»}Ùzq¿ÞîX¸¥ °4Á—~o´Xº~‡!$;ðµxXYÉ"³+%kc§Mßï=dø+Ë¯Ù‰ÓØÂ×=>%?·‹ovzýß<çceÌv¡øø1ÃâWÒs_êq:I�*øòGm² ’˜šÁµ\Új‹Ä²ÔD]œ’¼(Të{E"MêËS—BF%ô}k5Kc “d“Å-Ù‡Ò?%¤°8­¨D”—”ˆ*¥m„ÐV­ÚŽÉ:HÊ2�˜Kʪ¯@CëGŠÖJýVBªÈ–;ËÚ}"=Y«§\ÇÓ¥|Z LñYŸÈV•´þ¹HêŸó3¤ô$J%÷OЍÙ,XõcÎIuÜXgÓ¸jÃ)×4ð‡s§Ì$A¡<î!ûi‚/?Á��-Z!Vï.»kB{¹„9ŒqbñŽbIÔU,Ë–¿ ñUaý.1Cjã_\%vK¢®‚ƒkÅ-RŸ15s—nX‚/)N+áZø ¯.:mÿÎÆJ¿‚ö¹ ÷VùÈ]&Õ%SätÌo@{iÀxë“m¿ÓàíÜy~eÆZß©`œŽç}†ÓþÝq¿f‘œÄ"i<08HEQ$‰ÂLý·äÆâP.»9úÜ’†0:Ÿ»:¯Y0]jÈó€- S Ö'r=ÕúyH·}þ �³ó<zvrZÎúÒ@íNnc‘›+Z—®‚€€€€€€€€´\|ù•]ë|YYq’_˜‘*ÓG”´µ’hJgÆ–µï "sŸô…\wcu`þµ}Šn�Êp+ °ü€ÃyhV5Lž¥ëü×*¿û2��&±€½í‘ÓtÉþˆ¦YX!àtK­Ò$á�mbÔr~}-´ù„¹Ö$+ñkþ°± ˜()1ržÒ˜!ªÚ³Ê$Êš–¡ ¦‚׃ª\iy¹Ä4Óò‹ZRJ$ A ©^ëaÚ‡"å#~Ò ¡ [CZ•.fÎY –e¬ÕE rž´zg²@”¼ÈdEÌ“†"“h22mH.×ðê±,^1ҢѲß×WoOêâ« bCHË9j¢°BÉ:˜d©ËGðuÿ’­º€J³V¹éU]ÜDÿS{EeÛ—<)’®+Æp>ùQ®¿¿õ/èþdaV]E�$\#1{�Ï’�{?VÃT><*ïdKB2%î‹uër¸NÒc'ø’?ž¦g[ô›lá*}fšX°h™X›kÕ÷Z”#‹YÓ‹�Š5/n+þöúªŒ>“E¥ÊÒ¹ÚV¾Qƒ±58¿$o«VmGp>¦y9[ Y˳<ç¦<¥-kW­™™™ž?>^•™!æ¤JVàÔtÈ"9íÖõ@¶8“j³$œ’¨D·ÞPd² 6-}•ØWî§bñÉ‘õÔ�s KêYÄh|,Ñ:fWòëYÒËzÓ‡}éz8ù她²X ”‘áû·Ldfi©BùÀ&Å/¥KÎ�±ì 9Ïò¯Ê}_ú›]ÊgR|‚¯d¯p…lX(!9‹×ÌB³–xŸ"²äõÁä�f!ÔJH3gúÔA®“3S ë ²¡,I¨¥¥+19EÌY�!6æ[ lärÒê�|-=ÛªÙ|(mP’ÊÕ¦ì,Û-—§Ýu¹ÖX×þN:IË2jB©€ûñši9H Á×5/ˆÃ–a°E.}yFßx‰í_,³›.¦ÜÄÖ¾.-Náý3D"šÀÊ#Ú’,|YÅ) ³(È}s¸ŠÐ+¼ôØ ¾DÉZéã«–�D‘’:Gd¬Ú’8Ѫ •kµ%ù"cÁ‘š’ÂV²Ebb¢HHHPÿ´v ·Å�\g¬…»R} ¡­jmGMOþ"]€C¼¬£±¨¬¼W‚ÈØã+Ȭe«K,å6Ÿ’ÌÖ¾¤|$ÈãŽ,³( °Éù·nãRþ¥~VîÂíŸä8-™7¨ÿ�Yå– '9Máp›¯àK³Ž•·w‹X¶|ž˜qÿD1\§|÷I/®#Yâjéþø‡S~Ðü÷äãâ©n\�žå|MÔë`ÚyH�¨Ë“&¶Ô¥['>:}Á—“2pÒþ�Œ•�Ê\¹'·�pæ<²¿°ÚTƒÚ‹Ô¾Ãoƒq�Û”U;wœ_ÆrŸ«¤ÉI=�Óê7µé3jÃíßRN6iPòkæ/3–A®Ý—¡[ìL˜––°Z.3_©¾„0†S�å8Ãñ§0¸Éìlê¸âßîy@N—™EÀXÕ›²ßpú“°ÎŠsƒò$•¡4¦+ –Ón8éK¶»Fœ+/9¸h) øò+©V,ø’Hr¶-_6Ë/Ò¥�¬†`@){+ër<Ʊô¢ÝæÃƒüÂÝúゆ)_vץح,šñÒb‰vùL˜Ãr0Ïæ4]Áý Ö€ÌÔ?J[-siä@>’òëóÑÂì[9v¯ÏG;v|=1‰EVËÖê �ø¥´‡PÕ=ã^¢´T]•X•.‹ÁŒºêqŸ$ædd›>Z•“|mZ¦µ­»È·!‰�©~Kô¬ê1ß¶L‹áÍö¨¾ú�´âXkk\–‚-EµK̾Xã+ù•ÅUÛ ¾vˆ'õús»øA[J’-ýSS ÛzofI‚/«8ƒ¥Iºo ×Azl_\ ÊR§²`֨Þ<&M›#²K|EP¶Å§ÞØ“)YÓ™Z13[´�ëLÐþ6„¶jƒ—þÕE8ÒÒIü!3QK#×q­�U3ÂK…Ë[¥ß¸f&Èã–M»±"Vþ¥~Vî|ËÏúÜ蟂Æ)çEãdò,‡-q š&Y¤+q°bª]³|iÂ/ϾBäÜ!>Êœçgýküü ‹\G³Äø ù÷e~QÚZ?Á×SÎQÅŸz5Ý<æÄÀ¼wçÎ�«¥¤¤„ä^v´õõ[èô{ÞQ/ñËwºï¬^òm鸂^Û�&¯àK‰éTþÅÝœ+óV±õuêvú=êEþÈC÷�EäÚD·t>›<1¥¦/ �ä2{”Ïjj¨ÿ艔tVùªÍqð4ÏŸ]v×�¤Øå÷Zί‚ÉoKZ@å·«Üœ¦+¸?¢ŠM/Q·³yq;ÞØZeÜÍåt“òKI´±<ƒÎÒ X.C›²W‚w/‘œ§´¬"šqAr»Ý¦ÇÆÆšÎÍ'RÚmÒ'ÇAI©´à:®…�ª!õ§‰L¢>R´îÒŸiÃúuôÙûKèñ¹þ%œ4'‹ëüjÒäø´v%_KË*á|ú·5×Ö…ÔùôÉj‘iCÁÙXÖcN�Ýu3{ÿ3QSL¯_߇þô‘çÞ“åÒccúú;´ºR¼ŠÎ<éÚªÞ›@ß¿A J¿éÚB·öN¤EÊõ‹_ Ã™“ýú¢2ziìÉ4ý+ÅÑÚpà ï¢îëG¿Ÿ¯\S¶ôðœ”töêѽ3u‰ëF±UßÑoϺY�“…YôþŸÎð8¥ zóè%VqK“tß×YzbÚÇRL'­Az“gÚ¹éç¼ ´någ´äýÇiÅ—¦›|’DY%dQå|’ûç÷(îÄõë É3éñÉWÒ©ý{R—.]¨sçXÚ0û7tí³J)™û ¹Îhõ^H=^åvâFÞ»hødÏx—š¹�žùMÚùÞt|ã‹jè¼T*ÍNè�ÒE+îêL×zœóµ§¤óN¥ž=ºpÙw§Ø£Yô›á×zÊ^³ß!öyÞˆô]Xù—ØÉy· §œNiDÇ`9l©ï š&n[ú|Bâ ƒ´8¨¡z*µwì.¹hÝóÉtãCz$΢¼Õ÷R×fús— é?^oSÓçÑ �æ$Õ5tüè t5ÏIrߘL—Ýó®ê“_ôGËùR)½uY?zèKÅÙDZyd%pÓ î·‚–ü¾7MS†–Ä—)õêʇVþމ‰£ÔN‰ÀvsZ iÿZbÂ+5?v{¹møö𫹇ì/¬6ånÈœUª×R{ÐÒ©ìårÑÇxÙ�ͱìÏŠƒãüòGö«…Ý�z §Õ/�6}†’í°úw9öV¿&ûõ+'© 9ÜeùµtÃ)¥ôÜéÇÑCêÄd&íãbè›_�o).¿tx\È~éÇþŸñlŽ?yÎk™Ã€ì VmR¹+çG«k†¯ÀG¡øµŽ7çåI Ûg,“Óë´ ÂéK¶;mäæŠz�8h5œê­–.]JC‡¥®]»R»vüýÊ©ÜÍ©âÌi|ÁýÁ—ÊH^v%i�É Rp†Á\H¿¬öý•¾×«ü kþ¸`à>1S³c #xØv¿¦®­ªåüW%ý•——‹*ÉÈŽÓt™ýÙ, ¸1]·ðÅÛ,òluIʯϯԅ© ­—óTB”y$†¯¯u ëdðê½¼¬ödBªD^žËn«baž-¬%El[ÆÆÓª™F¾äzj�UžärIN·úhX+2¦iBƇ҆´¡àlìê±Ýu úeEðU·÷c1F¯3$î_²É_h¥‰¹´ýŽ÷L~f¯ÛeøñJ­ÙkˆÄtÁ˜É�wIG¾–¤¥ãšW ™'ïxýv½Þ&ÍùÚˆ³‘_NÒHðUU^"JÊmj'@OÔòŸ¼ˆe6Á7¹î¦g[ˆ¤ª²E²&%‹�’¹ÎX·åàõQŽß? É?¥ˆ¬ÜL#Ó2Ìm”?êë¬ÿ?{wUuþ üGH€° #ˆ€ F"¢ .X«–jójU*FK­­µXƒÕ¢V-*Š(Z*‘ ´QYŒ"’Y K�Å@IH$$!îûÜ;sçž™Ìz“0$ù͇03w=ç{ÎÝŸ9G‚�•dº¶Í¶ºjMR·É îx}+ÿÊÃášìŸ‚¯³&û¯ zõãI«œုp·=3Üc¥Y¾þÞÕý�ÿs«»=óœÇþ6U“íE©×a�'û˽5<Ø6e?¿Á¾Â­jZ­óW^üì3œc¿`ûw­å0 ’9ç•ö’�ÛzÒ³Úì©fý¦­ôÝ·UP>>©uØó˜¦ä×O}±[®vçó‘|ÏA5¼ðoá¹_ßÔyýï |]ÿq®Qž”e+Çt=ý5+ƒð÷¥·;IOmŸ+ú*#£(@ P€ (@ P€ ê·¾ª•ŸCûn�3kÖ¬Z¶£ÚÕ8rÖ�[FÀ×WÙÕÆûpz|išä/ØfyŠ3ÐeØÝSµ]¾žÌû̼r£ÝÏÃõÁݩ۪-eíTëá€tU©D_v°›ëÕV¦ °›.u>ȱêñòÌl%DX- Sɯqx/W j’n"•œ¸>Ê/ä­ �ðŠ©yò|V}5¾‡(i÷(CeêµV`ˆ<”ñùÐîÀrWëAô©Kv3oK}Ôý€ß_ë"j —Tè+Oj}Aâ³Zµ�8Y¿;8GÊN}Pj n£¦K]§Çp5FaõõÑø’@ª5Ï vÛé­c<1ïk­B ´rjɰ#›YÁ9úƒV ÎòhÅË#˜ Z²G`–3ø+{ñxk}¿ÿÀ¹®\%àëš<—)ë­Øö�G�îTZ«‹€/›éñð%�W�šÛº¿z/¶Õ §p¾ª×ù2myŠਗëìmÖ[­3¾·åàõÑ×¶£Ö3µ<}ýæßtïHTµÕŽaÓ•}»si•û–xlo�€8wN‚¨ R>‡•õá°Íý“¾êàë¬Ãc°§àiRê�ê XzÔ¾vmzÝ]Þz¹O]·Ç# Ë3øª@{ç‘!Öôcæk{]ÁW˦ZÒç2>x¢¯1ïUÉ“µuÇ]Aa‡>Õ.t×¹‘Ú ­Œ©�]>ó©{ÙêðÛR7¹‡›i^<Õj=Lºt<-¾ÂÙþí+½ËÙû»º?€W€©sZ¯sž}®à×lS‘8ÞzçÛû{ÐmªùU�Íý¶ç0ï#GèÇ�@Z=S~öf~CÞ¿Ë ¶Ë)Hô´¬›®\È6Ÿ¨o÷ê1ÂLpïž–ê/&”ý ¿c¸Ýrµ;_ù©Éõ€‹à+Vç ïú'¸³ý<)Ëö¾v²Yv÷¥ê>Âc»«É¹bYž¶9#CË�¿]yî3¤à…Å)(@ P€ (@ P€ (@�z)À€¯²CÚ¦ï¾3nŠê7F7e|¥½ëjyKÈZ¶Næ¼iúÝwZöQ‡vhç&í;×°ŒM›´¯–¼ëøš5w™¦Ó—•‘!ËÝš­ù‹;ݾÔîPô‡´wO]¢í+”–”*+µÂÛ´ÔgÍ_ÏëïS4óy]ð-A¹ÑîçaÉ1¥{H·^³×í2º[<–·K[èþÕ¾+h éÔ|ÙM—çI·´>°n_¡³ûÈÂ]ÚìG‡Y¸á#¨È/ê1¥k4hÏ.ÌÐòìÓvp>è«Ü·PY.´”ÔuÒª�³Ûʼ]kµ”a.Cý¡Ø¯–vü®Ó9BÍ“ù°1È,^£ƒ×i²A³º¡ÓÓz·¶$cŸvLê`eY¡¶mmª°íÑ%ûŒu”m›­ä;I{sy†v@ê®Þ]ç±By²|ºÕÅœÔ/3æÄwžö)-¥ÉÄ1ojÛèewLÛ•±Äcýúv¢_Ù߆‚Ûx<$RºâT‡cسZƾÚ¾m»´B?�I™…b|UoÑ^¸F©zݸæwÚÌy‹´ôÿ­×vn^¯}³lŽöÌï‡+Æúô#´o¼[ðò øÒ}ž™÷¹V�{P+-8¨íYõ†R2nE–³¥®‚¯µd}½®¿'Þ“ydúÒÜ,-ýÃ<æqNs¿ö}n¾«•¯ºèÒÑ^z||yt‹mXÊl-c×gw²ÒR]Þ¾ mú«Å8-b˜åf¾o›­ì�¥ÜÍýKÞ®uË3MMµZ«SëŒïm9x}ô½í˜©“w5�K/W#èíQm—w½”‡œVªkŸ¥w³{,OËX¢n·fýxTÛl¶”B@€’"÷ǰòïèdoÿ¤¯8ø:eï§tI¦—[­ƒý8O“R<Ü”Õ>è_OÔ¬î�åvÕ˜ÉÚœ5ë´u{÷hßïߣ­ËL×.~]»Ç †tmû33‹ÝAVÙû¹÷ ºÇmSeŸt¸@Ë>Q¢mß¿I›ùŒÕ’0AK?a¶V¢ÍcÖy6A[¶7[Û{¼XÛ{4[[–:Ác¹ïìµZÛ•®« Ñ^]—)-ˆI+b‡2µw¦ªë“å&E.àËîöo÷XY­ ½¨ûcŸ£ì“Ê ÷i©ê9OâTÍj€Éþ6e{Q굿sÒÍvºÜe;·Ÿ_ÕØÜoÛ­zñ©Ûµs?û w±‡º—l—S°4èË–€`óg¾?»Öª]îô†ðÁ—¯s¶àõÅýù‚g¨&×þ-‚¯W�×(“�¯‚;ÛÏS k'{Û¤Ý}©ÿíNÉ¿ïÂ9W<–1ݽ$N]¼�8(@ P€ (@ P€ (P¯}ÀWÙÞÕV°–èecy¿ñcž¶ú]³°Þß]­•ø©"æ²ýŒ8X½�n>èñ=ƒrÃXd©¿Q7§Wo6«Á*úø]Kžuß46žøzŸ½Ù×’Í5x¿O“tª¡t)©<¨u=öHÃ0õaaðeʯwJ«·—.µ¼<Òî#?of„c©wëãÙ¢�±üÄéî²Þœjuæw݉)4Q=·�†¨y \ý-%xYs–íÒž¤èŽwÏvçYï¢j‰«õ9¿yvÙßý¦Õò™¿<X95¤í@_WílCÁmüÖcy(ênÊ•G=]Sͨ6?ÅáøÒ[ó*Þ¦½÷û„�óŒkÆKІ�îÍ–±. ¡üî|C+PZKŸîP湌ÑÓ?Ð^¹És˜ÞÒׯ¾Ôe­“™iÒm®yÙc�Þã“^\íî*ÒVzF¾[­…*�¿l×Ak^y1ÊNº^ u»ô~à®”½s£-YR½ëÝ™ªuÉ÷¶¼>úÛv¬êfu}šè ê6Ý÷ƒÈ _û4%?cÞ\¢MOòòÒ»¾T üï¬ôXŸBÉÿ›îõI÷¸j™ØÚ?yWø6w¦¯NŽÁ~œjä`qz|r|IàÕñLíña^e¦”©¯ýôã‹«·¨µnñÓ!í—^ÝtÐ(f´Æu4]»'Èúô4Œ^è½Nµ+É é6YÛêî Òjùë¹tgZt‹`/Ûe –©Ï|úÛþóm+ƒåÃçy‰ÏtIkƒÞç<6·)=Mö¶—àû7µ\¼�ñ�,Ôùünç6ó«»—m»ÈN-йƒº\ŸûÖÐ÷ï¶Ë)hô%+eiÔ·1Ú6ï â@¦ŒóékŒWÖáÓµ›å*'6Îy•„øh÷zÀ¿E€•¹F©ç¾öóê0ÏëŸÐœk#Oî4˜×N¶ÊÀÞuG íÎî¹¢ºß g¼49(@ P€ (@ P€ (p: 4ú€¯9ß…ðõÕÞ£Úwÿ!ÐË “•üu¦P“€¯mJ�Ù�ï &7Ìïv=¤¼{¶ïàƒm©î¨w϶Z}1—wl×J-%ÉjqÆ}c\¦ 3UZ’QŸ~›szž&}îʼu²^X‡¥h……Ve¬dµ|ÙeAò(åvÓ¥>ðxsm†¶Ð£u4WïÖR×Uë00Xrä!Ý6íYo§$ϲ޷.U3̇%µGß\©J_�9ŶÙV Ùìp£ÅŒ…/+s]úC¼•³S|É$JW޲�U¯…eÚºÔ©Z’W‹1fýM6F›½ÒÙ¤¹u»òÎSžú ¤ºûYiùn—խ㣠=—©/;üm(¸M zìë¡wàý„¦�”ÖpÔîõÏ{ÒùhÉ˪GCï¯Í[¶^+Uµ<–Qü?í×Cþ¤?—åÍÑ’|%?÷AõÀ+ Üú|úýî}“YnÀ`í…yÎ@¬‚4Ïœ]JJ _wºÒ(Ad]Lêé,X¯�v¥É æ¨&­‹™ã“¦[_UvÒsó[>ꥳ¶•X§Mã#XÓH[¢6æÙÙÚ®ê•Ú¬ª>ßËö­Ôõ±�ëûé £‘“Bmö˜a¦z½8¶ÙjÏw= ^m;fb •V' ûž%~›…”íýM«[V«ìe[—V õWaÆlÏý�¾Ï“}á³lõ0sÅAÞƒç¿LKu·å«KÞð÷OÁ×i%:üý‡5¯ÏO~œ‚§)˜CõµUj'•À«bí«/æj£“­®­²um³‰C´ÑSçj_²Zö2»O4ßwe}ª=”äìºÑ{~½å°e{ ”uš­|éAgYÒ Ø}õßœÿ¤ Ú™^Ab®à­ìCke}Ö~ÏœGo)lÅáƒÚO¸ò“8A[çjUì«Tk=¯nr¦ç„X{Õ¤ ìnÿz€t¸ÇÊ`ùصÐÜ~ïÖÖJ«£ S”ÍmTo±s›¿÷ð·)3Máo/Á÷o�Ž·æz}½/Os®ðóëoŸk¿ø˜3Ž ~öfêõ÷Ð÷ïιÂ.§Ò /9o¥õC•P[Èt¦Èó«KP¢Ç9nðúb-)üruÎkw>kÍþ>Ù¹ðoáo-Öpû×?¡;ÛÉSðk';e`o_èœÝιb™rNçëºÞ*~¢(@ P€ (@ P€ ‚@m|5Ñ1ä!XدççUó­í¯ÔnbíÏç(ANN¡Ô=ùRbÛ¢½Ÿ¼ª+)/)Á±£.k©»±mÛ }k;õ¨9?�õÇÈê£e¿0sJ·¡ò"9dc­¬”zÑ&ø¶z² Ò¡Êf}v”£¨¸eeÃ>:¶Ú¶ë`»î”ä¢P–…J 6®3:¶ P Ë‹ñS~9Ú´‰–m%�:´óªÛ”””õ¡u‹0 ÃÊ]xŸÂHO›¶íÑ$&ȱMlKŽÃÑ2}»Ôët¬l¿íQ“]kQÎO(‹iƒ˜Ê2D·í$uÝÓ×!ûžrá�nѺFë ÎÆÔR‡Ê+“²�q–}µ}ä).û`Y°¹ ¶Xsü)ݘ+­…÷|íªŒx)kaz,•ãzy¥ìSôc`t ´�ýòaìPK‹¢Ø}Nҭ圤U(ŽlsGŠŠPâÚEËvzVG9&yUȹHñ±rã\¤E›ö83Œs‘(4AÇ&ÍäÿºÕdû¯½c¥�|J™çÊñÛØõÇâœs;"è»ÛT½Ü^j�_oqÛõ Üsï‡ù½vËÉ�¥ã/Åÿ{u‹‘Š…û*qû¹žÇ¿0“W;“Û-W»ó…�êSu=P÷×?VfÃÏS×N6Ë ì}i°í®Î-9~¢(@ P€ (@ P€ ê³€Ýx«  wïÞhÕª¢¢äI¾Â¯õ-à+ürSÀó�G¡|µ7Gñ�§�€V^ ­J¢°øª¹@“(DI šœŠ�š'—K @] —p¯£š¦[W«8í—Û¦I4Z¡éiŸN&�õY |ûÄ^x¯3 I³qlÉï<”³>çøôO;¯Nÿ2b )@ P€ (@ P€ (@�ú-À€¯–¾"ˆŠWͧœ«³' �t¶òe¯ÁF{ël s5‘Ö³š4= Zi ¾ÌVý(Ò*Q�“õ+ѵ”ÚfˆB\im‘/ P ŽÈùß$_–ŒÕ®5HW”—Èp¯:y±¼þ ™ŠR€ (@ P€ (@ P€°%À€/[lµ3¾jDZ>,…<êC)1�†€}iÇ¥¥¯ÆÝ"�íÚ M^F5k 0ØË6!glxzŸß%ÒÊW©´öÕ˜^-¥U/½u/¶óטJ�y=u%øàž6Hžç¹ÆÄgWâOýÌ«ûgÏiøíÔðúçÔ8s- (@ P€ (@ P€ @ã`ÀWËž_Ä?Å«þßk×â²GVk�º®�_Á.Oqpuá œ¬‚&Ðÿôh ¾ü èÑÒ…c“(é²��^þ�8¦Ñ È^•úŸXÚ@5ôÝAŒìb$Ì«)C½h)3[§‡@^»8�l±R“ôì¤>•Ä®-’ˆ~âõODù¹r P€ (@ P€ (@ P 0à+‚…Ì€¯âŸâU—çÿˆïÌ—µ6CÏK.Eǧ8\(@ P€ �@þ�[ðc~©œ^7C|×Þ8·#»q<�Š—×?§Si0- (@ P€ (@ P€ @C`ÀWK•_Äçª)@ P€ (@ P€ (@ P€ (@ P€ (PðÁBcÀWñ¹j P€ (@ P€ (@ P€ (@ P€ (@ ÔC|E°ÐðA|®š (@ P€ (@ P€ (@ P€ (@ P€õP€_,4|EŸ«¦(@ P€ (@ P€ (@ P€ (@ P€ @=8m¾þtG=Ô«a’çÎ�k,aÔ¨Q5\g§(@ P€ (@ P€ (@ P€ (@ P€ ƒÀß:sùäÝÍÃÊî‚ лwo´jÕ QQQh¢É+¬%¸&6#θé¸�Ùëõ< :õ︣F»Õë’câ)@ P€ (@ P€ (@ P€ (@ P€ (�™ËZ+fÀWüðt®’ (@ P€ (@ í‘Ø@IDATP€ (@ P€ (@ P€õX€_,<|EŸ«¦(@ P€ (@ P€ (@ P€ (@ P€ @=`ÀW �_Äçª)@ P€ (@ P€ (@ P€ (@ P€ (PðÁBcÀWñ¹j P€ (@ P€ (@ P€ (@ P€ (@ ÔC|E°ÐðA|®š (@ P€ (@ P€ (@ P€ (@ P€õP€_,4|EŸ«¦(@ P€ (@ P€ (@ P€ (@ P€ @=`ÀW �_Äçª)@ P€ (@ P€ (@ P€ (@ P€ (PðÁBcÀWñ¹j P€ (@ P€ (@ P€ (@ P€ (@ ÔC|E°ÐðA|®š (@ P€ (@ P€ (@ P€ (@ P€õP€_,4|EŸ«¦(@ P€ (@ P€ (@ P€ (@ P€ @=`ÀW �_Äçª)@ P€ (@ P€ (@ P€ (@ P€ (PðÁBcÀWñ¹j P€ (@ P€ (@ P€ (@ P€ (@ ÔC|E°ÐðA|®š (@ P€ (@ P€ (@ P€ (@ P€õP€_,4|EŸ«¦(@ P€ (@ P€ (@ P€ (@ P€ @=`ÀW �_Äçª)@ P€ (@ P€ (@ P€ (@ P€ (PðÁBcÀWñ¹j P€ (@ P€ (@ P€ (@ P€ (@ ÔC|E°ÐðA|®š (@ P€ (@ P€ (@ P€ (@ P€õP€_,4|EŸ«¦(@ P€ (@ P€ (@ P€ (@ P€ @=`ÀW �_Äçª)@ P€ (@ P€ (@ P€ (@ P€ (PðÁBcÀWñ¹j P€ (@ P Q œ()FáŽ�(ÌúÞø;q´°Q:øÊt³¶g"®w?Ä� â.è�f­Ûùš¬Þ;á¨BfÎalÝŸ�­ã@ѱz™§v-[ ñœ¸¨Ë™HìÒmc›×Ë|0Ñ (@ P€ (@ P€ @ø ø ֿ߬`ÀW­QrA (@ P€ ‚ ïÞŠuSÇ¢²¬­ÚŸ‰6gvD³±Açk,œ(/ñÃù(-:Œ˜–mpåŸg¡]÷‹Tö�–UàOÿZ��¹…hݪ%Ú¶k‡Ø–zhRïòyâDŽÁÑ£ÇЪE3üý7ÃpÁÙqõ.L0(@ P€ (@ P€ (¾¾Â7«µ9ðUk”\(@ P€ (@� kÿzÊó³1lÔhwV|Ðé돰zîLÄžu®™4¯A1ücÍfÌÿv†^7 ç÷îÕ òVxø0–ÿ÷tk×3{}ƒÈ3A P€ (@ P€ (@ `ÀW`Ÿ:Ë€¯:ååÂ)@ P€ (@ x¬xäzœ}^w º5Ùc¸£hþýéü(Ý=–•Ÿ@ùQ EÛÖè|vtëv]Ú›zÌÒ࿬ÿÏ<äþ´׿º¢Aåõ…eëñÍž<Üù[Ï: g²òPÖÌ]ŽãúgiíL�(ZuŽG|ÂèÖ:žÙÂ~ºý·zåjçìÇ‚?$�nIcz(@ P€ (@ P€ (@�:`ÀW †ºH|…*Åé(@ P€ (@ Ô\À_ÀWÉö�Ñá®w¬ ^Ÿû F'ž`š†5ª1|Ul}�Ý<>`ALY†;ÇÞˆæ§ >²dßzlOÛ�n·ŒDÇVÁ§6¾‚ q<(@ P€ (@ P€ –¾"Xž øŠ >WM P€ (@ 4:¿_»>C‡o‰G7L˜økô®<Š£¨Dæwkðîš}n§ùK>Ä­]›¹¿7ä�2àkûÛxìH±&âÚ”ûqΙÖUqÒcÕGk¬â¾õ]¼øÊ(´´†„ù©«Ñ‹¶·|œ�Ÿ÷mæüÕ'gÀWu¡(@ P€ (@ P€ @C`ÀWK—_Äçª)@ P€ (@�F'<àk(Ò7<оJ÷�;¾˜‡~�ÿÛ°2aVŒìa¹U•`·tXPæ@LlKt8£ÎîØÑÖÆ'GÕ 8MÑ¢ySé.2ûò*Óº%â;Æ¡…k]E¹û±7_:Œ‰FËVmЩSÚËô¾^%E…8p¸G¤×Á–mZ✳;Ë´Õ§T× Tá`öAäëëhŽ3Î< =:úïž°q|%c⮹ˆW ²â@þsõ0|íb¾ö»qÛÏÏõ@?YQ‚ãÅ…Ò-h%ƒf-âŵÇ4Rä{Òî?ÿú¸iáO>°*+dxÓzñ[/GòwíEiÙ 4�=­ÚŸ…vgµG”5…û¾Üü@ P€ (@ P€ (@�F!À€¯3¾"ˆÏUS€ (@ P€�N xÀ×åX—–‚þM7•à�1÷à±tàf øZä øÚñÍÇH~ð]lõVpÖM‰þíÍ`­r¼3f$ÂH,MŽAÒøºç˜öÁûøC÷b¼üÄC˜¨4 eNpó½1ï¡�p‡eß�—'ÿ?±Z3§�0i*þšÔ[ 6s­·ø·Hñ<¼ùëgáÝiåYþdù^!IÆ"wÀׯðç>BWï®§aÖeðÅú3žÝõ<â$@«dë¿ñÙô™Xõ¹�B¼~&þý/ˆ7z-Aúøv˜ó‘Yjžï½þº�ÜÛßxhÍëxwÔxäxN\ñgüù�gÐõL52 `À—7¿S€ (@ P€ (@ P a 0à+‚åË€¯âsÕ (@ P€ @£°ðu/�ù&*_;–¿‰~O®pùuÃÈ».FË›­îϿ٠nFGcŠr¼?~$FW‹ꋵiÏáŒ/^E¿IΑ} ŵ݀M›Ö`í.™ùÞgQþP¢s=U¹xjàýxɵVÈ´õV}°Ætvó„©�&�—�õžßúèùŸXaj“ç¾�?&VùbÀ—�€/qÍž}+¦>ó_ù4ã7­DO ä*üâ�xúÿ^s²Kw�½®?O&ü/²¤ËFãuë‡xí•Û¤e®r¤Ol�9¸†{½™_‡–Ü�çyÇ56-še¯Âן;CÍÐç¼ðéC�z øòÂäW P€ (@ P€ (@ 4p|E°€ðA|®š (@ P€htÁ¾wéxóÄW±è—U¸wðc˜/z7ß?oþ~ :ºóÊÞðz�u¶àõ΂ù¸ç|½m.5ðê¬üä^\Ý9EE%ˆ•~º‚Á†<òC‡o‰�WI ]W{tÿX.Ý?Ž4º4ºk4r¬À«§gÍÁÄ�Fß~.ûøð/¿Á¨Oä«t¹öùÛqyGwŽJùH÷Œö�ÔuÛã(yòJ¥ëFV´®{Úhéë¾ßÄ?ï,­õŽœ8 ³oï¡,øú�§pÝ›ÒÒ×/Ç£øoC¬n#]S1àËwÀWå¾cüÐßJî€/Yå˾¹xpè}2àWø“tyž»‹È|;ºæ}Üþq±�Y�[V@™´ öƒ´ æžG_n VßÙ‹¾Õçs›¹VÇ€/ß(@ P€ (@ P€ (ÐHðÁ‚fÀWñ¹j P€ (@ P Ñ øòGr9æÿgž]ÙkÞC¯ñz�®—tÕ8ùæ«q˰KÑ£­«é0bòˆûð¬tóøô¬w%h,ΜÚõn„Y-vY_¯Kkc£�ÖÆ¬Ù¶.z&KÙ€q8øö��vª<^ øòð%-|�÷náKä*¬ÇÆ�?Ç�}Y(È?Š­%è®ä[l0ºa ðå¸u䛿áÉ»&9Ë¢ÏPôò¨_k�%Á^ú‹_NþO P€ (@ P€ (@�Æ*À€¯–<¾"ˆÏUS€ (@ P€�N ”€¯!C/‡Ñ#b«Xt?«\Ö7 ê�ö®Ø«�ó§àÊ—¾ j÷úïKp—Þr“xe�©³ŸÀwËã�'ç-t©c&Kp×õப\<5ð~¼$#Ÿ~WZ 믶¦Ïa­ÃWÀ—¯õª_ðeµ1åL¾||Yó$ž5U�ñÀú H8+ù_<‰gþOæçÕgžÿô/°JMmáË3à+{ö­˜úŒèg‘wJ _ƒõî$]/¶ðeJð� (@ P€ (@ P€�C€_,g|EŸ«¦(@ P€ �@ð€¯Ë±n] ú7÷O“/-|uÕ[øpŸ´Œusµ–±ªÏicù ¼²¦?�ƒ{÷bíš•5}…kð Ø´î~\м/K _¥…¯‘_•î»Y³Ÿ¬¾†L˜†#õ_É^†ÒJ—´Þõ˜Ñzׯðg邱«GwŠúäEÒ¥bG£KEàa<µëeœU±³.º[dl¯ß¿‹;Ç&!îÌ6Ðã�m|OÞñpýLL{g ¬jå?à«DZøzBoáëŠWðâ¿‚G�¡²L/|ù“áp P€ (@ P€ (@ 4L|E°\ðA|®š (@ P€ht¡|­MKÁå¢lJv}†#Þ»nXôÉ4ÜÜÙìvÑgàÀ+_sYë¸ÎôXËðhv47 {kea½ò6^ÚQ>Yóø 4cÀW¸_ü8û>¼òLªQd‰Ï�±É}=ƒÄvH�˜Õwk`WHÀ׿||Ýùi1-Á9k‚t–ˆ±_o@â9ÑÎAþgÀW ަ(@ P€ (@ P€ @`ÀW ”_Äçª)@ P€ (@�F'JÀ×: øê à ûñ‡+»ºÞù¿Â§ÓF`XWW‡ˆ%øú¿‹±¦ã�˜h]é ¼ªÂw‹þ�MñpûeÝо¹3xlÇšè7~¾Ìk|ÙkÞC¯ñήþn~äi¼3ª¿³u±ãûñò“aâ}]Öô�× 0à+pÀ×âݳC ªGQ¼;é3oÅŠÏucýåjÝKb±¬-àÚé�ôÿú#ÆQ‚œ¯gcΨñÈÑ'÷ÑÂWÚèvø—,oàó0*¹¿,¨GÊcqF‹½˜A_|­Ï×ça<<ë)ôîæêºQ¦ùqÑß±ó¬±þósõ)Ü/|¹)ø� (@ P€ (@ P€�B€_,f|EŸ«¦(@ P€ �@­|‰Úî/ÞCÂãÎà+qÀ帹Õq|¼f«ËTºbÜ ]1ñ[¾ªöãÞ�AíÒ_}ôE\ñV¬•®�×mQüä@´0¾H·Žc¤[Çt×8iaìæ¡m”u÷=ÿ:ÞÞÅ5A€õÊçOÁ•/}']SŽ“®)o¬Ö5åúÿÌCîOûpý«f÷’æzë÷û ËÖã›=y¸ó·�¾ä±ÏŸñçŸG×3\Ó8~ĿϿ«ÌŒÆÄo"ÞÝú—Õ¥£1[ŸD`»t ÙGZût Ž~òG<óÀkÖ¯øÛÅ–Ï�¨>>Zº“|g)�1àËââ' P€ (@ P€ (@ 4|E°”ðA|®š (@ P€htÁ¾†b]Ú£�[ør©íþæcŒ{ð]£EÈó‡âõGoÅ=WusjY�W¯ð>F+Ý÷¡ªÎü'FÍ6y¬% ¹KZ{èg]úŸ¾/¦Í‹?\e{éË °^{ð›èþà|ô½k"¾ýÓ@(±CF"ðe0¸ÿ‹¿"Wýö\ùËApÇm¹ÆVJÃÒG†aÕ·îÉ‘øû™øõŸïBþÔv˜ùžhIÀ×YʌǷÏÅ㿸ϚA>ÅßúF¿ô't”ÂÈ_ó:>�²<¦�/}’qgÊ Ú1Ê8|)üH P€ (@ P€ (@�F À€¯2¾"ˆÏUS€ (@ P€�NÀ_À—}ˆ*å¢<º Z8ŽÃѼ5:¶mþâªN ¨ðJ¢cÑ¢¢ Ž–gàì@Ë‘®#�@ ™¦¼èرuµ€­ðá9Gc ø¨¬(ÇIG¥tåy—ÿD6¦u4oîç饫,-Ñ'ÇI õ³¦wÈr¢åköÒ|–GKÝ)ÃÉÖ�к•÷D?”ƒÊè8é&ò(N¶ˆCë3œí½y¯�_Þ"üN P€ (@ P€ (@�†-À€¯–/¾"ˆÏUS€ (@ P€�N ö¾.aã øª¿åÉ€¯ú[vL9(@ P€ (@ P€ ì0àËŽZ-ÍÀ¯Z‚äb(@ P€ (@ „ ðÅø_ MÛÖ¸öÞ‡B˜ºqOòå{¯¡¤´ ?ŸöIƒ‚xé“ïðÅölŒ¼'ÍšÛh�í4ÕøxÉÇÐJŽ`þý¿:MSÈdQ€ (@ P€ (@ P€µ)À€¯ÚÔ sY ø Œ“S€ (@ P€¨�À�Ëÿ‰­©/!®K7t<·Úu>Íb[Ö`‰ kÖeÇQœ{ùû~Dá�ŸÐ÷îÇÑó÷4¨Ln?x¾ÿb[¶Ä9]» îÌ3Ѻuëz™ÇŠŠ >ŒÜƒ¹ÈÏËǃ?¿·¼ ^æ…‰¦(@ P€ (@ P€ Â`ÀWx^µ:5¾j•“ £(@ P€ (T ;m)²×.AÁö h'«‚Nߨ&hÕú\†®CnA×Á ³µ¨­û ðïôøöǃ(;QY¯‹¸iT$ví„_^Ü7ô=¯^ç…‰§(@ P€ (@ P€ B`ÀWèVµ>%¾j�” ¤(@ P€ (’ÀÉÊ(+Ì…£üxHÓ7†‰¢[´Dl\gDÅ4œ®•ÛIMÃá’29^h²Óv\l³htjÛ 1M£NÛ42a (@ P€ (@ P€ @Ý0à«n\CZ*¾BbâD (@ P€ ´À7/ŒAçK‡¡Ç w5è|6ÆÌÍÿv›´$–ƒéÉ×5Æì3Ï (@ P€ (@ P€ @ 0૎`CY,¾BQâ4 (@ P€ ®@Iά|< ÍÛÆá†é+¤u­æ 7³�(gzëaKþ—…é+2Œ\ß>ðÜ{M"Z5�iD Ì*(@ P€ (@ P€ (PW øª+Ù–Ë€¯�8 (@ P€ (@�(P¼{+öó r7®Fâ=)(Úµ ÓW¢ë�[ÐåÊáhѾSÌuÃÍRyev*BÖ¡BìÈ-BÆž\œ×¡-Æ^{ âZÇâ½µ›±vG6.íÖœçüëǰ†[%˜3 P€ (@ P€ (@ Ô©¾ê”7ðÂð؇c)@ P€ (@ DZ@ÓNB«ª‚vRÞO:œïUú{NêÃ�qò]ÞOÊ0Í5®êDN-D…þw¬Èú|ä0JîE›.=ù�ˆxšµiodóØ�qàÛO‘³~…±üV�Ï•qqFë_z `Íψ3¾7kÝQMcÐ$ª)š4Õÿ¢�ÏQúgc˜×w÷°¨HsÖúúõ–´ô?ùçzw~?yRƒÃø;‰ªª“¨”?‡”a• «”²rTéãe˜k¸õ.Ãõñ®y�áúüú¼Æ´Îù+$À+ÿX JŽ#ÿèq?áÀùgµCŸ³Ï4þ.Œ�Ã9íÛxä·°´™ °-ç0¶<Œ …Žm[¢cý/±Í¢�a1M£ÐTþbd|´¼ægy×ÇG7m‚¦ægeœ9½>¯± }Ú(ç´MšQM¢äh"_¢äÏ9LðE P€ (@ P€ (@ Ô|E°¨ðA|®š (@ P€hT'+O@¨:š½SÞw£òøQ8*ÊPU^æ|×?ËŸ1ìD9ªäïde…iF`ŒH%ÑThÕÔèv±iL3D5k�¦ÒcÓfÍ�ÃŒï®á2L¥¿»†ë�]m»œ�6çôDÓæ±ý+ŽàÈO;Qš»ŽòãFzô 2gºN ªROcNi•á’Ö“®ñúg}œVUé PÓƒÕôˆ(h’&I_L D7—´Kô¿hã½¥ó½EKÄĶBëø8£Û’Öó�üLl#�•Ÿ@žFéÁQyÇœï%•Fð•ŒUé¨2‚²ôÏ'$àªÒ¡iYÃÌiNèAWúôFÐÖÉjAKfS”D4éANz@•ôdNÉp#Êün½›�Vú¼Æg% J]Nó˜¦è -wu� -=X«}«FðTîIô)>^.&eWM P€ (@ 4h= iÓ»“PV˜‡7Œ”`¥!F÷‡ :Óu�9½+Ë< šÛ½"UäÎÄ%£Ÿ‘V΢ý®é§ÃGñúÿÃþÂcrA\tN$Äw0ZÂò;G4H�£e'�™ã øKÛ¹-b¢ñè pÁÙq 2¿Ì(@ P€ (@ P€ N¥¾N¥¶×ºð寠(@ P€ jI`Ïçóq0c®úó¬�[¥ª¥U7ÌÅH PßL‹³/»ݯé3�‡Ž”bìœÏ0òŠÜqùawqès¡Ø`–oÞ�7¿ü¯Üõ3ôìÔ®Áä‹¡(@ P€ (@ P€ @$ð u×:ðA|®š (@ P€hÐz«T±gvF›sz6è|žÊÌÛ¿KZL;„N_ísµ{ Ž W‚¾®èïs<RàûŸò¤¥¯¦èsö™Ä (@ P€ (@ P€ j À€¯àÕtV|ÕT�óS€ (@ P€ (@ P€ (@ P€ (@ P q 0à+‚åÍ€¯âsÕ (@ P€ (@ P€ (@ P€ (@ P€¨‡ øŠ`¡1à+‚ø\5(@ P€ (Шb¢€è¨&hÚ�|Ðd|•üç8©¡òd�‰ýŒÖ¢¢q²i4´¨¦ò'ÀWãÐN"êdšT9%|Q€ (@ P€ (@ P€µ'À€¯Ú³ {I ø ›Œ3P€ (@ P€K@b¼Ð2ÚèÖŒœØ- ~wh�د�_Žf±8Ý,äé9aȪªDtE™d2ŒJÔ°I˜; P€ (@ P€ (@ ÔH€_5â«ÙÌ øª™ç¦@ĥسs¯bbÐùœ Ð¥C‹ˆ'«îàÀþM�}\²}Fw Hè\÷«äê@€åX¨a-²<7 ÷È<1èÞ:×p÷á(Þ� Û²�åu½xº´ +9 fâÜÌtì9"ûå–�Ñ¿_wÔ�µÁ¸4¾Œ”#+}# ôC´Ç±Êßð:*ÏEúÆ=�¤ C¯þèÕ(ÎêÐ3ÌEë-yµŠ©Ý`¯ò‚�HßyX–ƒ—@|#ÙÑèA_%•¡ëÔë`¯òddì†ÞU\ïèÕ±áð¡­ë±×8Vž�Kú÷Dó0·+»“;ƒ¾ä"‚¯ˆ ”ÈùgVí�F,#\q­ ”æîÁ®ý‡�ó•9�¾ ¡Kƒ<�®Í|úÛžü ¯õB«g ¬íëßÓ+û¼¿RWåÑpïsDິ® ‰Ë¥(@ P€ˆ¨@í|ih¢ÉËNNžŸWaÌöÀM§ËM¿“Èß·Gô>+¢Zâœñˆ –±Š£Ø·w¡ìDд)bcÏ@‡ÎñèÚµ£ß›§¡|cÓÚ ç«`H¿.ART*ÓëzÀÕW èŽè sp4(ž€#w-F%Ü‚åÊl “V íáÊ_­í'€³EB‡À[èþMk±CžXÇœqºlÏ¥˜5¸+R2% S°;m,Úùʪ­a–OL°ý]é¬ýv7*cdE¥1¸àÚ!èÒðžÇÙR m¦º,ÇÐRÐØ§Ú4+ צ¤ “VìÆÃj¶%•nš…®×¦ÔÚòêgù(õƒ±"{)4ÒÀ·úY~µ˜êÒt$u½Æ¦«ü ¯ÅU{/JÝ6C;Wð^ÂéôÝ:Në©jyv?\™Ð!„–#sí×8¨G½É+è1Þ9Y­üß¼)ÐBïÃQ}•cû–ÍØ¸ù{lý©eåå2Q Ä�Õý.JD¿~}qn;ÿ'gþ wî¿_XµÖlÿ­&ítÿ\.Q_rÉëÿ%×¢iß!W¿ŠnÖ —ë¿»a ¬Z¿v Œ;­ºáš«ûø½nuäoÇWë÷É2�¶ç_ŽËz´÷Ÿ„Ž)Ýøz^9ÞXÊ…“¿Áª?ªáO·ÙKð�gà/[õt Ų‚/qYëS—ÆèŠãÒ½£kgpêVË5¹jûü“° AÀ�µ¯�Â-“<înÈytZ;�®ý|úÛžü oµ¥&yhØ.Êu¨zíQ°Z˜·tO:¾Ý}Ť–çb蕽üžk•î—ûl;$ðS~ÔpÙUèÞ.ðýÊZHbÐE¨×R¡ß7‘¼ôo°C‚ÛOåuGÐ̨DàºT]=?S€ (@ 4»_CÇLÆo®é‹6rëü› ?5�€¯Š|lXõö3ï`7ÇIIèàç®ù;¾ÅêÍzkþ^íqù�?C·¶QÕ&9à+Ü €p§¯–2  ”céøxün®çT#f¤á­»<zS·O}ÜðiÈN½×ÿƒ0Dî¦QéþLl–f¼:÷ê‹î­‘”âƒä®xP¿4ýÞA¾«>�n’•gabü ¼å^Üxdä<…îþŸÍº§äS ËÑ\ß Ôö ïÒÌÙè:ø1c�SVíÆØ~á ”"3}ŽÇœ‰¾õºU,¥^c8Ve§¢ŸßHƒ€ÅSÏF6”ò«EöòM-è‹T�Uþ†×⪽¥n›Ã§¬BêØ~Þ“ÔŸïêqÚHõ8l.œŒ`?GAîrÄ%$[ù tŒ·¦ª•Om¤u/½KG竟½û"~ùÈ›æ¿ïIxê^ôô³åݱ¸ä£vá•´=xø’pö·~WY/Fè]: ÔÊWy&O]¹™¿§ מí;kÅ_ÿ }®û«käh|[òÎóó\qË?Ãõ�­1¦­ë ¬Ò­³ÐsÀƺnœ–޹èï;õvh >¼ý <ò±ž�$|^ð}ÔóºÊ^T•Cºv, iñþ¯GBš�ùÈœ=ƒsî¿Â?_ô±Àbý¨|ÇžEètÙ¯…�BZÎ+Hh@××u‘OÛ“¿á^È�îkm_ÿڬɵ“¿y•ëPõÚÃ~"keNÕ\_à4¹Opo€ûö‚«j#©þ\å÷�¶îsDî^jȸ. 9mœ� (@ P ^ Ø øê÷«?¢Uû³Ñ4F‚¡šDÕÿ€¯Ã»3°Fºm0C½œ¥ØW'Ý„x?_Gw�Ï2r”oŠ–íÛ¢¹ã8ŠŽ9[.sŽ< ×ß1¤Z 8!|…{îôJø‘E ³%àé1ã° x;m1n©u Y¶²}&ÈW½‘¬q©›1y¸¿G¥‘ºiäÀò‰��,UÕ[#QÒ4XÖ– X ÅS™Fññx@¯L‚ò=xîç—áO%¤ cõt÷ó€Ð9ÿ¯.P‡åX}eâC@ïš`gÎQƒøÞ½PÓÏÚ»êL˜C‚1:Áõ½U,¥^7¢€¯†S~>6»ƒÔã‰z¬ò7ÜîzB˜OÝ6ë}À—êçÊ{(êƒOc¶Sô ¬‰zµ•€/ãU¾»uþú•+áæÛEƒ‘”ØŠ¥_™'æÈáødÛ{¸±«çïÆð¥Ë•€/ÿí{;ðñÓ?ÃogÍGaÌ¢=xöæsMP�÷´É?ÃíÏ:ƒ¸ô37•â×xZ;gÈÇ?n茿¬u~{1ý~Û·î"”ðåt®³ÿ¥ò4+ÓÏ‚½]�›—ãý ¨ûãPößþ–ùᬵUêyJ¨·ññK·×øº¤¶ÒV›Ë©‹|úÛžü ¯ÍüÔÇeÕöõ¯]ƒš\;ùŸW¹U¯=ì&²–æ³ê¢yr¼üXã)¿?ÖP·“SyŒðïj?à«Î~¨ZKe£ÞÆiTgj+{\(@ P€ À©¨�€¯èúðu»¿þXZ†Q´¤¤ëT ø:ŒU ¿D�«¬Zví�Ÿ]q¾»ûNJûðÅ—�ÝSÈ4gõ¿CÎoëšÚùf+à+” õAL(Ó{¤Š_(@� Ž,Œï4sõ ‡Ï@Nê]ðõhÊçrÔíSŸÀ¸ç2\ºKHõÓ]B¤nåâ¥Á ˜"Ï=‡OKCê½zBÍ—gšvKÀW­µk¡úøÚ9öã¥__Œ)Î^”ìe‰­÷:,G[éáL5¨ÉÍÙ‚µ/¡÷-S$ #°*ç-ô y§VÓT×öüJ½nD_ §üj±>ø;žø^‹«ö^”ºm6¸€/ýô`H*ò&Ð=Ì~<w1^1aôyâj9`Ü\¶×»Þ²—ÞÂäªíµá½0^ öýâ˜0âôì`9J �ñŸên³Õ)}�#�ž; ý­ÉÐØ¾ô¾ô–¾ü½²×¿†~Ã'9Gß·û߸ÍGýø “[tÇkÊBn{ç{¼qO¢2Äõ1ÿKüºëõøÆø:_IK`½ê0П_Õ‹ v‡HÀ×ñP¾]�ÔnŠÓÒ¬‡ÿÀ©|˜_ûƬµešµh<�1în`ZZîmHÍz)Hu‘OÛ“¿áJrø1‚5¹vò?¯r*÷²jõ>Y ¬Ôºh.&ÐõˆzÝr*�þ]OÀ×éRgÌzÂw P€ (@�ú#`7àkÆÿÀ¹Ýº£Y›¶èrv\}øª@Ʋ¥Ø}\ ­i\!­Æ÷¶ém}ùøräoÂG«w:Kºùy¸9i ;ØË,þ£»Öâ³�‡Œ¯ÍÏ»Iå—ãÊ+²_åÈJÿ›¶üˆcÍ›£9š¡ýYç ÏE¢{g%tÃQŠ=;÷Á!鎎ë&ã¼ûE’ñYÎñ2ºwï\íf~qîä–!&¶úøriÝdǶÈ:p'NÍZ·Çyç'¢oB%€¦û³²Q†JID'ôêÞAQôüX°' yzb¥4zôR—! +…´.kyƲÊ*×Cò]…Mk×â‡ýE’È.¸á–!èP[J �¹-»öæ¡DG�WëöÝ‘8°¿W7zVÚBû$e³i3¶ïË×åÓ*‰—]‚.Ò„LyÁìΫ^&áä¹¼ ß}³ ?>†æR‡ô²;§[\xQw¿u 7k +uO_õHX^€¬Ýy’ÖtêÑ f‚ŽÒ\ìÙW(Ã¥LºK½(E–äkWN>J‹ÄKÖ›péeHè¢ÔÛЀ”©BÜdŽâý{�Ÿ½ƒnrv›&ísaÙúÑèPé@›øî謉õA³’iæËÏÃRÏ›FþZÓ ¯<ä±§¾­ø©ßƒtÅÉ‚ Ü}Š;ïánóîm#Ýdh…rÙ¶7bKÖcŸÑ¬™l{ ‰(ûÍðvKöËÑQœ+-SJ–b¥e*_Û¼¾­d!ç¨lѱžûm«î9÷¥¹™øö»L*1èÝïr èÕÙÍU¼gÖed¡Hö�z^Ïë7PÆû;8¤nïDæî]È3ê¢,¦Ykt镈ËýtSè�}ÿ¸qÓ–Z¨Ëæ>͹ïªÚ¿ k¿ýAò!Aà—Ü€ë¤U@uÿæË±TÒ²yÓvä—{qÄËññ£œ¥dî–ãb âäd¬s+gÉ{Üœ•‡5c¢±?sþ— ®”cÏÁ|l™÷~÷Šsãš±l=®☎]e670—ív±•^˜š5Ó�+íߣ7.òqìw`°ánæòÅH_³[~:ì<µï‚~ý/C¯ÎM¥ËÙxg—³®€¯‹*õ–ÔÊŒ9ãäøÒÙÌ’¹,óݵ­é_cã{(yׇ„~œÐ§V_ú¾bëæÈÉ;$Û¬ë|«_ c|õ8äòs¦ÈÎ~Ë!e´s³œ§Ès¼Ô»v»¡÷ŽÝuOÍo¨ŸëÔEO„¿ã‰¿áJÂí8é³ïIÇë¶@ÎŒÐ\6’.çõÃez¡yÖè4èAc �°(I¨öÑþñ̹¯­½}›««L=hKo Ëx¸.i6Iw³×šçM®¬yã­}qížw›_9_<‹®·¸CÎ0sUÆôw,Ù+qÇ…·c©+¹‰Y‚ïŸâú�€¯™ëbìElßð?lܳ_®i*d�Ñ—\5 ƒzø_$¸l‹\ìÜãy pÉ þ„æcG%û¨í?êçʱè.çÛ­Q‚-߬ÇÖÝr%)kݹ7®¼bâÍÀ4ÙOnüz¶gçfq]ÏÃeƒd¼�E #=Á¾*e;»UºTuhK€–×zÙÿ–ãó·)úÊÇófâÇEc«uu~hõßÐï® ¼‡cÿK¿ò8ç©(ú ;3·!k.*#¦uºõꇾ}Ï•­Ñÿ«x÷z|ùõ÷"ÙÂØfÏéÞý/ïƒæ;æ¢K¿ß3ztéXž�¬]¹rmÜçöíiœ“íÝ˜Ž­;³Q*ç)1ÍâpÎE²ÝËzýŸ“ɵíIkæväéç>rÞÜ®k\$óuéè…¤$ÝQ"ë–ó“÷Ëýý ¬Ï×é<ôêw!ÎjígmŽ"d|ù%~ØW€æ-Z ¦}W¹¼½ÎŽ–.[èÒÑ�û·aÛ®�Æù”~¢ŸO�Óû ìßÓÃT·ß}@¿™"qœç÷ÁYþ²à²Ó§‹=ë|ôh¥çÝÿ˸æÊ t=¢Îkÿ­.Åûs8Ç?õœÎþ5«~ßc‡ÜÉržë×T]ÎCbB_tñµOp'8Œó™G}øïóa¾y>ÙßÄ¡·œ—û©aî¨Â;^Ù»O^ýPSg}¶Ž;uqM¢ßÞç~IàëóZ»µ²ïü$e½ç`ÖM„8�š± Ë…€ÃÑݽʾ®óÞù²‡z�/h>; Àæý*Û“÷ðQÝJ°;Üë‘Nr=pÛ÷*P»×Ur�-Ü{‡î5‡¹Nu_éqýëÚïèç8öîy„x­浓;Ÿú‡ óVÉuhWçu¨œçÚ½Or½öHœÿ/j]Ô§ržÂ'`ÎæÕHêR}ïîqOAºë³ûÇ0�»JùêÇH�{# ƒÐ㌓ïGx¤)ÔûR¯­ò˜"xc=~¨Î1Þ¿®÷˜ðŽÇ׫®Wåf!cã&ì—Ghsn"† PíDMîÉ9Sâ6ã�E¹Ê±s®R7ÞÕÇ (@ P Ñ Ø øZ°`z÷î�V­Z!*ª^wéX�MK—bß™ãú«/�KK%,@À×É£ÙØ¸ãÊKJÐ4¾?®¸àÌj•H k)_7�&_Å™ËñÄàd¸îçTKwˆ)xÿÕ±è.7kû—¢ÓÅ¿sN3n! '_ç1}¹<ÀŠw=À|uUŒYƒ{ E $^ÓrRáü±`1–¿ö’'ùKÅpÌI{I Ä# ’ä�Aš±æáÒòHªï–GÊ3‘?F/{’–UÙKÑψO c]fî”e ž’ŠßîKÆéÚÎùò•Os\8ïlú` ®}Ðzøä=÷ˆI 1íáëª=ôðžÎû{ùžå¸ï²d—…çØ”9‹Ñá“[ð˜A/žÒ²”áržƒyJ«P‹ßÇØ!Ý­—Jvu•a‚\h§y^hë–nš%SŒy&­Ø�‡8¸2g'c°³ïDL[˜Š¬¿&ã-£>Y‹×? ?ÿ|*ÉãÞs ßßÂÙ$•RŸ»ºêsõåUïú°ú4êýˆIÓ÷ÅcxËY¹1Eò=Ö•okNõ&…¯Ö0l”GÀ²¾÷÷Y‡7·[)°>%HKdiÒ™’¦Ó°ìŽc¸éŽIÖdʧI‹7ãá!þº«T&4?ú}_ Ýhövu£©O,Á^9�‚½jÛEÝîƒ-[Ù™ù2ÞímóÖ60Ë2^À†Gc’«Îx,^ZÒØ<÷aø¸gç1™õÅ~9nš•„k]‘w“ä&àÃÕn*ÛŠºÍ{Ô½ÅxúÌOqƒµsµ’6jr^¹+žáB²FÊöž²ÿ™0Äãá“£ S~\1Kêä®Ï#�º~†÷R—=Ò³ ÓÎOà;ôV®ª¿Â­ËV¹ Gêâ›�|‹3ØC_²¹¯ðïXŠ•/�ÁSœG4�Ô NÁâ?uÀ-·8ƒ'OY…¥cû“xÜ]¼ ˜uR|,çH]kÔußë±%�ÅYËñ̽ɘëcßëœg8Þ^1·Øà½py\n÷èØ¿^|‹Ïó˜“f !s&&-Ðë<ÆÅ,H’ãˆs£,-.õh±ÐJXÖÉô ë,Bq ï8a-ÈÅ¢çØW|‚´4)UŽñÃ=ŽñáÖãPÊÏ™";û­b¬|íÜ1ÉÙ⃚3óóðñocúS·#œ’?.FúüOü 7f²ã¤ÏX޵³Å-)¾ÎkGaÆŒxÌ|pŠ~ÀW°4ù8ïªÃ}›zc�¹þ5'¯$)ç~œ8 w¼åÜ�$Èpã“ðå‘ÞÚ=ïv|ÂKƒ.Ä?8•üÖ×øçÝzJ¿Š6ÌB‡kŸpM4Ÿïý/~æªìV _ xæ­ÿÃÎqDª�Å%ýeÞâ: ÎR_lœ7Æù¿H~nfŽ÷œoË»wá’Gôý‰¤eýD|<è—˜®.ÖõyÁ惸 Ÿá—r ·¦Úx_]T†Ÿž _±̽£ÿØ™_]0îýh®ùŽL0÷ŒÞŸ¯§6 Ë~„ËÚ« w`Õ„ùúcàßfcâ°x×EøìåG0j¢/}}’$ü#ý=ÜÜ×c�2¼ioŒÁí�ùšo4¦¿Óo�þ+¶É”jÀ×¶wnŵéa€C±$s:ÒÇ]‚ç\ÝLÊ@ëuó Hÿׄjçd¥;þ‹ÇûÝ‚[Sz|ºñé˜>ñ6¯ë™"¬z9#'êV¾_7N˜‡—Ÿ õŽ„#ûK<ÒëzŸëºmò{HØò ž›¯›&áó‚��誤Žüõx1ù*¼æ+_Æêå|`ÓLÜx�s†moü ×>æ¬iWMKÇþÐßg"­ò.œ¼_�ëés:ç@å<²ÚTæõˆs„ýctµ+Â?þYç}°uÍZ*çZ� ò�fxʼ1¡úµn¸ç z&Õ‡ÿÕ¾ö㵤‹­k�o#û­Û=ÎU(¯�6ŽW¶îĸ&÷¬^ ´¾zwj÷šD¿ƒÜë vÜt ¶lסVÖÕO�Î#õ°絿>G°õÖ$OáŸ/O�§CÐ|nÏö±{¿jœ\g8ÏÿÔíÉ{;»æÛßÊ5¬ëzD¹ÎPËCÿ¼géx\ö»¹Æà„I«�ö°ó:Ï{:Ïïö¯«lÝ;4Vno�þ®­}hø÷<¹V TÌktO[ë[ðy/´ŒlÝ' ¶�yÖk+e�?Yuq¦M‹Åc�¹nn®¥/Éãž‚�€/;Ç]«|«ßé3ö~lŸõ¦ÏL˜e⑦ïsè÷oÍ€¯„”eH›p¥káã}&Îk �ã±ÇuÕˆÌHøú|N"nocxwë^–¿mÉJ–r.¥Þ““ ÂÙf¬å‰¨­s•ºñVÓÅÏ (@ P€¾ôZpò$$lÍU$LZüÚy\ÿê¿…/×ÄßÊö}‹�¿Ë6¦©Í¾‚6ñàAVqú,ô¸ÁTc$,a0ÆÝ8(ÜŽ·æ*$&!3íat†ÚK 6Ê�k%×™ÈÍ ó§€2¼ZÀJñ:$õ¸ÉÕJÐä½’$è˱t|<\÷0œÉ> 7ö‰ÅöWÞR‚”äG_ ©{´Çƒ¢”Å;1aHõG‹ë^Cï›&9Sçn-)Üu¹~’,†Éd¶ÜýTʹXçÿJ�”:8ÌÏû—?‡‹“•=R£öDYÞ,Xî|(¦/rø´UÒ�^(7y\ �›¦É\¥”&FŒ…c?ÎÅr5HÄÈ›Ò"CHyöº‘GN#Æaà9ÀöϤì¬d#eq¦”Sgg¢Ô:9\‚–Rï­vÓØã^¹©`ÝœpåÏxKÀð}�­ <Ö9xÊ | NðsøÛC)�‰1sUH¹*e' †ÌY�ÉI½®S½ >c=Þ¸$ =;7ôÖÂ2ò&Cª¼ò²nR@}8jLa¿<ü×ïë1éÿÊ0é^y”î3 ‡H‹Z“¥…%MJJ¥2`Tü1Ì] Ö>¥Ž©Óúû¬Öw~‹ñÁ¸î_ëNiÙ“‘`ÝëðZZ]¸˜Û½Í}ФÐî6ïo1j`µí:¼@û娦I½±m„²lu›7÷O^ûÖá#F9^û(ka.û0l�ñÊ>fÆúlÜeo9öà¹N—Y݅ɼƒe™=cËd¶Îàcyf9ºî'= R—ú¨ËîY%mþ>ªFÞÓ˜AZê4ªã& t½ÖèjÌ«o[=eÛR�Ó®…ªe®îG­u&È1 z]1ÓPžµ#¹ZósÏ” �x21ämÙ§Ý\‰qLí|Œ¡Oà\^lYž×¶>B‚ºßru»ä÷ƒÝíA¢ƒ1NŽqjzF�¿±6à­Ê~ËuŒÓË좢åvq²³ÈùÍN9¿ñq�×÷Æ$£Ž% uój —èÉð�f–e'¿ð¶ŠÁÃG [=Žñ ¼˜&Á‹ÆËF=Z~·ëÇ${û­¬Eã¤{+ÆvÑ3y^Ûâˆixë.<”שq1Râóx"cü ·é¤¯kÓìq²Í*V®óÚ rn”¦ì·ôiÕmVÿøeóxV‡û6ÕoDÊÄ.IqƒÊC£�òËùjÛ–™Éèàñ3pSáL¤èÑ£îc¼Œ�2ñ^âµß Vm¬ð³çßhuéh×8éž±@ºgô× ‘ÇŠ¥Èîîn ùp ^¾Éy%d|©3$ ù÷—ãØú9Xê .ÓÇ}ñs|ù€u~úÓ²gÑý7Ê5ÀEƒ1zÐù8~è;¤.³*LÒôÕøè>ëÀç:/ŽÑ‰À;ÿRϽ”4]#ãå<ÝcüMï ôÃÛÝ­)ÛIOð€¯6Ø9ïw¸f´3 J šr¦®ÿ¹·˜/ßú¾€Ïg¶ÅõC0F=µ2¸º£• Ç�xºuo¼m ‘@«ƒ_b�¿UŽ�ÿÐ ÿ÷®5é…7�Æõ¶ÄŽ—¦KÈ›ùJÄ?2¿ÅÍ=¬BßòÎoqýCδéS™ó¥/ŸŽo¶šó9ßÕ´o“ù®UæsN‘ˆÛî»%Yïà3%HJ�OŸ®bÇ|tëw·sã™ï¡›pæñL¼ý®Ù–œŒ�ÌöI ffËdYþ׌RÒ:$YZ:m‰¼·æa@IDATõ²>%­Ýa–lÄ: P‚½qÏ„›»Þ6ë\É�Ë)lU¾Äz²X¿æ­¿]5r4z¶<ŽôwS�8ç(ežƒŸáÚî¿t�{éåÏ{Ü/pN_„ÞÞÁø�Ìüºs ¾J±tâHüÎüUŒs!H𸑖aßÛp-(È›�ãŸzNg->´kVýX/çbÖKεÆÝˆ¸2¯{4r�#GºÏu×dç ú:Ô´ªçŸzÍl¹ærÎä~§\·WÛ¯[ U>Ù<^©ÇdõšAY²z~ëLoLHõCYDõ�æ±I?}±v»r�¡†×$Ò}°ç�”B¿_ü8hï|®zæ­!zÝû¹Ô=…@F&`°ÜÞH+¼ÑÕšv]æÉÆy¡�óµ ù\–„iÝ]×!×CóŠ¡|�=+ƒîpY�—{«OùØWÊ6˜,Û ë�>'#G·x«à¼>ÕäºÊÖ½CY¿ÝuúÛÿ¨Ã­ìù¾Žõ8—–àÍp®U{d¹ö5®�¬¨Ÿ‚_wÅ»ŒÔùB»OVûÛ·™ËV¿^ëGHs]6�“lLöúÁFõ}®Õ›‚Ý㮕3UÖûUü ¢^þ›ëGÞæpå~„”‰š&s ó¾„÷½nó>‡>Ýž•³ðÚÇÛÑý†‡ñ°œÓë/;ÇxcÆ@ÿÙ<»¯«¼ŽEþîG­Ø� ó7ª©ç±ÜL¨Ÿ{ran3f¿vÏUêÄÛÌ"ß)@ P€ ÜµðÍæëoï—kú_aaáiòwP[õþ,mÖ,ýï}mëA»éÚ«ý÷ærfiŸg¬–?ç:fU^Í"g•6ФÔ4y8¢e³’é‡ûœ>SKIp-GÆ�˜²LËQ–•·s…&··œë‘÷ñ 3�´-Kì– -ÌÌSÒ›­ÍnM¯§On”ñ…Úî“ÜË—ºÙ·{Å÷0yì¥-ÌÈVæÉÖNa�wå7{•2Ϩ9Zž’n§WŽ6g”•¹Ø±½.cyÙ.C·W‚6eázmwv¶üå(éµ[?vj“ÜËë9iËÌ\6Í2ÀmUNèëI›¦ø%¤hë³­y×§¦(ËÕ½†k«Ìñ!äyçbuþÚâͪEž¶bÆ(eùãµÍf9…P‡³Ó¬<›å§—…G~ô:6~޶;ÏÊSÚÛã”u*ù1×í÷ÝÞö`Ô¿Û˜•.g½ôñ]±�URîyuwð$Ïm¨°PÙμ¶ÛåBYç(åáL§š%MÆ>c°6gÕN«g¯÷Ø×H ¨5Îoy¸–¯ø`ø ÙÖõm;A)ãqV�õ³¬ºt±³ÿrÖûÛüz�íʹ ìT¶�ŒÔñ–�Wñ[ ;ûå¨n—êöj­OY¶š¦œ4�ã 0J[‘iîGd2EÙéu+a¼–¶Û<îäh ÝÇ#hj½Ü¹LÙ7yÌ#õ*/S›6Â:> Ÿ¦ìo«¥GêršR—s¼ê²ëØbåSÝ.u½µýèÛÖ`+/úqWuP÷£Æ1Yö—žuEqO—rMYè<ßu:äh‹½ökê6ÈJçá%烡ŸwyïkkoßV¨¸Ž˜±JöÛÖ¾îmÛÖfå5#m³6ÇÜ«eÂyI0+ã‹‹ µ#ë_voßCÿ²D«*) ùO‚–¬y_\ížïûéʾHÊ}ècs´Übk¹?ÌSŽÍRv鿏,í…‹ÌíÚó¾v/SOWö +­Ò 2_‘öÃ[VZô}üèéŸkf^ö~¢%»÷+Îå«Ë.ݶHê?\KÏ­YztWæúðCe•ÚþÌyn; yEû¡¼JË5ÿŠÓµÛ\é¹pÂçZnÉ÷Ú�êws:yß§.çæ™Ú�®qÛ×¾b-IÚüÌ#ÖòË�hó''[ã‡Xóåï^·îøøÒ=Ê|¥Ú¢iÊ|2^·Üã¿zg´µLwÕ„Ú%V¾¾]ô„5^]gy�ö·!V¹ßøô'î|è&?f~⑦×™y9¢½èžo¨ö�Mî´èóý�¾@»ÊåŒÖ¾r¥å«w”< yAû¶ØJ㾬Ï=Ö%-|iŸ8Çÿ°ò+ý}ŸÐV¬°ÖW’­½8RÉÃëß»ÆÑf*Ãÿ¶Î3�F™g¢]h¦SêÂörGÀúcÖ­À×#ö�Ñæò}¿Û;þ©çtæ9Xh׬»µ)î㭜ץ,ô¸ß“�±Ðã3m•uïÄîyƒšVë<>GK§\sÉ9VfÀs9Ï}€ýã•ïc²Z6êù­•ÞB-pýðLŸº<ãsµk€Zº&±{¿$„ã íó”ÊQ½n™¢Ô1ÝÊvÙ†�'�e‡x¾\¿ùTÎmüÝsõW}oOž÷±œõ6[{Û<’ý¡Z—ÝõsçBMâ>œûa�kµ@õÙþ}5íçÞaaí¬S5°{ÏÃÞµjàk'wyøÜvÍ«Ü1Ê1ôûd5©×�Ó«ÖE¹Îׯ�7ϱŽõr½¼l·gýòW× íwÕmO?FV¿7ȵPSÓdcC»Ïá™7ýþj�\ãÚ¾¥Í:£Þ�ÊNÓÆ+ÏÔ{Yêö«nKV}Pê£rÝeo›±{®R7ÞV½Ë—ßiÃ:À:À:À:À:À:Ðxë€on¸Ö‡~¨mܸQÛ¹s§¶k×.­‰¾9éûõü¼ cžn:ö¼u3Cm´ðåÀ޵Ÿ`ó!gÞЦ’~‘èþ•®™î… ï¸ãs�ïwõW�2E‚üÜ.Î÷”Ρ…iVkʯçË3¥ûÅÁ:§‘.vK ÖïtœƒKåW²]ÍÀ¤ùþi¾¿<ý5il’1��á©ë\­6™¿ŠtÎêüß«Ièu¯%á&£ï±,”�®ë\ŽEãâa61iÙN<|¥÷oF ¤ieÃøÅ‘>ßj\×Aºî�Ö[œ Oûø¥iº´juƒ«U+ó×r6×Õ9Zòâù˺QÒÊÉ+~饄ô¹< ¯=: ë�mÅòc#�¹ToMM}•Ë/ÃâáìY*œ’ÄÎÝB ðöúÜÞËó�é¯%ã†If+ªe°<{þúrÒ2éÆíJï$]x&Iž®_‹Í�õߥ¯_­ÃJ�Ts¬þbK.V1ÖÕEœú«%½e§Í…“½~ é•.¥;HuùÞŸín†¦W~‚¶º§®\™Wú"UXêo³þBZ¶SÉ©ü*ËÃÎ+ßá”Gõ[-w:ÝùPÒ$Ã_mònËy3Ú²Ô¤ëÕÆSqëSK±sÁüJ[´¤jÚÌ¿q©_]Þòú8ä]lYb‘6±¸h¼~™üS¶b†lSëZï[*ÖûÚÝ‹úøqôX«´ûaO+ÃHçGß·ÈK�q}‹®+ºýWå%Û .«X�íbq·_�-Š–lÅ ¼˜LÈÛ¬3&ÿuZƒVÏÄmbût•aç0ôýP,}LÛh#â©:Ðm�¾¢ÛÍ�“®°G>–3W<"VÕìý/E ŽñG!|?ám+¢}¡“ù^!ã£îÖ@…bíqú%mP1õØ[~†u¯P㮆¹ÖB ÀÖÙ—x¶P5²R´xžþ¸Ž?ºÎüÍhS5TvíCoZ*�‹îOt;äëîM[ÊãS3&½gÅÚÇD›Ym´ÔJ§ï�ã’I¦ïéŠmÛô˜®`ÒRÌ*ø‡ç]a¦=_¶K™Ý.ÅpÒcËáb)t$ÞpÆ·ºL<׉¸Ç݆…¯�o�C‹>V;Þ{ÊÛb5+µvÜÈAdݱv�qˆÞb©ëÛR—×ÚÖpl,½ G›W9"˜õÿŽÄ•ÿgýž¼h#†ž&ãæÈ:L¼~Þ‘9À¼¿Ç¦CÅòŸþˆ¿ß‹¿— ·¼³eº4°ÎG>š�ú]n´~ô¼ßÿ}�g«È¥“‹3ÇØƒð+gb×Ô Õ}[ŽWþÜ ù‹H€H€H€HÀ PQ¾(øŠÖ§R¬zm!Önßc»4ů.ê{}!z•qVðå $Ù�€A½ß$ JܺÂ*ÈöL÷¸bª¼áÏÊã¹æ¥e+DÖ}”bæìSpÅãX&fQÃJ|äl¡$¦ƒ‡ËÖPæ†Lâ׉p!vAÓ\?˜u¶‰ÔB¥áò@Œ³] \ïy ïº\„ÊÖ¶nœ:¿Aí¿v7ô¨®èyCð쌡èÖ¦Yð=èF–Ñ‘ËF¥G÷q.[àŽ‰éi”_ýà.î!‚Þ¾Ú½‡B÷Òx¹[‹¥³¿Ž aèנê× lÕ\ŽêþÐå<>C·[åqÝ�I/bhá™hV?…tº)ö©û�åW�\¯Øí‡È¶ÝÏ©sڧМCß³Aã ·>ǶA^Dž_žºìÓ^ÚûŽ»Úy¢”Géjqyªý_*í¼ßœuýx\o®Ž`ø‹ëd�ÃouDÖh±_~óåEõƒzÜ Ójl‘~ÆÇ·¢ÓV ±Ú’Íã£íxPÐ÷Lú+•ÆhŸì Ü;/Õó=îÕù‹ñðS÷;>}¬']îöh`jL�;ž~Û§Ì`œMs‚]'4ãJ]sP Sb]èõD#û‰ò76Œá¥ë›f¦¯»g½Õ�sXQé—'cÆó1iI÷§›®žW¥½v˜<¾qŠ7×Ý»Ž ù¦³æn®ªïÅ$y¶äŠD~õ¹4ÖWªìþVyõÔE@¿ì¢ËÂ[×ï¡ê0ý×F4;•N»L´ÿôÖ9b 5\JÚ¿UŸí3Œ@”»ñlÅ÷åMOY¹íFнä¦M1Uó®0÷Lø±J–x»xD$@$@$@  ¾âŠ: _»¶áíWÞÄf۰п,8-�·§}>a_CF�BŸð¢NÛÿ‹ Óí‡jP¯'“–l+ʪJÔ³L¢oð9 5I€¼i%oç7“ë£oâ”§OǰÝM [c Kŋѻm,‘k &,”Bò°[/*ˆ{áðQø…¼¡íùÔ­‹ï^š€Y¶Ø£À¶ÄQ¾q.ï4غÔóR™¼å×¶–‡Ù+ßDÁQ²ª�A\žI|:‹ªžŒ$ÿQ^²¯þs!–½¿k·nÀÎ�€˜\4=®Yã¨]â'»�!ëÉbÁ$lš=ñ¥¬-¨é°U9ûå9¥°e¾ªÞRŽNdµ_U'u>ôÞ»¨0D„YæcYȤ­ÙøÆ©÷9?H`)äÇ'JËIù�ò1Ïè>mÝB—‹”é<»LU8,ë€òЋT~e-éÑåáM§‘X•¦€¸û73ìÿGç+OT_ÑûÀ½\¶�k8Mµÿ€´!ùו/?.µ)VúÃÜóš¥Û­Ò-q‰u&ŸÛÄ=RþXé¸u=Ð÷�¾_£Aë:â¹ç“Ä™¬üÔy�›.6.{ -ÃÚ k±aóÎh{j¨�ªäõ—$=p7¯þGÚŸ#\޽Ò�£vó/ox, éüè8ýýªüzêJ�»¤X„RZ÷´-h:9ÈÇÀá=Ñ£Ûé8¥S»Ð" ´ïUþ²å«ôq—øôqe"(ia JÃçÁz<�”] Á×Wb]¨�)t2¬t¥.¼2"Ñ"+ÙoÜl‰Å\”¼A%óªkNŽŸðy­ƒyã5Ú¿óâ½ÿ¬Åšo>Å÷bìÈ™¬úÈ�D-qŤå!i\ÓΧNÓdIÓИ4¹ç]á–2Ýô¤*ø*ù�X­êz³MÔò“XÞ ZãV‹³›>a“!ÖÚõÉÓbëRóÚËf‰%´ß+°T,\�iY¸ñÒ²È]ÖË,QÐwäí2§üÑŠÇù[¯¶?ÿÛ¶d�7äY¼9>ÁKn6wý•Ù¼*ݵC+æ´ãoA\ôýœÖ<6Ô\UÝÿi·{‰üªs÷‹Îg´íȰ^ëzàwì2÷ö%²ÃGkg‡û:/rê4êöÀ ǰü�Î3ÿÚˆbçS&:Mþq'ö¯¹„éãµÿàãôûãÔÚXÉ[ìzƒ ìtyèrrÓ§˜èv-Ä=£ãJw¬Ry¼ÝœòˆH€H€H€H€¾|ê@8ÁWyÉgxíÕ彎õ©u~Õ³+šÕqâ¿C ¾äÙfyÀ™ðÅÔòõrx¯å‰^Ðý'FeÛ™CdÛ3¹î[úëç ‘7O Ñ�³5£+N±ÞÎ9QÞ„man³ä¼­£MUG'dzÌŒ#ù'<#m®ÉqGŒ&þµÕ™ÄD·×Ë(.51 ˜¨'Oyâ+Š^ŸŠ“.›ø"ó¬wRžÐƒÎ³žÐy<•G±Ä`>KÒa'ÉsJaÅ1Q¶œ°k�³%O ~õ^×ÏTê­oœž<ÇÿH%Ü ûÁ3)ä§é¢XDxìKË‹æ‰%Œ+ì_òfï:±,×T‰t\*œ ·¡�€üÙ$)kñ§Ë#6�r6à�­�ô¤þÝëâŽt¾ädáØgqÿÐsQª¶ˆ4üøm½g†¥ýk^æI÷O(.:l7¨„Gnû%– CÞóº,ô½áF¬ÊÃgq̽.öHù `¥ãÖõ ùýv�»�6ÍØ/Mê¼Nä­Ç©¿ëd[˜‰Í§÷·Ç_%ÖeÍοÜüûåälå¾^&íl«�ÕùI§âï©+Aî»HÑbŒúCŸ¨ÛKTDÝC&à–›®B^ãX"±Wº¿Cݪü Kk¾c ÐÝP�£à¼èmT47wûiï›æ©”…o?WœNoªÍ_Q�=å*¡z˜ùÄéãä¶[,ž1 }F8™c/.À„ٷં<¯Ø ö2ç·'-Aåç\¬¾ÃrÑñéöÄÏ]»©¨:œt=òì:Œ?·iœ7}oêºw¡vÐiÒé××ÈqÒþ,Ào¨4q«tEó¢Çâ²í&Ù¾>”å¼èXZÝŸžt)÷èµ1 ùÓ|ÕX73j+]Á×ö÷AÓî–`IûuÅSÀä%²]ãÉ^kZFr·¿3M{Œ7S~õã²uka[óøËצ¢Ug;=Ó)à�W˜¥Åg~q&K“{Þn˜ô¤*ø2¶$¼N¶$4,BWãߥÓÑfû+èÞâStÞ¤wD4ÔÅÊùZŒlÐβÚeoµø£Œ�xÛ[X4:ߺV‹š,—¤Ïÿž¿±‹G|5xÞÜÑ#ÞÚ–v ¾î|W,†�ûV ‚¯¤)5.è&ÖÁÞ0­ƒÉM‡%�ý ýnpÄ`±ôÆ�sïÀ½:Xm±‡ÍÍX!"¹#b½x,§)Á—Xêzð‚¶ö6˜qž<š‹yB„]Ýma—!ä³,”‰ØMYnsEr+ø gùöÑ Rœ,¦ßÿé¾ (=~íµöçÄžø;_¶Þžgm½²Œ‹SÞ±±,+ËKÔZ{âTxΪ~!íyi ~u¥Ùj÷häIX¢ªßñôG¶ŸdéRç£q+·´9èñ«_?¨ÃN”-uΧ(§ÀC]'4cÝçWnžRfÈ!“|êú¦…ävåÛÂ.mÑz�¬¹æ›k®‰Ä4þE˜ñ¼Êï0£ Z; ¿¶Ä%ˆ¯›cuÏÆÌwÒŸ«‡åÆt”ȯ:ÀTçÓ·íŠ6Æ=Üý­×�˱`ôÙ0ÝzÑ ¬lÍ>ô ÏZ`*uÝ›4ÿg :ß:LׯbS¾Æ5™úwã1ŽÒïã½þ}~…ì�Skc½L—Š5å62– º—ÜÔ)¦1õ1Ý{FÇ冟èH�U*ƒw¢¨yŽH€H€H€P´ðWðé ¾~ܼóß^ç†Ô¤-Î;§#®é:ù…|É =*hò ÔpÓ‹ jP¯èþ,Ãs fȶ,# ³\ÊœpD¬k5·­k™[ tZ�Þ-zšÖ»ÓÏÑ·6äí½Mó®ÁÊq½Ñs²�+ó¤MÎ Ÿô€¼¥5‰fDêýüôš�Þ­‡g3ÂÏʶŽç6ƒ¶*àÙJGs�PÓ‹+xbäM`¸_^a�Èè Gá¦Kºã¸#¡ž¼�^O¶vúðá~`nÙ;)O§Î³*{¯% òL¤“ä9¥°e"ÝêSD¶u6O¹¤Ko›¦ëg*õÖ7No¦ã~¥nÐý�J~â"tÇè�sN¾õŸ(œ‰ï¦÷qUs\o¼x­Ù©p<î*,ãПM’²6ü­™�ù#ÌÐâÓ™©3Xÿ? òµbÆt·­½žëýÚÄØ,Hà_GŠ‹[K§MÉäž×e¡ï 7?ª<<÷´{…ÿ‘ò§ë–ºXÇ­ëAòû'(ì w;RÍØ/Mê¼›žˆå¦QMJž”ÍM(8õ84:XÚÓ܆Èùñ}ôë2À|–åú3âL’㊄÷‚�nŸ/íÏ¿Üüé’³ NSò8U~=u%È]g¬Eëÿ‹÷ÞX„^ž€æ8AŸOý!aèûA•?òÄ Ð’kd»«ØO‚¼èí2‹¥²8ëne=D¶‰Ý&2•²ðí'Ä—cI?ȉM©÷wÕcO¹J š™üL§ÝrÒW^R„ÿ.‹æ¿€ ³+ ÎYéë+®®“ÿ‘N‹Ÿ¥__pñÄ`!Óigôµ’Žt8ézµr“—Èš9hž½éêmƒb.Ô?ušœtêóöq¨þLüêö"å4qªt¹þô#y9ä³%8ë‹GÐÜÜú]xF·§U÷§'OAîv&3ø2_‰à+ÿF+”v£±iéHX &ø�¿œ…ßL²„ ˜þ6ž¸ÔPFˆ5£¿ÉöˆÃŒ—a‚_¥ÿ}DâµÅbSÄÂ×UQ¾é%Ô9ñ ÓŸñ§ÃFcÌeÝÑöȃqP½ƒd�ƒåÓú¢�§W˜U‚¯°éIYð%yžT×>meù!Ùªñœ Á çßm:Üû®XØ:ű°UŽWFvÆÀi«äÜü;òvÜwŽlýø–yíÙ’ñ:Ù’ÑüxDMÀÐi�Ëœ2Æ,’u¥õ÷§]8âÌþ8ï”Ã<‚/O˜êú]«g¡eç+M-lÒB°Ð‚¯^7cÊ…GcW¢äJ ½hÐoq¨ÒQ—oÿ+Þo½ô îý›µ%¥J²l±h‹ç4›ö"¼Zfl ûñ¦EðÊuõ1ðoε„ëœ×¹-n$u3÷`äþðþÐѲ֥¹X>t˜À_×ȶœ­·»ÖÜp»ˆÏnµÅgU%øò_Ûpr˜ì;�þO÷Aã>¿öZûCÁp< [µîJ´<"R÷¾— iNøþQÇÕz90¤^'k9ñÒeçŸoÕ/¤=/MÁoÐ:Aè~ÌÌB’~'YºÔùh_¨ÜÒæ�lN¢Ã–ô§3Nñ)±8']'<õWÇëé·½AøÕí¤ó,OØ)Z÷Ô~BpÈ$ŸAõ0(Ì wÉÃÌå[Ñ»•!¬jk¿”éîªà¥ìÿ«BæU�eë¿v:NÉB}?{ê`4Ûêž��ï˜×¤3WMV4RŸƒD~Õ¹¦:Ÿ¾m‡ÄXy÷·ÏÚrÙ2 hÑ#jÍûÑåß¡Où ÞÅZ ÔeTv^Hþý®Î·Óõ«Øù”o¦þÝxÜ£túx×—ßQøþXÏ«‚û ÷…{ýœ&yy(¦¾õ1õ{FÇ•ÞXÅåUq¼Ý0yD$@$@$@$à àËea¥'øÚµmæ½¹6ÊA-:á¼Ó[§dé ¬à+º¥[4Ö˜½¢õkf �­ñ¬uQ‹[1^�ŽÒBÙ¬³¡§PDóä­Ÿ¹ÝV"Ï|ˆ#Vˆ>+D²Šìšƒ–‡¾ëîÁ;}N²,dûÅ­“{[L´©j±V¶U¬•©uì¸ÔÄ9È6‘ù²M¤ùØÅÃÌ1Œ•-eõËð˜Q\É&Fq)KËAO–òG=‹gFžgµíuyƒýbóM+ŸIyPlºìýÞ 5ü‰¸Ñbnº†;Iž=<ƒL¾ v%ŽÈŸ°ó®‘­÷tºT�ÔÙØ"œòúXkô€f5A¶Ç¸Æg¯º²"Nê$NÒ±¸ÇÝ)äÇ�)æHù�.ðx.Ùˆq‡tÂdÛmÂÂ¥8rvk2Í.“òH¶ ,qërŒOg’º’Ô¿'ÃÞŠOüVe²%[‹è–l"3+h³Å š ¢2¹xÂN¯ýÒõ8Ý{^—…¾7Ü\«òðYs¯‹=RþtÝR—é¸u=ÐùñOÓLÌÏã±ö„�$N]þv¢Ôùhz”›D&Ûú>#ÛúƘoPoRGý™A&I�\ÄÀNQà—öçÏÈÁ[³ ꫵÐYç'yœ*¿žºä˜=DJ¶`õ» 0yÀˆèqÞpÙ~dLòíGtÓºtYõq†U¡ü“`ê¥=y´ò²xboô™`©Õ]) Ú;dA;@ܺŸ _ìm®S|é¼eR�cóœA»å[úålÙ¸ þo2FLvÄ_Îv}IFt:-© ¾2á¢ýêöÄÏ]§-Íñ©®ÏA[Ooy}ò.¶zv}Ïú2v=iJsÜ•q?ï$Âç[ñÓyÑ{‡Ì\‚ó?¹Ù¾× ±hótt4›eÕÖè2I!½>)IÉÉ|5Üó1.ozfÛ>ü¬cù&y½¼éÙQ�ð5¶µú¯à+~ûD#<-Ðr¬ƒiÝn�‹Þ?xåÏgá‚�´ò_aÓ“ºàK¬€¼p#:÷Ÿb"üôÑcã0ô3E\°¨ä œ¨ºì¢ù· s¿»ÍkZöJol‡›?ȇO˜Û#š'õ–޲ma‘l[˜¤2½ôöŠ^ÁYô|³ðtìm¥C ›Â ¾ôv‡÷®Ø…Ë�O5µnš[:~‰ñ�[aêj#TÛÂWŽXcsü‰…±Yëÿ‰óZ¨Â1.UV¼4ã”ñùöÍ;Ñî|ËzÝyÓ>Âßz­ÇQbõËøô}ì¿xð²æ1*dKÇ Ö6ìT¤õ•¤ÿÓ}A:sVý²Ï¤¥[1¨MŠuCµÅéŽuZ‘? ‹¦ôÀBžšãv�’Žå“a&ý•·§_pK'h�@�{uäúLtÔÙ~’¥K��Æ� ‡dý 'ìô桉(8çt�ðÌ[<ñVðXD‡�ê¸PûIs¼fä50Ÿª<½sW‡TƒÂ r7BÔ»!LZŠYŸâp±úe| X‚é—XârÓ!ÉO…Ï«ÖCÇ)yÑ~u]Ó÷³vw³¯îÙØùŽ{Qô(ñ\5½°¢�š‰üªsí™Î§ÛQ™÷·^ÿusU´`4N`­õéÝ Ñ%°y�.‹Ðscy¦ ó­ÃtS¡Øù”o¦þÝxŽ’ôñ¾,gÝ~¤;�×~êŒÐswX6Îsš {ÉMkКœ{…>JtÏ|ôÈte?OJg¬¢#ÐÇ™ðÖáð˜H€H€H€H J€‚¯( ç Á×�_àåùÿÁ¶×&mϯ;¦ú¾8PÕ‚/ïâ…˜}Mg'Óî·Þ’%OÞ,[2ÒÞ.©¯�;OPåÍÓI'¬µôé…™y3¨µõfШ&à¿×�2{¬néí]d"äˆÅÜ8G”ErP_,]y?z¢3 —öÂ].6-�aÈll_ ûÕV2iǥ⠜tyS–Î/=1›´d3åÅ,¦‹’!Íó­m9 KkÑeIbÑ `bYméV1õƒP‹£ŒI‹DÔgi¨’ä9f±'h»‡eS{£ÇØ%fB‡¿(Vغ6ó ¾dan“ýbì2á]yßÓ~¯4« Åg½ð0ÐÙF2 ªŒî‡”&å P~£ <1—zË(O6R]c‰u]̤<ô‚�S¥C/¨Ä§3I]‘pûWÅ*>þ‹­E"$:)ú@BÞ‹uy§YƒÂ r7Ó'\‡ËK˜³Œ£ð@— ¸~ì3ò#/®›‡®ú…6ÓCðOZë žyUzk‡¡ã”lh¿zެïgíîæ\ݳ1ó�ôçªÁa¹ñ%ò«Îùµ¤Îg´íÈh¾”N×Ýe®×Ýó¦Åê²Ó‡ý.OžŒã×È8Þøè²È¤ßÕùÖaº©PìbÊ׸&Sÿn<ÆQú}¼×̯ úcÏËÑëÞkä^õÙÒÑ÷EÁÀ59!�æúÎö°cUóŽÁÏŸ$@$@$@$@ ¾âjÂÏXõ¯ç°v§q¢!~Õ÷|4óÝš±\®{Á¾hÒöW"öaKŸª|e£Ö±Ôv�:ÉîDP¶õ"–Œì=­ßBs½‹™ÚÌpô <+ çª - ZÔ|}œX·qY~áXL¹(Z©g!ÚJ‚‹ñ=a¡,Lu¶¦ìáãR“Í€‰zñÆ5øjÇn@¶·8.¯Uœ€I§-öXsŽ8"âºBÉ¿ý€I�°b>ŠOl~£W*q©éVø>›~It»šÊä¶MÑõ8Ý{^³Ô÷F”‡.Ï=í^á¾u~üDIïNÑxË1IœÉÊ_��Ö+½X-"dcKa-?3@¿P´EQÒæéýl«ŠIÒ#à4ÿhœþ@=®ÚŸ¹ù/xkÒ+áµü–ÅSÅâØh\:MÚ¯œ*¿žº¢Ý•�JÄÇ£�iŠâÚŸh¤L´àÎOнÖ>Ðõ'½ûA§ÓØ&ÎÚÚY‡¯ïoç\¥…=Ž›|k»ãœA?¡EÌ~[.–qNË Î\ŽÉçŠàKY ]�e|+„ Ón•Ï�.ƒ§›$âËȤ…N¾‹ÌGõ]¥\T{ái‡ÜÃp2†ú¾ó»g±åuôγ_NúžUh|u}NkÜ¥û…˜±ƒ‘Nw:iÒbýé{Û‰Ç[7Ô=ìIW�»ŠhKÕ¸ûxw§0Ò3=;‚/ÈK-çu,YŒœúÕpü÷éÑèÐØOõUŠW&Æcœ‘)ð�!Š8Ù‘{y·t4¶WÑÂ,+ÕE¸¥KÜý‘õë™�·¡o‹œ˜­ c-ƒÉ–z¹ˆpÐùh«b•-øš,yªòh< JOZ‚/l³·õ3„U«œ¬á²§×aâEÇF[›q_ç¸wµ×yðÜ�¸£×ÑÇåj»Ç Õ¢1'£ÿÄU8³ÿݸïá‘8ƸgW?‚c;_k…Õ^¶\æl3h/¢³ß‰@íûgE¾°} ~wd7;ÌÞ"~zA‰ŸÜx-a\7Œ™û®ëu,ÖÿýFüj eíNÙþòÿE·¿´ýÈ—°Ý»L¶Èlü½_# ›o]3tÞ&Œîá})M‹Ä¢‚/|è źNƆ…C½ã)‰ŠHÌá/³â[þàEè9±:œh¤1N°BðåìK ôÑVJýÿ®Ÿ®ÿó¶¥/ž#J˜³êîdlö¢X/Ž{H?’/ýˆ¬Ž`ìì)ZÐJ*²×šh:ã�V=^Ôó�1ÔËŸ‰%eïòŠ?4q Ý_éqdšëž~,¶~¦Ô9‘¤ß +8¾ƒúÂÐRè·ÃŽS¢iNpT' /•™§´Ç…½[!�ùÌ …äîÃ2±˜Óö˜c¸™ë>žyªseâoo<±ñ­-ª{@¢Hgí0|œþó_#‡ú~Öí’›{�^{³Vعª+~îäÆéw”ȯ:ççºáè|êqt&õÚ ÝÿÈ-/½þë½ÖX39[ÖLbV =‚¯Lú]�ïäå_&éùÎgØ>ÞK+æWý±îKŒP }^ò<(/ºO¶^twËUüù¼(è»&v}'äX%Þaç~1¥ÃŸ$@$@$@$pÀ àk×·ødÝfì©UË,ôZø}ôöØUàˆ¶ípD.Ìß{Äñ°V' Yƒš(—­_P[96ow šâ§¨?o �uà ­›AkǪ\ð%o+/~8˜¯‘I ó‡cáCDû¦òðbO)V/x=[ïÊé�µta<(éݺ§ûÐ\®‰Y-“‡ü=lKFÈ‹uK† ÷S.[k9æÊ ×±³qëå]…k”oÄkONÂà –dȰ޳R¬÷¥ŸÅèÉ”€¹22D¬üŒw­üîò W²‰zÉo�Q¦'OL*/±¶¾´¢Múwýœ!èr½�GÙFaáCWK9ÔEé׫ñÜÔ?aÔ¬¨ÄÇ kÈ£K0¾Ÿ‘Ñä�9n�3aöƒ¸ð´–(ß¾O�íƒ Î³+“›ž'˳ð”7—7�ÏðGↂö¨+·Oé×âáa=Õ©©‰¨,ßx,ÒäySn,À‘Rõ¾^ý:îéq…-³BÖ—õ$Ö<+o@.¼Çâ…È×xþÞa¸~ºó`LÄß9VéœT}gp?$[ŠÒpW~õOœ—2±˜×²˜=³h”IyÌÐ×u!&L'.½ bnõñÐe8ôG±.Ъç$¯+ÚÂ|::ߊOPÚŒK ë8-ºXfæ�߯öÏËÖ¨FSQ™\¶)™ÜóšeòÅ1}Od}—£× ]>X8¶?Òhðúœ{p…ù†²·gë½$q&+u>Z¯dÑʵˆ(½†Ñ.õ’vIúµO?‡ëH»àÁ0K6Ý�¼úFmI’ã µMm4NOxþ?´?ÿr ZðވѲ­«%µ‘.®püó…hÙ°¿9=U?mĬӔßQÁ—œÛüÖT´èim7ç\zõ­÷᢮§¢e³ƒ�ßâ£å‹ðÔ°ñpå*²™à”WñÄU�/æ·¶Œe:üj4Þyôjt+f½JßOÁqYÅàµJl¹�zyFž‘ÊçeEΫR];Ì$Î .ú~ÖÝœª{6:ÇÓnéÌU½åíÎ}­¹“§ßQ"¿p·ÞóŒsÝpt>õø;“zí†îä2O¼Vä7Gö–Eø~WçÛ¦“æD\ë{Öd‚üGÛ›hýpÂv¿Ãöñn>GôǺ/qB5s!®>×Zg/^ý<þÐãúèz–n#­Ʌ½gÂ�UÂó?÷s8ò›H€H€H€4¼àk׿÷1ïíÏS.÷§÷Âé-êa×–å˜÷ïÏRö‡ZÇ ×ïNC=å#ÁWÔz†L?›7(jÉFçjATì$³l †·È·L‡»>⎆Ì\*>Ûĸ»¼¬Ç8îÞñÎ…%˦¢u�±ò€G®Ðzë\c|o\0�LÐN¾Ç,ù —äžV*“L±~4@"íhÄ0ÇBÌóÛ¢2t\jäË\OFOš}3¦ËÈ÷‚�˜=» ë9›Ò–Iˆµâå BVA QðÝ3X`®ãê2L–g+œ5s‡#°ó :&lçgÞp,yeŒ*yððºlWq±+(tÏÄé-$Üʼnøëb]&ÉöƒœíbOúý{?èòó­~‘Ùn²xìÜÏA÷‡ã[oñaºÅÞÏâ®Æz¿°�ëcëÔ@FN¶…‘•ÆE"Õ~é:ãdÀó|Ï_¸ûÙ‚n„yuÐâ–û DßÓž|~$¯Áå`%É'ä‹ðwž#üM§æäWþê¼®W~‹“:)'ÍÆ ¯ €z‰Úx ›¦à%%~ô«oÁ t ñÇÚŸ¹ ¾ÄhÅ»SÑ¶çØø@m—Â�xf–¥ÞÕ’Çéí»Ê–¾ŽhB[kŠFœ7?y4úv2ÞöMö‘í‡7M··Nr­*Gÿ+ƒï‡KÚ쌱Té‚åê?¸X¬ÑŒaÅ"hûWY]=nJ¥þìJŒ9÷(3¹áëq?|!"¶ü¤ü>[r�9fL¿ÝŠ`Á¸_c€m…,åÂI‹dÃŽ‰.ñœ«2.“Ú`pÔjšêOtý‹igÒçde-Öòž'Ã1?ô=sÊ÷g*¼7îJÒÖJLº½H+MªŸŽ÷§â•8 �-./±ÄJVæTäa¯üyÜ$ÊŸq¿ª¶Ë¹"è[ ¾Œk6¿?t¿NÙ™ òi¹ßüÔÛ¸«�΃å¾êo—àäaÎ[‰Ãx|ÉF <ٞϔ®ÀEÍÎöʼ¾¯À‹o…>¿÷ Óÿ`úî~�ºÜh^î¿e£›&ÿó×HšŸÿxgËt‘/2=É6®H°�ëîz ±·FÍhÖÊVÏ«ZWF›¬ˆ°”‹sXòŸ©8¡ëpç'Ðþn|´l$u]¢GŸÏ¿§÷󲊞TS–ã÷íE e¾ys":ž³ó3áwº‚¯'ĺÖMó� {ãåâÐÉàl|"p_ﶸw±õ3ðoÿDZvÆ@{¾/VÖÆœŽ�b¥,Ù§ï´e²=å)öe›ñ`�—,.ój7�«d»ËߨÛ]úÅwÙ´qü+}p§”d@IDAT«™?ûŠþOaÃŒþÊX©ÇÂp5þ]:m<º°Ô_žy�J�5‘{*ƒ>Zs®ÿËhÎÙˆ‰…�0aILRbÆX5;nxµË "À´Ú¯¸1ªg ?i-ƾŒÙCψM‰ïïpýUøu‚¤õÃ7•Žc’~'ÁXÁ A��í ÃqH’;ÙaÇ)N®ƒ¾õ< ®Nˆ§ÊÌS*aëñ²‘‡°å3vm!ˆ•áî]¯rÇàš]¢¸¬°U™›þÛ*Z×&ø«ê¢ÿUÌ«‚Ö3ˆóä%#dÎbŒE¼Ûêq©æèæÉ,Ù¸¿1WÕå�CÍ�¢n>Á~/Å?3X[[¯}’èqrû§dcèø5ž¸²Ùï&/_cmĽ—¢°Ë$W½„—&óbÿú 'z®��z8Ûoræ«ÆT#Ù‚KÌ@zOµÅm@Âgµ&öžA¨±JXÞ©–§“A~“ � � � ð‚¯XK]ɪDë³z£Só:"øZ!‚¯uÉ.wÏÔ½{vDש ¾äacs[¤%üM²u™ÒѨíÃÈz¹¾‹%ê*�ëgÇ\)ÂÜi†­xÑN^ÁpÜ>öœÛ&Vde…½bƱŠaMÎ!V[>›#>‹ÙjÍ»�‹7©eã¾[Gc²¥<òœÌ8·�¸ ��òÏiÉŠGкû(ÛOf¯|–™O8Î�ôã’Å—!bÉȪ/ó2Ì•óƒMi<äv$ß‘¢Å¸ãÚ>ˆ§²ÏywËPtlZ‚9Ã/Çõ³Ü•ßDnÂ Ž­|y…˜ùè­hüòŸÑÇ4g)uO¬„¶ò'+ÏÅrÏë18º=µC¢p”X²íW×v²¶uô·&ç\íÿ]ýY¢öÝ?¶«j‡ýúww ø|Ùšl^ÌÖdº0D·N¯Ýýæ:ê¼±-ýf—¦¸§c¬àËÌEi^yñiLŸ-–¼þí“Ûvùö‡�tY/t ¼~Ÿ /ŽFÛK–S…xký|3}œlÃâŒG…xñƒ{ðÛ¶ÞyUdÓbŒ|!¦ÄÄÝíÊÛ1é¶¡8E泆^†+wC`5@db�º\gþ¸üØÎQYñ­}f8Ú]9Ó:/±�mƒÎË”[�³;`˜ôL~[Â?Ñi]¬øõßXÁÊ×â¶í¢VµÎ¼íU{SnºSçÇ‹¢Î¼ênÜróÑ©…—…áûÛÿ<�»^�Ç ±ïmb)ìµ14ÏÚÖq°l=y‡½õ¤®YÛ'ƆÁó×Õǵ3B»‹J¦ãDO* [0æê»m«\N¬òÝ^¶r9Wü¾‹wì#[k.ÿû4L�x3^Y­®·Oìz5†Œ‰ßŸ}¬÷dùf<ûu¸v¢¶WgÄ3�y'φ~wçnÆ{bý쳯”ô=vúÝàXs‚”´== ×]t J>œ…‹Î¸ÒM¯Ç±aî@Oš¿}óN´;ßâ�9þ<c' ë{¯¾~Üáu ø<±ë_˜¹\@\®súý_æsV̹£¯Ÿ¬æïvŠòò1öO·áª~�=œeFjü»è¢÷eNn­ÅŽ?�#ëçá×]®°Óá�_¹Œü�Ò﯌p­>“Öã"ß�êWüæóIÆ P}¡wNbE–>‡$éQy;NQAÄêí<ýê„á¡2ó”Þ¸ÐJ~‰ó®Íç‚Ü5|wÌ$ïeŽ•—X‡vÖ§S>Îx^•öÚaøµ�ü5·úÎ3™ÇFÂÌUS˜;@ ßÌ×ÂÔëÀtÚ'ÖÏ‘5‡ë�6?ùZQ™¬™´�5çã»þ¢ßM^¾c ×Kd-$ÙÚJ‚u'3Ñïôûø¨×Àƒpýñ¦Ygà®Ã-ëîò"û=§oÆŸ¯»"nîmìŒr÷Ђ¸uöpkr‚:Ì=cæ=ÌX% oÕ'¦9÷ ,"ž    �ýœÀ/øÊfù¦,øª¬D–GPRR‚ÒH9°ÈiØÍš/ÜWV2ÊJ¶`ûvIC®¤!§.6nŒúuãžÎVHô—cñ,Ù[R‰“^²¥‘œÈ‘òÈiØ�ÍmÆ\?å‘2ì’]AkÕ©�ô±”#1¸ _akQ-ë(m1Öx†äÙjÍ�3Õ£HY JvFP^.áKèMš5CLòヒ|— "~ŒònÜ´iÂ|éÅóèV�¤¸d§FÝhÚ´±�·øèRvÙGÓësa¨òð Çã‘2Þ#7çîÝÈÖ•uozâ¬à•ÂÅNc˜6¥rïù †—Bp‘’b””J; waÝ�Ñ´±çÉf !Tà%R_‹Š#h Û EÊs|Ú†r”•í’µ–Ôå,¦3�,—[�¸´³²;´Ý ”ˆ°Ö¶0ßEØ4Â÷^ZŽ’âRäŠ9ÒÝ»sÑ q}oÛ*ídYi)vJšÊ…o]aØ@úìôû&7ÖLŒ¾–ñCnnŽtq + “A?Q&÷ÉÎTï“Ðõ8IùÙØÃ´[‘²2”î´û]é»ë6l ã•ÌáâÖ·tŽÂp’åsl)úZÚÃ\ãäȘVÆE™cŠ&»2û³h$ûáA£Ú5s)-ÁwÎXVʬ^½8¬q¬ˆ'л÷„lwºy{‰Ù^ïF]ü¢…Œq½Wx~mÿº?æ6@înkÐ$vk< Ϙ¦åÈø+“vÖi‚é¤g×Ï{„$ò ™·ü\«ræsA—mß�SææÔCƒ&MR·Fðͦ¯d*œ‹\)ÿMšWè=”VÈV}ß|ý�17&j¨W÷`4j"óÁ@Ö‰]Ò—îÜ�eP`ä±NÆhÜ Q-v £¯Ì‘¾2Wâ9â°êwd;жÉVî r±KúûCk“6OIŸf¤=~’A�(©ö6g-/Ö-Û¥‘�ð­+ã›Æ±ã±Ø‡7ÄTq¿CõWR†é¬DS›Jýˆ^\µ¡8¤˜Äpã”OpYåæ)�ñ²�Æ ç¶&`æÊݹÀ8?såVô>*Y/à’ãšÉ¼Ê^†Y;Ì,N'åô-e—Þ\5µ¹“ê2ñë¢v­ðz­¯¨ãJéw+—klÖSíãcýþ® þ¸¬Xž“ØÏjê6i&kl‰Û†Ðkriß3vÎÃŒUÄk…ó,ž    ��_Y,ó¬ ¾²˜÷ý!êò- pvžls•7 k–ŒDÛR•‚¡èÝ9xèïcõâ÷ñë‰/bèM=ñDäͨ涵 d[æy � � � � � ì«(øÊbÉPð•EøGÁ|<ãR¼cóðÛö²ÆÞŸ-ë^²­ãþôáœu*Mæ…*“@9¶¬xƒ»Æ;šŠµØœzÚ÷·µÃÔsÎ+I€H€H€H€H€H`ÿ"@ÁWË“‚¯,¯€¨KŠÖcóàðÖmäA|XaAlÁÔü<Œ]£ÌCÖÈê³�Y&S)órñ܃ƒ?H€[OD^Ÿ žœæåI+¾ÆÓŠcÔ‹k0²ë¾b_Ò“\þ  �}Š€aá˰ôÅOf Ë^†…¯T>{kÔDyÝú0¾ùÙŸ ”âùA�píÓÞ<žxÛ«xuô9Þ­ Eä•»« Æ–ŽûÛ‡sÖý­D™¨he˜;¤;o_ÚÁç�zoŽìêm++:êÀðö¯µÃÀlò � � � � � ìç(øÊbSð•Eøû{ÔÙìŽ?ãúé |sZ8v&Æ^ÛÍr|OïSŽ+é�wÇ.ü C;7Þ§ÒÇÄ� �@e0¶ØøsÏëáÛŠçbæƒw¢wGïf�•‘†I$@û �Z¢÷ª+r¨?J»HËEäÙ³òzŸ5°'·.öääŠ? îÒƒW]®ÞŽ¿vnŠ[W»é=ï¶ñÐèߢ¾ë„šå?™Û8¾öÇç¬ûc©2O$P‘JðH~kŒRï�GGxÚÊŠŒ1¥°ö£µÃ”òË‹H€H€H€H€H€H`?$@ÁW •‚¯,Â?@¢./+ƦÍ_aÇîƒpÐîïñ=Â1ǵEÓúÕ@ée—Q¤x#Vþ­üÊÅ1í;îcÖÔ�ŠÄl’ d‰@9Š‹6aë·;�{p.¾ßòjv Ú¶²¶éÍR¢- � Tk†ìÈØæ‘ŸÔÛ7¦«óò Ù´ô%0~ö?Å×àóoËdºVÍ~q,ŽjÚÀͤXõÚ_E^n&EÉ9«ÆÁc V[ùƒ´•¹ÒV'm¥–Åúx¨B§ýaí° q1*     اPð•Åâ à+‹ð5 � � � � � � � � � � � � � � � � TC|e±Ð(øÊ"|FM$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@Õ�_Y,4 ¾²ŸQ“ � � � � � � � � � � � � � � � �@5$@ÁW �‚¯,ÂgÔ$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$P Pð•ÅB£à+‹ð5 � � � � � � � � � � � � � � � � TCûŒàkô€ÚÕ_fI~ì±ÇÌ®¾úêÌ¢o                 �‚ÀøÙ?™ù¼åÒ:iå÷™gžAÛ¶mQ¿~}Ô¬Y5öÊ'­ì‹ïzjW¨„‰k_óóè£�šI£&                �jH€‚¯,_Y„ϨI€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H  à+‹…FÁWá3j                ¨†(øÊb¡Qð•EøŒšH€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€ª! ¾²Xh|e>£&                �jH€‚¯,_Y„ϨI€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H  à+‹…FÁWá3j                ¨†(øÊb¡Qð•EøŒšH€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€ª! ¾²Xh|e>£&                �jH€‚¯,_Y„ϨI€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H  à+‹…FÁWá3j                ¨†(øÊb¡Qð•EøŒšH€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€ª! ¾²Xh|e>£&                �jH€‚¯,_Y„ϨI€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H  à+‹…FÁWá3j                ¨†(øÊb¡Qð•EøŒšH€H€H€H€H€H€H€H€H€H€H€H€H€H€H€H€ª! ¾²Xh|e>£&   �$~./GñúÿbëÇ˰íãå(ùr½øØ›Ä×�qºVnmÚæ$vBg‘×�Z´902Î\’ � � � � � � � � � � �À>@€‚¯,_Y„ϨI€H€H€H �òÈxcÜUØüߣNƒƒq𡇡ÞÁ�P£F�¾œS?ïÙƒÒíßbgñV”ÿ´ §\ú?èØÿOæ”H€H€H€H€H€H€H€H€H€H€H€²H€‚¯,§à+‹ð5 � � � $ °vþL¼7} N-øŽ?³{‚+ìS{Êwã�¿Ï@ÑÇ+Ñ÷¯o£á‘-l Ì= � � � � � � � � � � � T ¾ªrP|‘¡; � � � d—ÀO܃ÕsÂïoŸ“�=XýÎÛxkýlÙñ"»~’óµÑä°ÆhqøhßþDœÒ¢AŒŸýûç7>Á3¦¡àÞçpD».ûwf™;           ØPð•ÅB à+‹ð5 � � � $ ,øŠàÁÁý1bY°çö}oÀ?n9G_²_�¡àk¿*Nf†H€H€H€H€H€H€H€H€H€H€H  à+‹…DÁWá3j   H@ ‘àëÉáýqõ[@û úcäY�ðUÉn tæ<¼«�0ûÞ„’[Î@]ç÷~üMÁ×~\¸Ì � � � � � � � � � � �À>I€‚¯, _Y„ϨI€H€H€H �T_½Fß�¹ýZº¡üðÆ\ñ'LüÔpú%/…_äžÞ¾m >ß²»së Qýƒpøá‡ I�ZîæÑÙ&rrêÔF~¦M[ñÞ|È!8òàÚÖµ»JñÉÆ­ø^tf¹õj£é¡�qd“r½ÏgO_o.Æ–²°uäÚCÑú0¿-'u¼@ùŽï°as‰ÇA Â1-š¡AlRíè(øòáN'           ¨D|U"ÜdASð•ŒÏ“ � � �@v¤$ø9 sû·ö$°tÕ|4ø7qû%ÞÁ×)†àë‡"<8þ1âŸ_x®5~Üp×$L,pÃ(ýô4-œŽÛî½ u_¾£Å’˜ù9î*?Ó [ßzyß°õ×/1÷¥èÕÂ…É©OÞy®µ:æ\Þ¹/ßÕ¿<ÌUp9ñŽä~œúé?qþÄ…ÎÕöw{ ÿ ?Þf_1¨ø“H€H€H€H€H€H€H€H€H€H€H€*™_• 8Qð|%¢Ãs$@$@$@$�=a_Û?|G^e²l _µŠpÝ7À�€Ÿö�»¡{Û:X4ÇÝþqü¬™¸±C#ó¼#¼2¨?í‡M²KkaÐiÂÓ¦{Kôï{*Þˆ¿½em$9ïõ¹èÑÄqmzë)´þ\4„þ—üøj%ž~Ë�uÃâ7ÿ„_l]âo×nÝÄÏ[XlZ,“ë:_…¯í…&ÑP­ ¾b€ð' � � � � � � � � � � � T2 ¾*p¢à)øJD‡çH€H€H€H {R|Ån鸫c.»!º¥ã»ïŽBî?îGçñ†™.±Àõ̵èuœ%ì®mxðæÁaœêvŠ'Ÿc£E-¼ºjô]¸ç¢<Ô•-·£êm~Í´þ%²1¼þæ8œe‹µÊ؆¥íDÇÓZ›a`×"2û“%2ëÜËþ·íík7½?m®±äg]ÿx^�gBÖñ¢ÛUXq{Ž?Ø�E0Ú]è7Õ)«e¦/ë_ I€H€H€H€H€H€H€H€H€H€H€H  PðU�ƒ¢ à+ˆ ÝI€H€H€H »R|µï{þ÷‚–øiG)¾Ù¼ON|‹íd÷y�l÷x4Þ7ˆ¨«ýïÁ²«Ûz2UºV¶¼DÄW�‡ˆå¬óLËYQáÕqý±é™B¦|D>_ŒÆ¿›lºŒ¼ëü¹G[4pweŒ^ C\f½4¿oá½èÍÇÆàü‡ ×o±âý+q¼œvýt“­(ÿdmE鄸czœ}›™·Çž—ãÝÖ‘‚/¿I€H€H€H€H€H€H€H€H€H€H€H jPðU5œ}c¡àË I€H€H€H ëR|%²× Ñ˜yÃibmë;Œ/¼ wØ["víÜÞãeñ2k+FCðU,‚/�…¯nâ6Ùrs=mÃÈScšë€þ—\޾ç��ó;4CŽíþõûÏ Õ5²ñ£ˆÆ6ŠhìHu½qXºöšM—#{ÛɃ”àKY‹zÛõ�1ÂÜJrÒœ'qÝ FJÝ_. ‘ � � � � � � � � � � �@U à«*(ÄAÁW:“ � � �@– ¤*øêuA7 ìG4lz:"ºçwÀ)ÍlAÔëÐ/ÿϘŸ,/Jܵ´¥D`Ú{ù¶u¸wÊ“¸ãŸ¶XÌ9)Û0nüß^8R¬umzë)´þœœ¹›>¸Èc%̸<‡Ú¢1êæ/_e~“ � � � � � � � � � � �À>A€‚¯,_Y„ϨI€H€H€H �T_½Fß�¹ýZ&å;Ü'¾F‹…¯ñ³žÄ�¼–±ü<&^)‘ßaåêÕxvædL[f�è?vfô> ÛÄÂW ÃÂd{Æwe{Æ:Ê£Fãð³ðEÁ—‘ � � � � � � � � � � �À>H€‚¯, _Y„ϨI€H€H€H �”_#'anÿÖ B‰àÉáýqõ[@ûKFcÙÿœ–àZëTTŒå'¼òõíÆÑËNOäÓWÐ¸ÐØ²˜$B³ëb„foσs§ÂúbÍû—¢µXK/-|™,ù‡H€H€H€H€H€H€H€H€H€H€H€ö|e±$(øÊ"|FM$@$@$@ TŒà ødÁÃèxËB3¦«Fß�;/ê€&"°2>Û7­Â}O|ŠA7_dŠ® ·„«ík0þ©M(¸ø,t�m#s ?aüŸnÀbåË|aÏŒ<í�˜fœ+^ó^º=ZXÖÅ>yçt¼þ óLôzù•0^ ¾L^üC$@$@$@$@$@$@$@$@$@$@$@û  ¾²X|e>£&   �R|u‹Z Zø’<â+#–èÕíìøê?X,[=Ÿþw=ŒÍÌãD«OÜ/â11f|Žk‰®�bñ2ÃR—õyú¥¿ã¢µÍÛ>|-®²„]†CûοÄ!%nœÀo±âÝ+q¼½Ýc¢xñÃgè—?ó%œIsÄbØ Þ­)¿Ùð Þ˜1 ÷>‡#Úu1ãç            �Ê#@ÁWå±M2_Iñ   È �T_#xãÎ<,yúÄ ×ƒ“Áˆç\q–ã©ÿ !qiw´ob µ¢Â«nCP<ù£&   �>|jVþßýè=r:¸q‚+yê³ÞÃÒçŸBÏI/á°: � � � � � � � � � � � �@% à«’' ž‚¯DtxŽH€H€H€²G`ÇæÏ1XjÖª‰æmNDãfÍQ¿ñ¡@�ÙKÔ>óÏååØQü ¶]„ÍëÖàÐcÛ£àÞP3'gJ%“B$@$@$@$@$@$@$@$@$@$@$@û' ¾²X®|e>£&   �$¶oü½ð6-}»J¿Orõ�yúà#�A˳.@‡‹¯Cí�LÌ5 � � � � � � � � � � � T1 ¾ª¸ŽŽ‚/MƒÇ$@$@$@$°oØ»÷gD¶ãÇï‹�½{÷ÍDVqªjÔÊAýC›QäUÅÜ � � � � � � � � � � � (øÊb= à+‹ð5 � � � TC_¼³>9}~£¦žI&           ¨|UÅ�aP𽑠� � �ÀH`ïÏ{ðòˆÞ(^·½&ÏGÓ¶'€˜e             ¾²X(øÊ"|FM$@$@$@Õ„À�Û·áóÿŸ¾ö,Ï댖gõÄ;SÿÍO=Çv¿‡*P£F5É “I$@$@$@$@$@$@$@$@$@$@$@$�) ¾2%˜� ¾2€G¯$@$@$@$°¯Ø»?ïÙÃ×Ï{ÊåûgùWn‹»éæ|Ë5{�cãüîÝØµs;"ßký+±¿w|‹�_aæ²åYà˜ü^8¤u;ó÷O¥ßÃØÞÑ‚}·q uê59u‚º�›¢žü«ÛèPÔ9øäÔ©‹µrP³fŽ|×BM9Žû6ÎÕ¬i�«i\S‹"²}­~1=$@$@$@$@$@$@$@$@$@$@$@$` à+‹U�‚¯,ÂgÔ$@$@$@$D@„[¥[‹°ýó�ELõ1~ün+Ê#? |רm|›ÿ~´Ý~Äž]òo÷.ü\¾[DR5MáT û»VnÔªmü«‹Z"¼2~,ó·¸ç(÷ZuêEÏçÔ=HD\Ç¢IËPï�ÃRjº—Kü%_¬Ãö/Öb׎ï°ç§ˆ¤5b¦i�|—ËoãÛpßóÓ®èoÓÝt³ÜM�Ú^C¤ö3äjæäÚé¬ #=¹ò/§n=ó8§Žq,nõê£þá¿À!­ò̆،            �Ê%@ÁWåòM:_ ñð$ � � � T)�›?—mÿŽ�o½dŠ™ kZÚjV݃5­fÕm|¨�ØB®:²›bÍ*MgUG¶WÄ_†PÌø·û‡øÑ°@VR¬,’£ìÛ-øvý ÔnÐÇžÓÇ�ÛOŽUuR � � � � � � � � � � � (øÊb1Sð•EøŒšH€H€H€�/ßý–Í�ã/¸ Çvÿ�)ìR§y˜"�ï‹6`ýÂÿCÑû¯ãœ1�ãàæÇ¤è“—‘ � � � � � � � � � � � ¤J€‚¯TIUÂu|UTI$@$@$@iø±d^rzÞ7OJ­ÒôÍËý|úú³øäå'„é?üNÓ�H€H€H€H€H€H€H€H€H€H€H€H |e/S¯|eJ�þI€H€H€H s¥[‹ðí§«ÐòÌ‚Ìc&cÈ�çÍ@Þ…W‘ � � � � � � � � � � � �@ à«‚�¦_éÐâµ$@$@$@$PÅ~þá?)¨Y¨!ÿø!           ¨t|U:âà(ø fÃ3$@$@$@$�{÷bïîˆüûI¢ß›•$TÛHEðU£v]ÔÈ©]m³À„“ � � � � � � � � � � �@u @ÁWK‰‚¯,ÂgÔ$@$@$@$K@¬yý) Ë^ü„&P#'5êÔíŸI€H€H€H€H€H€H€H€H€H€H€H€ à+1ŸJ=[ù‚¯Ö¾÷>¶ír‹Ó;4¯Ôü0ðƒ@dÛZ¼¿v›d6Çžv:š×݇óÙŒ÷Þß¹pØ §á„ÃöåĦαtó¬ûr Û3µë7G^‡£‘IÎÊ·‰wW!¡å¢å)§ãè©§%›Wn^õ6”Hé ƒÓN=6#ÙÌã&Ù,í͆jÒÞgƒgª�½"öÚ»§¼ÂR)^‡e뾕ðrÑúÔÎûvŸYa¹¶2-}å&ï�ªkTÁ¸ª,¸j5Ž«2*ûoDéŽY?ª]`›ZýËÐÈË1ÛåXÑkiåøòƒwñEÙ�µ6¾ñr¯üú’nZù)ªÌ²Ç¹2sŰ«†×ppÞOר业žbXM ŽÉ&  �š_qÅ¿_¯_�ï~ÚÔj€cNh‰dö vïÜŠ ë?ÃWÅß¡," srP¿þ!øÅ1­qlËÃåŸÿ'Á×ö ïaéúÿ’¸Þ²Fä�ƒ7�ë:LÁw+‡¢I?•z;>xc)¶J• OíÚhܸ9Žnu š7Iþ 0(ºW�¦vG§aoš�ßóîw¸éôìת œ–~0 ; 3Ow¸ç]¬¼éô K«‰{9Þ¸·/Îýó<•ÞxwçJœž�HKsÚ×ËÔÍx)¦žÔÃV.g ƒE1pÃåѾD :µ7û·}%-¥2†YÃÔÇI¿þšç$O]dó*¼¹ò+ûÂÚÈË?§J„¨{÷ìÆÞˆ<‰‹ùlß´®\‰å«Ö d{?ÊùzMšáèÖmpòÉбíQ�‚Óú-:ß´Ä ñîE1ò´Æ1¡ïÏ?k æA5j$ÌdõìƒfiŸ>ÉvuŸ.ž L\¸1ã�^?<ýVýcðë_�€„ÝVé—xcÉy £6ÚtéŠc›$¼ºË78¨ÊlS]>FßÜUúæàünxï ¬/1&ýBçðÎ8çT¾|\jñg*³ãc£K�Ò÷нḖ¦æ®ûÌÚ\\®+Ü!t=âä^á)׆ëOuÕî8+œ«%&8€À�>– Àb:ë6qÿX£N”Ûj|Žm`5.<&�H€H€\|é²�|�·þ±Ÿlw,;Ôů/¿­5G»±~É?°hM±Å{œsλø<´lXËë.¿R|é‰R\I:Ü1‡ÞvE.R%‰0•ÓzМÂõgž‚©wE‡ Ô•~¹ Ê«•ÍO8Çî'ŸR@Ya—¬š~NúãSfxS–‡¡§V`áTX*­€JWMGÓþhþè=e9^zjÇPµÁ•o˜ƒÜãÄD:+|Û)÷ò º¯9íëeªrƒ™6Ä SûÖËw¾„S3½¹áÈG¥XõÞj”Õ> 'W±Å´ º©ûÀê#F<�ë�7ïºüŒ3zé Lî}´÷¢¸_åø×ð\Üª²ß»ëì-wéÛ×½ŽqÃúaʿݴøà¡—ïÂ5ÝZÅ�^õ·kpò°gL÷ÉK6bèÉ’àK´^uB�œÚq\´Cõìƒtª×quÇ%#Ôw$ów œO6f b·?Õ�0åÛo=,s�! æ:úÁ]UõUV¾‚Çl•Ù¦j>‰ò»vîpœx±Û‘�zéSŒï}l˜"9`ýTf9°PÓÉxé"øêT�ki¥îܵ÷ÃØùÒ¤3u j³ÓÉR6® ]�ƒøG>Àeõ:Á\� Á1 ƒdýi˜0÷y?Aü÷ù„3�û�à±BðØe_HwU¤A·‰ûÃuU0ËJ|˜ø^­®c’¬Ô%FJ$@$@UH€‚/öÖµK0ñ8R/˹λü´ R½÷,þ¹r»[\9 ЬYc”—lAq©éî�ØG|©¾VM¿PÄ5Úš�]²£Þˆig×Â÷Æ–Ž�ŽÂ Gï½@“,Ñó½±xëKøÕaQ‡ Ê1O$_(ëÏ|›&Æêô h›Lëüt<o=x R7$\÷u¸|…»/ö_å›ç!÷JVªÚbZpÝ4¶ù¸è{IS.Ž:ñ„4êûþP"Õ?º¿0s#f¾“\ G#²¸v¡<`Ó#Ÿªj—~–íaoç¸áÿ³w6ðuTeþú^Jy)/ •¢€TÞ‚€à½¸w—³WdE²+èu òW Êþ—¸ÑUÌîj@…€üÐÀ.Á…üy‰@x‰`ÓB ¤´)mhÓ–´$¥IIÚ$œÿ93wæ)רÌ#ÿîïmMµB.³ûy¤Ê&™ëB|zEM™oy}g!"œrqtÖWøå"ú÷êüvÖû²ÊÉô^-k.Âu5Vúù©ïŒ[#ìºÏ9ííeª9 Іr¯�(ƒú Ž’èk­IëW…舫^É’L‡²ëf^Ñ"pÉ ðþ³”‰¦žì£“Þ–j©‡e~[§Âí©vi|xPŒ ˆmOÞb¤O'^.|v¹Ø¹}À¹®îÚ*¶t>"nùü ƽåuO±{ÄKu—ø×¥‡/ãš�sò¿·;º1™˜}PÉ«Wbx½ÜSu+±°Y¢ïȆ'û˜ÑÎnòèG6:ök<ÿÞ\;Û¢TíW¶1[1eâ|ÂÚ�žo,éŽÑ¥g/;l\ÉJ ˜å˜5a\,6wMÕ‹x«(ö6»HÂ,Ú‚ë±±žX/öÄ@öþ´`¨LzÙÆ.“>óé ò61Ûørªð@>÷NÙëêÄ“ì�´!€€Ž@R{«ûî»O¬X±B¬^½Ztww‹iJ$¹(û“Ôâ,vBÖ#ô콿¡×¤Sšyý¯¿=�ÞþÃÑŠmÊC—ÝÃ×Î5�Qã“ëÝX;‹*ËOv�Ùÿow>Düq‹sfîGþ’þaÉÙÕܶt4°æÛµƒr[½0‡ðc´im7½ýîh†‡¯­kWÑy~ÞÁGÑ1 çÓЦ•ôìó+iË�ÜÊhö|:î´OÐYÇ-ôSX»œžyaõïÞM³gDGŸv¶¼žÀå#/ÂûȪ{iŸã½íëÊ©]nÙvVF6Gä›—¯Ñk¯Èü(Ùi6täÑôѲ�Ò‘�íÞ\Komz�¾vöe®kþÊêúÎY4::�Ž=îHÃ#Ljô*óÚ+¯Ñª [HfY"‘yþÈGe¼æ} ÍóXÉsŒ–ÿáÔùf¿ x$]xÉ'éЙî�cC[©kÅJz]Æ+Aºò¾ÿ(:îÔãiáüôM^¤…ú–i®|E¦ùÆR™‘ŸùC§ž}F¢--MÝ ÛÒ1÷21³8F[×vÑÊ5¯Ó–-CäH*uñÈãN¥ODl/7°ö�ÔòÌK´C–â\ÉõÈ£O£3Ï:Žæ®º‹f…“Œíí©b•µ™·ð_#[WÑóO/§ÕÛ¤äsç:z¶èè餓�1=�l¥µ½oÓ3ÿr<]áî¦I• môéönttú°¬«Ù´'J÷ÇØÖ—u�ÃôͲ™ôæÊvzqåGgT�_$ëÔÙRÿíé$-÷p6þÙ±úã­ôÒúm.£ƒŽ¤ÓN?“Ž[8Sn‹±OÄ–Ž1e’œW­ÙB²e¤£ÊŽ‘=€tcý̳´r­l¤@ó;Ž>qÎY²®¦¥“²-o{†Vɺ.[F§í9ýòºÅ+$Ñ­úãó´ü¥Õ´C–·,q:è°EtâÉ'Év#ÄçQ†<#´vùŸhŪ\Ë%]§^•uJöqªÉQmÙÇG'Ãtfd@ê×[´âޝÑçn~ÊÉ\C[—ãUqÖû?DG.˜+ë¦×gdoãœÀ1Úœ(Ýœ9´‰º×½í”ÉÇêEºr®Géûu^ÜþodëZúSÇ Úà´;n™|ôãgË|Ûµ=Uì¯d}@îm£jÏÖl|בë`YÎV]Lë–ºqÞaDzþ2G�É1çnñ²¼[ûÂJÕµÓ“ß<ËÃÝ&·j :6••õöÁ¬^+ë騛ËéÏvÊñ Ña»�þª,ÁØ$-�ëák=}o~ÝâIøùŸÒ†__A ½ßßcô‡[ÿ�>uCKúÊ9ôøúßÓ'qr_¿xa3}åÄ1Zõ§å´bÝF9¾Ø%[…ý裟HÑÇ�NȈ_žÚF+»^£Õëút?¾à(úèÇO¥c ipF¶Ñªµ}²ÞìCG�x”Û–=ÿ½òÆ[é¶l1�}Öé¬-ÛN+žk—cž·-[ô!úØÇåõ�¨]ñ¤ž¼±šV¾±†ÞÚ²Ó‰“fïK‹ŸLŸøèQÆxjZ\_Iû íGœ¬Nò2�ãÄ9ÆÚ8¥Ïse¿³jù Z½ñ-RJ-Ûì²3?NeY½ôÆë["Çq^û0‹¤LÇÆÉÇM…ks£ú®ºqû]¢ñ¸êpÙ�âè�)ç|ÈòË6f´&cëö}ä\k=½+µ�fFÇcoc�þUÞ&{–Œ¹ÏKØqÎùK.V_Îë‡JÊõóUFM=Ëéâ#3ÇÜSƒÑW™Œ©KÙú¹“þŒŽ]0žuÌfÈ”´M5ä×?8Ÿ`~7=ó#úÀyßõo®nꢛ.>Îÿ�yP@.!ýܶʕ/÷1——Ÿbébòr”k@«äШ^ëñdõ¿}›E‡Éñ¢¿lâŸ/Ò\(n_�!Oܹ�ŸãŒ]n¶¹�}-Í�lHÎËVЫé±ÕìùGÈqÙéÎüAÍ-Öly—fÍ;˜>ìϹL_ÃÒÃ×Ì¡7©ýÙ³ÎAríï’ö-˜1™§®uªµ§YéuB㺣¬]å^—7°¼é»6­¥�oë¼�$^g°ðçë‰_Éê¾Îƒ$õ/[j®ÁÄlÏüDä �œ¿½´â5Ú¸E­×¥×>–¹V76°Iz¾~[†œ'=_‡Ï‹Þ\E峿…õ×qæyþ2u]w’ŽëâÖ+ò0f9±�qE�Üg.æ:–T†[ù½&ç™[ú‡œµûEe'ÒÎÿI¦Ÿ°ÍÅùüÆÑU¹nf_o:Œä„²ÈãÌ=ß·ç³FÍK*ì8y—«~ðTKQ§òM³ë¸ö6PÓIÂS‡æGÁvµ°ÏèbèÄÚð~ƒ½Só¹/,ƒ€€À^L ©½ÕÒ¥KiñâÅ´ï¾ûÒôéÓ¥û…„Ÿ¤g “ 6,Úï¾]ÜýèËÂõÁ5,žiô¼}Ù=|íXÿŠhæñÄ£�ŠŽ ™Þ»TB»7µû^ßZŸ‘vN¾2B¹'¢Þ®uî’o¿¥Ÿªkí�U¾÷ ©«úØñª5,šªSú»žªi�ïE,Öyƒ¢>åÉ“mÊû v5koaL./å5M:ÏòÝ¿º´g/ïºþ.íþ«�ý¢¹V{°Ò÷xr”‹¦ÎÀû˜ÏfÑXåÝ«¾Sé¸ûEK­öΔ/‰òêFÇãËbž‡£¢£AyJáò˜Çµ-±ßŠÌ¦{ñÊDgo´¯]TûemÊèÊ_!š»üBҥ߷Ö:[yUІ†ßS\æÛSÅ*k&žõ0*í2Qת߈ì¨ËRŽ\ÃŒÖ}þ–Y]k›¨ó=gÊ¢¼N„9çIZîaÒòs£=­Ö:^QÛ j+\ž¶îNQk«#åµåÒ/ÛÇJk›§Êµ\4¶»�j6ý’[ß ‘S§D�ÛæDëfG]Ê×ýÚ �‚ñê‘×ÈK›è x¢àíemk�QùýHÖÄm;¯T¯†ÝMº?*«u½ÆÑ™\YðþB³­Ý'_£½Í~›Me^ý6=|ézQ.š[|ýPñ;úš«p!÷)_[¾žÅy¹xi[.^·Ö‰[ÏÕíå’ï?â{òÒ¾N7ÞöSq™Ñ^è0åß¿_¼ãxãémËn»†É£ï÷x^öƒÌp/Õ]�sŽxü…GÄÕ–4—vn;;ïKB¯_ éÚìçÃóF¶kýãâ:–WOý}‰xpù?\l_±û ¸íŽWðÉê¤:ü;~œZŸIÔ·4‹*K»�ªæcZ�z²¾E�›2=ôô˜}ME#'Fµ¹QcäBµ¹Ñ}‡K(J^s¬¥© ‘„+~_?’ä#[ŸNt¢¸æÄÌvÄ­¿îx’·ÛŽ~ðù¤;X=ªŽv‹J¿-ñæ?á$̳ Ê©ˆ}¹Î¥¨¯gsdé™:0t²aŒ¡3Æ)ÉtI· ™ý܉ߴ÷ ^hÈ»M5K'øKó1ûæ¾víUYéSUSW0¨ñ;IËÆÅË»›H”N…´U2`Ü1—“Vu1q9ZÖ€X ðv¢¶]k¶f\è¹P²¾šËw.IJ›yh”›eý†·}|-MÆ6ÜÝ쯧éñ�Û¶Ö4µŠú ¯�åm&óðUQ/ÚZj­ã;=å]3‘@IDATÉ¥¿KÚ·dbíiÒ2UµdÜ0ÜÅÇÝaí|?[s+Ê!yb=¶ñϺž˜¬îgd4}‚ד`9+oÄÞb’öÌM¢W4V{ëžÎèïŠÚf6"û¼XÅÈô% ³±çyVþ|-9þ¸.YÝIHÄW’r(Z#e�Í<�¿$ëX*h_{£e}JéT`=µ ýDæÅ닃ºš­.•ýð.&7o3Ó@¼¯„ãÌ=ß·ç³FíeÖö�¼�‹¥éäKQ§òM³`븶60Í& O[©šë­…}FWÿ³ÖÕÚ?°>^÷U|éæ1�žæ2.“3±=ÿ\ÍZj¸  {%�¤öVA_ØàK–ËߌQ€å`ð•Ki¾ÕѬ ¾žÙ�dO|ùÛ'–3wçrrç|*•WTŠòTpЦ—WÊë�0 ¡F8YÕ'².ÐèÛÜ£>QÍ´öê'ÄÃ]�z1ʹ§LTTU‹ªÊÀ‚IUsz+ÈAÑT• „‘‡Sò�rY•èr -¤q[¥Î¯´–•WŠêêªÀ‚žÜ’Š[fÈ<…ñt½î„µ«Q?\sâMUˆÊž …Ûf²§9`ìU–rÒ¬(×Ñ•,åõñ¶:´-ôÇ/“tyˉ».g—Jêbee…~ðï”qæä¿ƒm/ÉË+ÐS'Ÿ†ñCñÊ:¨Å™¿ûD}À *UQåêY@îšV¹]«ü(¶Æ§i�O9ú[�ÖßÌ”Ü3ѺÏb+÷OÖ)¥£)ïwºl Ž®l:Œº'ª.Úä œ—í”ß~¥ó[Y-ëxEʬÇ3S7’ê"×m?Oe墲"ЮøŒd~S!×Ë�-hûÛ{².V©¼Û«²Zá–¸Ë"TÅ7¤\ ƒF9Y²Sa2óQá,Ä+^)ž§4o¥sU�ò�]mœ’8~›­›œ�i˜¿9T-ý_™j“3ÊÙÔ+·T’ýŸ¨HÒ6ö¶°¶¢Z„›¬õm�ÓŸÅÔ™\)èò«uÌè¹6mlŒ§Ã7º, lkg^ö:N·MòëªÔ×lFnÁ´Â~�o÷|^Ç[^÷œo¸ä<Ù¾Ím ¯ëÒÆ[ÚàKÇKt‚¸ìK—‹ò€áÅ’=n¤·î¾ÀƒýÏWÊp—]˜û6’>Ÿ/W~Þ3㲤�Ï ¹~á¯ÄNn„¶}¹¸.ÐV,ùüåR¦K˜Þ©ø.˶¸†kq ¾|y-m]°Œã·;nÉ'ª“aJÃÎ%‰3\ŸËDyEEƘ[zÇc©ÉIè[xÝ’1²‡Ô²åÜA¿k‘pÜT”67ºï��½ŒvNéUÔX˃›”«Þö�D?’ä#û˜ñZñ³o¤Ìq”dÃçC\']ý-ÕzîPÕÞ³ v0ƒùÒ�žµÙˆ¨ó Ë©(zåÊ©ó¯ÆH²N¤Òm¤äTÕ¤_ÆðrÅÇÐf}*LÕm¢+Çy×ÿ0û˜M ÆeÒáÃÇ�Á6ÕË—í[óÑ_ýÜD�³Ïg“Ö1ž¶Î—ËEç#a[•dÌ¥ Q—#_oák@¬PyÜ\oC`.”´¯•Ç2>0æB,¯¡‡¹Ìml½2—m‚§‡as3éP^/÷�‚”1NC` À o™ƒ¸ÆDÑý]²¾%”Š<ÙÃÖej2æ� æšV3tbìoÓíSºàºæñrÖ B泺ËØlüùy¹5¦~%0aÝ·¡P"ä°“´=sôÁ7 L·cå"¸VW&_²õ>¼>ðzë]7tŒ×ý$ó<ΙÇåé`Ý*§¹´6vÝÑ9´%-Î4J?ãµ1ñÖc¼|%]Çì4ûaõâq…œK˜kˆÒ�×[S·•¯'ˆüæu—ë[83³/æ÷¨°Ù×›^)Þ8³}{ò5j?ô0y[?dú¥¨SM3ß±K–:’„gh‘z'½¶1ЮæýŒ.�þg¯«SWDø�‰B_%Uƒ¯mkŸwÜîy »C¼2À�ÊÜD÷¨Á_ ‘~ý¶š˜UŠö^ÇâI 6*Úƒ“ʪEg¿·l?,ZjRþâV¬I¯Ê64s™\$�ÿ{D�?àå‹eòÍÁ”;¡T“òòÓKÕ`w‹aìPÏ^EîÔ#‚²›“‹rÑÒ­—�ÔâI ÷üÅeÏœK�-]¢pPþ)®¦§²¦.ý­Êp_'÷T)º<Ôñ~ö‰ZŸ‰ê&sá½·MsPo{uxÅŸC"ÁÉ»$y™ôµÕøúD†®É˜G{�‡�åõ,�…«šþ*ó­*^ÞÅ+ëh€}­,¿’}«á JÖ¿íy‡È4ØÐo ª‡,\?£Óͦû|1GÕ)åI¤�éaw3“Ùðp�¼Ü£$îâ Ê©ZÃûÕp†ç/n˜“\¦.ƒ=‰ÊúvýÀ²¯ÍhW'^¯†{Zô·á£—µc$*êÚ c0õÆo�«[´ÉWPžÌraF�¬Mâoe¥ª›M�£}†×ÆŠFïá¥l§ü‡œ§,©È6N•fò6'›n†·72µ¤õ(£ÿKI¯�Ú¤A®FåÅ7£tÖ~=Y�¬m�ìáA¨ü}Ì(,]Ÿ“éŒ=ÇÞ]~rœÑݪ�§+šŒzàÞÏ2I£ÉfØÍóÁÛAUË*ëDW_¿엋ɬÝòdˆó=>¼YÜy¡7¾�Þ±Öso[ÇÛ_`ž´.ϧ ž‚_K®½KlÙ®ãzõnÔu‰Xæ{[#naa×ÝcŸmx짺ï$n@¼zÛåì‰+ë»<íõ�dxãqï캟yüÒ†[ÊÐmËcÌûى׈—6nÕjÛ»Ä/BŒå’|e¶u¶>(i»“¬Nf×¥dqê:âê�ãÉ‹éq§á…—·ÍÉûž¦®[â¹Jõ�ìwuo\ô�1F.b››­ïHÜGÈ\ë¹G¼>»ú‘<Bð¶28fÌÆ.L? ¯.r¼aÎdÜœ·2£° # œÄù+¢^éüËú¦æGÜã�ßµ2ÏÇк>© '×%^váý\–1›L™Ëo\¯äÎþÑ|¤WB9ie}µJ«2òå¥brIÞV%sIVEÔÅÄå˜Ãz �›ëmpîQ˜¹PÒ¾Zˆ <™ãƒð¹Pv-–Ws™ÛX8ò:@e5‚¿ÿØÅç̲>(ƒ/=e|É9H›ƒ æ ̘ÊÞf'{dãÓV“J�!ËD‹gâʯ^´¢k¯ežq0×µXí‘…¿m=1ñúN6ék¼M6ûÓäí™ÑÿÉPÛûô‚œ¹>X&šÓåÀu�×[�VFù® Xù×’sŸKsùãÕ�Ãð£äåP¬6&ÙÜ:é:V¯±ö[ÕСװk?$=÷9Ó [ù2À¼îr}ãõ!|Œ¢Æ Ú8T‡µ�]Š6ÎÌc­™¯Ñ)ºœÖŒä˜€¿xg�š¡=LÞÆ%Ð�<ưÉëTáêqAÆ.Ö:’„gh‘ê“cÉÂ<£K<¶UϰlkÃRjû˜$ù8VÆ$·ÒKd^è>ã¡�.ï"–µ—´õ[Ö=fŒQ|jä„3z\÷sΕ0öÖ¤ìºx0ª/|ò­®ó)÷€x�Ÿ}†Qg#÷¨—¾ÓX$e‹éùÈÄuMy6 šÔµ×z à².gx¯�0ª¼‡åŒÛRzð <'tr3Ƚ´0]6䑸Ãw/i¸™˜/ÂÕw†´8òM¯úšZÑÐØ$Úº¼ ¼_¶ mœ&�6'›n†ë|>õˆç“DX›ÓÛ¢F¦.ôøÿ'ì Ò6J/—A èjÔF¥ÞØd:�B—Ÿô”2* J|/šò ã@eàÞaªZúÄh·~SY/«gtÜ`Yzè f0Z,ëãï‰}#+ÓˆÊæÙKŸß̼ƒIƒ¯�®Q—ið¥=ñpw2C©[Ÿ\çQm{AÜòùKD¹òæuî�bƒg°åsã4m`¦âÝù3»ð§[E>ÿƒs´AØ—îÒÆ`NÜ[Å#_÷<ˆ™_«ï»QÊs�cvãÃ]ÚØ+-O·üGO9×c|Å胷; ë¤UqÔ…„qê:¢Æ—UÞ4dÄæ¸!ýx8�¾…§éÍÚj™'KÙߘCÿ|ÆMÅksí}G€YŒ±V>\ ¯Éó¡d1ËÙlpíìlá¸Á†|øÜß{´‹¯›/+ع䓿â长¦ÇBíu¬~ÈñŸsp–¼¯ÊG—¢û9ž-§ÇšË>äãG=fõÂgûÖ|ä‹õuÚ�Û™ç6g ê\+.—ämUÒ1—ÓFûÅ ;®L\Ž|½…}ðÂáq›zËÆXš %î«¥ÀIçB<¯áǹÌm˜·iŸ#o å:›§{é´óþ”ÍQsÑ>¿Õk2¤í¥Å„cOÖ°ïþv½ŽÆ_D2Æ9ª¾«?ãE0!Úü¹²Z+scç²Çj�lzz>yÝc<ÇÛ=³¾è¹ Åšç›òòõ/ퟥ4>op×mrxa óuÖ4Ïym ”³J‰÷?qÚ¼|êŽÎaØQ>ýJ±Ú˜$së¤ëXÃÝl÷ ¶–ä³lg/&V¸»XË×e´;\ï£Ç(¶±$×�àØ…ëG¡Æ™Bìé¾=ùµæ~d¶qžW$Ñ�RÔ©‚¥Y°±KØ@ŽK’Ô·ðBegyÝy¹;á3ºÂè°®f“Èù4ŽžÊ§xÌÈL¾@²7e).ÓG^fìá‹g´ŒKçQz‚ó¶",jY%ü–yq¶ÿtt3¤î¥oïiÖzVQ¯½šñüxì)XZu_†à×*}�O<*®ãZ_ŠVî|ñZz93<§å2XF&Ρ:dË"ο–½uí‘ÒÛ\hyøbŸMO¥e‹n¯˜Ç=.OÆ„×IÔ,wëõV•^¨W[Ö¶tõfýx2ëo3.Ïx̽ί…µq:–lGšŸæ£îçùôëi:"Fo¤ú¶äõˆç%Ü£"_ø Ê“-ökEê,m£©OÁnPªË!™ÎØsì]Ñå'Ó’ÝÞ ÓMïá…{oÀ`R>Me·x{Çõ%UkzðÒMú=¾õ¦[$‰ãák¨‹mwx‚x°Ëõ~Å ¾Êë\#(mìå…­¾çkþØÂ3” Þö[Çmf½Ã ¾®»oe†a–GâÏÀÌ7$/ÝvIZ3Þ0ŒsÛžò½‡yùˆkð§Ê¥œ ô­x‹Q'“Å©åcã”@ƺ™‘¦×&åÓ·ð4ÕÖìÝMÚT�urk%KÁÆM…msy[àqqÐåÑGäÃ5Pl�Ÿ ô#�|¨Äy9ó6T]³²ËŽëIy†W½uµQ*1Û'¯ü¯/×Ütiö«$ø Î’sÎG—xœáýÏ?“3Íš‡/^›š6øðæÛÎwJSŠÊ%¯¶Ê”3ã—mÌe?¯�‹UŽLVbFåÅ8íÂØ&‡_H¼=bu?Ñ£cñÚõ?³®ò6À—‡žÊsJ6.+Âx'³ p@@&<�¤_���âÅ_¯¾úªèêê””DR’¦.™Á×¶WwÜq‡óçryßw<ð¢Ø’°w=äRä©èɾŒ‚ ÞøÕH…¼ý`„‹¸n î"¥Èd,‡-»ç w¼2 žw*«55Õ¢ºÚü«©æ¯ôÕ:0å R®ŠêšŒ8«kjD%3D+¯ïHç˜ Lo9zHŒ7ÃÓùNUTŠº†fÑÑ�‹1†S¼ïÑþnÑÜP'ª++¥­”H¥R¢¬¬ÌùsÞÊtdÑ|r‰�ó÷ˆù¹¸eâ¦9*ºÛ›E�,ËÊ éí‹ÉYÆ™{F[2O³¾ÓŠkd!´¼‹\Ö†Á¼N†Õ­ôýüí>^Çxž=öÁ$l¿CY¤oæ×ÂY2go*sy’•»EZƒSƒœú…}ÂÝLç#S·ç…K¦¯ë:¥ÏÉ­o,zê´É¾ç7m %�Ñ–³rQ^½…z]ÏS¢²ºN4·vX NÃËØÍ»fiã<IÚžO®ï*NÎÏ×yC?2=±y²„×#–KÌ&�wÜïä}@ü¶QÉf,66yÛvª]r›EYº*ó¶tPéŒ ˜ý£Ë/]'¸q#÷ZÇ.I¹Ô‡—ƒ_öÁóú)“&ßÿÆþè,™^³ Ã&f¥Ïo¿¸Ð˨í 3 ¾~ñì† ã+~çòŸ[ ¾vm\.¼íqÝ—.—ÞµÎKÎ=G”�x‚ó§ë·i˜Å ¾~ñBfšÜàëÖ™ôu3^7¯[Åê'ï·~ÿqå祷/&O™ïM/%ôðÞN²zËÛºt�'iw’×I»–%‰S×ÙG˜–¶~Bam™.fßÂÖÉ1—Ö#Ýwù‰«ƒB�› Üæò6Âè;òè#8›p]t€0¯kºÏ6˜…üˆ­yäC%ÏóÂÛPuÍÊ.[8ÖN+Ã@mŒÏ võÖS*�¬Ÿ¼òÇÚ„ë•æfÖs+m¬ÁYrÎ:žüÆú#N“å?¤Mä2…ëqöð<¥à1Ï—7žÐmˆê+}�³Á°ê7.›ºKÊ1.å’W[¥ÒM2æb, ¬‹‰Ë‘×-fô¡rè}xÜ\oùù°òáå—ë\ÈK3I_%�£+¾‡5³Îz醳r³ÍmÂ8òs–òv¶¹OyãA.KÓ–ç—÷k¶ó*o±û–p ì,““´‡i?É«�Õ5ÿ%¨¾Vß‹7 沇锵 9k®Çaç™<ª=Š·–Dzn94õÞ·pKÞžÉ<øsu¹@øZG¦069ô�¬ì8³$ó¼0ÎNB,�8zÌ㳄³×�ð#Î%\ÇT()wD¿–å7¤¿ “Ç9—€9ÏGœµ5.<!RòòàºÂnåu×ÖO„öÅ2.“Á²ÐãL?/{®oçù¶•çÊÛy_ܰƒ<Ú¸\d &™[˜ÂÖ©b¦ÉãÎyìb©#<.[yFÿfu#¬}ä²D\ÏÔ©<õ?¤Ý³êpzjŒ,ã2’^ÏTýýžx®]~¸@@öIí­~ýë_‹§žzÊ1úZ¶l ¾Œ"Û-ÞZÛ!¥‡/Ϩëî§Ö·¨ÞµŒ 9œàƒL=� äƒBcÇ“Æùtxk¸Ì뙃ɀ ÁŸKjÆ¥Pé;øµðx™Ž³ —'v¹Ò~pNÒÃWæV†êþÂËÅ�ç7Œ“¾®ë”>g¾læXn?ê×ÑJß»J”<6*îážVÃ@5X>åUu¢³Ÿ{ çéÊÉ®YÛ8!’¶9<Ÿ¼Ž«´Cùqýˆ]�X^,a³ÉãòHò‚> aÛèHÇ »øv+ü�ÄàU|�‰æ ËO× ¾Õ�ò.¤>Ü«¡gôÂË�×7Ûùhi¢ï6·I\¶ÅõÀ¥�º²ý^'n=×ë·´¡”6ž"që³éícÛ»Þoó¯¼óß(l݃7úçƒuØü­ÓS²rƒ¯°4£dÒ×ÍxÇ·/·øyôòþ�Ôà‹—µ.1VoY¤®'mwd+Y„qYü8u±÷ac‚\©ga} ëè‘oXÏ=uhúÆ‹ ~_^îž^†Ž‘ Üæò¶Àè;òè#8›p]T\¹2b–Øú‘G>”Ùòbe—5œ4ìªö¶®–^®<ƒ[î©$ƃkC¯,º¡ò¦ÿÆøÇ6[U¼¶�æ¦û-÷ÞQÑ\¥óŸªmsNót¸ÎèxìuÛ¦K¶8µÌö6QÝ“ox�NæÏI¯´-ζë|‹HÙ6Hï>ác÷ìz©S ¯c‘ùâu&n[•xÌÅÊ¢Àº™_Ë\(—ºe‹ÛvÞ+^þ\ß3¯›õ'i_%�ÑÆžLá߬Üls®O^Ù†�ËH _Ô²~UÛr³4½øay~y¿f;ï�Ù·Ò ûÙÕP‘z[3jÁnÿ>è{°÷ú{¾%ŸcpÙÃtÆZ†6Öaçù¹¸u? @àœMïmçÍà!í™!¯m­ÃŒEýŠNÏ®c±çy\FC_íixó2÷õØŸJ}Ûê¿'ó8š‹ Rò,—5–~fŠ‘q&.sžo<�ýÛ]Så᪼½T3¤ œÈ¡?l`R¬²ˆâþäi‡MäÒ�ô– ÒKJ½çI.—E¾ÐT�“VÝ—Wù5¯L͘˜Ž³ /ƒxånÆžñ‹s* qYí(¼LQx~Ã8éëºNésÙøõ‹ú”W*|ÏQò“bV.šç¨èéj�u5¢Ü�ßKG}ó‡ûá<ݸØ5‹ÞæÓæð|úõ4�‰P~\?,ò¨àáõ(:/ÙäI‹•ø+÷> yÛè Çò)[šW,l«öƾ™™8:c† û¥ËO× ®+eÕ­2˜ôÖçë§vaÏË�×7Ûù°ôãžS_ÚK‰îò�¯"�¾Ößï{O#ºD¼´Í5ÓÆSvƒ¯wž½…õUî¶�»ºîòÏ©Åþ²Ï_/–>ü¸xiù bu×J±a}—xðÚÒ÷˜†YÅ1øÚ,üo?N×ÕÝ%žö9ñjçr±®k�ذü^ŸÁž0øâºä0J0ÖɽNæ®MqâÔuÄÞG„µe¹„SÎtÝÒ} ›á¡Ç›óìò6Wêb¡ÇM¼Nû.Fð؎˳�àlx»c¦ÎÕ¼Çþ+gýÈ#*õly±²‹ÇÇÕTÙ伨Òצ_0©Žóà#¯ü±>ÎRÆÙòh/ÎM÷[þý†÷ jôÑ®z¿­æ:“�¿Ÿ¥ŽrÙyœ:ËÈø/ßð:�Ì#3_Ì/M;Û¢Lö•�²wÏü˜á3_ìrC„×±È|q�ŠÕVå3æbeQ`]ŒÌo_|ë@®cQiF•Ÿ¾®ëO>}u”<Ñs¡LtÏD—[¨á×1Ky;ãÚP¯cÑiòüòþÐvžç.ç¾…²w7úíZu«\óló½wy[Úúž6ä¸AÕõ¶êT:Œ~yIEÏe约“f\x{fcvžŸ‹U÷µÙŽ´^›c5Ûy3®�öŒËkñdbÆáþŠN�± ÕÏó´ZíÛxºçùVUõ]ÜCMöpêªu`Ê]ÏÊ·ÓcÆ9 •ltX3µ‹újnüc+”ÐHÝ“|’ªi‘SÝÌOK•÷–:›ÔdÞ–q†ÇíMþ— ×J‰æžI™§>™àrxa‚Âö¶Tû‹•~ØR”µ'˜‘6_8ónp¿¹ž¦,ÛXzìÍ�ö_ƒ¼êQt^²É£ià([Àë@̶ѓŒ¿i_^ßålçè½%\ÑÐéÝ–õ;»Îd ê\Ôå§ë„¹à^-:»[ü‡HåõZ.^~ÙËXm磥‰¾c|xP¼zÛ%~¿AçþTl xã²~qÃ.ºðWbg:?¶}bÐ#—g(ÅÃ-ùþý~|<ýG¾¾ ¾¶=Ŷ»ŒpFƺ•wgk›£Žv‰*©ÿî˜[sÈ%Mž_®+¶ó:?�£l}KàÖПÒ+ˆ—‡2éͰ·£.�Ÿ”hKÛiêmnå D}=ºoH{ñrÙÃtÊàÂÛ3ÎÚã¯" ;Ÿ´î{BF|sæyHÜžqy jðż-rf–üe�ç…qvâIØæñøb×KÒ§—ƒ ŸX?³‹d½š�yÒu¬¶Þd32ʈ—‡EW’ö*­ð:Ãt‡×uC¸Ž3yc¯§0Y-|¸îxí5Ïw¬5jƒAÈÞfÄ|^‘D?JQ§Š™&/Þ†{¤õuÖgsýa:�„§—Žý;Bß,²øñ±ëž.}e>úRWÃtß‘%=5ÆŒ·ŸGÛA¾ã[¼8  ”@Rƒ¯ûî»O¬X±B¬^½ZtKG<”4ÿIHš^t8n¤Õ(և؟±[´7ê퟿I&µCE/k-AÆQ`ØÛ 'x_{­Ö‡êVív;Œ}0¬í·]÷“/t%.w›�Þy>Q”ú¦Â£=ÍÚ(ƒMBó‘‰3òtÛI}Gñ××õBAwS•/§Õƒ_¿~kšÊjümp¢ä1&ÅŒ�’ux°_ôÛ*uE~úZ}ªð<0°v,—‘Žeò­ó¿ÍáùÔõÔ•Çë—I^õˆåÓ’—lò¸R%ù?f�GÛèK'9Uúík�h¨õ¶gI õ²~ð_g‚1dþÖå§ë„º‹×Ó²2ÏøXm£u–—ƒ_ö2¬í|fêñÏ(ƒ¯ñ��ˆ%7ù}õ}Ë3 ›‚F`kî7Âðm í<¿ÇÛÒ‘ŸûÅ !ÆUÛžcX—ˆei�bA2.‹g,ÆãÎ~�y“_~}áÏC Ð^½írÖÞ=çäõ½Ýa=»Y6ÑeÊê-kŸ´~Åowd+Y„qYü8y2 ­Ò˜øxÇÛæ9Ÿ¾…§Y×éúàQX¸·/σ‡+BqÇȼüƒ}€©)æ/k¸<úˆ|¸šÒ…ýŠ©yäC¥n”s‡éIÉÊ."œŠ·»I�Ë«|¯Ne5ÊccŒO^ùcmB�ûrÍÍì·tΤGß{�4œ÷û0Ó*]âåÃû?-Ë?k½ëù†÷â ûÖ|Ìüz÷ö¶hC"eðRÕ,Ý ±Oq¹$l«òs±²(°.&.Göà�äü:ÌÓZ[�žkr‹J3ªüõu]ô¹ø}u”<Æ%¤.0Õ F—›ñ°Ô+[cŽZ)ÂÞ=äFÚÊ›òžØÒ±ðëLlk5éQßA‘'I¯~Þ¸°¦¡Î?®jî1X'.C®Çsèù„uß�Ôþƒë0¯/‰Û3fPGòA¼gDÇ%”´å© QYY)êÒí(—#ôE²~6Çç̶¸k¡œ•„Ñu‡—¹?®Ë«îp2™Ç‰ËAå¦S¿TÁËV§ÂòkÔg}‡í(.s>?޳ÎÍóŸªÉ4´VeÖTU!Ê¥.UVÕ‰.55ãå[à~Bñສ¹æÆ²`ãL™G¯�R}a،Զ֜TÏùœ-ÞµM‹¼óÉÛ¸$úÁÃì©5Ìb¦®�[®¯¬Ïæu„µ§\Μë›NÊrÄêKË¿Ù"KØu¿Í-”þ‡´{¼ÝôÓs„I®§¹Ô9ÙpaýƧˆ˜’Ú[Mbƒ¯1ñâRÏHk©Ø`ñÞµéÅ„g°uûÝO‰�uxåQ}ÏOHó/óã…7Ïæö+jÀêÄba0™›ØæÄ2l ›K<Ü8B>Ã\‹Þ–ôƒ«”¨e ÍÆÀ4`$Ä�llì–ô6ˆ©ŠZÑíϳóìjÔ6ï |bÈoúº;EGG‡èèì]¬µá2õ#¸Ì;,Z|—ûä<œmpfý¶ØÌófÜÞ+žÌ`%N™ð…¹€”Tõ¤ØƒweœâaçeÉ�d|i¥ð°|"R¬²öÓÎrÀ�ûøv�~ɤÂϳi˜ÊÞ˜ý€óâ†s*¿¦dx|LÇù„/�ºÈcÏ<æéIWÐ![qŽÆbz2Eqˆâ¯¯³…i\¥¢ë-µxžu8ùà�=0�’ǘ{å"�9«vuÝk½Ñç]/g{Êà+N»“¨NfÕ!’Æ©ëˆÒs$7I¹pêµéR?š¼Ág} O“×-¾€­úUþ²˜ã&^§ùX-¹1v ö‰ûˆ<¸f“7©~$·ÆVÎJNƒy`>”-œ“Go[C¦—ªíŠ3—pâ‘ÿ%Ï_~}¹—~طΠßb7«ù‰;¶ó –Ý6œ×'e\¿gÆÁ1›Y¾†L~?oüè_Ë~ ù„|©ÐÁ±G=78,*™6{i&çù<“Äœ�cqËÙ¨o�qe6Ú<\¬räã|Ù¯d%É2ð‚˺ËãŽJ3ªüõu]ô9•Vp¶Ÿû�Ë©¹%ÕeÎRn†A„ 'ÙÕdÌQ¥wš”ÓsÔ¤†22³¼\x—´oÑüìGÜS°jãÕŸi˜Þ/ꌼª{R¢%ðR —=VÚÖ2-çÕ}{ö�+¦ëùh>í<7º 3¨hM¯;*î•M®á,—£¢±Ë�Qýh«ÕžÅ•J§¶%�çY8'oóò©;Y5Oµ_árëvÍ ð+)ó¤ëX2ÿ©tUmNÆK¥}ÞÚ¸ª£U¢[½_UÄ~BÑສë=g™9vñ)jœY‚¾�·wqרýü[·qIô£uªˆi†ë£­¯³:nk“ðÔIYŽXÝðÚn~§MïvÝŸKJÿC^ÀæzÎÇ$JœÄz1FÊg¼Ã×pã­z€ñ   ‡ ¾†ß/¿ø¢kT#¾ÜñŒ¸ãvÏàëvñp»:ç>8|ñűaGÚlhµ¸›ÝwûÝÍ¢cõ±m`‡xkƒxñ‰¥ÚØKÞ×øÌú ­€ÁW2_BúÉÒÛªIk…hîèƒr[‘Ñá~ÑÕÖÈ fÔ›Åú-C>0u¶±éé=]Ý¢_NzGåÖ�Þb–ú®¨m=ýÒK˜Œ·¿·K4ÖxÞQTšÕ¢ÇwD’}p>ÜÕÀâ-õ-¢WÆ;<,½…õËÓ-uì�@ŠMÐE�ÿ0¥LxÛ¼e(Rȉ®&«Ü®§½§ßI¯¯»]ÔUš'T^«õ6Z!ѧôdˆ/',¹¢�›¤aOc»è—\†ûDG3碘» �¾×¢«u­¬Rn«Ò«ò9(º;š�xÕuâ#sS¬²6@Y~(/n^Ü<9y”y–ùîënÕ)/¯ò»²Ùð ÎÞ’Pàt6Ýç×ô‚ �€é¸ñ`(a¹ó¨-ÇÆ–9T&ê[»Ýìë;§"�›˜¨}ãÅ__7åÑÛIySÕ²>ö9å­ô¼½Q{,TzѤcq?LcÁÕ/^Vra¾ºAn×Õ+=ªz5(úz:Œ6@/Üóm%匦Ñ×Û#º{ÕR1‹3lBÞ‘O›Ãõ/Ø.k¦¼½‘u8q=ŠÎ —‡·ŠC’69Q�WÛ¨+•é Ï­/5m�'1¼|¥æ®3:Û‘.?^'ÔÝÚs@YºŸ vòràúo;ïÉ0èo;#û…àÖtÞM–oÏàk|ûJq˹^û’þ>÷rñ‹{îË–¿ Vw¾ žø.qã—.0ÚseÐõüÆË7ÜrÚþs¯Ïw­;·m;7®÷|�n�x£Ø’63·–Ôa¶t>.ný’·•£–ñê;]�ZÅóðÅ=ŠI#¸;ÛT¶¬Ëî»…�c<™¾&^Ú²UÓà+i»“¨NZtÆ;�4N]GÒÜÊõ˜m¸¿[4T¥˜Ži�ª%í[xš¼n©·f›ªØQ>x­E1ÇM¼N›m®G7ü›‡ öÉûˆä\Ã¥tÏ&Õ�äù°=lsåÉÆÎ®^ƒc?©»eµ¾®xwåò�<ùôåÙ%Óùö[f8¾¥‹7®7ëSr]âåcÆéÉ�mÌ&G+EôX¢ù˜ã2O2÷{P4Vz}�ú–F ¾ÏbrI8ÇËkÌU<]L^ަ~¤ª¥¼Z{�säö¦Œ927ŠJ3ªüõu]’öÕJ—¢ä1æ(þ\ÈÔÆð_Ñånð¥¼Ôê—ùHÎQëšåÚŽôäÞÓÕ*j˜÷?çeC¦è4y~yÈÏóþnÓʤëLáTŒ³†ñ‰[Ÿë–$íÜÀHÎ!Âú.»­=kð¹i½±ñ·�O>N1rúCëu°ÝKÞž�v›kB•õ-ÎÚc¿³Ö¡=irÓ{\J4´Ë—BÕš¢ Ó\ñ·MdzgžÇ |ã1‡‹Ï².ÀËœëqòºZ,ìdòrà²ÆÒO–zæ!c‡yâu,9~ç}nY•hé”ëãÒ«›jó+ý5e9ϯó¶m/^?¡x„×3Ms½‰S,Ð8³$}{ò5jN ì8y—D?JQ§Š—f¸>jÊúz}�š/Ç®o:­ð#Öf„µ«Öö8»î·¹yê?÷f¬«¼Ýäc’½ÿ¹š|Þ|ï ¼@p@@&,�)oð5¼þ)Ã0Ë3²}?±vÈ/ì�®'r {÷¡À¼4ücèipÑ�EbXô× ý.š9˜ÔçÓa­á2¯ûƒI–lÖC9õß(•ÙŒ´³f‡»EMŠ/$[Ž+Ì4xújQ*ýW›^¼ên6·¡ð®¿:¹ä<å„ ™½¡Œ‹ÿ®¨ï`™äb6ñ`wXy²|ê´*Ess­Ÿï|.ÛIrodÆ¢HÂ2 {`âÉ£¾+ë›E�¿˜.³ô6t½­™yàaùqPW‹SÖÖ1.t6òE<­‡\^*«é�–ü°VöþY²è>Ÿ°eêGgê¢1IJXî~ÔÖƒàÒNŽ~Ë7ùÄ-¡LQ¢øëv9 Ï`§ÞZ/´>ºy«j2ßÔ�’G=äÐq�æp·çy"3uÍô8ÆóçëbY�lC£Ú8Yˆù´9YtS3Íìë’Õ£è¼pîf»aòÎpR`Õåd}@>m£…å×ѽOòæ¤:£Ó ?Òå§õÓ»s°“?¤Ê|Ë——o—lçu¼zk³ü¼;ìß¾Á—2ºÚÞ%î 1¬òëF°.Ÿ{�x)`쥌¯^ª …Ùëå�Ï®ÓÆbÜ£V0-ç÷åâÁûnÌèÇï\¾AD{øÒ2EméøümÀ¶,"/WÖÝ+n½0�¿/Ü%[�쟨2µµuÉÛ�­ ÇeÙò‘¬žë:àR憗%J¾…·õ¼n9¹3¶Ù“Æòµzk˜b�›xùǪ³Yú•—d}Dr®?ëÉôCE—4YË9 »¬áÒùãe¦ÚÄÊFsÛ>+†� ÉòÇú6Ë|’ËG¯t�Ìì·Lñù¶%nýͨO ë(—=#δ¼œü~ɳ©¦A÷ƒááÍñŒ1†63™ñKóÉ—7�öˆö�Ùñ`èuEä¢dHÒV%sOó)Çžó…_GBú¾…oTš\ïÂtKë«?y̢䱎 e û]nÆÃhg"æ¨)¹uš¯ûŒCó)ž_£Ý²¶Ù›Š0žñxi^®·Bž÷žþöôZLzk[Cæt47¼×�aö¦~Ø–SIÊÝ“*Ë÷h¯h¬›hVˆ&ùÖbk�w­ÚX¼rcŒ/çÆ×Ðý®`; ¶ôò ùLC*Gžáé%лîé¸û]V^-Zº¸i:Ì &n¹ ÷¶‹ÚJ��™žÒ±ÊšÑÌ‚lû�7ÓU}rêZ.mœ\ŸÌ£Í±é¦f*·‹Êhoä²wìz�—á®F¿]¬hàÞói““õù´�^Íâ[²h�nÞUý�HgtðУ®OçÃÚ ¹èŸ~ –b[™zÙê#?V/†Y½1ËÏ‹Ùþýžô~án³¨�œÖ={ˆ'/]§–|þqÏÃ/ˆ�iÏ\Áð«ïùZZŸ.O¯Y)–^{‰¯_þB·ô öàrf앎kgW³¸:èiLÖË%_ºQ,[¯d\'�Ò˜‡0yí/(ƒ¯ŸûiÜ)ezõÎËõui f¿.· d_ãCÄãu^~4¢sÄ-÷<åijíÙŸ›ýõ§:ã¥U¦Êó”öcêRòv'I�äR‡Ç�S/0“¨oëM†7Ù4ã² ÑØÞ– jxc÷-QíêpW+Ã2æ™G®'aŒlosóÌÏÚúïžø}D:d®^šöïøúáÅ•$QcF»(ýpeêeÆ<)cûOOæ8ßñó—O_ž]²ìý–vPÎOt;.ëpÈ8%I�n¥Ö1›z¥å •)K›jæ0ó—æ>.3Bôµޤʪ[õåu,:_:ú$mU²1Wñt1:¿ö¾Qy�ìxötµZzöô·%•¶ oèZwÂÆÝFûc.”´¯Î��և̣èrSuÌ[ó"c-MƦæ¨r^§·mUýµœÃKñÒß8[Ãác–è4³õ‡¶6[�‘â¯3e ;ÓQϼÆK�Q³Õþvc&¬½I\†6þ¶óé įûa97ÏEõ§IÚy/…îÖQ¶&$×›ÜE;ïVç{´¯]®Uò1xúXzïèï-Õ)·_’/:[÷¥CÇžçY9ç§ÇÉêŽ�Àþ£(ýJ¶vÖ.Šº›¹]üu,'è ô \Íê¬ZËIÿUÖ6 ßѦŸNþýDX�WÑ}I½ _oò…Jjœ™t­9?=Ïg�:H"ø;q[?dÊ¥¨Sy¦Y°±‹µ L—HžÁÂôGè[”,ì9›ùŒ.©þ«²Ï^Wíc7Sñõ4‚�m’ñ‹W=W³= õË   0± ÊàkšÂ '±??¼g—æ{sb‡Ý«ŒŽÐàΧñ3hö¬¹´ß¾s³ŠøË_þÒ¹^Y)—’ðIN`lˆ6mê§1ÃÌ™´Ï>ûÓ‚óif¶Gh`lÑè(ÍÚg?š?7óî¡�MÔß/c•·Íœ¹íЂÐû²%vmdhˆwì á±1'Þ}öß�Ì·éÊýûùÑÕO•Sû`3�5?,Æìç6½Ióö£Y£Ã4sÿ÷ɴ̼Ž� ÑˆÌæÌ¹ó)CöÈmW–É›}ôß~³$›™ô¾CÊpŒ††Fœ2ž?7Èk„6½Ù+u`–d:S–ÕBYV6á2Ï«¬3SÊ<324@ý;†iLêƒÌ´PÊnQf |Îä û‰£ORî9$6"ëb¯¬‹³fͤ™²~/<4FE(’L9ˆ~ËØ ôÓà°,ïQYâû/?á±ÚÏÊô†iǰÒ1Õ>îCû-X�¥®�ÑÀÖAÙ.ªæq–¼7¢- I9q›“‡nî¹z”›¯�€%—ämã=tÍiô7?[é””Ü2”.>2¢�‰­3!J0AO‰ÝÃ$FÝqiFTÝݾ�†eÝuZë}æÒþ’¬½–ýî¦�í²Nªf`.}`Ñ!òûg`óFÙ�Ï—ýøÍÜï�=Ó�ÛÅ‘:¹�ÞÜ:"ûë™n}È�ÖþZ1¢:—-­¯%nwdü±ëd2åçÊÛþžNþÚ=NŒr[-úæi²“ú±µ?=N”cÔÌñPˆ{¸o)å¸)#÷9ô‰ûˆ"qÍU?‚yMœ�`DÞïØy·òï±7¢Ó>ø7äô,•Í4z{y  àwç~\ðüåžtñï,Š.å?f+~Æ#R( �fì¶*¯1—Nw¯9’|·öõûë½ïÐ,s€âK�O_]|é’¤0F#Îò„ÐÍœ›n·Ò�Î}÷)_y= 6•bÌ\³ Ñf'í[²':1¯Æ®û…ÈfíÙÐÀVÚ1(çëR‹öÙï :tA¶™�šn¥þ÷ûÙ“2Æ[ðCø ˆu'�r(p&Ýè’2OºŽ%ÃmíÓëÍ‘í¾”oÏöÑc—‚�3KÒ·ç·F¥‹‰Û¸¸ú¡)E�*EšQÐî'áO1Ï%Öÿˆº1&QYJ¬§<0Þ‰„Ë  S–@R{«¥K—ÒâÅ‹iß}÷¥éÓ§ ¾¨ ¾@›bAÆ6É*�TÊj¨·óZ8Åò�ì‚€ÀÞD`¢µÉ#«î¢}Ž¿ÂEXÞ :]^¸‡N{SÁJñ½÷îŽBņx¦Ï éÒ` ;Óà«_|-°ßŒ+ °W¢{ÿ~?ºÌµS$ù&=]^V0s†½"‡@lÞ|æ.ºõ¿Úé¥Övºàç­ô�s5nY)ÇÞ'§ÇÞ©zêò«„žÝ@„S”êÎ-øØÙÆ8362I_%T|•þ„Hz„îÿû}èsò�Jª¾ƒžüêiBj  ““ÀDj“ÇhÓò¥tÙÇ.£§Ò…!·\ ¯â¡|¤j*_ÊÓ>ùpŒ½¤Ñ>v0ø²³Á•½�ÀØÐ&zð¦Ëès7?å C⽯� €@Q ¼ùÐ5ôÁ¿ùY:� jéú)ý¯ãu¼{m]õÿè[Ç_@i{Xªjê¦[/>¦¨ò r˜(Pw&JI•NNŒ3KÇ)ƒ€€€L|0ø*aÂà«„ð'HÒo®¢�ïvìqthv¯î$G@&.�½¿M6߈õH—Õ´Òò>Y�-·¼8'ó·�['ŠÝr�|’˜6�¦ÍÙ—¦í�­“ ¸÷„‚Á×ÞS�ÄNÀðéß–¢–ÞÇé¯ÎôÏà@&?�Mô£“?@ßuwKOg·ŒÊä&·æ)xhŸüº€Æ#€º�×Ô¹ãÌ©SÖÈ)€€€€@ñÀà«xl#c†ÁW$"Ü   �3�ú÷“¢«Ù§òšfj¼¡[9æÌ0}ã{ã$ÆG‰Æå·ÜêŸhÓ”7/ù7mæl"iô…O4�åÿ~>}ìê§œkÛûé;gaã§hj¸cOZþï´ßÇ®fÉ–SsW#•‡­‚L#oÒ]ÕWÑ?{(4ǵMTû­‹ ö°¡xpr*@ݙʥoÍ;Æ™V4¸    9€ÁWΨ # ¾ Ï1‚€€ÀT&p[ÿ®@IDAT°uíJZ»u'ÑìÙ´pÑb:òP<�ŸÊú€¼ïÝF¶®¥—Ön•BΦc>z¼¹îÝÅ5u¥ÙJ+_[K;wKM=p!->îHO]m@ÎAÒƆ¶RÏÆ ôÎè<š7º�¶Ó¾tÌâãéÐùð|%�lPw²Ñ™‚×0Μ‚…Ž,ƒ€€€š ¾ M4F|0øŠ ·‚€€€€€€€€€€€€€€€€ ¾J¨0ø*!|$                 � ¾JXh0ø*!|$                 � ¾JXh0ø*!|$                 �À^cðUý…Y_~"ÿú׿v"øÇüÇü"Bh�)Aàæ{G�|~¯bN¬ü.]º”/^Lûî»/MŸ>�¦ ù‰CúfÏâìŸ.|7I𠦩©É‘ÿsŸû܄΄Ø3~ñð<'!|íÞF*0ø2pà€€€€€€€€€€€€€€€€€@|E*æe|“.â�ÉG_%,S|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’� H_%,4|•>’˜T†6­£·W¯ þ5/Ñ;ë^¥÷FwOªü%ÎÌ´i4á1tб§8SFÓgÌL‚€€€€€€€€€€€”ž ¾JX0ø*!|$    0i¬~ðvêºÿ?iæì9´ß!ï£ù –FM3&MþòɈ‚†w¼C;¶õÑ®�ƒtè‰gÑÇ¿õï4cÎ>ùD‹°            %$ƒ¯‡ÁW á#i�IA`gßFzâ[ÐÇŸLŸ¸ä š1kÖ¤ÈW12ñzûS´ü‘è䨦£>ui1’@œ            {€ ¾öd[0ø²‘ÁyÈ�ÀÛ¯/§gðEúäWÑû�ùˆ 4N¯<ÿ=½f mÙ±›Fv©­gÓ‚C¤Eï{?�tÒñtê¢ù¹E> ïºïÿVÑ1^N'\rõ$̲           Sƒ ¾JXÎ0ø*!|$    0)d|�ÐÏ+/¥k—Ù³wÒg¯¢ßï“t¸ý–I{_“¶h‘1�)D_%,l|•>’˜ ¾~{Í¥tåÓD'ýõ¥ôí?;€z·� m {ë£W¼\ö;´ý{gÓ\ï÷ù†Á×)hd@@@@@@@@@@@`R€ÁW ‹_%„�¤A@@&�l_]ÿ3ºÿâê|¾ÛC7\^E?îV§Î¤¶g«éÌyúòÀÖ-´~Ë�5‡Øw½ï}Ñ‚93ô ÎѸÜ&rœfΙM3i7mØÐGïŽÏ¤ý:ˆß¶ïÀ–�´~ë»D³fÒ¼}÷³Ä%o¡Í›¶Ñ–�ïÒ(Í¡C>˜Ž>4|ËɱñÝ466ƒæ:2�Óæ ›iËv•†”÷à÷ËpÑæk0øò‹            0a Àà«„Eƒ¯ÂGÒ   “‚@Vƒ¯oÿ„î¿ôh#ŸC+ÿ‡ùâòÜ™Ô. ¾NU_ïn¤Ÿßôotí#=ƽêÇU?ü ýøÇP÷£tÈ%·Ñ?ÿèŸiîÃ5t½ô$æ|>üeÚ¶ô"š¿k#ýôº«ôùôeõuÑ×Ó=W�á{{ýùÿ¦Ë¾ñíuÌ»÷ôÏRÛ/¥3åÆf#ô+¹UåUÛÿ�–ýèCTÿ·5¤rÁ?çÉøÿKÆn.æÞ ƒ/N Ç            01 Àૄ僯ÂGÒ   “‚@\ƒ¯�ÿM‡ù72ïi_36Ò×ϾÊ7ž:éô%tþâ9ôä½zûǛ¾Uv€ÃË3ø Â;éêŸÐ²/M¯?ô3:å_\+0'.é`ìå—Ÿ¦6åU승ªÌ ºáé{èØkð£¹ô Ÿ&êí¤ß=í�-¡¶§ªèÌý½[FÈÛªÒ;C>‰.]Lô»Gü�*馻+eµ›|Áà˧‡˜°`ðU¢ƒÁW á#i�IA «ÁWpKGé}놿¿ÊßÒ±½½šfýþgtúMÊ@ëLºé?ÑEv »h×Vúùu•t­º´ä*Úvë'ÏYÜàëË×ÿ�j?sÍÝ5D´:oÔ7Ê:ïêÒc_ùôrû×è Î¥´Hyø¢%ÔÞ^E§Îñ¸ß~_0ø2yက€€€€€€€€€L50ø*a‰Ãà«„ð‘4€€€À¤ �ÕàëÛ?¡û/=:K>õ6‰'}ázZöÎÈr¯{É7ƲzøÊŒÂ“6à:yÓ£tà%jËF¢ŸHC³¯ Íž»ûúó:åì³ôÚŸ*èhg'H-+ ¾tø@@@@@@@@@@@¦,|•°èaðUBøH@@@`RÈÏà‹èõ–z:å{®®/__Cÿú™2ZàX lXI?ýM7]qÝgÒFWl»ÅPƒ¯qzñþèå…§ÓÅû -˜ãFôúÓKé”k”G¯3©MnÑxæœ-ôí3¾Fÿá”À™ôPóUô‹\ïb¯?ÿßtÊ7~ã\¹È0XƒÁפPXd@@@@@@@@@@@ @_€˜4 |%%‡p    àÈfðuž4˜z,«‡/Ç87¾Rq~�.Zò~ÚÑû"µÉ­ÕçÒÖSÇ9Ǿ·®0ƒ¯ñ�tÅW‘2íRŸ“N?‰ÚþŠ}özÚþ½3h®¼¶uÅÓ¢/»†]î½gÊ{ušDŸ–Û?~‰>âo÷˜ÝàkÅïn¦³ü"‘”kó/ÿ’¨HC>÷ýß*:æÂËé„K®¹ŠS            � ¾JXJ0ø*!|$    0)d3øúöþ’~ð‰C£óùîFúù­·Óµ¨mÍÏ¥W|•®­8ŸNZ0Û¹à|-ù*m»õ/ÉõË•3ÞO÷ýâ7ôņ§ÍHä¯ó¾pÝqÕ'i‘oÀE´ye]õƒ[éÒ†e^ ó>ûeú�k.¢�ÌóΨomðõ÷þ–®<ÎH™6?¿”ŽúÆïHmMùG¹5åL”Ãà‹ÁÀ!€€€€€€€€€€€LP0ø*aÁÁà«„ð‘4€€€À¤ �ið•<[c»†hóÀnZ°ÿlÜ9N :€æ¦·wŒëøn臆fîCsw ÓØ¼èp§í30Ð/͹fÓܱÝ4¶ïtè¼$‰Úb7ÏÃàËä�_            0 Àà«„¥ƒ¯ÂGÒ   “‚@! ¾&�ˆLÀà+.ƒ€€€€€€€€€€€À ƒ¯ ¾JIƒ€€L Ý�Ôö/—ÑÇ?sý±³'EžŠ•‰áÛ©ùßþ™—_IÇ]ü�b%ƒxA@@@@@@@@@@@ŠL_Eœ-z|e£ƒk    Mà½ñ1zî_¤íë^£…9‘~íÈûiúÌ™Ñ�§ÂBÐÎíoÓö-›hÓš.£Ôî£}ûàTÈ=ò           “’ ¾JX¬0ø*!|$    0iŒ¾;Hk~m~ñqzëÍI“¯Bfdö¾ûÓûOKч/ø"íäâBF�¸@@@@@@@@@@@@ö0|íaà<9|q8�ü ŒîÜAÃ}$¤ç/|$�iÓhÎþÑœ–‡Ó�@@@@@@@@@@@@`€ÁW _%„�¤A@@@ „x�úûSèÓ 4}Öì"¤€(A@@@@@@@@@@@¦:|•P`ðUBøH@@@Š@àͶfZñËïÓÉ_¼žŽúÔ¥EHQ‚€€€€€€€€€€€Lu0ø*¡Àà«„ð‘4€€€�ÀŽ�Ý´þ‰ûhëk/Ð)WÜ@+{ ø¡èCŸü-øðÉL Q�€€€€€€€€€€€Lu0ø*¡Àà«„ð‘4€€€À”' ¶_ãã$Þ“ãcôž:–ßê÷{cê[�“ßéó㣻i׎·id`+íÚ¾•FÞyÛùÜôÍž¿€Ž\ò:âì¿¢™û̧ñÝ#´éÅÇiÃ3Í4´y=íwćiî�‡Ðœñ¿Õñ̹óhÚŒ4}ú š6sM“ßÓgÌtÎM›>“¦Ï”ÇÎ9y]þž6}:Ñ´iS¾ì@@@@@@@@@@@¦2|•°ôaðUBøH@@@`ÒPÆYƒÖÐÀ¯Ð`ïZÞIc#ïÊ?ö-Ï�ïv ²ÔýÓ¤ñ”2¨R†TÓ¥ÁÕŒÙûÈ¿¹4cŽüs¾ùo÷xæù�¾>ÿð£èÀ£N�†\[y޾;Hï¬ïÒ2Ic0%Ã{£»hl—<Þ-åq¾w¹ÇÎuuÞýïIÃ4i„&ÿ#!͘5›¦Ïšë‹)ƒ1ïo†:ž#ÿ¤ÁÙ~ ¥\GŸHû/ZìäË*.€€€€€€€€€€€€L80ø*a‘Áà«„ð‘4€€€À¤!0üöfzã±{iãó�ÐüÃŽ”Þ´Žu¼hÍ=ðPíQKz×R†Q3¤¡”ò¨5>ï��J£0i4& Úv)ocïl£‘íÛüïÁÞ7#³…gü9õ©Ki¿3²�<€€€€€€€€€€€€À”'ƒ¯ª ¾JIƒ€€L ï¼ù:ý©îúПÿ}èüÏ:Þ­&EÆ ” e¶ñ¹ßÓš‡ï¢²ŠïÒû?zn�bF4            ¥"ƒ¯R‘—éÂà«„ð‘4€€€À¤ ðô Ÿ§cË¿L ÏøÔ¤ÈO±2±ãÍÕôü-WÒ§~ö˜ÜªrN±’A¼            {€ ¾öd[0ø²‘ÁyÈ�À�Þ#·+üM›>=·Sø® Ï4ÓûOMÑìùLa È:€€€€€€€€€€€L|0ø*aÂà«„ð‘4€€€€€€€€€€€€€€€€L@0ø*a¡Áà«„ð‘4€€€À¤$0cÑ éìkÆ4y0…?ï Aã‚hì½) Y�IJ_%,X|•>’˜T¦Kû®}¤µ×Lììh”ë{ÒèëÝ1×øË¸€            – ¾JXt0ø*!ü"&=²e ­X·M¦0‹Ž:õt:lnî‰mym­{g”hÞatê)GQŒ ¹'‚;'!�Z³lm“ª3뀣èôÛ+ó˜OÝ(x†F¶Ð²ëH"£CŽ=•Ž=µ­àŒ áÄÐï‚e·�•BÏK‘¦d¦Œ½æÏœFSÜ©WVíÝ{�¾òé0vÊZì¸           0I Àà+£`ߣ­=ëé�Q¹ÿÍôyô�£Ò>÷DœxoˆzÞØâЬtô¦0g¹|í¤—ÛþèrpôÇèô£¤±íkèùŽ7eü³è#g�GGì«äÙ.ïëpîS¿æ~ �}Â!ê0â3B¯µ=G›•ÕƒüÌ:ä#tÞ)G¸?öÀÿ;×-£?¾ñNÖ”fÍ;€?ìZtÔaÂêåÛËéüêg�<ýËcoÐ7O?0kþôÅ�tû9‹¨ú5uæzlÃCtºS¶ú�@(��˨|Ñ_�£u'ÜLo<ûÊUëBã+ÒÉäu£ðí|ùvZt~µñ ÿò=ûÍÓ Ÿb, � ¢ß…Élac)…žgKsËËíôê¶wå`ãp:ë¼Èíârçdg³¯4öY¿ŒžËaL±PŽ)>tôÄSdÏu¼«ÊÓ× 4úÚ?ÉûŒ�öÆò„L           Å'ƒ/Îx×VúÓ“ÏÐúÁñôÙ9tVy9-šÃoŠ>ÞðLJè�v¹7Îø]ô·g„�ådðÅt{F ÛÚL‹/¼Ù‰ß7(b÷¹ •:ûo¢HÓ­--tÐ —éLíacþ€O a;:‡nn¼…¾rÁ ¶öŠó•©ã˜4"~ŸcD\@/…¼;G|=ƒ¯\5«znOÓÒDZòõê"�#—±Ìl9æÚGZ}­¼ã+ôѫ٘&På?z„þûŸ 1¦£ß÷Púß?'*ûÁãôÒ5{§×ÀÝÒØëÿ³w'€QU÷À?!�‚€ b ʊТ_Š�¨+iÅ¥.E#Åê¥ÏÔZD)*ÐWÁ¶P¬¥Xª E*‹l! !�� äýï23çΖ™É2Iø¦Å™¹ë¹¿sÏ�‹÷óœújh¯ðüœW íY P€ (@ P€ (@ P€ (PË |á vþÖ™=r9�åá!N‡ø:s«ÞY‰ç6´÷H¾´+†/ÄÁçRà?o´ÓÏ뇙ÎòjëœW¿ÓÕÀWÖ²˜7¤‡–Åx!Ù†l!O™‘‹…wk'_h:j Ä2i:G¹#)Y-=PŽÑz Lê¢9èS eQA`à+$ÐHœçþ÷éç7N©_g[T·L૥ܳÅx¾~¿¢S¯ô¾§8¸{#þá×xüM÷=Åß7ìŽâB²õ^¸¿r)žÞ¤¾ü9Þ½·aþnj½{i½|5�—Ÿóªé �„ (@ P€ (@ P€ (@ ø`à '±~YvŸæ1ôú�(ûïGÈ/Õºç -ðµûóïàXM_2T[º Õ¦�òçëAè¼õEÛMž¨;˜jϵg˜ú{ VȰ€ƒüä¢*6É�f#�!Íd ãåñ0½¤°OT"ö¼îèÖé46­^�mûJ�]0jÌptôŸ&sn1à»øÊ^µWz+óSXT`IÆ ˜ð†ñ€6Y†`ËqÁf/AÁîƒ�R¢»­NïÛ„Õ_nCé)àÂËFá:[G¥ vé é|³½Êe´@û.]‘dë‹.†_rT”`Çæ<ìüþ ¬ÒBÖ‹F»ó/A¯~½Ð©µÁQQŒÂïŽèå‰ïÕÍ»‡/GÖ}º[öFË–-Ñ¢}ô0‰�šË�Žñ‡t´KIßlÿßÀ))~‹¸öèÚ3 }m]à+WᮿK¤þZÃ^Rˆ�›¶àûå8¥û…�‘4p0º(Ý�•í+Ä¡âõ˜2j‚1DàøÙX;y0*â›è{? °ß�ZÙw�ÐçŸ×=�|X›kÖ§ö1ö‚îõbGÁºÿbÓ–]8&v¢§Cï>—Êñy÷jå(+–ÞÖŽh[’ÞÖ|Ô…Ì)ÛW€"é+:ö$vsŸ+n»PÏ}íÛ‹r ʺMí˜Ô—¾=àèmk/)À¿Ø„]‡�ç‰ÔuçKzãÒ>¾ŽÃ�âÂB‘¶ê¿‡/)WÞV|ó]”–Ëi,Û³õÆi3þªB*#¬ö¢£ú9pÛÐÂ�;�—¿+Œfݺâ»÷BŸn�WÕ=x.+\‡�Öl�(¢¥´Ý.]ûcà D´,X„ †<¤¯à¼¶z®j{3Öå8Üõ¦�ëÚЩÅؼm'•V \6xag¶y_G”†ZÎàÏmóXvK�è× Ùi‹8tILžÃ5ÚËP¸ÿ¶ü} îš™«—nö²µ&M*úü¹ÆXϲ�Êìü}Ó¶ªÿFÝ�ÒZhcz!=ÿ¡üž\"mC®š(Ü´[ ¾G¹\t�v“„Ár͵^ùÕ …ßnBrQvYÿç¹\;Cn[~‚9ÁÞç(ÇëùÑWàkfî^L¾Ì_ˆ«ÿ˜|~þºqO1âŸ`åžÃºÚ±gÇ7ØžW€bó~ἄ®èß§/.ö¸_(Ý[ˆò»ùÀÈûð©V¸{^Á¶GÉïf+$öòüÝ ~»úqÊ9™¿Ë¸ÇI”ë¿cï&¬Z³ Gä Ó€Q¸¡�ówË�C»w`‹vc^Cµ{„.r Mê†ø 嚦ԌÜ7åm—û¦oêmG›×¾’ð9LtàßY¹÷NJ©ø‘ (@ P€ (@ P€ (@ 4¾$ðµ)'ßuè‡_õ#‰…(°_'ŠÖãƒÏwë'FË »ã¢Sßá[-4VÓÀ—ô6+¹²ä™¤3”àîù"EzPYhô ¢>WNÏñ Öcfj7eŠó£O»·Í1v:sb–ÞSìyH�OÖÃfÉÙ qçwé˜ Cü¯Ú®Ëø2‡§tîÂã½bÓ\ ¨eêS“³–!g²1SÞüt–R�ÄaáÒÑHc„8´Õá+ –cÊ�t¼í±]ç×”Ìxej*¬±¡2|<ëÜ–õ†s1¯÷”Œyxùɱp>rÝ47#3�ÀC– ¹9YrÓ|9ö­ÆCýÆø,CZÖlØò^5{2“º•°ž;ÿV†å³Gz–ßÒcAî+Hµ¹÷Ký-ÃŒž¹r›ÖóŽ÷+kéfLÞEfT`nr2�ÓÂcA›sý=öúš'.ɦ‹%°ç±daNÞexÛ²V!w²ñ¾,o9Oö_¶´lüí¥‰Ðò�ÎW º0–QŽ×–�ݹ�ú·Ø…xîK[L�i„å ´Qg¡œïÊ>$Å"õ�cÖwuu-=¯-ý&WÚµºOõ8Ì}•¬[‚{œ>çþ]ïiX¸vRÖMÁ¼/cì g+ó±ˆ×$;VÏ}c2}µ™ñ˜=;¯>”­çc�×V÷&ª«ƒïö&+‡|j½I°rñà­¸í!×EÖ]9?äþÕÚ¾õ¹a”S9ï]×%ë�}Ï(˜Ù-¥,Î�ÖóF½>;—p¾«×aQ ãZ¶ “¤Mé5©¾Þ¾w¨mÌr­tîUÞ…ȸ` Œ«Ip¿Yîß“d,[ÿ{|õp2²ŒË¹²aù˜’…ÍoLF�ÔWøí& ½DõžkAÐðÚ–ŸÀW°÷9Ö°|óø*”À—ò›hY(ÿz.Ú&?®O1ý_X™áÖ±|Çr‡ÞrÝ }»F¶üe¢¾ÜWH¥`Ð{&»'wv¼J §Iyï¹­ŽÀŸßTÊ+ì~]2½¥“Ò †t çš&…Û·|:ú¥+Wù½?¸Nü o+?b)3VÉpÑý]‡ãó÷A›ö½“kÓü@ P€ (@ P€ (@ P€ š¤_^Õjàë v®^Š�´! �„+R0ô’&ò]c˜È¾¼ è{‚38 sÓf¯Â/�ý£2�}®a•5Õr³s7#nV?Ü¥=OT_^�!éYhñ|Ü>T’hŽv­ƒL^(ûõüè÷Ÿç‚ò½øã`3{¨r¹´ÅÜ=²+ÙÆgcþooG¼dWšÇµCLTæ¦v‡Ù¹R2cÞTwÏ…cÊÀÛ\�“2´äÝz×Z˜Ÿš€)ú3\éag­ô°“èJ[ $/÷$ßeÆcíÁ™H”}ú;¦‚E{È|h›œ…õoOvõFe—ž¿±ôüåRXÃN)X¼~®“àŸñª�@àé�̹] ûä8CKyÈ� �Ñ»�¶´ÖKÐëÒK�>²à…ë‡ Û ¿¨á4{Þ|Ä'Ã}z†Ì‡ñ&ÃrNJ€3?§îϵ± …õ2CaVÜ-aÅv(Æ Érî™åLË^†—&s…ò´žˆ¦öå:ÎŒÅyxò:#å¯.\û“Í¥'ÃhÖâ¹oéíÈgÐÄ|qZ”¬~AB�Î^ØÒ°tóKÞÅÙÎX·h*F=ä¬Q%4§´K»Yb—eÚM’kóãú¡G r²ïq ¿‡I‹%tv�Ì ·½¸Uý}òUªUrÆBüõÉw/{eL›·sÆvó·y÷t� Bæâ͘z�3äÝ;‘zއÛÞÂ:µÞôÒ{´Ñ²Îs­çH5 Ê>­çGš„Œç(½XzUEH |}ôÆ<§ïÇ=¤cf¥tCÆgÆîSŸX‚¿=~̺P¾ûc<Ðo¬+\õª 9Ñ6Ò¾m>ZyT_1õŸà]Ë‘áo×Ý×Q¦¤{~�7Ÿº]ï].Jîq[•žÊ¦,Â;Ϥ˜=�Éòr }gúÝH“k‡öJ}þ"×Ð`_a]Ó”ÞÚ´ýe,ÈÅ“©Æ5Kû^¼f>l£�C‰Ë9 !ÞþæOœ¯ßm�pï�´uù¢(@ P€ (@ P€ (@ P€MY€�/¯Ú -ðUþÝ—Xþß½úVš_8c†÷D3m˜Hg/a|¥ÌX‹7R¶ãÛ]z¹’3eøÃ©î¡Š´!µÜ½(eHÏMS±2=Þ;ôbY/½´ÌÔ{iñB {‚ú€oFnîöÓ}�g JíÑÅÒ‹ &IðJz¡’à•óe·²¤Ç³É^=ž•IoKÝÍÞ–lK‘û¤ôôá FhJ™�ƒ Çyõ³oõ|üc{Küèân¸òÇÃôP€zLÎ ä!èÜÔ^®Ð™¯ž5ìã KØ%$ï Ie-Û�ÉÃ<{‹’a?eÛYúó\ç}‚ëôžš”0“‚¥G(§øãé¢3zâPƒîaC={?2W óÍw¯Vî�,‘°Å#lá¬c»ôPïì¡JzðÚ-=xy;*¤°g`ióP4g¬ó]îýiŸ�¯šžû2”Ü4é!i޾+g]*û­X'¡›QfïlÎà–”EqÎL`Ö2t˜ç‘ZÃX³×aœÖÅŸ�@Œ ´JÏvÍžíWI¤©R# �†µòð=a¯¤ ¡½¸6êÿƒ¯úP›3rÊ5@i¼Ú¦ÄrþÌ÷Ѳ[Wtë%†%zžÿÞû³œg¾Ž[Úã 2T®3Dè|…ßÞÂ:µÞä0œç¼zD–óß‚ ¿œÖë¿ïëzáòYxâïkqlùr\­ö$gÌ TiOÒƒÓ é5p�3›*½8…}-S�\!+÷pÇZ\ 7‚u|EG� ç8Ä ‚:Û˜*ëû³zl°eJ��S]=k¨Twh)ìß™¸Dâ<Ÿšžô~8Ýì™Í£'BßµüT_�¯W×îÇÄ>ÎÀ¬u[ö½«1áÒ›\Á­‡ßÚ‚Gw‘^¸Iï^ _ýŒôÖ:ç[WEé³ÐqÔÓúÔ¤)ïáëgŒžÁÊ%ðÕÖOà«FÛýZ¶›lÉ€û±­Lz S.“j ìÕµ‡ä˜•™Z)å:÷�ï#¦û%èqÙUÒ³cP�¯ð®i˜õÈ ¬=¶Ë�¥!Oî·Ì~(ME»üæš÷›×_¿áß;™»ã(@ P€ (@ P€ (@ P€h |yU®ÖªnHGG>|÷sÓ·!C9Þ|=Îן³)ÛˆDà+[z�™/! îfh¼ …6Ó5šcßr\Ð/]/µtø‘Àâ�^Y\ÓµÙêÃûd,Û�¯ü‰¾•ðÿ¡>àKÉš‡‡.»Ç++� FG#º²Û¿x™3ͬô9ò^Bj·ˆj8)9kr&²Hí±%C†×{ÒÇðz€tÎ3:®P…5¤5iÆRLN»�Z{Ø!á_q—}9ÓÐï.#^äîÉF­?wdjqÕpƒ;ô"5/=|%Ôz_²g� ”5¢†™Ü!)õ¡³¯@Œ~<–íº{ QÏ/wøNPŒjùÜ_7+£²Œ^ö2$4ó¤søEÙ½%h—-ÃZM”a­,õï? ²o¹ÔuºQ×Z¯-s´Ÿ|bä\”^å’Í™?»’}û`�ŠA\L,âÚµF¡ÒÃQhíEuõýÙW}”­“°å¨,cÛ$,ž?#;y…+}oÑ÷ÔMsÓ1ÒìáÐßq«eq�ûÒ{‘«W¼Û[Xǡ֛eˆ;å¸,Á%3DUk×…0¯ëJ¹]vz‘•öäy<5°õw~æd` 9ÖmJö iGîk¿Úk–µŒŠ­��êµÏwÈÙzŒÎkXØ¿35p‰Äyö>MkW»³\o}TDˆ“|¾R§ÿS.¿÷[?[ŠŒê=Å4ì-Ÿ ­ïÒü¿g Ï¤úÞ_V€ÿáë·�Æ]Ž—µ¥®þ=J–OÔ{Ô øª­íŽ˜þ¬ÌpŸçZJ¿’ÚH#€†>÷ã_›Œëzù¿†Vž nHǰ®iZ�ªy¹Î�k„{:àú½÷ÞÉ4­¦0œM P€ (@ P€ (@ P€ ±_^•§„µ¾øfU6—C9vz#'Äš[S¶‘À— )”Ð@3”)A§©fÐÉýÀVzE‘Þ R:�ôÓË‘ò`Û‚ò«Ñõ_p�;^À Žî´”ú€ÞvroͲ[2oê »Ý=_ûƒ#ÈžéÆË6Z'ÁçИÎ5’ÓÆcôðQ:lútó~¨ªîÏõÐR Hh½…í•Þ¼ŸGú æðkæÎÓ22!¥wÅx�‘Ò¿—�7\þIýß-"5°ç§7ÕN Eø›nÝqxßÜçŸôh´`=žKí¦oÈQ¼רÒõQæl2¼à'úð‚ÖÝ >ën›·œ~¬®Þ±Ü= ù¬ K±Õs\Sµ óÜwHïZ8{×’a‹f¦šÃPªC[*=YÎ)ËBshNKy%Û¥ôXçª3u]%H¡¿;ëÔub{±nÉû›ºmWÛ([ƒôî£ÍÞΜë$c|ÆhŒ1ö©6dé\Ëù®îÇßqû<Ç-á7”öÎq¨õæ§�ú<·këºðÜv pݰbÕ:äïÊÇ®¢c8räˆIœ‡<çõÆXÔç(íÉ#Ìaé1Q– ÉVuRÎoXzÊ›$AÚçÌ ­ô$5Mz’š£Òù;çþÍ0Âç›z^ø>w|£zÎ…ÔnjP—ê>}—ÕOx·çyØû4µ]ë«õè³&B›è+ðÜîÂß¾€!æ=Å–¿LÄe›a°>ixææÎ8qº¥X”âé ̉)XW¼dÌÇ@�¯ÚÚîÌU…˜<Ø£çG¹öÜÜå'ȱ3÷M¹£¯Š�r ��sŸÿÁ¾Î5Í,ƒ£¬ÿù× ¬û*ùwá˜ü—ÎëGžóâáq�p�² ×ïƒÚöC¹wòu›`ñá P€ (@ P€ (@ P€ (ÐøøòªC%¬ ðut÷çø÷ú"}íV C1zh‚²%‡ éø.v—I­záæÑý}öV³xñb}�Ûn»MY7Ì�ÊC1WDÖ¥J�"WÛ¤ k¶W†¹k�}˜~^?èƒø¹ÊlËCXeºkÙ0Ëçg5õŸŸEôÉÉ)²º= ·§óÎOé�Êõ�PÙX°ûp¯’,C‘å˜C‘Ù±z~&ÆLq†ÁÜKŸR�½ð·¸7Åæªcu®ò(õéá+ïÈ“®ÊÜ[T¼�B›o¤ø‘Pû"q/ïû“»—3e{–zu¯§†\ç�Ìö7ݽf >I°+Ù vA œ¨½Q©áŸž^»—!úΓ!úôéîíª_ן‘2=ìs_rÎBÓ¢»Ú¥ÔË�sZ=GüÔ—vxek^�áGÍ#u³êg]õø'-ÎÃs×uò’󜠮ã9Ï÷wµ½ø^Â9Uݶ«mÈLmÈÖÌŸ�q…�Ë;ßS&eã·�Ý [;whÁ9Ï×»ºŸI‹wÈq{÷ÒãóW}mØÇ4w{ ã8Ôýù­së¹½VzkL”�P­\ü�ÛÒcÞ¬[š=Dú8he’zÝÐÃié2,©Þ±�;8«/®«²~ �.[u]‹“2D l(k… ƒ:HÂ0ÒkÖ¤ødãºé7$â{Ïêy¡ž£î¥•kƒó:-áõœs/è“Ùnjp�W÷Y_çyØû4)\ë[ê1�SpóB |�}ÆÜ‘†_Œ¦÷ÎåÜ‹%˜åœð=_¿�!¡¾nÏ9Ó÷vgæJàë2�À—¬¢ QùÈØ›ðçmÎõ­ï©þÏfÞ‹$¹†øÒ¶ƵyßdzÐï¶,k|~³^#\ç†,ëj{jÛåÞ‰�/ŸâœH P€ (@ P€ (@ P€ @Ó`àË«>ƒ|�9„�ÞùDúx0^ †¢sôÈ(9ú«™ô´ù¿Û å½Ð¼=ú ü¢OŸAÛ‹Ð!¶™±�ü³Î_p`¹ôr’nör²xw.®ún.âGfêeÈX¼O^×E>+°-aýMwB�?¨ø²Vì�‡õáp8,Û�Š ò¨î½º¤d`öè.8yÒ² Ë—Sźõ)P:ƒ£l¾^ÿ%V}ð.²ß0†éSWR‡S÷çó¡¥-»s'z×,õà x„2f̆”^ݵõó))ýÐ[‘Ò_ ¸T_ª�Üð7ݺ³p¿)å’M,X©ÝÊ0+¹²ô^ƒ¬CvúôôÚuæË¦SŒt#Ví�ƒþ! W]XÖUÊRç¾e˜7 \=)�+µç=ËpƒêƒmKY,–Ž’æ"ÁlÃ)3ÌÞÜü¬«Ú¹Â0ÖÍy}S× ·½xmÔœ nÛ»>ØWð5¾\¹ ï.ËÆr½.Õ-Ihn÷Bhyžê^ê~ü·=oâ“Ò7å:÷UG™Z{s–*„ãP÷ç·Î}œÛuz]°cyF<Ò]W›8<†”Ë{¢í¹±ˆ�nƒ¨_aì£7>—�~øJ{r^ÜÁ õXCµU×õpRëÒ“ÞAéI¯lÍ,ô�¥—(Ãlwú— þ¡^û¼ÏQm¾�Q=çBj7kx/”sNÝg}�çaïÓ´w­ïQ�ATMÀE|¾~¿ªS‡vOa |�ÎÀë?M€=ÀOîI¹_¸c|Š>œwÐ=|Õ`»þ_Ž{v|�Ï?Z…·ß9Ÿy’¥à‹}‹pù¹Á éè^;økšc_Ž ~—kU[Z&7=/j‹ØX¹~ÄDaãkc‘>Sû±1ðʽ“óºã* ?P€ (@ P€ (@ P€ (@�¦'ÀÀ—W�ø:Y„e9Ÿ�.¯õýOH�a‡º†}¬�À—<šVÂ!“äâ¾yc²µ$EVI(&F+¯òÛòÖßtÿÇv)¤ô@IDATê×Ã_Y1{Õ^LÔR:!¾ª{@¯!8cíAÜ�8@VíîvnÅò7gbÊLgøË=l˜õ˜vË1i=Î(õýõª£õ¾–,½¯é¡'óA¨:Ü—ôTsP†‚ ¾ôÕןj§7üM¯Ö&ÈJV¿€^cŒ^ªRf¬Å);q�ôú¥½ÒfçbÎ8›kKyóÓ‘<ÅpV{þr- °‡¹b¯ƒ‚ |ã…d²5óº8÷KV#¹×}˜J¤-À‘9£0?=Æá(½~iÇ ³æ÷‘Å”í’e8½œ‰2|§z~)DZIìFšvþ!:Ÿò�Zo/ʶ}¶ e¾úÑ^VŒ­k–cfú×p�¶ êóÉëªmê~fÈuånוâ�§Ãv›Þ×!\ç¾¥BmojéÝŸ‡Ÿzs¯­}’ÀWº„Í^³ôs».¯ j™�Œ…›ßFJý‡Â],¥—>—�>W¹æx„9¬çwˆ¶j™”óÛ(P±„EmfX4¹ßÀwS/0kiÈ•ß9›GñÝâýIm_¡¾Ân758ç"qž‡½O“:oQ’’4aš m<Ç×ÐÆÞuÌ_�¯™2ðäˤë­^_‡A�¿7¯n8„‰½‚ÿÅ øª­í|YT»ölú|9~û£®á“¦,Áš§¯Ã)G•uᾺ¦í˜?I~¯�>I“3ãí©×™C»wðñ´ds¸Õ_~}Ü;…~+é. ?Q€ (@ P€ (@ P€ (@�F"ÀÀ—WEørã£w?Cióæhîµ¾6á4NŸVfÈrÚ„îW§b`§–®uß×¶+yæÂÑfƒ-/OŸhÁ‰\ N/å!½åaº¿éæjµð¦><öýp½ú�T÷€~ßòéè—n;’³–!gò0ŸµWT ªuk�0‰e%vÄulç1ÝØÄêRÍ0{í^ŒKlmÚËuLêC} Ûù !8ö-—ž1ŒÐ“»ç ¥þ$|±lw†ùìáÈŽ {ZKïîWõõ§Ú©Á ÓÝÛ®á'G2.½¡”L̲ ei‰“±tG†+#ð©=b©=©YJ “h“Âr§êCfªç—ϰXÙj^qŒ1ìi�œûJ`ù|ùþ0Ðþ÷,{Ýn7îFLÿVfx^3�µíå刊‹s_¿er ÀWmm×_àË^^†r mçûzm×›ð©VôŸý%óÆ¢Y��¯P¯Íß)�¯¹E¸Û3m©·jù¬Ã¢ºÚ^Ø÷NF=ñŸ (@ P€ (@ P€ (@ P ) 0ðåU»g°åÃw�L›ÑWßú?èä…ÑkißNb}NvkõìŽÔÔ�pǼÜkÔOàËú͹wkøEy€my˜îoºs+@Ia¾?Z DŸ‹ÙºyÜKúþä/â{ißS«}@¯†�$T±tÇBK HßjñÇH¶Ý&a¸dd-|“Sº¡`É4 ™`Äoüõ>¦>üvšú>&ÅRvèk˜15<æ|jÀÇ_`íãéÒc†t –œ–…—_šŒn{ns;ªvîЋµ)k Ã\×^‚¼o¾‡Ô<ν°'ºu ½;�usÓ1*Óˆ±h[Õ"9yè)š3Öz©½diˆÍáµuœ/Õ\ y¨ÓÓæ­Åœ±‰ÎUô÷5³Ò1:Ë,Cˆç¾eC¾¨=I©‹e¯�Þß<Æ'TÏ×p�êJòð{RÂH=Ìb Çù Ĩa)9÷½†D,‘ó¾—vÞk¯IXð9t+_#!¸ÑFÀ*„ö¢Óßgµ>ôú?*´듡�:kñW¶à@Ú+¤êÎ6õ¼†tmUÚ{ª´w#6§¾Âlo"Öq¨õ&…óìÝN+¯åü1‡,Ô"uv]PÉÙØ›3Ñâ­So‘`ªÓ–6«^缃­a—YuòužT¬CzÂ(,×/"ššñš½¶HB¸žq5ç\ßïê¹ã �XU�Q µ…ù;£m:\µ¬õrž eMö©«Ã^�“z ¾9Z·­n´õý½j+ð%ã�âÚ.?1ÂQrýûÏ·‹p­@Ö÷¿ÿc\–8[ä~á÷oÍÂÔÑÝôÉ–À×ËŸãÝ{• i-m×+ð%ªGG\…—·I®~?,¿[b_/i?7w¼Æèåkô+(ùǸê_²Ýp®ijàËû¾ÉŽ�§§É½Šëê!Aywõú}ÐzGU{ •o¡Ü;i 5½GÕ¶Á(@ P€ (@ P€ (@ P€h¨ |�<Œová´Ö —¼šK Û¶í–>ºŒ×…½úàÂh­Ï.½“.œß­7:ÅU—Sz k%�¯Ñ‘ |IbÀ 3™OýÊlËÃtÓMy779™zZ$+öæèÃè9çóîû_0kº—Q@û~@ïÀÇÓ®1‡ÒÖKÃÂUO`xŸNhé(GáÆ�0cô3D#±—…›ñ\JØ !~ÈCæŽR0cñcHØíbšã´½ß­n“Þ¤ô%äø¥÷--¿ãï˜ö-Ÿ&=�2-Þ4cé|Ü|E¢Ë÷cõ¢ç‘®÷peîN4¯’a µ‘è2|šs¸CmnZÖB(µÔ«¹¨¶„2< ¿À’3±êÕ_ Ã é?¤[7´“m«C…Ú²V wò ÷FƒüdíÑÌX)sÙLæùt]zcÊpÑ&Ë%g`Å«÷£oGy¬}º[—¿†QŒY´­,Ø|©€”s>FN16.çg¯x7õ½HºbÙ��Åü.ÕÜ2\Tuç¾¹É`ÞÔ�¶¼Þ Íp•^Oî�8öåH/ow¹&dÌ[�_¥ô…œrRä�xíáÑp=+/=„Í4{óˆ±#'#fçG²ïIX<ï ½$·¯Æ¬GîÂÆ Œäì2<¤V�áµW¡|ðnÑX”ž€‡œ™»ŒÙ˜þókÑó¢vh.½"–—îÄ;3D¦YÈd9×r‚:×öašôlèjmãg`þonFB»hìÿf5ž™îjïZqÕs?¼ö¦œ/²½ä`�C­7Ó-sÁ Üw�Qç%[ÿ‰Ÿ�zȼÆHØÁÙ£›,^9µ�(eõu]°ôÀ#ûÔÎÁ¥<ÒÖ¾YýLw^óÌKP0wï³°é½³©C«™ Váî+:àÚë¡Ð°Ë¬:ù*³×9+e³eaGîdx^Mœ¥ö÷®^}ÿž(~Êuº&í&lé‘®~ÏsM-ü}jçÞüÔLÑó>îß8uÊôZ |ɹôïߌÀO^1/Œr¿°4÷IŒìÛ 1r¿°sÃGxnÔ}Xhîá·¶àÅÑ]ôojà WOúyÆïf›îÝÐ>ªv¶ëøB9Þ¸=÷,3 4bÊ+˜1þZ$ÆK¯¤Ž•îÂ?^x¯Ç3búðï‡áxµ=|©çyð×´‚E“0ä!ó~DîV¼zŸüVÇÈï×V¼3ë×µÜY·“æåâ¹±Ú�bíß;iç[MïQ�åä;(@ P€ (@ P€ (@ P€hˆg}àëdÑWÈùüÛ ë&aè�š[ÍòÒÃ×2éáë¸,V�=|9‡ýRà FA­î¼{‘QÒËÃôÝ9wÃ5PYÏ2ÝyøÊzòà{…”U×õŽsUóÝ;âs¼B�µ¬_«@/ËÛ ñBÚ@dëš­ë[¾¥ÍÆî9ãÌã·cùôë‘.=gU÷J›±J†�Ó†„óÿÐRúêÁ¬T²ª+ƒ¾«gáò00=[Ÿè³swcœÍiX]ýÉãP?�/mˆ@çù¤î/Kz¥š,©6¿ë© WûY)Ÿ¾¬ Wwp&=BPú¬Š¬öâ·´®¾Ú»½p9®˜î 5¹öúà»w7¯ÅÌ Å«gÁ6&ËßlËtÏkf8í-¬ãp™ô ¥HÞ_$�¸{¡óÚļœž�/÷õÞ½ËMóÓ1rŠ»÷=÷ãÓø Ñû£t(ôIuöJï|ßɺɞëÚ²±;w¢~] «Ì�Îo³pê5I›4~ÞzÌkô¼d.Ô›º�¯ùR4Ñz�ïwÆ(VX.²j}ŸçZiÃß§r] óžÁÐòþgí¾dÛrýûÝÍ—ãéϼ÷c™ò3é-ëÿÆIœÑ|I{võ¤åœ&ï¿_Uˆ©ƒåw9ÌíªA2ïÀ—lv÷r í7Nz«î•†uÅsÑ·‚|iÅ ãÚ¬¶UŸÅ�… »!==Ë2Wû²Ü)ríx[Ÿnm{áÞ;ÕüÕRH~¡(@ P€ (@ P€ (@ P€ Là¬|9mÁ»Ÿä]-ݯJÅÀx_4ª›p ï£l+•~ÁZõ’¾ú×Ã�Žˆ‰71Þ�.Öfõ è5F %Ë�†9CÊCØIÒËŽöœÍ|hoäHÔé³åa¾çPjÊ|m¨½¢9èâM‹2¤7#Ü2;w¯„•œ Õ3ð犼EHH6zâr«è{� éIëEL{h¦w¸Ä&C9>òî;È2|™<òĺ%ó0ó¥,,÷‘û²%�Ç¿žŒqÃÝÁ‚ ì 1;^Çä(Æ’ì)˜0Ó#LaKÂyO Ý²ß`L¶6/C†×{ÒÀ‘)…«ñâÓ0ÓGA’Çgá©)÷bPÕO© ²yן]ÁéÅl‚ÎåyÞø 8}Õõ<Ã2¾í}OuŸ—ZÞªšÞ›ìû°äOZofÞa([JžÉú®Kt†ÝÜûs”¬CöãÄÍ=Mÿ$=…­úë¯Pò§;�!¦$Dµþ§yõv[ øµlÓ\t™i.cÃÂÍŸ Åì…Ì׊ûÖ-ÁŒg'à ¯p  “f<‡Çîn†͵íÒþ‡�8K6çWbÑ‹Ïã¡™ÆÃtuŸã³à7¤¢“3ìåšN{q­ì󃿶a/^‡yÏÏDÖž•¤mƆñ™`òãÐM=½}îÁ:±D5ž[MË”^òƶÀ�a'-X/AAwÖ¶z{“öêq8_ÚÓf`Õ/;à5éuím�kMZƆ¹ÆhÃmʹøÂ½C _ÆŒ•¤ 5sžù=dÛêÎo}»Åx!Ù†lÝ.ˤÇÅaÞ—g‰ü¾Wÿ{bÇé5ϸÄ�GnÑLØ,¿{á·›�]Ì£¨ïó\ÛmxûTÎ=ø²ó[-ÕÎp¾òÿž�>“èË¿.!¢ñ}¼8¬v[ÆåXù÷ñ褙ÞAª>2”ã”§qÚ ¯áw-“{­ÛŸ³ìãU)ÇDW9Bßnù¶Eh;äA}›Öm¹wcß¿Ê~�¿îyµÓ–±á¾'Äԇơ‡pTž .ð¥­ò5M[gßj<ûÀÌñøýÒîS¦ÿv2úw,âŒ;ñ�ò§Ý[$ç=QË÷NêùÞ=ªfÀ(@ P€ (@ P€ (@ P€h¨g}à+’³xñb}÷·Ýv[$‹qöíÛQ�ââR¸I^QQˆ‰iƒvíZÃ+ïâ!c¯¨@ù±c°Ë0IQQ1ˆi‡v­-Oú=ÖðÿÕ^VŒý¥DGG!Jöß©cðI– Y·TÖ… 5ª•£M»vhS]éý—%à{ÊNËŽ*+gÙ�sXÇäìU2 Ñ»YÀmyÍt÷|¥ÍR‡bôZT�à°£¬¬ åv1¨ƒ6íƒò³—• ¬Ü.õ.u×Û…WwjQêú³½Bü�I™åœ“#EûN� �œîŽåÜ/)qŸÃí:vDµ§N˜í%¬"JÝV”—ã˜];f­mÆ NÎïjËpgvïÛ/õ-í%JÚ‹†Põaµ·`�C |IÏl{¥wEíJPQR‚R1ЮOqí:Ê0²Õ·ï°ÊÐMfJûßWbG\\”\÷¢Ð±£ gYÇ�ŠŠ“2rs1UQ(+)G´t†YY-ÇàûúZ›eÖ†ˆ½¦ŸÙSœ:Ü©¥¼õø¥í&<—œçˆ®IÛªÍÚh!#mÇF�S››4¶%Ã8í/sÝ/ÄÆÆ¡}»8�và±[i7¥Ò^ä"¦ÿnÆùj¿ál×c7>¿Êµ§\®¡GO×ÐØXãA-Â)ùoNœ®ò¹ºß‰Á^Ó” ”ïƒ=J¬dݨ6róøñrØ+pRÊÒ¼eë ¯ñ5¹wRŠÆ� (@ P€ (@ P€ (@ P I0ðÁjdà+‚øÜu øxú5Ò3V2—æaêðN!oÏ^°Hz3zfóì(ä�q 4F?�¯Æx(‘-s–H/•Ìì¼zVŒlá¸÷zh&Y¯6Ñuøª‡²×÷.*UpH/_|Q€ (@ P€ (@ P€ (@ 4n¾"X |EŸ»®‘€£p .¨ ™‚U{¢ð”É:oZŠ #' ×,…s¨ÈŠ+S ± 0ðUãsTã_/NÀ]3Í«‰Çð‘5Þ7Ðh´¾´ž¾øò/ uìU^bï^þ7Ç9 (@ P€ (@ P€ (@ P€`à+‚ø |EŸ»®™€½»çÆ#±K» ·eí…ǹ’-s)>™:<ðYÎ…ùN�¦$ ¾RdHÇ…Æ�ŽMéëêX,=ºv’ŒÅyÿÄu�¬OºfóC“Ðú÷Š“^¾´Þ¾øòÐb^ZØë ó^Þ8œB P€ (@ P€ (@ P€ ¡_¬4¾"ˆÏ]G@  s“»#3Ͻë”Ì…˜75!uæ^�Ÿ(и*6!5a¤ÑÓ�-»s'"Øødã>ðš—¾bÓ\$ŒÌT6”‚…kç!%‘Wå¬û¨e½bšKO_ÍϺCxÀ•2„£]º÷bØ+ gR€ (@ P€ (@ P€ (@�F%ÀÀW«‹�¯âs×()Ì÷‡�ÑÑèÔ¹'ºtd8#"Á�6; 7mÅáJim»¢bÇR®FP ée0ï›oq\·ë„ž‰]mÕV_EÔ‚_ÍexGÉ~�Õ/mGíO{õ:«Ï<(@ P€ (@ P€ (@ P€MS€�¯Ö+_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐLàë7?kÞùjVä×_]ßÀ=÷ÜS³ qm P€ (@ P€ (@ P€ (@ P€ (@ Pà¬xþÍÓúqþöç-C:Þ·ß~½zõBë֭ѬY3œS%¯�¶`.ü¿?VÂÙWC[gÞ¼yz‘&L˜ÐЊÆòP€ (@ P€ (@ P€ (@ P€ (@ P€ P ܼ_µP™ |Õ"7A P€ (@ P€ (@ P€ (@ P€ (@�³H€�¯V6_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ P€ (@ P€ (@ P€ (@ P€ (ÐøŠ`¥1ðA|îš (@ P€ (@ P€ (@ P€ (@ P€�P€�¯V_Äç®)@ 4a�•'±¥è[lÛÿ6ËûÁòÒq´QÍ¢Ðû‚.èsÑ%HŠïŠn:5ˆr±¨N øh©´¥Ýz›ÚV¼Zk¯¶1­Ñ÷¢®úŸ~�»¢]l\C(Ë@ P€ (@ P€ (@ P€ (PÇ |Õ1p Í3ðH‡ó(@ P �ýG�àáwæàÀGкM´n×-cbÃÙT­¯sæÌi?z å?”áÔ©SH|-&^õ“Zß7H�Úø÷öõøýÞÂ9ç4C\Û¶Ò¦Ú¢yó¨ÚÜEØÛª”vT!í©üèQÄD·À 7ýRS†½A®H P€ (@ P€ (@ P€ (Ð(øŠ`51ðA|îš @øÝ‡ÿÀª]›qåOFã„„y”gNŸÆ?ú{ v`Áϧ {Ç‹d9Y( œr8ð“מ@›ŽqõOŠ11 åXi)V缇 [ÆémªA’…¢(@ P€ (@ P€ (@ P€¨5¾j�2ô 1ðº× (@�À�Hï^{OŸÀÈ[n1t`ïûKñÝþ“ˆë=.raà ÔÓÜÃÅÅøxÉbüñæûpÅ%?ª§½r7MàpÅQÜüçg1häHtïÓW_ùÌ¡­øêÝM@G.¿e¢CÛd�-½áÓOqpç.|0ñ™:Û7L P€ (@ P€ (@ P€ (Ð0øŠ`=0ðA|îš @ð|U ÷ú>xëS 1ûLþµZ‰ôá3ðéàþƒðø:¹q>~}…ªŠ)¥o¢k\0[ªûeøª{cî� (@ P€ (@ P€ (@ 4¾"X |EŸ»¦(ÐD|¾ÖÞÒHzñLø_M´êyXu à3ðµu!~=à·²·ã±Ò?#��¯:�ç&)@ P€ (@ P€ (@ P€  0ðH§Žç1ðUÇÀÜ<(@�³P V_Ž üð]1Ž=ŠÓˆE\§‹Ðñ¢¶�5í?àÀöÝ8q hÞÂX§­¬ÓÌÏZìáË '7(�Z |…ѦŽïÙ…ƒû�-¢Ñ"¶=Îír!ââ¢üú°‡/¿4œA P€ (@ P€ (@ P€ šœ_¬R¾"ˆÏ]S€h¢5 |X1¯�ÎF‘§Ïˆ0åo�¢ëEÞ�“¢÷ç"û–lÏ5äû8d{ñ1Þ³øò6ᔆ'P�¯�ÛTi>>zä¼·(ß äªÿû?ßÛkº6��/Ÿ,œH P€ (@ P€ (@ P€ š¤_¬V¾"ˆÏ]S€h¢5 |•¾ÿwšŒ¸×ô¾_ó. ¶×üósÜúÓÎι–w¾,üB P€ (@ P€ (@ P€ š´_¬^¾"ˆÏ]S€h¢a¾Ô ÉˆG‘¹x2âͤVéªùxjÔ3ºXbÖbLþí`C¯|+þÚþF|¥}“À2?*ë˜=€•Æ�À…=:Ëzü“�/~m�5 |…Ñ¦Šæe ûÁwu‹¿õ!n¼¥·9,ª廾:÷@œ�ó´øj�§ E P€ (@ P€ (@ P€ êD€�¯:a n£ |çÄ¥(@ P x�p_'·.įüVßÑøü�ÔÃ:tãŽÿýþ”eôÚõĉ§p¡Ì®n�@¥fà+�ç5�š¾ªkÞmª¹·ôÁ[ïËÑß÷*^~õ'fØ+8 ¾‚sâR (@ P€ (@ P€ (@ P )0ðÁZdà+‚øÜ5(@�&*nàë‡U³ðĨ�¾�âw'£­‡ÏÉ�»B „ýSJÿŒ®q@uëxlÂò•�/ ¿4P�š¾ªkÞmê{|8à*,“¡¼b-RG^’ _!qqa P€ (@ P€ (@ P€ (ШøŠ`õ1ðA|îš @7ðUúþðÔ-¯ŠJ&²+'Bò\–—»·¢ã1 |%È{ÿtþð耟þ/þøÏt´´¬ø _�}8·aÔ$ðr›ÂFÌk3¶È¡ßúßM¸f€gì2° _�}8— (@ P€ (@ P€ (@ 4%¾"X› |EŸ»¦(ÐD |•K_™Z_¸�›‰„+�ørõðµBz­­#!°cóXǺë7¾¬üÖ0jø ½M¹{øJzåCL˜Ð;$¾Bââ (@ P€ (@ P€ (@ P Q 0ðÁêcà+‚øÜ5(@�&*0ð DR¹u!  Ù(½ åJïBC¬½ íúãÏðRæ—2÷<}â1tŒÜ!0à¦Uëq}r}ý`þÁÀW0J\&ÒÕ¾CoSȽ¥Þz_ŽzÄÓÈþèn¯žöy0ðH‡ó(@ P€ (@ P€ (@ P€ @Ó`à+‚õÉÀWñ¹k P€MT Pà+ñ7/ãö»ûâô‰J¯£oÞ¶ ¹ÝSð‰>çÇx ÿ�¸´‡ú:°b.~7:[Ÿ“ôâ˜ð«¾Æúå[eºõ!耡¸wã+¸¬¯úª<´ ›þµ¶ñ#ÐÊXÚòO¾,üÒ@¾†b|nZ§½Ê�=£ðA›!µ©¢y÷!ûA&U^‰¿y÷<ñÄé=ç�Ä�Uâàù× ©¯5ŒéÜ5_N ¾S€ (@ P€ (@ P€ (@�¦/ÀÀWë˜�¯âs× š¨@ ÀW CŽÏ~¿ú_dŽ4‚]Ú²ñ#~ŒÖ‡ÿƒ‚­Î5ïÁǞ…ÊÐ�{çeà¾ë\è;IʰåÓ|}Úí·!¹¯$b<^ |y€ðkƒø TäÞ˜Rú!:~=7´6%!Ê¿Jˆò+eÓ‰?ŠŠ÷¿D‘6mÄñÇ�Æ¢¥2ßù‘�/§ß)@ P€ (@ P€ (@ P€ @Ó`à+‚uÌÀWñ¹k P€MT ÜÀ×àW>À�ú⇵ïá­Ic‹+äe@%Þ÷4nÿÃݸ0ÎÎ�oß|ÿøÅ«F E™�8.c_ºñíeüG�_ üÚ Â|ÝŒÇJg"AÚK¨mêÌ¡�ø`b&þó¾štà ÅMoeáÚ[z£™{¢ë_. ~ (@ P€ (@ P€ (@ P€M^€�¯V1_Äç®)@ 4QïÀWxzüÐT"Ñ;δ逸8ïЖeËŽ“(?Tûqš·ŠA«öÐ2Æÿ: |Yôø¥� ø |…[ÔPÛTeéa”)Çéè(DǶC›ó[û z9ËÃÀ—S‚ï (@ P€ (@ P€ (@ P é 0ðÁ:fà+‚øÜ5(@�&*P[�¯ºæaà«®…¹ýÚ¨ÍÀWm”'Ð6ø ¤Ãy (@ P€ (@ P€ (@ P i 0ðÁúdà+‚øÜ5(@�&*0åÝyÈÿá n¸cš5oÞ`�roAÖüûC̼u"&$6Ør²`g·@Ù‰r¤ÎÍÂ¥ƒ!iè°�‘»ìœ8P‚÷&<Ý ËÉÂQ€ (@ P€ (@ P€ (@ Ô\€�¯š†½¾Â¦ãŠ (àGàóÝÛ0-gÎmßçw錶:"¦U+?K×ïä3gÎàXi)ÊJ¡øÛïеŘ“ö+´ˆò?ôcý–�{£€·ÀÓÿú>)ØŒ Ðþ‚ Ðö¼hÞ@ÎÙÊ“'Qvø0ï—?Åøå•ÿƒ;¯¸Þû 8… (@ P€ (@ P€ (@ P I 0ðÁêdà+‚øÜ5(@�&,ðå·Ûñîæ5X÷ÝTžv4¸#íÔö<Œè™„Ÿºmc[7¸ò±@P´6ôÖ†ÕøxÇרu¨H�Õ >7;§úvKá'}ãù_ (@ P€ (@ P€ (@ P€M[€�¯Ö/_Äç®)@ œŽ3§QRþŽ�´7ˆ£�jÖ ZŸ‹scF�c ……hTÇO�Ä¡ò2œ:}ºA”;6º.ˆkÇ^òDm° (@ P€ (@ P€ (@ P þøª?k¯=1ðåE  (ÐÀf¯Î�CÂ-�Œ¼¹�•ŒÅ¡@ãøñìLÌùÙdôèxQã<–š (@ P€ (@ P€ (@ P â |E° øŠ >wM P€A é×úr«ùcPËs! PÀ¿@þ�½˜ð�—qÇÀkpÿÕ7ú_�s(@ P€ (@ P€ (@ P€ (@€�¯8u=‹�¯ºæö)@ P \�•'ñ_|ˆ¼â=h.C1vëÐ ¯ú âZƆ»I®G�³VÀ^y l]‹Å?ÃiGÿX¿ ‰çwÆØW³§¯³ö¬à�S€ (@ P€ (@ P€ (@�ðø ß®Æk2ðUcBn€ ‚8}æ *Ïœ–ᨔ!+µwù®¿Ë÷rûqìûá0ö•¾²h=¥ØcÜ ‘hvÎ9x{ãj¼·y�RéÒ¾#:·•?í: ]l¢›7—?QˆjÖ-´wý{sù®}n†sä|Q 1 híGûãÐÚ�ùÇõ]Ú�1MæK»:r¼‡ÊËPR~åýÀÑRì•v5²WÜrY²´�°;*±ò›¯ñÞ–58&m¯k‡ ѱu[tŒ;×õ~nL+½Mi�K­miíJ{o~Ž|—ÏÚôæ®ïlg�ùübÙ)@ P€ (@ P€ (@ P€ @¨ |…*V‹Ë3ðU‹˜Ü(@�³\@ i}¾kö”ÄQû ùS�$H¢…IÊOÚqºê´E´ÀH3´nƒÖ-ä�¼Çµˆ5Þ]Óbßö<\qñ�ôé*«Öë×ú=;õ}?uR¶{§ìÆÙG¹|>n¾kA²3�©’ ÄF·”žÁbÐ6¶5ÚHˆ¥­üÑ‚b—ué��'"&*ZÝ ?S ^´óyÛþ=غÿ[ gý`žË']çðqí|–óü¤„³ªäÍ$hå [ÅF·�ó¶b[´DŒ|ŽÕ?›Ó´ïÚt™¦�÷½.è¢ÿÑ‚‘¾^%G‘'åØ/�ËŽS8)½���?vùl¯¬”?ò]�.ßµ2�<])m¬ gªÎÈŸ*=x©—EÚ[kÙ+­�Ë»V­½Ÿ×¶N—ÈŸ‹e^K_Eá4 P€ (@ P€ (@ P€ (@�F"ÀÀW+Š�¯âs× šˆÀ! ªÌúä=Þ�+ºöFB»ŽèÒî|½÷­óZµAËèèÑÖ֫˜+>zßK°å{ ¨í<´_†Œüã‡\�Ÿ& mål"§#€@±ô¸µhÝ*¬Þµ}$•Ðþ|= u~\;\Ц-:´>WHiá)­w»ÆöÒÚÚI ˆ“ö¦õ2¦…Ù´P™öþý%zÈm`B"~6pzžߨ�å¥(@ P€ (@ P€ (@ P€¾"x0ðA|îš @8åp`›/#UÂR7÷¿²Q¦´ÀÚôaxÏ$Œ•áîø¢@] hAÃ_¿ûgŒpµÞn´¡H϶—6åÊ_cþ—+�1ò ¾¤×ÙFÀã¥(@ P€ (@ P€ (@ P€�^€�¯V!_Äç®)@ 4��ò7â?ßlÀó7ÝÛ¨�¦Hzüšô柰tÂSú°y�ú`Xø-ðÄoàò„ž¸¥ÿU ºœõQ¸íÅ{ð䲿âí{¦±ÝÕ8÷A P€ (@ P€ (@ P€ jQ€�¯ZÄ uS |…*Æå)@ P@È“ÀFUUú\t‰:¹Q~~o󤨣EÔÙ×ãR£¬°FZèóÖáÊî6œÓª‘Aí;gËŒºtb¢¢kwÃÜ(@ P€ (@ P€ (@ P€ @� 0ðU§¼�7ÎÀW`Î¥(@ P€ (@ P€ (@ P€ (@ P€ ¬ |Y=êõ_õÊÍ�Q€ (@ P€ (@ P€ (@ P€ (@ P Ñ 0ðÁ*dà+‚øÜ5(@�&&P%Çs§q²ê *Q…3ò§¡¾¢q¢Ð ­Îií3_ˆ„Àii#Ç«Nëí¥²A·˜Úщ’¶­·»fú{íl•[¡(@ P€ (@ P€ (@ P€ˆ„_‘P7÷ÉÀWñ¹k P€MH@ ®”UUêÁ•ÆvXqçD!Í[±YÞF.pR^Z›i¸±ÈºŽ“°eœÄ.ù¢(@ P€ (@ P€ (@ P€hœ |E°ÞøŠ ~ vm/ÊÇW»É¢ÑcðPÄÇÔ`cúªìÙ°ßUÈÛõÀФøšnð¬X¿öêÁŽü/¿Â¡JúŸ'N=ÈÃzØëL£=º¶úŠeè«ÑÖ_c+¸ó:RuªVÂ^ŽÒ½X¿u�D£Ë€+Ð9.X ;v®]�ç´ßžî¸<é¢`W¬µåΕv׊í®Ö<Ïö mù»Êäfªu<_ÞÆí1ï±ê÷¼àß)ê×»‘ïÍQŽ]ÛwàP…üµh�ø.>¿Æ±mä(áßQºk¶~'ˆÆ%†ââ ïÂß'׬K�¦ýû‰óµöþýMÝÕ»¿2ÚÉ¿Ì÷üw€ ýá=�ûL¡…Û¢ñ|*/Ú…{AîRÐBþ~aKºØüûEã9–”þjï7$¿éþ�‹s(P·þîÕêv¯Ü:(@�Æ!ÀÀ—W=�Æþ‚9uh‡®½/Ak¯eŒ Çö`Ïí¯Õ¼ül'øÀW)6¬\‹ƒÚ¿‹½À†k/¿¸š–Ëò¹Æòí1|höáP�X(³7̉�¢¯òüš#xlhûPV÷±l9fõkƒ‡·È¬¤—qdódÔt‹>vÒä&ÕZ=”‰‘m†áMˆþMî<9è¸ ãxôD!r?Ý.=|m/ŒË{WwqàÛµ¹(,“–èóqŵüþÖù5t”bçúMز}¾ÝQŒÒvY41çµG�ž½�Ø·?ú$% ¥ß ¸g4“�çŸÓ’ƒ;ºIø©ŽH@ò”ôðeyÙå|Þô֯݊]Å¥°ëç3Ð>¾laÐÐÁÇÃÛŠ ¯ ç )ú¦žX³©®í™{-ÿ/n=w8¾Ð¾&Í@þ¦ÑÖœU_oÚ`ªZ»ÓÚ_¨™€r/‹k°æØ* ÕÚK£ºÇrÿ}K{²ÔyØõH:?p/x{6¬Džü­Eƒùû–Rµ~Oëö©öï£å»°2·§Zhç@ ØF]‹‹™#ªY«åµE+qkçë�£l7éù5ØüØPe ?†"P¾aÚ |X_¥vþA({ç²µ.Ш~¿B?úHœ¯µöïoB?Ü ×ðWFŸÓü9R—÷A“6�iÑ@*"Èb8°ò·âºßXîRäï›�¿_¹.F�-P‹¿!‘øMoж,\“ðyOÖ¤�˜G P x¾T+û~|úþr|Sê0§Æàú;ïDw?ÿ‚zß§Å¿¾ÑpW÷ò½� _¡Þ†º|uÅç|‹@íßX”cÁMmp·öwÙÔ×pì½I2ÌRð¯ò=[°Qº‹ï}z4¹ÿ*»[¾ÜŠŠçã2Wo†M­ÕCù | ¬ÅÀ—ÿ2_«gÓ’ôªim–žŠÊ6Ìv…N.}~5VN½¢šÍ–ãÿúwÄ“ZÐñìè \Â…gg΋˜0f¶W³$Ý�EÿüFö¨~ãìå«:Lί ‡ôëU"mÆý*GîÜgpÛýrOòóéϼ�‡§ÞŽÎÊ}aÅ–?£gÿ_ékL_·¿¼<ØÀ×F | ‹hàK+tðí®ñ\«›ö}‘Ÿ“3â“•{Y¤bý±÷Œß”Z¿ÇªÃUÿþ¤í¦Ú{òÈ=<ôŽ+õPmùC´T}…ÉìùȈ½/¹6Ÿ‰�'žCåºéšÅ°cÉÄXÜ6ϺûŸÏߌ¿Ý•d�ÈoA ”o™ƒ6ýî×—yýLö~ è=pÁzh0¿_5¹ÿò¿n$Î×Zû÷7ux"ø+ã–9¿@¿ûÿ®ïÙÕ¾íð‹Ø�ЧÖöon­cÞÔJùêb#þÎù³Ñ¢.|ëg›Ž]‹Ý3Ýcg°ùÄ\$ñ~ÒÃ…_­@-ÞgDâ7½!ºûÿ;rC,-ËT�€¿úôw¯VÝö8Ÿ ÀÙ ÀÀ—YËósñÁê<8£^Æä8Üpç8\âó/•ØðÏùXWÌiÒ^¶s›×v‚|…ú/B]>˜Cà2.­«Üíû~�ï2|Ó¥½Ñ>ðüïZÏÿå_>\#�¯U¡¾ÈɈÆMòT¥)þWÙŽ¢Dw¾Iè”Þ"LÈÚ«éÞ=;~ІtlÛ½/òa½Ÿ Tf?«œÕ“éUóê?PuåJè䆗Ö`ÁäÕl¸o�éˆGôÿhòF¬8ºIÕg²ôm~ÿï'1(åeû}qÄ‘èßYÚΉRlúrþýÉVeþp,=°CÎW&ùøØZ†–k#CÌñE�º°KÏ^eÒ×þrìÅ+cñ;õ?Öf$ Ç¥[Žh?=Øn9—µ™¿ÂgÇ_@OóÞ0ìÀ—Üq~ŸŸ�£úoOgô¬áo�V²p^Á¶»Æs­nÚ÷EáÔqý¬£Ü˪�/9Ïkó«N�Eùû“yÑòÐ�¼÷f¦úëYY9æz}ÐèWÊòß)ªÑU|ü†áì»0튞ÈÖÃä²½¤g±sÓèÁŸöjpë{v9æÈlt¿þÛ—„…›?Ƹ¤jnÒ껈�p|ØÖ+-`‘ÆïWMî¿­‰óµöþýMÀŠ«ÑLe¬6ðUÛ¿¹5: çÊuxOàÜE{÷Ο} ¬jB*Žz}Jš°Ÿ¾2®þ½{HEà¨�Ú»ÏPÛŒ+”\GаvèïÈ «¤,M0þëÓß½Z0[å2 šº@m¾Pæëw³Wi"÷rTmÿ÷Usçεþù‹ö}aÕ·'ü•ìDÕg �ë¼#Ë9ªªù¿¯?¾·áܧï¹ÊÔë«~é’BûsÍkUÇ”Y>?†º¼Ï�pbý «šŸê®ß#!íøûªg“ŒuS_ÛÒš�aáƒ?kœ÷øyÕz¿m±aIc,s$éUsýýgìU;7ýÉl+¨’ÀW•6-💪—œ×ÜXµâhuË›ó�¯«ºÕù{$ï·¾ôaUþ)ïuó >´,wéãVS{Õg*kŽÁ-P �U§ÍsQÚ@ºùÛkžÓ·>ÿ�ª5J,çê·‡ ª¼t¯«}é÷b/©Úk¶1µíI_–u·Aïv‰åƒmw�çZݴ9½#8[¹—EjÕújÿ²Á¢úÛµú÷'íš ß_§V­ñ{,Ê1ó÷3û yz sÜZ¦ÐþNQMAT_Ç[ù]Õ³×(×Ô¤g«vòg½ÔÍ®Ü^5ÁüÝCêüªFòW¬a¿Ûc›_sÝ+ÈöàWä’ P“û¯@ëò| €îcÖæ×~îݾ«û]ô±�ú�T‡÷õ{ AïÍÿ9öY�Öܾp‚«½½¶™w) °ŠX¤&Àßt­Bý¹�U‹„ë3$.B PÀK ܼÕ[o½UµqãÆª;vTíܹ³êmËá¤ãÂMœ…³/ßëØ‘»è¯È+—¹Q�pý-Ãqxå?±±Dëë+P_v|)ëmÖÖ‹³áÎqÉðÙ˜ï�êSÃêá+˜ÿrLý/°-Ë;P”¿‡++ѪC7ôˆ÷Ñ�‹ýò ŠQ)½WuJì ×�®é­Ð-©‡ÈHWÙŸåbË®bh#Åuê�+“‡ÂµIG)6¬þ ù{ŽÈü8ïâît¥Ì÷‡T~[¶nÁ7»‹Q~Êj)î¼0l°ïa ½ÊcÇ® _acþ^}ý-ÎCBÒe–t1Bý�ÊíÊGñqÍ(QŒذr%6Ëq ÅÅ�v-ÚÛ‹°³ð°µ’¾zøø/�Ê¥,±m÷ݦE\\6d.–®Àì‡v¡ ø8¢[u@ÏñfÙ¬ÿµÙ éá+ª|Öäþ{‹Ë ¿N ²�aú6œ§Též]8P´÷K7†#œ0ÛŠÊÊVHì}±ë|tˆíö�b»·XŽ¡…¬.õqa7ôp©ÔW¨:ν;ph×vl)øÅzµÍÆáâÞp¥ÇЋÎ5ÜïvìÙò5ò ÷¡øH¹I««>,ç•ëô°—b×÷°ñ/÷ã¶ìOôUç¯ÞŽ«å?>�¾°«8ÄÀQn­‡6Ç´ž×ŽëËv�s×ï¹fž;Ú‚­º$ê¦E»¤]H�ûîáË<Ömr¬ÒÞ5Âq硋죟«ecA”Y/œôv¡ÛU·=ca¿ÿ,/Ú…ÂÃZ/5Ñf›´.jœkZKÎíÖÓ»®¥�îÚ¾r6¢ƒçüúh�A{Y�Kýæn«Æõ¬¼h r¿Ø"õ$×9{_~%†öŽw­Rºk>[›�#r�Ñλî—“ùþ{4°ÊÇŸnÀŽ’£ˆ‰‰Ñë=¡{ôíç«ÝCê5ðµã|Ks“v�Ÿ‡¼­²ŽV^ó:y™\·.v]x]Eø¡XzøR{ªÓ¾J?Ç­®3†¡Kýv.½­ý”αë-$$Ž7çÞ‹•Ç_Á¥®Fî½R+éáëÜj{ø’ß1³½¶ê$×h±*/ÊÇÆÍ;p@®'ÚOr§„$ –ä}mV~7åzãØ³+s7Ëù ë �ÿ±ôn^ý„s½ eGi‘\çËQúûýJ÷äcŸtYݪz÷pŸß¡œŸvéÉ2okòåwCûIÖ®yÝt.“ßÔUè]©^SìÈÿò løzŽJ›’V…óä÷­O¿¾ò{ë£wE¥ÎŒ{�šÿÖ;{øúaí+è=lŠ«„�-ÏCÆ Ý]ß=?Xù".»~škòóy%¸³wœ¥íMßT†_&Eáû-k±që>Tœ”kM˹�ó@IDATöˆïÛ“<îG8°kŽè¿=Ö¾ïúezl‡®è*7V'íÆ×6¡h¿qOÐî¢.è{ÅtöÛŨ‡åz´}géëH±[Æ¡ó�úcðåÝÑÒuÚ™TM» éZbý*åô1Ø6ì}‘¶¯Ð®ï5¸î:0e^°Ç¨¬¢ µ­º¯Æï¦v¯ðÕú�ï7-û”{‡/?ú_[bü.žw1.tzÇGÉðä±ÿßÞû×qÜwž?üåJ”DÙ’e[¶LÚ²%‘“«µnã{NR§õ– ©œs•r ºŠË j¯î#©Š²¸u\¸.[H•!® ÖñÙ�j»"؉áZ¶VP*µï¢²H)„,B! ¤R E€x €¾_Ï{3óëy=ÿú½‚à÷Ià›73ÝýëOÿú׿éùMOåõ䑾|›õ±ê–…-~>Û¨Iíyý$�ö�SùϺ#ýWŸ`úïq+ôæÓµd_âüWï¥õù$ßß”)ë5…¬nì¶äc\_êgèÏ?ñ.úü�ª©»úiúÙ?¦% �䢯Ïâcm†ÿ[E”ööûõ¨k}=;9ûßèî�W^=ÈëØÑ‘éÿ“òüÀþ;>@·Ò¼³Ÿá×i‰íÊ�§þ…Þ¬ú·w°ÿðóÞ59�á/œ´_{Tçµi~™lÕ�üjWÛ–n«+/Ñï°?ðÚ Ezö…<ó9ÇÑ?©Ás4Ž\C*q[îs îú•·Ìpì7Ưæy}ÓŒs¹ü¯ç i¥¯y®g£ó7¾›ÏÞ™umôœˆ¶�¶¹¾ÍXá«Ñu¹}ï ûfû*¾�Û®>A^»œ§=óæm¶¾ø•ªók›ÊB×ëdÞ¹IžÛÈ2òmÆXv;Ù”:²}}eî-zæÿ¾›>ûW•öí9B�ðDp¹¼Ÿ>Às{á”ZvY…¦T73ÌI×$ró3j²‰ìpõC²ö�ÊJ8.óäÒ‰ÏYw1N6kÞ-‚1ø)Ç]6ÏÒK|æå×ߤ%=ñÇóZ]<�ÒU³ºz#ï—eõ büŒjmòèF=czsmоU’on1*O–ùŠ<ó@�²Än¸ûâéú[hõ@ö¾æû |wrÿûºÂû±¢¿ÿësôüytŒÉÛ6aÖYm¨[¿JkÏöÈý@ߟ åË;ß'ç`çÉdáØ�«HÀ5Þê‰'ž Ã‡Óž={¨µµ•uü¸Fœ9gIVRÅÇ¿ªÿá1µä•+w%¯ðUôWøzü§'c7}…¯Å)UðŸæíR¶çN§†‚'i‹áLJ»«û jòøÕççù›)©ÒÌXXŽq¼[MÌFŸÎ)«©‘þ Lî 5Û=ƒ5«šIyŽÌWƒ…Út^^݃j6ÏÓå¥ãª»*Cah\�öÉ| ÞSþSC…@ÆÁÈÓ»¥™ñ }´.c“j¸ÇÏO®~ ž6ëVG&ƒü£y NÎVuxQ UWöŠžÃïO©®F° &Ã'£jÏ#ÕÝ?ªæ-½"iWy¾¨úãx{ìzÔø´}9„ùâhŒnh.a:©‡Q¹ùÕ•žxÑv8>¶K!aµ³é_—I†¦”â'3 Õ6§H¿X˜W½±œµÌÝj´X!˜Eæ<ù%µ�>6Þëë©ñ¹¨’—ÂUã¸n>3™çB1Ô³pu¸Íë�YxIyk¶�¾:©Š£}ö~Ó;Æö¹¤ÆúCý�:U˜TQzŠ­ãø`ø¯<¿²Ý¥†&gL‘ yì¶ÃO°Èz¬Úèëžøî³Úg?}ô[¯ $Wjæ _3GÕĈW9J^‘è¢*;ªŠ¯ŸV§V—RÎ͸—쯽#jb$¦Ý© ÆŽ‡c˜fŽÝj|rÄÐÙGÜÚÇÅÞæOµ{Q]P¥¾0ümU¼TÑiÙ÷¾ôÔ¤úR°r^˜¿g7º¿¬ŽÊÕð–‹ê~¿ßw}Y½ä¯ÊÇ«è=PÝÿ£“ꙉ/º*íÑž:Y#÷é7�¨‡EÝäù•íϨÇN„«˜¥­ð•ÕV»´¯ÑØÖyúˆÐ}ŸkðíûEº�4·Ùwá'ä´;Öj;óÔQ&L«‡¥¯vàˆšžðWQ�è*s ýͰÌòìdìØÕ38¢{ºªº*|\i³cmR~YÜüí°.Ö-±RGÏà°êýhH\…i…ÿn[ñÊI×’®C~QýîGjÛªÒ¯}2e¾¦k”¸%ø˜+NÏ«aÃîõ«éˆ-7óMÓ][LâR¹>óËpÃ7ÏÿõåLü6új#}Ê$;Y¹^pö3¼ -ª‰�ð:Ë jr2\Ë»3 ¤é…ŦUÓ»µ¹«í5„6~«+LQCF¿}·{È:?á2ŽJ?©±s4ìQ6øzŇå>—à®_NeÆŒ_’y^ß4Ï\@VÿËç*¿³¤­W_]ôÃj_rØ;YG»Ñs"V¹°ÍXá«ÑuÑ×…Á›œ|»œ¹=òöÝò�®ó›Ë⸘3®ï ̌…óµ]ƒ<7™ö1ø6v,¯�lF“Ú1œçV*¯¬kÖ9i™ÆÅÞÉôömW?$_ßqž'¯ íR÷pœìn¼›�¦¿7,›ÔðĸꋙÏ/ôGæ\t¿,—_ãgèùм÷rœÇô&Ú”ôy‹ooÈ“uŽ éúÆ¿Fö5$ù»>_ o³µþI›T§,nþ¶Ï/æ[ÈÚ=2­ÄëÙx$Ëë …½­ ør×µøë�«þäÿˆðf®Ò÷7nîÊ>ŸxMÃ#º[ð ¾ÔHð0‹¶w}ê¸ý™�jnÍàꛫ�µ™þo«õw¦1Ûŧ\T£½â1Y_Çõ�Mãn.?ƒ+2< ¦u�ÿ¼kψ[ÕKóúÜѦq™®mžo|±¶RÍN9�úvŸ%à:ŽJ¿0(³s4®\k DwÔ1—à¬_®eJ›'Æ/+ó,óPÑëójç¹…([ñ;‹ïV�¾ºê‡dØ—ŒöNTÏØlôœˆUF.Ѻ_êH�`ˆ™éG£ëRŸOàh—3µ§cÞ Óu^øl¹ý#yç&¹IêWþc»fŒë’L××1þsÝs`.v² uÔíhÎ+k¢K zž»ú@�‹¬Uðyæ¤ý¶rµw~ú¸o7?$¿.:Ï“³à®u—ö2ðMªýÎ÷\óŽãéï·—Ý¥ºùÞCô^Ha¨ò0¹—VÚs1æûùêo9ncï�+Óv?ÈðcÊtÑ )[È<ƒÚ,›Â³ÙNs‹1ò$ÏWd™’-ißn¨/Ñw{‰á^·þ0¯† Õk..¯oÌ|(]¾—ºGD@˜cÛ°¸¹mhŒŽ‡5·õ«ôö”}NöEçù>'½“µÀ6€løªi‹Œ_¥SjÔøúêªX|J=ñø×•Äõõ¯?®¾óÃgÔ+çãoŠúçÖˆÝ!È, |~p#DžŸ!é$ÊAsz$|òH;�½ÃÅpUœù#‘›@¤úÇ ¢ÒìD¸‚R5hªRE|c¦ÑÇ玄OëÕŸ¦ʨ<úéŒy±LÏŒ $“ ¢l£¿kyŽüžà›>‹‹üW α�û©k@É’éñè* á͉ډ^™fJ¬»µ8­ÄMF¹Ê@IÜŒ2.øi¾áÀñãü¦EÔ×yþ¸\…­WM vQ$ò÷üQ¾à>¾ –çÄ fX3ê€~—º|² od*ÔŸò¼¹úRßDõ×!x2ZòªH$yWt•'L‚:“5 ¡Ì«Ï?¬•˜~!Ÿ.+ô� ç˜Ë�ÈÜ3ê;Öñ2»å'éG¶ç'ƒ~ÕÕ?a”ý¸R_3ðE;Áá…�?u5úc2`®^¸83aØÒaãn» Beߦ|mœ5VFÒüïÿü«o�ªߺXWðWZà‰W[Ù_½ö×+y {¹pÜxŠOÚ!ã (NÛÕ;¤¦çÔâ‚*y¦Ìµ}\ì­Ks2IŽÑ¡vˆÉl9öeÐOs‚£[MÌÈ»ö¼ª‚\õNæ³5gŒa=CGŒ`Fý„®ìË2€µc½ø2Vª“ÁV~ÐUŽïhÀ×ýÿþ[êE±’Wñ»b…®‚\ÉK|DÀ¯ðõ�§Û¾}û¸úÚ1X¹|L="|‚/=ô»ÿA”Õõûêé·ÄÊz«¯ªÁýÍ:çê&/X‹€xëx:/‚ÂŒ1!¡¢5þsƒæÀœæy›TG®¾œ·Š8—Î6ÝiNÚÝÞ%´bEW¿ˆu1ã|½›.:Γ;ûXfûéñ¥qónÉTõQi«ý±MÞ¶8n¼"Ã5«(RŽ›²O»úòÚ3ôÜ|T)›_oóY̘Þ$›â¦« »FžìóÉ×È¢!­›î¾¸´Wv}·(vÖag„ß ß@sÄ¿õ'ǹŸKunšÁO’º+ûUR{Ê~.Ó8Ï5Ô¡w¢!±  [‚¾jš!cÀ×ê)õDðõÕ ÐËâ’ßߟ:SSŠÞáŸc=(wÊR;Ë…?á’ð'n†N#g(ó‰™�È2ÐOèWå,‚à âW¨‰0 >£¬&úüÒ¡žæ×¿ðSz5/¾y$Wõ¨d+_Kç¯lU="'¨8¸ª6­tÖ8XLÞ·®Êlÿ2Ÿ²ê5–<­¤°;æÍ‚QË»LäŠJÚ e2'ŒUƒªBJ§EN�Ëö’ûƒà=™áÝ”©­í,¿Vc`hD��1‚åjÏ ÷ÌŒr{u{�F69ã²ÒŒXÕ¨Ç\åÍË}±/éྠ>ÉÅl�ÆÖ³cáëÝ¢«Âé4SCáSæ}ãÕçìbú…tÚ‡�›­óRüdÙðÀ SG¦ý€“x™ÝòóJŠùGm™}`jXܘÕ:À2PP- xwõOVòç½›ßãyÅTZì–i¹~a‡ªœ#ê¨ë?:iùpE¸°ïpžbbn0¸ZÅF&>F‚¾žn;JÓb•;¶y¾Ö¹ _µ´�<Á²½¹_+êôë?«|UôK3öþøuw¿ýG_V�ýCQ½X}å]Ú IþñL�'²¿r™A?\Jr5A1yº8%ƒˆy%ĈJ8·�?±­dµ·.i¸Ž6»'ªÎ›¢_ã|š~–ŒIéÁ#6íäq®à·w—š¨y•¬)‰ÿËh^ÁËŸƒð�ëïE¹˜#䘢;1Ö{_ÇÂW“f{jü `FÀWá�Õó5Áb¯Š­pe­³r…/ðµq^=W‘zä©Wƒ€.¿¯U=í+u fÛ±�ÄúEº®ö½»SS/¹Ã©ŽõôUaØ^Ùü8¹ºD0+ý =žúÁÕae¤Ÿjø¸’�a“Üe‘äó·Cy­[BÖÀ/X(†�1ÌÌ\}AÔ!Z7W]c Wò6–ë�x×µ2Å´±l« žV ‘�‚u÷«¡þЧÖãÿX­�ŽdÀ²5‘‹ó~UüßššŸézà\_]–lKÖ]9.»úóÂ%1ŽU‹øå¡î¹Û4gN¶7¨Iì†ì›ö¹ 9?ÎÔ3Ž~’eE —9g®±d®s îú¥”k™Ñ~â»>ó¾©Û\€´é¦ÿR�ÛJN묯u\ÏÚíKº½‹«ae¿ôQÌk—9»Œ1×`[êëH²¼IG[wŸÀÝ.ë`äd?¦ž¼“ØécI:/�Ù}`»ä.¯a·xõöÈÔƒ’«¯Øæ4ìµ5ëј90w;Ùœ:Æô·*W›î2'Ý´ñÐÉq×E—yòzêÞ´y7{§0öJ®W®]]�û�¼ñ_ �ÁžËqS™¸úV?ÃI7ØúÉ{dÖûkvÔ´›�šWw×Õ¨<Ùç+Láu†¡±?êñÅÓô=¶Ðê�zúšÎbv<¼¦ïÇê{°£b>Q>PË�Îó¾.6ÔªãÕzû_Rwe¿’û£í)ûy˜&Ò·sÝÏ1ÇÖâÖG¤Î¶]gW�}¯Ãîè¢ã?u¬«¯ ûÀ«bFƒ^µœVSú¸<6Fã§½ú|…ŽHv±6ÉQ–Üþv|Køu¨ñ ø€´{ÄãrhOY7ƒ…Å?©Š!'góø±:îå+dâ›™Û¸*Sâ—ß–òÁ"ß_áï¯6›x¥Ñd.îcxb­½ƒ�÷ÓÊ”íh³9y]õõÛR·ŸÔ]Î7¬«¸Î5IJ‰´á5 ¯î5a½V“ýþ`b…¯:lš;Ûk0°ÿ�}³7XýYž+Ø ¶žqT–Ù¨9w®²®ŽÛB7åî¬_YĈ)3î&•džÇ7u› °ëL–jEçâÏF™õðW+—9ÛË®G?ìöE–c·wR*Ûv¨õωØeŒ±�Bw¢¶Ô&g–}�¬‹©9|‚:ì²Y¦¥=ëÊ;� Ô%á‹zÉä±Mba\߆s•ZÈ]¢²&ÕSÖÃâc:™q,©8ÿ˜ÈWÚfýlx ߨ:Æô7_–´ïY]æ¤ë±wÉb:ø!õô‡yòzê.Ç—ÆÎ»%SÕG¥ 7tU$� ß`œ#ô&ΞËz÷‚8_¹?�_`÷3t£F†ìcºi³dSêÑUcÞ)ÇA„AЮ¢Ý“6å‹Ûô=©\}¬ž¾VÉ›ƒ¸zÃûÃ]]áõEƒ�ëhj×q“ˆì?qý*Úž²Ÿi¸7æ~N>½3kƒ_  põ ૦ 2|­�WÏŒ�«qý÷âz³&žë’*>!VþzâYµ)Ë5à«o`@ $ýõ‰'®ÅDl£ÚáãµÏ®™ƒmÒñÚ‹ÙòÂŒRý½½¼zTeå2í NŠ˜Õ¥C`“ÇtZkËŒ4…ø). c‚-̺V¾äÅ�åéÚJru)“(3&­¬¯ttâöëòŠb5+?0°ÐÓ«†FÆÕÔL–à%�ÅØ,«™â¸èW½=¼Ú¯6ç·W—¸ $å”ÌìíePý!¸DÚ_Ÿ ó ¼È{âå*ÆSÒé•m'û _‡Î¢ï<Toÿ�ŸœŠ  K�Ù)?—pŸlÿà© ^-Í—{ˆ_ \¸}>2P¨êD'eøY�Mí� ¼ÂjÆl‰´¶~#Û5åx «iiª’H] ÒÊ SÁZ /u–ºzØŽ÷«þ~óo ?œ|0VI‘E¶¯JÀ—¶zV=sôêÑG¿¨>Ý}OlØ`Q¼’ÎOùÎx’©�X7‚§öB—ýŬTOû¸Ø[—4RÆÐîI…ýBÚ³4ý4:HõôÔèf?û½ÒÆOÉ‚c·¥Ìñö?½ÍìiE}-ã„M¨š€¯ê« ¥"º*Ï•Á–ƒÇÎ76à«[¼êQÈ Ëô·B™–ø5ãßV_ú£ßW=È«}>®îúç�eüJÇG‹¹^é8<%(ýs,¶·‘n{ûÚÚGîsé#²Ÿ‡ö™sÍd;ø4±rE�>SÚMªc]}UôÛ¸¨[J<l¯ÿ·¦íóÉ.Î&9Ë2#Kœ¿m“[ì²u÷Ë›rrÕ-ÁSÖMäc[Ù/Ѫki¶š[ÛÈÏT¦ÏÃ5HŸ°!ë%'’EÐW¿²=ö#ÓÇȦӺr‘c�‹�µ¹þo,¥ê©[–¶|V]õ•m!u7’o?CÊ7ÈN‚>V‡M“eæms—ñ%µÕ„ý´3í*|Y{:]2§MñmmieÞ5+ÁíŽí2M^®iŒ*Ç›3—`Õ¯@ üe~ƒè'ÒÛ˜{meó™œæì:T+q#9­k=êÑ™6´/BΘkèÄjòAY—zçDì2š67�=Á–¦Éw¼‘u1t1fÜ•å5Â.eÚÚ³›Ç,Ü/tIØØÊqqlÓXDÞ00a”Åjó]})óay+¥R'mõǃöòw°“œ6 RäßRǘþÈ©7òË*û¶Ývx?dšF�‡¹ý�ºúŽ~ {8�ež¼žºK»Òèy·ÚV2÷H¹‡£‘ÎÕS­×¢oÔðe×-Ño¥mŠ)3·np½$ó\24æԥ«‚•͆Eê*í˜d ÷›bÿeè�åžg%Ë–â‹ÛôÝ^b¸W–ílg˜¹ÿàšÿ�ø¿ãÑ{Õu´�”Ó®ca�‚­Žó†l·À¿Šì�¶§”%H#ËŠÑ]®µÿ§õƒyt¾ø€€ÀV!€€¯š–ÈðU“β£ôŠXékT�Š ´N_üº¨H6µóê&Á@/&§â&­dYÚ`0 ­ƒ­õx8™¨ÏNˆU”Ä ƒÐAñ/JÌtqr†E 'Q:Ôá 1["]Œƒ`­«t,$s£”¾†FÖG”“VÖW::qû+Å–Ôä° ñYúßÝjhüxòÓø†üüƒŸà _éåçcÿ–rJf}©ï|©–*¸XÚPæ)u2n²÷ˆxí¨©�°ËF™¶ö”ÌrÚü$l•cB—„�­9¶i,¸dØ¥W‰õ_¡,WJÉ|ãÜ«ˆ¨£­’oÊñ ½u¾®vR§mxcú›.Ke•};뜴LcúqãcŽñ�½è\óõ²múNÞyòzê.íJhë+ͧÿ­'ï0û–ÌÛV¶Ne½Ö�|m}‡ÓÅÕ+n(¡è·Ò6Å–™S7dK•A^cÙê+c5gq<°)b_¶~Ã+E« V6y"u ÊLØ_Í8ñ+‹Þ¸úâ‰óAYv6^v;3'_íÈ6ÂúV‘:ÚFʙՆÆùÒ’I\ÿ‘ûe;ë´R– ŸËºÅèŽNkíÿiý€Ó%É£óÅ@¶ |Õ´D¾Ø�/Žú«|}G�Ž,ñåðŃ–‘X#º¿#n�‹Ûï§ãoù*—`Ðäýr`“ûý¤ÖÁÖ?Èßáñp2ѼyBª«g@�MÕñéi5ï÷››ŸSãÁ«Ât:Û4yø ·…˲)ÒÅ8a]Ä«.2°Õ2 Ûžö”²Æ”)ë+�¸ý²bå…YUœU½bå7q�Ø=ä;Ö2•m»¤ÆÅSAD]ªxL§Ž«é™5;;¯æ¦ÇUW5o)§df{å§­´´6”y:)—¨¥�Ê�Iž—ï3_G”Úve5;]T£Cª»`»°ç„‚N)ôG^ÈÌ“Ÿ‘ÐòC<©U} [Ñlã ¥ÊýÈpůA=¿0´QÏÈt�çÕé�Yx"F6DZ[¿IkWq<ÐU±/é&íbDǯ¤öW³H‘‡¥—:KÝýjddX Çÿ �«yO!àÿŒ�PL�ˆIJ|L=Øñš¹:_Œü9ŸS§¾§Ê õ…¢-& bi\À¿Ö4è«=ʰOÚKÃfTA6¢}\ìmž4RF[ »iô‹ý”ºÏmÖ?<’¨›ÃC¼Ò!¯ ˜å“.³ÎÅ­ÍŒúÆÚ\SJðuúÔ·ÕÝ�nòkS‚£º-Ëà««ðuQ=fŒÑ÷¨‡‡¿¥¾ô¨zæä uôÔiõü‰°Þ›ðeo_³eâåé#²Ÿ¶]g-uÜèf¹Vûž)í&ÕQÊ’»¯¦ØFaå'Ëì oVEÈÙýn™ÖàÞYŒü¤4qþ¶<Dz-d5t§zª\Á€zÆxo)¬³”EäÓ _ÂÚFAu¹é6ê55Ü#âH�NËÇ ªy&¤—¥Zû`†k%9Öäñ±®Žÿ+klÛNoG×úz¥%´…Ì7�Ÿ‘ž.ƒ}ÉiÓd™yÚ\Ï3¾Èt¶mÙ7SÙ ŸEÖÞN—fcÒÊLË;<ε„ûøº·�×+Úf6b.!Ž‘dÚp÷2ãüYŽ]ÑE;‡:“g. -¯0×Ú­ä´®õ¨G?dÚ���SŽ¥µJØÓ¸9»Œæu| {‚-M6åPãêb\'Ű•zôY¯œv9µÌºòNA'}…š¾—®g�g¡åå2Ë1ï½è¼m°jvu¾2­jÁq‘Ÿ­M%ß”ãA{×a›+b ™RǘþæænÓeßÎ:'-Ó4v< ”ß°�q¾^¶mî~Éååœ'¯§î²/ö2¬rÓæEuRn[Ùú뵆äkë;œÎõ~™iB+ÎÏÐ2êOfÝàsÓ˜ÇÊ m”­Þi\ÄñÀ¦ˆ}:€)ßÜ¢°'6y"u ÊLØÏ‡R?YôÆÕO+\–íngæÅýÆê}+ºnUùBÔÑ6Rά64MǵXYú•lg�FÊôsY·ÝÑi­ý?­ètb%ç¨<:_|@@`«@ÀWMKÈ ­ÚU¹jNOÜ!óz¢1+|% Z�(qƒ\Üþ !?œ3>y š|\lr¿ŸÔ:Øúù;<:·á>Žæ¨<%.’x›}þ»§Ãtú@š<|Fx¦æb?ZŠü-ÒŰ–r,$[Û“lº^y- :’õI/SÖW:qûe�Œír‰ƒ²Šj¸_u©ñ¹ Q%²Žü$ïø¬e­9ñt—”sj8,/³c˜Ò†Öv¨Vvr Üx�eôIŽ™¬WL›K†¥…9U^›¨/`ºúýeØE[fÔ»äüdÉöíÙà)½âÄœ*Tœûð ™ðUD…!~å‘pU½±™° %ÏÍë�ùy…DZ[»¥µ«8èª\Þ8®³²ßi¦•OŠ<|’¼Y<<�¡ÏUsNûò‚O–‹apU¦€/óü—2z-©—Þ<©ž9ñªe%£0xˈyzø3A_|ô„íuwaš†|‰àZÕÙn�ípÞ>.ö6%�ì§¶:ð(®ü d£_¤è§¡û#ùV~ m›ÁkeÙVÆ?Álhdm3—±^|�啰€GR¿=v"“>Ÿ:ñ5OŸþžz~yÉK³e¾Ø|šWž ü¸zìÔÅÚ:½ÞŒ€¯p|ÏÛ¾6}IÝ—ÒGd?l»ÎÔÐñ¸WÆØw1^ÄððÍx‹ÝI­�턤:õÈÛWSì€Ædó—dýcÇÆYÕïÛéÿÈ´ylR=²ÄúÛ6ØbŸ�ÕÐ�à”Õô1~è£8¾EÖÍh£œº&}_™g CLÇÛ8HŸ°!øÔ¾ªr1dá1ê®®‚&òk2×1\Ž«›çÿ .ÖÍôvt­¯WœlˈžIyü ™.n,˜ë | �z‘ϦÕÅÀÆ=ÉöÚÎ�ì“öÓÎN´«°“Íô“d»Ød �‡s çês’z—s.!”3Þ—´êWeÆÝ¤rmgCô;y.À®3Ñ<ì¿“ÓºÖ£ý�íê£�3b�ìõ²ïmÆœH(£œÏÌûЧ]Þ¤½�ª { áœh [©�°Ë©eÖaó“˜Uމú lÓXTJ–+¡vO+ý:G—ž‘ãéÕ2Îu´ÕCÚ¼”ãA{Ë49m³/ZcëÓßtauÈê2']�½óÙäúNòCÐwòÌ“×SwiW¤õYÔ“·ŸGÜ·9ÎX@á„‹SÃA´ö[ßát®÷Ë »(m“Ôç˜2ƒz&醮“¸†·1�•!mœH“QXÖ¥«)6.R× Ì„ýÄ�fúâ Åz‡Ñ䪑þø¢¿kƘ:򮁠6;Fdzô+ÙΚÙÏ«amFÝ6{&­•q@6�¾jXË ­¸€¯Uõʳ?Rßÿþ¸}ü uìüZM.ÞŽÕÓê;_õWøâ€¯­ðewY…Âá2nLÉý‘W¹ù©� „�2ÒILs­ƒ­Ÿ)‡ÇÃÉÄpŸž¸ O‚db9s"^¥Eœ’&O¼3䳑î\J¹FÒ±à÷dÛb9äEI'?ÍÁfIe}¥£·¿R¹’Z˜_ˆ½q//öFlOâG ±þtû7ºXDsgN�„¯�ì'/älaàHp~¸Á7ŠúzTwo¯êå×$V^…$ÚÂàUIem‡j†‹ÇG‚ ¸ž‘¢:2Þ�›�ÚÈ~q@K‹ ja1r¾/ôü¤*øm{Må3ßø\Шʟ©ß%Œmõ´¯Ù2¶_ùûˆìç�m×Y×cßåx’ÓîØjeîË[Çzújšˆñ7 ·GÙ\öòlxóÊðq%»\6)‹,yým“|Í/!«¡;âDÓ—ï VL5®·êÑ5Ù× ^¡±:î�âØÆaöñ[‚�Qß Ålpì�'ý抺Mæâ:†›ãªåêf‹^�ºÖ×k®„¶4yd÷3ä�’žÑé@+ ØÍ+äL¸Û´ºð•lC¯“¹¢²oÚü̸ëÄzÆÑ´2e{Úd �‡s4õq [¼f‹õÎu.ÁY¿ê(3î&Uó¸vÖ<òÏ›n™©alìHNëZ�zô#Ô74•aÜ3ª÷£ s"²ÏXeO°¥qbfÚß ºº˜Ë§p·ËéeÖ“w½$�Ç6�EU^özýëlž�ôWE-¨Él f‹Š§Ô#M'Åñ`®ÇNú’5´Žòþ�´\X²Ê±6ëœt=öÎGÿ�ש¿ïä™'¯§îiãK=yÇ󬑶:|ÚL%}Š^ßg}ƒ|¿Ì°‹r,—ev)¯np ÎófM°)|§Á}n1EnJY×ÀŽ%ì7[ßþKÚ‡ÆÏYÚËô÷ÖÛÊ3cÁ_/ÈÅ&ôÊ’òúÖ½m$£¬6Ôð¥ëèW²�57ÙÏ_­És qzç·#¾A@`«@ÀWMK¬©gŸƒ´NÇÄr�úÑãÊ%ãW¿ó¬=øå©Ñðœ'¦T$Þ+8V#BtG¬=±ú;î|ÞL²Ù‚’8€%Ó‘é#þ]{Î7MžX‡ZÈdßLw.M¹ýh‘Že˜ðoWû¥Ì©Á‚¿ò†þ9²N¾ŸÖ¬¯tt$`5=>A=ä¿Ï,ÌÎÛ’9qObIä ?~]`´Åô; Ð@OhpTàVÊà(®{M ÍüDxÓŒüW.J¦µ7ííàK,�XÁ�åö[Ì?Óp@}þ|s§Ï¿±ïï T7d ×™�ó‹jû-VôÑܽ?“ñBqH\TÎéêŸ423yF[·Yý1†—!YÜ‘ÖÖFqvÐÏN—}JB†¯kôñ7÷ƒž€³œ¤K‘Gg!ƒZ¸X'øæü¾PPƒã3¢àøÍJpÊ’úæ¿¿'l箇ՓoÙXŽþ×Ãó¸.�üÃis% åÓêé£Eõ$ÿß”�cçÕ`°‚ ëу_QϯÚËÐ2Íœø–xm©¯� ózñäQ/ÿ'��S2žˆvÓºÞcy*vn" ¬£Þ± xNÚKÛ8æÚ>.öÖ%�ÖÙOm7Tep«yC>]?e c\@âDõ5Ë…žAeÌÄ«§RlÿýWýzÁÛQó©W×@h›RÛLÞ$2ÆÕx�ü€¯³—Ä*w^ŸþŒúæIûkGO¿uT=Rðí«þ~X=SÕý-³Â—¬OáË5Aœú5–÷{õ¬ÖãÁǽ¾—©ßœ#ãqíßJJ¹ö©3Ò/Òe9Û÷:ìN3êèÞWÓí€Á/ÈéX‡úk|\“­áãJvÆX-ò4ö‡Ä²È’Ïßó¶n Y¥_`ž[Vþêá]ã>©ƒ³®É¾ÉÓ—Ãà"®¨wåêçžð-øDë¤Z_#îù£=#†ßÝL.®c¸Wk¯™šåÿÄb6ÒÛѵ¾^� m)yäñ3¤^’Üö+87®0¬uCö1g›æèW»Ž/~]â¾%«Ÿ)û·ôYêGÓÊ”íi“)<.æ&¹Æq ö×1— ë™K¿ê(Ó:GÀ•‘²Ø˜s;~;;Ï[À@Ú®¾5Éi�ê¡Ë¨C?B}“s�BΘq¯¦jÖ͘ gެ²'ØRUšWǧ¦ÔÿÍÌY.~¬uðw6¦.†.ư•zл,í\L™Î6ßÇû-t©¦¿ˆc1r5žE(hðfõZÌó!å|ixjÊVJ=’tRç,Ží]��Ò6®Žæœ‡agë‘ÕeNº{'ÐÔlºú!õ÷�óäuÔ]ö%£ý|uäíg÷-m5ñ}¯Úq“øsý܃`îáý0ËCE¬?áq9†9úº¢?ú×V®º‘Ê\Úfß7ñ 6Á¦p¾îºš"ç-ëرèþškd¯²ñÿ4Ñ�/´z¤®þ`>p5ñC5}úMuéÒ%õæé—Õ�¾#Â8¿gN×}?`¬F¦è‹=Åø{¾ùdm¡oTÍÌ/ªRiQÍÇDCåf œô–›LýrãÛÚãádâôˆÿd“¾Q2 Š³ ,KIÍÏÕP¯ÿ*Çê�IvÄûFãÒä1&7 gÖ—(î;ݹŒ«k¸ôº–¹K �óëóx…­ÙéI5 ƒ$¼‹‹�ƒ!kÎÉÉA3œš�ãòfԙ®ô�·á –eA·5¯Î²À“OCâ|¡6ˆ‡'*Ã@¾á7ZT œ_iq^M�Ëüü6ëSǃձJæ«^ºúÔÄñYµÈ+hiÝë\…¡bµtS_ƦÔüÜl0a×¾èr¹ÙJëИ%€ÆÚ_„°îúGÔÔ̯l£ë»¨æg§  ŸŠ“ùl¸œ~®üüÚ$,< l3. *í3xÄ|œðêôÇ8^Y&EEÙú�µ]Gq\^$–gåÓ1U=_äv÷lÓÕ_ðõ›¿{ǃ`¢,ý˜—˜ nWt²G�Oq?(—U¹´ ¦�Œ}¬o\®Á&d�l«]:¾Ö‘õŒèõðð·Ôw�SÅ“ÇÔ÷Ÿú–z¤÷㦮pÐGtu¯™£a@ØÝ¼Y�¿â:ú3=}\}áßV:pëù×_UÏŸ:¡ž.þ@ þQ¸’�W׿v�Ý8¯¾ôù�+¥°L�'¢Ýü~=0ƶ¨ÚF³ÅaÛä læÄ€msmŸÒt~{ë’F7»¹ºLA�g<»´8?£Æ‚§…«:j¼z-¥¿pÞòõšmÏบåq£Ìú¹07­FĘÍOŽEKŒ¨¥øYVã½¢ßúy¼Ÿ÷ú”?Š£"@�Ë•«0Ê1ÎÞf¢^Çú à‹õùÅb¨ë¾>ÝßûEõµ‰Iõô‰cêI›.³Œ!^Oºe¾ŒøH=¬ž¾´¤2õ;ž _WÈAíÆxìÞ¾BIj6�ûˆxºUúE ¼0�³}¯ÃîÔTLìp­£{_ýÅ6n²l²Ïɱ1êãON{> ¶=ãQÛ#û¢dg”Ù8Y²ûÛ¾mSÈ*ë^sêb$¨I�·FÝêÐ59ÉÓ—C¶QTdzø"2}b=ýýoÁ'Z_ÿý½8=jø ú5‰þº�Î}0×1üêø¿’˜m;½¸Ö×+-¡-ÝýŒÕ§ûBõ¯«gÈ»vZ˜ŸUG"ã¼>Gêž»Msó«]m¯­¥ä>Ù·òù,îãhZ™i×Ëáq97áÆU²°n×5—à¨_õ”ÓOÒ˜v8EŸfý¯n!Ûµr¼ïfŽ÷yõÕ|®ô÷ì׳¡¾É›å‚M̸gÕ'ËÎF̉ØeŒ @‰Ñ-ÚâTøÀ]× ?¿e:fW#êbèb [©Ï�±Ëéíénóc`»“®WÒåj<‹@0¾‘+áVÆÊ�È|\xvÒVJ=tÒËUÚ»;)Dm\cú›.«.Y]椛3ºú!�è;™çÉ똻”}É>¾4‡«Viý1ŠWÕóï5•fÔH_!ðUu Lø¨¾i?y¿Ì°Å�_ õYgf=[Ï.çËé Y¹òIuBÖŸ˜�~Ë€9°ÉÁÔ—@®e?îß(敇|�¤œVYzÕø¸ù4°–Q¿~0MíP‡\¢L_àØoÓ¹´±Žs,ø�î‘U¼ÂIo�m�_Y9H™ÒË”õ•Ž…¾@tC0,žQãÕ•X¢íýÝ3<K#zÀvq(óëWC2¸MËä¿îpñx¸”¹�U¦×OìÎøw…¸p©WÁy]•UºâÛ¡"u8áà;¹æªWAݤŠþUš7G‚òkdç×�ú:� óÇü96‚¼º*u5tÄK7¯† }¬¬H!õ¯š±äPSG�¶9ý1©�ªÌ‡Rú�¬�h× Oq<ÊëøhøjÒØvïêç€Æ ·tyüSK3j Ú±ykþ=æª~rÛ·�u"²Š�µ-+º@~Yµ¬Ð%Xx´h|鲊ßý¢˜$©æ•TNá‹ê™e¹˜\)ìSn_�-M(Ÿž¤ —vÔ6Nyl�Ú§ä`o]Òh cžÊ´ñ/ ª0¬3¥¿Tkf| SÛŽ—d«‰“¾²Ø®Cߨ´‘Kz›åëeÀ—Öç—Ž>n®|ecìû”zL{éô²¿Ø_[j×wc…±ÂWÔKœW¥/ŸW�ú㨱ß?n–)ûè“Ãá+Tmöå¡áo«/ùyûuzð¿°5Mÿ$ÚjÇöM.Õ±�ÄúE�u²ïœ§ðî`wšRGÎÔ­¯¦ÛÙç̱1ÅÇõõÉû>†ku�Ph9š(K¬¿�ÜÒ§6ë^›N¾zÁëk\·h?rÒµ4ßF‹’¨ãõp­­§±G–k´¥q–÷#z½Ù+Úi]²Ë.uÔÐcß¿hŽÿ[KMîIoGïl—úꄲÎ5méêgð‚žÆÓä>¿ð»§·úŠyæícn6�ëâÄÀq|ñ Çÿ#í§ÝÏLðYÇÑ´2åØm“)¼žv[Wщk<ÿH=s ®úå\fL?Ic7Õè¹…p<õéÖ~ËöüÂê\Šk=¼Rõ#Ô·ø€¯,õª­ieO#æDì2šóRA_ŠÑ-�äµwqòËý�¨Kê|IŠœnv9Ûøå–·$dߎ×ùt¹’Ú¬~yEùž¯aYAÈ^¥È^‘OÍøÍ§&褗‘8.õÒÙNÒ ÙêªcL«–U—¬YÆÚÈœtsÆCw?¤^]ÌÏý²8¿ÀÞ_Ýt#�yœ*úmmŠfꦫ)òp¾²®ÒŽ%_#û­œð�Å>°.埳L(Ó?äÐצ†ÅÜmŸš÷Ò¼lÙÞËE†Šáì°[Ûp®YEl¨k¿JjOÙÏ£6¦Ys qz·ßoZ|ƒ€Àf¸î¾VÏ<›)hËÎz改R×¥Ó/ªñѯ[óøúè¸:vêBl›úyÆžàà§Xz}µg¤æ†‚Zð]šÏ^5ç-«)ËS¶Ú‘íçÉøE~òÈEI¿X]F¾ë}ÄŒrð2ž: +ú �›Á1¥ÙIÕW'‚}‡ºÐ;¨¦<_dA�ô„ÃN9—/å±¿Ž°¤FƒElËøF%ô³sÙS•§ÇÎ:¬ ŸEY”çx”Þ€a¥>]ª�WJáõËÔ¨Ÿ·±´pz™%ñ´|Oäf6G­Â¤Ä+§ Š 3“sW¡W�LZV¼òQX¿ÕäpøºH¿½ˆøõs¼â‡þ,L™+ì�ÔÁE~¢¦ßþ3åéSsQ•uÙXM÷ƒj~‰íP‘Dý‘êê“«1y'Tþ‘ýÅN«.ÍÕ ¸9ÖWËÞ¥zFÔLTÝdvÊOˆ»uä«ËøÊó§†Â›,:˜(*¶>÷ªôÇ^RþÚí”~“Ю^^®Ú^Ý8[U½Û¤Û½oxRÜ´ö%K‘Ç?Íûæ~4Ò±ÕþÐÅ}‰Wϳµ�‘…øñF(R Y~U=6üûêþ˜à„û»VñÔ1u:š®úûÔ±¯6÷Óß8Zð¥ƒRN½yLýÅàÉ�2÷?¨Ë9*VöòV8 åA¿ÿF=Y »´5¢’þ¦x¡mAϰšÒ«SZêÙÓ?ZcOÒÇ ¿—öq±·.iøY­ù¢ê�íh¼rÖÔÂBø:dJ h³ëçâÌ$çïÊúíTùÖcsq6�vúLù»4ë��¦­äÛÕݯ&¦koñ¤·Yþ±>ðåYqŸùæ7þX=`íóšígÔF'ÕKÖɰ¿ ;oé/Õ_þÈçÔÓ~ðãò1õ�n7ýg¬´'úǃ_«Y�Ïë'�é£çÕØðÃÁ±�5¯ÄÇ+áé´/ýš¹ÚW÷ÿ›ÍÞ¤Ùj‡öÚ³éÖGâý¢J1¹íB×Õõ$uIDAT{v'¦bb·[uùûjºHò7ùQ]5Ú/| _»zÔ¯Ú:9à¶'v,n€,¹ým�ݶ)ü‚¨¯]{:_Ÿ>=÷aé늓së÷Æ ß»¯¦³�×ñôô‰m,d¯Ù|âüH™¦8$ýý.5!œüfq©”Ÿ ¿*þ¯„U³�ÞŽa’üõUåép5®žZ=só3*ÍyþsÕ‡¨úg]Ý}l#øJx&\ý­gÄ ðÖ©óÛ´J™œÒÁ¯v·½~©Ñïº}‡qT–Y3/Á×Ë9æh*usá¥ýÍyÖ1—à¦_ŽeÆŒ_’yÞy(§¹€4ÿ+ŠXþNH[O=*Eä×Cƒy´<öNVβ݀9»Œ‘¾äË£#Z29Ö7¤-b[w5 .Ú6¦ùRN›ï“ß.§—é×7Þ~Ê„ïX�O—«ñ,L9ç'ëÂ7˜ç¤ÿJ©G‚Nzy _Μs´“�SGösÇÂ9çÚ±­NYóÎI{uÌoï"h,?Ýý�úúÎB¶yò@âüuO_üÌóçí§Œû–� ÃG¦Ô˜±J}uî…¯]G‹áÚ^a^õß/ËåÄö×üº‘Îf¼3kîµçqy¯Í—hß¾γ�n=x ZGÿÔ5ZZò°,–rÖ–XÿBy’õo�.œ[äzéêuо{#eùe6ñ›ûËÒâ"]*•h�ë»k×.–ã@‚.¦Èœ;¿&ÖÍ’õæ÷Ç^7k×ÊÒZ¸¤Û�û2kÞM·ßNóä. ÷ƒ3gHçÌÆ‚õj?pÐïój•ó°ÁW.œ£‹%¢�ÜVø{ïMhOÄ>¸W@§\£Ë9ï��(Ô¾k'ÝÈýc‡iÆS‹ÙßÒN»)yܤ•çè¡]¥¿Ò¹ØŽþ}ÅŽ.�;GüŠY�ã¾›x iDÛÇÅÞ:¥á¶åWYr °î컉°ØÚTêñ',]8C ¬�<´h?a?ëNtl‰O�p„íß… ´Xâ¼Ëœ÷þ›èöƒ   ®Ò}E÷™¸Ïîó/Uô¹�ûåÎýè†zÆË¸‚š¹ŸÇè¹ùÚ»¯�}§vºÙ2F_®ŽÑ·íÚ›ÞïY3Øê&µoî>’âé*e¶ï›dwr×±Ú.Më«A»›+læØ6tth{¿Sû¯)‰þµÉþv­™ödÖµL¹UOÊ ãy²»ç6…‹_‡1|óý__Ø|;Ô7­Ô•:üŒµÊ…0û†ìƒV}² Ïü Ýôñ?ðŠå"ôïºìc¿³Msdàj{Óø9oÒ8ê.Oc®WŒòëœKpÒ¯:Ë4ä¯÷Gî¹€ þW¬Lõ¤�Í4<àØï ¶ïÖÒsNû>úy* MÑßÿÎ}×tE�ír†Z7>ïæê¼›¼kô½ß½�~õÑ<"c³eúõ÷äœ,ÉÀ²îS겓›\ǺdeRl»²ÏIWÉ6ÉÞ¹ú!nºè¨%Mª»'Mó~á??D÷þïÞl! M-ÒïÜǾ&ßO:·P½ÿÀ÷Kjï_D˜ð½Uî—¹êF¤FWýç¦ê*Û†¤ûc™`\M_¼�ý!K]�Û†åÌeC]ûUíÙÔ¹†,pq€\Yâ­lb���Ñ¡C‡hïÞ½_ÕJM øÒÁ^:˜ëri�Î_\¥³çW¼›XçxûÒÒ­Ñ•ò­sð—þ´é ¯äÕNûù®üÁ;é]·î¤ÛnÙI·ðöž]mðÕœ /¨¤}W5à+I0s"ðÚ3�ÑŸýM‘žŸ,Ò'ÿÓ$=ò‹�|V^xŒvÝûÙÊ>TXà@…Æø ù \¦uZT^ØXþÄ[$…Ã>ØÒIìN$Kx‘œGAÀ$ð|•c‚$Í3·÷¯Ìýn{cH¯ìN:£M<þö&ÂFQ �•ÀÚkôØüÏT|¹HÅK¿F“ã¿C‘+azì¡]ôÙÊ=8¾ ·À7áp%œïuôëºW�kÀýàÿº�>ù_ �É9úÃ_ºýÚ«$n�•—x.øîê\p÷?üû›�{ø·aRÖ—ÑõPÇú!õf0¾àkns”   °uÔðuøðaÚ³gOs¾t�×ÿSâÕ¼..–½`¯3¼ZÁÙ·Êôu…W\Y£ÅåuZ¹²QðÕÉ_»v´ÒÞÝmt¯npûÁNºíæNº�¿tÐ×�¼*Ñ.^õ«•#¿š°ØWæÖEÀWfT×ĉ¯}ïw齿úhUÖš˜þSú•ôV£:÷Òè÷îþdeU>£ol†þì×ïº&ê!A¶6î¬XâVùÚÚÒW¤ÛÇ«{íI[ÝKŸŠÀ‹k¡9·¼Œ«´A Š—»Î?™ûÝuÎ vgk)üí­Õ�*^£ßmy/WÂCô§½¿Bù!¼µ•sôÔ_þ}òóÕh/꣙òŸÑ][pq´æV%ýÚª-¹ìÖ^ù&u|àA>ØMS‹ã¤™Áçz$°Fgž{‚üèƒô£jõ“V¸¼6 ]u¼6[æz”_×c«£Î   >�-𵾡h•WîÒ+z�xe‘~:·Lóìu™ßؤZyv�oóËy}† ÓÕñW©¬ôÕâY稱5^~l�Wöj¡wÜÒAï×núð]û¼¿t`X[«ŸÎG²yßøÚ<Ö›SÒú“{ßEPY¥»ZduÑ üŸøt ÐÜñ?$<ã'˜`@ .:Øë°¬_ƒ«é×8ê×9fúÈ€¯F¿7“8i»XæÞré_¯ž¶ÈÕïê)h;¤…ÝÙb­{‹5Ä�À™§¿Dïúå/4ººøJøãJ«Ý„ð#+èWVR8oKà@×—N¾AtÃô¡÷`5Ã-Ñ&›*Ä}ó¡}ôà_™…v LÒsøKÞCÁæ‘kñ×õPÇk±]®o™ðu}·?j  ×;�-ð¥W÷ZZ^£ù W觯/Ó 'éµ7®ð+ùÕ�ª�vî褎Žjá`­}»ÛéÖ›wÐþÖ�îÍ·®ÐÒå5ÚØØ òj™®\YåeÈÖ醽­ôžÛvн‡öÑûïØC·ØÁ«€µ_µU¾ðµ »ß ¿Î¢ÿaúì£ß³V®gpŒï×éöŒ± ÖL°@,t¸óe`YáÕ‹¶új_:ÔZ¿ÀqwKíàïÌŸ¥çèû>ZyB¶kˆŽÿ^�›NŒÐýd‰ûÌ*o\ƒÁ’Ñú¤ýÖý®ƒûÛž¼ý.-ãí~vgëµ0üí­×&�˜€~åêÃÿ,Y¯„»zhì±?¥_¿Ï|Ù#À�@VЯ¬¤p€ÀÕ%p�þüÞ›èó"Þ¹{`œFÿ°{½Êñz¨ãÕÕ"”žŸÀsþ úèçä%,.Ð#ÿ ·ù)"€€€ÀµJ`Ë|é`/½º×Ü|‰ž;q�fN—8€k�–xe¯–Öþ§Í[Ñk}�ƒ¹ÊezÏ;;é¿pÝÉ+wéÏ«¼Øßÿó�~cÕ kmåÉœ©R¼îÉF™¼ˆ_ñØN‡Þ½‹îûðz×­»¼U¾®Æ«ðu­v›t¹×–ÎÑìë§éíònÚ]¾Hùeew¾›îE¤W:=œ P/üÅ#_½Ù4-}k°*gÞ"Vè•çž§s«0vã]t¿6h� /“­ÛgQG÷~׈үå<`w¶jëÁßÞª-¹®oktîµYzãüÛÔqC]xçNú�n£{>P¹xzqf‰þú‡gé'§VhÇŽÔÉ+�µµó«U%MkËíì\§ܱ“þõ}7ÓÞ½‡öíéàór¬0Ò AÀWƒ@"¸Nl¹€¯·—ʼ:×2Mÿt‘¦N,Òo­QGçNôj%½ª—þã75ÒÚÚ¿ªñ ÝýþÝô™O¾‹ºø5�ú£_ÿø­‰9N¿ì|µ·W^ÙØÊ¯ôᕾÖV¯ð*_ô ÷Ü@¾k½û�»ùu�¼zØ&ŠÅ¢WâÇ>ö±M.Å�€€€€€€€€€€€€€€€€\‹¶LÀ—oéòzãÜÛtñíËte¥L¼8íÛÛIí-àUö¾ô¹õµººÊÁZ�TøùtçíÆoâyõõešü§ótêì §i'|¾þnïhãÕÁ-ñ búÕ�ûö鍊nÚGï                  °í4-àëøO.Ðè}•^ ½{÷qÀV+--­ÐÊÊ*­¯op�×­–Ëü·Fkü}ø=ôk…éî÷íäx®Nw…¾óôMó·þ­ƒ¾ä§�_ëØÙÑN;:ÛhçÎVºïî›èÁO½�îýày¶A@@@@@@@@@@@@@@@@@`Ûøö·¿M‡¢={öPkk+µðëýÅ´êªd%àë§ôÒ«Ë´{Oe…¯Å¥-/¯V‚¼x…/ø¥_é¸Á|O'ýÚÿ´ß øjoo÷¾¾Í_'^åWB¶´q¸—ðÕÚÆ«|µµqÐW íÚÑB÷}ø|½_uµƒ€€€€€€€€€€€€€€€€le~À×Þ½{ðõâÉ ô×÷*M¿z™Ú;÷Py½…Wèri•W÷ZçW:n�~O£RüÇ_ïå¾8àë#ïßEÞÊ^cO…_ú5ŽòÓÖÚBm¡Æou¤½»ˆWøº‘~ãß¾�_鈾$'lƒ€€€€€€€€€€€€€€€€l:àëðáÃ�_á륟^¤ñÉ×èÄ+Kte½“–¯´ÐÛK«te•WöÚPäUYHÌ øÚX£qÀ×ÿRØG÷ܵ»ðµJýßÞ¢ù)¯ðÕÚÎñ^­õ–E¼kÏκy ýÜÝ7Яþò{èCï¿Ñ8?@@@@@@@@@@@@@@@@@@`»hZÀ׫¯/ÒÓÅ3ôÂÉKôæ… º¸Dty•huM¯ê¥¾ªy…¯�õ5ºûÎvúô'öQ|uvvò«¯Ð·ž|‹^|å µ¶µG}Ì[iƒÚh�ìm¡;oë䀯é—>v;½ïŽ}Æyø                 Û…@Ó¾Þ8·LÇ^Zà¿ ôµÈA_ŠÖZvÒ:µÓÚyU¾ÔÆ:|•éÃðõ¿þò~º÷•¾N¼ºJ£?8O/x_ïÕVe^IزQ¦Ö�ÝvSÝ÷áøï&ú™ÝDï<¸{»´ ê                 �¦|½½¸J¯�Y¢_¾@ÿýÇçéÔY~�£ÚEkª“Ö¯ÏåÅmµÐ|­¯­ÒGÞ×N¿ñ+7pÀ×.joo§z…¾Þ Ujkï¬|yË‚ñê`ìÕ¦ViWÛ ½ÿ];è?z+u}ð½çö½tþN£‚ø                 Û…@Ó¾VË´¸´J/Ÿz›~ôÿ�¡éW/ÓÂb+•Ê�¤Úw‘jé óµ±±Á_Wè#¼Â×gþçø•Ž;©µµ•½Vhô‡é_~ÊÁ]í;8à«òJGµ¾JåË´»£L÷+úÈ]{éü*ÇÃwÞ@ûövRg‡ùêÇíÒP¨€€€€€€€€€€€€€€€€€|ç;ß¡C‡Ñž={¼8«ÅŸF`ѹ¬s0×ëg—èè çèÄÌ%:5w…Î_"ZÙØá­ô¥ZÛIŸ·¡ÖéÎw¶Ó¯üÂ^oÅ.]þ«gÊôÔ?/Ñ«gש­­ƒ÷ðÊ^ÖJ+´£e…Þ@t×;é#‡n Ÿï:Hwܶ—Ú8(¬¥¥Ò#Øzš𥫪ƒ¹––Ëôæùe:ùêÛôÜ¿œ§™×.Óü… º¼ÚN-í»©¥c'ñíÝÝA·Þ¼ƒöìjãß-t¹´Áç­ñ·âŸü ȵ­/Ÿ§Ýí%ºõ@+zÏ^úè=7Ó¡÷ÝHï¸e·—Á^[OÁ €€€€€€€€€€€€€€€€€@ã耯Ç7~…/_ÄõuEWV×èìüezñ'oy¯x|íl‰.)ZYë¤Õ�vZW´¶ÁA]ª•×ñâW2ŠUºZZ;¨µc7­¯^¦òۯѭûËô3w {?xÝóÁ›é¶[÷ÐŽÎv^L$ò Ç7€€€€€€€€€€€€€€€€€l#Møò^Ù¸¡¨´²F/]áÕ¾.Óé³þß2�»p….-•i¹´Æ�a´¶nÒmÛ±Ÿ:nx7¿÷q�VÞ:I‡ÞÕB¿öÀ]ô³¹•nÜ¿ƒvílçwQ¶àUŽ&6ü؆šðå3Sù¥ƒ¿.ó+ϽµLgÞ\¢×Î\¢y~Ýã¥Å+´ÌaW®¬sÀ—>OQ¹Ì^WÖ¨´¶“.«ƒÞö*¯ðuï¡]ôÙ߸—îëz§äÕ‚÷8úˆñ                  °Í lZÀ—樹*¯x\÷VüZ.•yU¯u/¸k�WÓÇ6ø[Ÿ·¸t…ÎrPØÌ©·éØKé�ù%Ú(/ÓÏ~øú܃÷Ñ}÷ÞÆ_x�ã6×OT@@@@@@@@@@@@@@@@@@ø›¿ù:tèíÙ³‡ßŒØJ-lÅëp]½�.^KP øZ¤é—ÏÑv–N¾rž.¾]¢»¤ßþßþºïgÞuõ„DÉ                  pø_{÷îÝ_š�úZ[Ûð^ãxæì%:ñ“7éø‹gè¹çOÓmïØG¿ý›£�þÜ»¯.                  W�€ø:|øðÖYá+ŠB¯ôuæìÛôòÉy/àkßÞô©OÞC‡Ý=¿A@@@@@@@@@@@@@@@@@`[Øò_z¥¯ÒJ™W¼W:¶·µÒmïÜOûöíÜÖ ƒÊ�€€€€€€€€€€€€€€€€€@”ÀßþíßÒ¡C‡¶î _Q�ñ@@@@@@@@@@@@@@@@@®Wøº^[õ¸æ耯Çc…¯k®å 0€€€€€€€€€€€€€€€€€ÀuG_×]“£Â                 ×*�ï~÷»tèÐ!¬ðu­6 ä¸~ àëúikÔ@@@@@@@@@@@@@@@@@à' ¾>Œ¾®ñv„ø                 ×|]�Œ*‚€€€€€€€€€€€€€€€€lãããtèÐ!¬ðµ=šµØÎtÀ^é¸�[uØ6¾÷½ïa…¯mÓš¨€€€€€€€€€€€€€€€€€À¶% ”¢¿û»¿£»îº‹vïÞM­­­ÔÂ;Õ¶­1*                 ×(�ååeúÇüGºóÎ;i×®]øºFÛbƒ€€€€€€€€€€€€€€€€\fggIÿÝ~ûí´cÇ|]mŽ*‚€€€€€€€€€€€€€€€€\£þéŸþÉ òºå–[¨££ƒZZZðJÇk´-!6€€€€€€€€€€€€€€€€€À6&ðöÛoÓ?ÿó?Óm·ÝFûöí£¶¶6|mãöFÕ@@@@@@@@@@@@@@@@@®aÏ>û,mllÐÁƒ½×9z«{é¾Õ#� Žš€€€€€€€€€€€€€€€€€\›t°×o¼á­ì¥_åØÞÞ^y•£^ÝKÿqµ”Þø­ßú-úÍßüMºÿþû¯ÍšBj¸F ¼ýöÛôÒK/Ñââ"½ãï ½{÷zÁ^­­­AÀ—®šðå×ñŽ;ÞM<ðýâ/þkú¹Ÿû9zÿûßï%ô�ã@@@@@@@@@@@@@@@@@@ ~J)*•J4??ï­è¥½ôëo¼ñFÚµkWì¥KòVö’+|™Åë0ùQüCÄ…µpÄG�ñ¿ÁI­œçZùͧ{›zWk m¬oð~E,µño/âŒSo¨u>¯•—S^^mú,N£+¢ü¼9#Nâ}6xÿZy�:y‰2}xu�Óó-‡'!'nioåã­ÔÆéô>ýÙØP´¾±NkZŽ��ª˜-´Îùéz(-ñ~]'Rœ�jå|9�}ï\ßÐ%é´Ù¼úiaõ1�†ÿYçãm,�þ_ ØÎy{r^Ñœ—®ƒ—Š¿õ•3õžÊGïñ~U²öw󷢯|å+â76A@@ ™€ŽüÖŸƒ&Ÿˆ£    CÀ÷'n¸á†˜3°;‰Àìì¬wþX<¥sçÎyßûÞ÷ÆŸ„# ° ÀlƒF¼Æ«àÛ[ŒI×xCÖ!>t xÛ,)ta›5èuZ_�qq�*ª  L@=%}âŽÛöË}iÛ¶ãþ¾¤oy,º­·µµQgg'íØ±ƒvïÞíýíܹÓÛ'WõÒçéB%ò( ¡ÁøpªAIœHqà’Þ«8H«µ•ß ©ã™t�ï¬dè…FG>éÔÎi¡¼@­õu/à‹Ïöâ¡6ôñj@Ô:GCyÁU:VÊ‹îâ 1ÂòÊãÌ[;Ú¨]—Ïyè ­Jˆ—>Î!VüShµ¶r U‹·j¡>¿³³�ÔšÂâ°*�tÒ Î£¼¾æÉ­÷êüÚXþ >Ï;MŸé2½šrP˜NÏÁ\:0MŸ¥ƒÇôGŸ¯ÿ÷Aê:jÑõaÍC×[×uƒÓr¸——F§ÔûÖ«yxé#|~5;oÓ BÓ'{éxCéP8¢‰‰ÿê}ãÈB`aaÁ;í¶ÛnËr:Î�o½õ–·ïæ›o®9†é^~ùeï$øcñ¬Îž=ë<|øpüI8Û€ìÁ6hÄk¼ ¾½Å˜t�7dâCꀷ͒B¶Yƒ^§Õñõ×ש Ú ×<?ΦQIÊÏv,mŸïÌ33 Ã0 Ã0‡”꺃±—Kè×Ãɰq!@0FÊ+ýzqIµº+¦ROªcd†a˜ÃK~â!àò2ø¡Mr<2a€ñ¸ž.ÁÝøõJ¿ØPªlzâëºgWï‘j„ÆR+Ã0 ÃθTÐ áÜ‘æë?¼.ç½ñŒ#3Lœ¹é1–úd =¦Œ¶LÆ2Û)/× °ˆa†a’Œ%?]ÇÝ–ãùSœ¸¬œ¥­ƒEqÇõ3Œ¶H¸×÷[¢ó@KBŒ Ã0 ÃìÇ’Ÿ.À¸iG[îœ~®óN‹ÚBƒòÅ>ÅUjõÖ uU"cd†aæÏXÍOç¡Áy≠îÌý2ÛÆÛ:ÓÀêÝòîŸ)*k4ïà†a†iNu‡ª Î�q�sFg€# Å¢~9ÂÉñŒ‹a†a˜Ö±ä§sðeÇZï˜8Ø8²K�`„Nj::^A1 Ã0 Ó6>Õ$6ŠÈ™aÂùéŸ-ûþµÙY(õjúÚ‘ERÑ9#,î=ËqË{?¿|õ{ßs{<ÚêÖÚ;¾¿ñ‚ F[NŠGl„Pªê´N'�G{ Ã0 ô­[Ouè”NxÿêìŽì)õlí8‰GüèžÒÐóF™Ï÷G‰´©L]M((M�3‰Èýúåîw{¹„„P—gÊ!„МÕáEËŠcßuµ-†a†aÚ§Û<[œï�œ½©©¨=ÇcŒP¾Cp½x‘ë‘/r½—cçú7~�à ^>ÎzëqýŒƒ1n9ñ!„RM§¤½qþ¸5º¾½Ç2 Ã0 ÓuÝ6ùŸm=oŒÓ<2\ʃA@ÛYÒl0õxÛùo^‘õQ¿la B€' 0N½ç ÇM­�K¥Ê”²ˆBê5jŽN(Ù^¥¬l_d Ã0 ÃÄC·özü¨¼·‹,R.Õˆ†Àà"Б¹Y}²„¼‰ gø£DßßxÖóÓ\�fÛøŒÖÎYZÛPáÓê†Jíêmú}—¼ûퟂO zû#c†a¦+ºeÁ³UÀýûÛ ûÑJŒÙ:Üí�€�yRÁ¬ËÝÏc@HàQ«‰âª]±â—ÿóR÷ímÿ‡­Ñï5�²Y^ Ã0 “DÝrØ+Ç(ôáyÇô9Þ»¯�`¿©G&ïnïy!™ÈËKäoâÃ0 Ã0Ñ-“Ÿš¨æÑ›�A…@õaïá¡ý+ñ4¯Ü§yïýÌsÿˆ"iì”Q–“[[û§©âJeïÊ]16Å�a†aR [ÎöªŽi:mi‚Ð$§¢½ó@oÿøü÷]òw]—½ÈfÂæŽœ»Ç£íòEȾN_¼ûáxÄ€Ðæ‘)B€ÔJü©Žƒa†éºn™üø­X§´ÅMJ©†À¿U€Ìá p†Ž·ÿýæÈªYKü�Ÿ4ØxñYÃÍGwôü�eÊ^`»¸À!Î}u¯k¾wKî>©Ž¥%‹ª¾½õwïï¯tô¼^ðFv�{‰bv¼b©Ñ´À.M©*W•òݪ²þ÷XäÛMrl ¶G\{Hõý½ç€âT\{u,RrMå¾Ám}!Ô#ÆÉsNîóe²âjMUT+?vÞÖüTÇ‘j“F˜oþðÚìÛšý{(« hÁmj%€¢Rug�ZªÐ+üÚ.�@4¦ÒÝ;kTÏîZµ²: Wb¤L'pHÞvËä‡P.«o<»‡ýø–ŽQ‚%تБå`ŒÈÍñ>‚1î<­õŸ[â4s6ÀS–1�àæy››çm`0õ#”ŽýÊU±ÈêÙ�ºÖÆ¢ó)@‹‰?Ã0LKrl¼5ÇÆ[=5¸é1Á‘#2‰Å4Ótˆî¨R+–G7î®Ñ¶”ù´5;kÔJoˆ”i„“z‡¥2ùÁ"—ÛÃ,Ž>ÂaÛßn((0 ™›}±²²°RS”7WEµ5u²Vш¯£‰Âo5áŸZK~?ä-Ì…:´§bG'”¼óSà³õûäÿ^rŒíî±}¤A‰©Á£,§¬/UþeGtaL¡•þ(‰DQu¶îO·Câ¼ÀÂ0B(ƒã-'™mã‡IÆ¡¯ÖÕ¾47äšÈ‰º&Ã0‡/«KV–ÀÐ'KèyÚ0Ó1�(‰•Ô¨U~m߯%òºï6E–Tø´Õµ!âQuJiàM¤$ùÁø³{Øo»ª¿ëÆAvCOÿ±ñÄ ¹$�a�È«j#[·ùc¿}ºËûÅž�²¤¹ÝÖ›S�—ù-bySKÇP‚ X"€h§ f´�sìñh5ÿ˜W÷p†‰ëqë)ö«ÇÝnçxý2÷Cð�?B¢Ë”Ò]5ê®=^uó×kÂ?n)WTuZ×™¶™ôƒÚ] ßY¼�ù°+ça€Î ùgÖÄ0LÙŒØ0¢Pê õ:}˜yüôs3oÙS«y–툮ú~stñW«C_Dº;Õq¤ ù1r8ãšÎgo’}M[Çšy,�ϱ Ÿc~í×µ;ƒrå§;½,.~µ7¤,‡Vî¨7x£ëKÃê>»ÈhíTGP·AÇpD[Ë7è¡‘øÂóD FvßszÆ ƒóÄ^mÅßv6Žëgè7®Ÿ¡œúÀÙ™·ûÂ$òáòÀâÏ~¿µjOì;B؇Ó>BÜîÜÇdJꇃo°!0†aR©ÈÅ;‹\ÖS/:ÚzêÛWe=÷åÊЯK¶F¿ž¿>üm…O_“ª¸’=Õ�»$Ç1ýú¾îË;sro«”ó·a9w}:±×¼'FæÍ9Êeú‹€‘­¹c£:)_Q^ÝžvõX}´iù}Áúð’o7D>̱sî?Ñ~igâo¯ 36Ýx¢ýœ¯nÉùôÕKÜŸåÚ¹ƒÆ]¦5wdf=2Ò`œ”ê8†a;o”åè.r=ñã}ù‹^˜æúrÂãù ç$;ޤ&?ù¼pä\ÆTì�vrŸ #œeÓúdžóÚ1…>12ov_›t��±É¡ô§ÊÐ"ÒÎ ©~ þ­è2´Fu@ <¿È÷¼¬Ñà%ÇX¯Î²qŽNß#”iá,Wg;÷•KÜodš¹Þ‰¾f*)DQ¢È‰þÒˆÖîÚ1J)U‰ªì íü}ghç/‰|ÿñ–Ç ®[îDzy~xªca†iŒÇ÷ÈÜ×O´OþôƜ޿6ë󳇛o¶°’T&�Ôa¯³,¶kr9![­$€Í8jW¡qK\ÞvA/Ç9)´Ÿõùnß×ïïð¼\�lx}OHù½<¢z Ì¢³íÖÈ uëEp W€ëŸ%„Ò7 |²©Lù9Ä‹®Ÿh¿¼³µ>�uÖpóq÷œ¡>yÿçžiɼn²J|‹«Ý+`Ñr` ³á碵Ç�“TÔÆ± >ÿ¤¬“ïqI®¬öÄÔƒþÿUÿïÉ­�-oiT;ä¦sŽ0˜Owæþ릪}'€@ªãa†iÊnÄÆ3�0�;óó¸eÅÑg- ¼6wMx¶ªÓ„þÍJZòƒÄÉ–Œó€(» ú#@Æ®'y‡ùi½“'ÚNÿj�ñ;Åž'÷†”UÕ1­f{@ÞѾä§>JŇ¡n�CUà�öz5Ï+ÿõ?E(�ÿ›`¿#ßÁgt9àN¸v‚휿ôd꼩¸~"Q ±²hY¶ûÀ›z›ûL;9ë”;3ÅÌ6·!‘‰[ë[ûÕO5?Þ/y$p¶V¢c4u£ÃýÒ›¾Ú›JÃ©Ž‡a¦%ãú�émxqs¹rÇ_×ÍX¸!ü¡N³~YÒ’;憸8î@â@Ue/±,v=Â!«À›.î“yÎIyÖcÿ³Ë÷Mq ¶©À$äu¬¥ý ÐŒ½eí¥Åþ×Q²§_¶0ú¢£-çu9ÐNâp‡2tB»]ò“H6Þ6ìç±³;ÛÀZœù@(!û"{×ÿìùù齑½ßèT�K²�È©îmÁ¡KlŽiÅŠ¼nq8ðO¶¶Ã0éLà7¼‡ÔûÝ«³^Y¸!|Á³ }36–)?SßÉIK~úˆÒ ܤÆHRP+ˆŸa>ŒÊ3‰Y· ɺºó­ Pý6-ƒ½ï/ ¼hÊHËÕýÜb©Î¡Õt¹> xxJ ûàj/Œ°©—¹×”‰îÉ–²{"Ôò+¥”FôHp…wÅ»k}k^Žè‘�ñŒ%YSÝ[bÂXº;Óý@…¦¯—£óS Ã0L{X Xš2ÚzêØÞ†#Ÿ^à{ý“Á—#Jünþ“–üô¥\+£ÕR@1/¥Ÿ‰iD}mCíËQ•V˜Å£Î²8Ï©Û(€`#õ_&œ±>QéHÝRãã «Ðe-ŠA "Т´-ŒA� øµ:\"ëto¼ßgwdäŒEÇdûè˜Ì1ó˜oñgœî/†/ —¬ü±æ‡G*b “ereó‚ë~gö‹7W•îðèÚ¶TÇÃ0 Ó…N!륋]Ma:ýú÷k®­ôëâÑnÒ’ŸlŽÏàšI~€¨°€s hå=©~¯ ¯þ®,ðÀÔ^ŽÛ²¨”«F«ÆîãÀ›(p œ�â8c}Fƒ  :º�yªÑ�A ÅPý.ó �üñï kDýt—÷�¤¼ñC\‘©hÚ)Ù§>‘-e÷j­· ¤‡ü?ÕüôÜÿúŠÍ5H”úLwå̾³ºì4•R_ªãa†i#|ÚPóØ%÷Šßßý‰çÞÂÑv.xÜb›ñ ®K(€²�€$r€ÍëII„¨F”J¼ïÄtZ›)q§ôrLÂ>HÑ�…jj�hºA„÷N€vþMmôŶ.©ý§Ó $,å³»þx×ñ·šyK³k?5Ј¦–EËÖ/®^tu¬z zX 'b„Гe̵vç£où=÷©”²�P†9dôt îW.q=—7ŸëõîÒà �ÐHgÛJ�ä  u�zs€ ©Í~–V…VüRþpSz9®Í”¸V?L›·¿7§‹ü²~qSÕŒ ª³!¯æ!‡àyBÖÄgZNà×ê6µ-\Z»ôÕõþu/ËD®HV�éäR{æuÛUyÛ÷áà,Êö’cæ’›Ág>7Õy¿IĶYKüÊZçö KZòãÕµ¡”âV†"H¤~˜ÔâS—ÍÚZóbT'Þ ‘+œÒÓqqk1'Ú³«^X^þ%¡’ß?/ûüÒUu+§§ª¨9ÕSÝ[2@4ô½Ãá~MD(% w2 Ãt…À!îšñ¶É·žl’ǨÕuÜšJZòãѵ *Ðv/R¤VÐ<:»XgüZ^½Òž0.ËrÞ0‡±ÕáA%DûxgÝœ™«nŒj¤Ã]yÝFXhxÍS>écé{ F¸ÅŸß˜ ÿâYöîe_L.�–-¤øÙ;\páIVû©çYíãRÃ0LG,Ü{VÆUWg½#hõf¸±¤%? ôßpè÷vŸ@”Rz]r’Ÿ˜FÔ�J¼¯ Q£Ì‹ûd^šì=¼þ±®êù¬«¼2¬u¬ ¯»±˜5Î9îå ¦¼™)f¶ºp�\³÷?¥Ÿýßÿªÿw­Bä²dÅx¨ºÍ‘uç &óe©Žƒa¦3DóÏ^è|è´¡¦‹Ú{NR?ÜWÅ"ó´v}€^?^ó%vB ¡”.¯ ÿ¶²6ò=ÀÄ\ëyCÆA ½hu²º}ž»>*ñ>¢ÓÎOß뎂cì¹yçÎ9Þ5¾ÍU»×úÖÎû÷Þ�NßÙó1´ÿg-�Ò±æ§13ÆÒí™Y�  g¥:†a˜Î0˜òçãý³…qí9>©ÉÏZ9úK­®uh(§a0MܘN)ùp‡÷ݘNjn‘ýJ#�Å„\¬%�Xé#k*î™·×ÿO�R9Y×MwW`,8çü‚ >ìgé F¸Åbù°üPóÃËßV.¼<¨·@%éZóÓX‘ æÝçÌžaÃ\¯TÇÂ0 ÓƒrÅÓÏÍœnÛ®cLjò³WUVoQb›;zUb;u Ê[BÄÓZO´xµ'2 §UœpBŽutü¯r0B)]ç�l»å×ÒËæïóÏb³ºþ€ÙÝ8¥à¯ärú¶´Z3¥”zdOÙ7_ßòsíÒ;4ª¥ÝƯéÞóÓàÉ0øf‡k¦€:V8È0 “.Nfšð×Ñ–[Û:.©É�? øÞP;2ôÕpn@ÞI€*ñÿ™]â™Põj!ÓõÜ·ŠnwÑTgi„’Åe�Ÿ.ùq÷©Ûü±%‰¾Þ¡DÀBÖ‰Y'½9)÷œ™fÞlmé8J)ÝÚºìý=ï�²#´c6¤é‚}‡BÏ@}ôT›ãÜ ¬#€¤õ|2 ÃÄ‹QÄÂŒ)®¿åع¡­—ô‚ÞõrtÉ/ÑðŠÎœKÂä]¨¿¨<¢x—?šoœ’o=9n�· ¤’Ø{;<ÿ¾û·²ó"a+77bãmý&å�óÅØÌ±ÓZÛ”T!Jl™gÙûsËçžÑ#[’cww“Ãuó“å8D’6†a˜Ældzð/™O\˽ØIßÞ"DHÅ¿uo�3š�æ›Ûè´ $DAÞC@*€„®ýmÖ%³‹½ok„zw^QÆÿÙE>¡]þAU�¼²¹úõK¼�Ë:íö›ivvŠÎQgäœùF‘©hxk›’ªDU—{–²Þ¿î K6 K�Ø~¤cd"{TR¿‹[wgÜùf‡ë¡½ªR¼SU–¦:†aþLѨŒ‘�S!,ÆٌؘŠΉ€1BSF[N{già„Õ{äÍ“’½½VÅ"_þ ßz´Ñ|dg¶ŽÐ}dèzTQ+¿Ùçÿ7€ÓÀ÷™˜k=¥Ó�µƒFˆþ÷•e/* ²Âæ&\¢ëØÉù罟mÈîÝÖ± ±9c uà©Éˆ `¹ç—‡76¾Ý™s•šŸÆú‹†ž8³_¹±ªôT™ÒêTÇÃ0Ì–n‹m~z¡÷qYƒ¸Ì æ0à^.Þ)ñHyœo3¢¼Þn¡ï„ÆÁ¹œƒÃˆã`ŒS½íxûÙŒØpÇ©·_ónõrY;xû‹”$? ¥�×|žGL_QçWÓ}dJ@ì‰w2š¿Ï¿¨2ª®8>Û2yˆÃاS µCD#òck+žYXx�m&ùgáÌ¿äMšÕžÄ€Ç¼à]IÝvÄÈ;Ý#x¨Ôü4u”ÁtÄÎì7žôT]"SNu< ÃÔ+÷kž;åo-~;,ßÑüó6#t|ãqÇ÷7Œßßxˆ"©(^×L´S†�Ó[š¸t{ì˦¯¥¬‹kƒ]üUÈÿ éB·�î§ ìé\ PMLó/,õ¿À#dŸÚ;³Ý‹#uÆâ²Àÿ¾Úã{–%>C€D‹l…á4ƒBgšmgO²Øÿ†Y4ÖQ²eþºð[|á¹~ÒKãÎ}¹âÆ…ÂKƒQKulm±›8ã•ÇÙþšÙS4eÉÐfû½O•¨òž®´£ûêk€¨FÛ= žPJWT‡—oÈëF8M'õ³I ëõ *zì“�Þ×T¶O×aéPöj bÌßìpß6ÆhžœêX†I�@¬6¤—-Úyý¢YUçN{£òÊo7„�*$­·š8Ð4º§KÙôù”7•iêš7}ž™ !ZWÚÑ}›†Bï×¾¥íOFN/°]f9sWbh l ŸÃÖ¡:ìÕÀÁqö‡œÙÏ âˆTÇÂ0LêÅTêý~sô“óÿYyò�{õõ´½±Ï²aÇÙÃMmRžòÊîÿEBï}¬ûOWÛÑýä:è‘Ö B)ý¥:´±8 /° \ß+ú9º{»Uà  Ï}m„ÓtF`Läµ&zbþCÎìÙBY©Ž…a˜ô@(„ß[xòøeÞ]›êxšƒ1B—g»š }¥<ùQ) ¾ã÷þ}‡ÛÝÕ¶Hê `Ë[aP tÞ>ÿ‡�øw~ÏŒ+»zÝöâ0ôþ׸Â÷?›Ø{ÅÅ}2ÿ1Òi:Å"àBhf,’aÒÑ(ƒiÈM׳B–TÇÂ0LúØU£®ºâíê©ßmЬ$$AûPuÁÐ|1¿ÐÉÛø¹”ÌöjªN×÷<᩺÷ù¬ü7�oïJ[Tˆ•è õÀÀ9þóˆCP#á¯÷úÿ 4CäòOɳ�Û•ëµFeH¼e„Äá4 (úíÅ�Ø®’ ²éÛRÿÿv•¥51­<¦?fEÑ„’º• ®±˜¶Û*ÔÊ5Þ–¥Á¡\óÓFMµ:¦•(ʦoBþ™ KÃÕ ÃteuÚ¶ëÞ«¾xöµÙŸÓ×0„K³5ƒÎi>õåïü?Ãþ¿Çi‘ü]‹~ö¾ß;úV‡û¡®õ†hònB ƒ�€¸? Ovz¿‰jdÀÀ à c³Ìƒ»zçØDÎx”Ë<ø(—yð_{9¦„5]^V^»Õûeî^ß7{BʲÃe¯/ TÞÙûcªãH”C½æ§1ÆÂ­÷ý%ª¼u£û:Õñ0 “>*üúö+ß®¾øëÛr¿”'öLu<��îi8^â6Y«_\8­2³�uOþ—Æ(€ZA ¶Cß¿#<€WÖ‚ß•>ÀŒÓzg^—kÅ�™ç¤Sómcoì¾}Á©}¿�wjßâ«ú9gô¶JDz}–˜tâæùŒG\93sùƒgP0 sx+­Ó6ÜôAÍÝ~Í—êX;®¿a„Ëʹ'<ùÁf#Ây Å *Ȕ־å÷ ÄŠuЪ lóĶn¨‹-èc•Ž:ÒiJ»?Þ!$qXh7>pdî½³Ç÷œûâØ‚oF¹L“0¶Î!¨» {5ÖG�zÝïÌzMB(3Õ±0 “^~Û›ÿöO��RGc9vÞ–kç†7Ö÷¯T;>Çr^¾Ipµunªåš×Ù…§þk\ѧ–ó¦ÛÀ÷�n4Œr8èNÃ^ x„ð &ëØ+íΰh†aÓ Äf- <·Ï«ySKccûŽnø>QÉ:Îd¾ôå¬ü÷N3ÛN;Æd1Ñl™xƒÃ}Ëgy=½œU°ô‹ý ¡Ü¦'u~(ðf<ƒ!”Ò­1yתPt€€�srFÆdª:7äV‘3\;Àuéûã{~7(Ã�´=­¦5ר3¯>Éd¹ Òl�a˜Ôò†ô½o,ñ¿«š6xNj…H úƒeâLǹO~„`é Âe!<Æh:Ý•óÔâ}¶Þåp4Ê`šlD¸0` J£ãF-�†¾«Õµ�ãŒæ¿dUsyÑ�:È»uШ~h$Bì†^oŽ+œ=(ÃpfªcéŽ8ÄeqˆËiú…¥íL´T1æïÈÌzøÉ8)Õ±0 “>(yççÀ[¡I›}�"r™DìHÐl/§ä<‡ôتKhˆ¶ xÐ:†C;8Þvy†ó¢É¶Œsk5­Z£4ˆÜ—ÏxB´oC�O@Ç܉&Ë…„Eªhµ´: Xà20p6Ø‚tÝ¿6Ç(¸™7sÚ»–jlËŒ¸šÚcÚ—Þ’Óôùeže�oôox¿3mvÇšŸÆryÁù +û™[ªJKª4mCªãa&=Ô…ÉöyëÂ+.9Ævrªcp[9·ÛŠÝa™”&$ùÉ‘rG`Äá\°Ò ôÔwnåï¿ s&›ÈõLD,?EÃ+Ê5u5€ã§šm'þé½~�D!&˜[a IDAT V`Î ÀÙñþD¥Q&„B#�¦ãs,ÓþWŒëa*`„3NÎ:ùI›`;h§öÍ�ÍŸmlþ,Y±8Eg‘M°4}ÞÈl�m³;Öü4Õ_�úþ=3ûõûj*Î�R· ÃÒè[bó¦�µž˜ëþ8øÌ™‚sw­–˜ž3o²與õü00Ñä�ªD\ªM*!Úwáà'1J€N1[/5aÜòÔq@BH@­Ðx;lA€Í°ˆ€RH‹^¡s­'ÿPœM(¤ýA€ ½Ì½OsKîƒ6—­–k6¦"&¦c0Bh¢Ù:îB9úðl¿÷oíŸI†aâcÍ^yu¹O÷õÈäS>3Ô,aÑfÄ öŠê±PÃ÷ ’àwa§,ƒ êKú-°‡è¾"¡¯L»N4YÿÒ‘ói @�Q€j €°gE€Íõß#éàU¤“Å!ò=ŒŒ²Nûš¾–¾—[xKϦÏï‰ìùo�R·¬½íÐŒPu÷a¯ÆnÎp]_£kÅóC�Âaô¾†iÞîZu·'¨×¦Cò`Q6@‚’ŸªXÕ¦Æ�£`„ß„Ñpœº Ì4’ˆK¶ha(°8JI)@!/1Ú`ÞÖ9Í¢P?<¦@´~,C@|ý0¶ ÀFˆ¯pâk†§Õ¶í<æòž¦ž›>ÿUÙœhG’ŸD8†½ˆ ·f¸,×Ô]kbõ³+†9|EZî‹ê5Ð?Õ±8-\.@‚f{Õ©Þ_ÂZø@ï ~œ«ùMâ:}¢G–Fß7Dq’Ùv¡±µ!¯Ž õë‘H}Ñ´²›@l«±í:È%”=:¨U4?¢P úþ/Òò¦«P´j�€—Æ&Nr!ë.GÖs6ÌõNu, äÐWïQv§:Ž&lHPòÔ‚»w„‹¿oú|—k…á €�ˆË¤D‘‹×ÉÑ¥6Ìg4�Oè)•ô­Oˆö�‹ D×ëÝ Cl›ò.J¥’€æ% (�ªÖ'D”¶?9Úâ�ý®Ó$w¥usèðé¤I¨¡’¡ÿß�Ùop€Œ©Ž…a˜ÔÚ\®ìJu 3ù€ {J¢¿z~}y uЩ–þôÇoîDÀ0Z] "¨‰¸üsCþ¯UJkFŒÇõ¤”݉R­þ " ‰ ýc0Á�ï†ÍW?„€Dh¦®hîÿœÄF}øa5?ñ�B§™­'nWbOÍÔݯQMuL 䆪ÓÄ~ØwB¦žÕÈ5KÖÔ­™K(ùóêŽA·ÕÂÈ„öUišoM,úMÃU'˜,J'§Ë©½èþ/zý•Hxï‘·þK­¤ –“?}-,ö/ ¨ú–Ô¾¦=§šŸÆ8„ðÕÎk�3š/€ƒ ú^ƒÃ°GáPt8öü4°bÎt»Ãý÷þ¢t|ªca&5”4œ‘œÐE‡‚ZpóâÊEËDnö�oáÂzþˆ¸÷Jé7!ÿµ~m8Ël›šÉqi1Í.„ƒ WDÃ_¤:¦}מŸ½E©ÇC®œ7,÷Hu, Ã$_†‘ËJu M%|ÅÅ]‘]Ÿ.÷,oab;¸>qóézhU,ú€€�ñh£ù,¡nÑí¾IŽn{ßï�N�ÍòbÃDC¿ûœÙoˆ9R Ã0Ée’P§WÈO”„'?„’è ï¯O¬÷¯_H›™ÆD†½¸¬å‡ƒ ]Ÿ…N(¥‹"ÁE!¢×80×o¼Ñ<¦Ë §¡”–«jÕSžê;+4•Õú0‡Œ:Ól;m²%ã.¡ä­wÁ0LÊ$¥:†*¡@’Ÿú‹©5ÿ­úî¦Òhéöæ @vó½`•0"е™±*¥ÚÒHè L0Y&§]¡sJi¥®yîª)»j½ýã’CÑá\óÓ�¾Ñá¼m„dÒ`<ËŒ¹C¦¾@!D«TÕš%‘ÐÏ÷Ö”ß~{ué9?EBoÆ(õ¦:6¦óR5ìõyÐ÷é÷‘àO©¸vk0Bh¸d|µÝù¤ˆÒ¯’a˜øqZ¸\‹T¿¥D:ˆª¤ A+<·A/�•/ü¼ôó+§ö˜ú‘™77ó�‚ Œ,°Bô ÐGoßÊØ{Tµd½]À#”qšÙzR\#ï B)Åè�íM›>¨Óµð9º}›,¯Þ«)Ë—GÿÕéú  %?âî¥Ùäº ‰ØÞ"UÃ^!Jjfxª¯.WäðBF*bh ‡¾*ÃyI™¦núOÐ÷ °á\†é–†ˆ=óœ+Õq„e¢c´ 5É­ˆ•ÏÿdßÇ—üµàÂ÷¬‚µÙ.1I°š µØG©«�‡Ö{ð‡ßË”V ¥QE¼Ø7±7k½-Þ*Ë«4 5QB”íª\®Ðƒ—ô.WÕÊ0%!¿®W„)©Öhý¨I¢Ù‰ØÞ"Uœ_äѵíwW—O{5»àS;Ç¥]/Ëm™î‡«t­ò§Hè½TÇÂ0Lü ÍO3KqÚP¼‹Jë4ï>¯êH]ò•±ÊoçWλ÷윿ñ7Ä:ô¢>澓Û:ÎÊ[›M~ŽÉ<öª#§µ÷z&Î÷EøRUó“/ˆyû¿%ßE‚¯ JC.µe^–¬ß‹öê#JE�»r^¿®²ôÄ(%žTÇÃ0L| Î' ÈÓfew_D¯ ˤ Åɪ–„KÞ›Wñ�õœ¼sgˆXlñÎ4„­ð›0úê;`˜¶ñO Ðï±È’†Âà<^8¦—(%í¼@Ýg[ì×þ³®f5@csL‡y£ÉFSªÎ�‡TÕü4ôü(”†Þôy,‡�6šF¦"žÖ!‡]“á|þu_íõM¿}€†é„€?”eŠYLŸEMß%o£’?Õ½d[pÛKßU-~J!ŠÒê�ˆƒíüøN<ª±»act:?ø¤þ[@§›mg˜îÚj‰t™ÍqÅ5vç Àv¯fÒDAt7~$¤ìöê² ·ÉòžTÅÔŒº6Ãyù™fÛÝâ¼ÙÃ0Iç¶r}®;Áv1ÆéÑÓL)Ð¥Û£+§Kòü^ÚàÛðu{Ž `;,ކ�üøoD] ¤@DÈ8\2œ’ì®}ÆÂµÎë®ÉÈ|шpv2¯Í0ÍÉmf†W�è;žòVÞY¥©i9¼t›Ãuçx“å¢TÇÁ0Lçñn˜h¿#ÓÌ¥´×½±`ŒÈeuZò“ñ–|cþ…#G=q”cÔ?ò�8C4ê)ѨæÿÝ÷Ûóa-jO›22Àn �§f,Ö)U¬˜+k4KÐÛh•cñÆ ÷ ÷dºg¹9¾*b`˜¶¬ŽE¿~Çç�¥rÐlÄTsó‚㦠×ÃÙÆzAªãhlùŽè–Úà5…I©ù1óæ¡§d�úÒ`Ûà0®òhù® þ ÿ^ç_û†B”}1=æ i!Ÿ™7·PüügQ=Zܹö•Ž0gŸÏcQ¤ ¥¤Ð‚Gˆ»Àæ8·�( x¤¶òÊݪ²¢í³&þ€È²é@M^Ò¾ùžÉ„>—Û3§¦$¸V ” ½§;sÿuSÕ¾“@ÓØ†IcVΛ~Næ=2ù´YÕ™J·T¨+à ñ5<—ðäÇÂ[M)˜òYž!o`ÓuWòŒy½r 9÷ë<öÆÕ¾U_ÅtÙÓÏÒ÷¤,)+¿½í{TïÞ:µn9‡8‡ÝzôÄyR_p“ZÈ&Uà u`§~’¼fàpÉ8ðŸÙ_O-ß}Tˆ�Ò¤^œa ~Ö#‡ÀªÓƒ…ÒÀ,_íí½±÷qFóèt›vŒÑtÔ�÷KoújoV( §:†aÚ†ŸúðD�ƪåêE©Ž#QÒyW÷JM]õ´·úÁ'\9/dp|Rm/ÆÒí™î¿íÓÔÍëåèüTÇÃ0LóŒʼùdû}wŸî¸EâqÊ—ÐiŒJ?ZZ¬êoü|BƒtKî¡FΘ°==êßιfíþ‡Üëà3Û:GCøPø Ê 0ÕÁD£`¡!0ÓXi¬4f�ü)!j¸…oï§ ézçÏ0?EBï¾åóö»ÍáºKÄéõ‡+›\÷;³_¼¹ªt‡G×¶¥:†aþÌeáú=69sæÅÇXÏy”vK½eûvCä?MŸOè:—èÎ1q¦„ el m[ªS½ÀÄ™d²t¦‚8! „`�5¥€ þ @Œ4 &#�‚*i�hëÃg%zd‹Æj˜ôF> ÖÍpp\î5ÎËRLSƒD©ÏtWÎ컫ËÎ’)­Mu< Ø%œ3i„銧.pÞë¶pötêj°§V-ý¹8¶¸éó M~Ð~‰h[#š¶;¼k^Ã㦣­¼ÍÝÚ9톧>Q0A™ÀÛô8J÷o¶Ú|òC€�¯Bë>cõ LºS(õ½ï÷>0L21Ú`žNÐ!4ÁdsµÝùØ[~Ï=*»™`˜”@„|ßëèÞ†¿\u¼uê˜Þ†#ÒeÓÒæè„’wþGÕéAß M~T¢(:Õuqqï Ûݷŧø65<Î7œ!`!¹ÿ �ÖÂ?!¥”nlþ¹Z©û1©11L'ù‰^ú„§ê†÷r 89>î{œuÕ¥öÌ«¶«òÆïÃÁYšlîÇ0L¼!ƒ ñH2I8{xñ„I#,Ç÷3œÐ?GÈMמžÆ¶V(¥ßnˆ|ÞÜk M~jåÚŠ¨ Yx‹=ÞmWŪ~‹‘X dfvJ¼¯Ñų÷5ßßl¯¯¸ãW€ ~l™ JØPHœìQ•_ª©øÛSY¹/Ú1ŸV³ïÌK÷ff=Zªª;¶*wc3Ìá ƒQ@…A»n Ï!C¦ g##„ûf …ENÞ™cçòÝ6®ÿ¨žÒGô� xŒÒjGˆö˜»&²`w­º¡¹×šüøTßî˜ó'"ùYï_7ö'9DÇqFΘ63U*b;æW̻ѯú7¦:–n@pKî1Æ‚ Œz™{°`€ý5ç”R"“Xxgx×úŠXÅ�%¡ ‚Zp3¤QÒy¨¼ÿ ¿÷ŽÏÛ÷‡ûn¥Wc6/¸f¸s߸®jßiUš¶=Õñ0L*LauÊàÂåñøÛ‚ÆûÏ /ðˆ;“�ƶU*oþàZ(;Ihò#ywµ\]ì’\…ñl×£xª½Š÷§ýñ ëàS9Ä¥|–ŠF4u{hÛÒ%ÕKî©SëÖ¶}Ó Î.؇“yìCý­ý'ZykfKõc&0e%fæÀµríÍ¿Zë[óJH ¥Å‡c:OuoÐ> øž)ľçY3ÎOuWÄÊ·ÊDÞP_›5Ä6ôÔ®¶)9Z«).mÿµF®Ù yST�†¢z4¤R5ªÅG)�R rkíHÊšaœ8ØaöÙκdBƒ3ùïí›%öxp’ã†)£-gΘ_÷â¼u‘·U�F»wwÃ!Î8Î9îÑ !#+^mšŠ†ŽÎuç�µ?ÞL�ªñj÷0BŠ„g¿éóô¿Íáº-ÝV€î)Hù÷9³Ÿ¹¥ªtk€è»RÃ0©A¥ËKb›ž]è{L'ÐæçkRþ�ÕÀÖUu«>ï]Wjs(¥tspóØ_á.q†<§èÚÕøæWÌŸ¾-¸õ �êþ¶�nž˜k½ì‚ž—Ÿ˜k=N¥ U¢|µÇ÷t(Fªÿþ…箾Ù§# ¥³.Ïzö†Ù5hΪÐ?µY@‰fì#‡g9)Þõ[Ã2Ž8oSpÓ{5rÍòx¶Û^‡úÿ³4öyÐ7c¨$ ;ÃbïòÍF¼!ßìpÍ|Ö[}±Ji$Õñ0 “|a…Ê|ίܧmjûè$ÔüP Ê/že�tµöǯú=5±š_»DçÀlCvŸ®Æ·%°ùå.$>$¤’Ð1Y–±"‡y3�¥‡†ç<01×z=@©W[wé›UWíñ¨µ6#6¼8Íùä_F˜oìjÜÝŒ0Ú1ú‹­.TÖ¡íÁm«VÖ­œ³Ú·zþöàö51=Öj–oì®�Ö�ׯ7Üö;Ôf{5'JIí£žªk·É±Ý©Ž¥)!<Õæ8wŠ5c:�RÃ0É%«D½þýš¿­Øû¶½ç$m¿Nõêï«þ{_T�vzQ&�R»Õ«zÔn¸%÷„¶>,Ûctæ˜éFÎØ ºðï±Ú™û¦ª �3$ÞòÔ¨ü§zYÅcvÖ¨¿Þð~Í-5-è¶ñÖ—.r=>®Ÿa*tƒÆx°òÖ^…¦Âq-½ÒB¾ïª¾›ùÖ®7‡YöåI‹*¿½èÛÊ…�Sþå‰oízsôO5?½ÒB�–Î?Â>üTq™‰‰þð!d×–ªjuªciÎM×ML–+ �ß)]_Ža˜ô–‰<}nÝk_­Í‚¬üžÔEŒv†w~ñ«gù{Ñ:\{A)¥%á�Ë % püÛЉñˆëD÷‰w]ÜãâoÏÏ¿`ÞQŽ£žéiêy•[r�1p†ÛU7_'”¸ ¼ý™Qùo噄�”Y²5úÙ£_×Í Ë$–cçï\•õÒÐñ”äÿ‡t䔜#\’»Gs¯…µ°AÅü{~ó®¸/¤…vjTóS 1BID%ªÏ¯ú7ýìYzÇÜò¯nUˆÒl]–‘3:²¥œ“+¦}¶)ò÷¯ÔÕ<"zÚ /Y1gºÉắ· ×Úq*¥•ÉŠ‰a˜ÄQ4ª¿ú½ÿ£YKü Ê+’ú¡K�Ê+ëV>ºÎ¿n^gÖþÙÞ5¿á{3ghlqY<‘Ç<ŸcÌí?È6èŒ3rμ璢Kß¾ºç5?ÿµàÂÿŽÈñF¸]³\4BƒÏm¨º}›_Þݰ6ÊH—y𭃳ž7ò8 È»KOÏZâÿŒJ �BÖ쫳ß,rñ#ãñ>e9Rîø–ö€[áýuvq¨xvkË„eWx×û«}«¿lîgKÂ’±Ð\8RÐÓv¨×ü4A‡ƒ³> Ô}œnëÿô =pf¿""·¢y†aÒ!”~¸<8ïùE¾¿ÇTÚb¯K’Þã ¹öûêÿÞ¼+¼keG òXÙΠ80äU`*8ÒÆ[㳋{3xÌ …¦ÂAgåžýØD×ÄW1ÂÆöœç‘µ÷®,½©2úÇÚ(Sz9μe�ûY„À@(DŸ^à»gÎêðƒòÅ¢�¯Ïùw¿láØ½•CB_KŸf×jŠh‘ðßš™¨ÒžvÖÖ­y#¬‡ªßB!o† ùK¶w‡šŸÆt ‘Ù~ï}߆ƒß§:–æe0ñwgö›BqßV‡a˜ÔS5ªÏ\äûðŽ�k/ DIUgÚHÉp‹B”ò9å_NÝÞù[{ òhÅrY—lKŸ%eŸÈcAH\”82cÄùÁ1 ½ÇoñÇþ;scÕ³�øÀ¾¤�ó¯÷μà`ŒTß÷¹çÆ•»bÛ¡ôˆ±ï+»^˶s}óÒ‡¸3oiöN}[hÛ�2‘+ÚÛ–GñüPýÍÖçò† 4Û«êP"¤ö)OÕuéX�Bg›mgM²ØïÂÍÖ†ˆKv\ Ãt�/¢‡žœç}ó‰oênP4ìl;)«5‰êÑ�ßT|}eI¸d9¡¤ÍM(w„Šht÷�ûXúŸà0òF³„¥¢öO)h Jý¯XâýwÃsfîš}ßh·é€K½Ú¶ëÞ¯¹©&H|#t|ã³.s˜iÆqÝíP aC‡°©éó”RêSêVJZ]_éOç�n nù¹¹×r 9…’¿NM7ö:ÀOô��{ªî¬ÐÔÚTÇÒ”ˆ1³Ã}ë£yrs¯oWä²dÇÄ0L×”zÕÚ›?¬¹ÿ¹o}wÉ w¥­”Ú†´Ð–¯Êç\¼Ö·f~‡Ò=‘=‹8Ãà)§ÙâØD¡¨"�uœ¹±êîÕáÍ ÏYEÎðÔQ3 Ìâ( ›Ë•ïoü ú_„D0Fèôaæ±ÓÏÍ|Å,agÜß@3ñ&�„ƒVéÖ©®UÆ*wv´=¯âÝØÜóq9�‰±+ºÛ°Wcëå蜷|ž™*¥mÞÀ$›ƒãì9³Ÿ/ă†T5J;ôûÌ0Lj­Ü%ï<ÿÕÊ ¾X~­=‹¶%%Éj´GL�í^X¹ð‚ùóžˆh‘f§ ‡Š×kTÛ×𸟥ÿiᤠyQJi�RWÑÃ[:z®J¨ç¾Ue—”b†azZÅü—Ž.xßmà,XysÆ|ïKŠVÿáqíû¤ç.t~`–pÂê™Ò�„E3‡¸ƒþ?uÐ5�âÙÝÑö4¢íhîyJ)Å›;"ÓŠ/‚¾™oû¯8T¼œPràÍQJéîðî � C�±` ‚äìâŽB«}«? ¨�}m}°½!eÍ“ë*ÿîSôc“C2Œý>2÷U3�] ¿ùCà™çùÞixý¢£-§ÜwVƳ‡¬qx i#ŽÃ€ãö³Ô‚þ€ð5}!„Œœ1?^×aêQùƒ€÷ñÅáÀ�é8l¸dì“Ãõ¬€Ð�Y›~]?èçƒa˜ô²¬8º~Ê«—?2Ç{“¢µ¾QiGŽþA@È’Ë ƒN0™ÿz¼ÑrB‘ öÎá…ƒ—{Ä•ótæÜß„ü/Ç(õP jE¬â»¹å_mjzÝ÷ 79£=ªGCeѲ«:KœdwKî6�` IDAT#ã½Bs%dGhÇï«êV>ÝÖ¾^­YZúì•ÍÕCï="û.cŽÇŸ’o¿#àúÇ?·ÔÜU©oæ"ß#r„çŽ0/ò˜¿í”ŒK‚1~q±ÿ¾®u ì‚=S⤃7§¥@¢tx £N‰®½ÙañÕ%Zw­ùi,HHųÞêëú †ïzŠbR‡¤Û‚BS­Ži%вé›�ÿ †)éÊŠî Ã$ˆF(ÙçѪ__âÿ÷GËC/{ÃúžD\'®=?CDÃY÷;³?ø8¯èÇ»3³ïk4�j.ñ°aÎtŸ3û�Û3³^³bܳáù˜Û·²nåëêVÎëášÊXÅʆ×Íœ¹¨ÐTØ?žq·dkpëÒyß\¤¥K‹¢ òg»êžû¾,øsÃ�±€1wë�¬kOγ^\(F*îø¸öúm•J€À!îþ³ÿ7m¬å&„šŸ±Ò]ðˆã1j¦ç±h‹×u:³¶TB�„�%ô@RdÀ†þÆ‚>„RÚ±¨ññVÞ*VÆ*vdŽg8x¨¤“bz,Z#×o løf[pÛÛa-¼—B|g°„5²gúêò[_>¦Ç»¹FÁà6òö‡çθç÷Rïv¿¼dõnù‡;?©�>벬gì&l2IX|p’ã_„x>_zºaÕ£a•¨j¢“Ÿd •6çpöj„._ï/Jý¯°;¯Lu0Mòbþߜٯþ ­SJ8”üE/†©ßšbs¹²óÓßBó®¼£Z]§ètyIGu6ùAY?ôaWÎëGL£b”„—EÃ+¿ 敨Êò�ª¼#HÈ^€vdo é&A}Ì}ÎÂc¯â­®Uj—7~íWï¯�¯õ¯ý0[ʘ)fŽíiê9¾ÐT4!$ X0H0Â-.dG)¥:Õu•¨²z̯ú«¶6ÿP«ø¶"V±J!JyKçÆÃjOdÁk›k^~èÈœ‡D®~ÆÚP‡±ï?ŽÊ劥»O ©¤lþºÈ;OÎóö|ò<ç�¸lŸ1sªó©ª€VùóöØ—‡Ë‡)„ŒœÑÕ£šú/a1£¥j K6 K^J@£ZX§�[ïpöj PêÃçy°— :ÞhÛ´'8•0Bh‚É2ÆÅqY€²/&y4BI]˜~ÛÛüáòÿoï¾£«*¶€ï9íöš^€„„ÒAE±¡< öJ}>–Ïg×§>TìŠ ± **¨`!:’��r“Ûû=mæûƒB åæ2¿µXËœsî™I1wgΞ½ƒþº;ú£7ŒË!ïi­ ~˜!Ý%$¥þ¯H‹Ÿp;îZ ¯òcµÚ¼R Æ�kèy€[rïòɾ½‡\‚cj¬´"RQZ©øn“o0ˆ±h]^’`ÏMÒ$gX}ƒØ”Cßt€ª¥Ö/ûNÑYé—ýÅ–*ÛcÞ-€ïõ¾ØÍÈ÷™Ñ'åꆃƒíºþOžœùîýë«'K* Î_xl`–Ð÷šÑ¦ ¡3gZp}êëW-¨ m®ln€�xÍ¥Y“çGq´EŬxÄ FÞØd®Ð¤ÌIÏŰøxKç²Ö½ö±¢ÀŽw[úº®*ŒqÍã.Çô÷3ºÿÒ�:]Ù†]N¢ç@Q':Œ÷çYFe"ÿ²3ºí—�Ñ%K7…—Õø”-бﻇiqðÓ�N×3Lê Ǿ³CWàcYÝikHËÒg ØÚó>†]˜`D oŒDÃ÷EìH?ÒrvÂɘ„æ9ïéeÖö:=Ý8‚A1¡ »Y&ì ˆÏ-ØíºGVIøö�\×'›Ø¯'žd �›Â§¼?-í�«8®ÛQ-uʾJ­T‚.™HQÃA dBÈ&Ø’l`k·¢�v!©UoÄNLÍm©¿¹Teû£.Ç/¤fÍ·²l»%®SÕ¹…D,–‹{*=ÊöEÁŸ6”‹?‡D\¥â–u^�§?U²´®R–VAœ–©¬¼u˜�·¥`‚qy¸ìÛ6Ü*áANsB ®{|Sížžóu¶AHØ¿$?£OòõU¹|i…ïI!žû>sß�bdŽè©íÐ;�Ï\p}ê+7¿[ëîZiUB?‰v¢b5† Ž{‚[¢t•Ç”M)ŒE>Ùëìs�=õ~ô[ŽEQ‰Œa±> ú=aÕŠç/;#Û×ï××ùÕMµ>ňa'!�'ài¬ÅÁ> îÙë’뫽juXÂÕ�5ÐiJ‡7yl‹Øäž†ž#ª¢Õ«%,�ÐÅý¾­ô¿Öˬé{[¿Ô™ Ç2õ|ʳò޺ê×ò³�1eÇê’Ø7w~ìzpñmé¯7\30[È]4+mÉuoÖ_á «-îÕ™¨Dõ8qƒŸ®.F°÷5¯ûž~‚¶ÿH�aH¢çCQÇ»Õ{bÅ//÷Ï•TÒæW!Õˆ’@ ªº¢2 I qaM¶Ÿ:^uªàÇ.Ø{™yKwL°Z.]Ù¨‹û ‹Hoìv=ž¢å³§äÚ.h8žcÒçŒÈ^xWAÕT�¨”|·5üÖ}Ÿ¹z=y©ý_ngòñ}uÃß¼1å�›ß©¿Ê9~W€��Wò9R5iý=—xèÊ�½D v<êrLŸŸž½´¯ÉHô|(êxVáR+Š"�èÕÿã©SÕ¸HÕ¤�4sf»B¹2R¹*Ñóé(!×¾¸£îžÝþØÞ†c Bhlºqè�RŸÑsL2! ¼õ[à‰EëB?(xGj†AhBýØç¦$Í7ë˜Ô#p¨ˆìÝ–è9ÄKW~ìÕXµ"oxÞãü·KUh_-Š¢ê •À�& w×w;!„ª#Õ{$,×�rZª>ªÿ»°æî·ÇöøÀ"°v]žc½¨>*W½¶Ë9;*ÿ#_yîîžÄgžÑWw2€À!öŠ‘¦‰® ~ᱯ=3$…Ä5'+^ŠƒÅŸÈXö&zGR­*HôN¿FB½ås÷™mO�Í!DËìP•‚b,¹¼pj‘[ÖÜ â…ElZocïá%¡’„Ì!ÁÈ&wä«9Ûêæ>88ý^ÇËpÓú$ÏØ+~¨¼XPKnýÀyëâ[Ó ÈÖôà9ÄÞu®õꨄ¥ÿýà»3&“N×[éh|²oí&ߦµG¿’:žé‹ ï™<^ès¹Ùvq¢çCQT×tà±WËœeK~ŒE(!ÛQ3´§òŒ`Š(áPu´ê·DÌ¡3øl¯÷ÙÏʽ_4>fâYݳ#²ždÓýP¹K.¸î­ú½aõ Už{Ï·]wó8óƒƒ:¼s9ud4çç`"!þ¹^×­ÛÄhQ¢çBQT×t ø10Lê©:ðS´ú+ ãs˜}îX £ÑEÔˆ³^¬ßÔÁãw &¡y;��üêô˜ÅÀ1ºçFd½œkÒœ ¤¨FZyϧ®û"ø@õcžC죗Øÿ5ã óC¨“%³we4ççp¬Ö>è¬�Q.KU‰ž EQ]Ï�àÇİIBÌM–¤™6­#'Á"V“¦MƒB5±Ú�2–�Û�K­…XŽA‚�cz˜¶×FWtwãó B¨·EÛã¾Ai/š6àÓ‚Ðü«ü‹Õ¿ LF÷ØÅö;& Ð_�:YB{WEW~šV!K«_õ:Ÿ`õ¸ÌS£(êøu`u _òFèôCÇë�7, ùŸí¨IðŒ�”oÌ?`wp÷òŽ7Ñ€¦›Ayz†qL®Q3zlšqt®IHi®Ü9YæqÕyÎ3[3TBBÿ]æ�mÓ3¶gX.j¸Æ¤eôŸÎJ{óŠ×ëä;"Ÿ}óM(ºòsd+ÂÁÙŸs—=õ¾DÏ…¢¨®ã@ð“Å É ÿ}�Å6­ ùÁ¡È›;b)Bòé<ÃóA%èóHî?�þŠãB É1j�M5\49×69KÇgXÖÈ2è˜Wi®ìi›ìß«;�ÿŒJÄýŸo½÷ôÏzŒÉ×f˜ý�“^`øW®N~qú{õ‘ß‹c_ €¨Î ð=—ÎñyWšm“=Š¢º†o¸«£¡U Ù_.;Ÿ×äN6Yn‡Žù‹•`p€[t•ùd_eŒÙá8òLš±�Íüè�qÝ—>vr惃lº>v-gnIà eazß”›ÎÎ4Oc°õµtæûÎi%uruãëz$ó©/_�òò©½´tW ÕiÅv¿îuÝ»MŒcBh�NQTÜXùÙ‹~³&Þ8VgÎ!ÄL1Y/[ôϯVäõñœ€À)6Þ~@]¬n‹ŒåºxŽ×Ñ“m†ßÔ;éîIÝ,Ú4œ¡=îkäÍc'g<[ñ›XZ.sÊ…·}è¼ï£™i¯¥™9kÃu}3„ns¦&?Õ|Ǿr—²¡=Æî$IJˆ5jYmo+oímå­6Á–bæÍ>ÿŠHå K�ä®È�*Q«U¢ÊÐ�õ¬hÎÏÑù°Zþ¸ËqëéÝ?·³¬õ诠(Šj½ÁOŒ�Àû~Ïó£µú„8Ë™oµ&?ú¨Û1Y!DŒ×,¼¥[¦6³�¢`Ñr8�Þ(X„¬Óû$=qKß”i �KÛSºŽ·½2ºÛ7ýQqiuXÞ²º$öÉýŸ¹3_¾:å)³îïÚCºkr¿øgÆ×_¬9×áW··÷<:kì£{{�—©Ë:«·±÷0žáù#]<ÔzòA;bŽê½á½ÔÆj~+•|#ci_¼'Ls~ŽM±$þüˆ«ö�§RÒŸ·2íóGEQTSzÜR‹|¹!=Ðfà\ƒéÜ|^83ž°òÖ‘:N§�*ш_ö¯ŽçXp'Ùuç¼5¶ÇŠ»¤Ý�À§AO“&÷±¡¯›y6 à‹Âðë/üè{ýÐëúe ™ïÜ”ö^–�;)^s‰'±Ö\Cî”+º]¹ú†œ¿;+uÂÿ 08¥¹À§)éÚô¬S’N™:)ãsoÍ»µplò¸×l‚}8ÐjÃ�Àêhøý^÷+ �à)Š¢â�0p†!€0€¼(è�Áû;l Ã]k±ß¡EŒ=Nã£|cþx€=á=15vÜ÷üaÒœ�ežùÂÈìwOK7çZ˜ÏÓR Bh\šqÄ­ý’ÿÇ3È ¨$òÊO¾§?+ý„ñÁùãûé†=?5ùE³ŽÉŽçœÚ—¬I>íÂŒI^š9ùÝ|cþ(=«73ˆiÓוc8ÎÄ™RÎH9cÖ”ì)_Œ²�zFÃhÒÛkÒ�ÑÇ^ÇN%$öUÈÿÒáÀO‰ž EQ'. ß�?UÇêr~�†¿(c;.8[o:s¨VwÁ^ß&âÒ2uY!Ä):ÿTˆ>ú«:/À\ÙÓöÄ #³ŸÏ5i2Ûë¾î˜Z[*9ôßÞ äà†»¹wò—çXg#."×�Ÿ¸¦oª�ʽ×Côg¼teò�©½æ/7È2è¾kº_ûÍ Ë  tœ..•«S4)Ý'¤ž={Jö”ïí‚}l{ߟ>öj™Æuϸëf–H±ê£_MQÕr@š6½—ž3Üú§{ͽ2!¾>÷œ�í{Z†áµ Ãϲ%Ý»EŒþÁ¸¶=OÒ$÷3rÆL™ÈâžPÉjH`SÕ¶ÒqŒ}Zï¤gï�6ýX_ƒ ! Bh§/ºo—_Ü’ÕÊ�îHQ‘/VRU*"*®S09j8à5,ÓC`‘‰AˆW Q¼auïMïÔ]÷åí‹óRùŒ†k91SGÏ�ÉdáÝŸº®�ÉÄßÚÏ9ž´¬6ë´äÓ^iuYGŒ‡B= 9C®íqÝ·Ëë–?¼3P4ŽãŸÇã]ãŠûœµ×ÌKÍþ,“çS=Š¢N,ž‡Û†_·Õ¿åݰ.Ú&FW¬ˆ™d´œ 0€×ö›h0ßüyÐ÷T{žªIjd�æ�r»$×q[ßGË"óì�©/_•gŸz´kLpYP¬® K%ßW~Ûæ�þ앲 Œƒ &hq®�c*Þ;ä•ÅuòŸw}â¼ÿÍÓæ¦™Y[Ãq†AèªÑÆ ¼üÒÓßzg‡Eìné˜ñ¤cuÙç¦�ûVsÿ =¶‰3YÎK;ïIqÂVÿÖç;z|êo¥’øÛ\¯ó¿%§=abXÚ¯Ž¢¨vÃød_�‰3%¶ ž±Æ½æîÁÎwýž9çèMgj†ç†»Þb›õC8°0„qE{ ž¡M? !„ÊÂ¥[0ÁÞöºoGbÒÞÐ+é©)¹öˆi²Ÿ–Š öˆŠo“'ºãË ïÂÞØŸŽ¨\† 4[Ö!xiY8 ‡–AŒAƒ4Íåa$"aIÅ€ULðŸ{ÄŸž\êysîUɳ×Òp 7k¼ùj‡_qÍ_xXVI¬õ_…öà F;6yÜóýÍý'0ˆmQ²JTUƲtÈýñj¦jö¡ œÁ2!õìÇœ¢sgm¬ö{hcÎÍùi5üS$8?7 ôšfIšÎ¡øæÏQÕup–" b˜ö‘7lðnx^ÂÒ¾rYú}y8¸j’Ér6@'¤_b´þ룀ç ·u`ÈÔËØ{$@U´ú×¶Þ/{qËý·÷K�©åáÐó˜R•ý–z?\Våÿ¨"$@3�R8ÙÓÌìÀ“{hËÑäZuL¦YϤÆ”fa“4òRù“–Ñé &x¯Sv‡D"Š ‘ëüª‹aÉ*Á‡SÔ ÿð?ìÿ”¢.Xx M_ŒöÁô7õ¿m„mÄd1Çø„”PpWp×jŸäÛQÃ{|²ï U,�Ñh­¼5CÏêdê2†çòK ¤çôƉéç~´ï£m15Ö¦íð4ç§õdBÂïù<åóB¿3õ¦q͵~¡(Š:V@@ìR‰ªš8“e„mÄìÕîÕ÷¨„ˆï<Ï�e0�Õ3ŒŽCˆ™aMºå÷hhñ^YZÛÖ�í‚}”žÓ[ÃJ8X/Ö­kû§ÒáÐ)©†)O Íü·–cÛn½Û«\\îýôÃRÏça/FÀ¦˜ØAgõÓ�é�.Œ�§qz_}Ÿ¶NŠc“Ÿ&4ΑÈmîz“–ÑþojòlgPu}µ1ü! ´u­eå­C&¤�ýèÑŸ°‹–mô.tŠÎŽ}Î#ä ²œtM?S¿É9†œAÍ]›¡ËÌ›4öéŸëžN s¬ŒuE‚]9×½�Áÿ<@£ËKô|(Š:þqµ±šUµ±š]ÙºnZ]º-°mA@•J⯫"¡?'ÍgXXVµÙv×=õ7)„´igVŽ!w8�x�OñÕ¸DWq{|2©»AzÿIiOø¸bŠq¹÷ËO˽s«ÃÒrð3—“ÌõÒ]sÖeÃ�“wÓôϲ³):þðà©#ñ,b_¾:åá�H<+vD>HDÄ F7Ê>ê#g<â.4L°Z(Zù§gͳ.ѵN%j¨¥ãHX*-ônx²(°ã�þæÓF'�¾ÅÊ[S�tý@ËÀ ·¶�vÄ+[:VúØ«í"W<ïqÎþojÆÛ),¯ÒEu@T�Vn÷o_’­ë6 E“’Ý×Ô÷úOÁÿù³ oÞh�~„�åLçL¿ ÎØ"F¿kí ��,$�bÃx%O¹ˆÅ¸WÙmOƒL·ôK~d�MŸßpLÁXÝê‰?½µö�-žè�˜À�ªØs’ø¡ÓO7OŸÐ_wV¯4>£¡é‘De,«*`I!2&?*#B?FaYÄò p Œ¶•�T’‘5¿zMò³×¾QïZWû:x§“�·ìeì}ΑÎKXŠ­uÿùæ÷šÇ¢xÚ8ŽªÑ}…Þ �×D« .̘47M›Ö䊂‘3YšMwÄ¿B+¿&ô±WûØ‹,}Íëzî{ÚæðÇÌT|ð èG¦èoNô<âÅ'ªŽ’€¸‚HG¿š:Q4$èâ�Á] Ç$Ÿz›™3[‡ZNžº+¸ûã€ìß²9ùáÏhdíD£ùl+Ëo²Ø¸»¾æ7H°Uƒ2œ&Ç�s Àîàî? ;œé¼lóÌ‹ºY'ìÏ뉩D~·ÄõÞü]®G" >hkúàîšsî>Çzߤ!úÓtÂÁ�IC°D¤Â½±½;ªåboX­R]æ”k½aÙçUêDùïö"’B$ŽEƒþ®ÎmÖ1¦TkK2²†É\ Ï¢4«ŽÉJ³°™ý2…i²Æj.èêfçS>˜žúƵoÔÏ,(�}Ý>_­c“kȽÂ*X“›:§`EùÕùëÜϺÇÚùñ®�Õ~÷eõ�˲._˜¢MéÑÔE½M½Ç­q¯îQ#Eí86ÕrxI0ðJ:Ç÷žiM¾)Ñ“é*ìÎúÉ=ßJô<âåçšÀï³Öì[­BƒŸ.äÀ.ßîßöÕhû˜’5ÉÝGÙF>°¢~Å• ²0àyqœÞ0ÖÄìoÓ0Rg~šÞpÍÊHè°6 ÇBÏê& Éi!%pˆŽãª’kŠ–pïÀôûwU†$ÇÃkf¯u†cr õHâ†Þq¶õþ›N3]Â3ˆk:¼a5²®L,ªt+Û¿Û^·µJÜè�à�2c‚ÿZåiñ ÃŽƒ?Dà `X„–�YËôÉOåûœÚ[7 ?•ÏK·0ù259™6ÎÒø…Ù6.õÝ›SÞ¼øGmI�\К¯QK±ˆµ±�x¤ó}…_nð®:^y7nÉýû’š¯¦_ÓýÚ%MR4sæôPg¥¯É¸Âd½´¨Óñ¤§I3ª‡QȰ°zvUX*ÐpÈvfí´=õRé£K<3¶UI¿«hàV@GèÙVí*¥Ða%ì�*Ñ& xšys“IÙTb1®yÖ]÷ÏE>®¥S•8M¾é”Àî¢ÀŽ% 4œ”ªI;  Xÿø%ZÞøú‰FóÄ“µº‹ã;ÕÄŸaºüÃRÏü ®Èb„@kÓ3C×–ŠK~/Ž}¬àøçÅPŒ1à&øU¢Ò½NªZ‘×?ârÜãU•¸î ¤(êÄp¤.Éêÿ–·ÃJ8`âLö‘ö‘÷CäOÞ—ÜÊß¿dÌ kœaM~Ľê*Ðñ¥ÚYv`Ë êÉ cûi´g5üë+hÏLf¹ÁI,7ÈÀ0=9„R  9Iƒ,¢Š•ïöùßl8Fˆuõ×@4¾» º:-£=¬æN¼y“]Ïê�M� +áVU–¦9?£0Y4×ëúŸˆ1 R)Šjw¤Q%ºgG`Ç#l#&#„P_Sßqk=žî]++eyóâ ï£[lɳ„Ðh�að­~jA,ò!´Ã/{@gfØÔtŽË°²ÜÀž¼Ð˜Vß?�ãR ­ŽAfbt< Á  a¢†1V¢JH¤V•][cÑ’JEÞãWÕ—ªTø°êcì"ðw+ŠCYx6ïË ß 2&�ûH‘8Öèér¼’gœtèñMJ&d"­¬$ÞF“¤®ï–[5šóÓ1€º,äŸ—Ï ý¯±Ø¯Lô|(Šê¼Žü`ÀÒ6ÿ¶÷[_¨A­†Ñè‡Ù†ßöSÝŠu*Q#½/]e±]ofØ�ϰ%ß»³®jEcG+æ‚8„4&†é6T£?ÿ<ƒéìtŽïÝGÐäèZÜÇçïªÅ !ªDˆÒu´Öp*A W˲»J‘j<ªZ¾1ݲ.þͧªÛÝ¡å•-@�¸òË�ò¦Žó ¯· I£Ü’«£ª€£}ΙG:QÃ%4ª•b„x_÷¹ÿ¯�F;h˜F7€V€¦(ª)G ~jc5?TGªvö4æ E¡!–!ÿØè-å�+ýªºçc¿÷ãÖ¤›~ÁŒÔê�©7ÝðuÈÿlK&! ”:^o¼ü4½ñÒ3õ¦S £ií'¤‚·‹Ñ½{e¹Ô‡•²2Y*Ù#I•NU®÷«¸‘EB{³Ehú/tøÄYP nW‰ª²ˆ=(ižG¼¦¿¹ÿ¤?\¿¯$@âþ}бº¾yƼ&w.ú%¿Lj�A¬V<árÜ‘�˜BH Ž1xiîÑ_ÕÑê-!%äµð–ƒ›þUhóšM¾M¯…”àîxÎb‡Y‡ÏÒ³zkSçw…vþÏñ©öU!KO¹÷>�’ùj2Ë5ù=¥(ªë:RÂóåáòeN±¾´áãÅd}äµôìïî¶§Î΄n- |bËå’Xþš×ù欺}—Þ^W5ñq—ãšß#áy5м9Œ±[!$ >Ï"Ö¦gõÝõ¬¾;‡¸^�îXÇ£â+ ø·•`USç̼Ù>Ê>ê!q‡µ¿hG(I“têHûÈÄV²AÁŠ\;¾ðRÑÈçïúÝoÒ ÐEêh+?ñ}[ü[—¤k3îG!#g4³ ûgmmí/ˆü](ðæùËÄn<Ÿ°¿íÅÕfÛ5߇8eSã{!f FwÑ-Ö¤Æé�#[2QLQ Q×Å"[¿ ùßú#^%¸O®F b8±o;µ›¾ÛàTMZ¾[rIŽX]aL�{$Ïvt{zg� mñm^–¥ÍÜT²ñ0۰˲¿|ƒwÓñhua䌽ÎO›øŠžÓ›š:ïWüue¡Ò•­½?Ýí•@ü<àÿÏA7`¢Ñ<1Ñó¡(ªó8jðP*þh„mÄõI𤠀>¦>ã·ú·^\©X\.Kë–…ýKgZ“§7\ŸÊñÉÓ­IOüÇUw þ«§`˜eKžs�Ù~ƒ�aZ\)wY8°b¡ßûòN)ö#4Ñ'‹gøìLm昆gdi³Æåzöw‰Îê]ÁÝ߬vÿ1/ ÖC °R§"R±È'û¦Ù[ê¡çFÐŒO=ó~žáMºÿ|ˆi²ak$ I#/L¿ð­n†îƒŽtÍÎÀÎ5Rt¤óGCw{%N”`ÿ#®Úë³9þ÷“´º¾‰žEQ�Ã1?9P¼;´ûû1š17hY�ᔤÑ÷VD*–€¼$èŸwžÁ<©/¤7¼æ"ƒå¼/ƒþóvˆ±o“Y®ÏýöÔW'Lg²G¨æÛ c¥ ÙðžßóÊ&1úµL~Óã>=[—}j/cï«û™ûž*03�x¾2R¹yQÕ¢Ûj¢ÕßÆÔ˜ƒ¡ËÞ�œWòîÜØöå¸äÓniê¼À¸äÓnM’ûmð®Îs¬&@Z�§Å3|jocï«&¤�ý ‘5&é:Ÿì­ßæßúZkÇ¡O"Äõ°«vú«iÙ‹»5úEQT×uLÁ"mòm|w¸mø5#=õ=‡fé².¨ŽV/©Qä¼oþ_RÚà ¯†»Ù’4{¾Ï»Ý–üÔézÓ¨c�&„¸±âyÍë~uy8ðfãêF§=kÈêmêuà ËI—¤kÓûi�VÁŠ\«Þ±ÞSðFY¸ì+ K­ÙnO%"oôn|i€yÀEv!©É:<à ƒ­ƒÏíiè9¢8´ûç;Ío{$ÏV Knä¨MdÄš-œ¹G¦.óÜÁ–!—w×wÊ1ÜsÍ!d³wó§ɳµ-Ÿ•xå²ôÇË^çS%¥?caÙ&oRÕuSðà—ýJB%ÌÆ° Ë ·�˜åˆ9V¨D ôͻŚt·�å ¯9]o›Ë ïç šÌ–Lj·$V>êrLß%Å~†F�ªXÄZú™úß<Ü6|f–.«WC~HD‰DV9WÎÙؾ@ÂRMKÆ¢:� ,YU¿jÎÅY—<×Tâqo²³ ¿|¨õäÉeá²m>Ù·µ:Zµ¹.VWQ#u15æltmž…³dfë»õ¶òÖAyƼ±&ÎtLÉÓŽ˜£¼ÐWøÂ±VTç·"|;�åóîIJ½+Ñs¡(*±Ž9øÁÇ6û6¿žoÌ®a4Z€A–Açx Æ×Æj¾ ©[às¿<Ûžz?÷×£-!¶%��BˆúEзxާþ_"!ÎF§ØCî•g$ŸñP¶>»OÃAKÒÎÀÎåËëWÌŽ©Ñ¸n…¦:. ½�íÍ>Ì6|Ê¡uÅ †É7æ€ÁÃmïmω• oií×7FÕhE{Þ—J û$è}4“çs¯4ÛNØ^„EÝ1çßTDö~ãˆ:Š�4ú_,b-߇ïVÊr“[–�Æ«*¡9žú§çxêg6|Œœ±ÏY©Þ¹,ë²�Ÿäs|SóÍ}ËË®¢�ωe•sÕÝEþßcÒtƒÑx +aÿ�ŽrŠÎß1>?!ÁW¼ÎÛ‹¤­ÖMQ]X‹‚Lpp³Óû˜à…óŒyc³tY㼪ZòEлH%¤EoZU <éª{`QÐ÷´HHCÃT6K—uîE™2:iôuZv“KL°Z.ß¼¨jÑä¢`Ñ« Q:¬ïÕ1$,9–×/ÿç:ÏÚ�¬th“J·è®YæXvï®àÎ7 �¶¨Ó­î�Kãª××Î,“DºªGQ]T‹‚€²PÙ7Nѹ·ác £Ñ�´�º‹AŒ`E$ø^¹,óê�WUBÿq×=òS$8OÝ_‘õ6ö™15ûŠÏr ¹C_¿Ù·ùÛÏ«_àë×m=qŠªÑŠ•Ε3—×/NÆrÜsn!¤,\¶õ‹êϯÞÜõ´[ÐE·ºw>¥²¸ò^gÍŒJYª>úÕE�hZü„ÕpɶÀ¶¯ëiì9ª�©ïuE)Zô-<–{¹Åÿogí+ÂÁ¹ ÇXÄFÚG½0¥Û”×ôœÞÜp\Â’ô£ãǧ¿w,›*b‘&5w˜àèFoáCóË^·Å·y™Œåv_"„�èq|_÷ý“ŸT~|J½X¿ èJM—P"‰Ëg:öMÞ!Fw7®ROQÔ‰¯ÅÁÀîÀ®rÀÓð±ÀšQöQ·#@z€ý»*J¤ØÞæîÆX|ÙëüÏšhøƒ†câÌ£ì§<3>eü­�¯�©±ØwµßÎ.ômxª-µ]¨ã“_ö|ïøþÊ…\R(Zî—ýî¶ÞŒ«£U;W:yñÃ} Çoòn|’Výîzª¹`–£êüO‚¾ÅA¬F=Š¢:Æ1ïöj̯øw‡ŠW · ŸÚp,[—Ý+×ÐsjY¸ô=—ªT¼ãó¼ödJÆ3B‡íØQ Qú=| ¼ÒPšE¬~¤}ÔÆ&��Î3¼ÐpmX ûW9W>·#°cÐ Í]–B”@M¬æ»%5_­J’NÊÔfžÕÇÔ÷¼TMj.Çp-£Õ©f&‹ª“‰UÑWÚ½¶:Zýse´rUL�U@œWzhÎO§F|X-ÞSó/áàyçÌמª×�Ð3ŒÙ„X]KвRuühu.B’�tö¬¼[—7>¶'´gý—Õ_œ'aÉÃ"d]œ™³-_ÐdúÚ_#¡‚»ë«Ï— ñ0Àð#í£^8#匙�ßÀbj,º¢nÅã[ü›çÍÀ3|Ž•·öIÕ¤ö0ó+‹Øî  ?C Qëd,y�’³Ö):K"Jd'Òaá&ýB£ù+Ù�~uûòaÕµ8àûŸ Ä×ÑcÇ�1¹½Í�Am/=Ãd1€4íus‡";—†ü�á&Zô4–¦ã‡L͵Íj¯q©#+‰%ßíóÏÚ]ùí“Î�¿t˜q ôî‰I{ÚºO*^¶5­útFihÏ[�æ»OJ¶qÇöÝR¬ì®ºê˪yÓþ Íɶ“=7í¼ûÄø¡R‰ªþTÿÓ³<ëÿCGP-€ààŸëΰZ˜¨_–èªS[úóÔV-ùž$üM¶‹8¿'ôÿí6j¶ˆ\sU! ô2ö>§¡BéY}Zqh÷·*QC5Š\yŠÎ01�ãSÂÇþãr<¸MŠýû¿q\_Sß›ÏK;ÿažáüu… ÆkÝk®õüù0ÜnM,©.ƒ@çúå@ô�j‰úž$ê禫ýk‰Dϵ5s¦šÐ¦(¶4\º$¤„êë¦ï64GŸs!@ãêOÞ÷BT€oCþoׯ"‹à¯¿Æ3´ÎJ�ð¨†Õh‰A!%¡’õ¿»~›­5EQEQí¨Õ+?˜à0IÎ7æ�;pCIJVÁÚk»ûb 8\¯*Uôús9@Ú{�5W„1®¡Ûä¬Ë¥jS»7¾§[rW/­ùúúˆ)mËÜ(Š¢(Š¢šÒ¦à ¬F<ù†üI�kòèY½- |Ž˜cµHˆß£ªd»ݼ)]°¿–Ï…“>îiè9¼¡9)@D‰„–Ö.½³NtüØÖyQEQE5¥ÍÁ�„E—…·ÊÖgn8Æ †± ö~Ûü[ªD�T)ÒŽRY*PDHhtטä177NpXã^óæöÀ¶— �fwBPEQEµV›3× e›ëû¢*´å.E“’ÕÛØûZ@*@T$$¸ÿxê©ã’ÇÝÙ¸c7!„TF*wn𮟃 ¦;»(Š¢(ŠŠ›vÙ¶ç–Ü…Å¡Ý+=>Â6r¦žÕg5|Ì!>e|êøgl‚-µñu2‘ÅŸêVÜU£{Ûc>EQEQGÒ.Á�BÿŸî?_;ôx¦.³W¾±×u ·  WŸ;¬ñ5˜`\è-ü¢&V³¬=æBQEQÕœv+Øä�+ª¢U{C¡a¶aWëY}n’�tÚ˜¤1Ó9†;¨¥†KtUnð®Ÿ�£EQEQ'¸6'<7¢b‚5y†ü3'28ƒ=¨¤A–AS3uY}ïîÂãß]¿Í+�”ÒŽó (Š¢(Š:¢ö,ÛFÓ}ZÏékl¼-«ñqË2Ïð‡5�¬ Wlû¬ú³ócj¬º=çAQEQu$íÚ§DÄbe¡gâC�7ø¬õ¬›OŠ¢(Š¢:R»7i+ —~î—ý®£]W­.Ý)ÿ¼½Ç§(Š¢(ŠjN»?.ѵ©"²wMs×`‚ÕBï†7%,9Û{|Š¢(Š¢¨æ´{ðC€Äֺ׾¢`åˆUšJÀ½3¸s!Ðî´EQEu°v~¼²·°4\º¶©s˜`¼Á»ácË5ñ›¢(Š¢(ª9q ~d,û ½…ïªX=lõÇ'ûêöKÇc\Š¢(Š¢¨£‰Kðdo¤üs¯ì©;ôľè¾—ä*ˆÓ¸EQEQÍŠWð˜àÀZÏÚ×U¢ª ÇT¢ª…ÞÂw€vm§(Š¢(*!âüì íùÊ/û WE«vz$wa<Ǥ(Š¢(ŠjN\ƒŸ�Ú¹;¸ë§†�ËÂe?ÅÔ˜£¹×PEQEÅS\ƒ ÛÛß+áÀvÿö/@=Êk(Š¢(Š¢â†;ú%mã�ËÂ¥«¬¼µoP ÐDgŠ¢(Š¢ª=»º7‰‘r „Ç*#•?Ä{<Š¢(Š¢¨„ck0sæþ‰žEQEQEQEQT—òÿüÙðÔIüÇ IEND®B`‚apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/images/opennlp-logo.png0100644 0000000 0000000 00000072633 15217274217 026670 0ustar00rootroot0000000 0000000 ‰PNG  IHDR?ÉÌøSsBIT|dˆ IDATxœìÝw|”EúðgæmÛ7›ÝM'¡wD�¢¢ öv(*'ØëÏÞõÔ³a;±a;õl¨g9QŠày¨ˆˆÒ;„PÓ“Ýlß}ÛÌï�Œ!=Ûóý|òùdwßwÞg!É>ïÌ33 Ã0 Ã0‡”꺃±—Kè×Ãɰq!@0FÊ+ýzqIµº+¦ROªcd†a˜ÃK~â!àò2ø¡Mr<2a€ñ¸ž.ÁÝøõJ¿ØPªlzâëºgWï‘j„ÆR+Ã0 ÃθTÐ áÜ‘æë?¼.ç½ñŒ#3Lœ¹é1–úd =¦Œ¶LÆ2Û)/× °ˆa†a’Œ%?]ÇÝ–ãùSœ¸¬œ¥­ƒEqÇõ3Œ¶H¸×÷[¢ó@KBŒ Ã0 ÃìÇ’Ÿ.À¸iG[îœ~®óN‹ÚBƒòÅ>ÅUjõÖ uU"cd†aæÏXÍOç¡Áy≠îÌý2ÛÆÛ:ÓÀêÝòîŸ)*k4ïà†a†iNu‡ª Î�q�sFg€# Å¢~9ÂÉñŒ‹a†a˜Ö±ä§sðeÇZï˜8Ø8²K�`„Nj::^A1 Ã0 Ó6>Õ$6ŠÈ™aÂùéŸ-ûþµÙY(õjúÚ‘ERÑ9#,î=ËqË{?¿|õ{ßs{<ÚêÖÚ;¾¿ñ‚ F[NŠGl„Pªê´N'�G{ Ã0 ô­[Ouè”NxÿêìŽì)õlí8‰GüèžÒÐóF™Ï÷G‰´©L]M((M�3‰Èýúåîw{¹„„P—gÊ!„МÕáEËŠcßuµ-†a†aÚ§Û<[œï�œ½©©¨=ÇcŒP¾Cp½x‘ë‘/r½—cçú7~�à ^>ÎzëqýŒƒ1n9ñ!„RM§¤½qþ¸5º¾½Ç2 Ã0 ÓuÝ6ùŸm=oŒÓ<2\ʃA@ÛYÒl0õxÛùo^‘õQ¿la B€' 0N½ç ÇM­�K¥Ê”²ˆBê5jŽN(Ù^¥¬l_d Ã0 ÃÄC·özü¨¼·‹,R.Õˆ†Àà"Б¹Y}²„¼‰ gø£DßßxÖóÓ\�fÛøŒÖÎYZÛPáÓê†Jíêmú}—¼ûퟂO zû#c†a¦+ºeÁ³UÀýûÛ ûÑJŒÙ:Üí�€�yRÁ¬ËÝÏc@HàQ«‰âª]±â—ÿóR÷ímÿ‡­Ñï5�²Y^ Ã0 “DÝrØ+Ç(ôáyÇô9Þ»¯�`¿©G&ïnïy!™ÈËKäoâÃ0 Ã0Ñ-“Ÿš¨æÑ›�A…@õaïá¡ý+ñ4¯Ü§yïýÌsÿˆ"iì”Q–“[[û§©âJeïÊ]16Å�a†aR [ÎöªŽi:mi‚Ð$§¢½ó@oÿøü÷]òw]—½ÈfÂæŽœ»Ç£íòEȾN_¼ûáxÄ€Ðæ‘)B€ÔJü©Žƒa†éºn™üø­X§´ÅMJ©†À¿U€Ìá p†Ž·ÿýæÈªYKü�Ÿ4ØxñYÃÍGwôü�eÊ^`»¸À!Î}u¯k¾wKî>©Ž¥%‹ª¾½õwïï¯tô¼^ðFv�{‰bv¼b©Ñ´À.M©*W•òݪ²þ÷XäÛMrl ¶G\{Hõý½ç€âT\{u,RrMå¾Ám}!Ô#ÆÉsNîóe²âjMUT+?vÞÖüTÇ‘j“F˜oþðÚìÛšý{(« hÁmj%€¢Rug�ZªÐ+üÚ.�@4¦ÒÝ;kTÏîZµ²: Wb¤L'pHÞvËä‡P.«o<»‡ýø–ŽQ‚%تБå`ŒÈÍñ>‚1î<­õŸ[â4s6ÀS–1�àæy››çm`0õ#”ŽýÊU±ÈêÙ�ºÖÆ¢ó)@‹‰?Ã0LKrl¼5ÇÆ[=5¸é1Á‘#2‰Å4Ótˆî¨R+–G7î®Ñ¶”ù´5;kÔJoˆ”i„“z‡¥2ùÁ"—ÛÃ,Ž>ÂaÛßn((0 ™›}±²²°RS”7WEµ5u²Vш¯£‰Âo5áŸZK~?ä-Ì…:´§bG'”¼óSà³õûäÿ^rŒíî±}¤A‰©Á£,§¬/UþeGtaL¡•þ(‰DQu¶îO·Câ¼ÀÂ0B(ƒã-'™mã‡IÆ¡¯ÖÕ¾47äšÈ‰º&Ã0‡/«KV–ÀÐ'KèyÚ0Ó1�(‰•Ô¨U~m߯%òºï6E–Tø´Õµ!âQuJiàM¤$ùÁø³{Øo»ª¿ëÆAvCOÿ±ñÄ ¹$�a�È«j#[·ùc¿}ºËûÅž�²¤¹ÝÖ›S�—ù-bySKÇP‚ X"€h§ f´�sìñh5ÿ˜W÷p†‰ëqë)ö«ÇÝnçxý2÷Cð�?B¢Ë”Ò]5ê®=^uó×kÂ?n)WTuZ×™¶™ôƒÚ] ßY¼�ù°+ça€Î ùgÖÄ0LÙŒØ0¢Pê õ:}˜yüôs3oÙS«y–툮ú~stñW«C_Dº;Õq¤ ù1r8ãšÎgo’}M[Çšy,�ϱ Ÿc~í×µ;ƒrå§;½,.~µ7¤,‡Vî¨7x£ëKÃê>»ÈhíTGP·AÇpD[Ë7è¡‘øÂóD FvßszÆ ƒóÄ^mÅßv6Žëgè7®Ÿ¡œúÀÙ™·ûÂ$òáòÀâÏ~¿µjOì;B؇Ó>BÜîÜÇdJꇃo°!0†aR©ÈÅ;‹\ÖS/:ÚzêÛWe=÷åÊЯK¶F¿ž¿>üm…O_“ª¸’=Õ�»$Ç1ýú¾îË;sro«”ó·a9w}:±×¼'FæÍ9Êeú‹€‘­¹c£:)_Q^ÝžvõX}´iù}Áúð’o7D>̱sî?Ñ~igâo¯ 36Ýx¢ýœ¯nÉùôÕKÜŸåÚ¹ƒÆ]¦5wdf=2Ò`œ”ê8†a;o”åè.r=ñã}ù‹^˜æúrÂãù ç$;ޤ&?ù¼pä\ÆTì�vrŸ #œeÓúdžóÚ1…>12ov_›t��±É¡ô§ÊÐ"ÒÎ ©~ þ­è2´Fu@ <¿È÷¼¬Ñà%ÇX¯Î²qŽNß#”iá,Wg;÷•KÜodš¹Þ‰¾f*)DQ¢È‰þÒˆÖîÚ1J)U‰ªì íü}ghç/‰|ÿñ–Ç ®[îDzy~xªca†iŒÇ÷ÈÜ×O´OþôƜ޿6ë󳇛o¶°’T&�Ôa¯³,¶kr9![­$€Í8jW¡qK\ÞvA/Ç9)´Ÿõùnß×ïïð¼\�lx}OHù½<¢z Ì¢³íÖÈ uëEp W€ëŸ%„Ò7 |²©Lù9Ä‹®Ÿh¿¼³µ>�uÖpóq÷œ¡>yÿçžiɼn²J|‹«Ý+`Ñr` ³á碵Ç�“TÔÆ± >ÿ¤¬“ïqI®¬öÄÔƒþÿUÿïÉ­�-oiT;ä¦sŽ0˜Owæþ릪}'€@ªãa†iÊnÄÆ3�0�;óó¸eÅÑg- ¼6wMx¶ªÓ„þÍJZòƒÄÉ–Œó€(» ú#@Æ®'y‡ùi½“'ÚNÿj�ñ;Åž'÷†”UÕ1­f{@ÞѾä§>JŇ¡n�CUà�öz5Ï+ÿõ?E(�ÿ›`¿#ßÁgt9àN¸v‚휿ôd꼩¸~"Q ±²hY¶ûÀ›z›ûL;9ë”;3ÅÌ6·!‘‰[ë[ûÕO5?Þ/y$p¶V¢c4u£ÃýÒ›¾Ú›JÃ©Ž‡a¦%ãú�émxqs¹rÇ_×ÍX¸!ü¡N³~YÒ’;憸8î@â@Ue/±,v=Â!«À›.î“yÎIyÖcÿ³Ë÷Mq ¶©À$äu¬¥ý ÐŒ½eí¥Åþ×Q²§_¶0ú¢£-çu9ÐNâp‡2tB»]ò“H6Þ6ìç±³;ÛÀZœù@(!û"{×ÿìùù齑½ßèT�K²�È©îmÁ¡KlŽiÅŠ¼nq8ðO¶¶Ã0éLà7¼‡ÔûÝ«³^Y¸!|Á³ }36–)?SßÉIK~úˆÒ ܤÆHRP+ˆŸa>ŒÊ3‰Y· ɺºó­ Pý6-ƒ½ï/ ¼hÊHËÕýÜb©Î¡Õt¹> xxJ ûàj/Œ°©—¹×”‰îÉ–²{"Ôò+¥”FôHp…wÅ»k}k^Žè‘�ñŒ%YSÝ[bÂXº;Óý@…¦¯—£óS Ã0L{X Xš2ÚzêØÞ†#Ÿ^à{ý“Á—#Jünþ“–üô¥\+£ÕR@1/¥Ÿ‰iD}mCíËQ•V˜Å£Î²8Ï©Û(€`#õ_&œ±>QéHÝRãã «Ðe-ŠA "Т´-ŒA� øµ:\"ëto¼ßgwdäŒEÇdûè˜Ì1ó˜oñgœî/†/ —¬ü±æ‡G*b “ereó‚ë~gö‹7W•îðèÚ¶TÇÃ0 Ó…N!륋]Ma:ýú÷k®­ôëâÑnÒ’ŸlŽÏàšI~€¨°€s hå=©~¯ ¯þ®,ðÀÔ^ŽÛ²¨”«F«ÆîãÀ›(p œ�â8c}Fƒ  :º�yªÑ�A ÅPý.ó �üñï kDýt—÷�¤¼ñC\‘©hÚ)Ù§>‘-e÷j­· ¤‡ü?ÕüôÜÿúŠÍ5H”úLwå̾³ºì4•R_ªãa†i#|ÚPóØ%÷Šßßý‰çÞÂÑv.xÜb›ñ ®K(€²�€$r€ÍëII„¨F”J¼ïÄtZ›)q§ôrLÂ>HÑ�…jj�hºA„÷N€vþMmôŶ.©ý§Ó $,å³»þx×ñ·šyK³k?5Ј¦–EËÖ/®^tu¬z zX 'b„Гe̵vç£où=÷©”²�P†9dôt îW.q=—7ŸëõîÒà �ÐHgÛJ�ä  u�zs€ ©Í~–V…VüRþpSz9®Í”¸V?L›·¿7§‹ü²~qSÕŒ ª³!¯æ!‡àyBÖÄgZNà×ê6µ-\Z»ôÕõþu/ËD®HV�éäR{æuÛUyÛ÷áà,Êö’cæ’›Ág>7Õy¿IĶYKüÊZçö KZòãÕµ¡”âV†"H¤~˜ÔâS—ÍÚZóbT'Þ ‘+œÒÓqqk1'Ú³«^X^þ%¡’ß?/ûüÒUu+§§ª¨9ÕSÝ[2@4ô½Ãá~MD(% w2 Ãt…À!îšñ¶É·žl’ǨÕuÜšJZòãѵ *Ðv/R¤VÐ<:»XgüZ^½Òž0.ËrÞ0‡±ÕáA%DûxgÝœ™«nŒj¤Ã]yÝFXhxÍS>écé{ F¸ÅŸß˜ ÿâYöîe_L.�–-¤øÙ;\páIVû©çYíãRÃ0LG,Ü{VÆUWg½#hõf¸±¤%? ôßpè÷vŸ@”Rz]r’Ÿ˜FÔ�J¼¯ Q£Ì‹ûd^šì=¼þ±®êù¬«¼2¬u¬ ¯»±˜5Î9îå ¦¼™)f¶ºp�\³÷?¥Ÿýßÿªÿw­Bä²dÅx¨ºÍ‘uç &óe©Žƒa¦3DóÏ^è|è´¡¦‹Ú{NR?ÜWÅ"ó´v}€^?^ó%vB ¡”.¯ ÿ¶²6ò=ÀÄ\ëyCÆA ½hu²º}ž»>*ñ>¢ÓÎOß뎂cì¹yçÎ9Þ5¾ÍU»×úÖÎû÷Þ�NßÙó1´ÿg-�Ò±æ§13ÆÒí™Y�  g¥:†a˜Î0˜òçãý³…qí9>©ÉÏZ9úK­®uh(§a0MܘN)ùp‡÷ݘNjn‘ýJ#�Å„\¬%�Xé#k*î™·×ÿO�R9Y×MwW`,8çü‚ >ìgé F¸Åbù°üPóÃËßV.¼<¨·@%éZóÓX‘ æÝçÌžaÃ\¯TÇÂ0 ÓƒrÅÓÏÍœnÛ®cLjò³WUVoQb›;zUb;u Ê[BÄÓZO´xµ'2 §UœpBŽutü¯r0B)]ç�l»å×ÒËæïóÏb³ºþ€ÙÝ8¥à¯ärú¶´Z3¥”zdOÙ7_ßòsíÒ;4ª¥ÝƯéÞóÓàÉ0øf‡k¦€:V8È0 “.Nfšð×Ñ–[Û:.©É�? øÞP;2ôÕpn@ÞI€*ñÿ™]â™Põj!ÓõÜ·ŠnwÑTgi„’Åe�Ÿ.ùq÷©Ûü±%‰¾Þ¡DÀBÖ‰Y'½9)÷œ™fÞlmé8J)ÝÚºìý=ï�²#´c6¤é‚}‡BÏ@}ôT›ãÜ ¬#€¤õ|2 ÃÄ‹QÄÂŒ)®¿åع¡­—ô‚ÞõrtÉ/ÑðŠÎœKÂä]¨¿¨<¢x—?šoœ’o=9n�· ¤’Ø{;<ÿ¾û·²ó"a+77bãmý&å�óÅØÌ±ÓZÛ”T!Jl™gÙûsËçžÑ#[’cww“Ãuó“å8D’6†a˜Ældzð/™O\˽ØIßÞ"DHÅ¿uo�3š�æ›Ûè´ $DAÞC@*€„®ýmÖ%³‹½ok„zw^QÆÿÙE>¡]þAU�¼²¹úõK¼�Ë:íö›ivvŠÎQgäœùF‘©hxk›’ªDU—{–²Þ¿î K6 K�Ø~¤cd"{TR¿‹[wgÜùf‡ë¡½ªR¼SU–¦:†aþLѨŒ‘�S!,ÆٌؘŠΉ€1BSF[N{già„Õ{äÍ“’½½VÅ"_þ ßz´Ñ|dg¶ŽÐ}dèzTQ+¿Ùçÿ7€ÓÀ÷™˜k=¥Ó�µƒFˆþ÷•e/* ²Âæ&\¢ëØÉù罟mÈîÝÖ± ±9c uà©Éˆ `¹ç—‡76¾Ý™s•šŸÆú‹†ž8³_¹±ªôT™ÒêTÇÃ0Ì–n‹m~z¡÷qYƒ¸Ì æ0à^.Þ)ñHyœo3¢¼Þn¡ï„ÆÁ¹œƒÃˆã`ŒS½íxûÙŒØpÇ©·_ónõrY;xû‹”$? ¥�×|žGL_QçWÓ}dJ@ì‰w2š¿Ï¿¨2ª®8>Û2yˆÃاS µCD#òck+žYXx�m&ùgáÌ¿äMšÕžÄ€Ç¼à]IÝvÄÈ;Ý#x¨Ôü4u”ÁtÄÎì7žôT]"SNu< ÃÔ+÷kž;åo-~;,ßÑüó6#t|ãqÇ÷7Œßßxˆ"©(^×L´S†�Ó[š¸t{ì˦¯¥¬‹kƒ]üUÈÿ éB·�î§ ìé\ PMLó/,õ¿À#dŸÚ;³Ý‹#uÆâ²Àÿ¾Úã{–%>C€D‹l…á4ƒBgšmgO²Øÿ†Y4ÖQ²eþºð[|á¹~ÒKãÎ}¹âÆ…ÂKƒQKulm±›8ã•ÇÙþšÙS4eÉÐfû½O•¨òž®´£ûêk€¨FÛ= žPJWT‡—oÈëF8M'õ³I ëõ *zì“�Þ×T¶O×aéPöj bÌßìpß6ÆhžœêX†I�@¬6¤—-Úyý¢YUçN{£òÊo7„�*$­·š8Ð4º§KÙôù”7•iêš7}ž™ !ZWÚÑ}›†Bï×¾¥íOFN/°]f9sWbh l ŸÃÖ¡:ìÕÀÁqö‡œÙÏ âˆTÇÂ0LêÅTêý~sô“óÿYyò�{õõ´½±Ï²aÇÙÃMmRžòÊîÿEBï}¬ûOWÛÑýä:è‘Ö B)ý¥:´±8 /° \ß+ú9º{»Uà  Ï}m„ÓtF`Läµ&zbþCÎìÙBY©Ž…a˜ô@(„ß[xòøeÞ]›êxšƒ1B—g»š }¥<ùQ) ¾ã÷þ}‡ÛÝÕ¶Hê `Ë[aP tÞ>ÿ‡�øw~ÏŒ+»zÝöâ0ôþ׸Â÷?›Ø{ÅÅ}2ÿ1Òi:Å"àBhf,’aÒÑ(ƒiÈM׳B–TÇÂ0LúØU£®ºâíê©ßmЬ$$AûPuÁÐ|1¿ÐÉÛø¹”ÌöjªN×÷<᩺÷ù¬ü7�oïJ[Tˆ•è õÀÀ9þóˆCP#á¯÷úÿ 4CäòOɳ�Û•ëµFeH¼e„Äá4 (úíÅ�Ø®’ ²éÛRÿÿv•¥51­<¦?fEÑ„’º• ®±˜¶Û*ÔÊ5Þ–¥Á¡\óÓFMµ:¦•(ʦoBþ™ KÃÕ ÃteuÚ¶ëÞ«¾xöµÙŸÓ×0„K³5ƒÎi>õåïü?Ãþ¿Çi‘ü]‹~ö¾ß;úV‡û¡®õ†hònB ƒ�€¸? Ovz¿‰jdÀÀ à c³Ìƒ»zçØDÎx”Ë<ø(—yð_{9¦„5]^V^»Õûeî^ß7{BʲÃe¯/ TÞÙûcªãH”C½æ§1ÆÂ­÷ý%ª¼u£û:Õñ0 “>*üúö+ß®¾øëÛr¿”'öLu<��îi8^â6Y«_\8­2³�uOþ—Æ(€ZA ¶Cß¿#<€WÖ‚ß•>ÀŒÓzg^—kÅ�™ç¤Sómcoì¾}Á©}¿�wjßâ«ú9gô¶JDz}–˜tâæùŒG\93sùƒgP0 sx+­Ó6ÜôAÍÝ~Í—êX;®¿a„Ëʹ'<ùÁf#Ây Å *Ȕ־å÷ ÄŠuЪ lóĶn¨‹-èc•Ž:ÒiJ»?Þ!$qXh7>pdî½³Ç÷œûâØ‚oF¹L“0¶Î!¨» {5ÖG�zÝïÌzMB(3Õ±0 “^~Û›ÿöO��RGc9vÞ–kç†7Ö÷¯T;>Çr^¾Ipµunªåš×Ù…§þk\ѧ–ó¦ÛÀ÷�n4Œr8èNÃ^ x„ð &ëØ+íΰh†aÓ Äf- <·Ï«ySKccûŽnø>QÉ:Îd¾ôå¬ü÷N3ÛN;Æd1Ñl™xƒÃ}Ëgy=½œU°ô‹ý ¡Ü¦'u~(ðf<ƒ!”Ò­1yתPt€€�srFÆdª:7äV‘3\;Àuéûã{~7(Ã�´=­¦5ר3¯>Éd¹ Òl�a˜Ôò†ô½o,ñ¿«š6xNj…H úƒeâLǹO~„`é Âe!<Æh:Ý•óÔâ}¶Þåp4Ê`šlD¸0` J£ãF-�†¾«Õµ�ãŒæ¿dUsyÑ�:È»uШ~h$Bì†^oŽ+œ=(ÃpfªcéŽ8ÄeqˆËiú…¥íL´T1æïÈÌzøÉ8)Õ±0 “>(yççÀ[¡I›}�"r™DìHÐl/§ä<‡ôتKhˆ¶ xÐ:†C;8Þvy†ó¢É¶Œsk5­Z£4ˆÜ—ÏxB´oC�O@Ç܉&Ë…„Eªhµ´: Xà20p6Ø‚tÝ¿6Ç(¸™7sÚ»–jlËŒ¸šÚcÚ—Þ’Óôùeže�oôox¿3mvÇšŸÆryÁù +û™[ªJKª4mCªãa&=Ô…ÉöyëÂ+.9Ævrªcp[9·ÛŠÝa™”&$ùÉ‘rG`Äá\°Ò ôÔwnåï¿ s&›ÈõLD,?EÃ+Ê5u5€ã§šm'þé½~�D!&˜[a IDAT V`Î ÀÙñþD¥Q&„B#�¦ãs,ÓþWŒëa*`„3NÎ:ùI›`;h§öÍ�ÍŸmlþ,Y±8Eg‘M°4}ÞÈl�m³;Öü4Õ_�úþ=3ûõûj*Î�R· ÃÒè[bó¦�µž˜ëþ8øÌ™‚sw­–˜ž3o²與õü00Ñä�ªD\ªM*!Úwáà'1J€N1[/5aÜòÔq@BH@­Ðx;lA€Í°ˆ€RH‹^¡s­'ÿPœM(¤ýA€ ½Ì½OsKîƒ6—­–k6¦"&¦c0Bh¢Ù:îB9úðl¿÷oíŸI†aâcÍ^yu¹O÷õÈäS>3Ô,aÑfÄ öŠê±PÃ÷ ’àwa§,ƒ êKú-°‡è¾"¡¯L»N4YÿÒ‘ói @�Q€j €°gE€Íõß#éàU¤“Å!ò=ŒŒ²Nûš¾–¾—[xKϦÏï‰ìùo�R·¬½íÐŒPu÷a¯ÆnÎp]_£kÅóC�Âaô¾†iÞîZu·'¨×¦Cò`Q6@‚’ŸªXÕ¦Æ�£`„ß„Ñpœº Ì4’ˆK¶ha(°8JI)@!/1Ú`ÞÖ9Í¢P?<¦@´~,C@|ý0¶ ÀFˆ¯pâk†§Õ¶í<æòž¦ž›>ÿUÙœhG’ŸD8†½ˆ ·f¸,×Ô]kbõ³+†9|EZî‹ê5Ð?Õ±8-\.@‚f{Õ©Þ_ÂZø@ï ~œ«ùMâ:}¢G–Fß7Dq’Ùv¡±µ!¯Ž õë‘H}Ñ´²›@l«±í:È%”=:¨U4?¢P úþ/Òò¦«P´j�€—Æ&Nr!ë.GÖs6ÌõNu, äÐWïQv§:Ž&lHPòÔ‚»w„‹¿oú|—k…á €�ˆË¤D‘‹×ÉÑ¥6Ìg4�Oè)•ô­Oˆö�‹ D×ëÝ Cl›ò.J¥’€æ% (�ªÖ'D”¶?9Úâ�ý®Ó$w¥usèðé¤I¨¡’¡ÿß�Ùop€Œ©Ž…a˜ÔÚ\®ìJu 3ù€ {J¢¿z~}y uЩ–þôÇoîDÀ0Z] "¨‰¸üsCþ¯UJkFŒÇõ¤”݉R­þ " ‰ ýc0Á�ï†ÍW?„€Dh¦®hîÿœÄF}øa5?ñ�B§™­'nWbOÍÔݯQMuL 䆪ÓÄ~ØwB¦žÕÈ5KÖÔ­™K(ùóêŽA·ÕÂÈ„öUišoM,úMÃU'˜,J'§Ë©½èþ/zý•Hxï‘·þK­¤ –“?}-,ö/ ¨ú–Ô¾¦=§šŸÆ8„ðÕÎk�3š/€ƒ ú^ƒÃ°GáPt8öü4°bÎt»Ãý÷þ¢t|ªca&5”4œ‘œÐE‡‚ZpóâÊEËDnö�oáÂzþˆ¸÷Jé7!ÿµ~m8Ël›šÉqi1Í.„ƒ WDÃ_¤:¦}מŸ½E©ÇC®œ7,÷Hu, Ã$_†‘ËJu M%|ÅÅ]‘]Ÿ.÷,oab;¸>qóézhU,ú€€�ñh£ù,¡nÑí¾IŽn{ßï�N�ÍòbÃDC¿ûœÙoˆ9R Ã0Ée’P§WÈO”„'?„’è ï¯O¬÷¯_H›™ÆD†½¸¬å‡ƒ ]Ÿ…N(¥‹"ÁE!¢×80×o¼Ñ<¦Ë §¡”–«jÕSžê;+4•Õú0‡Œ:Ól;m²%ã.¡ä­wÁ0LÊ$¥:†*¡@’Ÿú‹©5ÿ­úî¦Òhéöæ @vó½`•0"е™±*¥ÚÒHè L0Y&§]¡sJi¥®yîª)»j½ýã’CÑá\óÓ�¾Ñá¼m„dÒ`<ËŒ¹C¦¾@!D«TÕš%‘ÐÏ÷Ö”ß~{ué9?EBoÆ(õ¦:6¦óR5ìõyÐ÷é÷‘àO©¸vk0Bh¸d|µÝù¤ˆÒ¯’a˜øqZ¸\‹T¿¥D:ˆª¤ A+<·A/�•/ü¼ôó+§ö˜ú‘™77ó�‚ Œ,°Bô ÐGoßÊØ{Tµd½]À#”qšÙzR\#ï B)Åè�íM›>¨Óµð9º}›,¯Þ«)Ë—GÿÕéú  %?âî¥Ùäº ‰ØÞ"UÃ^!Jjfxª¯.WäðBF*bh ‡¾*ÃyI™¦núOÐ÷ °á\†é–†ˆ=óœ+Õq„e¢c´ 5É­ˆ•ÏÿdßÇ—üµàÂ÷¬‚µÙ.1I°š µØG©«�‡Ö{ð‡ßË”V ¥QE¼Ø7±7k½-Þ*Ë«4 5QB”íª\®Ðƒ—ô.WÕÊ0%!¿®W„)©Öhý¨I¢Ù‰ØÞ"Uœ_äѵíwW—O{5»àS;Ç¥]/Ëm™î‡«t­ò§Hè½TÇÂ0Lü ÍO3KqÚP¼‹Jë4ï>¯êH]ò•±ÊoçWλ÷윿ñ7Ä:ô¢>澓Û:ÎÊ[›M~ŽÉ<öª#§µ÷z&Î÷EøRUó“/ˆyû¿%ßE‚¯ JC.µe^–¬ß‹öê#JE�»r^¿®²ôÄ(%žTÇÃ0L| Î' ÈÓfew_D¯ ˤ Åɪ–„KÞ›Wñ�õœ¼sgˆXlñÎ4„­ð›0úê;`˜¶ñO Ðï±È’†Âà<^8¦—(%í¼@Ýg[ì×þ³®f5@csL‡y£ÉFSªÎ�‡TÕü4ôü(”†Þôy,‡�6šF¦"žÖ!‡]“á|þu_íõM¿}€†é„€?”eŠYLŸEMß%o£’?Õ½d[pÛKßU-~J!ŠÒê�ˆƒíüøN<ª±»act:?ø¤þ[@§›mg˜îÚj‰t™ÍqÅ5vç Àv¯fÒDAt7~$¤ìöê² ·ÉòžTÅÔŒº6Ãyù™fÛÝâ¼ÙÃ0Iç¶r}®;Áv1ÆéÑÓL)Ð¥Û£+§Kòü^ÚàÛðu{Ž `;,ކ�üøoD] ¤@DÈ8\2œ’ì®}ÆÂµÎë®ÉÈ|шpv2¯Í0ÍÉmf†W�è;žòVÞY¥©i9¼t›Ãuçx“å¢TÇÁ0Lçñn˜h¿#ÓÌ¥´×½±`ŒÈeuZò“ñ–|cþ…#G=q”cÔ?ò�8C4ê)ѨæÿÝ÷Ûóa-jO›22Àn �§f,Ö)U¬˜+k4KÐÛh•cñÆ ÷ ÷dºg¹9¾*b`˜¶¬ŽE¿~Çç�¥rÐlÄTsó‚㦠×ÃÙÆzAªãhlùŽè–Úà5…I©ù1óæ¡§d�úÒ`Ûà0®òhù® þ ÿ^ç_û†B”}1=æ i!Ÿ™7·PüügQ=Zܹö•Ž0gŸÏcQ¤ ¥¤Ð‚Gˆ»Àæ8·�( x¤¶òÊݪ²¢í³&þ€È²é@M^Ò¾ùžÉ„>—Û3§¦$¸V ” ½§;sÿuSÕ¾“@ÓØ†IcVΛ~Næ=2ù´YÕ™J·T¨+à ñ5<—ðäÇÂ[M)˜òYž!o`ÓuWòŒy½r 9÷ë<öÆÕ¾U_ÅtÙÓÏÒ÷¤,)+¿½í{TïÞ:µn9‡8‡ÝzôÄyR_p“ZÈ&Uà u`§~’¼fàpÉ8ðŸÙ_O-ß}Tˆ�Ò¤^œa ~Ö#‡ÀªÓƒ…ÒÀ,_íí½±÷qFóèt›vŒÑtÔ�÷KoújoV( §:†aÚ†ŸúðD�ƪåêE©Ž#QÒyW÷JM]õ´·úÁ'\9/dp|Rm/ÆÒí™î¿íÓÔÍëåèüTÇÃ0LóŒʼùdû}wŸî¸EâqÊ—ÐiŒJ?ZZ¬êoü|BƒtKî¡FΘ°==êßιfíþ‡Üëà3Û:GCøPø Ê 0ÕÁD£`¡!0ÓXi¬4f�ü)!j¸…oï§ ézçÏ0?EBï¾åóö»ÍáºKÄéõ‡+›\÷;³_¼¹ªt‡G×¶¥:†aþÌeáú=69sæÅÇXÏy”vK½eûvCä?MŸOè:—èÎ1q¦„ el m[ªS½ÀÄ™d²t¦‚8! „`�5¥€ þ @Œ4 &#�‚*i�hëÃg%zd‹Æj˜ôF> ÖÍpp\î5ÎËRLSƒD©ÏtWÎ컫ËÎ’)­Mu< Ø%œ3i„銧.pÞë¶pötêj°§V-ý¹8¶¸éó M~Ð~‰h[#š¶;¼k^Ã㦣­¼ÍÝÚ9톧>Q0A™ÀÛô8J÷o¶Ú|òC€�¯Bë>cõ LºS(õ½ï÷>0L21Ú`žNÐ!4ÁdsµÝùØ[~Ï=*»™`˜”@„|ßëèÞ†¿\u¼uê˜Þ†#ÒeÓÒæè„’wþGÕéAß M~T¢(:Õuqqï Ûݷŧø65<Î7œ!`!¹ÿ �ÖÂ?!¥”nlþ¹Z©û1©11L'ù‰^ú„§ê†÷r 89>î{œuÕ¥öÌ«¶«òÆïÃÁYšlîÇ0L¼!ƒ ñH2I8{xñ„I#,Ç÷3œÐ?GÈMמžÆ¶V(¥ßnˆ|ÞÜk M~jåÚŠ¨ Yx‹=ÞmWŪ~‹‘X dfvJ¼¯Ñų÷5ßßl¯¯¸ãW€ ~l™ JØPHœìQ•_ª©øÛSY¹/Ú1ŸV³ïÌK÷ff=Zªª;¶*wc3Ìá ƒQ@…A»n Ï!C¦ g##„ûf …ENÞ™cçòÝ6®ÿ¨žÒGô� xŒÒjGˆö˜»&²`w­º¡¹×šüøTßî˜ó'"ùYï_7ö'9DÇqFΘ63U*b;æW̻ѯú7¦:–n@pKî1Æ‚ Œz™{°`€ý5ç”R"“Xxgx×úŠXÅ�%¡ ‚Zp3¤QÒy¨¼ÿ ¿÷ŽÏÛ÷‡ûn¥Wc6/¸f¸s߸®jßiUš¶=Õñ0L*LauÊàÂåñøÛ‚ÆûÏ /ðˆ;“�ƶU*oþàZ(;Ihò#ywµ\]ì’\…ñl×£xª½Š÷§ýñ ëàS9Ä¥|–ŠF4u{hÛÒ%ÕKî©SëÖ¶}Ó Î.؇“yìCý­ý'ZykfKõc&0e%fæÀµríÍ¿Zë[óJH ¥Å‡c:OuoÐ> øž)ľçY3ÎOuWÄÊ·ÊDÞP_›5Ä6ôÔ®¶)9Z«).mÿµF®Ù yST�†¢z4¤R5ªÅG)�R rkíHÊšaœ8ØaöÙκdBƒ3ùïí›%öxp’ã†)£-gΘ_÷â¼u‘·U�F»wwÃ!Î8Î9îÑ !#+^mšŠ†ŽÎuç�µ?ÞL�ªñj÷0BŠ„g¿éóô¿Íáº-ÝV€î)Hù÷9³Ÿ¹¥ªtk€è»RÃ0©A¥ËKb›ž]è{L'ÐæçkRþ�ÕÀÖUu«>ï]Wjs(¥tspóØ_á.q†<§èÚÕøæWÌŸ¾-¸õ �êþ¶�nž˜k½ì‚ž—Ÿ˜k=N¥ U¢|µÇ÷t(Fªÿþ…箾Ù§# ¥³.Ïzö†Ù5hΪÐ?µY@‰fì#‡g9)Þõ[Ã2Ž8oSpÓ{5rÍòx¶Û^‡úÿ³4öyÐ7c¨$ ;ÃbïòÍF¼!ßìpÍ|Ö[}±Ji$Õñ0 “|a…Ê|ίܧmjûè$ÔüP Ê/že�tµöǯú=5±š_»DçÀlCvŸ®Æ·%°ùå.$>$¤’Ð1Y–±"‡y3�¥‡†ç<01×z=@©W[wé›UWíñ¨µ6#6¼8Íùä_F˜oìjÜÝŒ0Ú1ú‹­.TÖ¡íÁm«VÖ­œ³Ú·zþöàö51=Öj–oì®�Ö�ׯ7Üö;Ôf{5'JIí£žªk·É±Ý©Ž¥)!<Õæ8wŠ5c:�RÃ0É%«D½þýš¿­Øû¶½ç$m¿Nõêï«þ{_T�vzQ&�R»Õ«zÔn¸%÷„¶>,Ûctæ˜éFÎØ ºðï±Ú™û¦ª �3$ÞòÔ¨ü§zYÅcvÖ¨¿Þð~Í-5-è¶ñÖ—.r=>®Ÿa*tƒÆx°òÖ^…¦Âq-½ÒB¾ïª¾›ùÖ®7‡YöåI‹*¿½èÛÊ…�Sþå‰oízsôO5?½ÒB�–Î?Â>üTq™‰‰þð!d×–ªjuªciÎM×ML–+ �ß)]_Ža˜ô–‰<}nÝk_­Í‚¬üžÔEŒv†w~ñ«gù{Ñ:\{A)¥%á�Ë % püÛЉñˆëD÷‰w]ÜãâoÏÏ¿`ÞQŽ£žéiêy•[r�1p†ÛU7_'”¸ ¼ý™Qùo噄�”Y²5úÙ£_×Í Ë$–cçï\•õÒÐñ”äÿ‡t䔜#\’»Gs¯…µ°AÅü{~ó®¸/¤…vjTóS 1BID%ªÏ¯ú7ýìYzÇÜò¯nUˆÒl]–‘3:²¥œ“+¦}¶)ò÷¯ÔÕ<"zÚ /Y1gºÉắ· ×Úq*¥•ÉŠ‰a˜ÄQ4ª¿ú½ÿ£YKü Ê+’ú¡K�Ê+ëV>ºÎ¿n^gÖþÙÞ5¿á{3ghlqY<‘Ç<ŸcÌí?È6èŒ3rμ璢Kß¾ºç5?ÿµàÂÿŽÈñF¸]³\4BƒÏm¨º}›_Þݰ6ÊH—y𭃳ž7ò8 È»KOÏZâÿŒJ �BÖ쫳ß,rñ#ãñ>e9Rîø–ö€[áýuvq¨xvkË„eWx×û«}«¿lîgKÂ’±Ð\8RÐÓv¨×ü4A‡ƒ³> Ô}œnëÿô =pf¿""·¢y†aÒ!”~¸<8ïùE¾¿ÇTÚb¯K’Þã ¹öûêÿÞ¼+¼keG òXÙΠ80äU`*8ÒÆ[㳋{3xÌ …¦ÂAgåžýØD×ÄW1ÂÆöœç‘µ÷®,½©2úÇÚ(Sz9μe�ûY„À@(DŸ^à»gÎêðƒòÅ¢�¯Ïùw¿láØ½•CB_KŸf×jŠh‘ðßš™¨ÒžvÖÖ­y#¬‡ªßB!o† ùK¶w‡šŸÆt ‘Ù~ï}߆ƒß§:–æe0ñwgö›BqßV‡a˜ÔS5ªÏ\äûðŽ�k/ DIUgÚHÉp‹B”ò9å_NÝÞù[{ òhÅrY—lKŸ%eŸÈcAH\”82cÄùÁ1 ½ÇoñÇþ;scÕ³�øÀ¾¤�ó¯÷μà`ŒTß÷¹çÆ•»bÛ¡ôˆ±ï+»^˶s}óÒ‡¸3oiöN}[hÛ�2‘+ÚÛ–GñüPýÍÖçò† 4Û«êP"¤ö)OÕuéX�Bg›mgM²ØïÂÍÖ†ˆKv\ Ãt�/¢‡žœç}ó‰oênP4ìl;)«5‰êÑ�ßT|}eI¸d9¡¤ÍM(w„Šht÷�ûXúŸà0òF³„¥¢öO)h Jý¯XâýwÃsfîš}ßh·é€K½Ú¶ëÞ¯¹©&H|#t|ã³.s˜iÆqÝíP aC‡°©éó”RêSêVJZ]_éOç�n nù¹¹×r 9…’¿NM7ö:ÀOô��{ªî¬ÐÔÚTÇÒ”ˆ1³Ã}ë£yrs¯oWä²dÇÄ0L×”zÕÚ›?¬¹ÿ¹o}wÉ w¥­”Ú†´Ð–¯Êç\¼Ö·f~‡Ò=‘=‹8Ãà)§ÙâØD¡¨"�uœ¹±êîÕáÍ ÏYEÎðÔQ3 Ìâ( ›Ë•ïoü ú_„D0Fèôaæ±ÓÏÍ|Å,agÜß@3ñ&�„ƒVéÖ©®UÆ*wv´=¯âÝØÜóq9�‰±+ºÛ°Wcëå蜷|ž™*¥mÞÀ$›ƒãì9³Ÿ/ă†T5J;ôûÌ0Lj­Ü%ï<ÿÕÊ ¾X~­=‹¶%%Éj´GL�í^X¹ð‚ùóžˆh‘f§ ‡Š×kTÛ×𸟥ÿiᤠyQJi�RWÑÃ[:z®J¨ç¾Ue—”b†azZÅü—Ž.xßmà,XysÆ|ïKŠVÿáqíû¤ç.t~`–pÂê™Ò�„E3‡¸ƒþ?uÐ5�âÙÝÑö4¢íhîyJ)Å›;"ÓŠ/‚¾™oû¯8T¼œPràÍQJéîðî � C�±` ‚äìâŽB«}«? ¨�}m}°½!eÍ“ë*ÿîSôc“C2Œý>2÷U3�] ¿ùCà™çùÞixý¢£-§ÜwVƳ‡¬qx i#ŽÃ€ãö³Ô‚þ€ð5}!„Œœ1?^×aêQùƒ€÷ñÅáÀ�é8l¸dì“Ãõ¬€Ð�Y›~]?èçƒa˜ô²¬8º~Ê«—?2Ç{“¢µ¾QiGŽþA@È’Ë ƒN0™ÿz¼ÑrB‘ öÎá…ƒ—{Ä•ótæÜß„ü/Ç(õP jE¬â»¹å_mjzÝ÷ 79£=ªGCeѲ«:KœdwKî6�` IDAT#ã½Bs%dGhÇï«êV>ÝÖ¾^­YZúì•ÍÕCï="û.cŽÇŸ’o¿#àúÇ?·ÔÜU©oæ"ß#r„çŽ0/ò˜¿í”ŒK‚1~q±ÿ¾®u ì‚=S⤃7§¥@¢tx £N‰®½ÙañÕ%Zw­ùi,HHųÞêëú †ïzŠbR‡¤Û‚BS­Ži%вé›�ÿ †)éÊŠî Ã$ˆF(ÙçѪ__âÿ÷GËC/{ÃúžD\'®=?CDÃY÷;³?ø8¯èÇ»3³ïk4�j.ñ°aÎtŸ3û�Û3³^³bܳáù˜Û·²nåëêVÎëášÊXÅʆ×Íœ¹¨ÐTØ?žq·dkpëÒyß\¤¥K‹¢ òg»êžû¾,øsÃ�±€1wë�¬kOγ^\(F*îø¸öúm•J€À!îþ³ÿ7m¬å&„šŸ±Ò]ðˆã1j¦ç±h‹×u:³¶TB�„�%ô@RdÀ†þÆ‚>„RÚ±¨ññVÞ*VÆ*vdŽg8x¨¤“bz,Z#×o løf[pÛÛa-¼—B|g°„5²gúêò[_>¦Ç»¹FÁà6òö‡çθç÷Rïv¿¼dõnù‡;?©�>벬gì&l2IX|p’ã_„x>_zºaÕ£a•¨j¢“Ÿd •6çpöj„._ï/Jý¯°;¯Lu0Mòbþߜٯþ ­SJ8”üE/†©ßšbs¹²óÓßBó®¼£Z]§ètyIGu6ùAY?ôaWÎëGL£b”„—EÃ+¿ 敨Êò�ª¼#HÈ^€vdo é&A}Ì}ÎÂc¯â­®Uj—7~íWï¯�¯õ¯ý0[ʘ)fŽíiê9¾ÐT4!$ X0H0Â-.dG)¥:Õu•¨²z̯ú«¶6ÿP«ø¶"V±J!JyKçÆÃjOdÁk›k^~èÈœ‡D®~ÆÚP‡±ï?ŽÊ劥»O ©¤lþºÈ;OÎóö|ò<ç�¸lŸ1sªó©ª€VùóöØ—‡Ë‡)„ŒœÑÕ£šú/a1£¥j K6 K^J@£ZX§�[ïpöj PêÃçy°— :ÞhÛ´'8•0Bh‚É2ÆÅqY€²/&y4BI]˜~ÛÛüáòÿoï¾£«*¶€ï9íöš^€„„ÒAE±¡< öJ}>–Ïg×§>TìŠ ± **¨`!:’��r“Ûû=mæûƒB åæ2¿µXËœsî™I1wgΞ½ƒþº;ú£7ŒË!ïi­ ~˜!Ý%$¥þ¯H‹Ÿp;îZ ¯òcµÚ¼R Æ�kèy€[rïòɾ½‡\‚cj¬´"RQZ©øn“o0ˆ±h]^’`ÏMÒ$gX}ƒØ”Cßt€ª¥Ö/ûNÑYé—ýÅ–*ÛcÞ-€ïõ¾ØÍÈ÷™Ñ'åꆃƒíºþOžœùîýë«'K* Î_xl`–Ð÷šÑ¦ ¡3gZp}êëW-¨ m®ln€�xÍ¥Y“çGq´EŬxÄ FÞØd®Ð¤ÌIÏŰøxKç²Ö½ö±¢ÀŽw[úº®*ŒqÍã.Çô÷3ºÿÒ�:]Ù†]N¢ç@Q':Œ÷çYFe"ÿ²3ºí—�Ñ%K7…—Õø”-бﻇiqðÓ�N×3Lê Ǿ³CWàcYÝikHËÒg ØÚó>†]˜`D oŒDÃ÷EìH?ÒrvÂɘ„æ9ïéeÖö:=Ý8‚A1¡ »Y&ì ˆÏ-ØíºGVIøö�\×'›Ø¯'žd �›Â§¼?-í�«8®ÛQ-uʾJ­T‚.™HQÃA dBÈ&Ø’l`k·¢�v!©UoÄNLÍm©¿¹Teû£.Ç/¤fÍ·²l»%®SÕ¹…D,–‹{*=ÊöEÁŸ6”‹?‡D\¥â–u^�§?U²´®R–VAœ–©¬¼u˜�·¥`‚qy¸ìÛ6Ü*áANsB ®{|Sížžóu¶AHØ¿$?£OòõU¹|i…ïI!žû>sß�bdŽè©íÐ;�Ï\p}ê+7¿[ëîZiUB?‰v¢b5† Ž{‚[¢t•Ç”M)ŒE>Ùëìs�=õ~ô[ŽEQ‰Œa±> ú=aÕŠç/;#Û×ï××ùÕMµ>ňa'!�'ài¬ÅÁ> îÙë’뫽juXÂÕ�5ÐiJ‡7yl‹Øäž†ž#ª¢Õ«%,�ÐÅý¾­ô¿Öˬé{[¿Ô™ Ç2õ|ʳò޺ê×ò³�1eÇê’Ø7w~ìzpñmé¯7\30[È]4+mÉuoÖ_á «-îÕ™¨Dõ8qƒŸ®.F°÷5¯ûž~‚¶ÿH�aH¢çCQÇ»Õ{bÅ//÷Ï•TÒæW!Õˆ’@ ªº¢2 I qaM¶Ÿ:^uªàÇ.Ø{™yKwL°Z.]Ù¨‹û ‹Hoìv=ž¢å³§äÚ.h8žcÒçŒÈ^xWAÕT�¨”|·5üÖ}Ÿ¹z=y©ý_ngòñ}uÃß¼1å�›ß©¿Ê9~W€��Wò9R5iý=—xèÊ�½D v<êrLŸŸž½´¯ÉHô|(êxVáR+Š"�èÕÿã©SÕ¸HÕ¤�4sf»B¹2R¹*Ñóé(!×¾¸£îžÝþØÞ†c Bhlºqè�RŸÑsL2! ¼õ[à‰EëB?(xGj†AhBýØç¦$Í7ë˜Ô#p¨ˆìÝ–è9ÄKW~ìÕXµ"oxÞãü·KUh_-Š¢ê •À�& w×w;!„ª#Õ{$,×�rZª>ªÿ»°æî·ÇöøÀ"°v]žc½¨>*W½¶Ë9;*ÿ#_yîîžÄgžÑWw2€À!öŠ‘¦‰® ~ᱯ=3$…Ä5'+^ŠƒÅŸÈXö&zGR­*HôN¿FB½ås÷™mO�Í!DËìP•‚b,¹¼pj‘[ÖÜ â…ElZocïá%¡’„Ì!ÁÈ&wä«9Ûêæ>88ý^ÇËpÓú$ÏØ+~¨¼XPKnýÀyëâ[Ó ÈÖôà9ÄÞu®õꨄ¥ÿýà»3&“N×[éh|²oí&ߦµG¿’:žé‹ ï™<^ès¹Ùvq¢çCQT×tà±WËœeK~ŒE(!ÛQ3´§òŒ`Š(áPu´ê·DÌ¡3øl¯÷ÙÏʽ_4>fâYݳ#²ždÓýP¹K.¸î­ú½aõ Už{Ï·]wó8óƒƒ:¼s9ud4çç`"!þ¹^×­ÛÄhQ¢çBQT×t ø10Lê©:ðS´ú+ ãs˜}îX £ÑEÔˆ³^¬ßÔÁãw &¡y;��üêô˜ÅÀ1ºçFd½œkÒœ ¤¨FZyϧ®û"ø@õcžC죗Øÿ5ã óC¨“%³we4ççp¬Ö>è¬�Q.KU‰ž EQ]Ï�àÇİIBÌM–¤™6­#'Á"V“¦MƒB5±Ú�2–�Û�K­…XŽA‚�cz˜¶×FWtwãó B¨·EÛã¾Ai/š6àÓ‚Ðü«ü‹Õ¿ LF÷ØÅö;& Ð_�:YB{WEW~šV!K«_õ:Ÿ`õ¸ÌS£(êøu`u _òFèôCÇë�7, ùŸí¨IðŒ�”oÌ?`wp÷òŽ7Ñ€¦›Ayz†qL®Q3zlšqt®IHi®Ü9YæqÕyÎ3[3TBBÿ]æ�mÓ3¶gX.j¸Æ¤eôŸÎJ{óŠ×ëä;"Ÿ}óM(ºòsd+ÂÁÙŸs—=õ¾DÏ…¢¨®ã@ð“Å É ÿ}�Å6­ ùÁ¡È›;b)Bòé<ÃóA%èóHî?�þŠãB É1j�M5\49×69KÇgXÖÈ2è˜Wi®ìi›ìß«;�ÿŒJÄýŸo½÷ôÏzŒÉ×f˜ý�“^`øW®N~qú{õ‘ß‹c_ €¨Î ð=—ÎñyWšm“=Š¢º†o¸«£¡U Ù_.;Ÿ×äN6Yn‡Žù‹•`p€[t•ùd_eŒÙá8òLš±�Íüè�qÝ—>vr惃lº>v-gnIà eazß”›ÎÎ4Oc°õµtæûÎi%uruãëz$ó©/_�òò©½´tW ÕiÅv¿îuÝ»MŒcBh�NQTÜXùÙ‹~³&Þ8VgÎ!ÄL1Y/[ôϯVäõñœ€À)6Þ~@]¬n‹ŒåºxŽ×Ñ“m†ßÔ;éîIÝ,Ú4œ¡=îkäÍc'g<[ñ›XZ.sÊ…·}è¼ï£™i¯¥™9kÃu}3„ns¦&?Õ|Ǿr—²¡=Æî$IJˆ5jYmo+oímå­6Á–bæÍ>ÿŠHå K�ä®È�*Q«U¢ÊÐ�õ¬hÎÏÑù°Zþ¸ËqëéÝ?·³¬õ诠(Šj½ÁOŒ�Àû~Ïó£µú„8Ë™oµ&?ú¨Û1Y!DŒ×,¼¥[¦6³�¢`Ñr8�Þ(X„¬Óû$=qKß”i �KÛSºŽ·½2ºÛ7ýQqiuXÞ²º$öÉýŸ¹3_¾:å)³îïÚCºkr¿øgÆ×_¬9×áW··÷<:kì£{{�—©Ë:«·±÷0žáù#]<ÔzòA;bŽê½á½ÔÆj~+•|#ci_¼'Ls~ŽM±$þüˆ«ö�§RÒŸ·2íóGEQTSzÜR‹|¹!=Ðfà\ƒéÜ|^83ž°òÖ‘:N§�*ш_ö¯ŽçXp'Ùuç¼5¶ÇŠ»¤Ý�À§AO“&÷±¡¯›y6 à‹Âðë/üè{ýÐëúe ™ïÜ”ö^–�;)^s‰'±Ö\Cî”+º]¹ú†œ¿;+uÂÿ 08¥¹À§)éÚô¬S’N™:)ãsoÍ»µplò¸×l‚}8ÐjÃ�Àêhøý^÷+ �à)Š¢â�0p†!€0€¼(è�Áû;l Ã]k±ß¡EŒ=Nã£|cþx€=á=15vÜ÷üaÒœ�ežùÂÈìwOK7çZ˜ÏÓR Bh\šqÄ­ý’ÿÇ3È ¨$òÊO¾§?+ý„ñÁùãûé†=?5ùE³ŽÉŽçœÚ—¬I>íÂŒI^š9ùÝ|cþ(=«73ˆiÓוc8ÎÄ™RÎH9cÖ”ì)_Œ²�zFÃhÒÛkÒ�ÑÇ^ÇN%$öUÈÿÒáÀO‰ž EQ'. ß�?UÇêr~�†¿(c;.8[o:s¨VwÁ^ß&âÒ2uY!Ä):ÿTˆ>ú«:/À\ÙÓöÄ #³ŸÏ5i2Ûë¾î˜Z[*9ôßÞ äà†»¹wò—çXg#."×�Ÿ¸¦oª�ʽ×Côg¼teò�©½æ/7È2è¾kº_ûÍ Ë  tœ..•«S4)Ý'¤ž={Jö”ïí‚}l{ߟ>öj™Æuϸëf–H±ê£_MQÕr@š6½—ž3Üú§{ͽ2!¾>÷œ�í{Z†áµ Ãϲ%Ý»EŒþÁ¸¶=OÒ$÷3rÆL™ÈâžPÉjH`SÕ¶ÒqŒ}Zï¤gï�6ýX_ƒ ! Bh§/ºo—_Ü’ÕÊ�îHQ‘/VRU*"*®S09j8à5,ÓC`‘‰AˆW Q¼auïMïÔ]÷åí‹óRùŒ†k91SGÏ�ÉdáÝŸº®�ÉÄßÚÏ9ž´¬6ë´äÓ^iuYGŒ‡B= 9C®íqÝ·Ëë–?¼3P4ŽãŸÇã]ãŠûœµ×ÌKÍþ,“çS=Š¢N,ž‡Û†_·Õ¿åݰ.Ú&FW¬ˆ™d´œ 0€×ö›h0ßüyÐ÷T{žªIjd�æ�r»$×q[ßGË"óì�©/_•gŸz´kLpYP¬® K%ßW~Ûæ�þ앲 Œƒ &hq®�c*Þ;ä•ÅuòŸw}â¼ÿÍÓæ¦™Y[Ãq†AèªÑÆ ¼üÒÓßzg‡Eìné˜ñ¤cuÙç¦�ûVsÿ =¶‰3YÎK;ïIqÂVÿÖç;z|êo¥’øÛ\¯ó¿%§=abXÚ¯Ž¢¨vÃød_�‰3%¶ ž±Æ½æîÁÎwýž9çèMgj†ç†»Þb›õC8°0„qE{ ž¡M? !„ÊÂ¥[0ÁÞöºoGbÒÞÐ+é©)¹öˆi²Ÿ–Š öˆŠo“'ºãË ïÂÞØŸŽ¨\† 4[Ö!xiY8 ‡–AŒAƒ4Íåa$"aIÅ€ULðŸ{ÄŸž\êysîUɳ×Òp 7k¼ùj‡_qÍ_xXVI¬õ_…öà F;6yÜóýÍý'0ˆmQ²JTUƲtÈýñj¦jö¡ œÁ2!õìÇœ¢sgm¬ö{hcÎÍùi5üS$8?7 ôšfIšÎ¡øæÏQÕup–" b˜ö‘7lðnx^ÂÒ¾rYú}y8¸j’Ér6@'¤_b´þ룀ç ·u`ÈÔËØ{$@U´ú×¶Þ/{qËý·÷K�©åáÐó˜R•ý–z?\Våÿ¨"$@3�R8ÙÓÌìÀ“{hËÑäZuL¦YϤÆ”fa“4òRù“–Ñé &x¯Sv‡D"Š ‘ëüª‹aÉ*Á‡SÔ ÿð?ìÿ”¢.Xx M_ŒöÁô7õ¿m„mÄd1Çø„”PpWp×jŸäÛQÃ{|²ï U,�Ñh­¼5CÏêdê2†çòK ¤çôƉéç~´ï£m15Ö¦íð4ç§õdBÂïù<åóB¿3õ¦q͵~¡(Š:V@@ìR‰ªš8“e„mÄìÕîÕ÷¨„ˆï<Ï�e0�Õ3ŒŽCˆ™aMºå÷hhñ^YZÛÖ�í‚}”žÓ[ÃJ8X/Ö­kû§ÒáÐ)©†)O Íü·–cÛn½Û«\\îýôÃRÏça/FÀ¦˜ØAgõÓ�é�.Œ�§qz_}Ÿ¶NŠc“Ÿ&4ΑÈmîz“–ÑþojòlgPu}µ1ü! ´u­eå­C&¤�ýèÑŸ°‹–mô.tŠÎŽ}Î#ä ²œtM?S¿É9†œAÍ]›¡ËÌ›4öéŸëžN s¬ŒuE‚]9×½�Áÿ<@£ËKô|(Š:þqµ±šUµ±š]ÙºnZ]º-°mA@•J⯫"¡?'ÍgXXVµÙv×=õ7)„´igVŽ!w8�x�OñÕ¸DWq{|2©»AzÿIiOø¸bŠq¹÷ËO˽s«ÃÒrð3—“ÌõÒ]sÖeÃ�“wÓôϲ³):þðà©#ñ,b_¾:åá�H<+vD>HDÄ F7Ê>ê#g<â.4L°Z(Zù§gͳ.ѵN%j¨¥ãHX*-ônx²(°ã�þæÓF'�¾ÅÊ[S�tý@ËÀ ·¶�vÄ+[:VúØ«í"W<ïqÎþojÆÛ),¯ÒEu@T�Vn÷o_’­ë6 E“’Ý×Ô÷úOÁÿù³ oÞh�~„�åLçL¿ ÎØ"F¿kí ��,$�bÃx%O¹ˆÅ¸WÙmOƒL·ôK~d�MŸßpLÁXÝê‰?½µö�-žè�˜À�ªØs’ø¡ÓO7OŸÐ_wV¯4>£¡é‘De,«*`I!2&?*#B?FaYÄò p Œ¶•�T’‘5¿zMò³×¾QïZWû:x§“�·ìeì}ΑÎKXŠ­uÿùæ÷šÇ¢xÚ8ŽªÑ}…Þ �×D« .̘47M›Ö䊂‘3YšMwÄ¿B+¿&ô±WûØ‹,}Íëzî{ÚæðÇÌT|ð èG¦èoNô<âÅ'ªŽ’€¸‚HG¿š:Q4$èâ�Á] Ç$Ÿz›™3[‡ZNžº+¸ûã€ìß²9ùáÏhdíD£ùl+Ëo²Ø¸»¾æ7H°Uƒ2œ&Ç�s Àîàî? ;œé¼lóÌ‹ºY'ìÏ뉩D~·ÄõÞü]®G" >hkúàîšsî>Çzߤ!úÓtÂÁ�IC°D¤Â½±½;ªåboX­R]æ”k½aÙçUêDùïö"’B$ŽEƒþ®ÎmÖ1¦TkK2²†É\ Ï¢4«ŽÉJ³°™ý2…i²Æj.èêfçS>˜žúƵoÔÏ,(�}Ý>_­c“kȽÂ*X“›:§`EùÕùëÜϺÇÚùñ®�Õ~÷eõ�˲._˜¢MéÑÔE½M½Ç­q¯îQ#Eí86ÕrxI0ðJ:Ç÷žiM¾)Ñ“é*ìÎúÉ=ßJô<âåçšÀï³Öì[­BƒŸ.äÀ.ßîßöÕhû˜’5ÉÝGÙF>°¢~Å• ²0àyqœÞ0ÖÄìoÓ0Rg~šÞpÍÊHè°6 ÇBÏê& Éi!%pˆŽãª’kŠ–pïÀôûwU†$ÇÃkf¯u†cr õHâ†Þq¶õþ›N3]Â3ˆk:¼a5²®L,ªt+Û¿Û^·µJÜè�à�2c‚ÿZåiñ ÃŽƒ?Dà `X„–�YËôÉOåûœÚ[7 ?•ÏK·0ù259™6ÎÒø…Ù6.õÝ›SÞ¼øGmI�\К¯QK±ˆµ±�x¤ó}…_nð®:^y7nÉýû’š¯¦_ÓýÚ%MR4sæôPg¥¯É¸Âd½´¨Óñ¤§I3ª‡QȰ°zvUX*ÐpÈvfí´=õRé£K<3¶UI¿«hàV@GèÙVí*¥Ða%ì�*Ñ& xšys“IÙTb1®yÖ]÷ÏE>®¥S•8M¾é”Àî¢ÀŽ% 4œ”ªI;  Xÿø%ZÞøú‰FóÄ“µº‹ã;ÕÄŸaºüÃRÏü ®Èb„@kÓ3C×–ŠK~/Ž}¬àøçÅPŒ1à&øU¢Ò½NªZ‘×?ârÜãU•¸î ¤(êÄp¤.Éêÿ–·ÃJ8`âLö‘ö‘÷CäOÞ—ÜÊß¿dÌ kœaM~Ľê*Ðñ¥ÚYv`Ë êÉ cûi´g5üë+hÏLf¹ÁI,7ÈÀ0=9„R  9Iƒ,¢Š•ïöùßl8Fˆuõ×@4¾» º:-£=¬æN¼y“]Ïê�M� +áVU–¦9?£0Y4×ëúŸˆ1 R)Šjw¤Q%ºgG`Ç#l#&#„P_Sßqk=žî]++eyóâ ï£[lɳ„Ðh�að­~jA,ò!´Ã/{@gfØÔtŽË°²ÜÀž¼Ð˜Vß?�ãR ­ŽAfbt< Á  a¢†1V¢JH¤V•][cÑ’JEÞãWÕ—ªTø°êcì"ðw+ŠCYx6ïË ß 2&�ûH‘8Öèér¼’gœtèñMJ&d"­¬$ÞF“¤®ï–[5šóÓ1€º,äŸ—Ï ý¯±Ø¯Lô|(Šê¼Žü`ÀÒ6ÿ¶÷[_¨A­†Ñè‡Ù†ßöSÝŠu*Q#½/]e±]ofØ�ϰ%ß»³®jEcG+æ‚8„4&†é6T£?ÿ<ƒéìtŽïÝGÐäèZÜÇçïªÅ !ªDˆÒu´Öp*A W˲»J‘j<ªZ¾1ݲ.þͧªÛÝ¡å•-@�¸òË�ò¦Žó ¯· I£Ü’«£ª€£}ΙG:QÃ%4ª•b„x_÷¹ÿ¯�F;h˜F7€V€¦(ª)G ~jc5?TGªvö4æ E¡!–!ÿØè-å�+ýªºçc¿÷ãÖ¤›~ÁŒÔê�©7ÝðuÈÿlK&! ”:^o¼ü4½ñÒ3õ¦S £ií'¤‚·‹Ñ½{e¹Ô‡•²2Y*Ù#I•NU®÷«¸‘EB{³Ehú/tøÄYP nW‰ª²ˆ=(ižG¼¦¿¹ÿ¤?\¿¯$@âþ}бº¾yƼ&w.ú%¿Lj�A¬V<árÜ‘�˜BH Ž1xiîÑ_ÕÑê-!%äµð–ƒ›þUhóšM¾M¯…”àîxÎb‡Y‡ÏÒ³zkSçw…vþÏñ©öU!KO¹÷>�’ùj2Ë5ù=¥(ªë:RÂóåáòeN±¾´áãÅd}äµôìïî¶§Î΄n- |bËå’Xþš×ù欺}—Þ^W5ñq—ãšß#áy5м9Œ±[!$ >Ï"Ö¦gõÝõ¬¾;‡¸^�îXÇ£â+ ø·•`USç̼Ù>Ê>ê!q‡µ¿hG(I“têHûÈÄV²AÁŠ\;¾ðRÑÈçïúÝoÒ ÐEêh+?ñ}[ü[—¤k3îG!#g4³ ûgmmí/ˆü](ðæùËÄn<Ÿ°¿íÅÕfÛ5߇8eSã{!f FwÑ-Ö¤Æé�#[2QLQ Q×Å"[¿ ùßú#^%¸O®F b8±o;µ›¾ÛàTMZ¾[rIŽX]aL�{$Ïvt{zg� mñm^–¥ÍÜT²ñ0۰˲¿|ƒwÓñhua䌽ÎO›øŠžÓ›š:ïWüue¡Ò•­½?Ýí•@ü<àÿÏA7`¢Ñ<1Ñó¡(ªó8jðP*þh„mÄõI𤠀>¦>ã·ú·^\©X\.Kë–…ýKgZ“§7\ŸÊñÉÓ­IOüÇUw þ«§`˜eKžs�Ù~ƒ�aZ\)wY8°b¡ßûòN)ö#4Ñ'‹gøìLm昆gdi³Æåzöw‰Îê]ÁÝ߬vÿ1/ ÖC °R§"R±È'û¦Ù[ê¡çFÐŒO=ó~žáMºÿ|ˆi²ak$ I#/L¿ð­n†îƒŽtÍÎÀÎ5Rt¤óGCw{%N”`ÿ#®Úë³9þ÷“´º¾‰žEQ�Ã1?9P¼;´ûû1š17hY�ᔤÑ÷VD*–€¼$èŸwžÁ<©/¤7¼æ"ƒå¼/ƒþóvˆ±o“Y®ÏýöÔW'Lg²G¨æÛ c¥ ÙðžßóÊ&1úµL~Óã>=[—}j/cï«û™ûž*03�x¾2R¹yQÕ¢Ûj¢ÕßÆÔ˜ƒ¡ËÞ�œWòîÜØöå¸äÓniê¼À¸äÓnM’ûmð®Îs¬&@Z�§Å3|jocï«&¤�ý ‘5&é:Ÿì­ßæßúZkÇ¡O"Äõ°«vú«iÙ‹»5úEQT×uLÁ"mòm|w¸mø5#=õ=‡fé².¨ŽV/©Qä¼oþ_RÚà ¯†»Ù’4{¾Ï»Ý–üÔézÓ¨c�&„¸±âyÍë~uy8ðfãêF§=kÈêmêuà ËI—¤kÓûi�VÁŠ\«Þ±ÞSðFY¸ì+ K­ÙnO%"oôn|i€yÀEv!©É:<à ƒ­ƒÏíiè9¢8´ûç;Ío{$ÏV Knä¨MdÄš-œ¹G¦.óÜÁ–!—w×wÊ1ÜsÍ!d³wó§ɳµ-Ÿ•xå²ôÇË^çS%¥?caÙ&oRÕuSðà—ýJB%ÌÆ° Ë ·�˜åˆ9V¨D ôͻŚt·�å ¯9]o›Ë ïç šÌ–Lj·$V>êrLß%Å~†F�ªXÄZú™úß<Ü6|f–.«WC~HD‰DV9WÎÙؾ@ÂRMKÆ¢:� ,YU¿jÎÅY—<×Tâqo²³ ¿|¨õäÉeá²m>Ù·µ:Zµ¹.VWQ#u15æltmž…³dfë»õ¶òÖAyƼ±&ÎtLÉÓŽ˜£¼ÐWøÂ±VTç·"|;�åóîIJ½+Ñs¡(*±Ž9øÁÇ6û6¿žoÌ®a4Z€A–Açx Æ×Æj¾ ©[às¿<Ûžz?÷×£-!¶%��BˆúEзxާþ_"!ÎF§ØCî•g$ŸñP¶>»OÃAKÒÎÀÎåËëWÌŽ©Ñ¸n…¦:. ½�íÍ>Ì6|Ê¡uÅ †É7æ€ÁÃmïmω• oií×7FÕhE{Þ—J û$è}4“çs¯4ÛNØ^„EÝ1çßTDö~ãˆ:Š�4ú_,b-߇ïVÊr“[–�Æ«*¡9žú§çxêg6|Œœ±ÏY©Þ¹,ë²�Ÿäs|SóÍ}ËË®¢�ωe•sÕÝEþßcÒtƒÑx +aÿ�ŽrŠÎß1>?!ÁW¼ÎÛ‹¤­ÖMQ]X‹‚Lpp³Óû˜à…óŒyc³tY㼪ZòEлH%¤EoZU <éª{`QÐ÷´HHCÃT6K—uîE™2:iôuZv“KL°Z.ß¼¨jÑä¢`Ñ« Q:¬ïÕ1$,9–×/ÿç:ÏÚ�¬th“J·è®YæXvï®àÎ7 �¶¨Ó­î�Kãª××Î,“DºªGQ]T‹‚€²PÙ7Nѹ·ác £Ñ�´�º‹AŒ`E$ø^¹,óê�WUBÿq×=òS$8OÝ_‘õ6ö™15ûŠÏr ¹C_¿Ù·ùÛÏ«_àë×m=qŠªÑŠ•Ε3—×/NÆrÜsn!¤,\¶õ‹êϯÞÜõ´[ÐE·ºw>¥²¸ò^gÍŒJYª>úÕE�hZü„ÕpɶÀ¶¯ëiì9ª�©ïuE)Zô-<–{¹Åÿogí+ÂÁ¹ ÇXÄFÚG½0¥Û”×ôœÞÜp\Â’ô£ãǧ¿w,›*b‘&5w˜àèFoáCóË^·Å·y™Œåv_"„�èq|_÷ý“ŸT~|J½X¿ èJM—P"‰Ëg:öMÞ!Fw7®ROQÔ‰¯ÅÁÀîÀ®rÀÓð±ÀšQöQ·#@z€ý»*J¤ØÞæîÆX|ÙëüÏšhøƒ†câÌ£ì§<3>eü­�¯�©±ØwµßÎ.ômxª-µ]¨ã“_ö|ïøþÊ…\R(Zî—ýî¶ÞŒ«£U;W:yñÃ} Çoòn|’Výîzª¹`–£êüO‚¾ÅA¬F=Š¢:Æ1ïöj̯øw‡ŠW · ŸÚp,[—Ý+×ÐsjY¸ô=—ªT¼ãó¼ödJÆ3B‡íØQ Qú=| ¼ÒPšE¬~¤}ÔÆ&��Î3¼ÐpmX ûW9W>·#°cÐ Í]–B”@M¬æ»%5_­J’NÊÔfžÕÇÔ÷¼TMj.Çp-£Õ©f&‹ª“‰UÑWÚ½¶:Zýse´rUL�U@œWzhÎO§F|X-ÞSó/áàyçÌמª×�Ð3ŒÙ„X]KвRuühu.B’�tö¬¼[—7>¶'´gý—Õ_œ'aÉÃ"d]œ™³-_ÐdúÚ_#¡‚»ë«Ï— ñ0Àð#í£^8#匙�ßÀbj,º¢nÅã[ü›çÍÀ3|Ž•·öIÕ¤ö0ó+‹Øî  ?C Qëd,y�’³Ö):K"Jd'Òaá&ýB£ù+Ù�~uûòaÕµ8àûŸ Ä×ÑcÇ�1¹½Í�Am/=Ãd1€4íus‡";—†ü�á&Zô4–¦ã‡L͵Íj¯q©#+‰%ßíóÏÚ]ùí“Î�¿t˜q ôî‰I{ÚºO*^¶5­útFihÏ[�æ»OJ¶qÇöÝR¬ì®ºê˪yÓþ Íɶ“=7í¼ûÄø¡R‰ªþTÿÓ³<ëÿCGP-€ààŸëΰZ˜¨_–èªS[úóÔV-ùž$üM¶‹8¿'ôÿí6j¶ˆ\sU! ô2ö>§¡BéY}Zqh÷·*QC5Š\yŠÎ01�ãSÂÇþãr<¸MŠýû¿q\_Sß›ÏK;ÿažáüu… ÆkÝk®õüù0ÜnM,©.ƒ@çúå@ô�j‰úž$ê禫ýk‰Dϵ5s¦šÐ¦(¶4\º$¤„êë¦ï64GŸs!@ãêOÞ÷BT€oCþoׯ"‹à¯¿Æ3´ÎJ�ð¨†Õh‰A!%¡’õ¿»~›­5EQEQí¨Õ+?˜à0IÎ7æ�;pCIJVÁÚk»ûb 8\¯*Uôús9@Ú{�5W„1®¡Ûä¬Ë¥jS»7¾§[rW/­ùúúˆ)mËÜ(Š¢(Š¢šÒ¦à ¬F<ù†üI�kòèY½- |Ž˜cµHˆß£ªd»ݼ)]°¿–Ï…“>îiè9¼¡9)@D‰„–Ö.½³NtüØÖyQEQE5¥ÍÁ�„E—…·ÊÖgn8Æ †± ö~Ûü[ªD�T)ÒŽRY*PDHhtטä177NpXã^óæöÀ¶— �fwBPEQEµV›3× e›ëû¢*´å.E“’ÕÛØûZ@*@T$$¸ÿxê©ã’ÇÝÙ¸c7!„TF*wn𮟃 ¦;»(Š¢(ŠŠ›vÙ¶ç–Ü…Å¡Ý+=>Â6r¦žÕg5|Ì!>e|êøgl‚-µñu2‘ÅŸêVÜU£{Ûc>EQEQGÒ.Á�BÿŸî?_;ôx¦.³W¾±×u ·  WŸ;¬ñ5˜`\è-ü¢&V³¬=æBQEQÕœv+Øä�+ª¢U{C¡a¶aWëY}n’�tÚ˜¤1Ó9†;¨¥†KtUnð®Ÿ�£EQEQ'¸6'<7¢b‚5y†ü3'28ƒ=¨¤A–AS3uY}ïîÂãß]¿Í+�”ÒŽó (Š¢(Š:¢ö,ÛFÓ}ZÏékl¼-«ñqË2Ïð‡5�¬ Wlû¬ú³ócj¬º=çAQEQu$íÚ§DÄbe¡gâC�7ø¬õ¬›OŠ¢(Š¢:R»7i+ —~î—ý®£]W­.Ý)ÿ¼½Ç§(Š¢(ŠjN»?.ѵ©"²wMs×`‚ÕBï†7%,9Û{|Š¢(Š¢¨æ´{ðC€Äֺ׾¢`åˆUšJÀ½3¸s!Ðî´EQEu°v~¼²·°4\º¶©s˜`¼Á»ácË5ñ›¢(Š¢(ª9q ~d,û ½…ïªX=lõÇ'ûêöKÇc\Š¢(Š¢¨£‰Kðdo¤üs¯ì©;ôľè¾—ä*ˆÓ¸EQEQÍŠWð˜àÀZÏÚ×U¢ª ÇT¢ª…ÞÂw€vm§(Š¢(*!âüì íùÊ/û WE«vz$wa<Ǥ(Š¢(ŠjN\ƒŸ�Ú¹;¸ë§†�ËÂe?ÅÔ˜£¹×PEQEÅS\ƒ ÛÛß+áÀvÿö/@=Êk(Š¢(Š¢â†;ú%mã�ËÂ¥«¬¼µoP ÐDgŠ¢(Š¢ª=»º7‰‘r „Ç*#•?Ä{<Š¢(Š¢¨„ck0sæþ‰žEQEQEQEQT—òÿüÙðÔIüÇ IEND®B`‚apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/images/parsetree1.png0100644 0000000 0000000 00000025426 15217274217 026330 0ustar00rootroot0000000 0000000 ‰PNG  IHDRVü,_Œ¿ IDATx^í�ytTåùÇ¿aKÀzÔD‚-Hl)T%�žº„b]XÃiàÐ6U¬¨ö§- àÑVjâ¡‚I[O ‡°ˆKEâÒ!,Új±,‡�F¢Áb Û�‚`Μæ««�aÀ­[C¿ãE$�\kryºª6èÂ…ÀªU@vvx×äçµµ@Y�™éªn³3$ày«ç§0úD¨æbõñ°94pœÅêø¤®û÷EEÀ®]|ìOeÖL‘(VŸ¯ ½\ÕP§Og ÀçÓÎá9L€buxÒÙ¼¤&MjnqåÊÐæ/ �ä X“ËÓµ©#X‡3ÿê‰ c'=G€bõÜ”%§Ãrb`Æ žgMMÖBá(VŸ®•æä„ŸaUÃ�u˧H8,HŠ5m¨Óß�ú €1—ª¤;|8s¬éŸ¶«ÏgY}úªªªy üH«Ï'�ÃsœÅêø°$@~#@±úmF9 Ç P¬ŽO;@$à7«ßf”ã!pœÅêø°$@~#@±úmFüóŸÿÄ�!CpêÔ©ˆÑõïßyyyPÿUÿïC  8F€bu }Ë®¨¨À´iÓpæÌ™¸•uíÚŸþ9öîÝ‹={ö4ýWý?…! �€e«eTÎ|ä‘Gðøã�£±±1n'²³³qìØ±¸åŒ(\ÛÈx D%@±ºhq”””à¹çžÃùóçãö*''Gމ[®¥(Ü–äýA$@±:0ë·Ýv6n܈ .Ämýª«®Â¿ÿýï¸åÒ]€ÂM7q¶ç%k gkĈغu«%�~ãßÀ{ï½—ÂÞ¤§j 7=œÙŠ» P¬I˜Ÿ�âÿøGÜš2220tèPM¶A»(Ü Íx°ÇK±Ú˜ÿ¯|å+8pà@Ü;Zµj…Q£Fáå—_Ž[6è(Ü ¯ŽŸb5™×ÜÜ\ÔÊ߆ŽsµnÝS¦LAyyy¼¢ü½M®M`,î*�k÷îÝñ™|¯^œ«]»vx衇 Çžx9K€Âu–?[·F bíÖ­êêêâéС–/_ŽÉ“'Ç-Ëî"@áºk>‚Þß‹U6ŒŒW§N�°}ûv|ík_ úüû~üfÂ�0aæÍ›çû±s€Îð½X�CË–I€‚J€b êÌsÜ$@)#@±¦ -+&*Š5¨3Ïq“ ¤ŒÅš2´¬˜H ¨(Ö Î<ÇM$�2žëþý@Q0v,0gN$Ÿ… ùðTY�™ È¿çÎ5ç¸r%P\œ2Ƭ8 V­&Mäk ̔ςÈ<÷êÜ}70e °kWdÙÂB@êËÎNCÇÙ„/ x^¬òÂ0{1™‰U/Z5›JÐ<@¹zy…+iŠTÍÞhelÕÕÀ°a¡õÒ½{è�yÉ’HËÚ‘²”«—W„³}÷…XÍ" «büòÚ²¥9ºuvJØz¢d-*+�¾}c?ÅÔÔD«’´:Zô›hy_0x^¬÷Ü,] #N»b­¨`„âõ%ëéÃø;õo³ˆU‰U>ÙÌ‘×W…3ý÷¼Xå…qøpd¤bG¬Æ²ÎL[M�hs)ѬþÍ3–Xcý.}dþ'à ±öë×¼)¡ß¬2n^™åXUÞ�XþXìfR4‹@£Éóôi`æÌЛ5s¬þXNŒÂb•<˜Q�vNÄÚIvbRØfâ”srš7±dm̘ž{Ub5;0}:óí‰Ïᆱ Fdº~}è´fMäq+³ˆ•ËÀD¤²TÄ)ÿ/—þ´÷ý7ïn‘¯Äª?r#�­¤Ü4ìKr¨¨uøpàÚk�ûî/?)@±&‡5k1'à+±ÊUJ@þ_ÿHÇ ª`½dÈfÕ AÀ»ïF>ÚS¬ÁZé­ïĪRò)+Š5ÝËÉ=í©§—ª*ó�P¬î™+?öÄ—bU/šüüð�´2ÇêÇ%}L±>øA±k-¤{´žkºA±= °J€bµJŠåH€HÀ"ŠÕ"(# «(V«¤XŽH€, X-‚b1 °JÀ·bÍÈÈc ÿ¾pá‚U.,ç3:t@CCCÓ¨.¹ä\wÝu˜8q"~ðƒøl´ŽÓ|%Ö>}úàСCaL/^¼£dóòò°{÷n§Ù³ýèܹ3N�:ÑBëÖ­qîÜ9,Z´6lÀû￯•»ôÒKQPP€)S¦à¶ÛnKaÏXuøB¬FqvíÚŸþyÄü}ùË_ÆÑ£G#Ä„‰öû%5›óV­ZáÏþ3FŒÁ'Ÿ|‚Å‹ã•W^ÁþýûqöìYôìÙßþö·1uêT 2Äïø8¾$ð¬X%ò0>ÚKtjõ2ʸM›6Ú Š—7\vÙe!/™×'žx?ýéOˆD±¿ýíoñÆohO@"ç«®º #GŽÄŒ3 OF¼H O‰µ°°¯½öZØxäEô€üù€¯%K–àÞ{ï »{ôèÑxþù笑·¥‚€YšGµs×]waùòå©hV«óÍ7ßÄï~÷;¼õÖ[¨­­…äk%�tûí·cæÌ™�´/Ðð„X�ÑeÛ¶mÑØØ˜ô™ìر#NËW#é.;QpÒ;à ¿ùÍoâ]ùö“K"ÇW_}Õ1:•••XµjvìØ¡¥–²²²0pà@L˜0÷Èß âx®k»ví"ÍÓ)9£Ì333ñÅ_~Á¤ Àw¾ólÚ´É´úAƒáïÿ{ªšnq½K—.ÅÚµkµ7‚úúzôèÑùùù(..F‘ü)X^�#à*±ÊNíƒ>6 ·Ür ªä+ŠºÆŒ£í믧Ÿ~Z˵ñJœÀ´iÓðì³ÏšVлwo(+23C¿SÏ}×®è  ù›ðÙÙ… �õë�ÊJ oßð¾ÿN½ú÷رÀœ9‘ã�ºjkÃÙ85Úêj`Ø0`åJ ¸Ø¼jŽV¬}´åó«=§X¤º]Yד&[·æ­}öYhzõ20{½¸õu’j†^¨?©bÍɉ”ˆD^¸ÑD)¿“�Ý›ÉÊme,sçÆ7 ýÆ’%¡Œþ ÄìEä&±*iÊ8ôo‚zþj<ò �cÆ„ÞH�ómV�ñ GÕ©ä!¬ÌÞxÜ6÷Éê�•q«7:Y7Ý»ò=.j]éûﵕ¬>³ûR.Võb3“®t׋b•~£­h«Df‘…›ÄªæA¢Öh‘”¼1VT„Þ ;v4«ªGƦÞH£‰ÕìÍÈþòõæÂfÑ¢èÁ„~mÔÔD«’´¼1E‹~½IÈû½N¹XãÉÓkb•Ç÷¬,àý÷ãðhb•¯ç\º�HOÿ˜í6±ÆŠ¤Œ¿‹õf)óiU¬²6ÜÆ!/i}ôoL½ë�IÍËäÉÑS8éÛˆ$�±ÆZ^ë/~L�ŠÔcl4±Ê#œä%�Š…¢�JõùmãE«ú¹¼ÐUkîe9FkÓï/ÖhóoäÁˆß›+!-b�õÈâE±JRþr‹~"–XûõkÞŒP9L7ŠÕ,2“h¬ÍJcš$žX�®7_Fö{mÆÅŒ4~úÍD7nôÚ'â¯;(Vó©—¡Ü&8�ÊÂ>v,<f|AwÞÝ(V³Gs³v¬T€ñäÅj¾ÀÌš±Nјm¢ÚXÎ,šBi«ßR*êÔ©š0!¶X•´Ôq­5kÜsÜJ¿¾dL÷Ý,^:R&o[¶„Ÿˆ%VcÔO¬AM˜môÉ›’\úSñø¥Ð ¬ºÒ"ÖX�{^M¨s¹j‡wþ|`Þ¼æc1±õTþÑ-çX�ëG½ÀeãM6WŒ»ÎÉ«™LZ°ž=u«â8|8píµáohj «§¦´©³)«ßŽ[ehÌ7ªãJÑ^*% 3àÖG9éû#�'Ï<yÙŠX•Œ¹ù[ ²äÛ A€üQZã9bŠ•b�80®ýô³(Óìñ^±>hà†e¤³0ûtT¼«ž? {FUêDþ^¦ÙbŠÕ ¯û}HjÄjå#­Æ.z= Æ£d/b•òêÅ’ŸïŽ�´š-›Xé›d}„9ˆi5cm–Çf*À¾ÌÜtGRÄꦱ/$@$à4ŠÕé`û$@¾#@±únJ9  § P¬NÏÛ'ðŠÕwSÊ‘ 8M ­b•¿=ñâE§Çœòöƒ2N=È Ž9 iÓ¦M5jTÓë¤C‡6lþøÇ?¢G�©h’u¦€Åš ¨y¡X“³x{ì1üüç?«¬U«V8þ<î¼óN¼ñÆ8uêÚµk‡ë¯¿Ï<ó ®¹æšä4ÎZRB€bMÖ FoAsK–ΤI“°J°ê®6mÚàìÙ³Q«ýÞ÷¾‡W^yõõõ�² @ii)n¸á†–t…÷¦€Åš ¨ŒXS@ÕûUŽ1o½õVØ@Ú·o�3gÎØÜ´iÓ°nÝ:?~­[·Fÿþý1þ|Œ=Úv]¼!ù(Öä3E£· ŽÙÊÒ‘Gö={ö„íܹ3Nœ8aåvKefÏž�ŠŠ =z’BèÓ§~øa|ÿûß·t? %ŸÅš|¦k ˜z©Ê+®¸GŽ ërvv6ŽÉ—ö¦ø’¨uùòåøè£�´uسgOüä'?ÁLùò`^i#@±¦u£· ŽY¿tºwïŽÏäUtWnn.>üðì0kU–••añâÅøÏþ£�2¸üòË!)„yòý–¼RJ€bMÞ J&ˆcîÒ¥ Nž<¶‚òòò°{÷–Uù‡?ürúààÁƒ¸pá‚vtkòäÉxòÉ'[V1ï6%@±¦`aQ2A³œ+mhh[5²+¿y󿬤ÔT¹aÃ-jÝ»w¯v¤ë’K.Á¸qã´¯ä X“Ã1¬– HF?h?�¹mÛ¶8wî\Øc¥|ï¡Ç/9¥0kÖ,ìÚµKcVVn½õVí ¼'@±&Î.ê�~–L´AûmÌr„I™õ—Dy�ÈŸVðéµoß>-ûöÛo£±±�:uÂM7Ý„^xÁ§#Nݰ(Ö°õ›d¬ òÓ˜e,rÉ7n܈‘#GZAà«2rtK>�°uëV\z饸àƒ|5¾T&­bMõ`X? � ¸�Åê†Y`H€|E€bõÕtr0$@n @±ºaØ _ X}5� �€P¬n˜ö�HÀWk}C=F­…ê«cÂX7a�öûYU³°­drºäxÞ‚Í ðÚÁ×°±x#N4žÀÐò¡(-,ÅØ«ÇZê¿þþ¬öY–îa¡ä¨®† äì~q±y�§Oò�$‡+V�> ,[Yvút ¬ ÈÌ ýnÿ~ ¨;˜3'²üÂ…@mmø=ÉUjjQÌÆ.-nÝ „�}׮ȾòÕ²ÙÙ©é§kMH¬Æ�Öž¨ÕäS2°sGÌ ûõú}ë)V/® �öYÉBº¯—¢~8J�<Œ’lNN¸,ÍêQ÷‰\ôÒQu{U¬Æ±ËxÔ”§û’%ͲÕ�[ÊS®Í«Œb5#V�ZõÝ6JÁ8@EEH;š‹UÉEd©„¡«Y”æ'±Êøe÷'ÑìŒ@e%з/M¬êç" cžQä"ùÙE‹šëQžs¬fo*F.±"ÖX¿³:_~+—±êE'Õ ¯üŽr-j5‹’båm£M‚•¬Q´ÑúmóÊLøVÆ£—‹´)³¿�žC—v]"„¥DªÞ(öÛgZ�Ù­.\#w%Z¹¿ld™6_ú¼¹ôE/b)gœ³ùµÚŸDË™EQf�·�£ßÓ ¤_¿PtÖ«Ws.×O«¼1MšÔœKŽ&OýF s¬Í«5-b5ž ЋÈ,âQÝS�ÝúÇôX/´x2Žö{ã£m¼ˆUú ïS¬ûU*C/V‘‘ñÍÆ(xÅE=në™(±>µã©ˆÇv)×Ò C=w©kížµMØeÜÑæ%ZŠEÿóD#éDk�™b¥äþõ뛣RãýÆ^«Ù©€£q}~Ù8ÆÓ‰Ì•ßîq�X£Ý2æê¬ˆ5ÚÑ(c×X—Êq¦C¬fGÐÌÞpâ‰UŸ£Õ�Ç,·luñêÅ<»j6Æç�×n-Û^†Êñ•(Z[„™CfjÑ«1¿*óµü¶åѶ‘}KsÁVÆ"2¸ï>`ñâÐc¿DT[¶„Ÿˆ%VcÔk&f½|׬ñæq+³T€‘/÷­¬8�D¬ö†$±Û±+Vc»fçX­F¬ê±úêîWkrŠ'VãF“]ffåÕ㿤*D¦ó¾Ú”¾Í:On{²)kÌŸš¥Œm(^òóTŸoV;Û²ád¶sÝR±ê7Ãd<~ɱR¬-{%9±JÔc–4>^[f¼k´ßë7cTÎ×nŽUŸgŒ'V‹Õk,±¾~èuÓ”BK?  8©4†<þ«JHî·[‡n¦}ª¼Š¼G^52,e¢ŸCã&™•ùM¤ŒDZòÝÔ'Ï<yÖÒŠXÕ1¢hQ›J Hÿ¼ôXkìk"«ÍE«ˆÌìT@¢ÆÊXO´�uýÉ�x«Ù©ýw<±Ên»ÕS±Ä*"3n¦7Ò]êÈš>£Žué�…O!èSê$ˆY.¸%lvƤߜ2û4V¼«>�wH~î\ŠÕÎÜø¹¬+"VíêŸÞRçX[’#ÔŸc5Ëå7YŒg*ã‰U$,R{õÀ«ÚÚˆuÖlóJ�eÕ÷SêÑoìD‹ØÍ„¤?Çj¬'ÑÅkvlKú[º½ÔÒyܽG÷†©3޵%ókwLQêÏ£êï�u* ÚGZÍÎr*éæç{ï#­Ì±Ú]QñË'E¬ñ›ñO‰tEZþ!Æ‘�@ðP¬6çœbµ ŒÅI €(V›“N±ÚÆâ$@k'�C&H-Š5µ|Y; �@ P¬œt96�ŒŒ \¼x1ð˜ÆŒƒ 6h233ñÔSOaÚ´i�çbÅj…ËŠ@ÐÅÚ½{w|&)ûß%o2—_~9>þøc´jÕ "ܵk›¿?"P‹Ãâ`)V‹ X,8‚*Ö6mÚàüùóÚD·k× “>xð`¼ýöÛÚÏû÷ï�={ögaØ)Åj‹ƒ@�Ä*�ú�ª«W¯^øàƒâNôÝwß�gŸ}Vñ—¾ô%lÛ¶ }å›nxi(V.0‚Xõ‘§ ÿÁį~õ+ÛkaÓ¦M?~eo¾ùf¼ùæ›Z{W^y%:”²¶ÜZ1ÅêÖ™a¿#à±þìg?ÃO<ÑÄñúë¯ÇÎ�;ÓÆuþüùxì±ÇÐØØˆÎ�;k' FŽ™¶ö�lˆbu’>Ûv%¯‹U¢ÄÃò×ÿw=ÿüó=z´c¬÷ïß�¡C‡â¿ÿý/Z·n�»îº ÏÈ—ãúø¢X}<¹Zb¼*ÖöíÛkÑ¡\"°sçÎ% …wåååaïÞ½Z 鎠S8¬ˆª)ÖtÒf[ž à5±JÕ•���cÇŽ¹ž³œ$�HZ6Ï.»ì2|ôÑG®ï³�R¬vh±l xI¬Jªò¨/¢òÚµ|ùrÜÿý�hûøñã^ë~ÔþR¬¾™J„HÀ-(V·ÌûA$à«o¦’!p ŠÕ-3Á~� ø†Åꛩä@H€ÜB€buËL°$@¾!@±úf*ƒ3�ÚµZ>%K0wÄܤÜm0R¾sº¸˜3(( wáB`ýz ²0~[ßþý@Q°dIsù¤C²X¡êËØ±¡þ/Gm-PV&¥ 4®¹Q¦tåÊ/\«f‰} #@±6 húôf))Hnë®]ÀÖ­‘¢7«^´Æ1=ð€7äJ±RZž#@±†GvÆHέb-,V­²³›—œU±Êrï–-‘o$n\À«g…}ŠI@‰µ°O!ªV¡¦®F+?ÿ[ó›Rõ õµjòsó±âݨk¨Ãº ë0öê±ØY»……ÚÏä*¸¢‹7"«}–öoc*@•¿æË×4•3ÖQ”W„ÕãVk÷ëÛÞqdª?¬6mÇê4GKHd—•¼ÿ~¸°Ü(Ö{î–.Œ§]±VTDÊÙ*Çt–£XÓI›m%…€«Õ(ËYCfirUrÛýénTM®ÂàœÁZÛë÷­Ç¸5ãš$¬ÊÉï”\õbÝwlŸ&á‘W�l§’ª±-U‡üW¤.B�Ö?; b‰õ¿¦N =b«¦Å*ù^ù­E‹ÂóÂvÄj,k‡aºËR¬é&ÎöZL@‰uHî�&ÙI¥ 6/@ù{åØV² ]ÚuÑä–›•Iê&÷)Q–ßQ®E´J¬ÏÞþ,F® c;f›[ú:nî}sDÛf‘°U±Ä*›>ò“&5ç0Ý*Ö~ýBùÑ^½Â7«Œ›Wf9Öêj`Ø0À+X«ÕÕÍr®! ÄZZXª‰P]"·ñkÆc턵¸ºûÕšÜnésKSz ZnVE­J¸"ÎmnÓ¢^ýã¿´¯iïþüû#ÚN¥X¥î™3C¡ä!åË­Üv*@�P0 ÒΩ³Í/×,JCG(V·Î û•@KÅj²™X+÷T⊬+4¹ªG~½XU^רIÉó¦[¬rLI¬iÂ÷ŠUxé�Š­YyÜÊ,bõÚË�bõÚŒ±¿MQ£Q�’?-y±DË©&±ªèVÿ¨ÿÔŽ§Pº½´)OkåD‚µ>ZNeÄ*b•K¢UÉaΟÈJuÓ9V}_TjC�ɵ’ ðÚ²§X½6cìoÔÇq³«^nÆÈTŸB� *cŽU6³N4žÐ>Œ ò¬ÑêÐGÑ*Çšn±ž>J ,[™�£å{UJ@ú©?‹ë¥ ªX/EŠ•¢ò;§Œr³{*@Ž`©{bíðë£\jÌï¦#b•6”È¢ÈO÷dÇÚHSŸ²¢XÓ=+l�L(±JîSÓU¾S‰On‰ö8.¿‹uÕL€ª®ë?ÔNätɉyÖ©T€B¥„åæˆUÿ&�Ÿý”€W_ŒX½:sì7 �€k P¬®�vŒHÀ«(V¯ÎûM$àZ«k§†#ð*ŠÕ«3Ç~“ ¸–ÅêÚ©aÇH >�ŒŒ \¼x1~A—hÓ¦ Ο?�nݺáøñã.î©õ®Q¬ÖY±$ ¸Ž€—ÅÚ¹sgœ:uJc*oñ`¤‰ ÑIDAT­[·Æ… pýõ×cçÎ�®cm§C«Z,K.#àE±öîÝ|ð�Fò¡‡Âc�=ÖDõÇ?þ1ž~úiíßòß3f¸Œ¸µîP¬Ö8± ¸’€—Ä:zôh¼ð Çk¯½ï¼óNT¦}ûöÅ¿þõ/´mÛ���®d«S«ç¦Œ&�f^ë+¯¼‚ï~÷»Z§»wG�ZžÂŽ;âôéÓ¸ôÒKññÇ[¾Ïé‚«Ó3ÀöI Ü.V•7m×®é–-[0bÄ-{ûí·ãÅ_L¨žtÞD±¦“6Û"�$p«XÛ·o¯=ÂKÿdC*×wÜ�—^zI«sóæÍ>|x2ªMIkJ°²RH·‰µG�8&ÂÀŸþô'Üzë­IqÙe—á“O>Aff&¾øâ‹¤×ŸŒ )ÖdPd$à·ˆõºë®Ãßþö7�Â�wÞ‰ 6¤œˆ¤Ξ=‹¯~õ«Ø/ßO袋buÑd°+$`—€Ób}øá‡ñøã�kݾòÊ+qèÐ!»ChQù%K–àÞ{ïÕê�ÿþæ7¿iQ}ɺ™bMIÖCpR¬Ò¶\�:uÂÉ“'}s“ƒÆÛo¿�V­ZiŸârú¢X�ž¶O- à”Xe·_Ú>wî\ zŸü[/¹äœ9sF;¢åäE±:IŸm“ ø’ÅêËiå H€œ$@±:IŸm“ ø’ÅêËiå H€œ$@±:IŸm“ ø’ÅêËiå H€œ$@±:IŸm“€  6/Àk_ÃÆâ�ÈjŸeãNûE?û (.ªªšï]¹2ô3uɇ�ŠŠ€]»"ë7–µÓUïØ±Àœ9‘w.\ÔÖee@f&P] ˜µ)§®fÎrrÂëR÷èk_°À¼=;}We)ÖD¨ñð1�U«€I“€­[�‚‚Ð@•h{õjšà’%Íåôeå^31ÆC§¶¾ê¾hb0¨¬úömnÁL¬2¾E‹Â˪rr§v¼~Æú=ÅÚz¼—|F š,e˜êw<Š\­”5J× .½X avvó�ÑÄ*%¦O£Q¬êßòÅXúè[?¾DúlÅje¦Y†\@@Ÿ 8ÑxCˇbÖ�Y(Ý^Ššº­‡EyEX=nu½5JK_‘HI¤÷�o„~K¬òûXuÅê ª÷ž{€¥K%òX«ü)/bÕG¹F±ªÈ{òäH±& ÍäFŠ5™4Y ¤�€™XëÎÔ¡jrç Æú}ë1nÍ8¬›°c¯k»'±¢9³Êâ‰U"ÍŠŠÈˆ3^Çôõ>ùØn±ŠX% °fM(窢\³T€Ü?wndt¯_v~O±Ú¡Å²$à 3±– ,ÁÜsµ^Õ7ÔcÔªQÈÍÊM(jµÍÅ«N$f|”�‡P_o¿~¡ÈRŸÛ�%V-j/ÔÆW´Í+%W}_Ìò¹ñúí÷k¢äx ¤™€™XK K›¢S?ŠU6ÀŒ»þ±Ä*WúÍ·AƒÌO¨©3ž~0Ëé&2Ík"Ôx 8@ Õbuc*@�J™®_ßü¸o"­:PŠJ¯*ÄÔ—¦bÓ¤MÚÑ,­D¯"­YU³"eW¬ú¨RŸ›U?W© c~Ud*ѵ>jV’VQw¬HXMoÁI9A±àÃ!’€Fñèe¶vÏZŒÏ�üÜ|-w)ySÉg*ÑEÛ,ÒËYm‚Åê‹ÕˆÕL’fWý’ó¯"~cÎUß•n(Ê+jÚŒ³Âͬ Åš(9ÞG>#`&+õ3jåøJti×EËM~~æsÈ—Ê�F‹LS‘c½¹÷ÍZÔ¦™šõh¯Ròsõæ�×#»?Ý­åƒc Þ,w›È4S¬‰Pã=$àC±•õ�ÈJ`ÆÈ.�§¤­íG¶Gˆ]Žg�x©Ó ú1Óz ÇŠj­N;Åj•Ë‘€Ï èó–Æ ý‘)ã½K´�$»èâ�c5;{«÷‡ä {”�vìËX‡ô1i©‡bµ;ã,O$à)Ñò¿©ÅšJº¬›HÀqÆO‡¥£Ck:(³  �´Pi‰d¡²3ŠÕ-–%  (V �X„H€ì XíÐbY °@€bµ‰EH€HÀŠÕ-–%  (V �X„H€ì XíÐbY °@€bµ‰EH€HÀŠÕ-–%  (V �X„H€ì XíÐbY °@àÿ9úØÀóÍÃIEND®B`‚apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/introduction.xml0100644 0000000 0000000 00000041656 15217274217 025550 0ustar00rootroot0000000 0000000 Introduction
Description The Apache OpenNLP library is a machine learning based toolkit for the processing of natural language text. It supports the most common NLP tasks, such as tokenization, sentence segmentation, part-of-speech tagging, named entity extraction, chunking, parsing, and coreference resolution. These tasks are usually required to build more advanced text processing services. OpenNLP also includes maximum entropy and perceptron based machine learning. The goal of the OpenNLP project will be to create a mature toolkit for the aforementioned tasks. An additional goal is to provide a large number of pre-built models for a variety of languages, as well as the annotated text resources that those models are derived from.
General Library Structure The Apache OpenNLP library contains several components, enabling one to build a full natural language processing pipeline. These components include: sentence detector, tokenizer, name finder, document categorizer, part-of-speech tagger, chunker, parser, coreference resolution. Components contain parts which enable one to execute the respective natural language processing task, to train a model and often also to evaluate a model. Each of these facilities is accessible via its application program interface (API). In addition, a command line interface (CLI) is provided for convenience of experiments and training.
Application Program Interface (API) OpenNLP components have similar APIs. Normally, to execute a task, one should provide a model and an input.
Generic Example A model is usually loaded by providing a FileInputStream with a model to a constructor of the model class: After the model is loaded the tool itself can be instantiated. After the tool is instantiated, the processing task can be executed. The input and the output formats are specific to the tool, but often the output is an array of String, and the input is a String or an array of String.
Command line interface (CLI)
Description OpenNLP provides a command line script, serving as a unique entry point to all included tools. The script is located in the bin directory of OpenNLP binary distribution. Included are versions for Windows: opennlp.bat and Linux or compatible systems: opennlp.
List of tools The list of command line tools for Apache OpenNLP , as well as a description of its arguments, is available at section .
Setting up OpenNLP script uses JAVA_CMD and JAVA_HOME variables to determine which command to use to execute Java virtual machine. OpenNLP script uses OPENNLP_HOME variable to determine the location of the binary distribution of OpenNLP. It is recommended to point this variable to the binary distribution of current OpenNLP version and update PATH variable to include $OPENNLP_HOME/bin or %OPENNLP_HOME%\bin. Such configuration allows calling OpenNLP conveniently. Examples below suppose this configuration has been done.
Generic Example Apache OpenNLP provides a common command line script to access all its tools: This script prints current version of the library and lists all available tools: . Usage: opennlp TOOL where TOOL is one of: Doccat learnable document categorizer DoccatTrainer trainer for the learnable document categorizer DoccatConverter converts leipzig data format to native OpenNLP format DictionaryBuilder builds a new dictionary SimpleTokenizer character class tokenizer TokenizerME learnable tokenizer TokenizerTrainer trainer for the learnable tokenizer TokenizerMEEvaluator evaluator for the learnable tokenizer TokenizerCrossValidator K-fold cross validator for the learnable tokenizer TokenizerConverter converts foreign data formats (namefinder,conllx,pos) to native OpenNLP format DictionaryDetokenizer SentenceDetector learnable sentence detector SentenceDetectorTrainer trainer for the learnable sentence detector SentenceDetectorEvaluator evaluator for the learnable sentence detector SentenceDetectorCrossValidator K-fold cross validator for the learnable sentence detector SentenceDetectorConverter converts foreign data formats (namefinder,conllx,pos) to native OpenNLP format TokenNameFinder learnable name finder TokenNameFinderTrainer trainer for the learnable name finder TokenNameFinderEvaluator Measures the performance of the NameFinder model with the reference data TokenNameFinderCrossValidator K-fold cross validator for the learnable Name Finder TokenNameFinderConverter converts foreign data formats (bionlp2004,conll03,conll02,ad) to native OpenNLP format CensusDictionaryCreator Converts 1990 US Census names into a dictionary POSTagger learnable part of speech tagger POSTaggerTrainer trains a model for the part-of-speech tagger POSTaggerEvaluator Measures the performance of the POS tagger model with the reference data POSTaggerCrossValidator K-fold cross validator for the learnable POS tagger POSTaggerConverter converts conllx data format to native OpenNLP format ChunkerME learnable chunker ChunkerTrainerME trainer for the learnable chunker ChunkerEvaluator Measures the performance of the Chunker model with the reference data ChunkerCrossValidator K-fold cross validator for the chunker ChunkerConverter converts ad data format to native OpenNLP format Parser performs full syntactic parsing ParserTrainer trains the learnable parser ParserEvaluator Measures the performance of the Parser model with the reference data BuildModelUpdater trains and updates the build model in a parser model CheckModelUpdater trains and updates the check model in a parser model TaggerModelReplacer replaces the tagger model in a parser model All tools print help when invoked with help parameter Example: opennlp SimpleTokenizer help]]> OpenNLP tools have similar command line structure and options. To discover tool options, run it with no parameters: The tool will output two blocks of help. The first block describes the general structure of this tool command line: The general structure of this tool command line includes the obligatory tool name (TokenizerTrainer), the optional format parameters ([.namefinder|.conllx|.pos]), the optional parameters ([-abbDict path] ...), and the obligatory parameters (-model modelFile ...). The format parameters enable direct processing of non-native data without conversion. Each format might have its own parameters, which are displayed if the tool is executed without or with help parameter: To switch the tool to a specific format, add a dot and the format name after the tool name: The second block of the help message describes the individual arguments: Most tools for processing need to be provided at least a model: When tool is executed this way, the model is loaded and the tool is waiting for the input from standard input. This input is processed and printed to standard output. Alternative, or one should say, most commonly used way is to use console input and output redirection options to provide also an input and an output files: output.txt]]> Most tools for model training need to be provided first a model name, optionally some training options (such as model type, number of iterations), and then the data. A model name is just a file name. Training options often include number of iterations, cutoff, abbreviations dictionary or something else. Sometimes it is possible to provide these options via training options file. In this case these options are ignored and the ones from the file are used. For the data one has to specify the location of the data (filename) and often language and encoding. A generic example of a command line to launch a tool trainer might be: or with a format: Most tools for model evaluation are similar to those for task execution, and need to be provided fist a model name, optionally some evaluation options (such as whether to print misclassified samples), and then the test data. A generic example of a command line to launch an evaluation tool might be:
OpenNLP Models
OpenNLP Models OpenNLP supports training NLP models that can be used by OpenNLP. In this documentation we will refer to these models as "OpenNLP models." All NLP components of OpenNLP support this type of model. The sections below in this documentation describe how to train and use these models. Pre-trained models are available for some languages and some OpenNLP components.
ONNX Models OpenNLP supports ONNX models via the ONNX Runtime for the Name Finder and Document Categorizer. This allows models trained by other frameworks such as PyTorch and Tensorflow to be used by OpenNLP. The documentation for each of the OpenNLP components that supports ONNX models describes how to use ONNX models for inference. OpenNLP does not support training models that can be used by the ONNX Runtime - ONNX models must be created outside OpenNLP using other tools.
System Properties
String Interning OpenNLP provides different implementations for String interning to reduce memory footprint. By default, OpenNLP uses a custom String interner implementation. Users may override by setting the following system property: In addition, users can provide custom String interner implementations by implementing the interface 'StringInterner' and specify this class via 'opennlp.interner.class'.
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/langdetect.xml0100644 0000000 0000000 00000023723 15217274217 025134 0ustar00rootroot0000000 0000000 Language Detector
Classifying The OpenNLP Language Detector classifies a document in ISO-639-3 languages according to the model capabilities. A model can be trained with Maxent, Perceptron or Naive Bayes algorithms. By default, normalizes a text and the context generator extracts n-grams of size 1, 2 and 3. The n-gram sizes, the normalization and the context generator can be customized by extending the LanguageDetectorFactory. The default normalizers are: Normalizers Normalizer Description EmojiCharSequenceNormalizer Replaces emojis by blank space UrlCharSequenceNormalizer Replaces URLs and E-Mails by a blank space. TwitterCharSequenceNormalizer Replaces hashtags and Twitter usernames by blank spaces. NumberCharSequenceNormalizer Replaces number sequences by blank spaces ShrinkCharSequenceNormalizer Shrink characters that repeats three or more times to only two repetitions.
Language Detector Tool The easiest way to try out the language detector is the command line tool. The tool is only intended for demonstration and testing. The following command shows how to use the language detector tool. The input is read from standard input and output is written to standard output, unless they are redirected or piped.
Language Detector API To perform classification you will need a machine learning model - these are encapsulated in the LanguageDetectorModel class of OpenNLP tools. First you need to grab the bytes from the serialized model on an InputStream - we'll leave it you to do that, since you were the one who serialized it to begin with. Now for the easy part: With the LanguageDetectorModel in hand we are just about there: Note that the both the API or the CLI will consider the complete text to choose the most probable languages. To handle mixed language one can analyze smaller chunks of text to find language regions.
Training The Language Detector can be trained on annotated training material. The data can be in OpenNLP Language Detector training format. This is one document per line, containing the ISO-639-3 language code and text separated by a tab. Other formats can also be available. The following sample shows the sample from above in the required format. The line breaks marked with a backslash are just inserted for formatting purposes and must not be included in the training data.
Training Tool The following command will train the language detector and write the model to langdetect-custom.bin: To customize the language detector, extend the class opennlp.tools.langdetect.LanguageDetectorFactory add it to the classpath and pass it in the -factory argument.
Training with Leipzig The Leipzig Corpora collection presents corpora in different languages. The corpora are a collection of individual sentences collected from the web and newspapers. The Corpora are available as plain text and as MySQL database tables. The OpenNLP integration can only use the plain text version. The individual plain text packages can be downloaded here: This corpora is specially good to train Language Detector and a converter is provided. First, you need to download the files that compose the Leipzig Corpora collection to a folder. Apache OpenNLP Language Detector supports training, evaluation and cross validation using the Leipzig Corpora. For example, the following command shows how to train a model. The following sequence of commands shows how to convert the Leipzig Corpora collection at folder leipzig-train/ to the default Language Detector format, by creating groups of 5 sentences as documents and limiting to 10000 documents per language. Then, it shuffles the result and select the first 100000 lines as train corpus and the last 20000 as evaluation corpus: leipzig.txt $ perl -MList::Util=shuffle -e 'print shuffle();' < leipzig.txt > leipzig_shuf.txt $ head -100000 < leipzig_shuf.txt > leipzig.train $ tail -20000 < leipzig_shuf.txt > leipzig.eval]]>
Training API The following example shows how to train a model from API. lineStream = new PlainTextByLineStream(inputStreamFactory, StandardCharsets.UTF_8); ObjectStream sampleStream = new LanguageDetectorSampleStream(lineStream); TrainingParameters params = ModelUtil.createDefaultTrainingParameters(); params.put(TrainingParameters.ALGORITHM_PARAM, PerceptronTrainer.PERCEPTRON_VALUE); params.put(TrainingParameters.CUTOFF_PARAM, 0); LanguageDetectorFactory factory = new LanguageDetectorFactory(); LanguageDetectorModel model = LanguageDetectorME.train(sampleStream, params, factory); model.serialize(new File("langdetect-custom.bin"));]]>
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/lemmatizer.xml0100644 0000000 0000000 00000030130 15217274217 025161 0ustar00rootroot0000000 0000000 Lemmatizer
Lemmatizer Tool A lemmatizer returns, for a given word form (token) and Part of Speech tag, the dictionary form of a word, which is usually referred to as its lemma. A token could ambiguously be derived from several basic forms or dictionary words which is why the postag of the word is required to find the lemma. For example, the form `show' may refer to either the verb "to show" or to the noun "show". Currently, OpenNLP implement statistical and dictionary-based lemmatizers. The easiest way to try out the Lemmatizer is the command line tool, which provides access to the statistical lemmatizer. Note that the tool is only intended for demonstration and testing. Once you have trained a lemmatizer model (see below for instructions), you can start the Lemmatizer Tool with this command: The Lemmatizer now reads a pos tagged sentence(s) per line from standard input. For example, you can copy this sentence to the console: The Lemmatizer will now echo the lemmas for each word postag pair to the console:
Lemmatizer API The Lemmatizer can be embedded into an application via its API. Currently, a statistical and DictionaryLemmatizer are available. Note that these two methods are complementary and the DictionaryLemmatizer can also be used as a way of post-processing the output of the statistical lemmatizer. The statistical lemmatizer requires that a trained model is loaded into memory from disk or from another source. In the example below it is loaded from disk: Once the model is loaded, a LemmatizerME can be instantiated. The Lemmatizer instance is now ready to lemmatize data. It expects a tokenized sentence as input, which is represented as a String array, each String object in the array is one token, and the POS tags associated with each token. The following code shows how to determine the most likely lemma for a sentence. The lemmas array contains one lemma for each token in the input array. The corresponding tag and lemma can be found at the same index as the token has in the input array. The DictionaryLemmatizer is constructed by passing the InputStream of a lemmatizer dictionary. Such dictionary consists of a text file containing, for each row, a word, its postag and the corresponding lemma, each column separated by a tab character. Alternatively, if a (word,postag) pair can output multiple lemmas, the the lemmatizer dictionary would consist of a text file containing, for each row, a word, its postag and the corresponding lemmas separated by "#": First the dictionary must be loaded into memory from disk or another source. In the sample below it is loaded from disk. After the dictionary is loaded the DictionaryLemmatizer can be instantiated. The DictionaryLemmatizer instance is now ready. It expects two String arrays as input, containing the tokens and their respective postags. The following code shows how to find a lemma using a DictionaryLemmatizer. The tags array contains one part-of-speech tag for each token in the input array. The corresponding tag and lemmas can be found at the same index as the token has in the input array.
Lemmatizer Training The training data consist of three columns separated by tabs. Each word has been put on a separate line and there is an empty line after each sentence. The first column contains the current word, the second its part-of-speech tag and the third its lemma. Here is an example of the file format, with a sample sentence of the training data: The Universal Dependencies Treebank and the CoNLL 2009 datasets distribute training data for many languages.
Training Tool OpenNLP has a command line tool which is used to train the models on various corpora. Usage of the tool: Its now assumed that the english lemmatizer model should be trained from a file called 'en-custom-lemmatizer.train' which is encoded as UTF-8. The following command will train the lemmatizer and write the model to en-custom-lemmatizer.bin:
Training API The Lemmatizer offers an API to train a new lemmatizer model. First a training parameters file needs to be instantiated: Then we read the training data: lineStream = null; LemmaSampleStream lemmaStream = null; try { lineStream = new PlainTextByLineStream((inputStreamFactory), StandardCharsets.UTF_8); lemmaStream = new LemmaSampleStream(lineStream); } catch (IOException e) { CmdLineUtil.handleCreateObjectStreamError(e); }]]> The following step proceeds to train the model:
Lemmatizer Evaluation The built in evaluation can measure the accuracy of the statistical lemmatizer. The accuracy can be measured on a test data set. There is a command line tool to evaluate a given model on a test data set. The following command shows how the tool can be run: This will display the resulting accuracy score, e.g.:
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/machine-learning.xml0100644 0000000 0000000 00000012445 15217274217 026222 0ustar00rootroot0000000 0000000 Machine Learning
Maximum Entropy To explain what maximum entropy is, it will be simplest to quote from Manning and Schütze* (p. 589): Maximum entropy modeling is a framework for integrating information from many heterogeneous information sources for classification. The data for a classification problem is described as a (potentially large) number of features. These features can be quite complex and allow the experimenter to make use of prior knowledge about what types of information are expected to be important for classification. Each feature corresponds to a constraint on the model. We then compute the maximum entropy model, the model with the maximum entropy of all the models that satisfy the constraints. This term may seem perverse, since we have spent most of the book trying to minimize the (cross) entropy of models, but the idea is that we do not want to go beyond the data. If we chose a model with less entropy, we would add `information' constraints to the model that are not justified by the empirical evidence available to us. Choosing the maximum entropy model is motivated by the desire to preserve as much uncertainty as possible. So that gives a rough idea of what the maximum entropy framework is. Don't assume anything about your probability distribution other than what you have observed. On the engineering level, using maxent is an excellent way of creating programs which perform very difficult classification tasks very well. For example, precision and recall figures for programs using maxent models have reached (or are) the state of the art on tasks like part of speech tagging, sentence detection, prepositional phrase attachment, and named entity recognition. On the engineering level, an added benefit is that the person creating a maxent model only needs to inform the training procedure of the event space, and need not worry about independence between features. While the authors of this implementation of maximum entropy are generally interested using maxent models in natural language processing, the framework is certainly quite general and useful for a much wider variety of fields. In fact, maximum entropy modeling was originally developed for statistical physics. For a very in-depth discussion of how maxent can be used in natural language processing, try reading Adwait Ratnaparkhi's dissertation. Also, check out Berger, Della Pietra, and Della Pietra's paper A Maximum Entropy Approach to Natural Language Processing, which provides an excellent introduction and discussion of the framework. *Foundations of statistical natural language processing. Christopher D. Manning, Hinrich Schütze. Cambridge, Mass.: MIT Press, c1999.
Implementation We have tried to make the opennlp.maxent implementation easy to use. To create a model, one needs (of course) the training data, and then implementations of two interfaces in the opennlp.maxent package, EventStream and ContextGenerator. These have fairly simple specifications, and example implementations can be found in the OpenNLP Tools preprocessing components. We have also set in place some interfaces and code to make it easier to automate the training and evaluation process (the Evaluable interface and the TrainEval class). It is not necessary to use this functionality, but if you do you'll find it much easier to see how well your models are doing. The opennlp.grok.preprocess.namefind package is an example of a maximum entropy component which uses this functionality. We have managed to use several techniques to reduce the size of the models when writing them to disk, which also means that reading in a model for use is much quicker than with less compact encodings of the model. This was especially important to us since we use many maxent models in the Grok library, and we wanted the start up time and the physical size of the library to be as minimal as possible. As of version 1.2.0, maxent has an io package which greatly simplifies the process of loading and saving models in different formats.
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/model-loading.xml0100644 0000000 0000000 00000016077 15217274217 025541 0ustar00rootroot0000000 0000000 Classpath Loading of OpenNLP Models
Background Since version 2.4.0, OpenNLP supports the ability to load pre-trained OpenNLP models from the classpath. It relies on either a simple implementation using the application's classpath or on the classgraph library to locate OpenNLP model JAR files. Our pre-trained models are bundled from the OpenNLP Models repository. This chapter describes how to load and use a pre-trained OpenNLP model available in the classpath. how to bundle a custom OpenNLP model to be loadable as a JAR file from the classpath.
Loading a pre-trained model First, you need to add the following dependency to your classpath: org.apache.opennlp opennlp-tools-models CURRENT_OPENNLP_VERSION ]]> by using our pre-trained models or by building custom models as described later in this section. If you need advanced classpath scanning capabilities, you can also add the classgraph library to your classpath. io.github.classgraph classgraph CURRENT_CLASSGRAPH_VERSION ]]> Make sure you replace the placeholders with the appropriate version values. Next, you can search for such a model and load it from the classpath: models = finder.findModels(false); for(ClassPathModelEntry entry : models) { final ClassPathModel model = loader.load(entry); if(model != null) { System.out.println(model.getModelName()); System.out.println(model.getModelSHA256()); System.out.println(model.getModelVersion()); System.out.println(model.getModelLanguage()); // do something with the model by consuming the byte array } }]]> Moreover, certain OpenNLP models can be obtained via a ClassPathModelProvider, such as OpenNLP's built-in DefaultClassPathModelProvider class. It allows direct use of models available under a certain locale, given that those are present in the classpath and can be loaded. In this example, the finder and loader objects can be created or re-used as shown in the previous code example. When running on Java 17+, the JVM argument may be required. Without this parameter, OpenNLP uses the JVM bootstrap classpath to locate models rather than the UCP class loader. For more advanced or non-standard class loading scenarios, using ClassGraph and implementing a custom provider may cover additional cases beyond the default UCP class loader or JVM bootstrap class path behavior.
Bundling a self-trained model If you intend to provide your own custom trained OpenNLP models as JAR files for classpath discovery, we recommend that you have a look at our setup in the OpenNLP Models repository. We recommend to bundle one model per JAR file. Make sure you add a model.properties file with the following content: Make sure to replace the values accordingly and configure your build tool to include the binary model and the model.properties in the resulting JAR file. To load such a custom model, you may need to adjust the pattern for classpath scanning. For example, if you name the model "custom-opennlp-model", you need the following code to successfully find and load it: models = finder.findModels(false); for(ClassPathModelEntry entry : models) { final ClassPathModel model = loader.load(entry); if(model != null) { System.out.println(model.getModelName()); System.out.println(model.getModelSHA256()); System.out.println(model.getModelVersion()); System.out.println(model.getModelLanguage()); // do something with the model by consuming the byte array } }]]>
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/morfologik-addon.xml0100644 0000000 0000000 00000014122 15217274217 026246 0ustar00rootroot0000000 0000000 Morfologik Addon Morfologik provides tools for finite state automata (FSA) construction and dictionary-based morphological dictionaries. The Morfologik Addon implements OpenNLP interfaces and extensions to allow the use of FSA Morfologik dictionary tools.
Morfologik Integration To allow for an easy integration with OpenNLP, the following implementations are provided: The MorfologikPOSTaggerFactory extends POSTaggerFactory, which helps create a POSTagger model with an embedded FSA TagDictionary. The MorfologikTagDictionary implements an FSA based TagDictionary, allowing for much smaller files than the default XML based with improved memory consumption. The MorfologikLemmatizer implements an FSA based Lemmatizer dictionaries. The first two implementations can be used directly from command line, as in the example bellow. Having an FSA Morfologik dictionary (see next section how to build one), you can train a POS Tagger model with an embedded FSA dictionary. The example trains a POSTagger with a CONLL corpus named portuguese_bosque_train.conll and an FSA dictionary named pt-morfologik.dict. It will output a model named pos-pt_fsadic.model. Another example follows. It shows how to use the MorfologikLemmatizer. You will need a lemma dictionary and info file, in this example, we will use a very small Portuguese dictionary. Its syntax is lemma,lexeme,postag. File lemmaDictionary.txt: Mandatory metadata file, which must have the same name but .info extension lemmaDictionary.info: The following code creates a binary FSA Morfologik dictionary, loads it in MorfologikLemmatizer and uses it to find the lemma the word "casa" noun and verb.
Morfologik CLI Tools The Morfologik addon provides a command line tool. XMLDictionaryToTable makes easy to convert from an OpenNLP XML based dictionary to a tabular format. MorfologikDictionaryBuilder can take a tabular dictionary and output a binary Morfologik FSA dictionary.
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/namefinder.xml0100644 0000000 0000000 00000063004 15217274217 025126 0ustar00rootroot0000000 0000000 Name Finder
Named Entity Recognition The Name Finder can detect named entities and numbers in text. To be able to detect entities the Name Finder needs a model. The model is dependent on the language and entity type it was trained for. The OpenNLP projects offers a number of pre-trained name finder models which are trained on various freely available corpora. They can be downloaded at our model download page. To find names in raw text the text must be segmented into tokens and sentences. A detailed description is given in the sentence detector and tokenizer tutorial. It is important that the tokenization for the training data and the input text is identical.
Name Finder Tool The easiest way to try out the Name Finder is the command line tool. The tool is only intended for demonstration and testing. Download the English person model and start the Name Finder Tool with this command: The name finder now reads a tokenized sentence per line from stdin, an empty line indicates a document boundary and resets the adaptive feature generators. Just copy this text to the terminal: the name finder will now output the text with markup for person names: Pierre Vinken , 61 years old , will join the board as a nonexecutive director Nov. 29 . Mr . Vinken is chairman of Elsevier N.V. , the Dutch publishing group . Rudolph Agnew , 55 years old and former chairman of Consolidated Gold Fields PLC , was named a director of this British industrial conglomerate .]]>
Name Finder API To use the Name Finder in a production system it is strongly recommended to embed it directly into the application instead of using the command line interface. First the name finder model must be loaded into memory from disk or another source. In the sample below it is loaded from disk. There is a number of reasons why the model loading can fail: Issues with the underlying I/O The version of the model is not compatible with the OpenNLP version The model is loaded into the wrong component, for example a tokenizer model is loaded with TokenNameFinderModel class. The model content is not valid for some other reason After the model is loaded the NameFinderME can be instantiated. The initialization is now finished and the Name Finder can be used. The NameFinderME class is not thread safe, it must only be called from one thread. To use multiple threads multiple NameFinderME instances sharing the same model instance can be created. The input text should be segmented into documents, sentences and tokens. To perform entity detection an application calls the find method for every sentence in the document. After every document clearAdaptiveData must be called to clear the adaptive data in the feature generators. Not calling clearAdaptiveData can lead to a sharp drop in the detection rate after a few documents. The following code illustrates that: the following snippet shows a call to find The nameSpans arrays contains now exactly one Span which marks the name Pierre Vinken. The elements between the start and end offsets are the name tokens. In this case the start offset is 0 and the end offset is 2. The Span object also knows the type of the entity. In this case it is person (defined by the model). It can be retrieved with a call to Span.getType(). Additionally to the statistical Name Finder, OpenNLP also offers a dictionary and a regular expression name finder implementation.
Using an ONNX Model Using an ONNX model is similar, except we will utilize the NameFinderDL class instead. You must provide the path to the model file and the vocabulary file to the name finder. (There is no need to load the model as an InputStream as in the previous example.) The name finder requires a tokenized list of strings as input. The output will be an array of spans. categories = new HashMap<>(); String[] tokens = new String[]{"George", "Washington", "was", "president", "of", "the", "United", "States", "."}; NameFinderDL nameFinderDL = new NameFinderDL(model, vocab, false, getIds2Labels()); Span[] spans = nameFinderDL.find(tokens);]]> For additional examples, refer to the NameFinderDLEval class.
Name Finder Training The pre-trained models might not be available for a desired language, can not detect important entities or the performance is not good enough outside the news domain. These are the typical reason to do custom training of the name finder on a new corpus or on a corpus which is extended by private training data taken from the data which should be analyzed.
Training Tool OpenNLP has a command line tool which is used to train the models available from the model download page on various corpora. ONNX model support is not available through the command line tool. The models that can be trained using the tool are OpenNLP models. ONNX models are trained through deep learning frameworks and then utilized by OpenNLP. The data can be converted to the OpenNLP name finder training format. Which is one sentence per line. Some other formats are available as well. The sentence must be tokenized and contain spans which mark the entities. Documents are separated by empty lines which trigger the reset of the adaptive feature generators. A training file can contain multiple types. If the training file contains multiple types the created model will also be able to detect these multiple types. Sample sentence of the data: Pierre Vinken , 61 years old , will join the board as a nonexecutive director Nov. 29 . Mr . Vinken is chairman of Elsevier N.V. , the Dutch publishing group .]]> The training data should contain at least 15000 sentences to create a model which performs well. Usage of the tool: It is now assumed that the english person name finder model should be trained from a file called 'en-ner-person.train' which is encoded as UTF-8. The following command will train the name finder and write the model to en-ner-person.bin: The example above will train models with a pre-defined feature set. It is also possible to use the -resources parameter to generate features based on external knowledge such as those based on word representation (clustering) features. The external resources must all be placed in a resource directory which is then passed as a parameter. If this option is used it is then required to pass, via the -featuregen parameter, an XML custom feature generator which includes some clustering features shipped with the TokenNameFinder. Currently, three formats of clustering lexicons are accepted: Space separated two column file specifying the token and the cluster class as generated by toolkits such as word2vec. Space separated three column file specifying the token, clustering class and weight as such as Clark's clusters. Tab separated three column Brown clusters as generated by Liang's toolkit. Additionally it is possible to specify the number of iterations, the cutoff and to overwrite all types in the training data with a single type. Finally, the -sequenceCodec parameter allows to specify a BIO (Begin, Inside, Out) or BILOU (Begin, Inside, Last, Out, Unit) encoding to represent the Named Entities. An example of one such command would be as follows:
Training API To train the name finder from within an application it is recommended to use the training API instead of the command line tool. Basically three steps are necessary to train it: The application must open a sample data stream Call the NameFinderME.train method Save the TokenNameFinderModel to a file The three steps are illustrated by the following sample code: lineStream = new PlainTextByLineStream(new MarkableFileInputStreamFactory(trainingFile), StandardCharsets.UTF_8); TokenNameFinderModel trainedModel; try (ObjectStream sampleStream = new NameSampleDataStream(lineStream)) { trainedModel = NameFinderME.train("eng", "person", sampleStream, TrainingParameters.defaultParams(), factory); } File modelFile = new File("en-ner-person.bin"); try (OutputStream modelOut = new BufferedOutputStream(new FileOutputStream(modelFile))) { trainedModel.serialize(modelOut); }]]>
Custom Feature Generation OpenNLP defines a default feature generation which is used when no custom feature generation is specified. Users which want to experiment with the feature generation can provide a custom feature generator. Either via an API or via a xml descriptor file.
Feature Generation defined by API The custom generator must be used for training and for detecting the names. If the feature generation during training time and detection time is different the name finder might not be able to detect names. The following lines show how to construct a custom feature generator which is similar to the default feature generator but with a BrownTokenFeature added. The javadoc of the feature generator classes explain what the individual feature generators do. To write a custom feature generator please implement the AdaptiveFeatureGenerator interface or if it must not be adaptive extend the FeatureGeneratorAdapter. The train method which should be used is defined as samples, TrainingParameters trainParams, TokenNameFinderFactory factory) throws IOException]]> where the TokenNameFinderFactory allows to specify a custom feature generator. To detect names the model which was returned from the train method must be passed to the NameFinderME constructor.
Feature Generation defined by XML Descriptor OpenNLP can also use a xml descriptor file to configure the feature generation. The descriptor file is stored inside the model after training and the feature generators are configured correctly when the name finder is instantiated. The following sample shows a xml descriptor which contains the default feature generator plus several types of clustering features: 2 2 2 2 true false 2 2 brownCluster brownCluster brownCluster word2vec.cluster clark.cluster ]]> The root element must be featureGenerators, each sub-element adds a feature generator to the configuration. The sample xml contains additional feature generators with respect to the API defined above. The following table shows the supported feature generators (you must specify the Factory's FQDN): Feature Generators Feature Generator Parameters CharacterNgramFeatureGeneratorFactory min and max specify the length of the generated character ngrams DefinitionFeatureGeneratorFactory none DictionaryFeatureGeneratorFactory dict is the key of the dictionary resource to use, and prefix is a feature prefix string PreviousMapFeatureGeneratorFactory none SentenceFeatureGeneratorFactory begin and end to generate begin or end features, both are optional and are boolean values TokenClassFeatureGeneratorFactory none TokenFeatureGeneratorFactory none BigramNameFeatureGeneratorFactory none TokenPatternFeatureGeneratorFactory none POSTaggerNameFeatureGeneratorFactory model is the file name of the POS Tagger model to use WordClusterFeatureGeneratorFactory dict is the key of the clustering resource to use BrownClusterTokenFeatureGeneratorFactory dict is the key of the clustering resource to use BrownClusterTokenClassFeatureGeneratorFactory dict is the key of the clustering resource to use BrownClusterBigramFeatureGeneratorFactory dict is the key of the clustering resource to use WindowFeatureGeneratorFactory prevLength and nextLength must be integers and specify the window size
Window feature generator can contain other generators.
Evaluation The built in evaluation can measure the named entity recognition performance of the name finder. The performance is either measured on a test dataset or via cross validation.
Evaluation Tool The following command shows how the tool can be run: The command line interface does not support cross evaluation in the current version.
Evaluation API The evaluation can be performed on a pre-trained model and a test dataset or via cross validation. In the first case the model must be loaded and a NameSample ObjectStream must be created (see code samples above), assuming these two objects exist the following code shows how to perform the evaluation: In the cross validation case all the training arguments must be provided (see the Training API section above). To perform cross validation the ObjectStream must be resettable. sampleStream = new NameSampleDataStream( new PlainTextByLineStream(dataIn, StandardCharsets.UTF_8)); TokenNameFinderCrossValidator evaluator = new TokenNameFinderCrossValidator("eng", null, TrainingParameters.defaultParams(), null, (TokenNameFinderEvaluationMonitor) null); evaluator.evaluate(sampleStream, 10); FMeasure result = evaluator.getFMeasure(); System.out.println(result.toString());]]>
Named Entity Annotation Guidelines Annotation guidelines define what should be labeled as an entity. To build a private corpus it is important to know these guidelines and maybe write a custom one. Here is a list of publicly available annotation guidelines: MUC6 MUC7 ACE CONLL 2002 CONLL 2003
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/opennlp.xml0100644 0000000 0000000 00000011014 15217274217 024463 0ustar00rootroot0000000 0000000 Version OpenNLP Written and maintained by the Apache OpenNLP Development Community License and Disclaimer The ASF licenses this documentation to you under the Apache License, Version 2.0 (the "License"); you may not use this documentation except in compliance with the License. You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, this documentation and its contents are distributed under the License on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Development Manual for Apache OpenNLP The Apache Software Foundation 2011 2026 The Apache Software Foundation
Apache OpenNLP Developer Documentation
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/parser.xml0100644 0000000 0000000 00000037076 15217274217 024324 0ustar00rootroot0000000 0000000 Parser
Parsing A parser returns a parse tree from a sentence according to a phrase structure grammar. A parse tree specifies the internal structure of a sentence. For example, the following image represents a parse tree for the sentence 'The cellphone was broken in two days': A parse tree can be used to determine the role of subtrees or constituents in the sentence. For example, it is possible to know that 'The cellphone' is the subject of the sentence and the verb (action) is 'was broken.'
Parser Tool The easiest way to try out the Parser is the command line tool. The tool is only intended for demonstration and testing. Download the English chunking parser model from the website and start the Parse Tool with the following command. Loading the big parser model can take several seconds, be patient. Copy this sample sentence to the console. The parser should now print the following to the console. With the following command the input can be read from a file and be written to an output file. article-parsed.txt.]]> The article-tokenized.txt file must contain one sentence per line which is tokenized with the English tokenizer model from our website. See the Tokenizer documentation for further details.
Parsing API The Parser can be easily integrated into an application via its API. To instantiate a Parser the parser model must be loaded first. Unlike the other components to instantiate the Parser a factory method should be used instead of creating the Parser via the new operator. The parser model is either trained for the chunking parser or the tree insert parser the parser implementation must be chosen correctly. The factory method will read a type parameter from the model and create an instance of the corresponding parser implementation. Right now the tree insert parser is still experimental and there is no pre-trained model for it. The parser expect a whitespace tokenized sentence. A utility method from the command line tool can parse the sentence String. The following code shows how the parser can be called. The topParses array only contains one parse because the number of parses is set to 1. The Parse object contains the parse tree. To display the parse tree call the show method. It either prints the parse to the console or into a provided StringBuffer. Similar to Exception.printStackTrace. TODO: Extend this section with more information about the Parse object.
Parser Training The OpenNLP offers two different parser implementations, the chunking parser and the treeinsert parser. The later one is still experimental and not recommended for production use. (TODO: Add a section which explains the two different approaches) The training can either be done with the command line tool or the training API. In the first case the training data must be available in the OpenNLP format. Which is the Penn Treebank format, but with the limitation of a sentence per line. Penn Treebank annotation guidelines can be found on the Penn Treebank home page . A parser model also contains a pos tagger model, depending on the amount of available training data it is recommended to switch the tagger model against a tagger model which was trained on a larger corpus. The pre-trained parser model provided on the website is doing this to achieve a better performance. (TODO: On which data is the model on the website trained, and say on which data the tagger model is trained)
Training Tool OpenNLP has a command line tool which is used to train the models available from the model download page on various corpora. The data must be converted to the OpenNLP parser training format, which is shortly explained above. To train the parser a head rules file is also needed. (TODO: Add documentation about the head rules file) Usage of the tool: The model on the website was trained with the following command: Its also possible to specify the cutoff and the number of iterations, these parameters are used for all trained models. The -parserType parameter is an optional parameter, to use the tree insertion parser, specify TREEINSERT as type. The TaggerModelReplacer tool replaces the tagger model inside the parser model with a new one. The original parser model will be overwritten with the new parser model which contains the replaced tagger model. Additionally there are tools to just retrain the build or the check model.
Training API The Parser training API supports the training of a new parser model. Four steps are necessary to train it: A HeadRules class needs to be instantiated: currently EnglishHeadRules and AncoraSpanishHeadRules are available. The application must open a sample data stream. Call a Parser train method: This can be either the CHUNKING or the TREEINSERT parser. Save the ParseModel to a file The following code snippet shows how to instantiate the HeadRules: The following code illustrates the three other steps, namely, opening the data, training the model and saving the ParserModel into an output file. stringStream = new PlainTextByLineStream(inputStreamFactory, StandardCharsets.UTF_8); ObjectStream sampleStream = new ParseSample(stringStream); ParserType type = parseParserType(params.getParserType()); if (ParserType.CHUNKING.equals(type)) { model = opennlp.tools.parser.chunking.Parser.train( params.getLang(), sampleStream, rules, mlParams); } else if (ParserType.TREEINSERT.equals(type)) { model = opennlp.tools.parser.treeinsert.Parser.train(params.getLang(), sampleStream, rules, mlParams); } } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("parser", modelOutFile, model);]]>
Parser Evaluation The built in evaluation can measure the parser performance. The performance is measured on a test dataset.
Parser Evaluation Tool The following command shows how the tool can be run: A sample of the command considering you have a data sample named en-parser-chunking.eval, and you trained a model called en-parser-chunking.bin: and here is a sample output: The Parser Evaluation tool reimplements the PARSEVAL scoring method as implemented by the EVALB script, which is the most widely used evaluation tool for constituent parsing. Currently the Parser Evaluation tool does not allow to make exceptions in the constituents to be evaluated, in the way Collins or Bikel usually do. Any contributions are very welcome. If you want to contribute please contact us on the mailing list or comment on the jira issue OPENNLP-688.
Evaluation API The evaluation can be performed on a pre-trained model and a test dataset or via cross validation. In the first case the model must be loaded and a Parse ObjectStream must be created (see code samples above), assuming these two objects exist the following code shows how to perform the evaluation: In the cross validation case all the training arguments must be provided (see the Training API section above). To perform cross validation the ObjectStream must be resettable. stringStream = new PlainTextByLineStream(inputStreamFactory, StandardCharsets.UTF_8); ObjectStream sampleStream = new ParseSample(stringStream); ParserCrossValidator evaluator = new ParserCrossValidator("eng", trainParameters, headRules, \ parserType, listeners.toArray(new ParserEvaluationMonitor[listeners.size()]))); evaluator.evaluate(sampleStream, 10); FMeasure result = evaluator.getFMeasure(); System.out.println(result.toString());]]>
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/postagger.xml0100644 0000000 0000000 00000034406 15217274217 025015 0ustar00rootroot0000000 0000000 Part-of-Speech Tagger
Tagging The Part of Speech Tagger marks tokens with their corresponding word type based on the token itself and the context of the token. A token might have multiple pos tags depending on the token and the context. The OpenNLP POS Tagger uses a probability model to predict the correct pos tag out of the tag set. To limit the possible tags for a token a tag dictionary can be used which increases the tagging and runtime performance of the tagger.
POS Tagger Tool The easiest way to try out the POS Tagger is the command line tool. The tool is only intended for demonstration and testing. Download the English maxent pos model and start the POS Tagger Tool with this command: The POS Tagger now reads a tokenized sentence per line from stdin. Copy these two sentences to the console: The POS Tagger will now echo the sentences with pos tags to the console: The tag set used by the English pos model is the Penn Treebank tag set .
POS Tagger API The POS Tagger can be embedded into an application via its API. First the pos model must be loaded into memory from disk or another source. In the sample below it is loaded from disk. After the model is loaded the POSTaggerME can be instantiated. The POS Tagger instance is now ready to tag data. It expects a tokenized sentence as input, which is represented as a String array, each String object in the array is one token. The following code shows how to determine the most likely pos tag sequence for a sentence. The tags array contains one part-of-speech tag for each token in the input array. The corresponding tag can be found at the same index as the token has in the input array. The confidence scores for the returned tags can be easily retrieved from a POSTaggerME with the following method call: The call to probs is stateful and will always return the probabilities of the last tagged sentence. The probs method should only be called when the tag method was called before, otherwise the behavior is undefined. Some applications need to retrieve the n-best pos tag sequences and not only the best sequence. The topKSequences method is capable of returning the top sequences. It can be called in a similar way as tag. Each Sequence object contains one sequence. The sequence can be retrieved via Sequence.getOutcomes() which returns a tags array and Sequence.getProbs() returns the probability array for this sequence.
Training The POS Tagger can be trained on annotated training material. The training material is a collection of tokenized sentences where each token has the assigned part-of-speech tag. The native POS Tagger training material looks like this: Each sentence must be in one line. The token/tag pairs are combined with "_". The token/tag pairs are whitespace separated. The data format does not define a document boundary. If a document boundary should be included in the training material it is suggested to use an empty line. The Part-of-Speech Tagger can either be trained with a command line tool, or via a training API.
Training Tool OpenNLP has a command line tool which is used to train the models available from the model download page on various corpora. Usage of the tool: The following command illustrates how an English part-of-speech model can be trained:
Training API The Part-of-Speech Tagger training API supports the training of a new pos model. Basically three steps are necessary to train it: The application must open a sample data stream Call the 'POSTagger.train' method Save the POSModel to a file The following code illustrates that: lineStream = new PlainTextByLineStream( new MarkableFileInputStreamFactory(new File("en-custom-pos-maxent.bin")), StandardCharsets.UTF_8); ObjectStream sampleStream = new WordTagSampleStream(lineStream); model = POSTaggerME.train("eng", sampleStream, TrainingParameters.defaultParams(), new POSTaggerFactory()); } catch (IOException e) { e.printStackTrace(); }]]> The above code performs the first two steps, opening the data and training the model. The trained model must still be saved into an OutputStream, in the sample below it is written into a file.
Tag Dictionary The tag dictionary is a word dictionary which specifies which tags a specific token can have. Using a tag dictionary has two advantages, inappropriate tags can not been assigned to tokens in the dictionary and the beam search algorithm has to consider fewer possibilities and can search faster. The dictionary is defined in a xml format and can be created and stored with the POSDictionary class. Below is an example to train a custom model using a tag dictionary. Sample POS Training material (file : en-custom-pos.train) Sample Tag Dictionary (file : dictionary.xml) It is Spring season the flowers are red and yellow my favourite colour . ]]> Sample code to train a model using above tag dictionary lineStream = new PlainTextByLineStream( new MarkableFileInputStreamFactory(new File("en-custom-pos.train")), StandardCharsets.UTF_8); ObjectStream sampleStream = new WordTagSampleStream(lineStream); TrainingParameters params = ModelUtil.createDefaultTrainingParameters(); params.put(TrainingParameters.CUTOFF_PARAM, 0); POSTaggerFactory factory = new POSTaggerFactory(); TagDictionary dict = factory.createTagDictionary(new File("dictionary.xml")); factory.setTagDictionary(dict); model = POSTaggerME.train("eng", sampleStream, params, factory); OutputStream modelOut = new BufferedOutputStream(new FileOutputStream("en-custom-pos-maxent.bin")); model.serialize(modelOut); } catch (IOException e) { e.printStackTrace(); }]]> The custom model is then used to tag a sequence. System.out.print(k + " "));]]> Input Sentence: Spring is my favourite season. Output POS Tags using the custom model (en-custom-pos-maxent.bin): \ PROPN OTHER PRON ADJ NOUN PUNCT Output with the default model POS Tags using the default model (opennlp-en-ud-ewt-pos-1.3-2.5.4.bin): \ NOUN AUX PRON ADJ NOUN PUNCT
Evaluation The built-in evaluation can measure the accuracy of the pos tagger. The accuracy can be measured on a test data set or via cross validation.
Evaluation Tool There is a command line tool to evaluate a given model on a test data set. The following command shows how the tool can be run: This will display the resulting accuracy score, e.g.: There is a command line tool for cross-validation of the test data set. The following command shows how the tool can be run: This will display the resulting accuracy score, e.g.:
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/sentdetect.xml0100644 0000000 0000000 00000025144 15217274217 025163 0ustar00rootroot0000000 0000000 Sentence Detector
Sentence Detection The OpenNLP Sentence Detector can detect that a punctuation character marks the end of a sentence or not. In this sense a sentence is defined as the longest white space trimmed character sequence between two punctuation marks. The first and last sentence make an exception to this rule. The first non whitespace character is assumed to be the start of a sentence, and the last non whitespace character is assumed to be a sentence end. The sample text below should be segmented into its sentences. After detecting the sentence boundaries each sentence is written in its own line. Usually Sentence Detection is done before the text is tokenized and that's the way the pre-trained models on the website are trained, but it is also possible to perform tokenization first and let the Sentence Detector process the already tokenized text. The OpenNLP Sentence Detector cannot identify sentence boundaries based on the contents of the sentence. A prominent example is the first sentence in an article where the title is mistakenly identified to be the first part of the first sentence. Most components in OpenNLP expect input which is segmented into sentences.
Sentence Detection Tool The easiest way to try out the Sentence Detector is the command line tool. The tool is only intended for demonstration and testing. Download the english sentence detector model and start the Sentence Detector Tool with this command: Just copy the sample text from above to the console. The Sentence Detector will read it and echo one sentence per line to the console. Usually the input is read from a file and the output is redirected to another file. This can be achieved with the following command. output.txt]]> For the english sentence model from the website the input text should not be tokenized.
Sentence Detection API The Sentence Detector can be easily integrated into an application via its API. To instantiate the Sentence Detector the sentence model must be loaded first. After the model is loaded the SentenceDetectorME can be instantiated. The Sentence Detector can output an array of Strings, where each String is one sentence. The result array now contains two entries. The first String is "First sentence." and the second String is "Second sentence." The whitespace before, between and after the input String is removed. The API also offers a method which simply returns the span of the sentence in the input string. The result array again contains two entries. The first span beings at index 2 and ends at 17. The second span begins at 18 and ends at 34. The utility method Span.getCoveredText can be used to create a substring which only covers the chars in the span.
Sentence Detector Training
Training Tool OpenNLP has a command line tool which is used to train the models available from the model download page on various corpora. The data must be converted to the OpenNLP Sentence Detector training format. Which is one sentence per line. An empty line indicates a document boundary. In case the document boundary is unknown, it's recommended to have an empty line every few ten sentences. Exactly like the output in the sample above. Usage of the tool: To train an English sentence detector use the following command: It should produce the following output: ... 95: .. loglikelihood=-288.25556805874436 0.9834118369854598 96: .. loglikelihood=-287.2283680343481 0.9834118369854598 97: .. loglikelihood=-286.2174830344526 0.9834118369854598 98: .. loglikelihood=-285.222486981048 0.9834118369854598 99: .. loglikelihood=-284.24296917223916 0.9834118369854598 100: .. loglikelihood=-283.2785335773966 0.9834118369854598 Wrote sentence detector model. Path: en-custom-sent.bin ]]>
Training API The Sentence Detector also offers an API to train a new sentence detection model. Basically three steps are necessary to train it: The application must open a sample data stream Call the SentenceDetectorME.train method Save the SentenceModel to a file or directly use it The following sample code illustrates these steps: lineStream = new PlainTextByLineStream(new MarkableFileInputStreamFactory(new File("en-custom-sent.train")), StandardCharsets.UTF_8); SentenceModel model; try (ObjectStream sampleStream = new SentenceSampleStream(lineStream)) { model = SentenceDetectorME.train("eng", sampleStream, new SentenceDetectorFactory("eng", true, null, null), TrainingParameters.defaultParams()); } try (OutputStream modelOut = new BufferedOutputStream(new FileOutputStream(modelFile))) { model.serialize(modelOut); }]]>
Evaluation
Evaluation Tool The command shows how the evaluator tool can be run: The en-custom-sent.eval file has the same format as the training data.
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/tokenizer.xml0100644 0000000 0000000 00000043434 15217274217 025035 0ustar00rootroot0000000 0000000 Tokenizer
Tokenization The OpenNLP Tokenizers segment an input character sequence into tokens. Tokens are usually words, punctuation, numbers, etc. The following result shows the individual tokens in a whitespace separated representation. OpenNLP offers multiple tokenizer implementations: Whitespace Tokenizer - A whitespace tokenizer, non whitespace sequences are identified as tokens Simple Tokenizer - A character class tokenizer, sequences of the same character class are tokens Learnable Tokenizer - A maximum entropy tokenizer, detects token boundaries based on probability model Most part-of-speech taggers, parsers and so on, work with text tokenized in this manner. It is important to ensure that your tokenizer produces tokens of the type expected by your later text processing components. With OpenNLP (as with many systems), tokenization is a two-stage process: first, sentence boundaries are identified, then tokens within each sentence are identified.
Tokenizer Tools The easiest way to try out the tokenizers are the command line tools. The tools are only intended for demonstration and testing. There are two tools, one for the Simple Tokenizer and one for the learnable tokenizer. A command line tool the for the Whitespace Tokenizer does not exist, because the whitespace separated output would be identical to the input. The following command shows how to use the Simple Tokenizer Tool. To use the learnable tokenizer download the english token model from our website. To test the tokenizer copy the sample from above to the console. The whitespace separated tokens will be written back to the console. Usually the input is read from a file and written to a file. article-tokenized.txt]]> It can be done in the same way for the Simple Tokenizer. Since most text comes truly raw and doesn't have sentence boundaries and such, it's possible to create a pipe which first performs sentence boundary detection and tokenization. The following sample illustrates that. Of course this is all on the command line. Many people use the models directly in their Java code by creating SentenceDetector and Tokenizer objects and calling their methods as appropriate. The following section will explain how the Tokenizers can be used directly from java.
Tokenizer API The Tokenizers can be integrated into an application by the defined API. The shared instance of the WhitespaceTokenizer can be retrieved from a static field WhitespaceTokenizer.INSTANCE. The shared instance of the SimpleTokenizer can be retrieved in the same way from SimpleTokenizer.INSTANCE. To instantiate the TokenizerME (the learnable tokenizer) a Token Model must be created first. The following code sample shows how a model can be loaded. After the model is loaded the TokenizerME can be instantiated. The tokenizer offers two tokenize methods, both expect an input String object which contains the untokenized text. If possible it should be a sentence, but depending on the training of the learnable tokenizer this is not required. The first returns an array of Strings, where each String is one token. The output will be an array with these tokens. The second method, tokenizePos returns an array of Spans, each Span contain the start and end character offsets of the token in the input String. The tokenSpans array now contain 5 elements. To get the text for one span call Span.getCoveredText which takes a span and the input text. The TokenizerME is able to output the probabilities for the detected tokens. The getTokenProbabilities method must be called directly after one of the tokenize methods was called. The tokenProbs array now contains one double value per token, the value is between 0 and 1, where 1 is the highest possible probability and 0 the lowest possible probability.
Tokenizer Training
Training Tool OpenNLP has a command line tool which is used to train the models available from the model download page on various corpora. The data can be converted to the OpenNLP Tokenizer training format or used directly. The OpenNLP format contains one sentence per line. Tokens are either separated by a whitespace or by a special <SPLIT> tag. Tokens are split automatically on whitespace and at least one <SPLIT> tag must be present in the training text. The following sample shows the sample from above in the correct format. , 61 years old, will join the board as a nonexecutive director Nov. 29. Mr. Vinken is chairman of Elsevier N.V., the Dutch publishing group. Rudolph Agnew, 55 years old and former chairman of Consolidated Gold Fields PLC, was named a nonexecutive director of this British industrial conglomerate.]]> Usage of the tool: To train the english tokenizer use the following command: ... 95: ... loglikelihood=-2.0234942537226366 1.0 96: ... loglikelihood=-2.0107265117555935 1.0 97: ... loglikelihood=-1.998139365828305 1.0 98: ... loglikelihood=-1.9857283791639697 1.0 99: ... loglikelihood=-1.9734892753591327 1.0 100: ... loglikelihood=-1.9614179307958106 1.0 Writing tokenizer model ... done (0,044s) Wrote tokenizer model to Path: en-custom-token.bin]]>
Training API The Tokenizer offers an API to train a new tokenization model. Basically three steps are necessary to train it: The application must open a sample data stream Call the TokenizerME.train method Save the TokenizerModel to a file or directly use it The following sample code illustrates these steps: lineStream = new PlainTextByLineStream(new MarkableFileInputStreamFactory(new File("en-custom-sent.train")), StandardCharsets.UTF_8); ObjectStream sampleStream = new TokenSampleStream(lineStream); TokenizerModel model; try { model = TokenizerME.train(sampleStream, TokenizerFactory.create(null, "eng", null, true, null), TrainingParameters.defaultParams()); } finally { sampleStream.close(); } OutputStream modelOut = null; try { modelOut = new BufferedOutputStream(new FileOutputStream(modelFile)); model.serialize(modelOut); } finally { if (modelOut != null) modelOut.close(); }]]>
Detokenizing Detokenizing is simple the opposite of tokenization, the original non-tokenized string should be constructed out of a token sequence. The OpenNLP implementation was created to undo the tokenization of training data for the tokenizer. It can also be used to undo the tokenization of such a trained tokenizer. The implementation is strictly rule based and defines how tokens should be attached to a sentence wise character sequence. The rule dictionary assign to every token an operation which describes how it should be attached to one continuous character sequence. The following rules can be assigned to a token: MERGE_TO_LEFT - Merges the token to the left side. MERGE_TO_RIGHT - Merges the token to the right side. RIGHT_LEFT_MATCHING - Merges the token to the right side on first occurrence and to the left side on second occurrence. The following sample will illustrate how the detokenizer with a small rule dictionary (illustration format, not the xml data format): The dictionary should be used to de-tokenize the following whitespace tokenized sentence: The tokens would get these tags based on the dictionary: NO_OPERATION said -> NO_OPERATION " -> MERGE_TO_RIGHT This -> NO_OPERATION is -> NO_OPERATION a -> NO_OPERATION test -> NO_OPERATION " -> MERGE_TO_LEFT . -> MERGE_TO_LEFT]]> That will result in the following character sequence:
Detokenizing API The Detokenizer can be used to detokenize the tokens to String. To instantiate the Detokenizer (a rule based detokenizer) a DetokenizationDictionary (the rule of dictionary) must be created first. The following code sample shows how a rule dictionary can be loaded. After the rule dictionary is loaded the DictionaryDetokenizer can be instantiated. The detokenizer offers two detokenize methods, the first detokenize the input tokens into a String. Tokens which are connected without a space in-between can be separated by a split marker. "); Assert.assertEquals("A co-worker helped.", sentence);]]> The API also offers a method which simply returns operations array in the input tokens array. Output:
Detokenizer Dictionary Detokenization Dictionary is the rule dictionary about detokenizer. tokens - an array of tokens that should be detokenized according to an operation. operations - an array of operations which specifies which operation should be used for the provided tokens. The following code sample shows how a rule dictionary can be created.
apache-opennlp-2.5.12-src/opennlp-docs/src/docbkx/uima-integration.xml0100644 0000000 0000000 00000066330 15217274217 026277 0ustar00rootroot0000000 0000000 UIMA Integration The UIMA Integration module wraps the OpenNLP components as UIMA Analysis Engines. These annotators can be used in any UIMA pipeline to automatically annotate text with sentences, tokens, named entities, part-of-speech tags, chunks, and parse trees. The module is located in the opennlp-uima artifact.
Adding the Dependency To use the OpenNLP UIMA annotators, add the following dependency to your project: org.apache.opennlp opennlp-uima ${opennlp.version} ]]> This module depends on Apache UIMA and the OpenNLP runtime. The UIMA framework dependency is included transitively.
Type System The module ships with a default type system defined in TypeSystem.xml inside the descriptors directory. This type system defines the following annotation types: opennlp.uima.Sentence - Sentence boundary annotations opennlp.uima.Token - Token annotations with a pos feature for part-of-speech tags opennlp.uima.Chunk - Chunk annotations with a chunkType feature (e.g. NP, VP) opennlp.uima.Person | Organization | Location - Named entity types opennlp.uima.Date | Time | Money | Percentage - Additional named entity types opennlp.uima.Parse - Parse tree node annotations with parseType, children, and prob features The default type system can be replaced with a custom type system. To do so, update the type references in the analysis engine descriptors to point to your custom types and import your custom type system instead of TypeSystem.xml.
Descriptor Structure Each OpenNLP UIMA annotator is configured through a UIMA analysis engine descriptor XML file. It specifies: The annotator implementation class Configuration parameters (e.g. which type system types to use) An external resource dependency for the OpenNLP model file A reference to the type system Models are loaded through the UIMA external resource mechanism. Each ML-based annotator declares a dependency on a model resource with the key opennlp.uima.ModelName. The model file is bound to this key through the resource manager configuration. For example, to configure the sentence detector model: opennlp.uima.ModelName opennlp.uima.sentdetect.SentenceModelResource SentenceModel file:en-sent.bin opennlp.uima.sentdetect.SentenceModelResourceImpl opennlp.uima.ModelName SentenceModel ]]>
Sentence Detector The opennlp.uima.sentdetect.SentenceDetector annotator detects sentence boundaries and creates sentence annotations in the CAS. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The full name of the sentence annotation type. Default: opennlp.uima.Sentence opennlp.uima.ContainerType (optional) - If set, sentence detection is restricted to within annotations of this type. Useful for detecting sentences only inside specific regions of a document (e.g. paragraphs). opennlp.uima.ProbabilityFeature (optional) - Feature name for storing the detection confidence score on each sentence annotation. Model Resource Interface: opennlp.uima.sentdetect.SentenceModelResource Example Descriptor: See descriptors/SentenceDetector.xml in the opennlp-uima module.
Tokenizer Three tokenizer implementations are available as UIMA annotators. All tokenizers require sentence annotations to already be present in the CAS.
Learnable Tokenizer The opennlp.uima.tokenize.Tokenizer annotator uses a maximum entropy model to identify token boundaries. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. Default: opennlp.uima.Sentence opennlp.uima.TokenType (mandatory) - The token annotation type. Default: opennlp.uima.Token opennlp.uima.tokenizer.IsAlphaNumericOptimization (optional) - If set, enables an optimization that treats purely alphanumeric sequences as single tokens without consulting the model. opennlp.uima.ProbabilityFeature (optional) - Feature name for storing token probability scores. Model Resource Interface: opennlp.uima.tokenize.TokenizerModelResource
Simple Tokenizer The opennlp.uima.tokenize.SimpleTokenizer annotator is a rule-based tokenizer that splits text by character class boundaries. It requires no model. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. opennlp.uima.TokenType (mandatory) - The token annotation type.
Whitespace Tokenizer The opennlp.uima.tokenize.WhitespaceTokenizer annotator splits text at whitespace boundaries. It requires no model. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. opennlp.uima.TokenType (mandatory) - The token annotation type.
Name Finder Two named entity recognition annotators are provided: a machine learning-based annotator and a dictionary-based annotator. Both require sentence and token annotations to already be present in the CAS.
Learnable Name Finder The opennlp.uima.namefind.NameFinder annotator uses a maximum entropy model to detect named entities such as person names, organizations, and locations. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. opennlp.uima.TokenType (mandatory) - The token annotation type. opennlp.uima.NameType (mandatory) - The annotation type for detected entities (e.g. opennlp.uima.Person). opennlp.uima.ProbabilityFeature (optional) - Feature name for storing entity probability scores. opennlp.uima.BeamSize (optional) - Beam size for the beam search. opennlp.uima.DocumentConfidenceType (optional) - Annotation type for storing document-level confidence information. Model Resource Interface: opennlp.uima.namefind.TokenNameFinderModelResource To detect multiple entity types, configure one Name Finder annotator per entity type, each with its own model. The provided descriptors include pre-configured annotators for person, organization, location, date, time, money, and percentage entities.
Dictionary Name Finder The opennlp.uima.namefind.DictionaryNameFinder annotator performs dictionary-based named entity recognition. It matches token sequences against entries in an OpenNLP dictionary file. No machine learning model is required. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. opennlp.uima.TokenType (mandatory) - The token annotation type. opennlp.uima.NameType (mandatory) - The annotation type for detected entities. opennlp.uima.Dictionary (mandatory) - External resource key for the OpenNLP dictionary file to use for matching.
POS Tagger The opennlp.uima.postag.POSTagger annotator assigns part-of-speech tags to tokens. It requires sentence and token annotations to already be present in the CAS. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. Default: opennlp.uima.Sentence opennlp.uima.TokenType (mandatory) - The token annotation type. Default: opennlp.uima.Token opennlp.uima.POSFeature (mandatory) - The feature name on the token type where the POS tag will be stored. Default: pos opennlp.uima.ProbabilityFeature (optional) - Feature name for storing tagging probability scores. opennlp.uima.BeamSize (optional) - Beam size for the beam search. opennlp.uima.DictionaryName (optional) - External resource key for a tag dictionary that constrains possible tags for known words. Model Resource Interface: opennlp.uima.postag.POSModelResource
Chunker The opennlp.uima.chunker.Chunker annotator identifies non-recursive syntactic phrases (chunks) such as noun phrases (NP) and verb phrases (VP). It requires sentence and token annotations with POS tags to already be present in the CAS. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. Default: opennlp.uima.Sentence opennlp.uima.TokenType (mandatory) - The token annotation type. Default: opennlp.uima.Token opennlp.uima.POSFeature (mandatory) - The feature name for reading POS tags from tokens. Default: pos opennlp.uima.ChunkType (mandatory) - The annotation type for chunk annotations. Default: opennlp.uima.Chunk opennlp.uima.ChunkTagFeature (mandatory) - The feature name on the chunk type where the chunk tag (e.g. NP, VP) will be stored. Default: chunkType opennlp.uima.BeamSize (optional) - Beam size for the beam search. Model Resource Interface: opennlp.uima.chunker.ChunkerModelResource
Parser The opennlp.uima.parser.Parser annotator performs full syntactic parsing and creates a hierarchical parse tree structure in the CAS. It requires sentence and token annotations to already be present in the CAS. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. Default: opennlp.uima.Sentence opennlp.uima.TokenType (mandatory) - The token annotation type. Default: opennlp.uima.Token opennlp.uima.ParseType (mandatory) - The annotation type for parse tree nodes. Default: opennlp.uima.Parse opennlp.uima.TypeFeature (mandatory) - The feature name for storing the parse node type (e.g. S, NP, VP). Default: parseType opennlp.uima.ChildrenFeature (mandatory) - The feature name for storing references to child parse nodes. Default: children opennlp.uima.ProbabilityFeature (optional) - Feature name for storing parse probability scores. Default: prob opennlp.uima.BeamSize (optional) - Beam size for the beam search. Model Resource Interface: opennlp.uima.parser.ParserModelResource
Document Categorizer The opennlp.uima.doccat.DocumentCategorizer annotator classifies document text into categories using a trained document categorization model. Configuration Parameters: opennlp.uima.doccat.CategoryType (mandatory) - The annotation type for the category result. opennlp.uima.doccat.CategoryFeature (mandatory) - The feature name on the category type where the classification result is stored. Model Resource Interface: opennlp.uima.doccat.DoccatModelResource
Language Detector The opennlp.uima.doccat.LanguageDetector annotator identifies the language of the document text and sets the CAS document language accordingly. Configuration Parameters: opennlp.uima.SentenceType (mandatory) - The sentence annotation type. Default: opennlp.uima.Sentence Model Resource Interface: opennlp.uima.doccat.DoccatModelResource Example Descriptor: See descriptors/LanguageDetector.xml in the opennlp-uima module.
Normalizer The opennlp.uima.normalizer.Normalizer annotator extracts structured data from named entity annotations. It can convert the covered text of a named entity into typed values (e.g. parsing a money amount into a numeric value) and optionally look up normalized forms in a dictionary. Configuration Parameters: opennlp.uima.NameType (mandatory) - The named entity annotation type to normalize. opennlp.uima.normalizer.StructureFeature (mandatory) - The feature name where the normalized value is stored. opennlp.uima.Dictionary (optional) - External resource key for a dictionary used to look up normalized forms. The normalizer supports the following target feature types: String, Byte, Short, Integer, Long, Float, and Double. Number parsing is locale-aware and uses the CAS document language.
Building an Aggregate Pipeline The annotators are designed to be composed into an aggregate analysis engine where each annotator builds on the annotations produced by earlier ones. The standard processing order is: Sentence Detector (produces sentence annotations) Tokenizer (produces token annotations within sentences) Name Finders (produce entity annotations from tokens) POS Tagger (adds POS tags to tokens) Chunker (produces chunk annotations from POS-tagged tokens) Parser (produces parse tree from tokens within sentences) The module includes a pre-configured aggregate descriptor descriptors/OpenNlpTextAnalyzer.xml that chains sentence detection, tokenization, multiple name finders (person, organization, location, date, time, money, percentage), POS tagging, chunking, and parsing in the correct order. This aggregate descriptor demonstrates how to bind models for all annotators in one place using the resource manager configuration. Each annotator's model key follows the pattern AnnotatorKey/opennlp.uima.ModelName, for example: SentenceDetector/opennlp.uima.ModelName SentenceModel Tokenizer/opennlp.uima.ModelName TokenModel ]]> Below is a complete example showing how to create and run an aggregate pipeline programmatically using the UIMA framework APIs:
Using Custom Type Systems The default type system can be replaced with your own custom types. This is useful when integrating OpenNLP annotators into an existing UIMA pipeline that already defines its own type system. To use custom types: Create your own type system descriptor with the annotation types you need. Update the annotator descriptor to import your custom type system instead of TypeSystem.xml. Set the configuration parameters (e.g. opennlp.uima.SentenceType, opennlp.uima.TokenType) to reference your custom type names. For example, if your type system defines sentences as my.types.Sentence and tokens as my.types.Token, update the descriptor: opennlp.uima.SentenceType my.types.Sentence opennlp.uima.TokenType my.types.Token ]]>
Running the PEAR Sample in CVD The CAS Visual Debugger (CVD) is shipped as part of the UIMA distribution and is a tool which can run the OpenNLP UIMA Annotators and display their analysis results. The source distribution comes with a script which can create a sample UIMA application. This includes the sentence detector, tokenizer, POS tagger, chunker, and name finders for English. This sample application is packaged in the PEAR format and must be installed with the PEAR installer before it can be run by CVD. Please consult the UIMA documentation for further information about the PEAR installer. After the PEAR is installed, start the CAS Visual Debugger shipped with the UIMA framework and click on Tools -> Load AE. Then select the opennlp.uima.OpenNlpTextAnalyzer_pear.xml file in the file dialog. Now enter some text and start the analysis engine with "Run -> Run OpenNLPTextAnalyzer". Afterwards the results will be displayed. You should see sentences, tokens, chunks, POS tags, and possibly some named entities. Remember the input text must be written in English.
apache-opennlp-2.5.12-src/opennlp-docs/src/main/resources/xsl/epub3.xsl0100644 0000000 0000000 00000003425 15217274217 026335 0ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-docs/src/main/resources/xsl/html.xsl0100644 0000000 0000000 00000002374 15217274217 026265 0ustar00rootroot0000000 0000000 4 apache-opennlp-2.5.12-src/opennlp-docs/src/main/resources/xsl/pdf.xsl0100644 0000000 0000000 00000006655 15217274217 026100 0ustar00rootroot0000000 0000000 A4 100% 0.5cm 0cm 0.0cm 0.0cm 0.0cm 0cm 0.5pt solid black 0.5pt solid black 6pt 6pt 0cm Lucida Sans Typewriter 9pt wrap \ always #E0E0E0 0.5pt solid #575757 2pt apache-opennlp-2.5.12-src/opennlp-morfologik-addon/bin/morfologik-addon0100755 0000000 0000000 00000001622 15217274217 026465 0ustar00rootroot0000000 0000000 #!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. mvn -e -q exec:java "-Dexec.mainClass=opennlp.morfologik.cmdline.CLI" "-Dexec.args=$*" apache-opennlp-2.5.12-src/opennlp-morfologik-addon/bin/morfologik-addon.bat0100644 0000000 0000000 00000001754 15217274217 027235 0ustar00rootroot0000000 0000000 @ECHO OFF REM # Licensed to the Apache Software Foundation (ASF) under one REM # or more contributor license agreements. See the NOTICE file REM # distributed with this work for additional information REM # regarding copyright ownership. The ASF licenses this file REM # to you under the Apache License, Version 2.0 (the REM # "License"); you may not use this file except in compliance REM # with the License. You may obtain a copy of the License at REM # REM # http://www.apache.org/licenses/LICENSE-2.0 REM # REM # Unless required by applicable law or agreed to in writing, REM # software distributed under the License is distributed on an REM # REM # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY REM # KIND, either express or implied. See the License for the REM # specific language governing permissions and limitations REM # under the License. mvn -e -q exec:java "-Dexec.mainClass=opennlp.morfologik.cmdline.CLI" "-Dexec.args=%*" apache-opennlp-2.5.12-src/opennlp-morfologik-addon/pom.xml0100644 0000000 0000000 00000005026 15217274217 024053 0ustar00rootroot0000000 0000000 4.0.0 org.apache.opennlp opennlp 2.5.12 ../pom.xml opennlp-morfologik-addon jar Apache OpenNLP Morfologik Addon http://maven.apache.org org.carrot2 morfologik-stemming ${morfologik.version} compile org.carrot2 morfologik-tools ${morfologik.version} compile org.slf4j slf4j-api org.apache.opennlp opennlp-tools org.apache.opennlp opennlp-tools test-jar test org.junit.jupiter junit-jupiter-api test org.junit.jupiter junit-jupiter-engine test org.slf4j slf4j-simple test apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/bin/morfologik-addon0100755 0000000 0000000 00000003305 15217274217 030200 0ustar00rootroot0000000 0000000 #!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # Note: Do not output anything in this script file, any output # may be inadvertantly placed in any output files if # output redirection is used. # determine OPENNLP_HOME - $0 may be a symlink to OpenNLP's home PRG="$0" while [ -h "$PRG" ] ; do ls=$(ls -ld "$PRG") link=$(expr "$ls" : '.*-> \(.*\)$') if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG="$(dirname "$PRG")/$link" fi done saveddir=$(pwd) OPENNLP_HOME=$(dirname "$PRG")/.. # make it fully qualified OPENNLP_HOME=$(cd "$OPENNLP_HOME" && pwd) cd "$saveddir" || exit if [ -z "$JAVACMD" ] ; then if [ -n "$JAVA_HOME" ] ; then JAVACMD="$JAVA_HOME/bin/java" else JAVACMD="$(which java)" fi fi CLASSPATH=$(echo "$OPENNLP_HOME"/lib/*.jar | tr ' ' ':') $JAVACMD -Xmx1024m -Dlog4j.configurationFile="$OPENNLP_HOME/conf/log4j2.xml" -cp "$CLASSPATH" opennlp.morfologik.cmdline.CLI "$@" apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/bin/morfologik-addon.bat0100644 0000000 0000000 00000003547 15217274217 030752 0ustar00rootroot0000000 0000000 @ECHO off REM # Licensed to the Apache Software Foundation (ASF) under one REM # or more contributor license agreements. See the NOTICE file REM # distributed with this work for additional information REM # regarding copyright ownership. The ASF licenses this file REM # to you under the Apache License, Version 2.0 (the REM # "License"); you may not use this file except in compliance REM # with the License. You may obtain a copy of the License at REM # REM # http://www.apache.org/licenses/LICENSE-2.0 REM # REM # Unless required by applicable law or agreed to in writing, REM # software distributed under the License is distributed on an REM # # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY REM # KIND, either express or implied. See the License for the REM # specific language governing permissions and limitations REM # under the License. REM # Note: Do not output anything in this script file, any output REM # may be inadvertantly placed in any output files if REM # output redirection is used. SETLOCAL IF "%JAVA_CMD%" == "" ( IF "%JAVA_HOME%" == "" ( SET JAVA_CMD=java ) ELSE ( REM # Keep JAVA_HOME to short-name without spaces FOR %%A IN ("%JAVA_HOME%") DO SET JAVA_CMD=%%~sfA\bin\java ) ) REM # Should work with Windows XP and greater. If not, specify the path to where it is installed. IF "%OPENNLP_HOME%" == "" ( SET OPENNLP_HOME=%~sp0.. ) ELSE ( REM # Keep OPENNLP_HOME to short-name without spaces FOR %%A IN ("%OPENNLP_HOME%") DO SET OPENNLP_HOME=%%~sfA ) setLocal EnableDelayedExpansion set CLASSPATH=" FOR %%A IN ("%OPENNLP_HOME%\lib\*.jar") DO ( set CLASSPATH=!CLASSPATH!;%%A ) set CLASSPATH=!CLASSPATH!" %JAVA_CMD% -Xmx1024m "-Dlog4j.configurationFile=%OPENNLP_HOME%\conf\log4j2.xml" -cp %CLASSPATH% opennlp.morfologik.cmdline.CLI %* ENDLOCAL./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000206 15217274217 032421 xustar000000000 0000000 134 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/builder/MorfologikDictionaryBuilder.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/builder/Morfolog0100644 0000000 0000000 00000007066 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.builder; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Path; import java.util.Properties; import morfologik.stemming.DictionaryMetadata; import morfologik.stemming.EncoderType; import morfologik.tools.DictCompile; /** * Utility class to build Morfologik dictionaries from a tab separated * values file. *

* The first column is the word, the second its lemma and the third a POS * tag (base,inflected,tag). If there is no lemma information leave the * second column empty. */ public class MorfologikDictionaryBuilder { /** * Helper to compile a morphological dictionary automaton. * * @param input The {@link Path input file} (base,inflected,tag). * An associated metadata ({@code *.info}) file must exist. * @param overwrite Whether to overwrite the output file if it exists, or not. * @param validate Whether to validate input to make sure it makes sense. * @param acceptBom Whether to accept leading BOM bytes (UTF-8), or not. * @param acceptCr Whether to accept CR bytes in input sequences ({@code \r}), or not. * @param ignoreEmpty Whether to ignore empty lines in the input, or not. * * @return The resulting dictionary {@link Path}. * @throws Exception Thrown if errors occurred during dictionary compilation. */ public Path build(Path input, boolean overwrite, boolean validate, boolean acceptBom, boolean acceptCr, boolean ignoreEmpty) throws Exception { DictCompile compiler = new DictCompile(input, overwrite, validate, acceptBom, acceptCr, ignoreEmpty); compiler.call(); Path metadataPath = DictionaryMetadata.getExpectedMetadataLocation(input); return metadataPath.resolveSibling( metadataPath.getFileName().toString().replaceAll( "\\." + DictionaryMetadata.METADATA_FILE_EXTENSION + "$", ".dict")); } /** * Helper to compile a morphological dictionary automaton using default * parameters. * * @param input The {@link Path input file} (base,inflected,tag). * An associated metadata ({@code *.info}) file must exist. * * @return The resulting dictionary {@link Path}. * @throws Exception Thrown if errors occurred during dictionary compilation. */ public Path build(Path input) throws Exception { return build(input, true, true, false, false, false); } Properties createProperties(Charset encoding, String separator, EncoderType encoderType) throws IOException { Properties properties = new Properties(); properties.setProperty("fsa.dict.separator", separator); properties.setProperty("fsa.dict.encoding", encoding.name()); properties.setProperty("fsa.dict.encoder", encoderType.name()); return properties; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000156 15217274217 032425 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/CLI.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/CLI.java0100644 0000000 0000000 00000011477 15217274217 033711 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.cmdline; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.morfologik.cmdline.builder.MorfologikDictionaryBuilderTool; import opennlp.morfologik.cmdline.builder.XMLDictionaryToTableTool; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CmdLineTool; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.TypedCmdLineTool; import opennlp.tools.util.Version; public final class CLI { private static final Logger logger = LoggerFactory.getLogger(CLI.class); private static final String CMD = "opennlp-morfologik-addon"; private static Map toolLookupMap; static { toolLookupMap = new LinkedHashMap<>(); List tools = new LinkedList<>(); tools.add(new MorfologikDictionaryBuilderTool()); tools.add(new XMLDictionaryToTableTool()); for (CmdLineTool tool : tools) { toolLookupMap.put(tool.getName(), tool); } toolLookupMap = Collections.unmodifiableMap(toolLookupMap); } /** * @return A set which contains all tool names. */ public static Set getToolNames() { return toolLookupMap.keySet(); } private static void usage() { logger.info("OpenNLP Morfologik Addon {}.", Version.currentVersion()); logger.info("Usage: {} TOOL", CMD); // distance of tool name from line start int numberOfSpaces = -1; for (String toolName : toolLookupMap.keySet()) { if (toolName.length() > numberOfSpaces) { numberOfSpaces = toolName.length(); } } numberOfSpaces = numberOfSpaces + 4; final StringBuilder sb = new StringBuilder("where TOOL is one of: \n\n"); for (CmdLineTool tool : toolLookupMap.values()) { sb.append(" ").append(tool.getName()); sb.append(" ".repeat(Math.max(0, StrictMath.abs( tool.getName().length() - numberOfSpaces)))); sb.append(tool.getShortDescription()).append("\n"); } logger.info(sb.toString()); logger.info("All tools print help when invoked with help parameter"); logger.info("Example: opennlp-morfologik-addon POSDictionaryBuilder help"); } @SuppressWarnings("rawtypes") public static void main(String[] args) { if (args.length == 0) { usage(); System.exit(0); } String[] toolArguments = new String[args.length - 1]; System.arraycopy(args, 1, toolArguments, 0, toolArguments.length); String toolName = args[0]; //check for format String formatName = StreamFactoryRegistry.DEFAULT_FORMAT; int idx = toolName.indexOf("."); if (-1 < idx) { formatName = toolName.substring(idx + 1); toolName = toolName.substring(0, idx); } CmdLineTool tool = toolLookupMap.get(toolName); try { if (null == tool) { throw new TerminateToolException(1, "Tool " + toolName + " is not found."); } if ((0 == toolArguments.length && tool.hasParams()) || 0 < toolArguments.length && "help".equals(toolArguments[0])) { if (tool instanceof TypedCmdLineTool) { logger.info(((TypedCmdLineTool) tool).getHelp(formatName)); } else if (tool instanceof BasicCmdLineTool) { logger.info(tool.getHelp()); } System.exit(0); } if (tool instanceof TypedCmdLineTool) { ((TypedCmdLineTool) tool).run(formatName, toolArguments); } else if (tool instanceof BasicCmdLineTool) { if (-1 == idx) { ((BasicCmdLineTool) tool).run(toolArguments); } else { throw new TerminateToolException(1, "Tool " + toolName + " does not support formats."); } } else { throw new TerminateToolException(1, "Tool " + toolName + " is not supported."); } } catch (TerminateToolException e) { logger.error(e.getLocalizedMessage(), e); System.exit(e.getCode()); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000224 15217274217 032421 xustar000000000 0000000 148 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/MorfologikDictionaryBuilderParams.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/0100644 0000000 0000000 00000004542 15217274217 034062 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.cmdline.builder; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.EncodingParameter; /** * Params for Dictionary tools. */ interface MorfologikDictionaryBuilderParams extends EncodingParameter { @ParameterDescription(valueName = "in", description = "The input file (base,inflected,tag). An associated metadata (*.info) file must exist.") File getInputFile(); @ParameterDescription(valueName = "true|false", description = "Accept leading BOM bytes (UTF-8).") @OptionalParameter(defaultValue = "false") Boolean getAcceptBOM(); @ParameterDescription(valueName = "true|false", description = "Accept CR bytes in input sequences (\r).") @OptionalParameter(defaultValue = "false") Boolean getAcceptCR(); @ParameterDescription(valueName = "FSA5|CFSA2", description = "Automaton serialization format.") @OptionalParameter(defaultValue = "FSA5") String getFormat(); @ParameterDescription(valueName = "true|false", description = "Ignore empty lines in the input.") @OptionalParameter(defaultValue = "false") Boolean getIgnoreEmpty(); @ParameterDescription(valueName = "true|false", description = "Overwrite the output file if it exists.") @OptionalParameter(defaultValue = "false") Boolean getOverwrite(); @ParameterDescription(valueName = "true|false", description = "Validate input to make sure it makes sense.") @OptionalParameter(defaultValue = "false") Boolean getValidate(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000222 15217274217 032417 xustar000000000 0000000 146 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/MorfologikDictionaryBuilderTool.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/0100644 0000000 0000000 00000004447 15217274217 034066 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.cmdline.builder; import java.io.File; import java.nio.file.Path; import morfologik.stemming.DictionaryMetadata; import opennlp.morfologik.builder.MorfologikDictionaryBuilder; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; public class MorfologikDictionaryBuilderTool extends BasicCmdLineTool { interface Params extends MorfologikDictionaryBuilderParams { } @Override public String getShortDescription() { return "builds a binary POS Dictionary using Morfologik"; } @Override public String getHelp() { return getBasicHelp(Params.class); } @Override public void run(String[] args) { Params params = validateAndParseParams(args, Params.class); File dictInFile = params.getInputFile(); CmdLineUtil.checkInputFile("dictionary input file", dictInFile); Path metadataPath = DictionaryMetadata.getExpectedMetadataLocation(dictInFile.toPath()); CmdLineUtil.checkInputFile("dictionary metadata (.info) input file", metadataPath.toFile()); MorfologikDictionaryBuilder builder = new MorfologikDictionaryBuilder(); try { builder.build(dictInFile.toPath(), params.getOverwrite(), params.getValidate(), params.getAcceptBOM(), params.getAcceptCR(), params.getIgnoreEmpty()); } catch (Exception e) { throw new TerminateToolException(-1, "Error while creating Morfologik POS Dictionary: " + e.getMessage(), e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000215 15217274217 032421 xustar000000000 0000000 141 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/XMLDictionaryToTableParams.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/0100644 0000000 0000000 00000003550 15217274217 034060 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.cmdline.builder; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.EncodingParameter; /** * Params for Dictionary tools. */ interface XMLDictionaryToTableParams extends EncodingParameter { @ParameterDescription(valueName = "in", description = "OpenNLP XML Tag Dictionary.") File getInputFile(); @ParameterDescription(valueName = "out", description = "Output for Morfologik " + "(.info will be also created).") File getOutputFile(); @ParameterDescription(valueName = "char", description = "Column separator " + "(must be a single character)") @OptionalParameter(defaultValue = ",") String getSeparator(); @ParameterDescription(valueName = "value", description = " Type of lemma-inflected " + "form encoding compression that precedes automaton construction. Allowed " + "values: [suffix, infix, prefix, none].") @OptionalParameter(defaultValue = "prefix") String getEncoder(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000213 15217274217 032417 xustar000000000 0000000 139 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/XMLDictionaryToTableTool.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/cmdline/builder/0100644 0000000 0000000 00000010273 15217274217 034060 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.cmdline.builder; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.Iterator; import java.util.Properties; import morfologik.stemming.DictionaryMetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.postag.POSDictionary; public class XMLDictionaryToTableTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(XMLDictionaryToTableTool.class); private static String SEPARATOR; public String getShortDescription() { return "reads an OpenNLP XML tag dictionary and outputs it in a tabular file"; } @Override public String getHelp() { return getBasicHelp(Params.class); } @Override public void run(String[] args) { Params params = validateAndParseParams(args, Params.class); File dictInFile = params.getInputFile(); File dictOutFile = params.getOutputFile(); Charset encoding = params.getEncoding(); SEPARATOR = params.getSeparator(); CmdLineUtil.checkInputFile("dictionary input file", dictInFile); CmdLineUtil.checkOutputFile("dictionary output file", dictOutFile); POSDictionary tagDictionary; try { tagDictionary = POSDictionary.create(new FileInputStream(dictInFile)); } catch (IOException e) { throw new TerminateToolException(-1, "Error while loading XML POS Dictionary: " + e.getMessage(), e); } Iterator iterator = tagDictionary.iterator(); try (BufferedWriter writer = Files.newBufferedWriter(dictOutFile.toPath(), encoding)) { while (iterator.hasNext()) { String word = iterator.next(); for (String tag : tagDictionary.getTags(word)) { if (valid(word, tag)) { String entry = createEntry(word, tag); writer.write(entry); writer.newLine(); } } } logger.info("Created dictionary: {}", dictOutFile.toPath()); } catch (IOException e) { throw new TerminateToolException(-1, "Error while writing output: " + e.getMessage(), e); } Properties info = new Properties(); info.setProperty("fsa.dict.separator", SEPARATOR); info.setProperty("fsa.dict.encoding", params.getEncoding().name()); info.setProperty("fsa.dict.encoder", params.getEncoder()); Path metaPath = DictionaryMetadata.getExpectedMetadataLocation(dictOutFile.toPath()); try { info.store(Files.newOutputStream(metaPath), "Info file for FSA Morfologik dictionary."); } catch (IOException e) { throw new TerminateToolException(-1, "Error while writing metadata output: " + e.getMessage(), e); } logger.info("Created metadata: {}", dictOutFile.toPath()); } private boolean valid(String word, String tag) { if (word.contains(SEPARATOR) || tag.contains(SEPARATOR)) { logger.warn("invalid entry because contains separator - word: {} tag: {}", word, tag); return false; } return true; } private String createEntry(String word, String tag) { return "" + SEPARATOR + // base word + SEPARATOR + tag; } interface Params extends XMLDictionaryToTableParams { } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000202 15217274217 032415 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/lemmatizer/MorfologikLemmatizer.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/lemmatizer/Morfo0100644 0000000 0000000 00000006412 15217274217 034173 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.lemmatizer; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Set; import morfologik.stemming.Dictionary; import morfologik.stemming.DictionaryLookup; import morfologik.stemming.WordData; import opennlp.tools.lemmatizer.Lemmatizer; /** * A {@link Lemmatizer} implementation based on Morfologik binary * dictionaries */ public class MorfologikLemmatizer implements Lemmatizer { private final Dictionary dictionary; /** * Initializes a {@link MorfologikLemmatizer} and related {@link Dictionary} * from the input tab separated dictionary. * * @param dictionaryPath The dictionary referenced via a valid, readable {@link Path}. * * @throws IOException Thrown if IO errors occurred while reading in from * {@code dictionaryPath}. */ public MorfologikLemmatizer(Path dictionaryPath) throws IOException { this(Dictionary.read(dictionaryPath)); } /** * Initializes a {@link MorfologikLemmatizer} and related {@link Dictionary} * from the input tab separated dictionary. * * @param dictionary The {@link Dictionary} to be used. */ public MorfologikLemmatizer(Dictionary dictionary) { this.dictionary = dictionary; } private List lemmatize(String word, String postag) { List dictMap = new DictionaryLookup(dictionary).lookup(word.toLowerCase(Locale.ROOT)); Set lemmas = new HashSet<>(); for (WordData wordData : dictMap) { if (Objects.equals(postag, asString(wordData.getTag()))) { lemmas.add(asString(wordData.getStem())); } } return List.copyOf(lemmas); } private String asString(CharSequence tag) { if (tag == null) { return null; } return tag.toString(); } @Override public String[] lemmatize(String[] toks, String[] tags) { String[] lemmas = new String[toks.length]; for (int i = 0; i < toks.length; i++) { List l = lemmatize(toks[i], tags[i]); if (l.size() > 0) { lemmas[i] = l.get(0); } else { lemmas[i] = null; } } return lemmas; } @Override public List> lemmatize(List toks, List tags) { List> lemmas = new ArrayList<>(); for (int i = 0; i < toks.size(); i++) { lemmas.add(lemmatize(toks.get(i), tags.get(i))); } return lemmas; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000205 15217274217 032420 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/tagdict/MorfologikPOSTaggerFactory.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/tagdict/Morfolog0100644 0000000 0000000 00000012726 15217274217 034150 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.tagdict; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import morfologik.stemming.DictionaryMetadata; import opennlp.tools.postag.POSTaggerFactory; import opennlp.tools.postag.TagDictionary; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.ByteArraySerializer; /** * The factory provides a Morfologik specific {@link POSTaggerFactory} implementation * and initializes related resources. */ public class MorfologikPOSTaggerFactory extends POSTaggerFactory { private static final String MORFOLOGIK_POSDICT_SUF = "morfologik_dict"; private static final String MORFOLOGIK_DICT_INFO_SUF = "morfologik_info"; private static final String MORFOLOGIK_POSDICT = "tagdict." + MORFOLOGIK_POSDICT_SUF; private static final String MORFOLOGIK_DICT_INFO = "tagdict." + MORFOLOGIK_DICT_INFO_SUF; private TagDictionary dict; private byte[] dictInfo; private byte[] dictData; public MorfologikPOSTaggerFactory() { } /** * Initializes a {@link TagDictionary} from a {@link File dictionary file}. * * @param dictionary The {@link File} used as input for creating the dictionary. * * @return A valid {@link TagDictionary} ready for use. * @throws FileNotFoundException Thrown if {@code dictionary} or related metadata * could not be read in. * @throws IOException Thrown if IO errors occurred. */ public TagDictionary createTagDictionary(File dictionary) throws IOException { if (!dictionary.canRead()) { throw new FileNotFoundException("Could not read dictionary: " + dictionary.getAbsolutePath()); } Path dictionaryMeta = DictionaryMetadata.getExpectedMetadataLocation(dictionary.toPath()); if (dictionaryMeta == null || !dictionaryMeta.toFile().canRead()) { throw new FileNotFoundException("Could not read dictionary metadata: " + dictionaryMeta.getFileName()); } this.dictData = Files.readAllBytes(dictionary.toPath()); this.dictInfo = Files.readAllBytes(dictionaryMeta); return createMorfologikDictionary(dictData, dictInfo); } /** * @return The {@link TagDictionary} used. * @throws RuntimeException Thrown if errors occurred loading or reading * Morfologik dictionary files. */ @Override public TagDictionary getTagDictionary() { if (this.dict == null) { if (artifactProvider != null) { Object obj = artifactProvider.getArtifact(MORFOLOGIK_POSDICT); if (obj != null) { byte[] data = artifactProvider.getArtifact(MORFOLOGIK_POSDICT); byte[] info = artifactProvider.getArtifact(MORFOLOGIK_DICT_INFO); try { this.dict = createMorfologikDictionary(data, info); } catch (IllegalArgumentException e) { throw new RuntimeException( "Could not load the dictionary files to Morfologik.", e); } catch (IOException e) { throw new RuntimeException( "IO error while reading the Morfologik dictionary files.", e); } } } } return this.dict; } @Override public void setTagDictionary(TagDictionary dictionary) { this.dict = dictionary; } @Override public TagDictionary createEmptyTagDictionary() { throw new UnsupportedOperationException( "Morfologik POS Tagger factory does not support this operation"); } @Override public TagDictionary createTagDictionary(InputStream in) throws IOException { throw new UnsupportedOperationException( "Morfologik POS Tagger factory does not support this operation"); } @Override public Map> createArtifactSerializersMap() { Map> serializers = super.createArtifactSerializersMap(); serializers.put(MORFOLOGIK_POSDICT_SUF, new ByteArraySerializer()); serializers.put(MORFOLOGIK_DICT_INFO_SUF, new ByteArraySerializer()); return serializers; } @Override public Map createArtifactMap() { Map artifactMap = super.createArtifactMap(); artifactMap.put(MORFOLOGIK_POSDICT, this.dictData); artifactMap.put(MORFOLOGIK_DICT_INFO, this.dictInfo); return artifactMap; } private TagDictionary createMorfologikDictionary(byte[] data, byte[] info) throws IOException { morfologik.stemming.Dictionary dict = morfologik.stemming.Dictionary .read(new ByteArrayInputStream(data), new ByteArrayInputStream(info)); return new MorfologikTagDictionary(dict); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000202 15217274217 032415 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/tagdict/MorfologikTagDictionary.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/tagdict/Morfolog0100644 0000000 0000000 00000005470 15217274217 034146 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.tagdict; import java.util.ArrayList; import java.util.List; import java.util.Locale; import morfologik.stemming.Dictionary; import morfologik.stemming.DictionaryLookup; import morfologik.stemming.IStemmer; import morfologik.stemming.WordData; import opennlp.tools.postag.TagDictionary; /** * A {@link TagDictionary} implementation based on Morfologik binary * dictionaries */ public class MorfologikTagDictionary implements TagDictionary { private final IStemmer dictLookup; private final boolean isCaseSensitive; /** * Initializes a case sensitive {@link MorfologikTagDictionary} * * @param dict A Morfologik FSA {@link Dictionary}. * @throws IllegalArgumentException Thrown if FSA's root node cannot be acquired * (dictionary is empty). */ public MorfologikTagDictionary(Dictionary dict) throws IllegalArgumentException { this(dict, true); } /** * Initializes a {@link MorfologikTagDictionary} * * @param dict A Morfologik FSA {@link Dictionary}. * @param caseSensitive If {@code true} it performs case-sensitive lookup * @throws IllegalArgumentException Thrown if FSA's root node cannot be acquired * (dictionary is empty). */ public MorfologikTagDictionary(Dictionary dict, boolean caseSensitive) throws IllegalArgumentException { this.dictLookup = new DictionaryLookup(dict); this.isCaseSensitive = caseSensitive; } @Override public String[] getTags(String word) { if (!isCaseSensitive) { word = word.toLowerCase(Locale.ROOT); } List data = dictLookup.lookup(word); if (data != null && data.size() > 0) { List tags = new ArrayList<>(data.size()); for (WordData aData : data) { tags.add(aData.getTag().toString()); } if (tags.size() > 0) return tags.toArray(new String[0]); return null; } return null; } @Override public boolean isCaseSensitive() { return isCaseSensitive; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_main_java_opennlp_morfologik_0100644 0000000 0000000 00000000166 15217274217 032426 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/util/MorfologikUtil.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/main/java/opennlp/morfologik/util/MorfologikU0100644 0000000 0000000 00000002425 15217274217 034152 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.util; import java.io.File; import morfologik.stemming.DictionaryMetadata; /** * A utility class that helps in finding (related) Morfologik files. */ public class MorfologikUtil { public static File getExpectedPropertiesFile(File dictFile) { return DictionaryMetadata.getExpectedMetadataLocation(dictFile.toPath()).toFile(); } public static File getExpectedPropertiesFile(String dictFile) { return getExpectedPropertiesFile(new File(dictFile)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_test_java_opennlp_morfologik_0100644 0000000 0000000 00000000171 15217274217 032455 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/AbstractMorfologikTest.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/AbstractMorfolog0100644 0000000 0000000 00000005044 15217274217 034243 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik; import java.io.File; import java.io.InputStream; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import morfologik.stemming.DictionaryMetadata; import opennlp.morfologik.builder.MorfologikDictionaryBuilder; public abstract class AbstractMorfologikTest { protected static Path createMorfologikDictionary() throws Exception { return createMorfologikDictionary("dictionaryWithLemma"); } /** * Builds a Morfologik FSA dictionary from the {@code .txt} and {@code .info} test * resources sharing the given base name. * * @param resourceBaseName The base name of the tab separated dictionary resource pair. * * @return The {@link Path} of the built FSA dictionary. */ protected static Path createMorfologikDictionary(String resourceBaseName) throws Exception { Path tabFilePath = File.createTempFile(AbstractMorfologikTest.class.getName(), ".txt").toPath(); tabFilePath.toFile().deleteOnExit(); Path infoFilePath = DictionaryMetadata.getExpectedMetadataLocation(tabFilePath); infoFilePath.toFile().deleteOnExit(); Files.copy(getResourceStream("/" + resourceBaseName + ".txt"), tabFilePath, StandardCopyOption.REPLACE_EXISTING); Files.copy(getResourceStream("/" + resourceBaseName + ".info"), infoFilePath, StandardCopyOption.REPLACE_EXISTING); MorfologikDictionaryBuilder builder = new MorfologikDictionaryBuilder(); return builder.build(tabFilePath); } private static InputStream getResourceStream(String name) { return AbstractMorfologikTest.class.getResourceAsStream(name); } protected static URL getResource(String name) { return AbstractMorfologikTest.class.getResource(name); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_test_java_opennlp_morfologik_0100644 0000000 0000000 00000000167 15217274217 032462 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/MorfologikLocaleTest.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/MorfologikLocale0100644 0000000 0000000 00000005550 15217274217 034225 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik; import java.nio.file.Path; import java.util.Locale; import morfologik.stemming.Dictionary; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import opennlp.morfologik.lemmatizer.MorfologikLemmatizer; import opennlp.morfologik.tagdict.MorfologikTagDictionary; /** * Tests that the case insensitive lookups into a prebuilt Morfologik FSA dictionary do not * depend on the JVM's default {@link Locale}. *

* The FSA is built once and shipped; folding the query with the default locale makes the * same dictionary answer differently on different JVMs. */ public class MorfologikLocaleTest extends AbstractMorfologikTest { /** * Turkish folds {@code 'I'} to the dotless {@code 'ı'} (U+0131) instead of {@code 'i'}. */ private static final Locale TURKISH = new Locale("tr", "TR"); private final Locale defaultLocale = Locale.getDefault(); @AfterEach void restoreDefaultLocale() { Locale.setDefault(defaultLocale); } @Test public void testLemmatizeIsIndependentOfDefaultLocale() throws Exception { final MorfologikLemmatizer lemmatizer = new MorfologikLemmatizer(createLocaleDictionary()); Locale.setDefault(TURKISH); final String[] lemmas = lemmatizer.lemmatize( new String[] {"Illinois", "INDICES"}, new String[] {"PROP", "NOUN"}); Assertions.assertArrayEquals(new String[] {"Illinois", "index"}, lemmas); } @Test public void testGetTagsIsIndependentOfDefaultLocale() throws Exception { final MorfologikTagDictionary tagDictionary = new MorfologikTagDictionary(Dictionary.read(createLocaleDictionary()), false); Locale.setDefault(TURKISH); Assertions.assertArrayEquals(new String[] {"PROP"}, tagDictionary.getTags("Illinois")); Assertions.assertArrayEquals(new String[] {"NOUN"}, tagDictionary.getTags("INDICES")); } private static Path createLocaleDictionary() throws Exception { final Path output = createMorfologikDictionary("dictionaryLocaleSafety"); output.toFile().deleteOnExit(); return output; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_test_java_opennlp_morfologik_0100644 0000000 0000000 00000000212 15217274217 032451 xustar000000000 0000000 138 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/builder/MorfologikDictionaryBuilderTest.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/builder/Morfolog0100644 0000000 0000000 00000005332 15217274217 034205 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.builder; import java.io.File; import java.nio.file.Path; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import opennlp.morfologik.AbstractMorfologikTest; import opennlp.morfologik.lemmatizer.MorfologikLemmatizer; /** * Tests for the {@link MorfologikDictionaryBuilder} class. */ public class MorfologikDictionaryBuilderTest extends AbstractMorfologikTest { @Test public void testMultithreading() throws Exception { // Part 1: compile a FSA lemma dictionary // we need the tabular dictionary. It is mandatory to have info // file with same name, but .info extension // this will build a binary dictionary located in compiledLemmaDictionary final Path rawLemmaDictionary = new File(getResource("/dictionaryWithLemma.txt").getFile()).toPath(); Path compiledLemmaDictionary = new MorfologikDictionaryBuilder().build(rawLemmaDictionary); // Part 2: load a MorfologikLemmatizer and use it MorfologikLemmatizer lemmatizer = new MorfologikLemmatizer(compiledLemmaDictionary); String[] toks = {"casa", "casa"}; String[] tags = {"NOUN", "V"}; Runnable runnable = () -> { String[] lemmas = lemmatizer.lemmatize(toks, tags); Assertions.assertEquals("casa", lemmas[0]); Assertions.assertEquals("casar", lemmas[1]); }; ExecutorService executorService = Executors.newFixedThreadPool(2); for (int i = 0; i < 1000; i++) { executorService.execute(runnable); } executorService.shutdown(); executorService.awaitTermination(1, TimeUnit.SECONDS); } @Test public void testBuildDictionary() throws Exception { Path output = createMorfologikDictionary(); MorfologikLemmatizer ml = new MorfologikLemmatizer(output); Assertions.assertNotNull(ml); output.toFile().deleteOnExit(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_test_java_opennlp_morfologik_0100644 0000000 0000000 00000000206 15217274217 032454 xustar000000000 0000000 134 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/lemmatizer/MorfologikLemmatizerTest.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/lemmatizer/Morfo0100644 0000000 0000000 00000004410 15217274217 034222 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.lemmatizer; import java.nio.file.Path; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import opennlp.morfologik.AbstractMorfologikTest; import opennlp.tools.lemmatizer.Lemmatizer; /** * Tests for the {@link MorfologikLemmatizer} class. */ public class MorfologikLemmatizerTest extends AbstractMorfologikTest { @Test public void testLemmatizeInsensitive() throws Exception { Lemmatizer dict = createDictionary(false); String[] toks = {"casa", "casa", "Casa"}; String[] tags = {"V", "NOUN", "PROP"}; String[] lemmas = dict.lemmatize(toks, tags); Assertions.assertEquals("casar", lemmas[0]); Assertions.assertEquals("casa", lemmas[1]); // lookup is case-insensitive. There is no entry casa - prop Assertions.assertNull(lemmas[2]); } @Test public void testLemmatizeMultiLemma() throws Exception { MorfologikLemmatizer dict = createDictionary(false); String[] toks = {"foi"}; String[] tags = {"V"}; List> lemmas = dict.lemmatize(Arrays.asList(toks), Arrays.asList(tags)); Assertions.assertTrue(lemmas.get(0).contains("ir")); Assertions.assertTrue(lemmas.get(0).contains("ser")); } private MorfologikLemmatizer createDictionary(boolean caseSensitive) throws Exception { Path output = createMorfologikDictionary(); output.toFile().deleteOnExit(); return new MorfologikLemmatizer(output); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_test_java_opennlp_morfologik_0100644 0000000 0000000 00000000211 15217274217 032450 xustar000000000 0000000 137 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/tagdict/MorfologikPOSTaggerFactoryTest.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/tagdict/Morfolog0100644 0000000 0000000 00000007377 15217274217 034211 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.tagdict; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import opennlp.morfologik.AbstractMorfologikTest; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.POSTaggerFactory; import opennlp.tools.postag.POSTaggerME; import opennlp.tools.postag.TagDictionary; import opennlp.tools.postag.WordTagSampleStream; import opennlp.tools.util.MarkableFileInputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.model.ModelType; /** * Tests for the {@link MorfologikPOSTaggerFactory} class. */ public class MorfologikPOSTaggerFactoryTest extends AbstractMorfologikTest { private static ObjectStream createSampleStream() throws IOException { MarkableFileInputStreamFactory sampleDataIn = new MarkableFileInputStreamFactory( new File(getResource("/AnnotatedSentences.txt").getFile())); ObjectStream lineStream = null; try { lineStream = new PlainTextByLineStream(sampleDataIn, StandardCharsets.UTF_8); } catch (IOException ex) { CmdLineUtil.handleCreateObjectStreamError(ex); } return new WordTagSampleStream(lineStream); } private static POSModel trainPOSModel(ModelType type, POSTaggerFactory factory) throws IOException { return POSTaggerME.train("en", createSampleStream(), TrainingParameters.defaultParams(), factory); } @Test public void testPOSTaggerWithCustomFactory() throws Exception { Path dictionary = createMorfologikDictionary(); dictionary.toFile().deleteOnExit(); POSTaggerFactory inFactory = new MorfologikPOSTaggerFactory(); TagDictionary inDict = inFactory.createTagDictionary(dictionary.toFile()); inFactory.setTagDictionary(inDict); POSModel posModel = trainPOSModel(ModelType.MAXENT, inFactory); Assertions.assertNotNull(posModel); POSTaggerFactory factory = posModel.getFactory(); Assertions.assertNotNull(factory); Assertions.assertTrue(factory.getTagDictionary() instanceof MorfologikTagDictionary); ByteArrayOutputStream out = new ByteArrayOutputStream(); posModel.serialize(out); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); POSModel fromSerialized = new POSModel(in); Assertions.assertNotNull(fromSerialized); // check for equality Assertions.assertEquals(posModel, fromSerialized); factory = fromSerialized.getFactory(); Assertions.assertNotNull(factory); Assertions.assertTrue(factory.getTagDictionary() instanceof MorfologikTagDictionary); Assertions.assertEquals(2, factory.getTagDictionary().getTags("casa").length); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-morfologik-addon_src_test_java_opennlp_morfologik_0100644 0000000 0000000 00000000206 15217274217 032454 xustar000000000 0000000 134 path=apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/tagdict/MorfologikTagDictionaryTest.java apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/java/opennlp/morfologik/tagdict/Morfolog0100644 0000000 0000000 00000006443 15217274217 034202 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.morfologik.tagdict; import java.nio.file.Path; import java.util.Arrays; import java.util.List; import morfologik.stemming.Dictionary; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import opennlp.morfologik.AbstractMorfologikTest; import opennlp.tools.postag.TagDictionary; /** * Tests for the {@link MorfologikTagDictionary} class. */ public class MorfologikTagDictionaryTest extends AbstractMorfologikTest { @Test public void testNoLemma() throws Exception { MorfologikTagDictionary dict = createDictionary(false); List tags = Arrays.asList(dict.getTags("carro")); Assertions.assertEquals(1, tags.size()); Assertions.assertTrue(tags.contains("NOUN")); } @Test public void testPOSDictionaryInsensitive() throws Exception { TagDictionary dict = createDictionary(false); List tags = Arrays.asList(dict.getTags("casa")); Assertions.assertEquals(2, tags.size()); Assertions.assertTrue(tags.contains("NOUN")); Assertions.assertTrue(tags.contains("V")); // this is the behavior of case insensitive dictionary // if we search it using case insensitive, Casa as a proper noun // should be lower case in the dictionary tags = Arrays.asList(dict.getTags("Casa")); Assertions.assertEquals(2, tags.size()); Assertions.assertTrue(tags.contains("NOUN")); Assertions.assertTrue(tags.contains("V")); } @Test public void testPOSDictionarySensitive() throws Exception { TagDictionary dict = createDictionary(true); List tags = Arrays.asList(dict.getTags("casa")); Assertions.assertEquals(2, tags.size()); Assertions.assertTrue(tags.contains("NOUN")); Assertions.assertTrue(tags.contains("V")); // this is the behavior of case insensitive dictionary // if we search it using case insensitive, Casa as a proper noun // should be lower case in the dictionary tags = Arrays.asList(dict.getTags("Casa")); Assertions.assertEquals(1, tags.size()); Assertions.assertTrue(tags.contains("PROP")); } private MorfologikTagDictionary createDictionary(boolean caseSensitive) throws Exception { return this.createDictionary(caseSensitive, null); } private MorfologikTagDictionary createDictionary(boolean caseSensitive, List constant) throws Exception { Path output = createMorfologikDictionary(); output.toFile().deleteOnExit(); Dictionary dic = Dictionary.read(output); return new MorfologikTagDictionary(dic, caseSensitive); } } apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/resources/AnnotatedSentences.txt0100644 0000000 0000000 00000031454 15217274217 032650 0ustar00rootroot0000000 0000000 Last_JJ September_NNP ,_, I_PRP tried_VBD to_TO find_VB out_RP the_DT address_NN of_IN an_DT old_JJ school_NN friend_NN whom_WP I_PRP had_VBD not_RB seen_VBN for_IN 15_CD years_NNS ._. I_PRP just_RB knew_VBD his_PRP$ name_NN ,_, Alan_NNP McKennedy_NNP ,_, and_CC I_PRP 'd_MD heard_VBD the_DT rumour_NN that_IN he_PRP 'd_MD moved_VBD to_TO Scotland_NNP ,_, the_DT country_NN of_IN his_PRP$ ancestors_NNS ._. So_IN I_PRP called_VBD Julie_NNP ,_, a_DT friend_NN who's_WDT still_RB in_IN contact_NN with_IN him_PRP ._. She_PRP told_VBD me_PRP that_IN he_PRP lived_VBD in_IN 23213_CD Edinburgh_NNP ,_, Worcesterstreet_NNP 12_CD ._. I_PRP wrote_VBD him_PRP a_DT letter_NN right_RB away_RB and_CC he_PRP answered_VBD soon_RB ,_, sounding_VBG very_RB happy_JJ and_CC delighted_JJ ._. Last_JJ year_NN ,_, I_PRP wanted_VBD to_TO write_VB a_DT letter_NN to_TO my_PRP$ grandaunt_NN ._. Her_PRP$ 86_CD th_NN birthday_NN was_VBD on_IN October_NNP 6_CD ,_, and_CC I_PRP no_RB longer_RB wanted_VBD to_TO be_VB hesitant_JJ to_TO get_VB in_IN touch_NN with_IN her_PRP ._. I_PRP did_VBD not_RB know_VB her_PRP face-to-face_RB ,_, and_CC so_RB it_PRP was_VBD not_RB easy_JJ for_IN me_PRP to_TO find_VB out_RP her_PRP$ address_NN ._. As_IN she_PRP had_VBD two_CD apartments_NNS in_IN different_JJ countries_NNS ,_, I_PRP decided_VBD to_TO write_VB to_TO both_DT ._. The_DT first_JJ was_VBD in_IN 12424_CD Paris_NNP in_IN Rue-de-Grandes-Illusions_NNP 5_CD ._. But_CC Marie_NNP Clara_NNP ,_, as_IN my_PRP$ aunt_NN is_VBZ called_VBN ,_, prefered_VBN her_PRP$ apartment_NN in_IN Berlin_NNP ._. It_PRP 's_VBZ postcode_JJ is_VBZ 30202_CD ._. She_PRP lived_VBD there_RB ,_, in_IN beautiful_JJ Kaiserstra§e_NNP 13_CD ,_, particulary_NN in_IN summer_NN ._. Hi_UH my_PRP$ name_NN is_VBZ Stefanie_NNP Schmidt_NNP ,_, how_WRB much_RB is_VBZ a_DT taxi_NN from_IN Ostbahnhof_NNP to_TO Hauptbahnhof_NNP ?_. About_IN 10_CD Euro_NNP ,_, I_PRP reckon_VBP ._. That_DT sounds_VBZ good_JJ ._. So_RB please_VB call_VB a_DT driver_NN to_TO Leonardstra§e_NNP 112_CD ,_, near_IN the_DT Ostbahnhof_NNP in_IN 56473_CD Hamburg_NNP ._. I_PRP 'd_MD like_VB to_TO be_VB at_IN Silberhornstra§e_NNP 12_CD as_RB soon_RB as_IN possible_JJ ._. Thank_VB you_PRP very_RB much_RB !_. Hi_NNP Mike_NNP ,_, it_PRP 's_VBZ Stefanie_NNP Schmidt_NNP ._. I_PRP 'm_VBP in_IN NŸrnberg_NNP at_IN the_DT moment_NN and_CC I_PRP 've_VBP got_VBD the_DT problem_NN that_IN my_PRP$ bike_NN has_VBZ broken_VBN ._. Could_MD you_PRP please_VB pick_VB me_PRP up_RP from_IN Seidlstra§e_NNP 56_CD ,_, I_PRP 'm_VBP in_IN the_DT CafŽ_NNP "Mondnacht"_NNP at_IN the_DT moment_NN ._. Please_VB hurry_VB up_RB ,_, I_PRP need_VBP to_TO be_VB back_RB in_IN Ulm_NNP at_IN 8_CD p.m._NN !_. My_PRP$ husband_NN George_NNP and_CC me_PRP recently_RB celebrated_VBD our_PRP$ 10_CD th_JJ wedding_NN anniversary_NN ._. We_PRP got_VBD married_VBN on_IN March_NNP 11_CD ,_, 1995_CD ._. Therefore_RB ,_, we_PRP found_VBD a_DT photo_NN album_NN with_IN pictures_NNS of_IN our_PRP$ first_JJ own_JJ apartment_NN ,_, which_WDT was_VBD in_IN 81234_CD Munich_NNP ._. As_IN a_DT young_JJ married_JJ couple_NN ,_, we_PRP did_VBD not_RB have_VB enough_JJ money_NN to_TO afford_VB a_DT bigger_JJR lodge_NN than_IN this_DT one_CD in_IN Blumenweg_NNP 1_CD ._. But_CC only_RB five_CD years_NNS later_RB ,_, my_PRP$ husband_NN was_VBD offered_VBN a_DT well-payed_JJ job_NN in_IN 17818_CD Hamburg_NNP ,_, so_IN we_PRP moved_VBD there_RB ._. Since_IN then_RB ,_, our_PRP$ guests_NNS have_VBP to_TO ring_VB at_IN Veilchenstra§e_NNP 11_CD if_IN they_PRP want_VBP to_TO visit_VB us_PRP ,_, Luise_NNP and_CC George_NNP Bauer_NNP ._. I_PRP read_VBD your_PRP$ help-wanted_JJ ad_NN with_IN great_JJ attention_NN ._. I_PRP 'm_VBP a_DT student_NN of_IN informatics_NNS ,_, 6th_JJ semester,_NN and_CC I_PRP 'm_VBP very_RB interested_VBN in_IN your_PRP$ part-time_JJ job_NN offer_NN ._. I_PRP have_VBP a_DT competent_JJ knowledge_NN of_IN programming_NN and_CC foreign_JJ languages_NNS ,_, like_IN French_JJ and_CC Italian_JJ ._. I_PRP 'm_VBP looking_VBG forward_RB to_TO your_PRP$ reply_NN ._. Alisa_NNP Fernandes_NNP ,_, a_DT tourist_NN from_IN Spain_NNP ,_, went_VBD to_TO the_DT reception_NN desk_NN of_IN the_DT famous_JJ Highfly-Hotel_NNP in_IN 30303_CD Berlin_NNP ._. As_IN she_PRP felt_VBD quite_RB homesick_JJ ,_, she_PRP asked_VBD the_DT staff_NN if_IN they_PRP knew_VBD a_DT good_JJ Spanish_JJ restaurant_NN in_IN Berlin_NNP ._. The_DT concierge_NN told_VBD her_PRP to_TO go_VB to_TO the_DT "Tapasbar"_NN in_IN Chesterstr._NNP 2_CD ._. Alisa_NNP appreciated_VBD the_DT hint_NN and_CC enjoyed_VBD a_DT delicious_JJ traditional_JJ meal_NN ._. An_DT old_JJ friend_NN from_IN France_NNP is_VBZ currently_RB travelling_VBG around_IN Europe_NNP ._. Yesterday_NN ,_, she_PRP arrived_VBD in_IN Berlin_NNP and_CC we_PRP met_VBD up_RP spontaneously_RB ._. She_PRP wanted_VBD me_PRP to_TO show_VB her_PRP some_DT famous_JJ sights_NNS ,_, like_IN the_DT Brandenburger_NNP Tor_NNP and_CC the_DT Reichstag_NNP ._. But_CC it_PRP was_VBD not_RB easy_JJ to_TO meet_VB up_RP in_IN the_DT city_NN because_IN she_PRP hardly_RB knows_VBZ any_DT streetname_NN or_CC building_NN ._. So_IN I_PRP proposed_VBD to_TO meet_VB at_IN a_DT quite_RB local_JJ point:_NN the_DT cafŽ_NN "Daily's"_NN in_IN Unter-den-Linden_NNP 18,_CD 30291_CD Berlin_NNP ._. It_PRP is_VBZ five_CD minutes_NNS away_RB from_IN the_DT underground_JJ station_NN "Westbad"_NN ._. She_PRP found_VBD it_PRP instantly_RB and_CC we_PRP spent_VBD a_DT great_JJ day_NN in_IN the_DT capital_NN ._. Where_WRB did_VBD you_PRP get_VB those_DT great_JJ shoes_NNS ?_. They_PRP look_VBP amazing_JJ ,_, I_PRP love_VBP the_DT colour_NN ._. Are_VBP they_PRP made_VBN of_IN leather_NN ?_. No,_NNP that_DT 's_VBZ faked_VBN ._. But_CC anyway_RB ,_, I_PRP like_VBP them_PRP too_RB ._. I_PRP got_VBD them_PRP from_IN Hamburg._NNP Do_VBP not_RB you_PRP know_VB the_DT famous_JJ shop_NN in_IN Veilchenstra§e_NNP ?_. It_PRP 's_VBZ called_VBN "Twentytwo"_NNP ._. I_PRP 've_VBP never_RB heard_VBN of_IN that_DT before_RB ._. Could_MD you_PRP give_VB me_PRP the_DT complete_JJ address_NN ?_. Sure_JJ ,_, it_PRP 's_VBZ in_IN Veilchenstra§e_NNP 12_CD ,_, in_IN 78181_CD Hamburg_NNP ._. I_PRP deem_VBP it_PRP best_RB to_TO write_VB a_DT letter_NN to_TO the_DT owner_NN if_IN the_DT shoes_NNS are_VBP still_RB available_JJ ._. His_PRP$ name_NN is_VBZ Gerhard_NNP Fritsch_NNP ._. Hi_UH ,_, am_VBP I_PRP talking_VBG to_TO the_DT inquiries_NNS ?_. My_PRP$ name_NN is_VBZ Mike_NNP Sander_NNP and_CC I_PRP 'd_MD like_VB to_TO know_VB if_IN it_PRP is_VBZ possible_JJ to_TO get_VB information_NN about_IN an_DT address_NN if_IN I_PRP merely_RB know_VBP the_DT name_NN and_CC the_DT phone_NN number_NN of_IN a_DT person_NN !_. How_WRB is_VBZ he_PRP or_CC she_PRP called_VBD ?_. His_PRP$ name_NN is_VBZ Stefan_NNP Miller_NNP and_CC his_PRP$ number_NN is_VBZ the_DT 030/827234_CD ._. I'll_NNP have_VBP a_DT look_NN in_IN the_DT computer..._NN I_PRP found_VBD a_DT Stefan_NNP Miller_NNP who_WP lives_VBZ in_IN Leipzig._NNP Is_VBZ that_DT right_NN ?_. Yes_UH ,_, it_PRP definitely_RB is_VBZ ._. So_RB Stefan_NNP Miller_NNP lives_VBZ in_IN Heinrich-Heine-Stra§e_NNP 112_CD ,_, in_IN 20193_CD Leipzig_NNP ._. Thank_VB you_PRP very_RB much_RB for_IN the_DT information_NN ._. Bye_NNP !_. On_IN July_NNP 14_CD ,_, the_DT father_NN of_IN a_DT family_NN got_VBD painfully_RB injured_VBN after_IN he_PRP had_VBD tried_VBN to_TO start_VB a_DT barbecue_NN ._. The_DT flaring_VBG flames_NNS burnt_VBP instantly_RB through_IN his_PRP$ jacket_NN ,_, which_WDT he_PRP managed_VBD to_TO pull_VB off_RP last-minute_JJ ._. Although_IN the_DT wounds_NNS were_VBD n't_RB life-threatening_JJ ,_, it_PRP was_VBD urgent_JJ to_TO bring_VB him_PRP directly_RB into_IN ambulance_NN ._. But_CC the_DT only_JJ hospital_NN that_WDT had_VBD opened_VBN that_IN Sunday_NNP was_VBD the_DT Paracelsus_NNP Hospital_NNP in_IN 83939_CD Weilheim_NNP ,_, which_WDT was_VBD 2_CD hours_NNS away_RB ._. Convulsed_JJ with_IN pain_NN ,_, the_DT man_NN finally_RB arrived_VBD in_IN Stifterstra§e_NNP 15_CD ,_, where_WRB the_DT personal_NN immediately_RB took_VBD care_NN of_IN him_PRP ._. Last_JJ year_NN ,_, I_PRP worked_VBD as_IN a_DT delivery_NN boy_NN for_IN a_DT small_JJ local_JJ magazine_NN ._. I_PRP worked_VBD in_IN the_DT area_NN of_IN 83454_CD Ottobrunn_NNP ._. I_PRP had_VBD a_DT list_NN with_IN the_DT home_NN addresses_NNS of_IN our_PRP$ costumers_NNS whom_WP I_PRP brought_VBD their_PRP$ papers_NNS once_RB a_DT week_NN ._. An_DT elderly_JJ lady_NN ,_, who_WP was_VBD called_VBN Elenor_NNP Meier_NNP ,_, lived_VBD in_IN GŠrtnerweg_NNP 6_CD ,_, and_CC I_PRP always_RB drove_VBD there_RB first_RB ,_, because_IN I_PRP liked_VBD her_PRP the_DT most_JJS ._. Afterwards_RB ,_, I_PRP went_VBD to_TO a_DT student_NN ,_, Gina_NNP Schneider_NNP ,_, who_WP lived_VBD still_RB in_IN her_PRP$ parent's_NNS house_NN in_IN GŠrtnerweg_NNP 25_CD ._. The_DT last_JJ in_IN line_NN was_VBD the_DT retired_JJ teacher_NN Bruno_NNP Schulz_NNP in_IN Dramenstra§e_NNP 15_CD ._. He_PRP was_VBD friendly_JJ enough_RB to_TO tip_VB sometimes_RB ._. Our_PRP$ business_NN company_NN was_VBD founded_VBN in_IN 1912_CD by_IN the_DT singer_NN and_CC entertainer_NN Michel_NNP Seile_NNP ._. He_PRP opened_VBD the_DT first_JJ agency_NN in_IN Erding_NNP ,_, a_DT small_JJ town_NN near_IN Munich_NNP ._. Now_RB ,_, more_JJR than_IN 90_CD years_NNS of_IN turbulent_JJ ups_NNS and_CC downs_NNS later_RB ,_, we_PRP finally_RB decided_VBD to_TO situate_VB our_PRP$ company_NN in_IN a_DT more_JJR central_JJ and_CC frequented_JJ area_NN ._. Last_JJ year_NN ,_, we_PRP moved_VBD into_IN an_DT empty_JJ factory_NN building_NN in_IN 30303_CD Berlin_NNP ._. It_PRP is_VBZ located_VBN in_IN Barmerstr._NNP 34_CD ._. When_WRB George_NNP Miller_NNP ,_, a_DT tourist_NN from_IN England_NNP ,_, came_VBD to_TO Munich_NNP ,_, he_PRP had_VBD no_DT idea_NN how_WRB to_TO read_VB the_DT city_NN maps_NNS ._. He_PRP depended_VBD completely_RB on_IN the_DT help_NN and_CC information_NN of_IN German_JJ pedestrians_NNS ._. One_CD day_NN ,_, he_PRP simply_RB could_MD not_RB find_VB the_DT famous_JJ Lenbachhaus_NNP ._. So_RB he_PRP asked_VBD a_DT young_JJ woman_NN for_IN help_NN ._. She_PRP pointed_VBD at_IN a_DT street_NN sign_NN and_CC explained_VBD to_TO him_PRP that_IN he_PRP 'd_MD find_VB the_DT Lenbachhaus_NNP in_IN Luisenstra§e_NNP 33_CD ,_, which_WDT is_VBZ in_IN 80333_CD Munich_NNP ._. Miller_NNP was_VBD very_RB grateful_JJ and_CC could_MD finally_RB enjoy_VB the_DT exhibition_NN ._. On_IN March_NNP 15_CD ,_, there_EX was_VBD an_DT accident_NN near_IN Munich_NNP ._. The_DT driver_NN got_VBD badly_RB injured_VBN ._. Driving_VBG alone_RB not_RB far_RB from_IN her_PRP$ home_NN ,_, the_DT middle-aged_JJ woman_NN crashed_VBD at_IN high_JJ speed_NN into_IN a_DT tree_NN ._. A_DT resident_NN ,_, who_WP lives_VBZ near_IN the_DT street_NN where_WRB the_DT accident_NN took_VBD place_NN ,_, called_VBN instantly_RB the_DT police_NN ._. He_PRP reported_VBD what_WP had_VBD happened_VBN and_CC gave_VBD his_PRP$ name_NN and_CC address_NN to_TO the_DT officer_NN ._. He_PRP 's_VBZ called_VBN Peter_NNP Schubert_NNP and_CC he_PRP lives_VBZ at_IN Max-Lšw-Stra§e_NNP 13_CD in_IN 84630_CD Gauting_NNP ._. The_DT police_NN arrived_VBD ten_CD minutes_NNS later_RB and_CC brought_VBD the_DT woman_NN into_IN hospital_NN ._. Although_IN she_PRP had_VBD multiple_JJ trauma_NN ,_, she_PRP 's_VBZ out_IN of_IN mortal_JJ danger_NN ._. Hi_NNP ,_, how_WRB are_VBP you_PRP ?_. Are_VBP nt't_RB you_PRP a_DT friend_NN of_IN Natalie_NNP ?_. Yeah_UH for_IN sure_JJ ._. How_WRB did_VBD you_PRP know_VB that_DT ?_. I_PRP saw_VBD you_PRP sitting_VBG next_JJ to_TO her_PRP at_IN uni_JJ ._. Yeah_NNP she_PRP 's_VBZ my_PRP$ best_JJS friend_NN ._. Are_VBP you_PRP going_VBG to_TO her_PRP party_NN next_JJ friday_NN ?_. Oh_UH yes_UH ,_, I_PRP 'd_MD really_RB like_VB to_TO ._. But_CC in_IN fact_NN I_PRP do_VBP n't_RB know_VB yet_RB where_WRB it_PRP takes_VBZ place_NN ._. I_PRP can_MD tell_VB you_PRP :_: ring_NN at_IN Baumann,_NNP Meisenstra§e_NNP 5_CD ,_, in_IN 81737_CD Munich_NNP ._. The_DT party_NN starts_VBZ at_IN 9_CD p.m._NN ._. I_PRP hope_VBP you_PRP 'll_MD find_VB it_PRP ._. Thank_VB you_PRP very_RB much_RB ,_, see_VBP you_PRP next_JJ friday_NN !_. My_PRP$ name_NN is_VBZ Michael_NNP Hinterhofer_NNP ._. When_WRB I_PRP was_VBD 21_CD ,_, I_PRP moved_VBD out_RP from_IN my_PRP$ parents_NNS home_NN into_IN my_PRP$ first_JJ own_JJ appartment_NN in_IN order_NN to_TO study_VB in_IN a_DT bigger_JJR city_NN ._. My_PRP$ new_JJ home_NN was_VBD in_IN Lilienstra§e_NNP 1_CD in_IN 25334_CD Hamburg_NNP ._. But_CC I_PRP realized_VBD quickly_RB that_IN life_NN in_IN a_DT metropolis_NN was_VBD n't_RB relaxed_VBN enough_RB for_IN me_PRP ._. So_IN I_PRP decided_VBD to_TO move_VB into_IN a_DT smaller_JJR town_NN ._. Now_RB I_PRP 'm_VBP a_DT tenant_NN with_IN an_DT elderly_JJ widow_NN ._. We_PRP live_VBP in_IN BŸrgerstra§e_NNP 2_CD in_IN 63737_CD Heidelberg_NNP ._. I_PRP really_RB like_IN the_DT smalltown_JJ flair_NN and_CC my_PRP$ studies_NNS at_IN Heidelberg_NNP 's_POS notable_JJ university_NN ._.apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/resources/dictionaryLocaleSafety.info0100644 0000000 0000000 00000000757 15217274217 033642 0ustar00rootroot0000000 0000000 # # REQUIRED PROPERTIES # # Column (lemma, inflected, tag) separator. This must be a single byte in the target encoding. fsa.dict.separator=, # The charset in which the input is encoded. UTF-8 is strongly recommended. fsa.dict.encoding=UTF-8 # The type of lemma-inflected form encoding compression that precedes automaton # construction. Allowed values: [suffix, infix, prefix, none]. # Details are in Daciuk's paper and in the code. # Leave at 'prefix' if not sure. fsa.dict.encoder=prefix apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/resources/dictionaryLocaleSafety.txt0100644 0000000 0000000 00000000052 15217274217 033512 0ustar00rootroot0000000 0000000 Illinois,illinois,PROP index,indices,NOUN apache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/resources/dictionaryWithLemma.dict0100644 0000000 0000000 00000000337 15217274217 033140 0ustar00rootroot0000000 0000000 \fsa_+^Cc€f¨meninapioÐão,ADo,NOUN,AAznho,AEj,ABjoi,AHCAr,VDsearØsaÈi`ona,ADaznha,AEJ,ˆr,AA,V-INFAA,ˆr"roÒasa,AA,PROPapache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/resources/dictionaryWithLemma.info0100644 0000000 0000000 00000000756 15217274217 033155 0ustar00rootroot0000000 0000000 # # REQUIRED PROPERTIES # # Column (lemma, inflected, tag) separator. This must be a single byte in the target encoding. fsa.dict.separator=, # The charset in which the input is encoded. UTF-8 is strongly recommended. fsa.dict.encoding=UTF-8 # The type of lemma-inflected form encoding compression that precedes automaton # construction. Allowed values: [suffix, infix, prefix, none]. # Details are in Daciuk's paper and in the code. # Leave at 'prefix' if not sure. fsa.dict.encoder=prefixapache-opennlp-2.5.12-src/opennlp-morfologik-addon/src/test/resources/dictionaryWithLemma.txt0100644 0000000 0000000 00000000325 15217274217 033031 0ustar00rootroot0000000 0000000 carro,carro,NOUN casa,casa,NOUN Casa,Casa,PROP casa,casinha,NOUN casa,casona,NOUN casar,casa,V casar,casar,V-INF ir,foi,V menino,menina,NOUN menino,menininho,NOUN menino,menino,NOUN menino,meninão,NOUN ser,foi,V apache-opennlp-2.5.12-src/opennlp-tools/bin/opennlp0100755 0000000 0000000 00000001615 15217274217 022614 0ustar00rootroot0000000 0000000 #!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. mvn -e -q exec:java "-Dexec.mainClass=opennlp.tools.cmdline.CLI" "-Dexec.args=$*" apache-opennlp-2.5.12-src/opennlp-tools/bin/opennlp.bat0100644 0000000 0000000 00000001747 15217274217 023364 0ustar00rootroot0000000 0000000 @ECHO OFF REM # Licensed to the Apache Software Foundation (ASF) under one REM # or more contributor license agreements. See the NOTICE file REM # distributed with this work for additional information REM # regarding copyright ownership. The ASF licenses this file REM # to you under the Apache License, Version 2.0 (the REM # "License"); you may not use this file except in compliance REM # with the License. You may obtain a copy of the License at REM # REM # http://www.apache.org/licenses/LICENSE-2.0 REM # REM # Unless required by applicable law or agreed to in writing, REM # software distributed under the License is distributed on an REM # REM # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY REM # KIND, either express or implied. See the License for the REM # specific language governing permissions and limitations REM # under the License. mvn -e -q exec:java "-Dexec.mainClass=opennlp.tools.cmdline.CLI" "-Dexec.args=%*" apache-opennlp-2.5.12-src/opennlp-tools/lang/de/abb_DE.xml0100644 0000000 0000000 00000025570 15217274217 023600 0ustar00rootroot0000000 0000000  östl. AB-Whg. Abl. Abs. Anm. Aufl. Ausf. Bd. Best.-Nr. Bio. Bj. Blk. Bsp. Dipl.-Ing. Eigent.-Whg. Eigent.-Whgn. Eigt.-Whg. Eigt.-Whgn. Fr. Gal. Gart.ant. Grd. Grdst. H. Hdt. Hr. Hrsg. Jahrh. Jg. Jh. Kl.-Whg. Kl.-Whgn. Mais.-Whg. Mais.-Whgn. Md. Mio. Mrd. MwSt. N cont. NB-Whg. Nb.-Whg. Nb.-Whgn. Nfl. Nordd. Nr. Pak. Prov. Südd. S. Sout. Str. Tsd. Wdh. Wg.Whg. Whgn. Zi. Ziegelbauw. Ztr.-Hzg. Ztrhzg. Zw.-Whg. Zw.-Whgn. a.a.O. abzgl. afrz. ahd. b. bezugsf. bibl. bspw. bzgl. bzw. c. d. h. d.h. dgl. dt. ev. e.V. e. V. ebd. ebda. ehem. engl. ff. frühnhd. freist. frz. geb. gestr. ggf. grds. griech. hd. hl. i. d. R. i.G. i.d.R. i.e.S. kath. lat. lt. möbl. mfrz. mhd. mnl. näml. nördl. n. Chr. n.Chr. n.V. nhd. nl. o.Ä. o.ä. o. Ä. o. ä. o. g. o.g. röm.-kath. rd. ren. ren.bed. rest. südl. südnl. s. d. s. o. s. u. s.d. s.o. s.u. san. spätmnl. u. u. a. u.a. USt-IdNr. usw. v. Chr. v. a. v.Chr. v.a. vgl. westl. wg. z. B. z. T. z.B. z.T. zz. zzgl. zzt. B. a. B. A. B. eng. B. Eng. B. sc. B. Sc. M. a. M. A. M. eng. M. Eng. M. sc. M. Sc. Mag. iur. Dipl.med. Dipl. med. Dipl.-Med. Dipl.biol. Dipl. biol. Dipl.-Biol. Dipl.chem. Dipl. chem. Dipl.-Chem. Dipl.kff. Dipl. Kff. Dipl.-Kff. Dipl.kfm. Dipl. Kfm. Dipl.-Kfm. Dipl.math. Dipl. math. Dipl.-Math. Dipl.inf. Dipl.-Inf. Dipl.-Inform. Dipl.-Inform. Med. Dipl.ing. Dipl. ing. Dipl.-Ing. Dipl.phys. Dipl. phys. Dipl.-Phys. Dipl. rer. oec. Dipl. rer. pol. Dr. h. c. Dr. h.c. Dr.-Ing. Dr. Ing. Dr. iur. Dr. med. Dr.med. Dr. med. dent. Dr.phil. Dr. phil. Dr. rer. nat. Dr. sc. hum. Dr. sc. Hum. Dr. Prof.Dr. Prof. Dr. Prof. Dr. med. Prof.Dr.med. Prof. Dr.med. Prof. Dr.-Ing. apache-opennlp-2.5.12-src/opennlp-tools/lang/de/namefinder/de-namefinder.xml0100644 0000000 0000000 00000002474 15217274217 027310 0ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/de/namefinder/fg-conll03-deu.xml0100644 0000000 0000000 00000002623 15217274217 027225 0ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/namefinder/en-namefinder.xml0100644 0000000 0000000 00000002277 15217274217 027335 0ustar00rootroot0000000 0000000 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/parser/en-head_rules0100644 0000000 0000000 00000001352 15217274217 025716 0ustar00rootroot0000000 0000000 20 ADJP 0 NNS QP NN $ ADVP JJ VBN VBG ADJP JJR NP JJS DT FW RBR RBS SBAR RB 15 ADVP 1 RB RBR RBS FW ADVP TO CD JJR JJ IN NP JJS NN 5 CONJP 1 CC RB IN 2 FRAG 1 2 INTJ 0 4 LST 1 LS : 19 NAC 0 NN NNS NNP NNPS NP NAC EX $ CD QP PRP VBG JJ JJS JJR ADJP FW 8 PP 1 IN TO VBG VBN RP FW 2 PRN 1 3 PRT 1 RP 14 QP 0 $ IN NNS NN JJ RB DT CD NCD QP JJR JJS 7 RRC 1 VP NP ADVP ADJP PP 10 S 0 TO IN VP S SBAR ADJP UCP NP 13 SBAR 0 WHNP WHPP WHADVP WHADJP IN DT S SQ SINV SBAR FRAG 7 SBARQ 0 SQ S SINV SBARQ FRAG 12 SINV 0 VBZ VBD VBP VB MD VP S SINV ADJP NP 9 SQ 0 VBZ VBD VBP VB MD VP SQ 2 UCP 1 15 VP 1 TO VBD VBN MD VBZ VB VBG VBP VP ADJP NN NNS NP 6 WHADJP 0 CC WRB JJ ADJP 4 WHADVP 1 CC WRB 8 WHNP 0 WDT WP WP$ WHADJP WHPP WHNP 5 WHPP 1 IN TO FW 2 X 1 apache-opennlp-2.5.12-src/opennlp-tools/lang/en/postag/en-tagdict.xml0100644 0000000 0000000 00003165414 15217274217 026037 0ustar00rootroot0000000 0000000 brave wishful Cabrera indignation champions liquidated computer-driven jet Wrap " # Ministry ! timed & brawl ' stressing $ % answer possibly sleeve ( ) . rushing Sandra , - 3 2 H&R 1 7 6 5 4 constructive ; payments : 9 Burnham 8 ? retiring D relies plummeting clouded E A chairs B C rejection M N ignorance O H I drawing K relief elephants relied U advised inefficient times S R darkened Y Roosevelt Z grotesque f Omni termed formally e b Fed c confused ` slated a airborne n consultant o cutting Options Lehman analyze advocates s safeguard Few invaded basis Fournier consumption holster drop infant entity futility Merksamer Asahi estimated basic jar civilian composition affectionate derived jam fathers guilt dozens unrest belongs advises resist adviser timid jaw much Monte weary ENERGY column fewer wears brass update Enserch small-town grapevine Paula suspicions spectators possible ruthless shrugged conspicuously Pravda reached spends Trouble Minnesota Sagan estimates Airways injection universally Mastergate magnitude minimize shadows hospitals reaches entire which royal anyone Production suspicious Institutional consolidated Eye hasty folklore last-minute two-day haste vans visually Economics modernized tolerance discrepancy write-off Abramson interpreted job Third-quarter resign dominion asserting hamburger shoulders interpreter regular-season uniforms muse assistance joy explicitly counties thought space Harper boys rather Citicorp discriminatory construction dingy aimed responding Blockbuster helps Connecticut psychologist Swiss recall Norway warning pencils manufacturing single formulate 9.80 reluctantly proposition Phoenix Really NEWS inserted muscles fumes Tell sleepy Pretoria analyst diversifying contract Spielvogel Bonner plunging Jarrodsville GAF vain Iron gaming deployed defensive Kozinski prisoner while one-day shoreline drum reinstated disagreement jeopardize drug cyclist answering Tommy Fat repercussions instrument pervasive Automatic whipped Far adversary 9.75 fought scientific nearing 2,000 Swedish advance forbidden sugar speculate swivel its teachers strangled although Thursday FTC Era bosses throat October terribly Boulevard Coleman admirable prey Grabski loaded McBride Mexico terrible thirty-five advocate abolish machinery press minimum dimly Holland Automated iron Datapoint graduation absolute Szolds worrisome Money builds contrary Dillon armored rates emergence Mather assignment reformer disobedience invested rated Honda Upon emergency Married requiring shoved must columnist friends unwilling curious Toseland subsequently churchyard Adelia Gloucester Eve marshal mute cherished Banxquote spare spark Advisory vary rumor lightning Prebon railway desirable argued stereo unlikely maximize oldest Aska walking argues dominance deviation garment Nonetheless all-time Girl Once joyous vast accidental Scott unfriendly beneath advantages D'Arcy helped newsprint Bundesbank prohibited Sherlock executives Hubbard giant gloomy G-7 pinpoint everything zero draw yourself Asia working compelling attracted attracts leaning outset matters Armenian Interpublic Wyoming displayed visual Eugene hallway ranking dance culture Tuxapoka placement Goodyear backward operates interbank Give complexity operated evidenced bluntly straighten accelerating Stalinist resolve drag prop Confederate pros Henrietta verbal amended fixing spate brother End succeeding restrictions purse Frayne Gillett connected acceleration trumpet Remember patent bicycle stalls contrast possessed Asea FOR drew sure Only wants populist hearing Emerson batch Zeta Eli golden characters dissolve carry-forward collapsing Operations Ridley nests interfere officers finding glass making resumed judiciary lung-cancer Container certificates philosophers ultimately chains unnecessarily century packaged-goods glare addition enacted Section weights target McCarthy furious Keith brewer pillar Fleet visions thumbs Apparently jeopardy Bush Kinder-Care Afghanistan wait briefing Cross kid Mengistu Patel Whittington Louis Shell Gorky stance black seizing limits Californians confirms awoke convention demonstrated vulnerable snakes mounts Farmers impress endangered lobbied owners discovery deserve flashed disappointing Bethlehem wage midday restructuring flashes extraordinarily Frankly sunk weighed sung hottest Cherokee whatsoever boat Stubblefield shipbuilding antitrust amazing Aug. sums forever speeches stands Chevy nothing time-honored Get construct comments Opponents Jeffrey body Cheney edition Taiwan rocked straightened blacks Alberta violently rocket key Borden coup wallpaper '' Crowd eager Chandler script Agnos cheekbones Crown oral imitation buy-outs containing lightweight disclosed meetings walk wall ignored barge Mead Shere HK$ Dover U.S.A chlorofluorocarbons whipping enhance organization wake touched demonstrates artist Indianapolis stems counseling Morristown audio communication singers touches funny audit temblor cows Buzz amendments bitterly wedding suit laying disabled disposed parking halted confirmed Maxicare deliver dough premises combine Meeting rented exercising beleaguered steps stripes exceeded emotion Ga. disarray funds snatched vulnerability obligated 'd pictures DEPOSIT followed Pension chuckled insistent neighboring 'S Karen striped compelled clinical jacket usual 30,000 larger stern Cineplex snapping succeeds sued 's company-owned Fulton -RCB- within Nebraska 'm equity Warner surpluses middle results gather trials barefoot gripes appropriate such doubt controlled suck openings offering rental league relative Vermont textile whichever emerging bridge controller HBO whooping equivalent recalled erosion investor conjunction busted adverse episodes Beech sends swept immensely generator indifferent treated giants exhibition skipping Gas reception -- duration loosen Elliott revolutionary barns occupy English-language guide fight redeem Environmental 35 36 33 34 39 37 occurs 38 turning showed danced imperative staring intervened 43 Gabriel 42 Itel 41 depreciation 40 stamps opportunities erased brain dancer turn severance homogeneous dances questioned billionaire 22 turf 23 organized 24 25 26 27 28 29 upheld Buck 30 afraid 32 crime 31 FileNet shower twelve ways born figuring 19 bore 17 18 Amdura 15 16 consequently battered 13 14 11 probes 12 21 20 allegations figure 20,000 Developments Evans pinned bricks rounded proceeded erect boss predicted Lotus 4\/32 seller Schneider 10 dashed Robins plots Gillette half-hour mixture hormone relating 79 recording 78 77 both Beefeater unreal Researchers 82 83 80 81 timing 86 siphoned 87 barometer 84 Current 85 67 expedition 66 schoolhouse 69 high-quality 68 association generates labels relation white bout Honolulu properly generated bursts 70 71 72 73 74 75 pigment 76 omnibus Moody cries 59 ambulance 58 57 antibody 56 55 singer engineering insolvent cooperate republics vanished Mushkat brace sailed allocation 64 65 ballooning 62 fearful 63 severe accent 60 61 glaring Minister popularity 49 bowl 48 ethnic crucial 45 deliberations 44 Realty 47 46 descent plainly discovering beaten 51 52 53 54 Chrysler relish masters tight eyebrows 50 elders malice accept bases kidnapped Sacramento ancient typewriter GOP 12-month sales intimate expectations STORES prizes considers real-estate speaking Immunex Geneva wishes Highland mortgage prized boil Isler researcher conveniently traced ward GNP wished flattened Hoag Viacom special-interest Fla traces Patent rarely Leona latter sailing disposal Pacific length boiler 99 want Teddy 98 hence peasants steak 97 listeners steal entertained 96 95 94 crisp 93 Foster 92 Congress 91 dedication 90 restricted access Johnson wholly fluctuations pullout patrolman brand Moore Troop 88 hates based 89 steam bolt Products hated Beers shocked compliance Cousin 45-year-old supercomputer GTE incidents witnesses bold OPEC sliding linked custom excesses thrown succeed implication tailspin throws Putting campaigns property advising sense staying witnessed withheld controversial hooked Adler blades indebted loan-loss bulls Salomon bomb revolving responsibilities wave hatch feelings friend Burt warn stop warm orchestra bony wart stocks pretty wars reared bond jetliner rejecting cunning wary bone laborers wash For Fox bono marine boot mistake immoral matter locally Visitors Udall thumping Bruckner steep Children steel rules ruled Ahmanson squarely observe discoveries steer book boom boon Schroders ranchers unloading Consultants seasonal IMA bright Da EC awareness warehouse leaked E. Co Barclay systematic objects hungry these intelligence defenses Ed Lorenzo Du astonished Do F. aspect steering opening bitter De Di IMF Ernie GE Fe scandal rival refrain aviation authority G. El FM ascending dating marriages chamber Place define stir Ga Nucor slaves morning enthusiasts implicated GM H. shooting circuits ham Hold broadcast Colo. has Certainly hat Kelly A$ component tourists adjoining A. had bushels climate stampede processes Probably Home monitor spectrum Fiske Stuart Wash. Holy processed Holt AB AG hay assumptions congressman III Windsor AM B. Sweden AN Aw At As Janice tested municipals immediacy Ah controversy C$ Ad Am An stubborn tonight locate Donoghue activity C. Al music sites By His ammunition clenched CS Ca viewed tracks Europeans Gradually authorize therefore never Be there CD approaching Schaeffer D. Him eternal motionless damaged govern somehow package M. traversed diverted Mutual calculation nagging gatherings authenticity Hope assault doctors her voluntary Leonard hen hem La Electronic transfer Gould pediatric activist batteries N. canyon pointed Ernst establishing 7.875 Color Me sensible damages spawned O. Church compensate Ma Daniel Md lands Benefit Council My IFI emeritus Giles Mr P. OK subscribe unless Manville Says OF feminine mega-issues hierarchy airline Catatonia Hong stay gallery star defied pretax appearances No retains forties 25,000 On preserving Oh Hey Hez insights Sabella efficiency Of stag calculating Methodist PC Her marital interior hid I. wisdom Go conceived him type retailer motions Issues his Massachusetts hit practically primary Marcos portrayal medicine IG He II onto staffers approve J. RU-486 IN locking pleasure sovereignty printing cheerfully Afghan owned dinner Network owner translations genetically If Perspective peninsula In K. Called goods reassessment scaring bruises Is It politician effectiveness arrest IBM Mesa three-quarters Jo annual L. legislators agreement Horn Had modify noses Jr Hal M$ abortion moderately night stem step Up giveaway winked editorial-page W. countries Metropolitan Merc full-year pro-choice monstrous submarine Shakespeare Rising awfully responsibility US Gyp V. Berlin revenues To churches modifications directives demon neighborhoods cocked incest portrayed unauthorized appraisal TW TV theft god organizing contradictions Norton messages We trustees dresses substantially depending Analytical Military liberalism futures-related editions Jewish complicity dressed wedge Barber aliens optimism repeated Va grabbed weep challenge Sara lighting reckless unaware Syrian down slackened week Drabinsky proportion demons Chicken climbed S. Former Gun Palfrey scandals surfaced Guy clobbered rebel heightened imagine Pa meaningless Scorpio dividend Hospital economy Albert possibility tumble R. Agnelli Suddenly thinner bestowed outflows PS Or gon totaled 19th-century got Oy gracefully Oxford dose struck So \*\* slashed initially collector SS Somewhere Cunningham ousted feminist uncertainty formation sounds Re Plant Plans tricky Saul tricks Surely moreover regret T. mattered defects Chicago-based immediate furnished devised learned ordered sensory actual weak wear involvement architects Wharton extensions Valentine lamps initiate gum shadow Plaza fifty planetary Tomlin Saint chopping stepping Saks Rachel alcohol backed Lippens congressmen mediator pharmaceutical stemmed wildcat switch Mehl establishes transport carpenter rationale refunding reporters IRAs artery jury just recordings fifth Handley guy theme blue-collar Shayne awaited gut established tossed contribute gun notions stockholders Overseas Commissioner Bermuda Said HUD swift despite Press discomfort attorneys looming Reinvestment preserve reproduce softening hovering scheduling vacancy unpopular totally Meet swing Leventhal shifts coaster jump objected smack Orkem Plato Montedison committees Got north two-part junk orderly traded aborted Tibet tariff snack-food trades trader acceptance DISCOUNT commissioned \* grandmother gambling flashing Same God commissioner fumbled their slogans river predicting Lang Lane dogs predictions said solemn Land noted college vehemently Saab personality lore syndicate references Georgian Deere childish solely chemical Irish sail detected concealing isolated Crandall portfolio harness featuring he confess Southerners resignations Fortune Australian Index Laos summoned Feb. singled keeping disrupted artificial murky go assessing taxpayer gift Fear servant financed indicate excellent de sustained shouts loot battery profit-taking Banks runaway do finances dangling prevented Ill look Jerry safe transfers violence wreck Richter Inc operator Advanced recovered newer en Firms notes et handsome Imo Unless gravely ca player lone by long wallet dock anti-Semitic installment Glory Harold FirstSouth Charleston liberal depends dignity be predicts establishment mysterious suppressor Fujitsu decided holiday Last played maximum nicknamed eloquent makers suggestion Office lighted collect Alexander does depress instituted skiing boast icy criminals edged Late foreign-currency Uniroyal lighter expects recommend statistics sack Fees edges ice directs `` members crap termination market-makers Gintel boats at as prediction leverage ax ai MONEY am privilege an cruelty ad mindless Hills growth newly Chairman Hendrik supreme 62.875 no makeup door forgotten California of realm Profits on oh legally 1,850 emissions maybe commitment or grower done cliff ox board trooper crossed delay small warfare wisely fastest catastrophes radiation squeezed CORP. Banco gradually crew Mercer necessity carefree fairness Water Fazio conservatism me twisting backup seventeen appreciation Bronfman collected vague Salinas my masterpiece malignant Yetnikoff bankers lows na teaching specified route Poland Arizona item Vince Giuliani Private technology cousin scooted India variations love warns high-definition eminent raped perfectly underscore conservatives Arts everywhere lots Lower remembering guarding Success ink stillness Saab-Scania loud endure la lightly lost loss catastrophic dome 1,800 microscope Minpeco Messiah Exchequer conservation if Mulford celebrate puck is it doll ill crib mimesis weakest rapid know in knot lose Recruit unfolds twenty Katie blue hostile continent strains Ian smart premiums Philippines JAL hearings pounding metropolitan arbitragers viable knew winner etc. ready Illuminating rhythms deficit-reduction Huxley aluminum BankAmerica Stowey slack knee outraged Marcus Scenario how expiration wo law-enforcement cling rendered loan reads pure Environmentalism hot load Pauling we climb busiest give events Lebanon restructure Summer brought havoc shrieked Johnny downside Mansion Block puny solitary voluntarily consciousness front us Israeli weeks up field peering Ariz pistol departures high-tech impressive Thornburgh to Iran affects v. chambre Army sipping pull round pulp hub messenger poorly inspection crop Iraq amount drained Willings conservative ta knit grinned so state-owned impression mysteries pump Globe providing openness counting Ronald birthday acknowledge ceramic 29\/32 strings appears Lady liberty reach tax-exempt implement bunch react System institution ladder provides Minn. provider suitors Elsinger knocking dilemma provided flooding Hague wrapped perpetual marching Hun sucking guardian applies insist Meeker energetic First self-employed Homes whether Remic Arab course open frightening Defense margin ignoring processor brothers broad-based Redmond EURODOLLARS Peabody delta Laff Hub redeemed associations adults contractors affidavits viewpoint Nigel objectivity cast-iron tomorrow courts wastes stricken contact Arby southern engage wasted portfolios Night Mingo Xtra suggesting Arco hum spear hut walked Lingus opponents mayor speak ITT haven evenly Nimitz appeals should Mutton stones decides grimly contended outpost Area determination Ashurst discouraging spilled butler Seattle puts yielded Lake contender Landry perpetuate IRS Mines rough producing disposable Cairo waterworks importance Jersey contain sensibilities babies yard Hot creatures prevailing beneficial mural clips push girl IRA froze attempts How Peugeot IPO ye ya urgent lock strategy refers nearest Nadine Blood motors gadgets applied menace poorer guarantee pushed mainframes discontinued Edwards president Are murmured chance Ark attraction bribery ceased 52-week distinction Depression competes attracting GATT few fee fed TransCanada grinning Philips ministers secondary undercut fraudulent visited token rhetoric GASB soybeans rivals enjoy Jesus Art ankles predict guess magical guest shorts crops having novels alarmed Harlem change Giants regulations distributed Europe capital expenses Brian i.e. witch Should distributes North negotiator retained fax fat wheels luck far repurchase fan borrow rural lacking confrontation delicate soaking discounted fad restored backbone misunderstood Chemicals Command underwater occasion education creativity Budget hotels Axa gradual Salvador Packwood-Roth methodically Greenwich homeowners FEMA furriers sensual Bahamas Kyle freeze inside venture Warsaw Demand diverse glow Machinists obvious errors Against limiting pressured Currently appealed medium-sized Judith doldrums Loral publications peddling silence echoed lender indeed recovering finest concentrating makeshift build dragged benign thinly FERC built identifying concentration formidable ethical Better NATIONAL pressures sending clergyman pilots thinks club improvement clue initiatives PepsiCo Seven topiary Crude endanger retreat stunned infamous obscure Program eye punch intellect occupation damage accusations Democracy Jesse Marion locks dissatisfied penny permits drastic fulfilling INTERBANK proudly shaking requirements curtains Bay Adobe distributor Combined Bar relevant subsidized Britain whining exceedingly into cereal reconciliation luxury schedule things Noriega embarrassing CBS professionals etc everyday ours blew sentiment Affairs workstations orgasm comprehensive Doris bundle feature expanded Clayton austerity 11\/32 descended backlog deferring gingerly glasses Clean tissue deferred likelihood adventure furnace high-grade dubious bridges foresee Marina Marine Gene Act Ada learning oust alter arguments Classic restricts stays upstairs quickly defaulted shores withdrawn Royal implicit Petco exported 55,000 unwarranted Consider Add nostalgia unhappy orange ducks explains devastation awhile Jacques Aer ceiling freely recalling exporter Sununu saddled Anything Flint reopen uproar Rudolph Age Aga shrinkage surrounded Peter era bandages Beaver precious unusual Medfield question devastating ensuing rugged multiple Manila adult freedoms Marketers appointment representative Healthcare originally foods effect ferry historical People glut lodge Mikey stallion expired nothin stare specially stark obscurity sacrifice expires represented boasted whereabouts wiser charitable continuous sewage singing again Air overhaul start stars satisfaction prize saving Census Wedtech propaganda cells Haskins Benton sacrifices Quebec techniques boulder start-up Publishers dared delegate Sheraton robbery upset aggressive end Nick options containers readily observation tremendously refrigerator represents Heights Canton Weston reading ego Democrats transaction 1.375 bolted aired BNL All egg terraces Calif. organs bidder School Tonkin forests achievement Amy E-mail Hawaiian persuaded injuries serene representation Lavelle Gen. surprising Ana And Any owning state Richmond credible Ann experiencing Amendment Florence landing designs leader tradition Netherlands blow defendants negotiated 11\/16 inch paused hard-line Inflation struggled traditions tides bloc Consumer vinegar struggles consulted Cicero specialty educate investment-grade benefit accompanies paradoxically threatening outspoken Kidder over bleak protein oven accompanied But Paper sprawling spokeswoman traveler psychological number overhang dumping gin contingency Being Dollar Whatever consisting arteries typically apartheid littered fille before adamant crashes double-decker traveled stake stairs Perhaps accommodate intervention leaking Arnold arises crashed FDIC Eichmann films Juan arrested BILLS provincial bolster hydrogen hardest Trelleborg clever Minerals banks invariably breed rocking stall in-house boundary close doctor facto Consulting facts oval occasionally get postal Atlanta efficacy draining exhausting Scotland Vecchio irresponsible gem stale Indians money-market carefully Otherwise safely Bergsma indictment households Hydro-Quebec Indiana discipline fraction practitioners purchasers Eisenhower Vinson accessories persons headquarters stand stomach sorrow DAF Bryant bands moderates buy-and-hold confines inception recorders impose Eileen hurling break operation DAX bread Mich pending Peasants eroding guarantees confined import central fetch screen Cilcorp Garryowen welfare flexible guaranteed Lucille include O'Kicki gas prime traffic sitting operating gay poster Unable crusade novel unseen gap talent protect addressing posted recover Princeton\/Newport walks handed Often witnessing flooded skeptics files clock quicker Venice flight billed walls Campeau Riegle Collins opted knuckles resemblance filed DEC location remains uncover Mission nursery procedures prior DES squeeze official DDB returning Coopers redcoat Planners projecting repairing machine dusk comparison Rafale statement Calgary-based pamphlets Warren employs dust stack Palace cotton Merrill projection stage Car staff Chase Can tax-loss duty able deciding Cap mounting mixed accessible receive application standard swaps 1,200 Coates print Juet Kravis rubles divergence handle Reuben slipped determines East stockade parental lure associate pride scrub danger defaults resistance FOREIGN regretted serve sweaters defined Milan instinct Bey neighborhood available declare Haney graveyard exalted Xerox Okay price Ben staggered Easy Fourth referring explosive threats Norberg Hopkins defer cursed pence CDL Banque fur caught notice resent Transmission stadiums CDs angle familiar lung rustling CEO Bally reclaim Kirby competitor automobiles faces Greece interviews Heaven takes faced varying taken conference overnight Straszheim reports charges victim fun charged Burgess receivers Dogtown angel Notes populations explosion Big anger passive Seidman Beijing Eventually Hines cigarette dump Robert photographs CIA inclination impulse dumb bitterness sticking Public threatened refrigerators dull lush high-school demonstration misunderstanding clocks vaudeville views determined timely journalism CNW for Richards angry swelled MIPS CO. Commodities clout distinct gifts legislator journalist glad information unstable fascinating guilty Mullins pretense occasional 'll carpeting hunger evil Hartford jumping Ginnie pleasantly ensuring updating effective wanted London dual Norwood D.C cloth pockets wired crashing stolen frequently purely CMS responsible diamonds extradition galvanized visitor emphasized proportions fog afternoons terminated Brewing foe cloud e.g. emphasizes Allianz lump Scottish reinsurance Jupiter answers fried Candlestick Flight buy-out misfortune please duck pleased wounds victims wires riskier restrict Mellon Estate parliamentary Reports fly roses even apprehensions passing evolved ever clay Yesterday dancing firing 'em Arbuckle fit Mills fix Bob notify announcements deduction Strategic pulled passion profit decade turban skepticism stains Box Boy families Dynamics Byrd clad Oklahoma safety Claire Ashland 2683.20 Greene propagandists horn brushed receivables hose parade Marxist Jerome Grandma reunification video opened thunder host notion contentious animation Previously neutral stationery extract slumping ratification bite Farm herself existed Pamela Kemper Blanche dependent chiefly Cohen Thank Barbara East-West wives senators noting Judges Below historians cartridge 1,500 increasing disasters hour meaning boosts bird A.C. totaling electronically undervalued public discounting raucous treatments bailout Software Milunovich sagged Brookings Emergency supply-side dramatically immunity notified lasted seemingly hook flames Faulkner motive releases Officer code Leaseway careers inspected insulting factors items determining secrets dam ARCO Cup factory day Businessland large hope Academy deteriorate misstated Each bill driveway blaze hops creator lights released coal Kennedy offset coat calendar Listen Hawaii welcomed Aquino portions folks acid A.G. bind engineers Torrijos cup Municipals reason Commodity otherwise Earl liquidation sufficient respond rotation sixth privatization unveiled sixty hold privacy EDT EDS regarding Nutritional openly sights neutrons recorder abstraction recorded ought pledge Bakes heading Baker Meyer Travel home non-recurring Angeles-based concludes holy Hogan savings quit goddamn retinoblastoma explaining thank Del prosecutors victories Deb drug-related probability hole portion satisfying peaceful articles dozen maneuvered guinea extraordinary secede Hirey Baldwin hypoglycemia pupil concluded cut stamping Sandinista installations midyear biwa Grumman acre intense HDTV honest potentially unrealistic multimillion-dollar Actually applications difficulties death-penalty Frank functioning spurring sectors kidding fronts arrive winter Anyone Clearly defeat Dan horses focusing resolution Day so-called Robards Tharp Dad bits cooperatives Nevada reinvestment depict palladium actively buildup Township registration arranging Reebok database Sierra abilities insists Stoltzman cops equipment cope Copper Times-Stock 7.60 obligations eyes interest Cie beset procedural Sitting copy barring cool cook lying adequate June Everyone 7.75 Rector models Olin Sisulu Kizzie breasts swear anonymity blade eyed deepest sweat Olga acts low-interest drunk foreseen Tandem 7.42 DLJ Armonk Paxton suits publish healing reckoning Wisconsin tubes landlord applicants Executive renewed lifetime pronounced Eddington Cigna 7.52 come comb Sikes drums Mips 7.50 7.51 practice belched July DNA high-yield 80486 defend con DFC debates 7.20 cop cow depository 7.25 faded scrambled nevertheless floors understood strengths retaining Small-business burned dressing Fraud Kenneth Coastal identities issuance 7.37 Publications Abbie period cost sweep Including Olympics fellows sweet reductions Anderson editorials profitability cork generate Speaking Mike 7.03 hurricane corn Farouk 8.375 roommate seven-day Conchita 7.10 hefty deductions chasing 1.125 coincidence secrecy Analysts sacred cry 7.15 Westwood emotionally Johnnie increase Beckett core Oppenheimer cord renewal airing greatcoat excessive suing Diego divisions house modest hostages fascinated avoid Delphine A.M. inexpensive unused blame Through setback strategies legislatures drugs energies hours slender Gen-Probe cushion scrap operational blinked goal measurements traveling nightmare detergent screens dislike Aunt Unix cents exemption funnel remove exploded Natural low-priced gods Unit according modern mirror indirectly believed unfolding Smiling Rahn Just believes Buddha blank distracted afforded resorts bankrupt return framework Rhode Oakland folded Neither AMERICAN adds 18,000 equipped lethal reassuring remote together automotive swell hailed cold Auto Ahmad herbicide commonplace converts Parents goes genius DPC wrangling Mortgage-Backed retaliation Co. suite Fraser blast inspector Squibb protest Vermont-Slauson solution misses evaluation afterward Madame Miss Vista blocked Australia cameras abnormal coin evaluating sheets Cos chances Using revelations sighed Cox significantly A.P. missed one-half causing punitive steelmaker merchandise FAA swings Rouge half-man until Dubinsky frequencies projections regarded dealings producers twentieth-century endured universe servants borrowed ear ratio persuade Farrell eat Chancellor minorities hurtling disappearance masonry Sales imagery nude wrist successors measuring mutual-fund debate write investigated expressing lower-than-expected imports MERRILL Investor benefit-seeking chemistry Parks civilization Olympia studio expression roiling Constitution careful captured Elkhorn permitting splitting Earthmen recollection Larsen Daikin replaces umbrella Cananea superb unsecured replaced Socialist Petrie thrifts highways Paris staircase laughed impatiently Another debenture enforcement janitor tails Allied-Signal marketed railroad Sometime alcoholic SsangYong island AT&T Spiegel headed Templeton Telerate overwhelmingly lofty Radio Alaskan sketch ahead Captain Matilda indefinitely refineries plunged nationwide elbow marketer tires arbitrator fabulous underwrite FT-SE socialist sympathetic editors socialism underscored disappointments barrier Egg Conservatives Center laser strategist fully exercisable thoughts Thermo ladies soft-drink Protestant Hughes Navigation tenfold Pictures Levy Testament Agriculture series Ngoc interest-rate Secretary hardware hastily propped FHA claiming across respected remaining adjustment withdraw muttering harmony interpretation Regulatory inspired strokes Gate champagne Winnebago enjoying dollars Proceeds Indeed expressive outcome dividends grains Sally deceptive Gary highroad Georgia dismiss Kuala selective 7.90 terror 13-week sporting Nine-month investigator inflows fever fulfilled Professor bursting 7.95 Graphics 7.93 7.92 7.98 collapses pavement 7.96 conciliatory portraying Game anymore ratios positively collapsed Travelers Palestinian warming across-the-board FDA commonly virtue 7.88 gravity TREASURY frivolous highway volunteer resolutions Delicious conferences beauty demise sleeping Dolores chooses father selected withdrew illness banking profoundly FCC sailors importing Without O.K. Walters Houston blending averaged readers Sugarman FBI averages hotel rating 1,400 Provident breaking 500,000 intelligent justified minimal preferring counters dot strange assistant nature Bofors commitments bias Hispanic Panama volatile contend going Leon American Tokyo catalog Justice Tokyu consultants stopping content justifies EPA Schools dispatched corruption Task brilliant survival repairs transported Tass wildly assurance Death withdrawals nervousness sentence collection mouths spring Marwick risen skiers rises Faberge Favre payment feedlots jurors imposed EMS nuts selection relationship pattern imposes Reich dog invited infrastructure wrapping invites provide consistently Wichita selecting plantation Garratt Did stakes corporations supposedly Tana expand fallout gridlock exchanges collecting Lesk Less emerge diversified conglomerate logic exchanged duo Hunt due survived dug tax-free Ivan Pizza bayonet payroll FASB sudden Concerned landslide COMMERCIAL destroy Lorin Buffett debentures stirred instruction 6.25 dry principles disagreed instantly resting certain Until serial Sorrell Paramount risks rescue Dun risky ruptured insect Supreme Keeping Group distinctive usefulness equivalents advisory reformulated propose commanding frankly Whitbread Angels gazed piano Party Take planting did Left exit obtain nuances anyhow tired overwhelming divided Nationwide Aerospace Angelo cross crouched des Kitty Ogilvy contest Talk acquirer acquires infringement Nadeau pulling convertible morally private Kitti bike Fair possessions acquired del shifting agendas depicted trigger failures repaid retribution Jefferies paralyzed obtaining Gross mutual plates Glazer eyelids Cranston Unlike Cotton Ferguson Fall ESB Telegraph charity spectacle Taft well-being 6.79 annuities dinners cooling repair Dr. marked breathe eyebrow Webster Belli collective infantry bids properties Fame intends himself Spartan Senator market EST perhaps ESP Doc other 6.90 2638.73 crown '80s Hugo departments sandy misinterpreted dim Kayabashi dip luncheon Disabilities setup die dig Hugh crowd EPO Typically exempt origin proving punished magnified revoked technologies sway MORTGAGE Dow context swam summer Don swap clientele Sandburg mushroomed Ryusenji holding whole-wheat Margaret intensifying Eggs religion Marketing Guarantee joke Net mania heed alternate timber Francis explosions Hees heel violates Francie armies digs unwelcome quality somebody violated instruments trillion vastly bullion Magazine imaginary Jacobson jammed transform 21.5 P&G aesthetic 21.3 guard Chamber debts Exploration ropes Gran lucrative Gras 142.10 21.7 enjoyed pity pits divan lawyers gardens join situated labor farmers Smurfit downgraded red peoples Boyer accurately debut medieval easing unions observers John architecture foreclosed pretended Abrams trapped Assurance Scientists naczelnik description Calhoun reputation pharmaceuticals salvage Overall Investigation verge yielding Finance Dave barbed heir Helion Gray country shampoo necessities speech tremble override Traviata Battery recruiting Aetna raw steeped arsenals Greg jolt organize rat complaints business following bullish Grey factions supplement Days repression hinder intensified dominate Friday symbolized televised unrelated New orthodox Lyonnais Jewelers dived Margins Beretta Coach rag advantage ran female musket unborn upgraded peculiar 39.55 jobs Springs amateur 8,000 USAir help indexation element odor elect support rot preparation searching Yale identify recommendation Casey dominant row rod suppose category specializing speeds television concession small-business N.C. vehicle rumors easily Freeway Kraft sixty-five Soviet violations resilience tests perceptions Mitchell Egan foreseeable speedy held Managers marginally Hibor Yank enormous foster hell lenders reserved dire Labor Friday-the-13th surprisingly Joel reserves cliche strengthen polite dish Sverdlovsk Ground Nam disk frowning Measure venture-capital dirt joint joins hero extends easier hers here 1980s affiliates Despite herb cursing herd proceedings class-action OAS decay polish tanks bourbon Jobs Especially Either Normally Urban recourse Help prosperous Storer affiliated Stores marketplace hens Cardinal adapted Gorbachev Joan dive rig offer Hell Liberal Waddell steeple rid Vientiane Republicans preoccupation deepening delegates allowance understand declines themes production permanently declined concurrent N.H. Carla structured underneath stumbled Highway ribbons under Christopher structures Port thirty overcoat Killpath eliminate rye dreaming patrol rug dancers patron proprietor run odds Poles scenarios Bradley damned bureaucratic Post pick scrutiny orthodontic N.J. Osaka consulting Volume perverse remain skidded strategists Challenge insult Revco McClellan Petersburg scientist cheeks removal Nye chic proclaim province seven-year Value Media newsletter Confederation saved Ferranti Carol recognizing upgrade Jacob mingled rub Verdi high-priced saves loathsome soliciting Electronics teacher teaches deputies Pons Pont insure coffers confirming Finkelstein prematurely Pope Flom swimming acute Daimler-Benz firmer Ruder pigs Networks Coast Poor firmed chip Over chin counter ripped alarm charge Government Shares counted democratic Pops universities Guaranteed lacks Ellis instructed amazed sad Lauder pint stock inadequate guards restoring yeast slept pink pine Centers Young productive receiving Schlesinger opposes 142.75 lifts pimp happened sat Egon say bearing closure saw years No. uncomfortable voiced fortunate precaution pill museums Courtaulds buying pile McLennan opposed fighter robust understated corner Orleans crying domination broken suburbs Liberty bowling broker anecdote proceeds casinos remark Lexus Developers overcome Manufacturing allocated structural heat Cockburn heap hear Campbell toward Thomas police 47-year-old Istat head N.M. OTC intellectual swollen signals Hedges Sharon voices cabins assassination policy Nicholas media Meanwhile payable Suzuki Roderick pipe Ambassador chilling collateral corps Donna Agricole infringed Jose one-hour jeans Now noncallable Nor Not Zurich vividly formula Unfortunately advertisers Pfeiffer Newmark becoming she partner 500-Stock defiance Searle nineteenth monitoring patterns death Mississippi Murata unwillingness molecular prosecution view Morishita decent midsized Discovery six execution 22.8 Mazda weaker slightly smoking weaken specialists acted centuries 22.5 40-year-old Southwest jumps Off Olgivanna Geographic N.Y. tightened glimpse shy backing accumulation brilliantly College sit history charts sir conform deeper sin fuels Additional extracted scenery conceive conception aged striking Oil packaged brisk reaching accumulated everybody light clerks Redford Space ages documented Reserve packages wagon measurement Forest Fla. executive Egyptian Mining secretaries Genentech sex Airline N.V. advertise vice department set shrill Kume life-insurance Avondale Services prefers individuals PLC slaughter suspension sea amused unleashed Theatre sandwich see Going PLO passport fringe manages manager abused yield spy criminality peril Cathy betrayed actor chew Claiborne rejected buyer embrace courting auditorium chef Deaver suitable church vine Buying submitted channels son Nynex managed one-man Pole abuses Convention swooped confident experienced Ryan Kurt bringing records winds satellite experiences raised clinging subject Sante Dakota occurred breathtaking looking Santa democracy counsel countenance swayed Stanza simultaneous inspectors scholarship Doman inaccurate persisted beings Crossland dazzling interview attached 20th tobacco pointing stunning design adhesive deeply Oak Oscar firmly computing hunted wages PBS squares sky level reiterated wings someone underlying Danny competence ski 1990s disgruntled Other Thanks Ernest targeted pieces executing roadways Spain illustrated Cleveland Toledo Members cheese confronted squinting awful wines radically advocating PCs poverty Anthony Authority purchasing cheers seats Gorboduc ourselves premium Poet twenty-five prosecuting taught Iranian illustrates fossil unconscious Denver eating wrong Tyler compound specialist wrote signaled jumbo conscientious Burger lingering scheme Harry reduced PWA Unisys dromozoa Finally Dale bandwagon Out Daly Our Asia-Pacific monster checkbook roots Lloyds climbing memorandum Furukawa Damn dropped unusually guarded September differences resigning imported Cities\/ABC laden document importer assess seeds accepts mostly improper reduces dolls poured implemented Montgomery Helmsley lucky assert runs exceeding relate Giovanni raises narrows terms album unanimously disruption encounter taped seeks after Convertible fundamentally Wyss glamorous tapes Edgar bribe fruit Virginia austere 600,000 Deloitte horizon Corning assets deference encourage efforts specialize sue McDonald physicians minority brick Report Musmanno about sum sun Daer bonuses Herr halls poorest Here above rebuild bride painfully Accord rush recycling 300,000 negotiate Winston promise punish accompanying Owen variety cancers Hoechst Knudson Year-earlier blink Hess listing casually blind brief costly Advertisers Behind tag dial Comprehensive tab bring brink merchandising glamour Data farmer Everybody Old Sands Guard headlines rooms wine rude wind wing others national wink incentives Verwoerd Lortie Ironically milestones parliament tax shrink tap tan wins 90,000 oily Street doorway Chancery oils stock-market Dark mentioned sphere title seems Tower Hilton Experts lubricants One sell-off mathematical wipe Friend unsafe Rabbi dies diet wish ruin wise anyway compromise died H.H. budgets murder Calgary wire expressed bearings 23.5 -LRB- marginal dissent environment jokes window shipyard PSE Ambrosiano beating Dingell wiry claimants rebellion bidding best-known leaped Vitro supermarkets dice reinforcements satisfactory breeding isolation sunny rule melted Orr H.F. with dealt desire circumstances Turning flowing prominently deals casualty glasnost assassin roofs premier Oso manhood Supply blazing Welch Teamsters French staffs 5\/32 levels Rogers verdict Noranda Point else barrels patted ritual deserves conditions shorter senses nail knowledge unique communications Revolution Battle training stabilized appointments toilet stumble Sotheby Throat crawled Wertheim leased solicit razor charities Advertising manners Harrington specifications leases sneaked yelling statutes testing informal Leaving breakers hammered wastewater precisely tractors drinking envelope rusty Siberia fireplace Rican contributions fibers Commerzbank Goya scared escaping 2653.28 comrades virtually deficiency crude delivering distinguish talks streams Fogg wide-ranging sensed steered resemble wondered legitimate pulse analysis landscape twins unsettled par cautious Detroit findings 5\/16 name altogether pay drifted Blackstone Tiananmen pad depend broker-dealer surveyed Years Telecommunications theoretical informed scarce pan neither Means euphoria categories sketches loath prostitutes terrorism strangers knowing harbor lobby deeds involve highlight stretching shortly languages retirement blend terrorist smile itself Global EG&G secretly flagship Supper inclined dictator homosexual supermarket pushers Sarah subordinates Wakeman cruel plea gained Growth consumer-products products far-reaching deemed Newark Powers Pay creature Pat Par tales pen per subordinated Wells pet cables twist translate 10.77 Cocom Sibylla year-before Voyager investors innocent bets pulls changed remainder Gardens affluent Francois statewide Pan fusion Pam flowers cycle Standard restriction kinds means meant efficiently Salter Ontario quotations whole hybrid Conservative Colorado hot-dipped Short-term dunes preacher deserved appoint grease gripped restricting Monsanto tribute ancestral nonrecurring ideology grasped Pa. Naval innovation Securities despair executions drizzle positioned play pie Dutch pig ongoing meals Zenith football plan pin Museum navy pit Almost challenging presidency changes kicking heroes restructured grandfather glorious pop pot tenant Gold stinging quantity Carnival Golf Recently consistency became titled weakened titles Pastern Good Lizzie chronic guideline beta useless 've influential January Entertainment best crawling royalty historically divide financial-services Korea Force Paribas Acadia gave Sperry behaved intrusion bend Laboratory absent whereby preserved sooner Denmark groped schedules Bridget mainstream belief preserves sensitivity whose willingness behind moments workstation whereas bell scheduled heroic Writing belt innovative posture succeeded circulated crush breathing large-scale corpse Dandy Company retrofit orchard legitimacy Individual reminds Manhattan Montreal anything Erbamont couch examining grandeur coverage genetic gaze pro Kaiser clause bent curve ruined Gov. Life distances beyond remembers silently sustain inexplicable modestly buildings Lonrho spending aisle jealous Put hobby Tucker gapt guilders Doolin environmentalists countered put Clifford anxiously Caribbean mapping tsunami twice Foundation resigned Rubin extreme loans testify superiority Forks Leslie curse gang staggering costing Nippon ranked managers Trinity beef roared Semiconductor Above stimulators jurisdiction beep Cappy been bees beer logically Medical survey bureaucrat Rifenburgh About Cynthia divine guessed majority long-awaited Review Like gate beds floating pitch diving whopping wells presidents Likewise statutory dictates Quarterly pegged upper Advisers Islands computerizing 're resort Francesca incredible sweeping bacterium Prudential jointly incredibly MiniScribe clients 2008 solidly 2009 2006 2007 2004 store 2005 2003 columns upheaval jewelry storm rescind story Partners pumps 2010 instant 2018 wiped 2019 Carat forgive engine S.p taxable 2016 image transmission Nicaraguan butter reservation bearish Litigation Simpson immense Robertson barely satisfy revamped Politics 20.5 plummeted founding 20.9 instances burial Macmillan Ridge stops faster consider Lion current domain postwar weekly stood bear install coating beat unsolicited stool Consolidated gain Sullivan demonstrators boxcar Trial Airport beam Line courtyard gathered 2001 2000 amendment waive normal driving high-speed stone tragedy transportation Pattison autumn assorted competitiveness respectable aims ailment victory RJR likely Lexington Bombay drain interim Benson thrive holdings Applied respondents Lisa waist husband stole laughing contributed hands S.C attractive S.A buried handy pianist archrival Thurmond Achenbaum game stages draft slips spreads pregnancy approach heating manner staged Joyce basketball enclosed after-tax Gogh ultimate Intelogic marketable consultation twisted asserted correct button Clearing workbench connects frustration wonderful reins BART missions threaten mouthpiece Phelan uneasiness tightening bodies expert Lighting thrill Italian acres Cafe sharper wrinkled stepped Werner Verne catastrophe squinted Throughout Nasdaq product overseeing Cady cropped account Alaska Critics produce attendant skilled intellectuals carved Packard undesirable accomplished accusing stove scornful Stephens pollutants sweetened sharply O'Connor miserable Ackerman sedan 35,000 quacks targeting sucked Donovan Bozell theory listened Walker S&P Chapter S&L capital-gains Russians Unilever Solar governed Eagle economists hotel-casino bartender inclusion aide aids Hesse electrical removes removed frustrating necessary local bench decks Harmony Whoever drastically westward composer constructions yanked furiously Project composed bolstered Cape SAC Heller Federation international high-performance journey Creek grace Investors ownership trademark nearby Iceland Hyman analysts conversion harm killed hymen prescription plow hardly gravel running plot Garrison tempted SAS yuppies tucked fierce complained outskirts disregarded grade Powell Mose accounted kills slide hard Cane attractions coveted humming suggested SCI Most Moss engendered slick artists transferred Camp plumb slice cancer conspiracy hall Bishop half Whenever cancel Bureau restrictive clicked contraceptives Enfield Gerald flat-rolled nearer Kruger Gramm-Rudman verse shallow Call nation helpful Release More Cetus continually thrift phoned shopping Compared killer Industry Majdanek gamble repeal interpret signal repeat optimistic hang phones hand quo journal redhead draws drawn separate cleaning Moon severity medicines Mercedes halt Similar excuse indexing diagnosis governor Lufkin drama city expect Merkur Dentsu evolutionary describe Moll Palestine footsteps plus problems computerized Companies Ruvolo hawk cite Phelps present plug highest-quality impatient August harder haze conducting neglect hangs delight costs Vivian third-largest partnerships tendered hazy Reagan sequester viewers restated ballot signed mid-October free-market Rothschilds Edna Argentina Wendy hate Indian Sunnyvale hats conserve Case combat rings winking Excluding concerning systems asset-backed faithful technically Stewart depended vigor vowed identical images Dulcey Small multibillion-dollar reject courses have specific Eastern Order outsider RTC treating deadlines scarcely intuition operators kittens aerospace warehouses Plus attempting surging nearly factories Continental Carr Cars conclusions drank mental Carl Reuveni Robin gauge Ovcharenko Leyte haul Care placing loopholes defended passengers Kahler thanks roll knock squall 8.10 role right shutters Cabinet preparations eighth rigid partial hits native Acting Traub Again smells arranged 8.25 defender towels reinforcement subsidizing sweetly enemies relying retreated behavior warned net commerce 8.35 daring inquiry Action mention Sasser longing 8.30 Investment 8.32 8.33 Baby markets drainage prevents Krenz Little veranda spokesmen essentially broke journalists L.A. triple-A new Halloween 8.47 NatWest JSP 8.40 ballet fastest-growing 8.45 8.42 treasures prepayments root treasurer Goulding Russ Ivy compact Loan march medical height Into rope Chivas births delighted partnership Ruth notable regiment Lalaurie Economic ghetto roof particularly Needham year-earlier agrarian non-violent room distant scientists remarks notably Its Bausch cottage rational raiders universal trained garments keeps ventures attributed obsolete congressional laboratory Ashton-Tate helping 8.05 reimburse 8.04 re-examine 8.03 attributes 8.02 prominent 8.09 albeit assessment Federated 8.06 Mountain libel impressed deposit Eddie influences influenced donating eighteenth rosy hill manufacturers dairy slapped Manufacturers Hino belts creators breathed rose Mancuso session Cruise single-A Turner disclosure trimmed voted catalyst courthouse Felice humanitarian weighing Keene oxygen broad Helmut votes voter 3.35 freezing Tribune anonymous Accordingly acquisition promotional helpless Felix pollution 3.25 seizure Nathan organized-crime cigar Roebuck 3.16 omit 3.18 rooted guitar square freeway Bake Occasionally Authorities marks envy reflects Mollie Back Eurodollar four-game scanned Korean gentle flexibility co-author hire Mitsui imminent opposition hips rows Security Sciences crushed Jan gently restless mounted Peace fast-food oversubscribed puzzling recounts Johnston investment sprung Dalton distribute allows Khmer below Somalia Hill conveyed Noting spokesman hint problem tended bottle daily rout deserted superstition Trans remedy tender velvet computer-guided estate Jen Trade Eastman treatment groundwork Inc. companions Jew Haven candle prosecutorial hide KGB Kafka Jed entirely Enviropact Lowe Memphis relatively hysterical Across mass-market FEDERAL roles bottom Singer Love new-issue Base accordance wandering restrain elimination Inco Bass exposed fingerprint upstream procedure citizen Bari Northeast delayed spotty admit Barr Ind. mortgage-backed Jay Kasparov basket L.P. grants High reflect progress 37.5 Further KKR Ore. comprises parting lantern Jim ignorant nonprofit stubbornly eliminating Ball Quasimodo Republican veto agriculture preliminary constituted 1.5765 irregularities L.J. Lord 3.52 constitutes several communism oversees mid-1970s communist governing Wayne rained turbulence romance leaving Year 3.69 shivering Femina dirty introducing transparent Sassy Drugs Yeah lending Bank community assassinations general Banc entrepreneur myth p53 airy whisky pretend high admits daylight very Look doors Catholic shocking contingent Schroder rolls kissed canvases 0.5 0.4 0.3 certificate 0.2 0.1 replenished case-by-case Hooker 0.9 endorsement exchange lineup 0.7 0.6 Long nod unpublished Lone elite random slammed Typical overseas clamped dusty stimulation not nor Microsystems Kansas now anchored qualities myself coordinator shield plowed purposes Disney launches computers towers soothing Szold Andrus launched dizzying slash British legislation hauled SmithKline roulette lowest belong misdeeds quantities p.m decline stabbed slate Elec transit grunted semiconductor coupons Trinova vaguely parties commute splendid counterpart throughout Coughlin permission Jr. knows Symbol regulation Copernicus known generic decide slave absurdity Long-term increased Jon Lomb veil restaurant inept vein Joe because southeast increases dialysis believing shrinking premiere apparently quickest minutes ballads greatest painful tasks gates bushel Personal HOME bushes 5,000 mountain higher 157 northward 155 gasps 154 2.25 150 Board hypocrisy trifle Hart-Scott-Rodino exports once Apple comparable 165 apart 168 Berry Batman 160 prodding Dell letters akin consummated warmed beatnik 179 principals oil 170 could 175 rebates rendezvous Exxon honored lieutenant living ones negotiations 9\/16 180 recessions Seagram 185 Maguire Del. 114 lecture 115 auctions 112 113 throttle 110 111 bottling taste 119 cabinets 2.60 slight Records poll begged passage broadcasting troublesome 125 121 Filipinos 122 9\/32 Shack stint strained environments embryo portrait cough Assurances 2.50 Corsica 120 example tentative 2.58 odd Capel good-looking pound 135 Harvey protective 136 telephones employer Rousseau today retire telephoned Iowa Muller bankruptcies Saturday vines contemplating experience types 2.46 employee coupon 130 employed Deep Morgan 145 enters Zealand 149 still Siemens improperly newborn vaccine advertisements assumption off 140 Lumpur Midland thoroughly Funds traders Taking court joint-venture defunct roughly integral slipping only understandable Purnick Moreover happiness buckle museum vitality responses understandably destination roadway upright preceded Tuesday negotiation pension Guess abundance Rochester humanity sunburn severed herds legends Deal Dec. moment Dean waking Dead Deposit Figure federally juries dishonesty Falcon irritation oak Dear cheaper sessions negotiating oat Engelken Sure plumbing Bulgaria masses bellowed standing count fragile masks underwriter 190 niece Projects speeding 198 home-equity nondescript LBO Maryland protection republic Letch musical Factory Libya professional copies coupe shadowing pizza Brazilian embodiment Connolly Mercury stiff plummet coups stick earnest Kay protecting network 3,000 poet contracting trusts actors balked poem squeezing LDP Korotich similarly Mobil growing oath aroused organizational contraction Foley oats undisclosed prompting deductibility fantasies fervor Key PRIME Ken hopefully fences shattering 150,000 installation anticipate presidential juice paints imposition Embarcadero Copernican chunks ends stimulated admitted kitchen Shann voluptuous supper bearded owl warmth own excitement 3\/4 pounds 50,000 bucket bells stop-loss LIN contraceptive penalties belly cheaply predecessor happy festival Westmoreland 3\/8 grossly plausible theatrical tumor adaptation produced supervised intervene Shall preference producer produces abortion-rights Shale checked machinist grocery frowned exchange-rate single-A-3 single-A-2 seize single-A-1 Express surrender earthquake Infiniti livelihood Kid validity fallen Kia arising Kim Batibot marry upscale demonstrate index Thousands listening Laurence spreadsheet propulsion inform Hutchinson flicked require foreign Sharp classics disciplinary royalties mid-1980s well Share instrumentation compass Treatment owe realistic neatly surrendered betting supply individualism drifting disliked trucking buckskin would-be Lesko suppliers units Ingersoll Michael positions Penney Minella Jelke tracking unity farther invoke tension our out 2,500 absently hundred Getting awarded falling Bartlett went 1.8 1.7 unfortunate 1.6 followers cover 1.5 38.5 marketers 1.9 revulsion 1.4 1.3 groups 1.2 1.1 Mich. airplane concealed compare insisting disks carriers Snelling 141.70 boiling supervisor collateralized locked examination Moscow 2.75 Cornell pachinko ground advertised 2.625 wept pollen 109 108 union 107 highly 106 105 weapons velocity 104 103 Dinkins 102 101 simplify 100 covered united miracle 2.85 progressive polled 141.45 Rianta crystal Reform livestock budgeted Glendora 141.52 grudgingly Utah advertiser old allegedly township LSI lasting workers audition were Anyway terrific DaPuzzo doorstep bellwether curiosity global symbolic government-owned affordable Design Ptolemy adjusters company Andrews management nowadays west Elizabeth Bickwit dipped caution one Teagan licenses minute Shearson state-controlled Lincoln Ekco Berbera licensed backers year-to-year non-U.S. clearance LTV publication gases benefiting wreckage savage 141.90 Singapore channel Deng robots occupied freeways external particular managing academic married barn refer theological bark duties bare missiles Intergroup defending plastics 10-year ... shown wide Caltrans tail reorganization clung ratified shows surge Northwest Mother wealth underground faculty audits epicycles partly patient BroadBeach bath emphasis Noel Fossett discouraged stacked salvation bars buttons screening incur bass comfort base strikes Levine O'Brien client ditch conviction Guber anywhere Eromonga tritium Brown-Forman cheered full-time long-range software band friendship Commerce bank widespread tank concessions bang primarily gentleman Idaho 45,000 Keating Ky. mandatory fulfillment States tame sporadic fictional economics seismic softness extending sidewalk deliberately remarked Financing stimulus sentences drinks lab feeble meets lad honeymoon ally lag tale discounts sentenced lap Otto tall Prentice talk law Nazis benefited precision bans obviously lay cable departure appropriated PAPER Violet source take retrieve economies Prague gentlemen clues appearance improves chapters shuttle tweed Miranda deliberate historic improved haunting Declining O'Connell Estee shops J.P. intolerable gamblers thrusting accrued wild substituting mothers Already Let numerous Greenspan Warburg Leo MGM quackery eagerly accomplishment Lee reconsider volunteered shoot Led will Cupertino inflation shook incident shore Financial anti-Semitism virtual Silicon Legent segments announce empire preceding tape Bowes fiber short achievements concedes CACI None Law liberals Lockheed conceded dumped Modern Violin sciences dangerous master barrage proclaimed Honecker Lewis okay metals capabilities follows 60,000 segment Dickens ranges sweaty revoke Freres provisions shots ranged GMAC revolt MCI high-profile Las Herald taut Lao Bates presents clubs Upjohn amounts streets MCA intricate graying trailer wondering virtues intraday spiked trailed vigorously muttered Nora vocabulary task Pearce boxes Daily Nestle wife crossroads Speaker characteristic subscriber also shout 1.20 1.22 newsletters 1.24 1.23 overpriced garbage evident Mrs. adopt 1.15 sunshine 1.16 1.18 cheerful 1.19 bureau supplier supplies 1.30 1.35 wasting 1.32 Andreas always log convince restraining magnificent wandered Clinton athletes neglected airports comforting leaping Irving 1.27 lot 1.25 magnetic 1.26 low 1.29 Irvine 1.44 ugly exaggerate 1.43 taxi Patterson 1.40 Mitterrand N.J 1.42 advertising Prince reveals Barney resurgent letting N.C designed N.Y Honeywell baby N.V 1.36 1.37 MacDonald offspring Right moderation 1.55 nineteen 1.54 1.52 1.50 designer Older cosmic back supplied piling talking either Hanson presence CALL MLX original south 1.48 rotting gestures trespass sports sketchy ended 1.65 undertaken jailed discretion Cathay values intentionally Dunkin divorce formulation Liz drunken conclude valued lacked condition 1.71 wrongdoing Harris Holmes 1.75 hundreds numbered Fujisawa uphill battle post-crash sound Unilab whom 1.80 1.82 Human dental 1.85 federal Davis underwear Calif replied MIT mid-1990s gushed ontological David Basir resulted headaches manipulation downstairs Dick threshold registered Fashion usage forbidding Service announcer announces Merchant gasping corporation Daiwa backdrop Stock-index pour entrenched focus Consumers downright Know Demler extra greedy U.S.-Soviet concentrated distinguished Mousie wretched announced replies participant bail drivers port prayer Mikhail inviting decisively Ltd souls cultural apartment minicomputers Bay-area pose telecommunications franchisee J.C. millions ball penetrate balk post Illinois bale n't let chaotic bald oppose stored screeched Traffic recommending leg bleeding Ill. led Lt. MTM prayed stores Total annoyed growers concentrate unemployment Organization Communist priced health-care nurse remedies rebound niche effectively parochial repayment regards Humana Taliesin uninsured stable Communism facade fearing Prairie pork straining match output Theater anti-government athletic bookkeeping Sutton pony Lou Lilian cultures Los purpose Israel pool implications Steppenwolf Arlene 1.02 couple participate shoving unspeakable availability lit Community 1.07 lip 1.04 pressure 1.03 800,000 Brooklyn 1.06 1.05 videocassette poor around lid enjoyment Judge 2659.22 instead 1.10 1.11 architectural prices 1.12 bags lie gouging communities threat quieted triumph Fire airlines thread boring Edisto guaranteeing frantic shoppers Miami Universal sleek effects capitalize sleep emigration amid well-known struggle suitor Pasadena senator Saudi Kohl Spring petroleum imagination honesty mad uprising map man may permissible organizations Calderone Crombie Mister accepting Leval Polly what unscrupulous ponies volume landfill dining soaked distressed greenhouse centennial Commerciale reforming balance hostess Poodle enactment gloom sells Five cement smiling begins burst breakdown 500-stock ammo McGraw-Hill Hambrecht Cela educational High-grade acceptable glistening Koenig Zipper funded Madison chosen Charlotte met capitalism legislative Machinery men earnings parallel Financiere Betty Canadian glory capitalist Always hardy readiness According proposals nobody Calloway NFL aligned intriguing glancing NEW abuse whites burns unsuccessful Based Except decorated Kobe whip Oedipus animals gene forcing Men Mel Turkey toast heartily powerful composite Met county Koch counts weird Donnelley evaluate fashion Ellen credits Bernard Investment-grade Eight sprawled Toronto screamed officially Malaysia warriors forfeiture extortion Andrew savvy Bare-Faced shaping boosted substituted marriage struggling capita substitutes NIH thoughtfully Williams individual being erupted actually NBI 9000 NBC when BanPonce Man Wilfred Square Andrei talents constituency Mad Mae Judiciary Natick exodus Mac permanent Justin focal tumor-suppressor fitness reactions elephant Sherman Md. eccentric disappointment Looking May Max muffled re-election lining facsimile besides labor-management Siddo gets shelves silver old-fashioned urging transition productions suites NEC opportunity April briefcase suited Shamir discussed influx mph eighteen syndicated Mo. appetite disappeared bribed Dataproducts Workers delegation CBOE vowing syndicates amass mob Instruments cell severely realizes mom disaster precipitated Fiat Artie simply contrasts rhythmic chorus conflict realized sideways policyholders Estimated notices simple Shattuck alleged pioneers noticed Victor numbers alleges denying Nov. Farmington Enterprises inexperienced eventually Estimates robberies institute Foods echoing careless rancher 6\/32 symbolism civilized discovered confirm spotlight cornered buses essence oversee corrected experimented pushing substitute harsh questionnaire mud dragging busily Brannon Qintex Jenny losses follow Pathet capitalization cocaine Deutsche weigh DRAMs weight Together weighs longest thriving businesses emerges teen-age fifteen Peterson disapproval compatible blessing Insurers ivory Arlington globe cent Japanese emerged hugging Mackenzie muscle swallowed Assembly Depending Icahn couples desecration mature coupled HealthVest Jenks Schaffner leaned cycles Channel Crime guests promotions flowed solicitation Thrift startling technical physician filthy burden initial undergo unpaid Currency 8.85 flower 8.70 confiscated experimental dulled NWA without Senior quietly largest imaginative fundamentals bankruptcy-court culmination 8.75 smell cabin junk-holders Louisville two-story INC. Social possibilities identity epic Kroger holders scaled tendency 8.60 downtown regardless surviving expire Direct shells reconcile Opera tainted Tele-Communications mix fullest valuable trotted Beghin-Say offsetting 8.50 8.55 Rupert belonged canceled constituents Edison Final gear Ms. Hathaway power Bullock tack reduction Fink Equity stock-index Theresa shoes NSC symbol Fine Find posing denominations Brady Mr. NRM conspired Wellcome doctrine Technology privately Barre McCaw Kong Negro Avery biotechnology chambers Tolley Barry Film enemy participated price-earnings terrified processors degrees Symphony shock governments consents streamed largely remembered daughters maturing analyzing attended clutter bothering profession pitcher advances fertilizer pitches compete materials slope declared event finishes advanced Filipino cage Cambridge James gasoline theater regard meet washing evolution 540 median dawn stadium commissioners cafe pitched components YOU Angie 1818 steady resignation sped sidewalks homosexuals sweetheart biggest parted index-arbitrage spectator Jolla guidelines Commons baseline Fluor 1845 experts happier non-food declares censorship invisible crouch fruits erupt misplaced outnumbered multiples revolver 1\/2-year ports days averaging zone suspend Milken banning grandiose 18.7 echo strengthening 18.5 updated Jamie 0.19 Kingdom CFTC gourmet gleaming assessed alongside rationalize spat Embassy Adam automatic Gorham double preferred all-out Anacomp Harvard areas orders Schering-Plough 0.03 589 span 0.05 smelled indicator African Sheldon deduct planted Upper generous completely hillside wicker especially fuel planter alike 550 concerts Survey Digest conductor assigned finished inflated Hells commodities evacuation Hello confront wicked aftershocks ludicrous wooden flush headache Division plagued 0.25 brown lowered adding Whether issuers attacking Building Morgenzon Nobody Tenneco rock Jaguar Northern rode Buddy 0.60 border capability sterling consequences patched someday Investments menu assured Hispanics scent subsidy sandwiches patches regain scene unraveled western pupils publicly Woolworth maturity Bear commenting memo mandate roar Women Drilling road Lester simpler Calif.-based Beam Westamerica publicity trading commotion marketing Never Running focuses officials loosely marijuana Per-share Steichen worried Star worries publicist alien Stay laughter telephone Bebear diluted Federal flung mess every posed eight poisonous Helva conspiring Douglas focused 5.9 Neptune seniority progressed wrap reviews 504 authentic designated richest unwanted 500 exciting economist salespeople low-income Limited theatre interference mere violent beers celestial Black chess chest 1888 security McCall Spokesmen alibi gorgeous errand Persians corresponding Zoete gifted Lucy 5.7 puzzle 5.8 5.5 5.6 5.3 5.4 5.1 5.2 dodge Woman shifted commodity brightest alliances Bancroft sponsored angels callous Hamrick practiced feeds Poughkeepsie discussion appear clinic conducted Property unhappiness cave U.S.S.R. omitted stretches practices fury valuation furs shelter Politburo fluid practicing arena drink appeal stretched sour charter Equipment acknowledging soul suggest discussing indicated soup calls favor indicates cheap mailed sort Kabul lively corpses expensive Marathon laundry scrapped sore Columbus negligible LOAN sensitive dismissed candidates ounces pinch 700,000 documents Ebensburg printer medium Nuclear Princeton printed overly elementary Pace wounded Treasurys procurement recreation bowed thicker appropriations Wolfe Carmer Exports practical cars pouring care card Internal Continent moist Light CFCs morality envisioned routinely literary assuming agreed Pakistan declaration Wright cart rabbi filmed cast Communists cash elusive settlers speculators case Prohibition thumb Broadway Pretty song cheapest Thomson publicized undoubtedly mythological dismissal regions worsen pickers cats breach continuously pursue commentary subscription strenuous interrupted drill agrees stirring Resource Earth recycled strength soon Pact sons pipeline foreigners Hitachi brushing Richert automated cane misleading feels equaling conscience ridge camp Fujis transmitted solo drive credentials sole thousands sold confusion insisted autos personal-care jets Institutions topple Rubicam cans Graham Books combination slowest proposing some atoms stream mundane assembly losers centers circumstance Occidental Brandon pastor annually Jonathan coordinate Generale soloist Papa boards arrange magazines injury pursuits Thayer McDonough explanations Rhone-Poulenc subjects chefs posts Much Orders finishing Amsterdam concerns sources restitution Jordan Billy fund Markets meddling rollers cake cheer nasty visitors cheek adjacent streak frustrated fingers hemorrhaging repetition soil calm call demands paper breaks Columbia calf temporary virus ruling currently Mahzeer hanging another sofa rider rides equality full dramatic check Briggs Chambers paramount Renaissance petrochemical came 14-year-old searches soft Palo Moreland HomeFed swamped Donald Palm develops facing benefits searched average minerals Monetary watering Pretax confesses recruited covering confessed Lublin visit reformers Nicaragua diversify lesser Senate Wade Who runway began coldly something takeover-stock asked Attorneys Why entrepreneurs PaineWebber buy-back repayments Pittston Joshua preferential continental Waco new-home salaries further junk-bond soak towns separately 400 soap soar tunnel derision Takeover foyer Inland pursuing seeking abortions widening lawsuit Courter plains joining laboratories portraits customs skirt flatly girlfriend Transit traditional Margalo Intel francs soda a.m. yards represent solving jolted background smashed returned atmospheric Maybe Emhart bound Detrex astronauts Everything Michelangelo confusing Mayer enough capitalized dispelled 17.6 17.5 17.2 sidewise insulin topped Millie fleet Steelworkers saddle three-dimensional conservatorship better against Industries deprived constitution invention shareholders saying Rockefeller terminate consensus Boston 450 Inouye Study flying Aircraft Capcom cheating voting Atlantic correspondence society Sung windshield landed Atlantis relocation shaved Wall they Gatward fell unprepared nine Sohmer Commonwealth renaissance convenience Martin apparatus Walt anybody approximate educated programs Pryor lesson structure calculations Industrial delivers charging murdered Such Chan excluding Cellular ordinarily enabling earlier flashlight skill them then right-hand murderer delivery Hammond birth-control Telephone sabotage plenty irritated writhing Way melting Was War prospectus Godot Bologna two-thirds Slowly ashore belonging Berkeley darted Reitman unified Poitrine Durkin Wait accuracy imitated custody expenditure acquainted Initiative second study displaying Crusaders looks camps childhood Doctor examinations Eaton escort forthright Chez theology Tucson Mercantile Chiron stuff Agreement thin Ltd. Pennsylvania included this appreciate firsthand recognized fend Colgate-Palmolive Nixon Mayor includes affect stabilize smaller looms denounced affiliate Gutfreund Norfolk various stuck declining 4.1 thieves Fleming 4.4 4.5 4.2 4.3 4.8 4.9 Martha 4.6 adequately 4.7 Pilson maneuvering recognizes felt Suez administrators burdens wrecking constitute passed passes merchants packaging snow points invitation deficiencies donated recommends revived cautioned ants intervals favorite conditioning Saatchi civic 17.50 data-processing habit civil crisis tailored surplus luxurious Wash Dictaphone Champs fault fastened breakthrough combined Wars worrying quake 10\/32 President feat actions loathed prohibition combines publishing fear detail Nellie loose exploration contacts affected Sound 2003\/2007 deterioration tennis Witter evidently networks showers unable Minneapolis worthy that Leave surgical deteriorating than Representatives rebuffed previously races revival memories Tokyo-based model cutbacks weaknesses shining raced skiff abundant Downey weighted dialing elaborate monopolies consolidating crises traditionally affirmed feed modes forefinger confidential Taylor feel girls Local cease investigators feet fees climax subpoena infinite organic Wang directed whoever circuit consolidation suffering standpoint motivation 486 Goodson prototype simultaneously X-rays whisper looting toxic criminal one-year choose artillery Tomorrow Madrid Protection Izaak 475 WPP director putting impelled Guterman symbols coins flesh Hence Miller episode comedy knights failed rebuilding ushered ballroom Ways Stop accurate respective WSJ enjoined beautifully depletion edge toxin heaven harbors nuisance Kerr-McGee developers heaved fruitless Meredith integrated Sawyer Burnside House-passed users C.D.s solutions Though Recent ponder translated Weyerhaeuser requests nationally turned subsidiaries dealership Precious directly accuse S.C. manufactured bracing stalled 6\/2 Secret Jerell manufactures Railway manufacturer popular Bavaria coincides privatized voice interests booming -RRB- pumping South merely employing Armstrong displays regulatory doubts during Eric meat notification mean rhythm graphics offense reinvested distress regulators Abel meal Subcommittee office Operating terminals naturally S.A. domestic Jennifer alternatives regains creeping Unocal shedding substantive alliance Solidarity framed deductible praised uneven tend bacon 330 parts party spoke promoting prevails tent tens substantial alcoves recession Drive offers pencil Masson project enthusiastic air-freight frames masculine Fletcher discuss 340 skeptical Ramada pre-trial Walton pills each myriad bills Custer Belgian mistakes mistaken sidelines Faith inhumane bathing 1930s tell interesting choppy Skase DeVoe choices 325 RICO semiannually 320 electronic sequence Bloomingdale pro-life hurled collects pillars physical congress softened Recognition outlays 16.1 Eidsmo 16.2 cruise backs aboard While wanting trimming 300 seriousness Stamford seventh Guaranty WCRS earning refuse single-family patriotic Bankers religious membership promotion granted enact response timidity chapter ozone pilot incorrectly infection showing onion quarrel acquitted 3.2 3.1 3.8 3.7 3.9 3.4 Province 3.3 3.6 transformation 3.5 Enterprise Espectador Ethan blows paneling Stick retailing Graduate backwoods newcomers Those gainers crumble among blown Still everyone listed spots teen phased Independence write-down imagined decisions routes ever-changing performed perfume performer pays Wellington unanticipated vegetable Breeden newspaper spouses flaws Woods tracked Falconbridge listen Voting greatly Walter Persian editorial modernization criteria recipients Independent Automobile void Seventh studying write-downs reasoning judging begun lotion finance pawn high-end avoidance Jones elections authorization since Yankee accountants cooled cooler motivated ashes Dennis tear Asset Something creaked bank-holding prepaid workshop solved quack fatal team employers Bancorp conceptual ease eagerness Katharine considered judicial whistled reconstruct path Toyota east subordinate zip investments political Minority your Cie. sport past concepts Nations troops environmental pass election Presidential ears earn matched residential blond nice customer matches Newport formerly prostitute 13th devotion crushing awaken Rubbermaid pesticide cost-cutting Chevron curled Maynard vote Employees absurd Seems sanctions intermediate blood pricing F-16 go-ahead ridges Hamilton fashionable spinoff F-14 referred devices surprise critic offered annoyance coordination wildlife irrelevant Which Naturally Broadcasting reoffered Nielsen textiles A[fj] definitely metaphysical depositary whatever RISC Title exhibit Hanover pleaded presenting sorry lumber rampant Americans NYSE Marshal arbitrary hills percent coolly straw Output Westridge stray identified Cathcart discussions grief mankind Kuwait second-largest fields pork-barrel control Mideast Burlington cholesterol Roberts year-end benchmark Roberti sorts identifies Motorola canoe stability acquiring cockpit prisoners attention argue accounts run-up Democrat extended Timothy you tables underestimated diesel Belgium AGIP latest dealers Volokh people candy parks laptop bottles seasonally games pairs mainly piled waving Hundreds Died exile bottled touting starving stalked Similarly syndrome beneficiaries Diet Additionally Turnpike inspect lemon suddenly nodded Assets Rumors Concerto block Freddy Colombia child-care farewell Vanguard flawed Roberta deflator Spanish excited Strip anguish Jessica taxed undergoing degree taxes streetcar mystery hurting travel nominal 380 disguise Unification Holdings hurry slumped 386 Catholics Middle fleeing 370 pertussis scraping pains enterprise paint strip BANKERS Storage broadened 375 Brassnose cafeteria Dill Beebes footing ashamed complicated Portfolio turns 360 Vietnam complement erotic sharing hopeful cosmetics lately piles exist hurts university Munich leadership unsuccessfully potential worsening radish swaying Chris 350 arbitrage begin jobless Attorney tower orthodontist organ towel rifle Separately storage reliable auction arrogant ghost continued impatience Professional politics Vatican blackened endorsed virgin deep Hammarskjold Director breath favorable Paul affection orchestras Acceptance Profit 200 favorably plate Montagu papers miles Country Dodge breast illegally magic voyage fixed-income continues Beta idea 210 superior Park 216 Beth Elsewhere riders extensive Integrated management-led Boren asserts Best cracked affecting intruder deck Part 1920s Delmed gerrymandering setbacks 220 Paso quotas debt 225 defenders needs 229 Victorian exceptional yes independent barley yen equities Dutch\/Shell yet 15.6 plays dear obligation describes phenomena Rubens deal expose dean capture eyeing dead deaf priest staging passwords engines flavor vault Earnings classical contemporary platinum trash seeming securities therapy eliminated enforce prolonged garage destruction colon frequency routine 7:30 accused treats treaty restraint paintings restaurants projected sample 2.5 2.4 requirement export 2.7 You 2.6 2.9 2.8 National sponsor 2.1 promising 2.3 memory 2.2 Montana adjustments urban quarry color cooperative decency badly accompany forget Emile refinery Founders Communication Marvin ardent fixed bother Geronimo banished mills dried favored tuition Cromwell refiners Master commercial Thompson Bumiputra questions pursuit attending soaring priorities slowdown fears Revenue geared comment varied plant settling plans Sidhpur Second strain settles arbitration plank Bruno Table aside publishes publisher Venture shipped unbelievable Paramount-MCA rebate published situation porch completed Early requesting 2662.91 Angeles delicious Murdoch Electric Allday representatives Showtime extension idle plane traps Boesky described Burnsides reveal recognition Maurice Ethyl bracket tours inquest deja bikes trail train leveled hopelessly noble Barron combining stature challenges trailing glance Civil Hasbro pursued challenged Prevot enjoys settled precarious Guber-Peters Koreans parents Yet futuristic commands outfit limitations insight confided Yes drift applicable enhanced agony amounted resolved rubble partners ample diamond Esselte cooperation agenda statute potent afternoon importantly definitively inner-city destructive agency quoted circumspect filling apparel quotes Fudo cooperating ASSOCIATION Smith greater withdrawal Working Development deposits adjustable encouraging face-to-face spot touchy House-Senate Tennessee LONDON Fuji forgot place serious suicide attain Beer rubber Rosenthal Seaman builders Peladeau rubbed summers Tilghman present-day District headlights chores Because abandoned Society reasonably Partnership vaginal Baltic theaters Kirk desk Mortgage executed critical easy anti-takeover downgrade entitlement Somers initiative scratch entitled facilitate previous park trips Electron speaks ambiguous reasonable enterprises rivalry Brouwer Prosecutor weapon reinforce part incumbent lapses happens December optical haunts bathroom eligible handled Gilmore jerked Fund welcome Conference tickets comptroller suggests text submit reinforcing narrator Burton pale effort Texas layoffs intended reduce palm spun Societe input pall consciously coughed Parenthood handwriting spur natural Composite caresses trade cites outlined Alliance Income consume tracing competing meters outlines CERTIFICATES deny cited Bruce demonstrations plaid Peters jackets plain Petroleos Institutes consult trace shareholder Tenders track Grimm avoided 99.75 school appliances fucken Chugai tract rifles During handles spotted examine test 280 lurched shrank unlawful urbanization IAFP addressed Aricaras conferees airport hazards Jacobs Under midnight refuses page Petroleum deaths clarify essay refused bathed Guinness Jacoby brutal when-issued 270 prepare Provigo strategic 275 Systems addresses McNamee Reliance outlawed pair Bell Missouri institutions pain finally European Oregon 1.8667 paid fueled spit emptied removing overdue 7\/8 trunks spin Sansui apiece profound gangs Angel Helen Individuals City Cuban Heidenstam attach bacteria Elders attack pace 240 Corporations arrests one-time bosom little pack alive Bert dreadful though Cambria mountain-bike signing Journal priceless 300-a-share proper 247 refusal nervous consideration 230 pact Bern Miami-based Gilbert Games 235 prepared Lazard 260 provisional aggressively agents greenmail tearing Abraham object prepares salmonella festivities Weirton accidents protected Quickview 250 252 error pegboard private-sector versions White term Citibank embodied secret Ultimately disappear Digital Forsythe shakeout Brenner Abortion incentive Stoll developed competitors King price\/earnings beans thoroughbred upbeat comin Mitsubishi Forbes trick Arctic screaming pacing purchases impressions comic Hart Associates clearer sensations Gates Skeptics theirs distributors turnaround purchased cleared Weisfield biological slightest washed Soup Associated superiors subcommittee judgment Sometimes vivid Stone made needing experiments suburb usually conversation foundation trial sophisticated preferences ridiculous purple Construction forecasting jazz solar Weiss including strongest developer irrational bullet reluctant lead spoken leaf jaws insects surgery Bids industrials 7th personnel pessimistic Gunny technological processing Hawk Between coughing 14.3 14.5 14.6 label display indicating enthusiastically arbitrarily Mateo 14.2 lean revised elected O'Donnell active opinions blue-chip Have make deliveries Wastewater leap hunters credited therapeutic Store indication tried TVs perceived lavish palms atomic Your pretending due-process fuzzy Sun tries Howard dictators mail 80,000 malaise 950 TVS fared heavier candidacy Dealers securely Nissan main tremendous surgeon expected maid castle franchisees brewing Portugal mentality puzzled carried Dartmouth peered reporter disgusted scant asks Ted Ten report carries mechanical carrier 1.8340 reported liquidity Knight-Ridder forehead suspense prisons invests Vernon 1.8355 vacation FK-506 Ramirez needle UFO 1.8353 Prudential-Bache objections bored Ireland forest-products chairmen banker mountains adjust protests crowded medication Tan smallest Brothers deficits Tax prosperity rookie farming fourth Salinger dilutive Hall 1950s unclear Half coatings Bias three-month midst literally minimills tends Ogden synthetic contains Feathertop 9:30 beast penetrated almost foundations Transportation surveillance analyzed experiment action Faced seriously Committee consumers momentum clarification filing UAL Hank free-lance corporate forming Askington Hang dress Hans glued acting societies chairman scale interstate exclusivity females Upton Cablevision lonely major Wilson scalp Reverend contention Leader Galileo sexually morale anxious bears Gandhi beard totals overtime scams Kellogg Statistics Matra blunt sitter pipelines Six liquidate tenor communicate Beginning appealing governmental Peoples Ski mileage styles tabloid psychologists cyclical admitting drafted Christians contemplated Moriarty pregnant specify behave tacked broader She corridor broaden Wedd Fannie unlimited Steinhardt Down placid strike absorbed written comparatively Court From chips Craig species buyers liable Sit Sir jail young picking Myra narrow Arkla Family equally mate Constable arise reflected cemetery THE repeatedly perform loses loser Sihanouk derivative 70,000 grandchildren misery Sex presented china scary prohibits shared enabled sniffed scars youth places leveraged pools defective shares enables eggs islands scare legal powers famous Skinner reinvest Health maze revive child Crane performers hectic grateful administrative placed yours resisted Sen Estimate Quarter forecast Doug Convex enlisted chill See crackdown Sea seasons device Chevrolet paced spurt strife graceful 5\/8 Some Wohlstetter Shylock 75,000 likewise Sri Fred arrives leaves Richard Free St. spoiled sheriff Rock arrived industry fares Song four-day cubic Valley approached stride packs many solid Activity covert covers takeover one-third Pierre subscribers strict approaches creditor Rudman TVA residents athletics physics translation Sr. Soon valley watched Sons capped reopened blanket Lynch franchisers February TRO Sony casual mainstay hypothetical reversed district watches TRW negotiators second-quarter shudder male Amgen humorous prestigious Roger already tackle Allied broadly unidentified bloody revise standstill perestroika mall Hettie Artists Uncle 11.25 beliefs weakening arched Could mask beach Father TPA skin mass mast parody Fran presently chief mare dream hints agencies mark temptation Exterior comes mart fountain Son Soo administration senior trough issue Milwaukee attribute carpets achieve coroner disadvantage magazine Griffith controls TNT details borrowings farms temporarily woo won 42.5 judgments Road reversal brains Delaware vision Finland tense replacing jams America Antonio maps address big-time special Matthews fundamental Boesel battlefield need Knife using 800 fish amazement brethren West Giant outflow missing Room Orchestra Productions Lucien Forces ordinary laughs heaviest creative Emma carving worthless attract smoke Hewlett-Packard doubted blocking Richfield sociologist Doaty smothered salmon fist 8.7 8.9 8.8 pretrial civilizational examiner horrible cereals trouble division missile Barton examined Rome wet Tariff INDUSTRIES thorough streaming firm dictatorship o'clock web guerrillas Institution fire louder Were Student Employers wealthy Carbide Panamanian vendors accords methods behalf proves considerable proven losing Nevertheless Maude trembling who stained volatility Armco theories opinion proved 13.1 13.2 populated 13.8 grave 13.4 13.5 switching 13.6 investigations Trotter considerably Pharmaceutical general-purpose near circulating Frederick neat Iran-Contra abolished murders anticipated Hesperus combinations reflection Instead neck anticipates understanding purchase former Concord fits throw area style wonderfully circulation wit formed Freedom taxpayers fragment Armed 850 five desolate program-trading capable win Popular reflecting message 15,000 mission arrival handkerchief visits why natural-gas Tisch Kageyama paragraph mystique Dalkon Rowe Miriam TCI Sam overstate youngest Ages woes 880 knife ring creating services tying Outside regulator loving provinces Hastings Well Cologne flurry thwart Prieur crumpled caller different Panisse creation Brodie pertinent recipes manifest influence allegiance voice-activated closet closes closer Weil bewildered neon boomers detailed closed decliners radical similar Germans Say Glass Roth floated San 24-hour bluff 1.8470 musicians plowing residence persistent Birmingham ripe furnishings choked Germany defeated bombers Khan Enron nomination subtle Ross Veterans Rosa programmers 1.8485 Research Rose divisive champion wiping liked issued Peruvian detectors issuer manufacture issues likes called procreation Agency clear-cut Week accomplish wax way profitably 20.125 estimating believe war snoring was ESPN abandoning risk army naval driven rise arms driver drives hopeless Aichi 24.9 Clay audience 18.95 profitable communists Generally mains threatens Waxman wad opposing spurred reeling wood arts Technical McKinley Rourke vs. intercourse forward Eugenia lifted Rex Rey wool Slater READY bullets Rev Providence Omaha flair Papa-san 4,000 constraints copyright vessels moonlight brunt proceeding coming Cavalry SHV professors rigs chanted breakfast stayed next whirling Three digital abruptly twenty-four voters utilization Haas Given enforced Senators Samuel convictions hair appliance surprises incinerator hail irons flags steadied news rift surprised passenger Foothills SKF McDuffie irony Gibby agree breadth Hahn squat dreams scrawled inner candidate SDI muddy vue woke scores gender electricity Congressmen Ray reactors redemptions Afrika scored coffee SEC 9,000 size salesman reforms United roads Sanford result opposite credit-card nets cocktail definite overwhelmed stagnant animal misrepresentations functions reluctance Red nest Cancer liabilities resume notebook squad Nancy grain operations raged harvest middlemen employees quarterly flash via doubling Beecham clutching avoiding Hiroshima planners authors anatomy excluded comparisons watching file 17\/32 McGill York grasp tilted exhausted Roe grass contempt Roh shocks teen-agers atmosphere Rob Rod Manitoba doubled salesmen underwritten Roy violate Brawer non-financial container Ron Aeronautics decidedly rapidly peaked trying appreciated Ends judge Dallas steadily giving gigantic desert establish quest utterly symptoms loosened clearly sector incorporates wander grant swells Devil justification fortune Agents silly ASSETS grand incorporated three regained returns characterize work worm celebrated earthy letter worn dialect videos bidders cattle heavily landmark recreational threw promote program fund-raising Africa word brush wore regulated Cawthorn 9.2 9.1 dollar-denominated 9.4 Elaine campus ride 9.9 Paterson 9.7 feared 9.8 9.5 9.6 Credit Julia Bridge contained Dixon fiercely Nobel Julie Reuter flame Winter Pentagon Genetics von 26.23 reinforced issuing defraud fine find film rice rich fill glanced engages Raymond Conway ribs outer engaged confuse 900 periods pants rattling Domestic Banking float Champion 747 time Imagine psychology speculation thereby Steel microphone mansion anatomical Sources outlets worship pocket contends lined smug protested lines malls uncle linen queer queen break-even Fitzwater prospect perceive Georgia-Pacific 27.9 namely currency Station 250,000 Whittle 27.1 coherent year-on-year Usually trousers impaired Torrio tilt Iverson indicators till Four veterans elegant tile unduly aunt majors Wheat thanked triumphantly transactions Voltaire competent booze qualify distaste crumbled bounce diminished appointed 30-day strengthened 700 reckons scramble Wednesday Whitehead Sears materialize 7.8 7.7 vital 7.9 definitive fulfill Va. Microsoft entrepreneurial orbit damaging 12.4 frantically 12.3 12.6 87.5 12.5 12.7 prefer 12.9 guidance Skolman crunch Ariz. cooks van Field Seats negotiable songs refinancing powder insider embargo flock author Dumont alleging uncommon 7.5 7.6 7.3 7.4 7.1 7.2 complaint complains males disrupt photo planned burdened photos wider great widen money-losing planner meager genes poetry D.C. hatred Henry Winslow Whitten given unwise Keenan Lines screeching secured Rather calmed raining amusing tangled auto survivors credibility costumes debacle accident bigger Food Bryan Hernandez Medicare emphasizing polls susceptible statistical Linda visiting Aikman primitive productivity inhabitants green vendor receipts advertisement robot links Sandinistas frequent outcry hollow dishes Van method partially settle stockholder Jennie narrative snap human-rights preferably Oakes related ambivalent request useful Via monumental Relations decreased assist hunch tire Mattel panic flood unscathed Results scrambling panel tiny Athletics explore personalities nonsense erode flashy 30-year speculative Fort lunged building borrowing 750 Texaco gives Ford Location impending scraped inherited Daffynition provision WHO profits dentist fitted mentally Heiser weeklong tips Congressional satisfied exposing checks yellow electoral downturn Contel hairy Comsat approved drilled hairs high-interest lovely Supervision fourteen elements Juanita offerings assembled politicians Prosecutors Lawyers propane contents Steve attendance drafting colleagues entities variables Dorrance hamper individually conscious professor Susie packet Quotron delightful 13\/16 use difficult sinking agreements 1970s Marshall Matsuo Steinberg Colgate goodness approves LIBOR Yellow backlogs plentiful Accounting handful fights feeling pennies B.A.T Jess prime-time nerves supposed Garry auditors hindered science GRAINS preoccupied Noxell vessel tells prudent 18.65 submitting triggering liking Atlas Bogart shapes modified percentages failure Debate third-quarter True tapping Wilder concluding shaped lobbyists packed taping contested setting ranging seizures Marks Stern inspire profile thus Computers approval cabinet gasped exploit Motors English natives expecting unit fishermen changing CenTrust potato reacted Marin Mario Guzman ties brokerage milling 1105 understands Engineering Matson income briefly Grafin gathering downward loyalty nights therein 8.3 8.2 platform 8.5 million 8.4 8.1 Berlitz relaxing Trig Bottom warrants mainframe Maria stopped Susan warranty tied Use Cubans convent Garth Seabrook criticized secure Club Dallas-based furrow Taxation remarkable tide takeovers advancing phony overheard remarkably characteristics promoters Cemetery tick Gibson compiled Theodore radio income-tax roaring Japan phone Westinghouse bothered asbestos undo barred enable frightened radar Partlow discernible attitudes specialized explode Lieutenant IFAR specializes year-ago loudly carriage Stein Power literature chose angered middle-aged barren injured formal hiding Arias Brazil Waertsilae Rothschild equity-purchase Following 200,000 Conasupo barrel highest convert insiders descending Philippine March affair receptor Television beginnings choking invite Lodge Nashua definition Machine Yamaichi Mexican Gansevoort pipes Jews myths municipal started hesitation lawn Nelson Prices budding Mitsukoshi supports accounting explained contemplate Dodd Utilities Two 600 principal laws sealed slow Contra Aviation violating 6.8 Nothing choke Chuck 6.9 Jean converting Parker withstand stringent requested colleges bond-equivalent review maneuvers Gamble peak Argiento Wilbur limbo Chestman sufficiently Violetta investigating unveil evening logistics checking targets clouds allies Scientific limbs perjury gains lazy peas Anheuser anti-abortionists award abroad aware Amira Fernandez comfortable Nikkei comfortably would future consisted approximately soared Stearns critics stress Wathen bedroom Source 11.7 differently 11.8 Dogs doing polished slug 11.5 bonus 11.4 Finding dread disk-drive straight Resources taxation slacks clothing Treasury intentions dealing adapt financially sister 6.2 6.3 6.1 stationed 6.6 6.7 knocked 6.4 6.5 defendant disciplined Oliver uniform makes maker swung stimulate Insurance Does meeting aiming dripped aborigine street rights Giorgio vested blaming rested Dole ticket pleasant Backer limit helicopter sentencing Hoelzer Dearborn flew yelled Sharpshooter fled Monica Ekstrohm Pfizer rumored attorney VAX O'Banion diplomats breeze punishment interval eleven flared capitalists wound Montero chicken principle massage solve anytime flights FUNDS wakeful banner parlor immune absolutely pages Octel mourning appearing banned lard telling German cease-fire revisions prowess last Bonds atop sometimes respects carpet resembles Marsh Pierce regularly Russian participation phrase lash investigation 6,000 mandated Bakker flaw Grosse flat unchanged Pitney Jeff Jeep flag late tub attendants eastern citizens Klein lawyer brakes Sunday Marty colorful copper farmhouse participating 57-year-old Fifth Cities inability extent seemed bargaining Leipzig sexual bondholders Shopping extend violation fabrication buoyed 650 nigger human two absorb Carlos interviewed resembled summary Freind Stockholm chatter Stock urgency Where Holden baseball humor McKinney Philip homeland option urges books Aeroflot shied trend Eurocom Superfund Mass. Adm. windows devaluation When investigate urged lobbying Canada forestall floor leading sponsors undertaking recommendations scuttled shaving try assumed shrewd rebels sensational Atlanta-based Canaan Wilmington assumes data Medicaid calmly Posner date Warner-Lambert arms-control entrance witness The hired earthquake-related Thi widow 1960s older hires Wisman confinement intersection League over-all Information replace expense dash showroom inventory Goodman laid Tim Kohlberg respect hurdles instructions attend lobbyist Vogelstein destined Arthur attacked happily dark beeper swallow Milpitas gripping dare collapse Beauclerk four-year-old alternative listings architect unpleasant reader Prospect Chung toe co-chief spree rocky land turtle observations Merchants pedestrian toy Technologies undefined ton rocks too top Adds lenses Macneff illusion agricultural Mason needed months flour Lung lamp slew blankets shift sergeant investing sinister engineered tie Grigorss saloon strewn shine tin Lloyd maintaining tip UPS championship filled center chancellor slim vacant patrols damp lugged slid vehicles toothpaste armed insurer Too Coca-Cola Top Tom alert awkward rewards damn Declaration Toy disagree concrete booth flows adjuster record insured promptly trees reserve boost buddies unfairly adjusted boasts ratings Shafer 10.5 budget 10.6 might 10.3 10.4 10.1 10.2 Olivetti 10.8 UV-B reviewed dwelling Austin US$ presumably 30-share campaign Luis boots diplomacy spray Snow speaker slip USX endowed awake slit 7\/16 darling Bill USA Aluminum spirit soybean USI Cadillac ten Try meanwhile pioneer five-cent What rounds haunted tea impact Kent dedicated candles civilians Mobile Founding closed-end shirt Walnut Lilly antiseptic 7\/32 Metall Deputy lack labs default await hunting subjective monetary treat Suppose draped Kemp prompted mornings Florio order Innopac recoup appellate Holding Hollander ships slot lagged Aristotle backgrounds the flamboyant grounded ending Gerry bronze classroom Runkel scratched helplessly blonde fortunes administrator cluster lady inhabited Andersson plastic institutional Volkswagen incurred U.K. answered pleading celebrity deputy ribbon Ala. generation B.V. asset troubled told Utility Plymouth toll authorities troubles wherever Buffalo dynamic promoter tomb truce moral horns truck Quick renamed piers promoted grew smiled Norman whack ignore muster tone injunction illegal suffer smiles taking bureaus hard-disk licensing expertise short-lived legend library advice resources fancy Bang-Jensen exception tool took self-conscious infected first-quarter policies marrying Blue Reynolds hesitated internationally priority tony plaster stating motion tons streamlining tensions involves U.N. tops station leisure narrowing criticism overalls Dorfman massacre mistress Russell involved polyps Ratners refunds treasury Democratic grab connect horse UBS-Phillips Goldsmith Carolina hacker disturb Nuovo knelt Alar Alan peasant dismayed cellar disruptions Simmons Nogol gray torn amusement shelters tore peace nursing lower Shareholders liability distributions Fleischmann village wholesale bones preamble tanned BRIEFS bonds health astonishing Wild Marlin Worldwide Will doubtful branch incompetence upon turmoil scattered uncovered Economists disclosing trivial Lufthansa Village MeraBank express decision brandy 10,000 425,000 brands destroyed Interest eventual endless painter Rainbow Picop boosting toes suggestions kronor 300-day clears freed Empire shortages swiftly truly Herman Christ Akzo Schwartz entered timetable shave sisters exceeds petrochemicals aimless writes writer penalty younger darkness motion-picture characterized painted clothes hand-held philosophy Odeon finger trunk diminishing Cobb involving surveys elevated greeted Citizens manipulate Coal disease grip enduring grin grim recital sight airwaves grid develop upside poker generating paradise regrets tears poked looked Conrad naked swinging succession writings maintain flow coated exactly Appropriations designers movements signs Laura nowhere laugh MGM\/UA part-time reasoned pricings Taipei mergers teams system innocence documentary deadline buddy day-to-day lies earns armor advise Coda Finnish intensify Code Control Foreign lackluster life significant graduate truth worked worker Alma Quist Murray Cody trust guerrilla Garden Mahfouz 4.25 works Quite reliance lied Fidelity subsidies Would artificially historian Bronner fabled world Bradstreet Quint Col. Sergeant Stephen become 4.75 Golden 13,000 Goupil necessarily Reflecting Buckley drawings decades Brussels considering Barclays demand exclusively indexes Coke Also tourism battled Penny tourist Daewoo Quina Hyde Furthermore Maxwell Giffen battles early discretionary ailing softly attempt fleets spared indirect performance tapped successive mercy Rate monitored delivered nervously Cable Erich bending vacated personally seven high-risk disdain artistic cable-TV Soviets birth Savings Bankruptcy imply After sadly reform carbon performing Conn industrialized grove Sept. topic aborigines like relieve U.S. Hitler grown unexpectedly Rosen Cook travelers outside reminder Fernando link constantly grows line Edythe Apogee 4.92 words Cold reminded Cole citing maintains glowed limp flip write-offs applying dissident donations Alex inventories signaling Come CORP jumped Alec Keep tour horror afterwards Rank plight pungent honestly Rand habits anchor delaying function contributing Corr Corp budge Merck outperformed yearly Ohio expenditures Pioneer soften dwarf lowering softer dogged lift town Pinnacle gross desperation parked Spencer Yield amassed noisy Geely drilling chimney healed Eyes students sixteen Upham indignant desperately grievance fools York-based teach noise richer Kean toys group Cos. freedom featured University racked located ingenious contribution features Commodore intact Victoria moving cleaned companies SOYBEANS two-tier fighters cities cleaner Transport bankruptcy explain acquisitions microprocessor Details ocean handling plucked naive Twenty lasts debris programming Accepted Planning cookies warnings materially minicomputer Duke shortage keyboard Allstates announcement compliment postponed Baird blocks talked wilderness hedging elderly mushrooms warrant Contras stupid impossible Duff turnover Beyond hosts deceased paying Vienna tenants longtime subdued agent refugees bastard tooth recalls Glenn coarse Equitec carrying arguing catching Resolution consolidate D.T. Aside protesters dimension Edwin Malcolm doubtless concert scorn stations Movieline collar concern marines score persist bizarre stealing birds council sexy curtailed Perlman weekend selections cradle inhibit sexes worth branches unavailable ecological Studies wagons sculpture Asian Texans semiconductors launching Virgin Blumenfeld sworn Hoffman pumped spectacular clippings merge Common capitalistic hammer mired apparent allowing CNBC unpredictable cooking Earthquake scout bombs Their Sloan LYNCH kindly 39,000 Polish supporters qualified Cypress replacement cause testament Fitzgerald industrywide Devices permit Vickers beloved shipping Music sets chattering faults undemocratic mentioning favorites academy describing mother Corp. conventional half-breed Milton Market release overcapacity William mining parity concept Pearson scope becomes suffered real mutually considerations Southwestern read apples colored insider-trading Orange rehabilitation abstract Rights swelling worst coach rear reap Benjamin merit worse away Scowcroft sprang sophistication remained Corps worry heavens cleanup Vietnamese These Corry receiver Seventeen received playwright ACCOUNT Fighting France admission receives Fruit Messrs. happen white-collar piece granting disturbance differed shattered Annualized There Components Isaac Wis. centerpiece Posted fellow Imperial pesticides invitations common offensive daughter desks Ciba-Geigy worlds estimate resulting Circus Summers whenever With direct impersonal arriving Okla. absence later hampered vegetables aftermath Franco falls decrease caffeine-free questionable abrupt drought commit hovered instance Wine hitting TRUST household associates willing traffickers charming Rankin associated Ehrlich Weekes Selkirk Michigan Video clutched crossing humble Thornburg memorable activists circles Vesole complete companion clutch Specter tractor Shortly outstanding watchers endlessly ominous rein circled expanding recovery benches outdoor grow service Melloan claim swore ledger selfish wrists venerable corrupt conceal colonial false weather rubbing Bloc prevent Hudson ceremony applause superpower soldier bicycles criticize Latin Policy nails language Carpenter unconsolidated long-term dreamed Rates separated Along probe Ventures Rated agreeing rent knees contracts Lawrence Police Please high-pitched Advancing concede rely ankle fella Alfred Hungary Broad distinctions directory Earlier summit directors Diana spontaneous filings renew transformed Majority tools Postal halfway Diane ACCEPTANCES complicate Dunn class northern winning urgently ambassador Later Phil unravel Venezuela rest machinists clash scratching C.J. Stanford Albany outweigh baked coast Brody high-technology triple coalition Grenfell Christie Hancock tortured gesture coats Genetic Highlands a.m T-bills skipped Stevenson Nashville entry renewing tentatively Consequently crumbling desktop resale creates smoked Rapid Cincinnati ironic subway compared Mercedes-Benz created sympathy salary Kurzweil compares Staff nickname immigrants Legal respectively overcast SciMed developing-country Bristol-Myers borrowers Deltec bit foil sloppy Wheeler urge nephew Gilborn sick Boies bin big muzzle counterparts drove installed 12-year interested 2\/32 concerned side reassured Cooper bastards 4.875 Alley keys graduates burning Shannon invest picks mortality Allen strongly precise melancholy Laband Polaroid deregulation visible Wally hinted Hungarian Florida Utsumi Drew planet graduated Side perspective Quayle planes Stacy Perrin Burmah Visa colors crack Wildlife foes utter bleached destroying sign gotten Jane serving sigh obtained salami Kodyke measure near-term exercise annuity balls invent statements built-in packing Average nation-state facilities Macklin double-digit recognizable Tenn. taller undermined starvation Jan. forge saloons Allan nuclear motives patience tenure Stocks box youthful bow boy Aaron refined vibrant Jake overhead awesome desperate bookings nullify raider Rebel aided 1,000 diagnostic Having ban final bag career Herbert hopes Cambodian bad Dominion Nature aides prone mistakenly Jastrow bay siege hoped colony Pemex bat Lauderdale bar foam Plan Manic unbroken tropical proof holidays cartoons Toronto-based normally gossip supported dimensions butt hiring denies kept enthusiasm 156.7 beautiful exceed denied exclude brings scuttle complied fantastic dioxide force fishing closely finds slopes tougher indefinite Within Pendleton difficulty Denny neighbor Jackson Manuel disturbing buzz exact House required beg bed fines incomes enter Wales maternal requires depressed roller-coaster notorious fined on-site bet peeled Greenberg enchanted prose husbands Football surely Realist meaningful Educational quick 40.1 Chicago Fargo roller contracted prosecutions vacuum bid revenue denial businessmen Shevardnadze added rolled embarrassed propelled condemned Jamaica Carroll four-year buys Education cracks objectives competitive proud consistent energy Spelman R.J. Funding Sens. snapped yourselves interruption tumbled impeccable integrate prove heads Heavy Computer Procter bunk quiet Mamma registering Charles temple goin colonel Donaldson Toubro smoothly Class Todman crane Vincent Shapiro complex priests Sherwin financiers R.H. plants sought bump modernize 62.5 Clara businessman Metal moons proxy Clark Airlines golf gold OFFERED site unfortunately deter R.I. bull bulk indications Kleinwort sits bulb writers unload waiters bouncing bust busy good coaches metal vagina Drug Navy bush closest modeled incorrect irresistible leather crash Automotive contractor electric incompetent bury diplomatic gone humans narrowly refugee five-year leaders economic difference Bong syrup tremors Lybrand Bond Bonn burn coffin immediately car cat overbuilt tangible can cap Beatrice children Nate cab Ching advancers arose petition celebrating Imports homely China triggered naming Costa killings budgetary Completion pullback lured reference wrecked Century freight Trecker celebration Treaty pistols somewhat competition electronics underwriters craft Mixte predictable imperial Municipal mechanism Strange Peltz Child baskets Chile insane Jazz bugs Jason perilous enrollment thereafter quivering disclose obstacles Born Carolinas Bork Avenue heights vodka planning Arabia Book annualized reeled London-based outline Fathers buds Auvil non-profit smoothed Quantum eaten shouted opera silk prelude Lyford mail-order romantic Jayark Comair friendly vaults Kentucky bug improving Drexel but Charlie bus buy introduce Duclos raising existential used resident longer gown admired Lipton situations sins connection tongue stronger longed narrowed sink Skyros picture stabilizing nutrition stories sing stretch hourly relatives exposure Bible appalled connecting quirt auctioned movies boredom calling ruining Gavin Chien tones Chief narrower Both funding beginning demanding Sinyard excitedly foremost oxen opens inheritance quite Energy uses kidney user fledgling fragrance courtroom intensity entertain failing panting Washington-based departed government Louisiana exporters Lolotte promised mood causal supplying pragmatic sagging projects blowing independently aim explicit promises Reserves retain air embraced Threlkeld retail mold raise exclusive marched exercises Morris aid embraces Hutton zing rewarding attempted repeating oddly Compaq left sheep sheer painting sheet shutdown exercised intensive Tesoro prescribed shah dapper chocolate Reno cocoa Rep. Newman legs casino ago discrepancies tightly illuminated Satellite dwell rails tactical disturbed chilly Lynn Alabama 50.3 exploring spinning Hurricane choosing any dubbed cost-of-living Figures Presidents seeing bundled willful strictly public-relations lent lens samples and Besides Wachter Fiscal diversification phase Institute lend Nomura sensation existing integration generally nicely prints appeared Nekoosa all quaint houses studios yields speed Brokerage Orthodox shed reckon topics housed racial declaring margins workout Reed Montpelier gallons legislature cured hurdle activities hospitable regime Lyondell move Deseret proponents Frankfurt Temple prostitution ruble committee committed spreading bites reputable month oversight Dreyfus Corporate Canelo region Others reportedly dominated emancipation most Shelley workplace utmost commuters patients Troubled quarters southwest widened curbs CPAs Kan. assurances Sydney entitle drying Times crawl prevailed illustrate aggravated violin additional ambiguities bitch sometime earth scholar Kane accountability studies Ready caused more relaxed age crimes value Tony affidavit spell lover loves scream attributable loophole Facilities chloride backlash Cray ceramics Gulf Lionel Robinson expressions studied approvals matching representing unexplained dominates thoughtful causes levy Touche moon Convenience ethics Gargan add masseur Napoleon playing resentment materialized achieved expelled crazy panels Schwarz Asked Purdew spent ads lest less double-A those dependents dispose loved ace customers devil mahogany spend felony tighter meadow tighten Grace suspected act lets cosmetic billings Christies normalcy Lauren polyethylene Laurel Rorer elevator lingerie veteran Obviously suburban redcoats upgrading buggy rushed Lambert toad strips owns choice robbed reasons Seeing personal racing blamed Goldman axe ability bipartisan Katz vocal RATE Jack induce blames settlement Gruberova reassurance Acala seconds string stripped Freud keen Kate frighten Russia Harbors brokers keep afford Seoul proliferation Kerry Prof. bloated outright Christian General anti-abortion Bennett Deacon Presidency dessert leery establishments finish Real homeless Town Stark militia Read Azoff 17,000 impeachment faintly Managua Byron Lawson forthcoming Seward shut Midler StatesWest four first-half confession defense sincere bankruptcy-law accord Rebs leftist tankers Byrne forty protects insistence Cambodia State restrained mighty praise increasingly grades momentary forth countryside shell Thanksgiving Trading relax Indonesia Publishing restraints dealer circular are billion-dollar Somehow initiated Failure shelf arm occasions fork form eased exclusion Waiting art Assistant revamping sturdy fort surged Randolph Brooks disproportionate ask Luzon ship 1-2-3 personal-injury stranger mode typical sections outrage money fore Fremont acquire centered mock apt Hotel insurers Mickey owes point doomed bank-backed devise shaken exceptionally owed luxury-car outsiders shop supervisors foot gyrations show three-year shot fool dismal aggressiveness shoe except Kremlin Leading sunlight food left-hand Gladdy Hohlbein Palmer favors philosophical lousy informing testimony excess ass fixed-price racketeering fond actuality Ethiopia fresh ate forms Marriott Connaught folk Ortiz Yields Boise fold Western Nicolas enforcers Cruz realization shortcomings negative occur bureaucrats That Tampa refining angrily Short lukewarm ingredients Stevens dripping movement bought borders B'dikkat Among LBOs essential texture deadly Safeco Intelligence paradox touch codes psyllium attacks array justify Jenrette Shops fantasy Jenkins epicenter tragic demanded classes AIDS hazard Delhi prospects tasted Communications bivouac refinance tastes Pete appalling designing moves precedent stemming consumer Acquisition consumed kicked Fireman George Someone taboo Inspector execute Fried Monmouth pickup watch beverages yesterday canvas fanfare Comex sluggish rattle rays frenzy tumbling often linking tough constitutional ideological hepatitis cumulative sweater justice Pinkerton through frozen Hyundai Peru classic population testified bubbles layer Merieux equal destiny Fairfield Della moved relations peers fixed-rate dense 1\/4 1\/8 Barrett workings novelist honey Madden permitted rank social rang recently empty reset rand 1\/2 nations Nikko accelerate differentials Register apprehension Republic assortment hoarse burglary bounced AZT Mahler McFeeley antique waiver retired Penn Euro distance rolling awaiting riding fiction rape note Quebecor water vintage faith movie incapable Maggie Nugget unknown Claudio sympathies nose patch Packwood apply disappears Newton newest furniture where chemicals correspondent indicted postpone rare announcing proceed wonder none litigation Pedersen Eduard administered patents nonperforming Gardner shipments detectives countless humiliation clambered arrangement Apart Shield Randy Fisher apple restore speculated turbines investment-banking expansion noon Delta Pulley subjected circle northeast unfair guided rate paths November Tobacco Colonel Competition premature economically Commercial fourth-quarter slowing entertainment balanced rash identification spread 16,000 technique faint leasing limited Boveri scar Gratt temperature basically yeah Capone year chaos selling Safety Richardson observes Seagate observed furor travels unspecified dangers attic bureaucracy plaintiffs fails HyperCard chase exclaimed slower substance viability Bobby chickens blindly slowed emergencies sentimental picket franchise mound Flying borough teens charm ABC ABB sticky picked hikers controllers mount transplants Vancouver sticks towering gardening chart newspapers garden ABM begging escaped Tandy adopted Monday Thor Thom ordinance ranch Therefore successes mouth Adams forest tactics stared binge subsidiary engagement regulate quarter advent valid Interior currencies mouse socks addicts Includes overlook whispered Peck granite Refcorp Rev. engineer Paxus Peat Southam fragments Northrop clarity performances surface articulate revolution vigorous towards guys elsewhere mill revision significance ringing accepted 190.58-point know-how milk mile mild alleviate Perry tissues sideline Joseph Students teeth Rural Antar protesting bubble collectors soldiers probable jungle conclusion massages Odds Management range B-2 Grand plead This escape foolish mink attitude Criminal Grant genuine starting probably mine mind billions engaging authorized slowly embarrassment divestiture mildly rests mint Linden confidence Science process chair really jitters chain successfully Francisco Gramm indifference jittery Queen goodwill offshore Coniston obstacle AMR courage AFL-CIO ghastly accelerated scripts tribunal AND ANC Southeast Sells charcoal contradiction Laboratories coward commented ranks Gonzalez faltered yell crimson They presentation thick Hampshire afflicted Then Amoco apartments Island opponent quota rattled Caterpillar Ferdinand quote suitcase volunteers terrifying inflation-adjusted goals beside County enlarge dropping shoulder costume thief maneuver miss assisting mist total photograph fret vetoed shipment privileges pesetas free search Stanley Walitzee Mack discharge repaired discrimination comeback whispering basement unnecessary parent Capital Savaiko Macy Alicia Made editor Third scenario Mirage instrumental adventures seating privileged burgeoning divorced computer Vegas poised Isabella thigh Quinlan discarded disguised locations blasted refund converter statesmen convincing desires Goldberg monopoly sand sang Nguyen Marlowe anxiety converted reminiscent desired sank cautiously highs insufficient 100-share altered possession Segundo fray Morse publishers constructed curiously same completion sleeves Italy profited pause suspicion affairs half-dozen Darman dealerships claims think winding Johns handicap sale similarity merits Altman flies thing salt Menlo mumbled sake intangible Nazi lawmakers unprecedented longstanding Main monitors Horse Chiefs questioning Superior Watson Mail overruns sides two-year completing restoration objection happening proposes reservations proposed technicians redemption cavalry Sachs tanker evasion curb Chemical relieved cure delinquent says tumultuous Customs mayoral forgetting hears Calenda heart measured third discount anti-drug Bicycle measures abandon Oct. glossy Housing unexpected Hardly heard buck Machines unconstitutional dollar cuts Reproductive Pennzoil Philadelphia consecutive hoofs socially machines chemists Boeing differ Shaw proposal healthy Letter negligence miners personal-computer save integrity illustration NCAA chromosome pitching refuge barriers mice buffer buffet Marous developing certainly objective Thus toppled heavy operate Western-style Thelma Think proteins Boyd stumbling Hebrew Shea Boys from anthrax longer-term durable hurried prestige Protestants Honduras alligator supportive prevail Metromedia dwellings between Gallery commanded twists disclosures governors important conversations intent ambition departing commander hidden Langford merging themselves intend found shippers rage floating-rate assure phenomenon unlocked Matt dying preparing shortfall Tire multinational honor undermine Hawkins conditioner astronomy Combustion Mass 5.25 complain split face wheel Nearly prohibit surrounding gunmen survive motor Monsieur possess drowned zero-coupon cult Washington factor snack Renault Docherty Ship Egypt billing exaggerated fact subsided prompt 100,000 minor rake Vila served Interstate Sports platoon Craven alley dissolved remodeling Airbus slavery Semel cellular Connie inherent certainty dispute billion poison lavender steelmakers medium-term vicious commercials Arkansas killing devoted raid Containers Doyle onerous tube prosecutor classified supervising bucking compulsion over-the-counter exotic knight facility emotions rail Heinz rain disposition Gordon consent powerhouse cups Freeman Franklin muscular misconduct waters Suisse supporting touching drops serves specifically skills waste chunk marble Lawmakers LATE whiskey 19th sober supervision disorders Ever uneasy fail directories Even youngsters prevention NCNB shuddered satire preventing housing hideous Show minister Conner table Shop create fair Roper titanium experimentation Series Pharmaceuticals snail cried earthquakes Make position Mann qualifications pressed encouraged settlements Aoun Many Intermediate cargo Manu diseases Switzerland character minds daytime Time dates presses long-distance fake aging Southern policeman cowboy briskly delays Conn. acknowledges Owners Vice saint suspended Brands secretary cares snake industrial article acknowledged fall strapped Styka Burke diplomat Mama Litvack preclude 5.75 separating rack race Retirement cared fame internally prosecuted undeveloped positive Initial cards mines Fritzie Capitol discover dated tune A-Z Serial clerk conditional encourages fighting Sioux efficient overboard 5.94 intention allow Mary Marx fans Mars recent View Mark officer offices Producers readings Bobbie Marc perfect lists wheat photographic Ocean separation moderate Payne woods Bunker nonetheless continue industries assume Burns buckled portray Remics participants joined Neal chewed spacecraft Memories Union neighbors Jerusalem Midwest smooth realities Cutler affirmative Work Piepsam callers Somebody diabetics scenes recognize lived ensure member scholars waves court-appointed low-sulfur nerve Sterling Houston-based standards register compensation utility Neb. waved introduced Colombian Castro formulated dialogue firms Larry fate kiss founded terminal diversion Bros. invasion overall devote deteriorated Hammack trains founder Very yearning Seita convicted detached cream weakness rally rising disorder accustomed names fast Joint insurance named 400,000 Bronx slashing evidence implies S&Ls fare volumes afloat pro-democracy fast-growing farm Baltimore creek buzzing implied Pittsburgh trails Enforcement BellSouth winners anniversary constant lessons indictments worthwhile Christmas thousand obliged sparked RATES caring scented presentations politely Sadie aggregates stroke convey Wilmer Trust shirts provoked Worse consists Wolf mentions carry holes thwarted entering dispel distribution Every unofficial creep Price Worth Gelbart uncanny huddled flopped 19.95 holds apron pardon getting ministry aspects England clear carts accomplishments clean guiding 26-week Holiday John-and-Linda waiter reactionary diversity unfavorable waited distinctly Lipper stroll Andy Neil closing stated Cuba Rootbeer fired Although gunfire fires Carson schools family anticipation copying loyal argument asking minus consist paved Yorker besieged Wood depth condemn discourage strong aircraft Trustcorp engulfed lives liver invade encouragement startled page-one feeding writing McDonnell Ptolemaic Brown Ivory ferroelectric six-month seal Administration automatically 40,000 Freddie Appeals Southmark Toshiba Sidley Comptroller Hollywood notwithstanding rendering Maidenform Fresenius motel anticipating punishable convenient generations licked Terry responsive BPCA blueprint distributing forecasts hearts complaining inevitable uncertainties less-developed lungs manage hung seas seat bomber hunt tarnished Murphy along commission alone bread-and-butter reviewing Brokers static Signal waiting short-term Anne unnamed U.S.A. sizable tangle inevitably inward Beach Maine examples fertilizers territory Association strode states captain consortium lengthy license Dassault International crept Willis holder recapitalization Trump plaintiff seed feathers seen seem material fitting seek Prime continuity Governor 66.7 Decker cousins actress harmful turbine Prior News meantime frontier trucks unbearable curbing sees comply lunch arrangements select Shanghai explanation Terms planets world-wide twirling Fortunately crest lifting grenades expectation -LCB- suspects troop Harbor Asarco federation marking nationalism fabric opium thrust regular percentage camera maturities WHEN regional Nev. Rockwell person reducing deficit 50-50 Gaubert detailing Carter calculated Wachovia existence ever-present Institut pledged tree Pepsi casting aspirations musician heels low-cost Things Maier crews Bernstein flushed Planned curtail inappropriate forefront curtain huge specter Ryder logical Nadir Dozen funeral Arabs trembled overtures countrymen improvements Coors mailing anarchy Seng chartered recommended self mortgages impulses fairly switches exceptions sell capacity stranded aloud prospective uncertain switched cases Ralph bogus resuming periodic Specialized Edward Next Feeling freeing prison nickel calculates glowing 1.875 allowed one-fourth casserole send Tiger ghosts Unice drawer Anta beaches sent timbers painters line-item Rally Sen. Roman utilities Curt penetration Business status 3\/32 plunge Negotiable trap seized biography disappointed junior sullen statue season tray Today proprietorship wearily Prize stiffened passionate inflict penetrating Balzac Inside devoid safer temperatures troubling Lowell detect advisers merchant merger metaphor inquiries gaining cigarettes aching Petrochemical first merged controlling retreating revelation heated adopting savings-and-loan parcel invented heater brow tremor Thatcher achieving Norwegian Bradford stress-related entertaining Patrick sympathize Nabisco Silver hospital introduction Central seated laundering guns leave Arafat disastrous River relationships ministries spirits adoption wearing Cowboys Commission retailers sounded starts lagging exists Blatz successful maintained Hawthorne guts Coffee successor housewives fiscal However least closings Strong Alto revealed spite disposing Henderson Mountains distressing committing conduct pasture unlike legendary Ramey realty cheated seldom consequence forced depths financial imprisoned bishop reward outlook unfamiliar learn Quest forces posting lease Shaefer Finnair mobile remember compounded trusted airplanes inferior correction 19.6 Gregory 19.7 gubernatorial trustee bargains lounge trip trim refusing treacherous Telesis eroded ounce upward Anheuser-Busch Mosbacher emotional bottoms Seth sovereign Addison employment automobile determine depressing Before lire Since heritage Parsow espionage futures spiritual repay confirmation 13.50 convinced monthly reality depression intensely pressing Blair Great biting simplicity thinking rebounded lips financier commercially revealing reporting sellers Twelve development politically Blake Morrison streamline spire department-store semiannual internal realism ideas lion partisan schemes blooming distorted Amen subsequent ideal developments harshly true Amex Antarctica players Ludie detective realize Ortega fraud military directions middle-class poems earliest 190-point imbalances Taiwanese Traders Futures homer homes credit grounds Kevin live fleeting amortization spill balloon Dayton liquid huts Greek Green apologized adjusting potatoes improve Broderick throwing Phillips Blinder continuing mineral 20-year suspect underwriting customary Edelman Circuit envelopes Motor list p.m. section hurt Donuts Camden slump Medicine Stadium corners earmarked villages Underwriters ragged 1970 1971 financing nine-month 1972 Krasnoyarsk subsidize 1973 1974 1975 brutality 1976 1977 1978 occurring 1979 signature stiffly compost 1990 originated 7,000 1982 1983 1980 1981 1986 1987 metric 1984 1985 independence virulence 1988 1989 shade chewing Hanford trends silent frank Major 550,000 Deukmejian trendy Works 1995 1996 1997 leads ambitions 1998 1991 1992 equation shady Broker 1993 1994 Kodak reply rallies earned franc World 1999 extremely reverse territorial judges employ shaft Discovision Karipo judged Mount pillows bran Puerto asleep unprofitable kick portable unconcerned somewhere payout student ordering connections UNESCO Alice however Falls rallied maintenance respectability kids physically frame 2-for-1 bucks widely Several Simms aftershock enormously repel cracking inquired clumsy liquor foreign-exchange existent Rice Rick Rich perception catch breakup widens Amid Rica incomplete brooding commissions Garcia hoping cross-border NATO Department conflicts Hunter bred inched responded wonders bikers NASA inches Simon success Zion tariffs Linear poultry Harrison imposing shake audiences Meridian brew Knight Leigh-Pemberton shaky Rico 1900 topping bargain Dresdner 1906 shall ambitious 1908 fence Steven creditors greatness frail reaction shame hesitate collaboration Ohbayashi reviving hospitality Parliament launch encountered tumors momentarily king quarreling kind version disputes Exchange command disputed labeled 1920 Bros figured brim jealousy Large cater reacting 1927 gloves figures research shouting Beverly Executives 1935 1939 Jefferson clearing kill fists 1930 glared Valdez woman hazardous per-share 1947 1946 1949 researchers leaks outperform languishing tripled criticisms shape 1943 1942 Stevie Flannagan Officials fingerprints headline 1959 1958 1957 direction lawsuits 1953 undertake presumed 1952 1951 Chinese 1950 miniature share knowledgeable elbows printers Casualty stresses skinny Negroes directing environmentally 1967 sharp 1966 1969 1963 1962 1965 flapping stressed inventor women 1961 1960 Czechoslovakia hedge massive popping decisive districts fiduciary claimed apache-opennlp-2.5.12-src/opennlp-tools/lang/en/tokenizer/en-detokenizer.xml0100644 0000000 0000000 00000005161 15217274217 027445 0ustar00rootroot0000000 0000000 " ' . ? ! , ; : ( ) } { ] [ `` '' % n't 've 'd 'll 's 're 'm .org .com .net # apache-opennlp-2.5.12-src/opennlp-tools/lang/es/abb_ES.xml0100644 0000000 0000000 00000010461 15217274217 023627 0ustar00rootroot0000000 0000000 a.C. a. de C. a.J.C. a. de J.C. a. m. apdo. apdo. aprox. Av. Avda. Bs. As. c.c. cap. D. Da. Dña. d.C. d. de C. d.J.C. d. de J.C dna. EE. UU. etc. f.c. F.C. FF. AA. Dr. Dra. Gob. Lic. Ing. Pdte. Pdta. p. pág. n.° no. núm. p.ej. p. m. Prof. Profa. q.e.p.d. S.A. S.L. Sr. Sra. Srta. Ud. Vd. Uds. Vds. vol. v. lu. ma. mi. ju. vi. sá. do. en. febr. mzo. abr. my. jun. jul. ag. agt. set. sept. oct. nov. novbre. dic. dicbre. apache-opennlp-2.5.12-src/opennlp-tools/lang/es/parser/es-head-rules0100644 0000000 0000000 00000002722 15217274217 025650 0ustar00rootroot0000000 0000000 13 SENTENCE 0 PREP SP[CS].* CS.* GRUP\\.VERB S SA COORD CONJ GRUP\\.NOM SN S 12 S 0 PREP SP[CS].* COORD CONJ CS.* GRUP\\.VERB S SA GRUP\\.NOM SN 22 SA 0 NC.*P.* GRUP\\.NOM \\$ NC.*S.* SADV GRUP\\.ADV AQA.* AQC.* V[MAS]P.* V[MAS]G.* SA S\\.A GRUP\\.A AQS.* SN GRUP\\.NOM D.* S RG RN 21 S.A 0 NC.*P.* GRUP\\.NOM \\$ NC.*S.* SADV GRUP\\.ADV AQA.* AQC.* V[MAS]P.* V[MAS]G.* S\\.A GRUP\\.A AQS.* SN GRUP\\.NOM D.* S RG RN 20 SADV 1 S RG RN SADV GRUP\\.ADV SP[CS].* PREP Z.* AQA.* AQC.* S\\.A GRUP\\.A CONJ CS.* SN GRUP\\.NOM AQS.* NC.*S.* 8 SP 0 SP[CS].* PREP CS.* CONJ V[MAS]G.* V[MAS]P.* 20 GRUP.A 1 NC.*P.* GRUP\\.NOM \\$ NC.*S.* SADV GRUP\\.ADV AQA.* AQC.* V[MAS]P.* V[MAS]G.* GRUP\\.A AQS.* SN GRUP\\.NOM D.* S RG RN 18 GRUP.ADV 0 RG RN GRUP\\.ADV PREP SP.* Z.* AQA.* AQC.* GRUP\\.A S\\.A CS.* CONJ SN GRUP\\.NOM AQS.* NC.*S.* 23 GRUP.VERB 0 INFINITIU GERUNDI PARTICIPI PREP SP[CS].* V[MAS].*[IS].* V[MAS]P.* V.*C.* V[MAS]IP3S.* V.* V[MAS]G.* V[MAS]IP[12]S.* GRUP\\.VERB SA S\\.A GRUP\\.A NC.*S.* NC.*P.* GRUP\\.NOM SN S 5 INFINITIU 0 VMN.* V[MAS]N.* V.* 5 GERUNDI 0 VMG.* V[MAS]G.* V.* 5 PARTICIPI 0 VMP.* V[MAS]P.* V.* 6 MORFEMA.PRONOMINAL 0 P.* SN.* GRUP\\.NOM.* GRUP\\.VERB 7 MORFEMA.VERBAL 0 GRUP\\.VERB P.* SN.* GRUP\\.NOM.* S 9 COORD 1 CONJ CC.* RB RN SP[CS].* PREP CS 16 INC 0 S SN GRUP\\.NOM GRUP\\.VERB SADV GRUP.ADV SA S\\.A GRUP\\.A PREP SP[CS].* CONJ CS D.* 3 INTERJECCIO 0 I 3 NEG 0 RN 6 PREP 0 PREP SP[CS].* CONJ CS 7 RELATIU 0 P.* SN GRUP\\.NOM S GRUP\\.VERB 2 SPEC 0 2 X 1 apache-opennlp-2.5.12-src/opennlp-tools/lang/fr/abb_FR.xml0100644 0000000 0000000 00000014746 15217274217 023641 0ustar00rootroot0000000 0000000 a.m. auj. av. bât. bd. c. c.-à-d. ch. chap. co. coll. dép. dir. Dr. e. éd. etc. E.U. ex. fam. fr. géo. gén. hist. hôt. H.S. i.e. incl. inf. int. l. lt. M. M.D. M.D.R. m. math. mai. min. Mlle. Mme. MM. mn. Mons. mq. M.S. M.S.G. M.S.I. M.S.M. M.S.P. M.T. M.T.P. n. nb. N.D. N.D.L.R. N.S.F. O.N.U. P. p. p.d.g. p.ex. pl. p.m. prof. préf. R. R.A.S. r.d. R.D.F. R.F. R.P. S. s. S.A. S.A.S. S.C.I. S.D. S.D.F. S.D.N. S.E. S.E.C.A. S.E.I. S.G.D.G. S.G.M. S.G.P. S.G.S. S.G.T. S.G.T.P. S.I. S.I.E. S.I.L. sing. S.L. S.N.C. S.N.C.F. S.N.E.C.M.A. S.N.I. S.N.L. S.N.P.C. S.N.P.L. S.N.R. S.N.T.F. S.N.U.A. S.N.V. S.N.X. S.O.S. T.S.F. T.T.C. U.E. V. W.-C. C.G.T. C.I. C.N.I.L. C.N.R.S. janv. févr. avr. juil. juill. sept. oct. nov. déc. apache-opennlp-2.5.12-src/opennlp-tools/lang/fr/tokenizer/fr-detokenizer.xml0100644 0000000 0000000 00000011637 15217274217 027464 0ustar00rootroot0000000 0000000 " ' . ? ! , ; : ( ) } { ] [ `` '' % L' l' D' d' S' s' N' n' C' c' m' J' j' T' t' Z' z' Qu' qu' Ma' ma' Jusqu' jusqu' AUJOURD' Aujourd' aujourd' Lorsqu' lorsqu' Puisqu' puisqu' Presqu' presqu' Prud' prud' Quelqu' quelqu' Quoiqu' quoiqu' dizaï' Optim' Demak' Automobil' s ex- # apache-opennlp-2.5.12-src/opennlp-tools/lang/ga/abb_GA.xml0100644 0000000 0000000 00000005130 15217274217 023564 0ustar00rootroot0000000 0000000 tel. Mr. Mrs. .i. Uacht. m.sh. lch. lgh. Dr. uimh. Co. gCo. tUacht. Uas. tUas. Msc. Ms. Sr. Jr. Bros. fig. Jan. Feb. Mar. Apr. Jun. Jul. Aug. Sep. Sept. Oct. Nov. Dec. Ean. Fea. Már. Aib. Bea. Mei. Iúl. Lún. M.Fr. D.Fr. Sam. Nol. Ltd. Teo. apache-opennlp-2.5.12-src/opennlp-tools/lang/ga/tokenizer/ga-detokenizer.xml0100644 0000000 0000000 00000005371 15217274217 027422 0ustar00rootroot0000000 0000000 " ' . ? ! , ; : ( ) } { ] [ » « `` '' % .org .com .net # - m' d' b' mb' dh' lem' apache-opennlp-2.5.12-src/opennlp-tools/lang/general/tokenizer/special_char_dict.xml0100644 0000000 0000000 00000004442 15217274217 031156 0ustar00rootroot0000000 0000000 „ â€� “ » « " ' . ? ! , ; : ( ) } { ] [ `` '' % # apache-opennlp-2.5.12-src/opennlp-tools/lang/it/abb_IT.xml0100644 0000000 0000000 00000057100 15217274217 023642 0ustar00rootroot0000000 0000000 a.c. ades. all. Amn. Arch. Avv. Bcc. c.a. C.A.P. Cc. c/cbanc. c/cpost. c.c.p. Chia.mo c.m. Co. c.p. C.P. C.p.r C.so corr. c.s. c.v. Dott. Dott.ssa Dr. ecc. Egr. Egr.i Egr.ia e.p.c. es. fatt. F.lli Gent.mo Gent.ma Gent.me Gent.mi Geom. g. gg. Id. Ill.mo Ing. int. Jr. lett. Mo. Mons. N.B. n. ogg. on. p. pag. p. pp. p.c. p.c. p.c.c. p.f. p.r. P.S. p.v. P.za P.T. Preg.mo Prof. Prof.ssa R. racc. Rag. Rev. ric. Rif. RP. RSVP. S. S.A. S.acc. S.B.F. seg. sgg. ss. Sig. Sigg. Sig.na Sig.ra Sig.ra sig.na s.n.c. Soc. S.p.A. Spett. S.P.M. Sr. S.r.l. Stim.mo tel. u.s. V. V.le V.P. v.r. v.s. ab. abbigl. abbrev. abl. a.C. ac. a.c. acc. accorc. accr. adatt. a.d.r. aeron. aerodin. affl. agg. agr. agric. alch. alg. alim. allev. allus. alt. anat. anat. comp. ant. antifr. anton. antrop. ar. arald. arc. arch. archeol. aritm. arred. art. artig. artigl. artt. assic. assol. astr. astrol. astron. att. attrav. aus. autom. avv. avvers. bal. ball. batt. bibl. bioch. biol. bot. bur. ca. cal. cap. capol. card. caus. c.d. c.d'a. centr. cfr. chim. chim. ind. chir. ciber. cin. citol. class. cod. civ. cod. pen. cod. proc. civ. cod. proc. pen. coll. com. comm. comp. compar. compl. conc. concl. condiz. confr. cong. congiunt. coniug. consec. contab. contr. coop. corr. correl. corrisp. cost. costr. cristall. cron. cuc. c.v.d. d.C. dat. decoraz. denom. deriv. derm. determ. dial. difett. dimin. dimostr. dipart. diplom. Dir. dir. Dir. Amm. Dir. Can. Dir. Civ. Dir. d. lav. Dir. internaz. Dir. it. Dir. pen. Dir. priv. Dir. proces. Dir. pub. Dir. rom. disus. Dott. Dr. eban. ebr. ecc. etc. eccl. econ. econ. az. econ. dom. econ. pol. ed. edil. edit. egiz. elab. elettr. elettron. ellitt. embr. enclic. enigm. enol. entom. epigr. es. escl. estens. estr. min. etim. etn. etol. eufem. f. fam. farm. ferr. fig. filat. filol. filos. fin. fis. fisiol. fisiopatol. folcl. fon. fotogr. fr. fut. g. gen. geneal. geod. geofis. geogr. geogr. antr. geogr. fis. geol. geom. germ. giorn. gr. gram. ha. ibid. icon. id. idraul. ig. imp. imper. imperf. impers. ind. indecl. indef. indeterm. inf. inform. ing. ingl. ins. inter. intr. invar. iron. irreg. is. istol. it. ittiol. l. lat. lav. femm. lav. pubbl. lett. ling. lit. loc. loc. div. long. macch. mar. mat. mater. max. mecc. med. mediev. merc. merid. metall. meteor. metr. metrol. microb. mil. min. miner. mitol. mod. morf. mus. n. n.a. neg. neol. neur. nom. numism. oc. occ. occult. oculist. od. ogg. oland. onomat. op. ord. ord. scol. oref. orient. ornit. orogr. ott. p. p.a. pag. pagg. pp. paleobot. paleogr. paleont. paleozool. paletn. papir. parapsicol. part. partic. pass. patol. pedag. pegg. per.ind. pers. petr. petrogr. pitt. pl. poet. pol. popol. port. poss. pr. pref. preist. prep. pres. pret. priv. prof. pron. pronom. propr. prov. psicoan. psicol. qlco. qlcu. qualif. radiotecn. rag. rar. recipr. reg. region. rel. rem. rep. retor. rifl. rit. rom. scherz. scien. scult. sec. secc. seg. segg. sigill. sig. sigg. simb. sin. sing. sociol. sogg. sp. spett. spreg. S.S. st. stat. st. d. dir. st. d. filos. st. d. rel. suff. sup. superl. tav. tecn. tecnol. ted. tel. telecom. temp. teol. term. tess. tipogr. topog. tosc. tr. trad. trasp. ungh. urban. v. val. veter. vezz. voc. vol. volg. voll. zool. zoot. apache-opennlp-2.5.12-src/opennlp-tools/lang/ml/MaxentQNTrainerParams.txt0100644 0000000 0000000 00000003002 15217274217 026711 0ustar00rootroot0000000 0000000 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Sample machine learning properties file Algorithm=MAXENT_QN Iterations=100 Cutoff=0 # Number of threads Threads=1 # Costs for L1- and L2-regularization. These parameters must be larger or # equal to zero. The higher they are, the more penalty will be imposed to # avoid overfitting. The parameters can be set as follows: # if L1Cost = 0 and L2Cost = 0, no regularization will be used, # if L1Cost > 0 and L2Cost = 0, L1 will be used, # if L1Cost = 0 and L2Cost > 0, L2 will be used, # if both paramters are set to be larger than 0, Elastic Net # (i.e. L1 and L2 combined) will be used. L1Cost=0.1 L2Cost=0.1 # Number of Hessian updates to store NumOfUpdates=15 # Maximum number of objective function's evaluations MaxFctEval=30000apache-opennlp-2.5.12-src/opennlp-tools/lang/ml/MaxentTrainerParams.txt0100644 0000000 0000000 00000001541 15217274217 026460 0ustar00rootroot0000000 0000000 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Sample machine learning properties file Algorithm=MAXENT Iterations=100 Cutoff=5 apache-opennlp-2.5.12-src/opennlp-tools/lang/ml/NaiveBayesTrainerParams.txt0100644 0000000 0000000 00000001526 15217274217 027255 0ustar00rootroot0000000 0000000 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Sample machine learning properties file Algorithm=NAIVEBAYES Cutoff=5 apache-opennlp-2.5.12-src/opennlp-tools/lang/ml/PerceptronSequenceTrainerParams.txt0100644 0000000 0000000 00000001556 15217274217 031044 0ustar00rootroot0000000 0000000 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Sample machine learning properties file Algorithm=PERCEPTRON_SEQUENCE Iterations=300 Cutoff=0 apache-opennlp-2.5.12-src/opennlp-tools/lang/ml/PerceptronTrainerParams.txt0100644 0000000 0000000 00000001545 15217274217 027351 0ustar00rootroot0000000 0000000 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Sample machine learning properties file Algorithm=PERCEPTRON Iterations=300 Cutoff=0 apache-opennlp-2.5.12-src/opennlp-tools/lang/nl/abb_NL.xml0100644 0000000 0000000 00000015141 15217274217 023633 0ustar00rootroot0000000 0000000 a.d.h.v. afd. afk. afz. a.h.w. a.g.v. a.j.b. a.m. a.s. a.u.b. Aanw.vnw. Abs. Achterv. betr. bijv. bijz. blz. bv. b.v b.v.d. ca. c.q. c.s. d.a.v. dhr. d.i. d.m.v d.m.v. dr. drs. d.w.z. d.z.z e.a. e.c. e.d. e.e.a. etc. e.v. e.v.a. evt. excl. fam. fig. Fr. Gr. Grs. H.M. Hert. Hr. i.c.m. id. i.e. i.g.v. i.h.a. i.h.b. i.h.k.v. i.i.g. Inf. Ing. Inz. i.p.v. ir. i.v.m. i.z.g.st. Kymr. Kzr. Lgrs. m.a.w. max. m.b.t. m.b.v. mevr. m.i. min. m.i.v. m.n. m.v.g. m.u.v. Mr. n. Chr. n.m.m. nr. o.a. o.b.v. o.m. opm. o.v.v. Onz. Orth. r.k. p. pag. p.k. p.p. prof. prof. em. resp. t.a.v. t.g.t. t.g.v t.h.t. t.o.v. t.w. t.z.t. Uitdr. v. v.Chr v.h Verdr. Verg. Versch. Vorst.d. jan. feb. mrt. apr. aug. sep. okt. nov. dec. ma. di. wo. do. vr. za. zo. apache-opennlp-2.5.12-src/opennlp-tools/lang/pl/abb_PL.xml0100644 0000000 0000000 00000006176 15217274217 023647 0ustar00rootroot0000000 0000000 br. cd. cdn. dn. godz. itp. itd. jw. m.in. min. np. nr. pt. r. tj. tzn. tzw. ul. dr. dyr. lic. mgr. p. p.o. prof. pon. pn. wt. wto. Å›r. Å›ro. czw. cz. piÄ…. piÄ…t. pt. sob. so. nie. niedz. ndz. stycz. mar. kwiec. czerw. lip. sierp. wrzes. pazdz. listop. grudz. apache-opennlp-2.5.12-src/opennlp-tools/lang/pt/abb_PT.xml0100644 0000000 0000000 00000356731 15217274217 023674 0ustar00rootroot0000000 0000000 a. a.al. a.b. a.c. a.c.e. a.d. a.h. a.m. a.m.a. a.m.d.g. a.p. a.r. a.s. a.-s. a.t. a.u.c. a.v. a.v.c. aa. ab. ab.e abc. abis. abissín. abl. abr. abrev. abs. Ã¥bs. absol. abstr. abus. ac. acad. academ. acadêm. acc. accel. acep. acepç. açor. acus. acúst. ad. adag. adapt. adit. adj. adj.2g. adj.2g.2n. adjet. adm. admir. admr. adv. adv.º adverb. advoc. aer. aerof. aeron. aerost. aet. aetat. af.o afér. afl. afls. afor. afr. afric. afrolus. ag. ág. ag.to agl. agn. ago. agr. agric. agrim. agrol. agron. aj. aj.te al. alat. alb. alent. alentej. alf. alfaiat. álg. alg. algar. algv. alm. alm.-esqdra alm.te alop. alp. alq. alquil. als. alt. alt.-al. altan. alter. altern. altit. alto-al. alus. alv. alveit. alven. am. am.a am.o amár. amer. an. anál. anal. anam. anarq. anat. and. anes. ang. angl. angl.-sax. angol. anim. anôn. ansp.a ant. antec. antig. antiq. antol. antôn. anton. antonom. antr. antrop. antropogr. antropol. antropon. antropôn. anu. ap. apart. apênd. apic. apl. apóc. aport. aportg. aportug. aprox. apt. apt.º aq. ár. ar. ara. aráb. aracn. aram. arb. arboric. arc. arc.o arcaic. arceb. arcebd. arcip. arcipd. ard. arg. arit. aritm. aritmol. arm. arq. arqueol. arquid. arquip. arquit. arr. art. art.o artes. artesan. artilh. artíst. aru. as. ascet. asiát. ásio-lus. asolus. asp. asp.te ass. assem. assemb. assim. assist. assoc. ast. astr. astr.f. astr.f.pl. astr.m. astr.m.pl. astrol. astron. astrôn. astronáut. astroním. at. át. at.o at.te ativ. atl. atlt. atm. atôm. atom. atr. atual. atualid. atualm. au. aum. aus. austr. austral. aut. auto. autom. automat. aux. aux.o av. aven. aviaç. avic. ax. axiôn. b. b.a. b.-art. b.-artes b.b. b.eis b.el b.f. b.i.d. b.-lat. b.-letr. b.m. b.o b.t.u. b.v. bact. bacter. bacteriol. bal. balíst. bált. bar. bárb. basq. bat. bbl. beir. bel.-art. beng. berb. bíb. bíbl. bibl. bibl.f. bibl.m. bibl.m.pl. bibliof. bibliog. bibliogr. bibliol. bibliôn. bibliot. bibliotec. bibliotecon. biblog. biblol. biblon. bilh.e bim. bimen. biodim. biofís. biogên. biogen. biogeo. biogeog. biogeogr. biogr. biol. biom. bioq. bioquím. biot. biotip. biotipol. birm. birrel. bisp. bispd. bitr. bitrans. bm. boêm. bol. boliv. bomb. bor. bord. borg. borr. bot. br. bras. brasil. bret. brig. brig.o brit. brom. bromat. btl. bud. búlg. bur. burl. buroc. c. c.a.a. c.ág. c.-alm. c.b. c.c. c.com. c.d. c.de c.dessa c.el c.g.s. c.h. c.i.f. c.ia c.-riq. c.ta c.v. cab. cabo-verd. caç. cad. caf. cal. calç. cálc. calcog. calcogr. cald. calig. caligr. calor. calorim. calv. calvin. câm. can. canad. canal. canaliz. cant. cap. cap.ão cap.m.g. cap.-ten. capac. capit. capix. caps. capt. car. card. carn. carp. carr. cart. cartogr. cast. casuís. casuíst. cat. catal. catar. catarin. categ. catol. catól. catolic. catóp. catópt. caus. causal. causalid. cav. cav.o cb. cc. ce. cear. celt. célt. cên. cenog. cent. cênt. centr. cer. cerâm. cerv. cest. cet. cf. cfr. ch. ch.b. ch.e ch.m. chanc. chancel. chap. chapel. chil. chin. chul. cia. ciber. cibern. cicl. cid. ciênc. cienc. cient. cig. cin. cineg. cinem. cinematogr. cing. cinol. cinz. cir. circ. círc. circunscr. cirurg. cit. citol. citt. cl. clas. clás. cláss. clich. clim. climatol. clín. cm.g* cob. cód. códs. cogn. col. col.º colet. colomb. cols. com. com.dor com.e com.or comb. combin. combinat. combust. comdor. comend. comerc. comp. comp.e comp.t compar. compl. compr. compt. comte. comunic. côn. con. côn.º conc. concess. concret. cond. conf. confed. confeit. confl. confls. cong. conhec. conj. conjug. conq. conquil. conquiliol. cons. cons.º consel. conselh. conseq. const. constel. constr. cont. cont.dor cont.or contab. contemp. contr. coord. cop. copul. copulat. coq. cor. coreog. coreogr. corog. corogr. corr. correi. corresp. corrup. corrupt. corrut. cos. cosec. cosm. cosmog. cosmogr. cosmol. cost. costa-ric. costa-riq. cot. côv. cp. cr. cr.a cr.º créd. cresc. cresc.te crim. criminol. cript. criptog. crist. cristal. cristalogr. cristand. cristian. crôn. cron. cron.f. cron.f.pl. cron.m. cron.m.pl. cronol. cronom. cronôn. crust. cruz. ctv. cu.ft. cu.in. cu.yd. cul. culin. cult. cump.to curt. cut. cutel. cv. cvs. cx. cyat. d. d.ª d.a. d.b. d.c. d.c.c. d.-cm d.e d.g. d.p. d.r d.ra d.v. da. dactilog. dactilogr. dactilos. dactilosc. dad. dasim. dat. dd. dec. decl. declin. decor. decr. decresc. ded.o def. defect. defin. definit. del. del.t dele. dem. democ. democr. demog. demogr. demonstr. dens. dep. depr. deprec. deps. der. deriv. derm. des. des.dor des.or desc. desemb. desemboc. desen. desin. desp. despor. desus. det. determ. dev. dev.º dez. dez.º diác. dial. dialet. dialét. dic. did. didát. diet. dif. dig.mo dim. dimin. din. dinam. dinâm. dioc. dipl. diplom. dir. disc. disfem. diss. docs. docum. dog. dogm. dogmát. dól. dom. domin. domín. dór. dr. dr.a dr.as dra. dram. drav. drs. dual. dualid. dur. dz. e. e.a. e.b. e.c. e.c.f. e.d. e.e.m.p. e.e.p. e.f. e.g. e.m. e.-m. e.m.p. e.n.e. e.r. e.r.m. e.s.e. e/s. ecd. ecl. écl. ecles. ecol. econ. ed. edd. edif. educ. ee. efem. egíp. el. el.s. el.s.f. el.s.f.pl. el.s.m. el.s.m.pl. elem. eletr. eletrodin. eletrol. eletrom. eletrôn. eletrot. elipt. em.ª em.mo em.mº emb. emb.or embal. embr. embriol. emigr. emol. emp. empír. empr. emprés. enc. encícl. encicl. end. endoc. energ. energét. enf. eng. eng.º enol. ens. ent. entom. entomol. enx. epig. epigr. epíst. eq. equat. equit. equiv. ergol. erud. esc. escand. escoc. escol. escolást. escr. escul. escult. esgr. esl. eslav. eslov. esot. esp. espec. especialm. especif. específ. espect. espectrogr. espel. espeleol. espet. espir. espirit. espiritual. esport. esq. est. estad. estat. estatíst. estenog. estenogr. estereogr. estét. estil. estim. eston. estr. estrang. estrangeir. estrat. estratég. estrem. estrut. estud. et. et.m.pl. etc. etim. etimol. etióp. étn. etn. etnog. etnogr. etnol. etnolog. etol. euf. eufêm. eufem. eufon. eufôn. eufor. eur. ex. ex.ª ex.ma ex.mo excl. exclam. exclamat. excurs. exe. exérc. exp. exper. experim. expl. explet. explor. explos. export. expr. express. expression. ext. extens. extrat. f. f.adv. f.aport. f.d. f.e.m. f.m.m. f.nom. f.º f.o.b. f.ºr.º f.os f.ºv.o f.paral. f.parl. f.port. f.r. f.red. f.s.a. f.v. f.verb. fáb. fac. falc. falcoar. fam. farm. farmac. farmacol. farmacop. fasc. fascs. fauv. fed. feder. feit. fem. fen. fenom. fenôm. fer. ferrad. ferrov. feud. fev. fev.º ff. fg. fig. figd. figur. figurat. figurativ. fil. filat. filol. filos. fin. finl. fís. fis. fís.-quím. fisc. fisioc. fisiocr. fisiocrat. fisiol. fisl. fispat. fitog. fitogr. fitol. fitopat. fitossoc. fl. flam. flex. flor. floric. fls. flum. flumin. fluv. fm. fo. fog. fol. folc. folcl. folh. fols. fon. fonét. fonol. for. form. fórm. formul. fort. fos. fós. fot. foto. fotoan. fotoanál. fotogr. fotom. fov. fr. fr.-maç. frânc. franc. freg. frenol. freq. frig. frut. fs. fss. ft. ft.p. fulv. fund. fut. futb. futeb. futur. g. g.al g.de g.m. g.-m. g.m.t. g.p. gaél. gal. galic. galv. gar. gasc. gaul. gav. gen. gên. geneal. genét. genov. geo. geod. geof. geofís. geog. geogn. geogr. geol. geom. geomor. geomorf. geon. geôn. ger. germ. gin. ginást. ginec. ginecol. gír. gliptog. gliptogr. gliptol. gliptot. gloss. glót. glotol. gn. gnom. gót. gov. gr. gráf. graf. grafol. grafosc. gram. grav. grd. groen. groenl. gt. guar. guat. guatem. guin. gutt. guz. h. h.c. h.cont. h.i.s. h.j.s. h.mod. h.n. h.p. h.p.-h. h.sag. hab. hag. hagiog. hagiogr. hagiol. haplol. hast. hebd. hebr. helm. helmin. helmintol. hem. heort. heort.f. heort.f.pl. heort.m. heort.m.pl. heortôn. her. herál. heráld. herb. herd.o herp. herpét. herpet. herpetogr. herpetol. het. hib. híb. hibr. híbr. hibrid. hidr. hidrául. hidrod. hidrog. hidrogr. hidrol. hidrom. hidrost. hidrot. hier. hier.f. hier.f.pl. hier.m. hier.m.pl. hierôn. hierosolim. hig. higr. hind. híp. hip. hipiat. hipnot. hipnoter. hipoc. hipocor. hipol. hipót. hipot. hisp. hisp.-am. hisp.-amer. hisp.-lat. hisp-ár. hist. histol. historiog. historiogr. hol. hom. homeo. homeop. homof. homog. homogr. homon. homôn. hon. hond. hort. hortic. hot. hotent. humor. húng. i. i.d. i.e. iat. ib. ibér. ibid. iconog. iconogr. iconol. ict. ictiol. id. id.q. idiot. idol. idolol. igr. il. il.ma il.mo ilum. ilus. ilusion. ilustr. imigr. imit. imp. imper. imperat. imperf. impes. impess. import. impr. impres. impression. improp. impror. in. inc. incoat. incóg. ind. índ. indef. indet. indian. indiv. indoch. indon. indost. indum. indust. indúst. inf. infan. infant. infer. infin. infinit. infinitiv. infl. inform. ing. ing.-n.-am. ingl. ins. inscr. insep. inst. instit. int. integr. intens. interamn. interj. interjet. intern. internac. interr. interrog. interrogat. intj. intr. intrans. inus. inv. invar. invariav. invenç. invest. investig. iog. ir. iran. iraq. irl. iron. irôn. irr. irreg. isl. islam. island. isr. israel. it. ít. ital. itál. italian. iug. j.d. j.r j.z jam. jan. jan.o jap. jard. jardin. jav. jaz. jes. joalh. joc. jog. jorn. jr. jud. jul. jun. jur. juris. jurisp. jurispr. just. k.o. l. l.c. l.da l.do l.l.b. l.l.d. l.n. l.º l.p. l.q. lab. labor. laborat. labort. lact. lâm. lanç. lanc. lap. lapid. larg. lat. latit. latoar. lb. leg. lég. legisl. légs. leit. let. lex. lib. lic.do lig. lim. lin. líng. ling. lingüíst. líq. lit. liter. literal. literat. litog. litogr. litol. litt.d. lituan. litur. liturg. liv. livr. ll. loc. loc.s. loc.v. log. lóg. logar. logíst. lomb. long. loq. lr. lt.da ltd. ltda. ludol. lug. lund. lunf. lus. lusit. luso-afr. luso-asit. lut. luv. m. m.ª m.a.-al. m.al m.alt.-al. m.b. m.ço m.d. m.d.c. m.e m.es m.esa m.f. m.kg m.kg* m.kgf m.lle m.m.c. m.me m.mo m.º m.or m.-q.-perf. m.q.perf. m.t.s. m.ta m.to maç. maçon. mad. madeir. mag. magn. magnet. magnit. mai. maiúsc. maj. maj.-brig. mal. malab. malac. malacol. malai. malg. malh. mamal. man. manuf. maomet. map. máq. maq. maquinof. mar. mar.g. maranh. marc. march. marchet. marg. marin. marinh. marn. marr. marroq. martin. marx. masc. mat. matad. matem. mater. material. matogros. mato-gros. máx. mct. mec. mecân. mecan. mecanogr. med. méd. mediev. medv. mem. memo. memor. mens. mer. merc. mercad. merid. met. metáf. metaf. metafis. metafór. metal. metalog. metalur. metát. meteor. meton. métr. metr. metrif. metrol. mex. mexic. mi. micol. microbiol. microfot. microg. microl. microm. microsc. microscóp. mil. min. mín. miner. ming. minh. minúsc. mist. míst. mit. mit.f. mit.f.pl. mit.gr. mit.m. mit.m.f. mit.m.pl. mitol. mitôn. mk. mm. moag. mob. moçamb. mod. moed. mon. monog. monogr. mons. mont. montanh. mor. moralid. morf. morfol. moto. mov. mr. mrs. ms. mun. mús. mus. mus.b. mus.d. mus.h. museol. n. n.b. n.e. n.n. n.n.e. n.n.o. n.n.w. n.o n.º n.o. n.obs. n.p. n.p.loc. n.p.pers. n.pr. n.r.p. n.s. n.s.p. n.sr.a n.ss.p. n.t. n.w. nac. nap. nat. natur. náu. náua. náut. nav. nav.fl. naz. neerl. neg. neo-ár. neoguin. neol. neolog. neozel. nep. neur. neutr. nicar. nicarag. nig. niger. nob. nobil. nom. nom.-acus. nor. nórd. norm. normat. nort.-am. norueg. notic. nov. nov.o num. núm. numis. numism. nutr. o. o.d.c o.d.c. o.k. o.n.o. ob. obed. obg.mo obr. obr.mo obr.o obs. obsol. obst. obstet. oc. ocean. oceanogr. ocid. ocul. ocult. odont. odontol. of. ofid. oft. oftalm. oftalmol. olig. onç. oneol. onom. onomást. onomat. onomatop. op. opp. ópt. optat. or. orat. ord. ordin. org. organiz. orig. origin. orign. orn. ornit. ornitol. orog. orogr. orôn. ort. ortogr. ortográf. ortop. ostr. otorr. otorrin. otorrino. our. ouriv. out. out.o oz. p. p.a p.ae. p.al. p.b. p.c. p.c.c. p.d. p.e p.e. p.e.f. p.e.o. p.ex. p.ext. p.f. p.f.v. p.h. p.i. p.j. p.l. p.m. p.m.e. p.m.o. p.m.o.m. p.m.p. p.n. p.n.a.m. p.p. p.p.s. p.per. p.r. p.r.j. p.s. p.v. pa. pa.g. pag. pág. pagg. págg. págs. pal. paleob. paleog. paleogr. paleont. paleontol. paleoz. pals. pan. pan.-amer. panam. papel. paq. par. pár.o paraens. parag. paraib. paral. paran. paras. parassint. parl. parn. parnas. parôn. part. partic. pass. passm. passr. passt. past. pat. patol. pátr. patr. patr.f. patr.f.pl. patr.m. patr.m.pl. patron. patrôn. paul. paulist. pç. pça. pdl. pec. ped. pedag. pediat. pedol. pedr. pej. pel. pent. peq. per. pér. perf. perfum. períf. perífr. pern. pernamb. pers. pérs. perspect. perspectiv. peruv. pesc. pesq. pess. pet. petr. petrog. petrogr. petrol. petroq. pf. pg. ph.b. ph.d. piaui. piauien. picar. píl. pint. pinx. pinx.t pirot. pirotec. pirotéc. pisc. piscic. pizz. pl. planej. plat. pleb. pm. pneu. poes. poét. pol. políc. polin. polít. pop. popul. port. porto-riq. posit. poss. possess. pot. potam. pov. pp. pr. prác. prát. prec. preced. precis. pred. predic. pref. pré-hist. prep. prepos. pres. presb.º presc. presid. prest. pret. prev. prim. primit. princ. princip. priv. probl. problem. proc. prod. prof. prof.ª prof.as profis. profiss. profission. profs. prom. pron. pronon. pronún. propag. propos. propr. pros. pros.f. pros.m. prosc. prosôn. prost. prostét. prót. prot. protest. protét. protoc. protoz. prov. provav. provb. provç. provc. proven. provenç. provinc. prox. pseud. psic. psican. psicofisl. psicogn. psicol. psicopat. psiq. psiquiat. pto. pts. pub. public. pug. pulv. px.t q. q.b. q.do q.e.d. q.g. q.-g. q.i.d. q.l. q.p. q.s. q.s.i.d. q.ta q.to q.v. ql. qq.v. qual. qualif. quant. quantit. quart. quest. quí. quích. quím. quimb. quinz. quinzen. quir. quirom. r. r.ª r.e r.i.p. r.no r.p. r.p.m. r.p.s. r.s r.s.a. r.s.v.p. rac. racion. racional. rad. rád. radical. radioat. radiod. radiodif. radiog. radiogr. radiol. radiot. radiotec. radiotéc. radiotécn. radioter. rall. rd. real. realid. rec. rec.º recip. recíp. recípr. red. ref. ref.te refl. reform. reg. reg.º regim. region. regress. rel. relaç. relat. relativ. relig. reloj. rem. rem.te rep. repart. repert. report. repúb. res. rest. restr. restrit. result. ret. retór. retrosp. rev. rev.a rev.do rev.mo rev.o revers. rg. rib. rit. rod. rol. rom. romn. rot. rub. rum. rur. rural. rus. russ. rúst. s. s.2g. s.2g.2n. s.a. s.a.c. s.a.f. s.a.i. s.a.r. s.a.r.l. s.a.s. s.a.t.g. s.b. s.c. s.carid.e s.d. s.e. s.e.o. s.em.a s.em.as s.ex.a s.ex.as s.f. s.f.2n. s.f.f. s.f.m. s.f.pl. s.g. s.h. s.i.d. s.il.ma s.il.mas s.j.d. s.l.n.d. s.loc. s.m. s.m.2n. s.m.a. s.m.f. s.m.i. s.m.j. s.m.pl. s.n. s.o s.o. s.o.s. s.or s.p. s.p.loc. s.p.pers. s.p.q.r. s.r s.r. s.res s.rev.a s.rev.ma s.rev.mas s.rta s.s. s.s.a s.s.a.a. s.s.as s.s.e. s.s.o. s.s.w. s.t.d. s.t.l. s.ta s.to s.v. s.v.p. s.vv. s.w. sab. sac. sal. sals. sân. sâns. sânscr. sap. sapat. sarg. sarg.-aj. sarg.-aj.te sát. sb. sc. sc.b. sc.d. sc.i.d. sc.j.d. sc.m. sc.t sc.t.d. sch. scl.t scr. scrps.t scul. sec. séc. secr. sécs. sect. seg. segg. segs. sel. sem. semânt. semic. semin. semiol. semít. semit. sen. sent. sep. septent. seq. seqq. sér. ser.-cr. serg. seric. sericic. serr. serralh. serv. sérv. set. set.o setent. sf. sg. sh.tn. siam. sib. sid. sider. siderogr. siderotéc. sigil. sign. signif. síl. silog. silv. silvic. simb. símb. simból. simbol. simpl. sin. sing. sinon. sinôn. sint. sínt. sir. sír. sist. sit. snr. snr.a soc. social. sociol. sól. son. sor. sór. sost. sov. soviét. sp. spp. sq.ft. sq.in. sq.m. sq.rd. sq.yd. sr. sr.a sr.as sr.es sr.ta sres. ss. ss.aa.cc. ss.aa.ff. ss.aa.ii. ss.aa.rr. ss.aa.ss. ss.ex.as ss.gg. ss.hh. ss.il.mas ss.mm. ss.mm.aa. ss.mm.ff. ss.mm.ii. ss.pp. ss.rev.as ss.rev.mas ss.s.as ss.ss. stac. sto. sub. subafl. subafls. subdiác. subj. subjunt. subord. subst. subvar. suc. sue. suec. suf. sul. sul-af. sul-afr. sul-amer. sup. sup.e super. superf. superl. supl. suprf. suprl. suprs. surr. surreal. t. t.c. t.d. t.geogr. t.i. t.i.d. t.p. t.p.m. t.s.f. t.te t.te-c.el tab. táb. tai. taí. tail. tam. tâm. tan. tang. tanoar. taquigr. tát. taur. taurom. taxid. tb. teat. teatr. tec. téc. tecel. técn. tecn. tecnog. tecnogr. tecnol. tect. tel. tele. telec. telecom. telef. telef.s. teleg. telegr. telégr. telem. telev. temp. temper. ten. ten.-cel. teol. teôn. teor. teos. ter. terap. terapêut. terat. teratol. térm. term. termin. terminol. termod. termodinâm. termom. terr. territ. tes. test. test.o têxt. tib. tibet. tint. tip. tipogr. tipol. tir. tít. ton. tôn. tóp. top. top.f. top.f.pl. top.m. top.m.f. top.m.pl. topog. topogr. topol. topon. topôn. torp. tosc. tox. toxiol. tr. trab. trabalh. trad. tradic. tráf. trans. transit. transj. transm. transmont. transobj. transp. trat. trav. trem. trib. trig. trigon. trim. trimest. trit. triv. trop. tt. tun. tunis. tup. tupi-guar. tur. turc. turism. tv. u. u.e. u.i. u.inf. u.s. u.sup. ucr. ucraín. ucran. ult. umb. un. unif. univ. univers. urb. urban. urol. urug. us. usual. util. utilid. utilit. utop. utópi. v. v.a v.a. v.-alm. v.carid.e v.de v.dessa v.e.mas v.e.mavossa v.ex.a v.ex.as v.ex.ma v.g. v.h. v.i. v.i./cm2 v.il.ma v.l. v.m. v.m.as v.m.ce v.mag.a v.o v.or v.p. v.rev.a v.rev.as v.rev.ma v.rev.mas v.s. v.s.a v.s.as v.s.f.f. v.s.ilma v.s.s. vad. vadm. val. var. vasc. vb. vc. veg. vel. veloc. ven. ven.or venat. venez. venezuel. verb. verbal. vern. veros. veross. vers. versif. vet. veter. vid. vidr. vig. vig.o vin. vinic. viol. vit. vitic. vitr. viz. vl. vm.ce vm.ces vo. voc. vog. vol. volat. voll. vols. vox. vs. vulc. vulg. vv. vv.aa. vv.carid.es vv.ex.as vv.ex.mas vv.gg. vv.hh. vv.il.mas vv.ll. vv.m.ces vv.mag.as vv.mm. vv.pp. vv.rev.as vv.rev.mas vv.s.as vv.ss. vv.ss.il.mas w. w.c. w.n.w x. x.p.t.o. x.y.z. xenof. xerog. xerogr. xilog. xin. yd.p.sec. z. zend. zo. zool. zoot. zootec. zootéc. apache-opennlp-2.5.12-src/opennlp-tools/lang/pt/tokenizer/pt-detokenizer.xml0100644 0000000 0000000 00000004551 15217274217 027511 0ustar00rootroot0000000 0000000 " ' . ? ! , ; : ( ) } { ] [ » « `` '' % .org .com .net # - apache-opennlp-2.5.12-src/opennlp-tools/pom.xml0100644 0000000 0000000 00000013363 15217274217 021763 0ustar00rootroot0000000 0000000 4.0.0 org.apache.opennlp opennlp 2.5.12 ../pom.xml opennlp-tools jar Apache OpenNLP Tools org.slf4j slf4j-api org.junit.jupiter junit-jupiter-api test org.junit.jupiter junit-jupiter-engine test org.junit.jupiter junit-jupiter-params test com.ginsberg junit5-system-exit ${junit5-system-exit.version} test io.github.hakky54 logcaptor ${logcaptor.version} test src/main/resources true org.apache.maven.plugins maven-jar-plugin true opennlp.tools.cmdline.CLI org.apache.opennlp.tools test-jar maven-javadoc-plugin opennlp.tools.cmdline create-javadoc-jar org.apache.maven.plugins maven-surefire-plugin -Xmx2048m -DOPENNLP_DOWNLOAD_HOME=${opennlp.download.home} -javaagent:${settings.localRepository}/com/ginsberg/junit5-system-exit/${junit5-system-exit.version}/junit5-system-exit-${junit5-system-exit.version}.jar ${opennlp.forkCount} false **/stemmer/* **/stemmer/snowball/* **/*IT.java org.apache.maven.plugins maven-failsafe-plugin jmh org.openjdk.jmh jmh-core ${jmh.version} test org.openjdk.jmh jmh-generator-annprocess ${jmh.version} test org.codehaus.mojo build-helper-maven-plugin 3.6.1 add-test-source generate-test-sources add-test-source src/jmh/java apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/ml/BeamSearchBenchmark.java0100644 0000000 0000000 00000014347 15217274217 032632 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; import opennlp.tools.util.BeamSearchContextGenerator; import opennlp.tools.util.SequenceValidator; /** * JMH benchmark for {@link BeamSearch} on long input sequences. *

* One op = one {@code bestSequence} call on a synthetic token sequence of * {@code sequenceLength} tokens. Long sequences are what expose the quadratic * per-candidate outcome-list copying removed with OPENNLP-1903; sentences of * 5-10 tokens, as used by the ME benchmarks, show no measurable difference. * Only public API that predates OPENNLP-1903 is used * ({@code BeamSearch(int, MaxentModel, int)} and * {@code bestSequence(T[], Object[], BeamSearchContextGenerator, SequenceValidator)}), * so the same compiled class exercises both implementations: to produce a * baseline, place an {@code opennlp-ml-commons} jar built before OPENNLP-1903 * on the classpath ahead of the freshly built classes and rerun. */ @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @Warmup(iterations = 5, time = 2) @Measurement(iterations = 10, time = 2) @Fork(2) public class BeamSearchBenchmark { private static final int BEAM_SIZE = 3; private static final int NUM_INPUTS = 64; private static final int VOCAB_SIZE = 17; /** Seed for both the input generator and the {@link SeededMaxentModel}. */ private static final long SEED = 0x5eedL; private static final String[] MODEL_OUTCOMES = {"start", "cont", "other"}; private static final SequenceValidator ACCEPT_ALL = (i, input, outcomes, outcome) -> true; @State(Scope.Benchmark) public static class SearchState { @Param({"8", "64", "256"}) int sequenceLength; @Param({"0", "64"}) int cacheSize; BeamSearch beamSearch; TokenContextGenerator contextGenerator; String[][] inputs; final AtomicInteger cursor = new AtomicInteger(); @Setup(Level.Trial) public void create() { beamSearch = new BeamSearch(BEAM_SIZE, new SeededMaxentModel(MODEL_OUTCOMES, SEED), cacheSize); contextGenerator = new TokenContextGenerator(); inputs = new String[NUM_INPUTS][]; Random rnd = new Random(SEED); for (int n = 0; n < NUM_INPUTS; n++) { String[] input = new String[sequenceLength]; for (int i = 0; i < sequenceLength; i++) { input[i] = "t" + rnd.nextInt(VOCAB_SIZE); } inputs[n] = input; } } String[] nextInput() { // Rotate through the input pool so repeated invocations decode different // sequences instead of hammering one fully cache-warm input. return inputs[Math.floorMod(cursor.getAndIncrement(), NUM_INPUTS)]; } } /** * Derives contexts from the current token and the previous outcome, interned * so identical context content maps to the same {@code String[]} instance * and the identity-keyed contexts cache in {@link BeamSearch} produces hits. * Thread-safe. */ static final class TokenContextGenerator implements BeamSearchContextGenerator { private final ConcurrentHashMap intern = new ConcurrentHashMap<>(); @Override public String[] getContext(int index, String[] sequence, String[] priorDecisions, Object[] additionalContext) { String prev = index > 0 ? priorDecisions[index - 1] : ""; String[] ctx = {"tok=" + sequence[index], "prev=" + prev}; String key = ctx[0] + '|' + ctx[1]; String[] existing = intern.putIfAbsent(key, ctx); return existing != null ? existing : ctx; } } @Benchmark @Threads(1) public void bestSequenceSingle(SearchState state, Blackhole bh) { bh.consume(state.beamSearch.bestSequence(state.nextInput(), null, state.contextGenerator, ACCEPT_ALL)); } @Benchmark @Threads(Threads.MAX) public void bestSequenceConcurrent(SearchState state, Blackhole bh) { bh.consume(state.beamSearch.bestSequence(state.nextInput(), null, state.contextGenerator, ACCEPT_ALL)); } /** * Quick local iteration only: {@code forks(0)} disables JVM fork isolation * (unlike {@code mvn} with the {@code jmh} profile). * Use the Maven-invoked configuration for publishable numbers. */ public static void main(String[] args) throws Exception { Options opt = new OptionsBuilder() .include(BeamSearchBenchmark.class.getSimpleName()) .forks(0) .warmupIterations(1) .warmupTime(TimeValue.seconds(1)) .measurementIterations(1) .measurementTime(TimeValue.seconds(1)) .build(); new Runner(opt).run(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_jmh_java_opennlp_tools_sentdetect_Senten0100644 0000000 0000000 00000000204 15217274217 032545 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/sentdetect/SentenceDetectorMEAbbreviationBenchmark.java apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/sentdetect/SentenceDetectorMEAbbr0100644 0000000 0000000 00000020233 15217274217 034075 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.formats.ResourceAsStreamFactory; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.StringList; import opennlp.tools.util.TrainingParameters; /** * JMH benchmark for the abbreviation veto of * {@link SentenceDetectorME#isAcceptableBreak(CharSequence, int, int)}. *

* One op is one {@link SentenceDetectorME#sentPosDetect(CharSequence)} call over a document of * {@code documentChars} characters. Three variants run over the same input: *

    *
  • {@code noDictionary} is the floor, the veto is switched off entirely, so what is left is * the shared cost of scanning and of the maxent evaluation per candidate;
  • *
  • {@code legacyVeto} is {@link LegacyAbbreviationSentenceDetectorME}, which holds the * previous full-text scan;
  • *
  • {@code boundedWindowVeto} is the current implementation.
  • *
* The {@code documentChars} axis is the point of the benchmark: the previous implementation * searched the whole text once per dictionary entry per candidate, so its cost per document grows * quadratically, while the bounded window makes it grow linearly. The {@code dictionaryEntries} * axis exposes the second factor of that product. */ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 3, time = 2) @Measurement(iterations = 5, time = 2) @Fork(2) @Threads(1) public class SentenceDetectorMEAbbreviationBenchmark { /** * The abbreviations of the shipped English dictionary. They occur in the benchmark document. */ private static final String[] PRESENT_ABBREVIATIONS = {"Mr.", "Mrs.", "Ms.", "tel."}; @State(Scope.Benchmark) public static class DocumentState { /** * The document length in characters. Doubling it is what separates a quadratic veto from a * linear one. */ @Param({"12500", "25000", "50000", "100000"}) public int documentChars; /** * The number of dictionary entries. The shipped German list has 215, the shipped English one * that the runtime module tests against has 4. */ @Param({"10", "200"}) public int dictionaryEntries; SentenceModel model; String document; SentenceDetectorME noDictionary; SentenceDetectorME legacy; SentenceDetectorME boundedWindow; @Setup(Level.Trial) public void prepare() throws IOException { model = trainModel(); document = buildDocument(documentChars); final Dictionary dictionary = buildDictionary(dictionaryEntries); noDictionary = new SentenceDetectorME(model, (Dictionary) null); legacy = new LegacyAbbreviationSentenceDetectorME(model, dictionary); boundedWindow = new SentenceDetectorME(model, dictionary); } } @Benchmark public void noDictionary(DocumentState state, Blackhole bh) { bh.consume(state.noDictionary.sentPosDetect(state.document)); } @Benchmark public void legacyVeto(DocumentState state, Blackhole bh) { bh.consume(state.legacy.sentPosDetect(state.document)); } @Benchmark public void boundedWindowVeto(DocumentState state, Blackhole bh) { bh.consume(state.boundedWindow.sentPosDetect(state.document)); } /* * ------------------------------------------------------------------------------------------ * Fixtures. * ------------------------------------------------------------------------------------------ */ /** * @return A model trained on the bundled English samples, without an abbreviation dictionary, * so all three variants share one feature generator and differ only in the veto. * @throws IOException Thrown if the training samples cannot be read. */ private static SentenceModel trainModel() throws IOException { final InputStreamFactory in = new ResourceAsStreamFactory( SentenceDetectorMEAbbreviationBenchmark.class, "/opennlp/tools/sentdetect/Sentences.txt"); final ObjectStream samples = new SentenceSampleStream( new PlainTextByLineStream(in, StandardCharsets.UTF_8)); return SentenceDetectorME.train("eng", samples, new SentenceDetectorFactory("eng", true, null, null), TrainingParameters.defaultParams()); } /** * Builds a document of about {@code chars} characters that contains abbreviations at a * realistic rate, so the veto is reached often rather than in a corner. * * @param chars The minimum document length in characters. * @return The document. */ private static String buildDocument(int chars) { final String paragraph = "Mr. Smith left the building at noon. She told me he lived in Edinburgh. " + "Mrs. Clark called tel. 555 1234 and asked for Ms. Adams. " + "The driver got badly injured near the old bridge. " + "OpenNLP provides tools for natural language processing. " + "I wrote him a letter right away and posted it the same day. "; final StringBuilder document = new StringBuilder(chars + paragraph.length()); while (document.length() < chars) { document.append(paragraph); } return document.toString(); } /** * Builds a case-insensitive dictionary of {@code entries} abbreviations, as the shipped * dictionaries are. The first entries occur in the document; the rest are synthetic and do not, * which is the realistic case, since a dictionary covers a language and a document uses a * handful of its entries. * * @param entries The number of entries to produce. * @return The dictionary. */ private static Dictionary buildDictionary(int entries) { final Dictionary dictionary = new Dictionary(false); for (String abbreviation : PRESENT_ABBREVIATIONS) { dictionary.put(new StringList(abbreviation)); } for (int i = PRESENT_ABBREVIATIONS.length; i < entries; i++) { dictionary.put(new StringList(String.format(Locale.ROOT, "zq%d.", i))); } return dictionary; } /** * Quick local iteration only: {@code forks(0)} disables JVM fork isolation * (unlike {@code mvn} with the {@code jmh} profile). * Use the Maven-invoked configuration for publishable numbers. */ public static void main(String[] args) throws Exception { Options opt = new OptionsBuilder() .include(SentenceDetectorMEAbbreviationBenchmark.class.getSimpleName()) .forks(0) .warmupIterations(2) .measurementIterations(3) .build(); new Runner(opt).run(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/BenchmarkRunner.java0100644 0000000 0000000 00000001712 15217274217 033242 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.jvm; public class BenchmarkRunner { public static void main(String[] args) throws Exception { org.openjdk.jmh.Main.main(args); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_jmh_java_opennlp_tools_util_jvm_StringDe0100644 0000000 0000000 00000000167 15217274217 032527 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/StringDeduplicationBenchmark.java apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/StringDeduplicationBench0100644 0000000 0000000 00000005275 15217274217 034161 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.jvm; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.infra.Blackhole; /** * A benchmark class / setup by Aleksey Shipilëv. * Resides here to investigate performance of String deduplication approaches * on different environments. *

* Origin: * * https://shipilev.net/jvm/anatomy-quarks/10-string-intern/ *

* His conclusion:
* "Do not use String.intern() without thinking very hard about it, okay?" */ @State(Scope.Benchmark) public class StringDeduplicationBenchmark { @Param({"1", "100", "10000", "1000000"}) private int size; private JvmStringInterner str; private CHMStringInterner chm; private HMStringInterner hm; private CHMStringDeduplicator chmd05; private NoOpStringInterner noop; @Setup public void setup() { str = new JvmStringInterner(); chm = new CHMStringInterner(); hm = new HMStringInterner(); chmd05 = new CHMStringDeduplicator(); noop = new NoOpStringInterner(); } @Benchmark public void intern(Blackhole bh) { for (int c = 0; c < size; c++) { bh.consume(str.intern("String" + c)); } } @Benchmark public void chm(Blackhole bh) { for (int c = 0; c < size; c++) { bh.consume(chm.intern("String" + c)); } } @Benchmark public void hm(Blackhole bh) { for (int c = 0; c < size; c++) { bh.consume(hm.intern("String" + c)); } } @Benchmark public void chmd05(Blackhole bh) { for (int c = 0; c < size; c++) { bh.consume(chmd05.intern("String" + c)); } } @Benchmark public void noop(Blackhole bh) { for (int c = 0; c < size; c++) { bh.consume(noop.intern("String" + c)); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_jmh_java_opennlp_tools_util_jvm_StringLi0100644 0000000 0000000 00000000156 15217274217 032541 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/StringListBenchmark.java apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/StringListBenchmark.java0100644 0000000 0000000 00000002422 15217274217 034072 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.jvm; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.infra.Blackhole; import opennlp.tools.util.jvm.jmh.ExecutionPlan; import opennlp.tools.util.StringList; /** * A benchmark class to test different implementation of {@link StringList} within OpenNLP */ public class StringListBenchmark { @Benchmark public void newWithArrayConstructor(Blackhole blackhole, ExecutionPlan exec) { blackhole.consume(new StringList(exec.strings)); } } apache-opennlp-2.5.12-src/opennlp-tools/src/jmh/java/opennlp/tools/util/jvm/jmh/ExecutionPlan.java0100644 0000000 0000000 00000004254 15217274217 033516 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.jvm.jmh; import java.util.Random; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; @State(Scope.Benchmark) public class ExecutionPlan { private static final String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; private static final Random RANDOM = new Random(42); @Param({"1", "100", "10000", "1000000"}) private int size; @Param({"opennlp.tools.util.jvm.CHMStringDeduplicator", "opennlp.tools.util.jvm.CHMStringInterner", "opennlp.tools.util.jvm.HMStringInterner", "opennlp.tools.util.jvm.JvmStringInterner", "opennlp.tools.util.jvm.NoOpStringInterner"}) private String internerClazz; public String[] strings; @Setup(Level.Iteration) public void setUp() { System.setProperty("opennlp.interner.class", internerClazz); strings = new String[size]; for (int i = 0; i < size; i++) { strings[i] = generateRandomString(15); } } private static String generateRandomString(int length) { final StringBuilder randomString = new StringBuilder(); for (int i = 0; i < length; i++) { int index = RANDOM.nextInt(CHARS.length()); randomString.append(CHARS.charAt(index)); } return randomString.toString(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkSample.java0100644 0000000 0000000 00000015226 15217274217 032431 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import opennlp.tools.commons.Sample; import opennlp.tools.util.Span; /** * Class for holding chunks for a single unit of text. */ public class ChunkSample implements Sample { private static final long serialVersionUID = -3092850871020409815L; private final List sentence; private final List tags; private final List preds; /** * Initializes a {@link ChunkSample} instance. * * @param sentence * The training sentence. * @param tags * The POS tags for the {@code sentence}. * @param preds * The chunk tags in B-* I-* notation. */ public ChunkSample(String[] sentence, String[] tags, String[] preds) { this(Arrays.asList(sentence), Arrays.asList(tags), Arrays.asList(preds)); } /** * Initializes a {@link ChunkSample} instance. * * @param sentence * The training sentence. * @param tags * The POS tags for the {@code sentence}. * @param preds * The chunk tags in B-* I-* notation. */ public ChunkSample(List sentence, List tags, List preds) { validateArguments(sentence.size(), tags.size(), preds.size()); this.sentence = List.copyOf(sentence); this.tags = List.copyOf(tags); this.preds = List.copyOf(preds); } /** * @return Retrieves the training sentence. */ public String[] getSentence() { return sentence.toArray(new String[0]); } /** * @return Retrieves the POS Tags for the sentence. */ public String[] getTags() { return tags.toArray(new String[0]); } /** * @return Retrieves the chunk tags in B-* I-* notation. */ public String[] getPreds() { return preds.toArray(new String[0]); } /** * @return the phrases as an array of spans. */ public Span[] getPhrasesAsSpanList() { return phrasesAsSpanList(getSentence(), getTags(), getPreds()); } /** * Create arrays of {@link Span spans} of phrases. * * @param aSentence * The training sentence. * @param aTags * The POS tags for the {@code sentence}. * @param aPreds * The chunk tags in B-* I-* notation. * * @return the phrases as an array of spans */ public static Span[] phrasesAsSpanList(String[] aSentence, String[] aTags, String[] aPreds) { validateArguments(aSentence.length, aTags.length, aPreds.length); // initialize with the list maximum size List phrases = new ArrayList<>(aSentence.length); String startTag = ""; int startIndex = 0; boolean foundPhrase = false; for (int ci = 0, cn = aPreds.length; ci < cn; ci++) { String pred = aPreds[ci]; if (pred.startsWith("B-") || !pred.equals("I-" + startTag) && !pred.equals("O")) { // start if (foundPhrase) { // handle the last phrases.add(new Span(startIndex, ci, startTag)); } startIndex = ci; startTag = pred.substring(2); foundPhrase = true; } else if (pred.equals("I-" + startTag)) { // middle // do nothing } else if (foundPhrase) { // end phrases.add(new Span(startIndex, ci, startTag)); foundPhrase = false; startTag = ""; } } if (foundPhrase) { // leftover phrases.add(new Span(startIndex, aPreds.length, startTag)); } return phrases.toArray(new Span[0]); } private static void validateArguments(int sentenceSize, int tagsSize, int predsSize) throws IllegalArgumentException { if (sentenceSize != tagsSize || tagsSize != predsSize) throw new IllegalArgumentException( "All arrays must have the same length: " + "sentenceSize: " + sentenceSize + ", tagsSize: " + tagsSize + ", predsSize: " + predsSize + "!"); } /** * Creates a nice to read string for the phrases formatted as following:
* * [NP Rockwell_NNP ] [VP said_VBD ] [NP the_DT agreement_NN ] [VP calls_VBZ ] [SBAR for_IN ] * [NP it_PRP ] [VP to_TO supply_VB ] [NP 200_CD additional_JJ so-called_JJ shipsets_NNS ] * [PP for_IN ] [NP the_DT planes_NNS ] ._. * * * @return A nice to read string representation of the chunk phases */ public String nicePrint() { Span[] spans = getPhrasesAsSpanList(); StringBuilder result = new StringBuilder(" "); for (int tokenIndex = 0; tokenIndex < sentence.size(); tokenIndex++) { for (Span span : spans) { if (span.getStart() == tokenIndex) { result.append("[").append(span.getType()).append(" "); } if (span.getEnd() == tokenIndex) { result.append("]").append(' '); } } result.append(sentence.get(tokenIndex)).append("_").append(tags.get(tokenIndex)).append(' '); } if (sentence.size() > 1) result.setLength(result.length() - 1); for (Span span : spans) { if (span.getEnd() == sentence.size()) { result.append(']'); } } return result.toString(); } @Override public String toString() { StringBuilder chunkString = new StringBuilder(); for (int ci = 0; ci < preds.size(); ci++) { chunkString.append(sentence.get(ci)).append(" ").append(tags.get(ci)) .append(" ").append(preds.get(ci)).append("\n"); } return chunkString.toString(); } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(getSentence()), Arrays.hashCode(getTags()), Arrays.hashCode(getPreds())); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof ChunkSample a) { return Arrays.equals(getSentence(), a.getSentence()) && Arrays.equals(getTags(), a.getTags()) && Arrays.equals(getPreds(), a.getPreds()); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_chunker_ChunkSam0100644 0000000 0000000 00000000164 15217274217 032472 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkSampleSequenceStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkSampleSequenceStrea0100644 0000000 0000000 00000005503 15217274217 034176 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import java.io.IOException; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.Sequence; import opennlp.tools.ml.model.SequenceStream; import opennlp.tools.util.ObjectStream; /** * A {@link SequenceStream} implementation encapsulating {@link ChunkSample samples}. */ public class ChunkSampleSequenceStream implements SequenceStream { private final ObjectStream samples; private final ChunkerContextGenerator contextGenerator; /** * Creates a {@link ChunkSampleSequenceStream} with given {@code samples} using * a {@link ChunkerContextGenerator}. * * @param samples The data stream of {@link ChunkSample samples}. * @param generator A {@link ChunkerContextGenerator} which shall be used. */ public ChunkSampleSequenceStream(ObjectStream samples, ChunkerContextGenerator generator) { this.samples = samples; this.contextGenerator = generator; } @Override public Sequence read() throws IOException { ChunkSample sample = samples.read(); if (sample != null) { String[] sentence = sample.getSentence(); String[] tags = sample.getTags(); Event[] events = new Event[sentence.length]; for (int i = 0; i < sentence.length; i++) { // it is safe to pass the tags as previous tags because // the context generator does not look for non predicted tags String[] context = contextGenerator.getContext(i, sentence, tags, null); events[i] = new Event(tags[i], context); } return new Sequence<>(events,sample); } return null; } @Override public Event[] updateContext(Sequence sequence, AbstractModel model) { // TODO: Should be implemented for Perceptron sequence learning ... return null; } @Override public void reset() throws IOException, UnsupportedOperationException { samples.reset(); } @Override public void close() throws IOException { samples.close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkSampleStream.java0100644 0000000 0000000 00000004605 15217274217 033604 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Parses the conll 2000 shared task shallow parser training data. *

* Data format is specified on the conll page:
* * https://www.cnts.ua.ac.be/conll2000/chunking/ */ public class ChunkSampleStream extends FilterObjectStream { private static final Logger logger = LoggerFactory.getLogger(ChunkSampleStream.class); /** * Initializes a {@link ChunkSampleStream instance}. * * @param samples A plain text {@link ObjectStream line stream}. */ public ChunkSampleStream(ObjectStream samples) { super(samples); } @Override public ChunkSample read() throws IOException { List toks = new ArrayList<>(); List tags = new ArrayList<>(); List preds = new ArrayList<>(); for (String line = samples.read(); line != null && !line.isEmpty(); line = samples.read()) { String[] parts = line.split(" "); if (parts.length != 3) { logger.warn("Skipping corrupt line: {}", line); } else { toks.add(parts[0]); tags.add(parts[1]); preds.add(parts[2]); } } if (!toks.isEmpty()) { return new ChunkSample(toks.toArray(new String[0]), tags.toArray(new String[0]), preds.toArray(new String[0])); } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/Chunker.java0100644 0000000 0000000 00000005170 15217274217 031613 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.util.Sequence; import opennlp.tools.util.Span; /** * The interface for chunkers which provide chunk tags for a sequence of tokens. */ public interface Chunker { /** * Generates chunk tags for the given sequence returning the result in an array. * * @param toks an array of the tokens or words of the sequence. * @param tags an array of the pos tags of the sequence. * * @return an array of chunk tags for each token in the sequence. */ String[] chunk(String[] toks, String[] tags); /** * Generates tagged chunk {@link Span spans} for the given sequence returning * the result in a {@link Span span} array. * * @param toks an array of the tokens or words of the sequence. * @param tags an array of the pos tags of the sequence. * * @return an array of {@link Span spans} with chunk tags for each chunk in the sequence. */ Span[] chunkAsSpans(String[] toks, String[] tags); /** * Computes the top k chunk {@link Sequence sequences} for the specified sentence with * the specified pos-tags. * * @param sentence The tokens of the sentence. * @param tags The pos-tags for the specified sentence. * * @return the top k chunk {@link Sequence sequences} for the specified sentence. */ Sequence[] topKSequences(String[] sentence, String[] tags); /** * Computes the top k chunk {@link Sequence sequences} for the specified sentence with * the specified pos-tags. * * @param sentence The tokens of the sentence. * @param tags The pos-tags for the specified sentence. * @param minSequenceScore A lower bound on the score of a returned sequence. * * @return the top k chunk {@link Sequence sequences} for the specified sentence. */ Sequence[] topKSequences(String[] sentence, String[] tags, double minSequenceScore); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_chunker_ChunkerC0100644 0000000 0000000 00000000162 15217274217 032461 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerContextGenerator.0100644 0000000 0000000 00000003453 15217274217 034167 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.util.BeamSearchContextGenerator; import opennlp.tools.util.TokenTag; /** * Interface for a {@link BeamSearchContextGenerator} used in syntactic chunking. */ public interface ChunkerContextGenerator extends BeamSearchContextGenerator { /** * Retrieves the contexts for chunking of the specified {@code idx}. * * @param idx The index of the token in the specified {@code toks} array for which the context * should be constructed. * @param toks The tokens of the sentence. The {@code toString} methods of these objects * should return the token text. * @param tags The POS tags for the specified tokens. * @param preds The previous decisions made in the tagging of this sequence. * Only indices less than {@code idx} will be examined. * @return An array of predictive contexts on which a model basis its decisions. */ String[] getContext(int idx, String[] toks, String[] tags, String[] preds); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_chunker_ChunkerC0100644 0000000 0000000 00000000160 15217274217 032457 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerCrossValidator.ja0100644 0000000 0000000 00000006024 15217274217 034143 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import java.io.IOException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.FMeasure; /** * Cross validator for {@link Chunker}. */ public class ChunkerCrossValidator { private final String languageCode; private final TrainingParameters params; private final FMeasure fmeasure = new FMeasure(); private final ChunkerEvaluationMonitor[] listeners; private final ChunkerFactory chunkerFactory; /** * Initializes a {@link ChunkerCrossValidator} instance via given parameters. * * @param languageCode An ISO conform language code. * @param factory The {@link ChunkerFactory} for creating related objects. * @param params The {@link TrainingParameters} for the context of cross validation. * @param listeners the {@link ChunkerEvaluationMonitor evaluation listeners}. */ public ChunkerCrossValidator(String languageCode, TrainingParameters params, ChunkerFactory factory, ChunkerEvaluationMonitor... listeners) { this.chunkerFactory = factory; this.languageCode = languageCode; this.params = params; this.listeners = listeners; } /** * Starts the evaluation. * * @param samples The {@link ObjectStream} of {@link ChunkSample samples} to train and test with. * @param nFolds Number of folds. It must be greater than zero. * * @throws IOException Thrown if IO errors occurred. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>(samples, nFolds); while (partitioner.hasNext()) { CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner.next(); ChunkerModel model = ChunkerME.train(languageCode, trainingSampleStream, params, chunkerFactory); // do testing ChunkerEvaluator evaluator = new ChunkerEvaluator(new ChunkerME(model), listeners); evaluator.evaluate(trainingSampleStream.getTestSampleStream()); fmeasure.mergeInto(evaluator.getFMeasure()); } } public FMeasure getFMeasure() { return fmeasure; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_chunker_ChunkerE0100644 0000000 0000000 00000000163 15217274217 032464 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerEvaluationMonitor0100644 0000000 0000000 00000002022 15217274217 034264 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link Chunker chunkers}. */ public interface ChunkerEvaluationMonitor extends EvaluationMonitor { } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerEvaluator.java0100644 0000000 0000000 00000005021 15217274217 033471 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.FMeasure; /** * The {@link ChunkerEvaluator} measures the performance of the given {@link Chunker} with the provided * reference {@link ChunkSample samples}. * * @see Evaluator * @see Chunker * @see ChunkSample */ public class ChunkerEvaluator extends Evaluator { private final FMeasure fmeasure = new FMeasure(); /** * The {@link Chunker} used to create the predicted {@link ChunkSample} objects. */ private final Chunker chunker; /** * Initializes a {@link ChunkerEvaluator} instance with the given {@link Chunker}. * * @param chunker The {@link Chunker} to evaluate. * @param listeners The {@link ChunkerEvaluationMonitor evaluation listeners}. */ public ChunkerEvaluator(Chunker chunker, ChunkerEvaluationMonitor... listeners) { super(listeners); this.chunker = chunker; } /** * Evaluates the given reference {@link ChunkSample} object. *

* This is done by finding the phrases with the {@link Chunker} in the sentence from the reference * {@link ChunkSample}. The found phrases are then used to calculate and update the scores. * * @param reference the reference {@link ChunkSample}. * * @return The predicted {@link ChunkSample}. */ @Override protected ChunkSample processSample(ChunkSample reference) { String[] preds = chunker.chunk(reference.getSentence(), reference.getTags()); ChunkSample result = new ChunkSample(reference.getSentence(), reference.getTags(), preds); fmeasure.updateScores(reference.getPhrasesAsSpanList(), result.getPhrasesAsSpanList()); return result; } public FMeasure getFMeasure() { return fmeasure; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerEventStream.java0100644 0000000 0000000 00000004323 15217274217 033770 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import opennlp.tools.ml.model.Event; import opennlp.tools.util.AbstractEventStream; import opennlp.tools.util.ObjectStream; /** * Class for creating an event stream out of data files for training a {@link Chunker}. */ public class ChunkerEventStream extends AbstractEventStream { private final ChunkerContextGenerator cg; /** * Creates a new event stream based on the specified data stream using the given context generator. * * @param d The data stream for this event stream. * @param cg A {@link ChunkerContextGenerator} which should be used for the event stream {@code d}. */ public ChunkerEventStream(ObjectStream d, ChunkerContextGenerator cg) { super(d); this.cg = cg; } @Override protected Iterator createEvents(ChunkSample sample) { if (sample != null) { List events = new ArrayList<>(); String[] toksArray = sample.getSentence(); String[] tagsArray = sample.getTags(); String[] predsArray = sample.getPreds(); for (int ei = 0, el = sample.getSentence().length; ei < el; ei++) { events.add(new Event(predsArray[ei], cg.getContext(ei,toksArray,tagsArray,predsArray))); } return events.iterator(); } else { return Collections.emptyListIterator(); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerFactory.java0100644 0000000 0000000 00000005341 15217274217 033143 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.TokenTag; import opennlp.tools.util.ext.ExtensionLoader; public class ChunkerFactory extends BaseToolFactory { /** * Creates a {@link ChunkerFactory} that provides the default implementation * of the resources. */ public ChunkerFactory() { } /** * Instantiates a {@link ChunkerFactory} via a given {@code subclassName}. * * @param subclassName The class name used for instantiation. If {@code null}, an * instance of {@link ChunkerFactory} will be returned * per default. Otherwise, the {@link ExtensionLoader} mechanism * is applied to load the requested {@code subclassName}. * * @return A valid {@link ChunkerFactory} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the factory associated with {@code subclassName}. */ public static ChunkerFactory create(String subclassName) throws InvalidFormatException { if (subclassName == null) { // will create the default factory return new ChunkerFactory(); } try { return ExtensionLoader.instantiateExtension(ChunkerFactory.class, subclassName); } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } } @Override public void validateArtifactMap() throws InvalidFormatException { // no additional artifacts } public SequenceValidator getSequenceValidator() { return new DefaultChunkerSequenceValidator(); } public ChunkerContextGenerator getContextGenerator() { return new DefaultChunkerContextGenerator(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerME.java0100644 0000000 0000000 00000016300 15217274217 032032 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.Probabilistic; import opennlp.tools.ml.SequenceTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.TrainerFactory.TrainerType; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.models.ModelType; import opennlp.tools.util.DownloadUtil; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Sequence; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.Span; import opennlp.tools.util.TokenTag; import opennlp.tools.util.TrainingParameters; /** * The class represents a maximum-entropy-based {@link Chunker}. A chunker can be used to * find flat structures based on sequence inputs such as noun phrases or named entities. * * @see Chunker * @see Probabilistic */ public class ChunkerME implements Chunker, Probabilistic { public static final int DEFAULT_BEAM_SIZE = 10; private Sequence bestSequence; /** * The model used to assign chunk tags to a sequence of tokens. */ private final SequenceClassificationModel model; private final ChunkerContextGenerator contextGenerator; private final SequenceValidator sequenceValidator; /** * Initializes a {@link Chunker} by downloading a default model. * * @param language The language of the model. * @throws IOException Thrown if the model cannot be downloaded or saved. */ public ChunkerME(String language) throws IOException { this(DownloadUtil.downloadModel(language, ModelType.CHUNKER, ChunkerModel.class)); } /** * Initializes a {@link Chunker} with the specified {@link ChunkerModel}. * The {@link #DEFAULT_BEAM_SIZE} is used. * * @param model A valid {@link ChunkerModel model} instance. */ public ChunkerME(ChunkerModel model) { contextGenerator = model.getFactory().getContextGenerator(); sequenceValidator = model.getFactory().getSequenceValidator(); if (model.getChunkerSequenceModel() != null) { this.model = model.getChunkerSequenceModel(); } else { this.model = new BeamSearch(DEFAULT_BEAM_SIZE, model.getArtifact(ChunkerModel.CHUNKER_MODEL_ENTRY_NAME), 0); } } @Override public String[] chunk(String[] toks, String[] tags) { TokenTag[] tuples = TokenTag.create(toks, tags); bestSequence = model.bestSequence(tuples, new Object[] {}, contextGenerator, sequenceValidator); List c = bestSequence.getOutcomes(); return c.toArray(new String[0]); } @Override public Span[] chunkAsSpans(String[] toks, String[] tags) { String[] preds = chunk(toks, tags); return ChunkSample.phrasesAsSpanList(toks, tags, preds); } @Override public Sequence[] topKSequences(String[] sentence, String[] tags) { TokenTag[] tuples = TokenTag.create(sentence, tags); return model.bestSequences(DEFAULT_BEAM_SIZE, tuples, new Object[] { }, contextGenerator, sequenceValidator); } @Override public Sequence[] topKSequences(String[] sentence, String[] tags, double minSequenceScore) { TokenTag[] tuples = TokenTag.create(sentence, tags); return model.bestSequences(DEFAULT_BEAM_SIZE, tuples, new Object[] { }, minSequenceScore, contextGenerator, sequenceValidator); } /** * Populates the specified array with the probabilities of the last decoded sequence. The * sequence was determined based on the previous call to {@code chunk}. The * specified array should be at least as large as the number of tokens in the previous * call to {@code chunk}. * * @param probs An array used to hold the probabilities of the last decoded sequence. */ public void probs(double[] probs) { bestSequence.getProbs(probs); } /** * {@inheritDoc} * The sequence was determined based on the previous call to {@link #chunk(String[], String[])}. * * @return An array with the same number of probabilities as tokens when * {@link ChunkerME#chunk(String[], String[])} was last called. */ @Override public double[] probs() { return bestSequence.getProbs(); } /** * Starts a training of a {@link ChunkerModel} with the given parameters. * * @param lang The ISO conform language code. * @param in The {@link ObjectStream} of {@link ChunkSample} used as input for training. * @param mlParams The {@link TrainingParameters} for the context of the training. * @param factory The {@link ChunkerFactory} for creating related objects defined via {@code mlParams}. * * @return A valid, trained {@link ChunkerModel} instance. * @throws IOException Thrown if IO errors occurred. * @throws IllegalArgumentException Thrown if the specified {@link TrainerType} is not supported. */ public static ChunkerModel train(String lang, ObjectStream in, TrainingParameters mlParams, ChunkerFactory factory) throws IOException { int beamSize = mlParams.getIntParameter(BeamSearch.BEAM_SIZE_PARAMETER, ChunkerME.DEFAULT_BEAM_SIZE); Map manifestInfoEntries = new HashMap<>(); TrainerType trainerType = TrainerFactory.getTrainerType(mlParams); MaxentModel chunkerModel = null; SequenceClassificationModel seqChunkerModel = null; if (TrainerType.EVENT_MODEL_TRAINER.equals(trainerType)) { ObjectStream es = new ChunkerEventStream(in, factory.getContextGenerator()); EventTrainer trainer = TrainerFactory.getEventTrainer(mlParams, manifestInfoEntries); chunkerModel = trainer.train(es); } else if (TrainerType.SEQUENCE_TRAINER.equals(trainerType)) { SequenceTrainer trainer = TrainerFactory.getSequenceModelTrainer( mlParams, manifestInfoEntries); // TODO: This will probably cause issue, since the feature generator uses the outcomes array ChunkSampleSequenceStream ss = new ChunkSampleSequenceStream(in, factory.getContextGenerator()); seqChunkerModel = trainer.train(ss); } else { throw new IllegalArgumentException("Trainer type is not supported: " + trainerType); } if (chunkerModel != null) { return new ChunkerModel(lang, chunkerModel, beamSize, manifestInfoEntries, factory); } else { return new ChunkerModel(lang, seqChunkerModel, manifestInfoEntries, factory); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ChunkerModel.java0100644 0000000 0000000 00000017030 15217274217 032572 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Serial; import java.net.URL; import java.nio.file.Path; import java.util.Map; import java.util.Properties; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.BaseModel; /** * The {@link ChunkerModel} is the model used by a learnable {@link Chunker}. * * @see ChunkerME */ public class ChunkerModel extends BaseModel { @Serial private static final long serialVersionUID = -5450757164882452147L; private static final String COMPONENT_NAME = "ChunkerME"; static final String CHUNKER_MODEL_ENTRY_NAME = "chunker.model"; /** * Initializes a {@link ChunkerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param chunkerModel A valid {@link SequenceClassificationModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link ChunkerFactory} for creating related objects. */ public ChunkerModel(String languageCode, SequenceClassificationModel chunkerModel, Map manifestInfoEntries, ChunkerFactory factory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, factory); artifactMap.put(CHUNKER_MODEL_ENTRY_NAME, chunkerModel); checkArtifactMap(); } /** * Initializes a {@link ChunkerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param chunkerModel A valid {@link MaxentModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link ChunkerFactory} for creating related objects. */ public ChunkerModel(String languageCode, MaxentModel chunkerModel, Map manifestInfoEntries, ChunkerFactory factory) { this(languageCode, chunkerModel, ChunkerME.DEFAULT_BEAM_SIZE, manifestInfoEntries, factory); } /** * Initializes a {@link ChunkerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param chunkerModel A valid {@link MaxentModel}. * @param beamSize The size of the beam that should be used when decoding sequences. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link ChunkerFactory} for creating related objects. */ public ChunkerModel(String languageCode, MaxentModel chunkerModel, int beamSize, Map manifestInfoEntries, ChunkerFactory factory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, factory); artifactMap.put(CHUNKER_MODEL_ENTRY_NAME, chunkerModel); Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); manifest.put(BeamSearch.BEAM_SIZE_PARAMETER, Integer.toString(beamSize)); checkArtifactMap(); } /** * Initializes a {@link ChunkerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param chunkerModel A valid {@link MaxentModel}. * @param factory The {@link ChunkerFactory} for creating related objects. */ public ChunkerModel(String languageCode, MaxentModel chunkerModel, ChunkerFactory factory) { this(languageCode, chunkerModel, null, factory); } /** * Initializes a {@link ChunkerModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ChunkerModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link ChunkerModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ChunkerModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link ChunkerModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ChunkerModel(Path modelPath) throws IOException { this(modelPath.toFile()); } /** * Initializes a {@link ChunkerModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ChunkerModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(CHUNKER_MODEL_ENTRY_NAME) instanceof AbstractModel)) { throw new InvalidFormatException("Chunker model is incomplete!"); } // Since 1.8.0 we changed the ChunkerFactory signature. This will check the if the model // declares a not default factory, and if yes, check if it was created before 1.8 final String factoryName = getManifestProperty(FACTORY_NAME); if ( (factoryName != null && !factoryName.equals("opennlp.tools.chunker.ChunkerFactory") ) && this.getVersion().getMajor() <= 1 && this.getVersion().getMinor() < 8) { throw new InvalidFormatException("The Chunker factory '" + factoryName + "' is no longer compatible. Please update it to match the latest ChunkerFactory."); } } /** * @return Retrieves a {@link SequenceClassificationModel}. */ public SequenceClassificationModel getChunkerSequenceModel() { Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); if (artifactMap.get(CHUNKER_MODEL_ENTRY_NAME) instanceof MaxentModel) { String beamSizeString = manifest.getProperty(BeamSearch.BEAM_SIZE_PARAMETER); int beamSize = ChunkerME.DEFAULT_BEAM_SIZE; if (beamSizeString != null) { beamSize = Integer.parseInt(beamSizeString); } return new BeamSearch(beamSize, (MaxentModel) artifactMap.get(CHUNKER_MODEL_ENTRY_NAME)); } else if (artifactMap.get(CHUNKER_MODEL_ENTRY_NAME) instanceof SequenceClassificationModel) { return (SequenceClassificationModel) artifactMap.get(CHUNKER_MODEL_ENTRY_NAME); } else { return null; } } @Override protected Class getDefaultFactory() { return ChunkerFactory.class; } /** * @return Retrieves the active {@link ChunkerFactory}. */ public ChunkerFactory getFactory() { return (ChunkerFactory) this.toolFactory; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_chunker_DefaultC0100644 0000000 0000000 00000000171 15217274217 032446 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/DefaultChunkerContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/DefaultChunkerContextGen0100644 0000000 0000000 00000007077 15217274217 034207 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.util.TokenTag; /** * Features based on chunking model described in Fei Sha and Fernando Pereira. Shallow * parsing with conditional random fields. In Proceedings of HLT-NAACL 2003. Association * for Computational Linguistics, 2003. */ public class DefaultChunkerContextGenerator implements ChunkerContextGenerator { /** * Initializes a {@link DefaultChunkerContextGenerator} instance. */ public DefaultChunkerContextGenerator() { } @Override public String[] getContext(int i, String[] toks, String[] tags, String[] preds) { // Words in a 5-word window String w_2, w_1, w0, w1, w2; // Tags in a 5-word window String t_2, t_1, t0, t1, t2; // Previous predictions String p_2, p_1; if (i < 2) { w_2 = "w_2=bos"; t_2 = "t_2=bos"; p_2 = "p_2=bos"; } else { w_2 = "w_2=" + toks[i - 2]; t_2 = "t_2=" + tags[i - 2]; p_2 = "p_2=" + preds[i - 2]; } if (i < 1) { w_1 = "w_1=bos"; t_1 = "t_1=bos"; p_1 = "p_1=bos"; } else { w_1 = "w_1=" + toks[i - 1]; t_1 = "t_1=" + tags[i - 1]; p_1 = "p_1=" + preds[i - 1]; } w0 = "w0=" + toks[i]; t0 = "t0=" + tags[i]; if (i + 1 >= toks.length) { w1 = "w1=eos"; t1 = "t1=eos"; } else { w1 = "w1=" + toks[i + 1]; t1 = "t1=" + tags[i + 1]; } if (i + 2 >= toks.length) { w2 = "w2=eos"; t2 = "t2=eos"; } else { w2 = "w2=" + toks[i + 2]; t2 = "t2=" + tags[i + 2]; } return new String[] { //add word features w_2, w_1, w0, w1, w2, w_1 + w0, w0 + w1, //add tag features t_2, t_1, t0, t1, t2, t_2 + t_1, t_1 + t0, t0 + t1, t1 + t2, t_2 + t_1 + t0, t_1 + t0 + t1, t0 + t1 + t2, //add pred tags p_2, p_1, p_2 + p_1, //add pred and tag p_1 + t_2, p_1 + t_1, p_1 + t0, p_1 + t1, p_1 + t2, p_1 + t_2 + t_1, p_1 + t_1 + t0, p_1 + t0 + t1, p_1 + t1 + t2, p_1 + t_2 + t_1 + t0, p_1 + t_1 + t0 + t1, p_1 + t0 + t1 + t2, //add pred and word p_1 + w_2, p_1 + w_1, p_1 + w0, p_1 + w1, p_1 + w2, p_1 + w_1 + w0, p_1 + w0 + w1 }; } @Override public String[] getContext(int index, TokenTag[] sequence, String[] priorDecisions, Object[] additionalContext) { String[] token = TokenTag.extractTokens(sequence); String[] tags = TokenTag.extractTags(sequence); return getContext(index, token, tags, priorDecisions); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_chunker_DefaultC0100644 0000000 0000000 00000000172 15217274217 032447 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/DefaultChunkerSequenceValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/DefaultChunkerSequenceVa0100644 0000000 0000000 00000003433 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.TokenTag; /** * The default chunker {@link SequenceValidator} implementation. */ public class DefaultChunkerSequenceValidator implements SequenceValidator { private boolean validOutcome(String outcome, String prevOutcome) { if (outcome.startsWith("I-")) { if (prevOutcome == null) { return false; } else { if (prevOutcome.equals("O")) { return false; } return prevOutcome.substring(2).equals(outcome.substring(2)); } } return true; } private boolean validOutcome(String outcome, String[] sequence) { String prevOutcome = null; if (sequence.length > 0) { prevOutcome = sequence[sequence.length - 1]; } return validOutcome(outcome,prevOutcome); } @Override public boolean validSequence(int i, TokenTag[] sequence, String[] s, String outcome) { return validOutcome(outcome, s); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_chunker_ThreadSa0100644 0000000 0000000 00000000156 15217274217 032455 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ThreadSafeChunkerME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/ThreadSafeChunkerME.java0100644 0000000 0000000 00000005657 15217274217 033776 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.chunker; import opennlp.tools.commons.ThreadSafe; import opennlp.tools.ml.Probabilistic; import opennlp.tools.util.Sequence; import opennlp.tools.util.Span; /** * A thread-safe version of the {@link ChunkerME}. Using it is completely transparent. * You can use it in a single-threaded context as well, it only incurs a minimal overhead. *

* Note:
* This implementation uses a {@link ThreadLocal}. Although the implementation is * lightweight because the model is not duplicated, if you have many long-running threads, * you may run into memory problems. *

* Be careful when using this in a Jakarta EE application, for example. *

* The user is responsible for clearing the {@link ThreadLocal} * via calling {@link #close()}. * * @see Chunker * @see ChunkerME * @see Probabilistic */ @ThreadSafe public class ThreadSafeChunkerME implements Chunker, Probabilistic, AutoCloseable { private final ChunkerModel model; private final ThreadLocal threadLocal = new ThreadLocal<>(); /** * Initializes a {@link ThreadSafeChunkerME} with the specified {@code model}. * * @param model A valid {@link ChunkerModel}. */ public ThreadSafeChunkerME(ChunkerModel model) { super(); this.model = model; } private ChunkerME getChunker() { ChunkerME c = threadLocal.get(); if (c == null) { c = new ChunkerME(model); threadLocal.set(c); } return c; } @Override public String[] chunk(String[] toks, String[] tags) { return getChunker().chunk(toks, tags); } @Override public Span[] chunkAsSpans(String[] toks, String[] tags) { return getChunker().chunkAsSpans(toks, tags); } @Override public Sequence[] topKSequences(String[] sentence, String[] tags) { return getChunker().topKSequences(sentence, tags); } @Override public Sequence[] topKSequences(String[] sentence, String[] tags, double minSequenceScore) { return getChunker().topKSequences(sentence, tags, minSequenceScore); } @Override public void close() { threadLocal.remove(); } @Override public double[] probs() { return getChunker().probs(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/chunker/package-info.java0100644 0000000 0000000 00000001646 15217274217 032544 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to finding non-recursive syntactic annotation such as noun phrase chunks. */ package opennlp.tools.chunker; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Abstract0100644 0000000 0000000 00000000160 15217274217 032474 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractConverterTool.ja0100644 0000000 0000000 00000010533 15217274217 034131 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.IOException; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.ObjectStream; /** * Base class for format conversion tools. * * @param The class of data sample the tool converts, * for example {@link opennlp.tools.postag.POSSample} */ public abstract class AbstractConverterTool extends TypedCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(AbstractConverterTool.class); /** * Constructor with type parameter. * * @param sampleType class of the template parameter */ protected AbstractConverterTool(Class sampleType) { super(sampleType); } @Override public String getShortDescription() { Map> factories = StreamFactoryRegistry.getFactories(type); StringBuilder help = new StringBuilder(); if (2 == factories.keySet().size()) { //opennlp + foreign for (String format : factories.keySet()) { if (!StreamFactoryRegistry.DEFAULT_FORMAT.equals(format)) { help.append(format); } } return "Converts " + help + " data format to native OpenNLP format"; } else if (2 < factories.keySet().size()) { for (String format : factories.keySet()) { if (!StreamFactoryRegistry.DEFAULT_FORMAT.equals(format)) { help.append(format).append(","); } } return "Converts external data formats (" + help.substring(0, help.length() - 1 ) + ") to native OpenNLP format"; } else { throw new AssertionError("There should be more than 1 factory registered for converter " + "tool"); } } private String createHelpString(String format, String usage) { return "Usage: " + CLI.CMD + " " + getName() + " " + format + " " + usage; } @Override public String getHelp() { Map> factories = StreamFactoryRegistry.getFactories(type); StringBuilder help = new StringBuilder("help|"); for (String formatName : factories.keySet()) { if (!StreamFactoryRegistry.DEFAULT_FORMAT.equals(formatName)) { help.append(formatName).append("|"); } } return createHelpString(help.substring(0, help.length() - 1), "[help|options...]"); } @Override public String getHelp(String format) { return getHelp(); } @Override public void run(String format, String[] args) { if (0 == args.length) { logger.info(getHelp()); } else { format = args[0]; ObjectStreamFactory streamFactory = getStreamFactory(format); String[] formatArgs = new String[args.length - 1]; System.arraycopy(args, 1, formatArgs, 0, formatArgs.length); String helpString = createHelpString(format, ArgumentParser.createUsage(streamFactory.getParameters())); if (0 == formatArgs.length || (1 == formatArgs.length && "help".equals(formatArgs[0]))) { logger.info(helpString); System.exit(0); } String errorMessage = ArgumentParser.validateArgumentsLoudly(formatArgs, streamFactory.getParameters()); if (null != errorMessage) { throw new TerminateToolException(1, errorMessage + "\n" + helpString); } try (ObjectStream sampleStream = streamFactory.create(formatArgs)) { T sample; while ((sample = sampleStream.read()) != null) { logger.info(sample.toString()); } } catch (IOException e) { throw new TerminateToolException(-1, "IO error while converting data : " + e.getMessage(), e); } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Abstract0100644 0000000 0000000 00000000165 15217274217 032501 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractCrossValidatorTo0100644 0000000 0000000 00000002343 15217274217 034175 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; /** * Base class for cross validator tools. */ public abstract class AbstractCrossValidatorTool extends AbstractTrainerTool { /** * Constructor with type parameters. * * @param sampleType class of the template parameter * @param params interface with parameters */ protected AbstractCrossValidatorTool(Class sampleType, Class

params) { super(sampleType, params); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Abstract0100644 0000000 0000000 00000000160 15217274217 032474 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractEvaluatorTool.ja0100644 0000000 0000000 00000003434 15217274217 034126 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import opennlp.tools.util.ObjectStream; /** * Base class for evaluator tools. */ public abstract class AbstractEvaluatorTool extends AbstractTypedParamTool { protected P params; protected ObjectStreamFactory factory; protected ObjectStream sampleStream; /** * Constructor with type parameters. * * @param sampleType class of the template parameter * @param params interface with parameters */ protected AbstractEvaluatorTool(Class sampleType, Class

params) { super(sampleType, params); } @Override public void run(String format, String[] args) { validateAllArgs(args, this.paramsClass, format); params = ArgumentParser.parse( ArgumentParser.filter(args, this.paramsClass), this.paramsClass); factory = getStreamFactory(format); String[] fargs = ArgumentParser.filter(args, factory.getParameters()); validateFactoryArgs(factory, fargs); sampleStream = factory.create(fargs); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Abstract0100644 0000000 0000000 00000000156 15217274217 032501 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractTrainerTool.java0100644 0000000 0000000 00000004001 15217274217 034106 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.IOException; import opennlp.tools.util.InsufficientTrainingDataException; import opennlp.tools.util.TrainingParameters; /** * Base class for trainer tools. */ public abstract class AbstractTrainerTool extends AbstractEvaluatorTool { protected TrainingParameters mlParams; /** * Constructor with type parameters. * * @param sampleType class of the template parameter * @param params interface with parameters */ protected AbstractTrainerTool(Class sampleType, Class

params) { super(sampleType, params); } protected TerminateToolException createTerminationIOException(IOException e) { if (e instanceof InsufficientTrainingDataException) { return new TerminateToolException(-1, "\n\nERROR: Not enough training data\n" + "The provided training data is not sufficient to create enough events to train a model.\n" + "To resolve this error use more training data, if this doesn't help there might\n" + "be some fundamental problem with the training data itself."); } return new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Abstract0100644 0000000 0000000 00000000161 15217274217 032475 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractTypedParamTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/AbstractTypedParamTool.j0100644 0000000 0000000 00000004063 15217274217 034070 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; /** * Base class for tools which take additional parameters. For example, trainers or evaluators. */ public abstract class AbstractTypedParamTool extends TypedCmdLineTool { /** * variable to access the parameters */ protected final Class

paramsClass; /** * Constructor with type parameters. * * @param sampleType class of the template parameter * @param paramsClass interface with parameters */ protected AbstractTypedParamTool(Class sampleType, Class

paramsClass) { super(sampleType); this.paramsClass = paramsClass; } @Override public String getHelp(String format) { if ("".equals(format) || StreamFactoryRegistry.DEFAULT_FORMAT.equals(format)) { return getBasicHelp(paramsClass, StreamFactoryRegistry.getFactory(type, StreamFactoryRegistry.DEFAULT_FORMAT).getParameters()); } else { ObjectStreamFactory factory = StreamFactoryRegistry.getFactory(type, format); if (null == factory) { throw new TerminateToolException(1, "Format " + format + " is not found.\n" + getHelp()); } return "Usage: " + CLI.CMD + " " + getName() + "." + format + " " + ArgumentParser.createUsage(paramsClass, factory.getParameters()); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/ArgumentParser.java0100644 0000000 0000000 00000042503 15217274217 033130 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import opennlp.tools.commons.Internal; /** * Parser for command line arguments. The parser creates a dynamic proxy which * can be access via a command line argument interface. * *

* * The command line argument proxy interface must follow these conventions:
* - Methods do not define arguments
* - Method names must start with get
* - Allowed return types are Integer, Boolean, String, File and Charset.
*

* Note: Do not use this class, internal use only! */ @Internal public class ArgumentParser { public @Retention(RetentionPolicy.RUNTIME) @interface OptionalParameter { // CHECKSTYLE:OFF String DEFAULT_CHARSET = "DEFAULT_CHARSET"; // CHECKSTYLE:ON String defaultValue() default ""; } public @Retention(RetentionPolicy.RUNTIME) @interface ParameterDescription { String valueName(); String description() default ""; } private interface ArgumentFactory { String INVALID_ARG = "Invalid argument: %s %s \n"; Object parseArgument(Method method, String argName, String argValue); } private static class IntegerArgumentFactory implements ArgumentFactory { @Override public Object parseArgument(Method method, String argName, String argValue) { Object value; try { value = Integer.parseInt(argValue); } catch (NumberFormatException e) { throw new TerminateToolException(1, String.format(INVALID_ARG, argName, argValue) + "Value must be an integer!", e); } return value; } } private static class BooleanArgumentFactory implements ArgumentFactory { @Override public Object parseArgument(Method method, String argName, String argValue) { return Boolean.parseBoolean(argValue); } } private static class StringArgumentFactory implements ArgumentFactory { @Override public Object parseArgument(Method method, String argName, String argValue) { return argValue; } } private static class FileArgumentFactory implements ArgumentFactory { @Override public Object parseArgument(Method method, String argName, String argValue) { return new File(argValue); } } private static class CharsetArgumentFactory implements ArgumentFactory { @Override public Object parseArgument(Method method, String argName, String charsetName) { try { if (OptionalParameter.DEFAULT_CHARSET.equals(charsetName)) { return Charset.defaultCharset(); } else if (Charset.isSupported(charsetName)) { return Charset.forName(charsetName); } else { throw new TerminateToolException(1, String.format(INVALID_ARG, argName, charsetName) + "Encoding not supported on this platform."); } } catch (IllegalCharsetNameException e) { throw new TerminateToolException(1, String.format(INVALID_ARG, argName, charsetName) + "Illegal encoding name."); } } } private record ArgumentProxy(Map arguments) implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (args != null) throw new IllegalStateException(); return arguments.get(method.getName()); } } private static final Map, ArgumentFactory> argumentFactories; static { Map, ArgumentFactory> factories = new HashMap<>(); factories.put(Integer.class, new IntegerArgumentFactory()); factories.put(Boolean.class, new BooleanArgumentFactory()); factories.put(String.class, new StringArgumentFactory()); factories.put(File.class, new FileArgumentFactory()); factories.put(Charset.class, new CharsetArgumentFactory()); argumentFactories = Collections.unmodifiableMap(factories); } private ArgumentParser() { } private static void checkProxyInterfaces(Class... proxyInterfaces) { for (Class proxyInterface : proxyInterfaces) { if (null != proxyInterface) { if (!proxyInterface.isInterface()) throw new IllegalArgumentException("proxy interface is not an interface!"); // all checks should also be performed for super interfaces Method[] methods = proxyInterface.getMethods(); if (methods.length == 0) throw new IllegalArgumentException("proxy interface must at least declare one method!"); for (Method method : methods) { // check that method names start with get if (!method.getName().startsWith("get") && method.getName().length() > 3) throw new IllegalArgumentException(method.getName() + " method name does not start with 'get'!"); // check that method has zero arguments if (method.getParameterTypes().length != 0) { throw new IllegalArgumentException(method.getName() + " method must have zero parameters but has " + method.getParameterTypes().length + "!"); } // check return types of interface Class returnType = method.getReturnType(); Set> compatibleReturnTypes = argumentFactories.keySet(); if (!compatibleReturnTypes.contains(returnType)) { throw new IllegalArgumentException(method.getName() + " method must have compatible return type! Got " + returnType + ", expected one of " + compatibleReturnTypes); } } } } } private static String methodNameToParameter(String methodName) { // remove get from method name char[] parameterNameChars = methodName.toCharArray(); // name length is checked to be at least 4 prior parameterNameChars[3] = Character.toLowerCase(parameterNameChars[3]); return "-" + new String(parameterNameChars).substring(3); } /** * Creates a usage string which can be printed in case the user did specify the arguments * incorrectly. Incorrectly is defined as {@link ArgumentParser#validateArguments(String[], Class)} * returns {@code false}. * * @param argProxyInterface interface with parameter descriptions * @return the help message usage string */ public static String createUsage(Class argProxyInterface) { return createUsage(new Class[]{argProxyInterface}); } /** * Auxiliary record that holds information about an argument. This is used by the * {@link GenerateManualTool}, which creates a Docbook for the CLI automatically. */ record Argument(String argument, String value, String description, boolean optional) { } /** * Outputs the arguments as a data structure, so it can be used to create documentation. * * @param argProxyInterfaces interfaces with parameter descriptions * @return the help message usage string */ public static List createArguments(Class... argProxyInterfaces) { checkProxyInterfaces(argProxyInterfaces); Set duplicateFilter = new HashSet<>(); List arguments = new LinkedList<>(); for (Class argProxyInterface : argProxyInterfaces) { if (null != argProxyInterface) { for (Method method : argProxyInterface.getMethods()) { ParameterDescription desc = method.getAnnotation(ParameterDescription.class); OptionalParameter optional = method.getAnnotation(OptionalParameter.class); if (desc != null) { String paramName = methodNameToParameter(method.getName()); if (duplicateFilter.contains(paramName)) { continue; } else { duplicateFilter.add(paramName); } boolean isOptional = optional != null; Argument arg = new Argument(paramName.substring(1), desc.valueName(), desc.description(), isOptional); arguments.add(arg); } } } } return arguments; } /** * Creates a usage string which can be printed in case the user did specify the arguments * incorrectly. Incorrectly is defined as {@link ArgumentParser#validateArguments(String[], * Class[])} returns {@code false}. * * @param argProxyInterfaces interfaces with parameter descriptions * @return the help message usage string */ public static String createUsage(Class... argProxyInterfaces) { checkProxyInterfaces(argProxyInterfaces); Set duplicateFilter = new HashSet<>(); StringBuilder usage = new StringBuilder(); StringBuilder details = new StringBuilder(); for (Class argProxyInterface : argProxyInterfaces) { if (null != argProxyInterface) { for (Method method : argProxyInterface.getMethods()) { ParameterDescription desc = method.getAnnotation(ParameterDescription.class); OptionalParameter optional = method.getAnnotation(OptionalParameter.class); if (desc != null) { String paramName = methodNameToParameter(method.getName()); if (duplicateFilter.contains(paramName)) { continue; } else { duplicateFilter.add(paramName); } if (optional != null) usage.append('['); usage.append(paramName).append(' ').append(desc.valueName()); details.append('\t').append(paramName).append(' ').append(desc.valueName()).append('\n'); if (desc.description().length() > 0) { details.append("\t\t").append(desc.description()).append('\n'); } if (optional != null) usage.append(']'); usage.append(' '); } } } } if (usage.length() > 0) usage.setLength(usage.length() - 1); if (details.length() > 0) { details.setLength(details.length() - 1); usage.append("\n\nArguments description:\n").append(details); } return usage.toString(); } /** * Tests if the argument are correct or incorrect. Incorrect means, that mandatory arguments are missing or * there are unknown arguments. The argument value itself can also be incorrect, but this * is checked by the {@link ArgumentParser#parse(String[], Class)} method and reported accordingly. * * @param args command line arguments * @param argProxyInterface interface with parameters description * @return {@code true} if arguments are valid, {@code false otherwise} */ public static boolean validateArguments(String[] args, Class argProxyInterface) { return validateArguments(args, new Class[]{argProxyInterface}); } /** * Tests if the argument are correct or incorrect. Incorrect means, that mandatory arguments are missing or * there are unknown arguments. The argument value itself can also be incorrect, but this * is checked by the {@link ArgumentParser#parse(String[], Class)} method and reported accordingly. * * @param args command line arguments * @param argProxyInterfaces interfaces with parameters description * @return {@code true} if arguments are valid, {@code false otherwise} */ public static boolean validateArguments(String[] args, Class... argProxyInterfaces) { return null == validateArgumentsLoudly(args, argProxyInterfaces); } /** * Tests if the arguments are correct or incorrect. * * @param args command line arguments * @param argProxyInterface interface with parameters description * @return {@code null}, if arguments are valid or error message otherwise */ public static String validateArgumentsLoudly(String[] args, Class argProxyInterface) { return validateArgumentsLoudly(args, new Class[]{argProxyInterface}); } /** * Tests if the arguments are correct or incorrect. * * @param args command line arguments * @param argProxyInterfaces interfaces with parameters description * @return {@code null}, if arguments are valid or error message otherwise */ public static String validateArgumentsLoudly(String[] args, Class... argProxyInterfaces) { // number of parameters must be always be even if (args.length % 2 != 0) { return "Number of parameters must be always be even"; } int argumentCount = 0; List parameters = new ArrayList<>(Arrays.asList(args)); for (Class argProxyInterface : argProxyInterfaces) { for (Method method : argProxyInterface.getMethods()) { String paramName = methodNameToParameter(method.getName()); int paramIndex = CmdLineUtil.getParameterIndex(paramName, args); String valueString = CmdLineUtil.getParameter(paramName, args); if (valueString == null) { OptionalParameter optionalParam = method.getAnnotation(OptionalParameter.class); if (optionalParam == null) { if (-1 < paramIndex) { return "Missing mandatory parameter value: " + paramName; } else { return "Missing mandatory parameter: " + paramName; } } else { parameters.remove("-" + paramName); } } else { parameters.remove(paramName); parameters.remove(valueString); argumentCount++; } } } if (args.length / 2 > argumentCount) { return "Unrecognized parameters encountered: " + parameters; } return null; } /** * Parses the passed arguments and creates an instance of the proxy interface. *

* In case an argument value cannot be parsed a {@link TerminateToolException} is * thrown which contains an error message which explains the problems. * * @param args arguments * @param argProxyInterface interface with parameters description * * @return parsed parameters * * @throws TerminateToolException if an argument value cannot be parsed. * @throws IllegalArgumentException if validateArguments returns {@code false}, * if the proxy interface is not compatible. */ @SuppressWarnings("unchecked") public static T parse(String[] args, Class argProxyInterface) { checkProxyInterfaces(argProxyInterface); if (!validateArguments(args, argProxyInterface)) throw new IllegalArgumentException("Passed args must be valid!"); Map arguments = new HashMap<>(); for (Method method : argProxyInterface.getMethods()) { String parameterName = methodNameToParameter(method.getName()); String valueString = CmdLineUtil.getParameter(parameterName, args); if (valueString == null) { OptionalParameter optionalParam = method.getAnnotation(OptionalParameter.class); if (optionalParam.defaultValue().length() > 0) valueString = optionalParam.defaultValue(); } Class returnType = method.getReturnType(); Object value; if (valueString != null) { ArgumentFactory factory = argumentFactories.get(returnType); if (factory == null) throw new IllegalStateException("factory for '" + returnType + "' must not be null"); value = factory.parseArgument(method, parameterName, valueString); } else value = null; arguments.put(method.getName(), value); } return (T) java.lang.reflect.Proxy.newProxyInstance( argProxyInterface.getClassLoader(), new Class[]{argProxyInterface}, new ArgumentProxy(arguments)); } /** * Filters arguments leaving only those pertaining to {@code argProxyInterface}. * * @param args arguments * @param argProxyInterface interface with parameters description * @param T * @return arguments pertaining to {@code argProxyInterface} */ public static String[] filter(String[] args, Class argProxyInterface) { ArrayList parameters = new ArrayList<>(args.length); for (Method method : argProxyInterface.getMethods()) { String parameterName = methodNameToParameter(method.getName()); int idx = CmdLineUtil.getParameterIndex(parameterName, args); if (-1 < idx) { parameters.add(parameterName); String valueString = CmdLineUtil.getParameter(parameterName, args); if (null != valueString) { parameters.add(valueString); } } } return parameters.toArray(new String[0]); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/BasicCmdLineTool.java0100644 0000000 0000000 00000002330 15217274217 033276 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import opennlp.tools.commons.Internal; /** * A simple {@link CmdLineTool tool} which can be executed from the command line. *

* Note: Do not use this class, internal use only! */ @Internal public abstract class BasicCmdLineTool extends CmdLineTool { /** * Executes the tool with the given parameters. * * @param args arguments */ public abstract void run(String[] args); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/CLI.java0100644 0000000 0000000 00000024455 15217274217 030606 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.chunker.ChunkerConverterTool; import opennlp.tools.cmdline.chunker.ChunkerCrossValidatorTool; import opennlp.tools.cmdline.chunker.ChunkerEvaluatorTool; import opennlp.tools.cmdline.chunker.ChunkerMETool; import opennlp.tools.cmdline.chunker.ChunkerTrainerTool; import opennlp.tools.cmdline.dictionary.DictionaryBuilderTool; import opennlp.tools.cmdline.doccat.DoccatConverterTool; import opennlp.tools.cmdline.doccat.DoccatCrossValidatorTool; import opennlp.tools.cmdline.doccat.DoccatEvaluatorTool; import opennlp.tools.cmdline.doccat.DoccatTool; import opennlp.tools.cmdline.doccat.DoccatTrainerTool; import opennlp.tools.cmdline.entitylinker.EntityLinkerTool; import opennlp.tools.cmdline.langdetect.LanguageDetectorConverterTool; import opennlp.tools.cmdline.langdetect.LanguageDetectorCrossValidatorTool; import opennlp.tools.cmdline.langdetect.LanguageDetectorEvaluatorTool; import opennlp.tools.cmdline.langdetect.LanguageDetectorTool; import opennlp.tools.cmdline.langdetect.LanguageDetectorTrainerTool; import opennlp.tools.cmdline.languagemodel.NGramLanguageModelTool; import opennlp.tools.cmdline.lemmatizer.LemmatizerEvaluatorTool; import opennlp.tools.cmdline.lemmatizer.LemmatizerMETool; import opennlp.tools.cmdline.lemmatizer.LemmatizerTrainerTool; import opennlp.tools.cmdline.namefind.CensusDictionaryCreatorTool; import opennlp.tools.cmdline.namefind.TokenNameFinderConverterTool; import opennlp.tools.cmdline.namefind.TokenNameFinderCrossValidatorTool; import opennlp.tools.cmdline.namefind.TokenNameFinderEvaluatorTool; import opennlp.tools.cmdline.namefind.TokenNameFinderTool; import opennlp.tools.cmdline.namefind.TokenNameFinderTrainerTool; import opennlp.tools.cmdline.parser.BuildModelUpdaterTool; import opennlp.tools.cmdline.parser.CheckModelUpdaterTool; import opennlp.tools.cmdline.parser.ParserConverterTool; import opennlp.tools.cmdline.parser.ParserEvaluatorTool; import opennlp.tools.cmdline.parser.ParserTool; import opennlp.tools.cmdline.parser.ParserTrainerTool; import opennlp.tools.cmdline.parser.TaggerModelReplacerTool; import opennlp.tools.cmdline.postag.POSTaggerConverterTool; import opennlp.tools.cmdline.postag.POSTaggerCrossValidatorTool; import opennlp.tools.cmdline.postag.POSTaggerEvaluatorTool; import opennlp.tools.cmdline.postag.POSTaggerTrainerTool; import opennlp.tools.cmdline.sentdetect.SentenceDetectorConverterTool; import opennlp.tools.cmdline.sentdetect.SentenceDetectorCrossValidatorTool; import opennlp.tools.cmdline.sentdetect.SentenceDetectorEvaluatorTool; import opennlp.tools.cmdline.sentdetect.SentenceDetectorTool; import opennlp.tools.cmdline.sentdetect.SentenceDetectorTrainerTool; import opennlp.tools.cmdline.tokenizer.DictionaryDetokenizerTool; import opennlp.tools.cmdline.tokenizer.SimpleTokenizerTool; import opennlp.tools.cmdline.tokenizer.TokenizerConverterTool; import opennlp.tools.cmdline.tokenizer.TokenizerCrossValidatorTool; import opennlp.tools.cmdline.tokenizer.TokenizerMEEvaluatorTool; import opennlp.tools.cmdline.tokenizer.TokenizerMETool; import opennlp.tools.cmdline.tokenizer.TokenizerTrainerTool; import opennlp.tools.util.Version; public final class CLI { private static final Logger logger = LoggerFactory.getLogger(CLI.class); public static final String CMD = "opennlp"; private static Map toolLookupMap; static { toolLookupMap = new LinkedHashMap<>(); List tools = new LinkedList<>(); // Document Categorizer tools.add(new DoccatTool()); tools.add(new DoccatTrainerTool()); tools.add(new DoccatEvaluatorTool()); tools.add(new DoccatCrossValidatorTool()); tools.add(new DoccatConverterTool()); // Language Detector tools.add(new LanguageDetectorTool()); tools.add(new LanguageDetectorTrainerTool()); tools.add(new LanguageDetectorConverterTool()); tools.add(new LanguageDetectorCrossValidatorTool()); tools.add(new LanguageDetectorEvaluatorTool()); // Dictionary Builder tools.add(new DictionaryBuilderTool()); // Tokenizer tools.add(new SimpleTokenizerTool()); tools.add(new TokenizerMETool()); tools.add(new TokenizerTrainerTool()); tools.add(new TokenizerMEEvaluatorTool()); tools.add(new TokenizerCrossValidatorTool()); tools.add(new TokenizerConverterTool()); tools.add(new DictionaryDetokenizerTool()); // Sentence detector tools.add(new SentenceDetectorTool()); tools.add(new SentenceDetectorTrainerTool()); tools.add(new SentenceDetectorEvaluatorTool()); tools.add(new SentenceDetectorCrossValidatorTool()); tools.add(new SentenceDetectorConverterTool()); // Name Finder tools.add(new TokenNameFinderTool()); tools.add(new TokenNameFinderTrainerTool()); tools.add(new TokenNameFinderEvaluatorTool()); tools.add(new TokenNameFinderCrossValidatorTool()); tools.add(new TokenNameFinderConverterTool()); tools.add(new CensusDictionaryCreatorTool()); // POS Tagger tools.add(new opennlp.tools.cmdline.postag.POSTaggerTool()); tools.add(new POSTaggerTrainerTool()); tools.add(new POSTaggerEvaluatorTool()); tools.add(new POSTaggerCrossValidatorTool()); tools.add(new POSTaggerConverterTool()); //Lemmatizer tools.add(new LemmatizerMETool()); tools.add(new LemmatizerTrainerTool()); tools.add(new LemmatizerEvaluatorTool()); // Chunker tools.add(new ChunkerMETool()); tools.add(new ChunkerTrainerTool()); tools.add(new ChunkerEvaluatorTool()); tools.add(new ChunkerCrossValidatorTool()); tools.add(new ChunkerConverterTool()); // Parser tools.add(new ParserTool()); tools.add(new ParserTrainerTool()); // trains everything tools.add(new ParserEvaluatorTool()); tools.add(new ParserConverterTool()); // trains everything tools.add(new BuildModelUpdaterTool()); // re-trains build model tools.add(new CheckModelUpdaterTool()); // re-trains build model tools.add(new TaggerModelReplacerTool()); // Entity Linker tools.add(new EntityLinkerTool()); // Language Model tools.add(new NGramLanguageModelTool()); for (CmdLineTool tool : tools) { toolLookupMap.put(tool.getName(), tool); } toolLookupMap = Collections.unmodifiableMap(toolLookupMap); } /** * @return a set which contains all tool names */ public static Set getToolNames() { return toolLookupMap.keySet(); } /** * @return a read only map with tool names and instances */ public static Map getToolLookupMap() { return toolLookupMap; } private static void usage() { logger.info("OpenNLP {}.", Version.currentVersion() ); logger.info("Usage: {} TOOL", CMD); // distance of tool name from line start int numberOfSpaces = -1; for (String toolName : toolLookupMap.keySet()) { if (toolName.length() > numberOfSpaces) { numberOfSpaces = toolName.length(); } } numberOfSpaces = numberOfSpaces + 4; final StringBuilder sb = new StringBuilder("where TOOL is one of: \n\n"); for (CmdLineTool tool : toolLookupMap.values()) { sb.append(" ").append(tool.getName()); sb.append(" ".repeat(Math.max(0, StrictMath.abs( tool.getName().length() - numberOfSpaces)))); sb.append(tool.getShortDescription()).append("\n"); } logger.info(sb.toString()); logger.info("All tools print help when invoked with help parameter"); logger.info("Example: opennlp SimpleTokenizer help"); } public static void main(String[] args) { if (args.length == 0) { usage(); System.exit(0); } final long startTime = System.currentTimeMillis(); String[] toolArguments = new String[args.length - 1]; System.arraycopy(args, 1, toolArguments, 0, toolArguments.length); String toolName = args[0]; //check for format String formatName = StreamFactoryRegistry.DEFAULT_FORMAT; int idx = toolName.indexOf("."); if (-1 < idx) { formatName = toolName.substring(idx + 1); toolName = toolName.substring(0, idx); } CmdLineTool tool = toolLookupMap.get(toolName); try { if (null == tool) { throw new TerminateToolException(1, "Tool " + toolName + " is not found."); } if ((0 == toolArguments.length && tool.hasParams()) || 0 < toolArguments.length && "help".equals(toolArguments[0])) { if (tool instanceof TypedCmdLineTool) { logger.info(((TypedCmdLineTool) tool).getHelp(formatName)); } else if (tool instanceof BasicCmdLineTool) { logger.info(tool.getHelp()); } System.exit(0); } if (tool instanceof TypedCmdLineTool) { ((TypedCmdLineTool) tool).run(formatName, toolArguments); } else if (tool instanceof BasicCmdLineTool) { if (-1 == idx) { ((BasicCmdLineTool) tool).run(toolArguments); } else { throw new TerminateToolException(1, "Tool " + toolName + " does not support formats."); } } else { throw new TerminateToolException(1, "Tool " + toolName + " is not supported."); } } catch (TerminateToolException e) { logger.error(e.getLocalizedMessage(), e); System.exit(e.getCode()); } final long endTime = System.currentTimeMillis(); logger.info(String.format("Execution time: %.3f seconds\n", (endTime - startTime) / 1000.0)); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/CmdLineTool.java0100644 0000000 0000000 00000004511 15217274217 032337 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; /** * Base class for all command line tools. */ public abstract class CmdLineTool { protected CmdLineTool() { } /** * @return Retrieves the name of the command line tool. The name (used as command) * must not contain white spaces. */ public String getName() { if (getClass().getName().endsWith("Tool")) { return getClass().getSimpleName().substring(0, getClass().getSimpleName().length() - 4); } else { return getClass().getSimpleName(); } } /** * @return Retrieves whether the tool has any command line params */ public boolean hasParams() { return true; } protected String getBasicHelp(Class argProxyInterface) { return getBasicHelp(new Class[]{argProxyInterface}); } protected String getBasicHelp(Class... argProxyInterfaces) { return "Usage: " + CLI.CMD + " " + getName() + " " + ArgumentParser.createUsage(argProxyInterfaces); } /** * @return Retrieves a description on how to use the tool */ public abstract String getHelp(); protected T validateAndParseParams(String[] args, Class argProxyInterface) { String errorMessage = ArgumentParser.validateArgumentsLoudly(args, argProxyInterface); if (null != errorMessage) { throw new TerminateToolException(1, errorMessage + "\n" + getHelp()); } return ArgumentParser.parse(args, argProxyInterface); } /** * @return Retrieves a short description of what the tool does */ public String getShortDescription() { return ""; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/CmdLineUtil.java0100644 0000000 0000000 00000024664 15217274217 032352 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Internal; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.MarkableFileInputStreamFactory; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.model.BaseModel; /** * Util class for the command line interface. *

* Note: Do not use this class, internal use only! */ @Internal public final class CmdLineUtil { private static final Logger logger = LoggerFactory.getLogger(CmdLineUtil.class); static final int IO_BUFFER_SIZE = 1024 * 1024; private CmdLineUtil() { // not intended to be instantiated } /** * Check that the given input file is valid. *

* To pass the test it must:
* - exist
* - not be a directory,
* - and be accessibly.
* * @param name the name which is used to refer to the file in an error message, it * should start with a capital letter. * * @param inFile the particular {@link File} to check to qualify an input file * * @throws TerminateToolException if test does not pass this exception is * thrown and an error message is printed to the console. */ public static void checkInputFile(String name, File inFile) { String isFailure = null; if (inFile.isDirectory()) { isFailure = "The " + name + " file is a directory!"; } else if (!inFile.exists()) { isFailure = "The " + name + " file does not exist!"; } else if (!inFile.canRead()) { isFailure = "No permissions to read the " + name + " file!"; } if (null != isFailure) { throw new TerminateToolException(-1, isFailure + " Path: " + inFile.getAbsolutePath()); } } /** * Tries to ensure that it is possible to write to an output file. *

* The method does nothing if it is possible to write otherwise * it prints an appropriate error message and a {@link TerminateToolException} is thrown. *

* Computing the contents of an output file (e.g. ME model) can be very time-consuming. * Prior to this computation it should be checked once that writing this output file is * possible to be able to fail fast if not. If this validation is only done after a * time-consuming computation it could frustrate the user. * * @param name human-friendly file name. for example perceptron model * @param outFile the particular {@link File} to check to qualify an output file */ public static void checkOutputFile(String name, File outFile) { String isFailure = null; if (outFile.exists()) { // The file already exists, ensure that it is a normal file and that it is // possible to write into it if (outFile.isDirectory()) { isFailure = "The " + name + " file is a directory!"; } else if (outFile.isFile()) { if (!outFile.canWrite()) { isFailure = "No permissions to write the " + name + " file!"; } } else { isFailure = "The " + name + " file is not a normal file!"; } } else { // The file does not exist ensure its parent // directory exists and has write permissions to create // a new file in it File parentDir = outFile.getAbsoluteFile().getParentFile(); if (parentDir != null && parentDir.exists()) { if (!parentDir.canWrite()) { isFailure = "No permissions to create the " + name + " file!"; } } else { isFailure = "The parent directory of the " + name + " file does not exist, " + "please create it first!"; } } if (null != isFailure) { throw new TerminateToolException(-1, isFailure + " Path: " + outFile.getAbsolutePath()); } } public static FileInputStream openInFile(File file) { try { return new FileInputStream(file); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "File '" + file + "' cannot be found", e); } } public static InputStreamFactory createInputStreamFactory(File file) { try { return new MarkableFileInputStreamFactory(file); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "File '" + file + "' cannot be found", e); } } /** * Writes a {@link BaseModel} to disk. Occurring errors are printed to the console * to inform the user. * * @param modelName name of the model, name is used in error messages. * @param modelFile output file of the model * @param model the model itself which should be written to disk */ public static void writeModel(String modelName, File modelFile, BaseModel model) { CmdLineUtil.checkOutputFile(modelName + " model", modelFile); logger.info("Writing {} model ... ", modelName); long beginModelWritingTime = System.currentTimeMillis(); try (OutputStream modelOut = new BufferedOutputStream( new FileOutputStream(modelFile), IO_BUFFER_SIZE)) { model.serialize(modelOut); } catch (IOException e) { throw new TerminateToolException(-1, "Error during writing model file '" + modelFile + "'", e); } long modelWritingDuration = System.currentTimeMillis() - beginModelWritingTime; logger.info(String.format("done (%.3fs)\n", modelWritingDuration / 1000d)); logger.info("Wrote {} model to path: {}", modelName, modelFile.getAbsolutePath()); } /** * Returns the index of the parameter in the arguments, or {@code -1} if the parameter is not found. * * @param param parameter name * @param args arguments * @return the index of the parameter in the arguments, or {@code -1} if the parameter is not found */ public static int getParameterIndex(String param, String[] args) { for (int i = 0; i < args.length; i++) { if (args[i].startsWith("-") && args[i].equals(param)) { return i; } } return -1; } /** * Retrieves the specified parameter from the given arguments. * * @param param parameter name * @param args arguments * @return parameter value */ public static String getParameter(String param, String[] args) { int i = getParameterIndex(param, args); if (-1 < i) { i++; if (i < args.length) { return args[i]; } } return null; } /** * Retrieves the specified parameter from the specified arguments. * * @param param parameter name * @param args arguments * @return parameter value */ public static Integer getIntParameter(String param, String[] args) { String value = getParameter(param, args); try { if (value != null) return Integer.parseInt(value); } catch (NumberFormatException ignored) { // in this case return null } return null; } /** * Retrieves the specified parameter from the specified arguments. * * @param param parameter name * @param args arguments * @return parameter value */ public static Double getDoubleParameter(String param, String[] args) { String value = getParameter(param, args); try { if (value != null) return Double.parseDouble(value); } catch (NumberFormatException ignored) { // in this case return null } return null; } public static void checkLanguageCode(String code) { List languageCodes = new ArrayList<>(Arrays.asList(Locale.getISOLanguages())); languageCodes.add("x-unspecified"); if (!languageCodes.contains(code)) { throw new TerminateToolException(1, "Unknown language code " + code + ", " + "must be an ISO 639 code!"); } } public static boolean containsParam(String param, String[] args) { for (String arg : args) { if (arg.equals(param)) { return true; } } return false; } public static void handleStdinIoError(IOException e) { throw new TerminateToolException(-1, "IO Error while reading from stdin: " + e.getMessage(), e); } public static TerminateToolException createObjectStreamError(IOException e) { return new TerminateToolException(-1, "IO Error while creating an Input Stream: " + e.getMessage(), e); } public static void handleCreateObjectStreamError(IOException e) { throw createObjectStreamError(e); } // its optional, passing null is allowed public static TrainingParameters loadTrainingParameters(String paramFile, boolean supportSequenceTraining) { TrainingParameters params = null; if (paramFile != null) { checkInputFile("Training Parameter", new File(paramFile)); try (InputStream paramsIn = new BufferedInputStream(new FileInputStream(paramFile))) { params = new opennlp.tools.util.TrainingParameters(paramsIn); } catch (IOException e) { throw new TerminateToolException(-1, "Error during parameters loading: " + e.getMessage(), e); } if (!TrainerFactory.isValid(params)) { throw new TerminateToolException(1, "Training parameters file '" + paramFile + "' is invalid!"); } TrainerFactory.TrainerType trainerType = TrainerFactory.getTrainerType(params); if (!supportSequenceTraining && trainerType.equals(TrainerFactory.TrainerType.EVENT_MODEL_SEQUENCE_TRAINER)) { throw new TerminateToolException(1, "Sequence training is not supported!"); } } return params; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Detailed0100644 0000000 0000000 00000000163 15217274217 032447 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/DetailedFMeasureListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/DetailedFMeasureListener0100644 0000000 0000000 00000017230 15217274217 034121 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import opennlp.tools.commons.Internal; import opennlp.tools.util.Span; import opennlp.tools.util.eval.EvaluationMonitor; /** * This listener will gather detailed information about the sample under evaluation and will * allow detailed FMeasure for each outcome. *

* Note: Do not use this class, internal use only! */ @Internal public abstract class DetailedFMeasureListener implements EvaluationMonitor { private int samples = 0; private final Stats generalStats = new Stats(); private final Map statsForOutcome = new HashMap<>(); protected abstract Span[] asSpanArray(T sample); @Override public void correctlyClassified(T reference, T prediction) { samples++; // add all true positives! Span[] spans = asSpanArray(reference); for (Span span : spans) { addTruePositive(span.getType()); } } @Override public void misclassified(T reference, T prediction) { samples++; Span[] references = asSpanArray(reference); Span[] predictions = asSpanArray(prediction); Set refSet = new HashSet<>(Arrays.asList(references)); Set predSet = new HashSet<>(Arrays.asList(predictions)); for (Span ref : refSet) { if (predSet.contains(ref)) { addTruePositive(ref.getType()); } else { addFalseNegative(ref.getType()); } } for (Span pred : predSet) { if (!refSet.contains(pred)) { addFalsePositive(pred.getType()); } } } private void addTruePositive(String type) { Stats s = initStatsForOutcomeAndGet(type); s.incrementTruePositive(); s.incrementTarget(); generalStats.incrementTruePositive(); generalStats.incrementTarget(); } private void addFalsePositive(String type) { Stats s = initStatsForOutcomeAndGet(type); s.incrementFalsePositive(); generalStats.incrementFalsePositive(); } private void addFalseNegative(String type) { Stats s = initStatsForOutcomeAndGet(type); s.incrementTarget(); generalStats.incrementTarget(); } private Stats initStatsForOutcomeAndGet(String type) { if (!statsForOutcome.containsKey(type)) { statsForOutcome.put(type, new Stats()); } return statsForOutcome.get(type); } private static final String PERCENT = "%\u00207.2f%%"; private static final String FORMAT = "%12s: precision: " + PERCENT + "; recall: " + PERCENT + "; F1: " + PERCENT + "."; private static final String FORMAT_EXTRA = FORMAT + " [target: %3d; tp: %3d; fp: %3d]"; public String createReport() { return createReport(Locale.ROOT); } public String createReport(Locale locale) { StringBuilder ret = new StringBuilder(); int tp = generalStats.getTruePositives(); int found = generalStats.getFalsePositives() + tp; ret.append("Evaluated ").append(samples).append(" samples with ") .append(generalStats.getTarget()).append(" entities; found: ") .append(found).append(" entities; correct: ").append(tp).append(".\n"); ret.append(String.format(locale, FORMAT, "TOTAL", zeroOrPositive(generalStats.getPrecisionScore() * 100), zeroOrPositive(generalStats.getRecallScore() * 100), zeroOrPositive(generalStats.getFMeasure() * 100))); ret.append("\n"); SortedSet set = new TreeSet<>(new F1Comparator()); set.addAll(statsForOutcome.keySet()); for (String type : set) { ret.append(String.format(locale, FORMAT_EXTRA, type, zeroOrPositive(statsForOutcome.get(type).getPrecisionScore() * 100), zeroOrPositive(statsForOutcome.get(type).getRecallScore() * 100), zeroOrPositive(statsForOutcome.get(type).getFMeasure() * 100), statsForOutcome.get(type).getTarget(), statsForOutcome.get(type) .getTruePositives(), statsForOutcome.get(type) .getFalsePositives())); ret.append("\n"); } return ret.toString(); } @Override public String toString() { return createReport(); } private double zeroOrPositive(double v) { if (v < 0) { return 0; } return v; } private class F1Comparator implements Comparator { @Override public int compare(String o1, String o2) { if (o1.equals(o2)) return 0; double t1 = 0; double t2 = 0; if (statsForOutcome.containsKey(o1)) t1 += statsForOutcome.get(o1).getFMeasure(); if (statsForOutcome.containsKey(o2)) t2 += statsForOutcome.get(o2).getFMeasure(); t1 = zeroOrPositive(t1); t2 = zeroOrPositive(t2); if (t1 + t2 > 0d) { if (t1 > t2) return -1; return 1; } return o1.compareTo(o2); } } /** * Holds the statistics. */ private static class Stats { // maybe we could use FMeasure class, but it wouldn't allow us to get // details like total number of false positives and true positives. private int falsePositiveCounter = 0; private int truePositiveCounter = 0; private int targetCounter = 0; public void incrementFalsePositive() { falsePositiveCounter++; } public void incrementTruePositive() { truePositiveCounter++; } public void incrementTarget() { targetCounter++; } public int getFalsePositives() { return falsePositiveCounter; } public int getTruePositives() { return truePositiveCounter; } public int getTarget() { return targetCounter; } /** * Retrieves the arithmetic mean of the precision scores calculated for each * evaluated sample. * * @return the arithmetic mean of all precision scores */ public double getPrecisionScore() { int tp = getTruePositives(); int selected = tp + getFalsePositives(); return selected > 0 ? (double) tp / (double) selected : 0; } /** * Retrieves the arithmetic mean of the recall score calculated for each * evaluated sample. * * @return the arithmetic mean of all recall scores */ public double getRecallScore() { int target = getTarget(); int tp = getTruePositives(); return target > 0 ? (double) tp / (double) target : 0; } /** * Retrieves the f-measure score. *

* {@code f-measure = 2 * precision * recall / (precision + recall)} * * @return the f-measure or -1 if precision + recall <= 0 */ public double getFMeasure() { if (getPrecisionScore() + getRecallScore() > 0) { return 2 * (getPrecisionScore() * getRecallScore()) / (getPrecisionScore() + getRecallScore()); } else { // cannot divide by zero, return error code return -1; } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Evaluati0100644 0000000 0000000 00000000161 15217274217 032504 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/EvaluationErrorPrinter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/EvaluationErrorPrinter.j0100644 0000000 0000000 00000016640 15217274217 034171 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import opennlp.tools.commons.Internal; import opennlp.tools.util.Span; import opennlp.tools.util.eval.EvaluationMonitor; /** * Note: Do not use this class, internal use only! */ @Internal public abstract class EvaluationErrorPrinter implements EvaluationMonitor { protected PrintStream printStream; protected EvaluationErrorPrinter(OutputStream outputStream) { this(new PrintStream(outputStream)); } protected EvaluationErrorPrinter(PrintStream printStream) { this.printStream = printStream; } // for the sentence detector protected void printError(Span[] references, Span[] predictions, T referenceSample, T predictedSample, String sentence) { List falseNegatives = new ArrayList<>(); List falsePositives = new ArrayList<>(); findErrors(references, predictions, falseNegatives, falsePositives); if (falsePositives.size() + falseNegatives.size() > 0) { printSamples(referenceSample, predictedSample); printErrors(falsePositives, falseNegatives, sentence); } } // for namefinder, chunker... protected void printError(String id, Span[] references, Span[] predictions, T referenceSample, T predictedSample, String[] sentenceTokens) { List falseNegatives = new ArrayList<>(); List falsePositives = new ArrayList<>(); findErrors(references, predictions, falseNegatives, falsePositives); if (falsePositives.size() + falseNegatives.size() > 0) { if (id != null) { printStream.println("Id: {" + id + "}"); } printSamples(referenceSample, predictedSample); printErrors(falsePositives, falseNegatives, sentenceTokens); } } protected void printError(Span[] references, Span[] predictions, T referenceSample, T predictedSample, String[] sentenceTokens) { printError(null, references, predictions, referenceSample, predictedSample, sentenceTokens); } // for pos tagger protected void printError(String[] references, String[] predictions, T referenceSample, T predictedSample, String[] sentenceTokens) { List filteredDoc = new ArrayList<>(); List filteredRefs = new ArrayList<>(); List filteredPreds = new ArrayList<>(); for (int i = 0; i < references.length; i++) { if (!references[i].equals(predictions[i])) { filteredDoc.add(sentenceTokens[i]); filteredRefs.add(references[i]); filteredPreds.add(predictions[i]); } } if (filteredDoc.size() > 0) { printSamples(referenceSample, predictedSample); printErrors(filteredDoc, filteredRefs, filteredPreds); } } // for others protected void printError(T referenceSample, T predictedSample) { printSamples(referenceSample, predictedSample); printStream.println(); } /** * Auxiliary method to print tag errors * * @param filteredDoc * the document tokens which were tagged wrong * @param filteredRefs * the reference tags * @param filteredPreds * the predicted tags */ private void printErrors(List filteredDoc, List filteredRefs, List filteredPreds) { printStream.println("Errors: {"); printStream.println("Tok: Ref | Pred"); printStream.println("---------------"); for (int i = 0; i < filteredDoc.size(); i++) { printStream.println(filteredDoc.get(i) + ": " + filteredRefs.get(i) + " | " + filteredPreds.get(i)); } printStream.println("}\n"); } /** * Auxiliary method to print span errors * * @param falsePositives * false positives span * @param falseNegatives * false negative span * @param doc * the document text */ private void printErrors(List falsePositives, List falseNegatives, String doc) { printStream.println("False positives: {"); for (Span span : falsePositives) { printStream.println(span.getCoveredText(doc)); } printStream.println("} False negatives: {"); for (Span span : falseNegatives) { printStream.println(span.getCoveredText(doc)); } printStream.println("}\n"); } /** * Auxiliary method to print span errors * * @param falsePositives * false positives span * @param falseNegatives * false negative span * @param toks * the document tokens */ private void printErrors(List falsePositives, List falseNegatives, String[] toks) { printStream.println("False positives: {"); printStream.println(print(falsePositives, toks)); printStream.println("} False negatives: {"); printStream.println(print(falseNegatives, toks)); printStream.println("}\n"); } /** * Auxiliary method to print spans * * @param spans * the span list * @param toks * the tokens array * @return the spans as string */ private String print(List spans, String[] toks) { return Arrays.toString(Span.spansToStrings( spans.toArray(new Span[0]), toks)); } /** * Auxiliary method to print expected and predicted samples. * * @param referenceSample The {@link S} from the references. * @param predictedSample The {@link S} of the predictions. */ private void printSamples(S referenceSample, S predictedSample) { String details = "Expected: {\n" + referenceSample + "}\nPredicted: {\n" + predictedSample + "}"; printStream.println(details); } /** * Outputs falseNegatives and falsePositives spans from the references and * predictions list. * * @param references The {@link Span spans} from the references. * @param predictions The {@link Span spans} of the predictions. * @param falseNegatives The false negatives list. * @param falsePositives The false positives list. */ private void findErrors(Span[] references, Span[] predictions, List falseNegatives, List falsePositives) { falseNegatives.addAll(Arrays.asList(references)); falsePositives.addAll(Arrays.asList(predictions)); for (Span referenceName : references) { for (Span prediction : predictions) { if (referenceName.equals(prediction)) { // got it, remove from fn and fp falseNegatives.remove(referenceName); falsePositives.remove(prediction); } } } } @Override public void correctlyClassified(T reference, T prediction) { // do nothing } @Override public abstract void misclassified(T reference, T prediction) ; } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_FineGrai0100644 0000000 0000000 00000000164 15217274217 032421 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/FineGrainedReportListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/FineGrainedReportListene0100644 0000000 0000000 00000074112 15217274217 034145 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.OutputStream; import java.io.PrintStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import opennlp.tools.util.Span; import opennlp.tools.util.eval.FMeasure; import opennlp.tools.util.eval.Mean; public abstract class FineGrainedReportListener { private static final char[] alpha = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; private final PrintStream printStream; private final Stats stats = new Stats(); public FineGrainedReportListener(PrintStream printStream) { this.printStream = printStream; } /** * Writes the report to the {@link OutputStream}. Should be called only after * the evaluation process. */ public FineGrainedReportListener(OutputStream outputStream) { this.printStream = new PrintStream(outputStream); } private static String generateAlphaLabel(int index) { char[] labelChars = new char[3]; int i; for (i = 2; i >= 0; i--) { if (index >= 0) { labelChars[i] = alpha[index % alpha.length]; index = index / alpha.length - 1; } else { labelChars[i] = ' '; } } return new String(labelChars); } public abstract void writeReport(); // api methods // general stats protected Stats getStats() { return this.stats; } private long getNumberOfSentences() { return stats.getNumberOfSentences(); } private double getAverageSentenceSize() { return stats.getAverageSentenceSize(); } private int getMinSentenceSize() { return stats.getMinSentenceSize(); } private int getMaxSentenceSize() { return stats.getMaxSentenceSize(); } private int getNumberOfTags() { return stats.getNumberOfTags(); } // token stats private double getAccuracy() { return stats.getAccuracy(); } private double getTokenAccuracy(String token) { return stats.getTokenAccuracy(token); } private SortedSet getTokensOrderedByFrequency() { return stats.getTokensOrderedByFrequency(); } private int getTokenFrequency(String token) { return stats.getTokenFrequency(token); } private int getTokenErrors(String token) { return stats.getTokenErrors(token); } private SortedSet getTokensOrderedByNumberOfErrors() { return stats.getTokensOrderedByNumberOfErrors(); } private SortedSet getTagsOrderedByErrors() { return stats.getTagsOrderedByErrors(); } private int getTagFrequency(String tag) { return stats.getTagFrequency(tag); } private int getTagErrors(String tag) { return stats.getTagErrors(tag); } private double getTagPrecision(String tag) { return stats.getTagPrecision(tag); } private double getTagRecall(String tag) { return stats.getTagRecall(tag); } private double getTagFMeasure(String tag) { return stats.getTagFMeasure(tag); } private SortedSet getConfusionMatrixTagset() { return stats.getConfusionMatrixTagset(); } private SortedSet getConfusionMatrixTagset(String token) { return stats.getConfusionMatrixTagset(token); } /** * Applies a {@link MessageFormat} number pattern using {@link Locale#ROOT}, so that the * figures in a report stay identical regardless of the JVM's default {@link Locale}. * * @param pattern The {@link MessageFormat} pattern to apply. * @param value The value to format. * * @return The formatted value. */ private static String formatNumber(String pattern, Object value) { return new MessageFormat(pattern, Locale.ROOT).format(new Object[] {value}); } private double[][] getConfusionMatrix() { return stats.getConfusionMatrix(); } private double[][] getConfusionMatrix(String token) { return stats.getConfusionMatrix(token); } private String matrixToString(SortedSet tagset, double[][] data, boolean filter) { // we don't want to print trivial cases (acc=1) int initialIndex = 0; String[] tags = tagset.toArray(new String[0]); StringBuilder sb = new StringBuilder(); int minColumnSize = Integer.MIN_VALUE; String[][] matrix = new String[data.length][data[0].length]; for (int i = 0; i < data.length; i++) { int j = 0; for (; j < data[i].length - 1; j++) { matrix[i][j] = data[i][j] > 0 ? Integer.toString((int) data[i][j]) : "."; if (minColumnSize < matrix[i][j].length()) { minColumnSize = matrix[i][j].length(); } } matrix[i][j] = formatNumber("{0,number,#.##%}", data[i][j]); if (data[i][j] == 1 && filter) { initialIndex = i + 1; } } final String headerFormat = "%" + (minColumnSize + 2) + "s "; // | 1234567 | final String cellFormat = "%" + (minColumnSize + 2) + "s "; // | 12345 | final String diagFormat = " %" + (minColumnSize + 2) + "s"; for (int i = initialIndex; i < tagset.size(); i++) { sb.append(String.format(headerFormat, generateAlphaLabel(i - initialIndex).trim())); } sb.append("| Accuracy | <-- classified as\n"); for (int i = initialIndex; i < data.length; i++) { int j = initialIndex; for (; j < data[i].length - 1; j++) { if (i == j) { String val = "<" + matrix[i][j] + ">"; sb.append(String.format(diagFormat, val)); } else { sb.append(String.format(cellFormat, matrix[i][j])); } } sb.append( String.format("| %-6s | %3s = ", matrix[i][j], generateAlphaLabel(i - initialIndex))).append(tags[i]); sb.append("\n"); } return sb.toString(); } protected void printGeneralStatistics() { printHeader("Evaluation summary"); printStream.append( String.format("%21s: %6s", "Number of sentences", getNumberOfSentences())).append("\n"); printStream.append( String.format("%21s: %6s", "Min sentence size", getMinSentenceSize())).append("\n"); printStream.append( String.format("%21s: %6s", "Max sentence size", getMaxSentenceSize())).append("\n"); printStream.append( String.format("%21s: %6s", "Average sentence size", formatNumber("{0,number,#.##}", getAverageSentenceSize()))).append("\n"); printStream.append( String.format("%21s: %6s", "Tags count", getNumberOfTags())).append("\n"); printStream.append( String.format("%21s: %6s", "Accuracy", formatNumber("{0,number,#.##%}", getAccuracy()))).append("\n"); printFooter("Evaluation Corpus Statistics"); } protected void printTokenOccurrencesRank() { printHeader("Most frequent tokens"); SortedSet toks = getTokensOrderedByFrequency(); final int maxLines = 20; int maxTokSize = 5; int count = 0; Iterator tokIterator = toks.iterator(); while (tokIterator.hasNext() && count++ < maxLines) { String tok = tokIterator.next(); if (tok.length() > maxTokSize) { maxTokSize = tok.length(); } } int tableSize = maxTokSize + 19; String format = "| %3s | %6s | %" + maxTokSize + "s |"; printLine(tableSize); printStream.append(String.format(format, "Pos", "Count", "Token")).append("\n"); printLine(tableSize); // get the first 20 errors count = 0; tokIterator = toks.iterator(); while (tokIterator.hasNext() && count++ < maxLines) { String tok = tokIterator.next(); int frequency = getTokenFrequency(tok); printStream.append(String.format(format, count, frequency, tok) ).append("\n"); } printLine(tableSize); printFooter("Most frequent tokens"); } protected void printTokenErrorRank() { printHeader("Tokens with the highest number of errors"); printStream.append("\n"); SortedSet toks = getTokensOrderedByNumberOfErrors(); int maxTokenSize = 5; int count = 0; Iterator tokIterator = toks.iterator(); while (tokIterator.hasNext() && count++ < 20) { String tok = tokIterator.next(); if (tok.length() > maxTokenSize) { maxTokenSize = tok.length(); } } int tableSize = 31 + maxTokenSize; String format = "| %" + maxTokenSize + "s | %6s | %5s | %7s |\n"; printLine(tableSize); printStream.append(String.format(format, "Token", "Errors", "Count", "% Err")); printLine(tableSize); // get the first 20 errors count = 0; tokIterator = toks.iterator(); while (tokIterator.hasNext() && count++ < 20) { String tok = tokIterator.next(); int ocurrencies = getTokenFrequency(tok); int errors = getTokenErrors(tok); String rate = formatNumber("{0,number,#.##%}", (double) errors / ocurrencies); printStream.append(String.format(format, tok, errors, ocurrencies, rate) ); } printLine(tableSize); printFooter("Tokens with the highest number of errors"); } protected void printTagsErrorRank() { printHeader("Detailed Accuracy By Tag"); SortedSet tags = getTagsOrderedByErrors(); printStream.append("\n"); int maxTagSize = 3; for (String t : tags) { if (t.length() > maxTagSize) { maxTagSize = t.length(); } } int tableSize = 65 + maxTagSize; String headerFormat = "| %" + maxTagSize + "s | %6s | %6s | %7s | %9s | %6s | %9s |\n"; String format = "| %" + maxTagSize + "s | %6s | %6s | %-7s | %-9s | %-6s | %-9s |\n"; printLine(tableSize); printStream.append(String.format(headerFormat, "Tag", "Errors", "Count", "% Err", "Precision", "Recall", "F-Measure")); printLine(tableSize); for (String tag : tags) { int ocurrencies = getTagFrequency(tag); int errors = getTagErrors(tag); String rate = formatNumber("{0,number,#.###}", (double) errors / ocurrencies); double p = getTagPrecision(tag); double r = getTagRecall(tag); double f = getTagFMeasure(tag); printStream.append(String.format(format, tag, errors, ocurrencies, rate, formatNumber("{0,number,#.###}", p > 0 ? p : 0), formatNumber("{0,number,#.###}", r > 0 ? r : 0), formatNumber("{0,number,#.###}", f > 0 ? f : 0)) ); } printLine(tableSize); printFooter("Tags with the highest number of errors"); } protected void printGeneralConfusionTable() { printHeader("Confusion matrix"); SortedSet labels = getConfusionMatrixTagset(); double[][] confusionMatrix = getConfusionMatrix(); printStream.append("\nTags with 100% accuracy: "); int line = 0; for (String label : labels) { if (confusionMatrix[line][confusionMatrix[0].length - 1] == 1) { printStream.append(label).append(" (") .append(Integer.toString((int) confusionMatrix[line][line])) .append(") "); } line++; } printStream.append("\n\n"); printStream.append(matrixToString(labels, confusionMatrix, true)); printFooter("Confusion matrix"); } protected void printDetailedConfusionMatrix() { printHeader("Confusion matrix for tokens"); printStream.append(" sorted by number of errors\n"); SortedSet toks = getTokensOrderedByNumberOfErrors(); for (String t : toks) { double acc = getTokenAccuracy(t); if (acc < 1) { printStream .append("\n[") .append(t) .append("]\n") .append( String.format("%12s: %-8s", "Accuracy", formatNumber("{0,number,#.##%}", acc))) .append("\n"); printStream.append( String.format("%12s: %-8s", "Ocurrencies", getTokenFrequency(t))).append("\n"); printStream.append( String.format("%12s: %-8s", "Errors", getTokenErrors(t))).append("\n"); SortedSet labels = getConfusionMatrixTagset(t); double[][] confusionMatrix = getConfusionMatrix(t); printStream.append(matrixToString(labels, confusionMatrix, false)); } } printFooter("Confusion matrix for tokens"); } /** Auxiliary method that prints a emphasised report header */ private void printHeader(String text) { printStream.append("=== ").append(text).append(" ===\n"); } /** Auxiliary method that prints a marker to the end of a report */ private void printFooter(String text) { printStream.append("\n<-end> ").append(text).append("\n\n"); } /** Auxiliary method that prints a horizontal line of a given size */ private void printLine(int size) { for (int i = 0; i < size; i++) { printStream.append("-"); } printStream.append("\n"); } /** * A comparator that sorts the confusion matrix labels according to the * accuracy of each line */ public static class MatrixLabelComparator implements Comparator { private final Map confusionMatrix; public MatrixLabelComparator(Map confusionMatrix) { this.confusionMatrix = confusionMatrix; } @Override public int compare(String o1, String o2) { if (o1.equals(o2)) { return 0; } ConfusionMatrixLine t1 = confusionMatrix.get(o1); ConfusionMatrixLine t2 = confusionMatrix.get(o2); if (t1 == null || t2 == null) { if (t1 == null) { return 1; } else { return -1; } } double r1 = t1.getAccuracy(); double r2 = t2.getAccuracy(); if (r1 == r2) { return o1.compareTo(o2); } if (r2 > r1) { return 1; } return -1; } } public static class GroupedMatrixLabelComparator implements Comparator { private final HashMap categoryAccuracy; private final Map confusionMatrix; public GroupedMatrixLabelComparator(Map confusionMatrix) { this.confusionMatrix = confusionMatrix; this.categoryAccuracy = new HashMap<>(); // compute grouped categories for (Entry entry : confusionMatrix.entrySet()) { final String key = entry.getKey(); final ConfusionMatrixLine confusionMatrixLine = entry.getValue(); final String category; if (key.contains("-")) { category = key.split("-")[0]; } else { category = key; } double currentAccuracy = categoryAccuracy.getOrDefault(category, 0.0d); categoryAccuracy.put(category, currentAccuracy + confusionMatrixLine.getAccuracy()); } } @Override public int compare(String o1, String o2) { if (o1.equals(o2)) { return 0; } String c1 = o1; String c2 = o2; if (o1.contains("-")) { c1 = o1.split("-")[0]; } if (o2.contains("-")) { c2 = o2.split("-")[0]; } if (c1.equals(c2)) { // same category - sort by confusion matrix ConfusionMatrixLine t1 = confusionMatrix.get(o1); ConfusionMatrixLine t2 = confusionMatrix.get(o2); if (t1 == null || t2 == null) { if (t1 == null) { return 1; } else { return -1; } } double r1 = t1.getAccuracy(); double r2 = t2.getAccuracy(); if (r1 == r2) { return o1.compareTo(o2); } if (r2 > r1) { return 1; } return -1; } else { // different category - sort by category Double t1 = categoryAccuracy.get(c1); Double t2 = categoryAccuracy.get(c2); if (t1 == null || t2 == null) { if (t1 == null) { return 1; } else { return -1; } } if (t1.equals(t2)) { return o1.compareTo(o2); } if (t2 > t1) { return 1; } return -1; } } } public Comparator getMatrixLabelComparator(Map confusionMatrix) { return new MatrixLabelComparator(confusionMatrix); } public static class SimpleLabelComparator implements Comparator { private final Map map; public SimpleLabelComparator(Map map) { this.map = map; } @Override public int compare(String o1, String o2) { if (o1.equals(o2)) { return 0; } int e1 = 0, e2 = 0; if (map.containsKey(o1)) e1 = map.get(o1).value(); if (map.containsKey(o2)) e2 = map.get(o2).value(); if (e1 == e2) { return o1.compareTo(o2); } return e2 - e1; } } public Comparator getLabelComparator(Map map) { return new SimpleLabelComparator(map); } public static class GroupedLabelComparator implements Comparator { private final HashMap categoryCounter; private final Map labelCounter; public GroupedLabelComparator(Map map) { this.labelCounter = map; this.categoryCounter = new HashMap<>(); // compute grouped categories for (Entry entry : labelCounter.entrySet()) { final String key = entry.getKey(); final Counter value = entry.getValue(); final String category; if (key.contains("-")) { category = key.split("-")[0]; } else { category = key; } int currentCount = categoryCounter.getOrDefault(category, 0); categoryCounter.put(category, currentCount + value.value()); } } @Override public int compare(String o1, String o2) { if (o1.equals(o2)) { return 0; } String c1 = o1; String c2 = o2; if (o1.contains("-")) { c1 = o1.split("-")[0]; } if (o2.contains("-")) { c2 = o2.split("-")[0]; } if (c1.equals(c2)) { // same category - sort by confusion matrix Counter t1 = labelCounter.get(o1); Counter t2 = labelCounter.get(o2); if (t1 == null || t2 == null) { if (t1 == null) { return 1; } else { return -1; } } int r1 = t1.value(); int r2 = t2.value(); if (r1 == r2) { return o1.compareTo(o2); } if (r2 > r1) { return 1; } return -1; } else { // different category - sort by category Integer t1 = categoryCounter.get(c1); Integer t2 = categoryCounter.get(c2); if (t1 == null || t2 == null) { if (t1 == null) { return 1; } else { return -1; } } if (t1.equals(t2)) { return o1.compareTo(o2); } if (t2 > t1) { return 1; } return -1; } } } /** * Represents a line in the confusion table. */ public static class ConfusionMatrixLine { private final Map line = new HashMap<>(); private final String ref; private int total = 0; private int correct = 0; private double acc = -1; /** * Creates a new {@link ConfusionMatrixLine} * * @param ref * the reference column */ private ConfusionMatrixLine(String ref) { this.ref = ref; } /** * Increments the counter for the given column and updates the statistics. * * @param column * the column to be incremented */ private void increment(String column) { total++; if (column.equals(ref)) correct++; if (!line.containsKey(column)) { line.put(column, new Counter()); } line.get(column).increment(); } /** * @return Retrieves the calculated accuracy of this element */ public double getAccuracy() { // we save the accuracy because it is frequently used by the comparator if (StrictMath.abs(acc - 1.0d) < 0.0000000001) { if (total == 0) acc = 0.0d; acc = (double) correct / (double) total; } return acc; } /** * @param column The column to retrieve the counter value for. * @return Retrieves the counter value for the given {@code column}. */ public int getValue(String column) { Counter c = line.get(column); if (c == null) return 0; return c.value(); } } /** * Implements a simple counter */ public static class Counter { private int c = 0; private void increment() { c++; } public int value() { return c; } } public class Stats { // general statistics private final Mean accuracy = new Mean(); private final Mean averageSentenceLength = new Mean(); // token statistics private final Map tokAccuracies = new HashMap<>(); private final Map tokOccurrences = new HashMap<>(); private final Map tokErrors = new HashMap<>(); // tag statistics private final Map tagOccurrences = new HashMap<>(); private final Map tagErrors = new HashMap<>(); private final Map tagFMeasure = new HashMap<>(); // represents a Confusion Matrix that aggregates all tokens private final Map generalConfusionMatrix = new HashMap<>(); // represents a set of Confusion Matrix for each token private final Map> tokenConfusionMatrix = new HashMap<>(); private int minimalSentenceLength = Integer.MAX_VALUE; private int maximumSentenceLength = Integer.MIN_VALUE; public void add(String[] toks, String[] refs, String[] preds) { int length = toks.length; averageSentenceLength.add(length); if (minimalSentenceLength > length) { minimalSentenceLength = length; } if (maximumSentenceLength < length) { maximumSentenceLength = length; } updateTagFMeasure(refs, preds); for (int i = 0; i < toks.length; i++) { commit(toks[i], refs[i], preds[i]); } } public void add(int length, String ref, String pred) { averageSentenceLength.add(length); if (minimalSentenceLength > length) { minimalSentenceLength = length; } if (maximumSentenceLength < length) { maximumSentenceLength = length; } // String[] toks = reference.getSentence(); String[] refs = { ref }; String[] preds = { pred }; updateTagFMeasure(refs, preds); commit("", ref, pred); } public void add(String[] text, String ref, String pred) { int length = text.length; this.add(length, ref, pred); } public void add(CharSequence text, String ref, String pred) { int length = text.length(); this.add(length, ref, pred); } /** * Includes new evaluation data. * * @param tok * the evaluated token * @param ref * the reference pos tag * @param pred * the predicted pos tag */ private void commit(String tok, String ref, String pred) { // token stats if (!tokAccuracies.containsKey(tok)) { tokAccuracies.put(tok, new Mean()); tokOccurrences.put(tok, new Counter()); tokErrors.put(tok, new Counter()); } tokOccurrences.get(tok).increment(); // tag stats if (!tagOccurrences.containsKey(ref)) { tagOccurrences.put(ref, new Counter()); tagErrors.put(ref, new Counter()); } tagOccurrences.get(ref).increment(); // updates general, token and tag error stats if (ref.equals(pred)) { tokAccuracies.get(tok).add(1); accuracy.add(1); } else { tokAccuracies.get(tok).add(0); tokErrors.get(tok).increment(); tagErrors.get(ref).increment(); accuracy.add(0); } // populate confusion matrixes if (!generalConfusionMatrix.containsKey(ref)) { generalConfusionMatrix.put(ref, new ConfusionMatrixLine(ref)); } generalConfusionMatrix.get(ref).increment(pred); if (!tokenConfusionMatrix.containsKey(tok)) { tokenConfusionMatrix.put(tok, new HashMap<>()); } if (!tokenConfusionMatrix.get(tok).containsKey(ref)) { tokenConfusionMatrix.get(tok).put(ref, new ConfusionMatrixLine(ref)); } tokenConfusionMatrix.get(tok).get(ref).increment(pred); } private void updateTagFMeasure(String[] refs, String[] preds) { // create a set with all tags Set tags = new HashSet<>(Arrays.asList(refs)); tags.addAll(Arrays.asList(preds)); // create samples for each tag for (String tag : tags) { List reference = new ArrayList<>(); List prediction = new ArrayList<>(); for (int i = 0; i < refs.length; i++) { if (refs[i].equals(tag)) { reference.add(new Span(i, i + 1)); } if (preds[i].equals(tag)) { prediction.add(new Span(i, i + 1)); } } if (!this.tagFMeasure.containsKey(tag)) { this.tagFMeasure.put(tag, new FMeasure()); } // populate the F-measure this.tagFMeasure.get(tag).updateScores( reference.toArray(new Span[0]), prediction.toArray(new Span[0])); } } private double getAccuracy() { return accuracy.mean(); } private int getNumberOfTags() { return this.tagOccurrences.keySet().size(); } private long getNumberOfSentences() { return this.averageSentenceLength.count(); } private double getAverageSentenceSize() { return this.averageSentenceLength.mean(); } private int getMinSentenceSize() { return this.minimalSentenceLength; } private int getMaxSentenceSize() { return this.maximumSentenceLength; } private double getTokenAccuracy(String token) { return tokAccuracies.get(token).mean(); } private int getTokenErrors(String token) { return tokErrors.get(token).value(); } private int getTokenFrequency(String token) { return tokOccurrences.get(token).value(); } private SortedSet getTokensOrderedByFrequency() { SortedSet toks = new TreeSet<>(new SimpleLabelComparator(tokOccurrences)); toks.addAll(tokOccurrences.keySet()); return Collections.unmodifiableSortedSet(toks); } private SortedSet getTokensOrderedByNumberOfErrors() { SortedSet toks = new TreeSet<>(new SimpleLabelComparator(tokErrors)); toks.addAll(tokErrors.keySet()); return toks; } private int getTagFrequency(String tag) { return tagOccurrences.get(tag).value(); } private int getTagErrors(String tag) { return tagErrors.get(tag).value(); } private double getTagFMeasure(String tag) { return tagFMeasure.get(tag).getFMeasure(); } private double getTagRecall(String tag) { return tagFMeasure.get(tag).getRecallScore(); } private double getTagPrecision(String tag) { return tagFMeasure.get(tag).getPrecisionScore(); } private SortedSet getTagsOrderedByErrors() { SortedSet tags = new TreeSet<>(getLabelComparator(tagErrors)); tags.addAll(tagErrors.keySet()); return Collections.unmodifiableSortedSet(tags); } private SortedSet getConfusionMatrixTagset() { return getConfusionMatrixTagset(generalConfusionMatrix); } private double[][] getConfusionMatrix() { return createConfusionMatrix(getConfusionMatrixTagset(), generalConfusionMatrix); } private SortedSet getConfusionMatrixTagset(String token) { return getConfusionMatrixTagset(tokenConfusionMatrix.get(token)); } private double[][] getConfusionMatrix(String token) { return createConfusionMatrix(getConfusionMatrixTagset(token), tokenConfusionMatrix.get(token)); } /** * Creates a matrix with {@code N} lines and {@code N + 1} columns with the data from * confusion matrix. The last column is the accuracy. */ private double[][] createConfusionMatrix(SortedSet tagset, Map data) { int size = tagset.size(); double[][] matrix = new double[size][size + 1]; int line = 0; for (String ref : tagset) { int column = 0; for (String pred : tagset) { matrix[line][column] = data.get(ref) != null ? data .get(ref).getValue(pred) : 0; column++; } // set accuracy matrix[line][column] = data.get(ref) != null ? data.get(ref).getAccuracy() : 0; line++; } return matrix; } private SortedSet getConfusionMatrixTagset( Map data) { SortedSet tags = new TreeSet<>(getMatrixLabelComparator(data)); tags.addAll(data.keySet()); List col = new LinkedList<>(); for (String t : tags) { col.addAll(data.get(t).line.keySet()); } tags.addAll(col); return Collections.unmodifiableSortedSet(tags); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/GenerateManualTool.java0100644 0000000 0000000 00000023565 15217274217 033726 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.io.StringReader; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.StringTokenizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.ArgumentParser.Argument; public class GenerateManualTool { private static final Logger logger = LoggerFactory.getLogger(GenerateManualTool.class); private static final int MAX_LINE_LENGTH = 110; // optimized for printing public static void main(String[] args) throws FileNotFoundException { if (args.length != 1) { logger.info(getUsage()); System.exit(0); } StringBuilder sb = new StringBuilder(); appendHeader(sb); // organize by package name LinkedHashMap> packageNameToolMap = new LinkedHashMap<>(); for (Entry entry : CLI.getToolLookupMap().entrySet()) { final String toolName = entry.getKey(); final CmdLineTool tool = entry.getValue(); String packageName = tool.getClass().getPackage().getName(); packageName = packageName.substring(packageName.lastIndexOf(".") + 1); if (!packageNameToolMap.containsKey(packageName)) { packageNameToolMap.put(packageName, new LinkedHashMap<>()); } packageNameToolMap.get(packageName).put(toolName, tool); } // add tools grouped by package for (Entry> entry : packageNameToolMap.entrySet()) { appendToolGroup(entry.getKey(), entry.getValue(), sb); } // footer appendFooter(sb); // output to file try (PrintWriter out = new PrintWriter(args[0])) { out.println(sb); } } /** * @return this tool usage */ private static String getUsage() { return "Requires one argument: \n" + " Path to the output XML file \n"; } /** * Appends a group of tools, based on the tool package name * * @param groupName The groupName to use. * @param toolsMap The {@link Map} of all cmd-line tools available. * @param sb The {@link StringBuilder} to fill. */ private static void appendToolGroup(String groupName, Map toolsMap, StringBuilder sb) { sb.append("

\n\n"); sb.append("").append(firstCaps(groupName)).append("\n\n"); for (Entry entry : toolsMap.entrySet()) { appendTool(groupName, entry.getKey(), entry.getValue(), sb); } sb.append("
\n\n"); } /** * Appends a tool. * * @param groupName The groupName to use. * @param toolName The name of the tool to use. * @param tool The {@link CmdLineTool} to append. * @param sb The {@link StringBuilder} to fill. */ private static void appendTool(String groupName, String toolName, CmdLineTool tool, StringBuilder sb) { sb.append("
\n\n"); sb.append("").append(toolName).append("\n\n"); sb.append("").append(firstCaps(tool.getShortDescription())) .append("\n\n"); appendCode(tool.getHelp(), sb); if (TypedCmdLineTool.class.isAssignableFrom(tool.getClass())) { appendHelpForTool((TypedCmdLineTool) tool, sb); } sb.append("
\n\n"); } private static void appendHelpForTool(TypedCmdLineTool tool, StringBuilder sb) { Class type = tool.type; Set formats = StreamFactoryRegistry.getFactories(type).keySet(); sb.append("The supported formats and arguments are:\n\n"); Map> formatArguments = new LinkedHashMap<>(); for (String formatName : formats) { if (!StreamFactoryRegistry.DEFAULT_FORMAT.equals(formatName)) { ObjectStreamFactory format = tool.getStreamFactory(formatName); formatArguments.put(formatName, ArgumentParser.createArguments(format.getParameters())); } } appendArgumentTable(formatArguments, sb); } private static void appendArgumentTable( Map> formatArguments, StringBuilder sb) { sb.append( "\n"); sb.append( "FormatArgumentValue" + "OptionalDescription\n"); sb.append("\n"); for (Entry> entry : formatArguments.entrySet()) { final String format = entry.getKey(); final List arguments = entry.getValue(); int i = 0; for (Argument argument : arguments) { sb.append("\n"); if (i == 0) { sb.append("").append(format).append("\n"); } sb.append("").append(argument.argument()) .append("\n"); sb.append("").append(argument.value()).append("\n"); sb.append("").append(yes(argument.optional())) .append("\n"); sb.append("").append(firstCaps(argument.description())) .append("\n"); sb.append("\n"); i++; } } sb.append("\n"); sb.append("\n\n"); } private static void appendHeader(StringBuilder sb) { sb.append("\n" + "\n" + "\n" + "\n\n" + "\n\n" + "\n\n" + "The Command Line Interface\n\n" + "" + "This section details the available tools and parameters of the Command Line Interface. " + "For a introduction in its usage please refer to . " + "\n\n"); } private static void appendFooter(StringBuilder sb) { sb.append("\n\n"); } private static String firstCaps(String str) { if (str.length() > 1) { return str.substring(0, 1).toUpperCase() + str.substring(1); } else { return str; } } private static String yes(boolean optional) { if (optional) { return "Yes"; } return "No"; } private static void appendCode(String help, StringBuilder sb) { sb.append("\n" + "\n").append(" \n"); } /** * Prevents long lines. Lines are optimized for printing. */ private static String splitLongLines(String stringBlock) { StringBuilder sb = new StringBuilder(); String line; try (BufferedReader reader = new BufferedReader(new StringReader(stringBlock))) { while ((line = reader.readLine()) != null) { if (line.length() <= MAX_LINE_LENGTH) { sb.append(line).append("\n"); } else { StringTokenizer tok = new StringTokenizer(line, " "); int lineLen = 0; while (tok.hasMoreTokens()) { String word = tok.nextToken() + " "; if (lineLen + word.length() > MAX_LINE_LENGTH) { sb.append("\n "); lineLen = 8; } sb.append(word); lineLen += word.length(); } } } } catch (Exception e) { // nothing to do } return sb.toString(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/ModelLoader.java0100644 0000000 0000000 00000004732 15217274217 032362 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Internal; import opennlp.tools.util.InvalidFormatException; /** * Loads a model and does all the error handling for the command line tools. *

* Note: Do not use this class, internal use only! * * @param */ @Internal public abstract class ModelLoader { private static final Logger logger = LoggerFactory.getLogger(ModelLoader.class); private final String modelName; protected ModelLoader(String modelName) { this.modelName = Objects.requireNonNull(modelName, "modelName must not be null!"); } protected abstract T loadModel(InputStream modelIn) throws IOException; public T load(File modelFile) { long beginModelLoadingTime = System.currentTimeMillis(); CmdLineUtil.checkInputFile(modelName + " model", modelFile); logger.info("Loading {} model ... ", modelName); T model; try (InputStream modelIn = new BufferedInputStream( CmdLineUtil.openInFile(modelFile), CmdLineUtil.IO_BUFFER_SIZE)) { model = loadModel(modelIn); } catch (InvalidFormatException e) { throw new TerminateToolException(-1, "Model has invalid format", e); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while loading model file '" + modelFile + "'", e); } long modelLoadingDuration = System.currentTimeMillis() - beginModelLoadingTime; logger.info(String.format("done (%.3fs)\n", modelLoadingDuration / 1000d)); return model; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_ObjectSt0100644 0000000 0000000 00000000156 15217274217 032453 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/ObjectStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/ObjectStreamFactory.java0100644 0000000 0000000 00000002323 15217274217 034077 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import opennlp.tools.util.ObjectStream; public interface ObjectStreamFactory { /** * @return Retrieves interface with parameters description. */ Class

getParameters(); /** * Creates an {@link ObjectStream} of the template type {@code T}. * * @param args arguments * @return The created {@link ObjectStream} instance. */ ObjectStream create(String[] args); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/PerformanceMonitor.java0100644 0000000 0000000 00000011317 15217274217 034001 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.PrintStream; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Internal; import opennlp.tools.log.LogPrintStream; /** * The {@link PerformanceMonitor} measures increments to a counter. * During the computation it prints out current and average throughput * per second. After the computation is done it prints a final performance * report. *

* Note: This class is not thread safe. *

* Note: Do not use this class, internal use only! */ @Internal public class PerformanceMonitor { private static final Logger logger = LoggerFactory.getLogger(PerformanceMonitor.class); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, runnable -> { Thread thread = new Thread(runnable); thread.setName("opennlp.tools.cmdline.PerformanceMonitor"); thread.setDaemon(true); return thread; }); private final String unit; private ScheduledFuture beeperHandle; private volatile long startTime = -1; private volatile int counter; private final PrintStream out; public PerformanceMonitor(PrintStream out, String unit) { this.out = out; this.unit = unit; } public PerformanceMonitor(String unit) { this(new LogPrintStream(logger), unit); } public boolean isStarted() { return startTime != -1; } public void incrementCounter(int increment) { if (!isStarted()) throw new IllegalStateException("Must be started first!"); if (increment < 0) throw new IllegalArgumentException("increment must be zero or positive but was " + increment + "!"); counter += increment; } public void incrementCounter() { incrementCounter(1); } public void start() { if (isStarted()) throw new IllegalStateException("Already started!"); startTime = System.currentTimeMillis(); } public void startAndPrintThroughput() { start(); final Runnable beeper = new Runnable() { private long lastTimeStamp = startTime; private int lastCount = counter; @Override public void run() { int deltaCount = counter - lastCount; long timePassedSinceLastCount = System.currentTimeMillis() - lastTimeStamp; double currentThroughput; if (timePassedSinceLastCount > 0) { currentThroughput = deltaCount / ((double) timePassedSinceLastCount / 1000); } else { currentThroughput = 0; } long totalTimePassed = System.currentTimeMillis() - startTime; double averageThroughput; if (totalTimePassed > 0) { averageThroughput = counter / (((double) totalTimePassed) / 1000); } else { averageThroughput = 0; } out.printf("current: %.1f " + unit + "/s avg: %.1f " + unit + "/s total: %d " + unit + "%n", currentThroughput, averageThroughput, counter); lastTimeStamp = System.currentTimeMillis(); lastCount = counter; } }; beeperHandle = scheduler.scheduleAtFixedRate(beeper, 1, 1, TimeUnit.SECONDS); } public void stopAndPrintFinalResult() { if (!isStarted()) throw new IllegalStateException("Must be started first!"); if (beeperHandle != null) { // yeah we have time to finish current // printing if there is one beeperHandle.cancel(false); } scheduler.shutdown(); long timePassed = System.currentTimeMillis() - startTime; double average; if (timePassed > 0) { average = counter / (timePassed / 1000d); } else { average = 0; } out.printf("Average: %.1f " + unit + "/s %n", average); out.println("Total: " + counter + " " + unit); out.println("Runtime: " + timePassed / 1000d + "s"); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_StreamFa0100644 0000000 0000000 00000000160 15217274217 032433 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/StreamFactoryRegistry.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/StreamFactoryRegistry.ja0100644 0000000 0000000 00000024734 15217274217 034164 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.util.HashMap; import java.util.Map; import opennlp.tools.formats.BioNLP2004NameSampleStreamFactory; import opennlp.tools.formats.ChunkerSampleStreamFactory; import opennlp.tools.formats.Conll02NameSampleStreamFactory; import opennlp.tools.formats.Conll03NameSampleStreamFactory; import opennlp.tools.formats.ConllXPOSSampleStreamFactory; import opennlp.tools.formats.ConllXSentenceSampleStreamFactory; import opennlp.tools.formats.ConllXTokenSampleStreamFactory; import opennlp.tools.formats.DocumentSampleStreamFactory; import opennlp.tools.formats.EvalitaNameSampleStreamFactory; import opennlp.tools.formats.LanguageDetectorSampleStreamFactory; import opennlp.tools.formats.LemmatizerSampleStreamFactory; import opennlp.tools.formats.NameSampleDataStreamFactory; import opennlp.tools.formats.ParseSampleStreamFactory; import opennlp.tools.formats.SentenceSampleStreamFactory; import opennlp.tools.formats.TokenSampleStreamFactory; import opennlp.tools.formats.TwentyNewsgroupSampleStreamFactory; import opennlp.tools.formats.WordTagSampleStreamFactory; import opennlp.tools.formats.ad.ADChunkSampleStreamFactory; import opennlp.tools.formats.ad.ADNameSampleStreamFactory; import opennlp.tools.formats.ad.ADPOSSampleStreamFactory; import opennlp.tools.formats.ad.ADSentenceSampleStreamFactory; import opennlp.tools.formats.ad.ADTokenSampleStreamFactory; import opennlp.tools.formats.brat.BratNameSampleStreamFactory; import opennlp.tools.formats.conllu.ConlluLemmaSampleStreamFactory; import opennlp.tools.formats.conllu.ConlluPOSSampleStreamFactory; import opennlp.tools.formats.conllu.ConlluSentenceSampleStreamFactory; import opennlp.tools.formats.conllu.ConlluTokenSampleStreamFactory; import opennlp.tools.formats.convert.NameToSentenceSampleStreamFactory; import opennlp.tools.formats.convert.NameToTokenSampleStreamFactory; import opennlp.tools.formats.convert.POSToSentenceSampleStreamFactory; import opennlp.tools.formats.convert.POSToTokenSampleStreamFactory; import opennlp.tools.formats.convert.ParseToPOSSampleStreamFactory; import opennlp.tools.formats.convert.ParseToSentenceSampleStreamFactory; import opennlp.tools.formats.convert.ParseToTokenSampleStreamFactory; import opennlp.tools.formats.frenchtreebank.ConstitParseSampleStreamFactory; import opennlp.tools.formats.irishsentencebank.IrishSentenceBankSentenceStreamFactory; import opennlp.tools.formats.irishsentencebank.IrishSentenceBankTokenSampleStreamFactory; import opennlp.tools.formats.leipzig.LeipzigLanguageSampleStreamFactory; import opennlp.tools.formats.letsmt.LetsmtSentenceStreamFactory; import opennlp.tools.formats.masc.MascNamedEntitySampleStreamFactory; import opennlp.tools.formats.masc.MascPOSSampleStreamFactory; import opennlp.tools.formats.masc.MascSentenceSampleStreamFactory; import opennlp.tools.formats.masc.MascTokenSampleStreamFactory; import opennlp.tools.formats.moses.MosesSentenceSampleStreamFactory; import opennlp.tools.formats.muc.Muc6NameSampleStreamFactory; import opennlp.tools.formats.nkjp.NKJPSentenceSampleStreamFactory; import opennlp.tools.formats.ontonotes.OntoNotesNameSampleStreamFactory; import opennlp.tools.formats.ontonotes.OntoNotesPOSSampleStreamFactory; import opennlp.tools.formats.ontonotes.OntoNotesParseSampleStreamFactory; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.ext.ExtensionNotLoadedException; /** * Registry for {@link ObjectStreamFactory object stream factories}. */ public final class StreamFactoryRegistry { private static final Map, Map>> registry = new HashMap<>(); static { ChunkerSampleStreamFactory.registerFactory(); DocumentSampleStreamFactory.registerFactory(); NameSampleDataStreamFactory.registerFactory(); ParseSampleStreamFactory.registerFactory(); SentenceSampleStreamFactory.registerFactory(); TokenSampleStreamFactory.registerFactory(); WordTagSampleStreamFactory.registerFactory(); LemmatizerSampleStreamFactory.registerFactory(); LanguageDetectorSampleStreamFactory.registerFactory(); NameToSentenceSampleStreamFactory.registerFactory(); NameToTokenSampleStreamFactory.registerFactory(); POSToSentenceSampleStreamFactory.registerFactory(); POSToTokenSampleStreamFactory.registerFactory(); ParseToPOSSampleStreamFactory.registerFactory(); ParseToSentenceSampleStreamFactory.registerFactory(); ParseToTokenSampleStreamFactory.registerFactory(); OntoNotesNameSampleStreamFactory.registerFactory(); OntoNotesParseSampleStreamFactory.registerFactory(); OntoNotesPOSSampleStreamFactory.registerFactory(); BioNLP2004NameSampleStreamFactory.registerFactory(); Conll02NameSampleStreamFactory.registerFactory(); Conll03NameSampleStreamFactory.registerFactory(); EvalitaNameSampleStreamFactory.registerFactory(); ConllXPOSSampleStreamFactory.registerFactory(); ConllXSentenceSampleStreamFactory.registerFactory(); ConllXTokenSampleStreamFactory.registerFactory(); ADChunkSampleStreamFactory.registerFactory(); ADNameSampleStreamFactory.registerFactory(); ADSentenceSampleStreamFactory.registerFactory(); ADPOSSampleStreamFactory.registerFactory(); ADTokenSampleStreamFactory.registerFactory(); TwentyNewsgroupSampleStreamFactory.registerFactory(); Muc6NameSampleStreamFactory.registerFactory(); ConstitParseSampleStreamFactory.registerFactory(); BratNameSampleStreamFactory.registerFactory(); LetsmtSentenceStreamFactory.registerFactory(); MosesSentenceSampleStreamFactory.registerFactory(); ConlluTokenSampleStreamFactory.registerFactory(); ConlluSentenceSampleStreamFactory.registerFactory(); ConlluPOSSampleStreamFactory.registerFactory(); ConlluLemmaSampleStreamFactory.registerFactory(); IrishSentenceBankSentenceStreamFactory.registerFactory(); IrishSentenceBankTokenSampleStreamFactory.registerFactory(); LeipzigLanguageSampleStreamFactory.registerFactory(); NKJPSentenceSampleStreamFactory.registerFactory(); MascNamedEntitySampleStreamFactory.registerFactory(); MascPOSSampleStreamFactory.registerFactory(); MascSentenceSampleStreamFactory.registerFactory(); MascTokenSampleStreamFactory.registerFactory(); } public static final String DEFAULT_FORMAT = "opennlp"; private StreamFactoryRegistry() { // not intended to be instantiated } /** * Registers factory which reads format named {@code formatName} and * instantiates streams producing objects of {@code sampleClass} class. * * @param sampleClass class of the objects, produced by the streams instantiated by the factory * @param formatName name of the format * @param factory instance of the factory * @return true if the factory was successfully registered */ public static boolean registerFactory(Class sampleClass, String formatName, ObjectStreamFactory factory) { boolean result; Map> formats = registry.get(sampleClass); if (null == formats) { formats = new HashMap<>(); } if (!formats.containsKey(formatName)) { formats.put(formatName, factory); registry.put(sampleClass, formats); result = true; } else { result = false; } return result; } /** * Unregisters a factory which reads format named {@code formatName} and * instantiates streams producing objects of {@code sampleClass} class. * * @param sampleClass class of the objects, produced by the streams instantiated by the factory * @param formatName name of the format */ public static void unregisterFactory(Class sampleClass, String formatName) { Map> formats = registry.get(sampleClass); if (null != formats) { formats.remove(formatName); } } /** * Returns all factories which produce objects of {@code sampleClass} class. * * @param sampleClass class of the objects, produced by the streams instantiated by the factory * @return formats mapped to factories */ @SuppressWarnings("unchecked") public static Map> getFactories(Class sampleClass) { return (Map>) (Object) registry.get(sampleClass); } /** * Returns a factory which reads format named {@code formatName} and * instantiates streams producing objects of {@code sampleClass} class. *

* If no factory is registered for {@code formatName}, an attempt is made to * interpret {@code formatName} as the fully qualified class name of an * {@link ObjectStreamFactory} implementation and load it via the * {@link ExtensionLoader}. Such a class must reside in an allowed package, * see {@link ExtensionLoader#registerAllowedPackage(String)}. * * @param sampleClass class of the objects, produced by the streams instantiated by the factory * @param formatName name of the format, if null, assumes OpenNLP format * @return factory instance, or {@code null} if no factory could be found or loaded */ @SuppressWarnings("unchecked") public static ObjectStreamFactory getFactory(Class sampleClass, String formatName) { if (null == formatName) { formatName = DEFAULT_FORMAT; } ObjectStreamFactory factory = registry.containsKey(sampleClass) ? (ObjectStreamFactory) registry.get(sampleClass).get(formatName) : null; if (factory != null) { return factory; } else { try { return (ObjectStreamFactory) ExtensionLoader.instantiateExtension(ObjectStreamFactory.class, formatName); } catch (ExtensionNotLoadedException e) { return null; } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_SystemIn0100644 0000000 0000000 00000000163 15217274217 032507 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/SystemInputStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/SystemInputStreamFactory0100644 0000000 0000000 00000002610 15217274217 034254 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.io.InputStream; import java.nio.charset.Charset; import opennlp.tools.util.InputStreamFactory; public class SystemInputStreamFactory implements InputStreamFactory { private boolean isTainted = false; public static Charset encoding() { return Charset.defaultCharset(); } @Override public InputStream createInputStream() { if (!isTainted) { isTainted = true; return System.in; } else { throw new UnsupportedOperationException( "The System.in stream can't be re-created to read from the beginning!"); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_Terminat0100644 0000000 0000000 00000000161 15217274217 032515 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/TerminateToolException.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/TerminateToolException.j0100644 0000000 0000000 00000004011 15217274217 034136 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import opennlp.tools.commons.Internal; /** * Exception to terminate the execution of a command line tool. *

* The exception should be thrown to indicate that the VM should be terminated with * the specified error code, instead of just calling {@link System#exit(int)}. *

* The return code convention is to return:
* {@code 0} in case of graceful termination
* {@code -1} in case of runtime errors, such as {@link java.io.IOException}
* {@code 1} in case of invalid parameters. *

* Note: Do not use this class, internal use only! */ @Internal public class TerminateToolException extends RuntimeException { private static final long serialVersionUID = -8501408388025885818L; private final int code; private final String message; public TerminateToolException(int code, String message, Throwable t) { super(t); this.code = code; this.message = message; } public TerminateToolException(int code, String message) { this.code = code; this.message = message; } public TerminateToolException(int code) { this(code, null); } public int getCode() { return code; } @Override public String getMessage() { return message; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/TypedCmdLineTool.java0100644 0000000 0000000 00000010356 15217274217 033351 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline; import java.util.Map; /** * Base class for tools which support processing of samples of some type {@link T} * coming from a stream of a certain format. */ public abstract class TypedCmdLineTool extends CmdLineTool { /** * variable to access the type of the generic parameter. */ protected final Class type; /** * Constructor with type parameters. * * @param sampleType class of the template parameter */ protected TypedCmdLineTool(Class sampleType) { this.type = sampleType; } /** * Returns stream factory for the type of this tool for the format. * * @param format data format name * @return The {@link ObjectStreamFactory factory} for the type of this tool for the format. */ protected ObjectStreamFactory getStreamFactory(String format) { ObjectStreamFactory factory = StreamFactoryRegistry.getFactory(type, format); if (null != factory) { return factory; } else { throw new TerminateToolException(1, "Format " + format + " is not found.\n" + getHelp()); } } /** * Validates arguments using parameters from {@code argProxyInterface} and the parameters of the * format. * * @param args arguments * @param argProxyInterface interface with parameter descriptions * @param format data format name * @param The generic type. */ protected void validateAllArgs(String[] args, Class argProxyInterface, String format) { ObjectStreamFactory factory = getStreamFactory(format); String errMessage = ArgumentParser.validateArgumentsLoudly(args, argProxyInterface, factory.getParameters()); if (null != errMessage) { throw new TerminateToolException(1, errMessage + "\n" + getHelp(format)); } } /** * Validates arguments for a format processed by the {@code factory}. * @param factory The {@link ObjectStreamFactory factory} to use. * @param args arguments */ protected void validateFactoryArgs(ObjectStreamFactory factory, String[] args) { String errMessage = ArgumentParser.validateArgumentsLoudly(args, factory.getParameters()); if (null != errMessage) { throw new TerminateToolException(1, "Format parameters are invalid: " + errMessage + "\n" + "Usage: " + ArgumentParser.createUsage(factory.getParameters())); } } @Override protected String getBasicHelp(Class... argProxyInterfaces) { Map> factories = StreamFactoryRegistry.getFactories(type); String formatsHelp = " "; if (1 < factories.size()) { StringBuilder formats = new StringBuilder(); for (String format : factories.keySet()) { if (!StreamFactoryRegistry.DEFAULT_FORMAT.equals(format)) { formats.append(".").append(format).append("|"); } } formatsHelp = "[" + formats.substring(0, formats.length() - 1) + "] "; } return "Usage: " + CLI.CMD + " " + getName() + formatsHelp + ArgumentParser.createUsage(argProxyInterfaces); } @Override public String getHelp() { return getHelp(""); } /** * Executes the tool with the given parameters. * * @param format format to work with * @param args command line arguments */ public abstract void run(String format, String[] args); /** * @param format data format * @return Retrieves a description on how to use the tool. */ public abstract String getHelp(String format); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000177 15217274217 032537 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkEvaluationE0100644 0000000 0000000 00000004067 15217274217 034120 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.chunker.ChunkerEvaluationMonitor; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.log.LogPrintStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints * to an output stream. * */ public class ChunkEvaluationErrorListener extends EvaluationErrorPrinter implements ChunkerEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(ChunkEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public ChunkEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream} */ public ChunkEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(ChunkSample reference, ChunkSample prediction) { printError(reference.getPhrasesAsSpanList(), prediction.getPhrasesAsSpanList(), reference, prediction, reference.getSentence()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000167 15217274217 032536 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerConverter0100644 0000000 0000000 00000002437 15217274217 034201 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; /** * Tool to convert multiple data formats into native OpenNLP chunker training * format. * * @see AbstractConverterTool * @see ChunkSample */ public class ChunkerConverterTool extends AbstractConverterTool { public ChunkerConverterTool() { super(ChunkSample.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000174 15217274217 032534 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerCrossVali0100644 0000000 0000000 00000006072 15217274217 034136 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import java.io.IOException; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.chunker.ChunkerCrossValidator; import opennlp.tools.chunker.ChunkerEvaluationMonitor; import opennlp.tools.chunker.ChunkerFactory; import opennlp.tools.cmdline.AbstractCrossValidatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.chunker.ChunkerCrossValidatorTool.CVToolParams; import opennlp.tools.cmdline.params.CVParams; import opennlp.tools.util.eval.EvaluationMonitor; import opennlp.tools.util.eval.FMeasure; import opennlp.tools.util.model.ModelUtil; public final class ChunkerCrossValidatorTool extends AbstractCrossValidatorTool { interface CVToolParams extends TrainingParams, CVParams { } private static final Logger logger = LoggerFactory.getLogger(ChunkerCrossValidatorTool.class); public ChunkerCrossValidatorTool() { super(ChunkSample.class, CVToolParams.class); } @Override public String getShortDescription() { return "K-fold cross validator for the chunker"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new ChunkEvaluationErrorListener()); } ChunkerCrossValidator validator; try { ChunkerFactory chunkerFactory = ChunkerFactory .create(params.getFactory()); validator = new ChunkerCrossValidator(params.getLang(), mlParams, chunkerFactory, listeners.toArray(new ChunkerEvaluationMonitor[0])); validator.evaluate(sampleStream, params.getFolds()); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } FMeasure result = validator.getFMeasure(); logger.info(result.toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000202 15217274217 032524 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerDetailedFMeasureListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerDetailedF0100644 0000000 0000000 00000002374 15217274217 034053 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.chunker.ChunkerEvaluationMonitor; import opennlp.tools.cmdline.DetailedFMeasureListener; import opennlp.tools.util.Span; public class ChunkerDetailedFMeasureListener extends DetailedFMeasureListener implements ChunkerEvaluationMonitor { @Override protected Span[] asSpanArray(ChunkSample sample) { return sample.getPhrasesAsSpanList(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000167 15217274217 032536 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerEvaluator0100644 0000000 0000000 00000006755 15217274217 034203 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import java.io.IOException; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.chunker.ChunkerEvaluationMonitor; import opennlp.tools.chunker.ChunkerEvaluator; import opennlp.tools.chunker.ChunkerME; import opennlp.tools.chunker.ChunkerModel; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.chunker.ChunkerEvaluatorTool.EvalToolParams; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default {@link ChunkSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class ChunkerEvaluatorTool extends AbstractEvaluatorTool { interface EvalToolParams extends EvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(ChunkerEvaluatorTool.class); public ChunkerEvaluatorTool() { super(ChunkSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the Chunker model with the reference data"; } @Override public void run(String format, String[] args) { super.run(format, args); ChunkerModel model = new ChunkerModelLoader().load(params.getModel()); List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new ChunkEvaluationErrorListener()); } ChunkerEvaluator evaluator = new ChunkerEvaluator(new ChunkerME(model), listeners.toArray(new ChunkerEvaluationMonitor[0])); final PerformanceMonitor monitor = new PerformanceMonitor("sent"); try (ObjectStream measuredSampleStream = new ObjectStream<>() { public ChunkSample read() throws IOException { monitor.incrementCounter(); return sampleStream.read(); } public void reset() throws IOException { sampleStream.reset(); } public void close() throws IOException { sampleStream.close(); } }) { monitor.startAndPrintThroughput(); evaluator.evaluate(measuredSampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } // sorry that this can fail monitor.stopAndPrintFinalResult(); logger.info(evaluator.getFMeasure().toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000160 15217274217 032527 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerMETool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerMETool.ja0100644 0000000 0000000 00000005724 15217274217 033764 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.chunker.ChunkerME; import opennlp.tools.chunker.ChunkerModel; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.postag.POSSample; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; public class ChunkerMETool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(ChunkerMETool.class); @Override public String getShortDescription() { return "Learnable chunker"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < sentences"; } @Override public void run(String[] args) { if (args.length != 1) { logger.info(getHelp()); } else { ChunkerModel model = new ChunkerModelLoader().load(new File(args[0])); ChunkerME chunker = new ChunkerME(model); PerformanceMonitor perfMon = new PerformanceMonitor("sent"); try (ObjectStream lineStream = new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { perfMon.start(); String line; while ((line = lineStream.read()) != null) { POSSample posSample; try { posSample = POSSample.parse(line); } catch (InvalidFormatException e) { logger.warn("Invalid format: {}", line, e); continue; } String[] chunks = chunker.chunk(posSample.getSentence(), posSample.getTags()); logger.info(new ChunkSample(posSample.getSentence(), posSample.getTags(), chunks).nicePrint()); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000165 15217274217 032534 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerModelLoad0100644 0000000 0000000 00000002625 15217274217 034071 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import java.io.IOException; import java.io.InputStream; import opennlp.tools.chunker.ChunkerModel; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; /** * Loads a {@link ChunkerModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public class ChunkerModelLoader extends ModelLoader { public ChunkerModelLoader() { super("Chunker"); } @Override protected ChunkerModel loadModel(InputStream modelIn) throws IOException { return new ChunkerModel(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000165 15217274217 032534 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/ChunkerTrainerTo0100644 0000000 0000000 00000005166 15217274217 034143 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import java.io.File; import java.io.IOException; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.chunker.ChunkerFactory; import opennlp.tools.chunker.ChunkerME; import opennlp.tools.chunker.ChunkerModel; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.chunker.ChunkerTrainerTool.TrainerToolParams; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.util.model.ModelUtil; public class ChunkerTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams { } public ChunkerTrainerTool() { super(ChunkSample.class, TrainerToolParams.class); } @Override public String getName() { return "ChunkerTrainerME"; } @Override public String getShortDescription() { return "Trainer for the learnable chunker"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("sentence detector model", modelOutFile); ChunkerModel model; try { ChunkerFactory chunkerFactory = ChunkerFactory .create(params.getFactory()); model = ChunkerME.train(params.getLang(), sampleStream, mlParams, chunkerFactory); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("chunker", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_chunker_0100644 0000000 0000000 00000000161 15217274217 032530 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/chunker/TrainingParams.j0100644 0000000 0000000 00000002636 15217274217 034062 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.chunker; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParams for Chunker tools. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "factoryName", description = "A sub-class of ChunkerFactory where to get implementation and resources.") @OptionalParameter String getFactory(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_dictiona0100644 0000000 0000000 00000000175 15217274217 032531 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/dictionary/DictionaryBuilderParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/dictionary/DictionaryBui0100644 0000000 0000000 00000002630 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.dictionary; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.EncodingParameter; import opennlp.tools.commons.Internal; /** * Params for Dictionary tools. *

* Note: Do not use this class, internal use only! */ @Internal interface DictionaryBuilderParams extends EncodingParameter { @ParameterDescription(valueName = "in", description = "Plain file with one entry per line") File getInputFile(); @ParameterDescription(valueName = "out", description = "The dictionary file.") File getOutputFile(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_dictiona0100644 0000000 0000000 00000000173 15217274217 032527 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/dictionary/DictionaryBuilderTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/dictionary/DictionaryBui0100644 0000000 0000000 00000004572 15217274217 034167 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.dictionary; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.nio.charset.Charset; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.dictionary.Dictionary; public class DictionaryBuilderTool extends BasicCmdLineTool { interface Params extends DictionaryBuilderParams { } @Override public String getShortDescription() { return "Builds a new dictionary"; } @Override public String getHelp() { return getBasicHelp(Params.class); } @Override public void run(String[] args) { Params params = validateAndParseParams(args, Params.class); File dictInFile = params.getInputFile(); File dictOutFile = params.getOutputFile(); Charset encoding = params.getEncoding(); CmdLineUtil.checkInputFile("dictionary input file", dictInFile); CmdLineUtil.checkOutputFile("dictionary output file", dictOutFile); try (Reader in = new BufferedReader(new InputStreamReader(new FileInputStream(dictInFile), encoding)); OutputStream out = new FileOutputStream(dictOutFile)) { Dictionary dict = Dictionary.parseOneEntryPerLine(in); dict.serialize(out); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_D0100644 0000000 0000000 00000000165 15217274217 032436 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatConverterTo0100644 0000000 0000000 00000002446 15217274217 034100 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.doccat.DocumentSample; /** * Tool to convert multiple data formats into native OpenNLP doccat training * format. * * @see AbstractConverterTool * @see DocumentSample */ public class DoccatConverterTool extends AbstractConverterTool { public DoccatConverterTool() { super(DocumentSample.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_D0100644 0000000 0000000 00000000172 15217274217 032434 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatCrossValida0100644 0000000 0000000 00000011053 15217274217 034032 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractCrossValidatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.doccat.DoccatCrossValidatorTool.CVToolParams; import opennlp.tools.cmdline.params.CVParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.doccat.DoccatCrossValidator; import opennlp.tools.doccat.DoccatEvaluationMonitor; import opennlp.tools.doccat.DoccatFactory; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.doccat.FeatureGenerator; import opennlp.tools.util.eval.EvaluationMonitor; import opennlp.tools.util.model.ModelUtil; public final class DoccatCrossValidatorTool extends AbstractCrossValidatorTool { interface CVToolParams extends CVParams, TrainingParams, FineGrainedEvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(DoccatCrossValidatorTool.class); public DoccatCrossValidatorTool() { super(DocumentSample.class, CVToolParams.class); } @Override public String getShortDescription() { return "K-fold cross validator for the learnable Document Categorizer"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new DoccatEvaluationErrorListener()); } DoccatFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new DoccatFineGrainedReportListener(reportOutputStream); listeners.add(reportListener); } catch (FileNotFoundException e) { throw createTerminationIOException(e); } } FeatureGenerator[] featureGenerators = DoccatTrainerTool .createFeatureGenerators(params.getFeatureGenerators()); DoccatEvaluationMonitor[] listenersArr = listeners .toArray(new DoccatEvaluationMonitor[0]); DoccatCrossValidator validator; try { DoccatFactory factory = DoccatFactory.create(params.getFactory(), featureGenerators); validator = new DoccatCrossValidator(params.getLang(), mlParams, factory, listenersArr); validator.evaluate(sampleStream, params.getFolds()); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); if (reportListener != null) { logger.info("Writing fine-grained report to {}", params.getReportOutputFile().getAbsolutePath()); reportListener.writeReport(); try { reportOutputStream.flush(); reportOutputStream.close(); } catch (IOException e) { // nothing to do } } logger.info("Accuracy: {}, Number of documents: {}", validator.getDocumentAccuracy(), validator.getDocumentAccuracy()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_D0100644 0000000 0000000 00000000177 15217274217 032441 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatEvaluationE0100644 0000000 0000000 00000003722 15217274217 034040 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.doccat.DoccatEvaluationMonitor; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.log.LogPrintStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints to an * output stream. */ public class DoccatEvaluationErrorListener extends EvaluationErrorPrinter implements DoccatEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(DoccatEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public DoccatEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream} */ public DoccatEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(DocumentSample reference, DocumentSample prediction) { printError(reference, prediction); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_D0100644 0000000 0000000 00000000165 15217274217 032436 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatEvaluatorTo0100644 0000000 0000000 00000011515 15217274217 034070 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.doccat.DoccatEvaluatorTool.EvalToolParams; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.doccat.DoccatEvaluationMonitor; import opennlp.tools.doccat.DoccatModel; import opennlp.tools.doccat.DocumentCategorizerEvaluator; import opennlp.tools.doccat.DocumentCategorizerME; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default {@link DocumentSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class DoccatEvaluatorTool extends AbstractEvaluatorTool { interface EvalToolParams extends EvaluatorParams, FineGrainedEvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(DoccatEvaluatorTool.class); public DoccatEvaluatorTool() { super(DocumentSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the Doccat model with the reference data"; } @Override public void run(String format, String[] args) { super.run(format, args); DoccatModel model = new DoccatModelLoader().load(params.getModel()); List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new DoccatEvaluationErrorListener()); } DoccatFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new DoccatFineGrainedReportListener(reportOutputStream); listeners.add(reportListener); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "IO error while creating Doccat fine-grained report file: " + e.getMessage()); } } DocumentCategorizerEvaluator evaluator = new DocumentCategorizerEvaluator( new DocumentCategorizerME(model), listeners.toArray(new DoccatEvaluationMonitor[0])); final PerformanceMonitor monitor = new PerformanceMonitor("doc"); try (ObjectStream measuredSampleStream = new ObjectStream<>() { @Override public DocumentSample read() throws IOException { monitor.incrementCounter(); return sampleStream.read(); } @Override public void reset() throws IOException { sampleStream.reset(); } @Override public void close() throws IOException { sampleStream.close(); } }) { monitor.startAndPrintThroughput(); evaluator.evaluate(measuredSampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } // sorry that this can fail monitor.stopAndPrintFinalResult(); logger.info(evaluator.toString()); if (reportListener != null) { logger.info("Writing fine-grained report to {}", params.getReportOutputFile().getAbsolutePath()); reportListener.writeReport(); try { reportOutputStream.flush(); reportOutputStream.close(); } catch (IOException e) { // nothing to do } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_D0100644 0000000 0000000 00000000201 15217274217 032425 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatFineGrainedReportListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatFineGrained0100644 0000000 0000000 00000004712 15217274217 033777 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.FineGrainedReportListener; import opennlp.tools.doccat.DoccatEvaluationMonitor; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.log.LogPrintStream; /** * Generates a detailed report for the POS Tagger. *

* It is possible to use it from an API and access the statistics using the * provided getters */ public class DoccatFineGrainedReportListener extends FineGrainedReportListener implements DoccatEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(DoccatFineGrainedReportListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public DoccatFineGrainedReportListener() { this(new LogPrintStream(logger)); } /** * Creates a listener that prints to a given {@link OutputStream} */ public DoccatFineGrainedReportListener(OutputStream outputStream) { super(outputStream); } // methods inherited from EvaluationMonitor @Override public void misclassified(DocumentSample reference, DocumentSample prediction) { statsAdd(reference, prediction); } @Override public void correctlyClassified(DocumentSample reference, DocumentSample prediction) { statsAdd(reference, prediction); } private void statsAdd(DocumentSample reference, DocumentSample prediction) { getStats().add(reference.getText(), reference.getCategory(), prediction.getCategory()); } @Override public void writeReport() { printGeneralStatistics(); printTagsErrorRank(); printGeneralConfusionTable(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_D0100644 0000000 0000000 00000000163 15217274217 032434 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatModelLoader0100644 0000000 0000000 00000002631 15217274217 034011 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.doccat.DoccatModel; /** * Loads a {@link DoccatModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public class DoccatModelLoader extends ModelLoader { public DoccatModelLoader() { super("Document Categorizer"); } @Override protected DoccatModel loadModel(InputStream modelIn) throws IOException { return new DoccatModel(modelIn); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatTool.java0100644 0000000 0000000 00000006072 15217274217 033462 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.doccat.DoccatModel; import opennlp.tools.doccat.DocumentCategorizerME; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.ParagraphStream; import opennlp.tools.util.PlainTextByLineStream; public class DoccatTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(DoccatTool.class); @Override public String getShortDescription() { return "Learned document categorizer"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < documents"; } @Override public void run(String[] args) { if (0 == args.length) { logger.info(getHelp()); } else { DoccatModel model = new DoccatModelLoader().load(new File(args[0])); DocumentCategorizerME documentCategorizerME = new DocumentCategorizerME(model); /* * moved initialization to the try block to catch new IOException */ ObjectStream documentStream; PerformanceMonitor perfMon = new PerformanceMonitor("doc"); perfMon.start(); try { documentStream = new ParagraphStream(new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())); String document; while ((document = documentStream.read()) != null) { String[] tokens = WhitespaceTokenizer.INSTANCE.tokenize(document); double[] prob = documentCategorizerME.categorize(tokens); String category = documentCategorizerME.getBestCategory(prob); DocumentSample sample = new DocumentSample(category, tokens); logger.info(sample.toString()); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_D0100644 0000000 0000000 00000000163 15217274217 032434 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/DoccatTrainerTool0100644 0000000 0000000 00000006602 15217274217 034066 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.doccat.DoccatTrainerTool.TrainerToolParams; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.doccat.BagOfWordsFeatureGenerator; import opennlp.tools.doccat.DoccatFactory; import opennlp.tools.doccat.DoccatModel; import opennlp.tools.doccat.DocumentCategorizerME; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.doccat.FeatureGenerator; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.model.ModelUtil; public class DoccatTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams { } public DoccatTrainerTool() { super(DocumentSample.class, TrainerToolParams.class); } @Override public String getShortDescription() { return "Trainer for the learnable document categorizer"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("document categorizer model", modelOutFile); FeatureGenerator[] featureGenerators = createFeatureGenerators(params .getFeatureGenerators()); DoccatModel model; try { DoccatFactory factory = DoccatFactory.create(params.getFactory(), featureGenerators); model = DocumentCategorizerME.train(params.getLang(), sampleStream, mlParams, factory); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("document categorizer", modelOutFile, model); } static FeatureGenerator[] createFeatureGenerators(String featureGeneratorsNames) { if (featureGeneratorsNames == null) { return new FeatureGenerator[]{new BagOfWordsFeatureGenerator()}; } String[] classes = featureGeneratorsNames.split(","); FeatureGenerator[] featureGenerators = new FeatureGenerator[classes.length]; for (int i = 0; i < featureGenerators.length; i++) { featureGenerators[i] = ExtensionLoader.instantiateExtension( FeatureGenerator.class, classes[i]); } return featureGenerators; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_doccat_T0100644 0000000 0000000 00000000160 15217274217 032451 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/doccat/TrainingParams.ja0100644 0000000 0000000 00000003136 15217274217 034015 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.doccat; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParams for DocCat. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "fg", description = "Comma separated feature generator classes. Bag of words is used if not specified.") @OptionalParameter String getFeatureGenerators(); @ParameterDescription(valueName = "factoryName", description = "A sub-class of DoccatFactory where to get implementation and resources.") @OptionalParameter String getFactory(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_entityli0100644 0000000 0000000 00000000170 15217274217 032573 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/entitylinker/EntityLinkerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/entitylinker/EntityLinke0100644 0000000 0000000 00000012120 15217274217 034221 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.entitylinker; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.entitylinker.EntityLinker; import opennlp.tools.entitylinker.EntityLinkerFactory; import opennlp.tools.entitylinker.EntityLinkerProperties; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; public class EntityLinkerTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(EntityLinkerTool.class); @Override public String getShortDescription() { return "Links an entity to an external data set"; } @Override public void run(String[] args) { if (0 == args.length) { logger.info(getHelp()); } else { // TODO: Ask Mark if we can remove the type, the user knows upfront if s/he tries // to link place names or company mentions ... String entityType = "location"; // Load the properties, they should contain everything that is necessary to instantiate // the component // TODO: Entity Linker Properties constructor should not duplicate code EntityLinkerProperties properties; try { properties = new EntityLinkerProperties(new File(args[0])); } catch (IOException e) { throw new TerminateToolException(-1, "Failed to load the properties file!"); } // TODO: It should not just throw Exception. EntityLinker entityLinker; try { entityLinker = EntityLinkerFactory.getLinker(entityType, properties); } catch (Exception e) { throw new TerminateToolException(-1, "Failed to instantiate the Entity Linker: " + e.getMessage()); } PerformanceMonitor perfMon = new PerformanceMonitor("sent"); perfMon.start(); try (ObjectStream untokenizedLineStream = new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { List document = new ArrayList<>(); String line; while ((line = untokenizedLineStream.read()) != null) { if (line.trim().isEmpty()) { // Run entity linker ... and output result ... StringBuilder text = new StringBuilder(); Span[] sentences = new Span[document.size()]; Span[][] tokensBySentence = new Span[document.size()][]; Span[][] namesBySentence = new Span[document.size()][]; for (int i = 0; i < document.size(); i++) { NameSample sample = document.get(i); namesBySentence[i] = sample.getNames(); int sentenceBegin = text.length(); Span[] tokens = new Span[sample.getSentence().length]; // for all tokens for (int ti = 0; ti < sample.getSentence().length; ti++) { int tokenBegin = text.length(); text.append(sample.getSentence()[ti]); text.append(" "); tokens[ti] = new Span(tokenBegin, text.length()); } tokensBySentence[i] = tokens; sentences[i] = new Span(sentenceBegin, text.length()); text.append("\n"); } List linkedSpans = entityLinker.find(text.toString(), sentences, tokensBySentence, namesBySentence); for (Span linkedSpan : linkedSpans) { logger.info(linkedSpan.toString()); } perfMon.incrementCounter(document.size()); document.clear(); } else { document.add(NameSample.parse(line, false)); } } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < sentences"; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000203 15217274217 032512 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000002516 15217274217 034053 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.langdetect.LanguageSample; /** * Tool to convert multiple data formats into native OpenNLP language detection * training format. * * @see AbstractConverterTool * @see LanguageSample */ public class LanguageDetectorConverterTool extends AbstractConverterTool { public LanguageDetectorConverterTool() { super(LanguageSample.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000210 15217274217 032510 xustar000000000 0000000 136 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000010734 15217274217 034054 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractCrossValidatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.CVParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.langdetect.LanguageDetectorCrossValidator; import opennlp.tools.langdetect.LanguageDetectorEvaluationMonitor; import opennlp.tools.langdetect.LanguageDetectorFactory; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.util.eval.EvaluationMonitor; import opennlp.tools.util.model.ModelUtil; public final class LanguageDetectorCrossValidatorTool extends AbstractCrossValidatorTool { interface CVToolParams extends CVParams, TrainingParams, FineGrainedEvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(LanguageDetectorCrossValidatorTool.class); public LanguageDetectorCrossValidatorTool() { super(LanguageSample.class, CVToolParams.class); } @Override public String getShortDescription() { return "K-fold cross validator for the learnable Language Detector"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new LanguageDetectorEvaluationErrorListener()); } LanguageDetectorFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new LanguageDetectorFineGrainedReportListener(reportOutputStream); listeners.add(reportListener); } catch (FileNotFoundException e) { throw createTerminationIOException(e); } } LanguageDetectorEvaluationMonitor[] listenersArr = listeners .toArray(new LanguageDetectorEvaluationMonitor[0]); LanguageDetectorCrossValidator validator; try { LanguageDetectorFactory factory = LanguageDetectorFactory.create(params.getFactory()); validator = new LanguageDetectorCrossValidator(mlParams, factory, listenersArr); validator.evaluate(sampleStream, params.getFolds()); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); if (reportListener != null) { logger.info("Writing fine-grained report to {}", params.getReportOutputFile().getAbsolutePath()); reportListener.writeReport(); try { reportOutputStream.flush(); reportOutputStream.close(); } catch (IOException e) { // nothing to do } } logger.info("Accuracy: {} Number of documents: {}", validator.getDocumentAccuracy(), validator.getDocumentCount()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000215 15217274217 032515 xustar000000000 0000000 141 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000004544 15217274217 034056 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.langdetect.LanguageDetectorEvaluationMonitor; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.log.LogPrintStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints to an * output stream. */ public class LanguageDetectorEvaluationErrorListener extends EvaluationErrorPrinter implements LanguageDetectorEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(LanguageDetectorEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public LanguageDetectorEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream} */ public LanguageDetectorEvaluationErrorListener(OutputStream outputStream) { super(outputStream); printStream.println("Expected\tPredicted\tContext"); } @Override public void misclassified(LanguageSample reference, LanguageSample prediction) { printError(reference, prediction); } @Override protected void printError(LanguageSample referenceSample, LanguageSample predictedSample) { printStream.println(String.join("\t", referenceSample.language().getLang(), predictedSample.language().getLang(), referenceSample.context())); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000203 15217274217 032512 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000011660 15217274217 034053 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.langdetect.LanguageDetectorEvaluationMonitor; import opennlp.tools.langdetect.LanguageDetectorEvaluator; import opennlp.tools.langdetect.LanguageDetectorME; import opennlp.tools.langdetect.LanguageDetectorModel; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default {@link LanguageSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class LanguageDetectorEvaluatorTool extends AbstractEvaluatorTool { interface EvalToolParams extends EvaluatorParams, FineGrainedEvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(LanguageDetectorEvaluatorTool.class); public LanguageDetectorEvaluatorTool() { super(LanguageSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the Language Detector model with the reference data"; } @Override public void run(String format, String[] args) { super.run(format, args); LanguageDetectorModel model = new LanguageDetectorModelLoader().load(params.getModel()); List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new LanguageDetectorEvaluationErrorListener()); } LanguageDetectorFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new LanguageDetectorFineGrainedReportListener(reportOutputStream); listeners.add(reportListener); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "IO error while creating LanguageDetector fine-grained report file: " + e.getMessage()); } } LanguageDetectorEvaluator evaluator = new LanguageDetectorEvaluator( new LanguageDetectorME(model), listeners.toArray(new LanguageDetectorEvaluationMonitor[0])); final PerformanceMonitor monitor = new PerformanceMonitor("doc"); try (ObjectStream measuredSampleStream = new ObjectStream<>() { @Override public LanguageSample read() throws IOException { monitor.incrementCounter(); return sampleStream.read(); } @Override public void reset() throws IOException { sampleStream.reset(); } @Override public void close() throws IOException { sampleStream.close(); } }) { monitor.startAndPrintThroughput(); evaluator.evaluate(measuredSampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } // sorry that this can fail monitor.stopAndPrintFinalResult(); logger.info(evaluator.toString()); if (reportListener != null) { logger.info("Writing fine-grained report to {}", params.getReportOutputFile().getAbsolutePath()); reportListener.writeReport(); try { reportOutputStream.flush(); reportOutputStream.close(); } catch (IOException e) { // nothing to do } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000217 15217274217 032517 xustar000000000 0000000 143 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorFineGrainedReportListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000004471 15217274217 034055 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import java.io.OutputStream; import opennlp.tools.cmdline.FineGrainedReportListener; import opennlp.tools.langdetect.LanguageDetectorEvaluationMonitor; import opennlp.tools.langdetect.LanguageSample; /** * Generates a detailed report for the POS Tagger. *

* It is possible to use it from an API and access the statistics using the * provided getters. */ public class LanguageDetectorFineGrainedReportListener extends FineGrainedReportListener implements LanguageDetectorEvaluationMonitor { /** * Creates a listener that will print to {@link System#err} */ public LanguageDetectorFineGrainedReportListener() { this(System.err); } /** * Creates a listener that prints to a given {@link OutputStream} */ public LanguageDetectorFineGrainedReportListener(OutputStream outputStream) { super(outputStream); } // methods inherited from EvaluationMonitor @Override public void misclassified(LanguageSample reference, LanguageSample prediction) { statsAdd(reference, prediction); } @Override public void correctlyClassified(LanguageSample reference, LanguageSample prediction) { statsAdd(reference, prediction); } private void statsAdd(LanguageSample reference, LanguageSample prediction) { getStats().add(reference.context(), reference.language().getLang(), prediction.language().getLang()); } @Override public void writeReport() { printGeneralStatistics(); printTagsErrorRank(); printGeneralConfusionTable(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000201 15217274217 032510 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000002744 15217274217 034056 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.langdetect.LanguageDetectorModel; /** * Loads a {@link LanguageDetectorModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public class LanguageDetectorModelLoader extends ModelLoader { public LanguageDetectorModelLoader() { super("Language Detector"); } @Override protected LanguageDetectorModel loadModel(InputStream modelIn) throws IOException { return new LanguageDetectorModel(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000172 15217274217 032517 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000005764 15217274217 034063 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.langdetect.Language; import opennlp.tools.langdetect.LanguageDetector; import opennlp.tools.langdetect.LanguageDetectorME; import opennlp.tools.langdetect.LanguageDetectorModel; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.ParagraphStream; import opennlp.tools.util.PlainTextByLineStream; public class LanguageDetectorTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(LanguageDetectorTool.class); @Override public String getShortDescription() { return "Learned language detector"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < documents"; } @Override public void run(String[] args) { if (0 == args.length) { logger.info(getHelp()); } else { LanguageDetectorModel model = new LanguageDetectorModelLoader().load(new File(args[0])); LanguageDetector langDetectME = new LanguageDetectorME(model); /* * moved initialization to the try block to catch new IOException */ ObjectStream documentStream; PerformanceMonitor perfMon = new PerformanceMonitor("doc"); perfMon.start(); try { documentStream = new ParagraphStream(new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())); String document; while ((document = documentStream.read()) != null) { Language lang = langDetectME.predictLanguage(document); LanguageSample sample = new LanguageSample(lang, document); logger.info(sample.toString()); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000201 15217274217 032510 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetectorTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/LanguageDetec0100644 0000000 0000000 00000005517 15217274217 034057 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.langdetect.LanguageDetectorFactory; import opennlp.tools.langdetect.LanguageDetectorME; import opennlp.tools.langdetect.LanguageDetectorModel; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.util.model.ModelUtil; public class LanguageDetectorTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams { @ArgumentParser.ParameterDescription(valueName = "modelFile", description = "output model file.") File getModel(); @ArgumentParser.ParameterDescription(valueName = "paramsFile", description = "training parameters file.") @ArgumentParser.OptionalParameter() String getParams(); } public LanguageDetectorTrainerTool() { super(LanguageSample.class, TrainerToolParams.class); } @Override public String getShortDescription() { return "Trainer for the learnable language detector"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("language detector model", modelOutFile); LanguageDetectorModel model; try { LanguageDetectorFactory factory = LanguageDetectorFactory.create(params.getFactory()); model = LanguageDetectorME.train(sampleStream, mlParams, factory); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("language detector", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_langdete0100644 0000000 0000000 00000000164 15217274217 032520 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/langdetect/TrainingParam0100644 0000000 0000000 00000002763 15217274217 034123 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.langdetect; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.commons.Internal; /** * TrainingParams for Language Detector. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams { @ParameterDescription(valueName = "paramsFile", description = "training parameters file.") @OptionalParameter() String getParams(); @ParameterDescription(valueName = "factoryName", description = "A sub-class of LanguageDetectorFactory" + " where to get implementation and resources.") @OptionalParameter String getFactory(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_language0100644 0000000 0000000 00000000177 15217274217 032524 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/languagemodel/NGramLanguageModelTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/languagemodel/NGramLangu0100644 0000000 0000000 00000006545 15217274217 034056 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.languagemodel; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.languagemodel.NGramLanguageModel; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; /** * Command line tool for {@link opennlp.tools.languagemodel.NGramLanguageModel}. */ public class NGramLanguageModelTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(NGramLanguageModelTool.class); @Override public String getShortDescription() { return "Gives the probability and most probable next token(s) of a sequence of tokens in a " + "language model"; } @Override public void run(String[] args) { File lmFile = new File(args[0]); try (InputStream stream = new BufferedInputStream(new FileInputStream(lmFile))) { NGramLanguageModel nGramLanguageModel = new NGramLanguageModel(stream); PerformanceMonitor perfMon = null; try (ObjectStream lineStream = new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { perfMon = new PerformanceMonitor("nglm"); perfMon.start(); String line; while ((line = lineStream.read()) != null) { double probability; String[] predicted; // TODO : use a Tokenizer here String[] tokens = line.split(" "); try { probability = nGramLanguageModel.calculateProbability(tokens); predicted = nGramLanguageModel.predictNextTokens(tokens); } catch (Exception e) { logger.error("Error for line: {}", line, e); continue; } logger.info("{} -> prob: {}, next: {}", Arrays.toString(tokens), probability, Arrays.toString(predicted)); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); } // do nothing } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model"; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000202 15217274217 032550 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmaEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmaEvaluati0100644 0000000 0000000 00000004044 15217274217 034146 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.lemmatizer; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.lemmatizer.LemmatizerEvaluationMonitor; import opennlp.tools.log.LogPrintStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints to an * output stream. */ public class LemmaEvaluationErrorListener extends EvaluationErrorPrinter implements LemmatizerEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(LemmaEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public LemmaEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream} */ public LemmaEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(LemmaSample reference, LemmaSample prediction) { printError(reference.getLemmas(), prediction.getLemmas(), reference, prediction, reference.getTokens()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000175 15217274217 032561 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerEva0100644 0000000 0000000 00000010212 15217274217 034157 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.lemmatizer; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.lemmatizer.LemmatizerEvaluationMonitor; import opennlp.tools.lemmatizer.LemmatizerEvaluator; import opennlp.tools.lemmatizer.LemmatizerModel; /** * A default {@link LemmaSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class LemmatizerEvaluatorTool extends AbstractEvaluatorTool { private static final Logger logger = LoggerFactory.getLogger(LemmatizerEvaluatorTool.class); public LemmatizerEvaluatorTool() { super(LemmaSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the Lemmatizer model with the reference data"; } @Override public void run(String format, String[] args) { super.run(format, args); LemmatizerModel model = new LemmatizerModelLoader().load(params.getModel()); LemmatizerEvaluationMonitor missclassifiedListener = null; if (params.getMisclassified()) { missclassifiedListener = new LemmaEvaluationErrorListener(); } LemmatizerFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new LemmatizerFineGrainedReportListener( reportOutputStream); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "IO error while creating Lemmatizer fine-grained report file: " + e.getMessage()); } } LemmatizerEvaluator evaluator = new LemmatizerEvaluator( new opennlp.tools.lemmatizer.LemmatizerME(model), missclassifiedListener, reportListener); logger.info("Evaluating ... "); try { evaluator.evaluate(sampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); if (reportListener != null) { logger.info("Writing fine-grained report to {}", params.getReportOutputFile().getAbsolutePath()); reportListener.writeReport(); try { reportOutputStream.flush(); reportOutputStream.close(); } catch (IOException e) { // nothing to do } } logger.info("Accuracy: {}", evaluator.getWordAccuracy()); } interface EvalToolParams extends EvaluatorParams, FineGrainedEvaluatorParams { } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000211 15217274217 032550 xustar000000000 0000000 137 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerFineGrainedReportListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerFin0100644 0000000 0000000 00000005162 15217274217 034170 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.lemmatizer; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.FineGrainedReportListener; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.lemmatizer.LemmatizerEvaluationMonitor; import opennlp.tools.log.LogPrintStream; /** * Generates a detailed report for the Lemmatizer. *

* It is possible to use it from an API and access the statistics using the * provided getters. */ public class LemmatizerFineGrainedReportListener extends FineGrainedReportListener implements LemmatizerEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(LemmatizerFineGrainedReportListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public LemmatizerFineGrainedReportListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that prints to a given {@link OutputStream} */ public LemmatizerFineGrainedReportListener(OutputStream outputStream) { super(outputStream); } // methods inherited from EvaluationMonitor @Override public void misclassified(LemmaSample reference, LemmaSample prediction) { statsAdd(reference, prediction); } @Override public void correctlyClassified(LemmaSample reference, LemmaSample prediction) { statsAdd(reference, prediction); } private void statsAdd(LemmaSample reference, LemmaSample prediction) { getStats().add(reference.getTokens(), reference.getTags(), prediction.getTags()); } @Override public void writeReport() { printGeneralStatistics(); // token stats printTokenErrorRank(); printTokenOccurrencesRank(); // tag stats printTagsErrorRank(); // confusion tables printGeneralConfusionTable(); printDetailedConfusionMatrix(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000166 15217274217 032561 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerMETool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerMET0100644 0000000 0000000 00000006033 15217274217 034077 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.lemmatizer; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.lemmatizer.LemmatizerME; import opennlp.tools.lemmatizer.LemmatizerModel; import opennlp.tools.postag.POSSample; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; public class LemmatizerMETool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(LemmatizerMETool.class); public String getShortDescription() { return "Learnable lemmatizer"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < sentences"; } @Override public void run(String[] args) { if (args.length != 1) { logger.info(getHelp()); } else { LemmatizerModel model = new LemmatizerModelLoader().load(new File(args[0])); LemmatizerME lemmatizer = new LemmatizerME(model); PerformanceMonitor perfMon = null; try (ObjectStream lineStream = new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { perfMon = new PerformanceMonitor("sent"); perfMon.start(); String line; while ((line = lineStream.read()) != null) { POSSample posSample; try { posSample = POSSample.parse(line); } catch (InvalidFormatException e) { logger.warn("Invalid format: {}", line); continue; } String[] lemmas = lemmatizer.lemmatize(posSample.getSentence(), posSample.getTags()); logger.info(new LemmaSample(posSample.getSentence(), posSample.getTags(), lemmas).toString()); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000173 15217274217 032557 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerMod0100644 0000000 0000000 00000002664 15217274217 034177 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.lemmatizer; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.lemmatizer.LemmatizerModel; /** * Loads a {@link LemmatizerModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public class LemmatizerModelLoader extends ModelLoader { public LemmatizerModelLoader() { super("Lemmatizer"); } @Override protected LemmatizerModel loadModel(InputStream modelIn) throws IOException { return new LemmatizerModel(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000173 15217274217 032557 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/LemmatizerTra0100644 0000000 0000000 00000005251 15217274217 034201 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.lemmatizer; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.lemmatizer.LemmatizerTrainerTool.TrainerToolParams; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.lemmatizer.LemmatizerFactory; import opennlp.tools.lemmatizer.LemmatizerME; import opennlp.tools.lemmatizer.LemmatizerModel; import opennlp.tools.util.model.ModelUtil; public class LemmatizerTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams { } public LemmatizerTrainerTool() { super(LemmaSample.class, TrainerToolParams.class); } @Override public String getName() { return "LemmatizerTrainerME"; } @Override public String getShortDescription() { return "Trainer for the learnable lemmatizer"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("lemmatizer model", modelOutFile); LemmatizerModel model; try { LemmatizerFactory lemmatizerFactory = LemmatizerFactory .create(params.getFactory()); model = LemmatizerME.train(params.getLang(), sampleStream, mlParams, lemmatizerFactory); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("lemmatizer", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000164 15217274217 032557 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/TrainingParam0100644 0000000 0000000 00000002644 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.lemmatizer; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParams for the Lemmatizer. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "factoryName", description = "A sub-class of LemmatizerFactory where to get implementation and resources.") @OptionalParameter String getFactory(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_lemmatiz0100644 0000000 0000000 00000000162 15217274217 032555 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/lemmatizer/package-info.0100644 0000000 0000000 00000001636 15217274217 034026 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Classes giving access to the opennlp.tools.lemmatizer functionalities. */ package opennlp.tools.cmdline.lemmatizer; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000177 15217274217 032522 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/CensusDictionaryCreatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/CensusDictionar0100644 0000000 0000000 00000010611 15217274217 034122 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.formats.NameFinderCensus90NameStream; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.StringList; /** * This tool helps create a loadable dictionary for the {@code NameFinder}, * from data collected from US Census data. *

* Data for the US Census and names can be found here for the 1990 Census: *
*
www.census.gov */ public class CensusDictionaryCreatorTool extends BasicCmdLineTool { /** * Create a list of expected parameters. */ interface Parameters { @ParameterDescription(valueName = "code") @OptionalParameter(defaultValue = "eng") String getLang(); @ParameterDescription(valueName = "charsetName") @OptionalParameter(defaultValue = "UTF-8") String getEncoding(); @ParameterDescription(valueName = "censusDict") String getCensusData(); @ParameterDescription(valueName = "dict") String getDict(); } private static final Logger logger = LoggerFactory.getLogger(CensusDictionaryCreatorTool.class); public String getShortDescription() { return "Converts 1990 US Census names into a dictionary"; } public String getHelp() { return getBasicHelp(Parameters.class); } /** * Creates a dictionary. * * @param sampleStream stream of samples. * @return a {@code Dictionary} class containing the name dictionary * built from the input file. * @throws IOException IOException */ public static Dictionary createDictionary(ObjectStream sampleStream) throws IOException { Dictionary mNameDictionary = new Dictionary(true); StringList entry; entry = sampleStream.read(); while (entry != null) { if (!mNameDictionary.contains(entry)) { mNameDictionary.put(entry); } entry = sampleStream.read(); } return mNameDictionary; } public void run(String[] args) { Parameters params = validateAndParseParams(args, Parameters.class); File testData = new File(params.getCensusData()); File dictOutFile = new File(params.getDict()); CmdLineUtil.checkInputFile("Name data", testData); CmdLineUtil.checkOutputFile("Dictionary file", dictOutFile); InputStreamFactory sampleDataIn = CmdLineUtil.createInputStreamFactory(testData); Dictionary mDictionary; try (ObjectStream sampleStream = new NameFinderCensus90NameStream( sampleDataIn, Charset.forName(params.getEncoding()))) { logger.info("Creating Dictionary..."); mDictionary = createDictionary(sampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } logger.info("Saving Dictionary..."); try (OutputStream out = new FileOutputStream(dictOutFile)) { mDictionary.serialize(out); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while writing dictionary file: " + e.getMessage(), e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000177 15217274217 032522 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/NameEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/NameEvaluationE0100644 0000000 0000000 00000004064 15217274217 034047 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.log.LogPrintStream; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.TokenNameFinderEvaluationMonitor; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints * to an output stream. */ public class NameEvaluationErrorListener extends EvaluationErrorPrinter implements TokenNameFinderEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(NameEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public NameEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream}. */ public NameEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(NameSample reference, NameSample prediction) { printError(reference.getId(), reference.getNames(), prediction.getNames(), reference, prediction, reference.getSentence()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000174 15217274217 032517 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/NameSampleCountersStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/NameSampleCount0100644 0000000 0000000 00000005676 15217274217 034077 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * Counts tokens, sentences and names by type. */ public class NameSampleCountersStream extends FilterObjectStream { private static final Logger logger = LoggerFactory.getLogger(NameSampleCountersStream.class); private int sentenceCount; private int tokenCount; private Map nameCounters = new HashMap<>(); protected NameSampleCountersStream(ObjectStream samples) { super(samples); } @Override public NameSample read() throws IOException { NameSample sample = samples.read(); if (sample != null) { sentenceCount++; tokenCount += sample.getSentence().length; for (Span nameSpan : sample.getNames()) { Integer nameCounter = nameCounters.get(nameSpan.getType()); if (nameCounter == null) { nameCounter = 0; } nameCounters.put(nameSpan.getType(), nameCounter + 1); } } return sample; } @Override public void reset() throws IOException, UnsupportedOperationException { super.reset(); sentenceCount = 0; tokenCount = 0; nameCounters = new HashMap<>(); } public int getSentenceCount() { return sentenceCount; } public int getTokenCount() { return tokenCount; } public Map getNameCounters() { return Collections.unmodifiableMap(nameCounters); } public void printSummary() { logger.info("Training data summary:"); logger.info("#Sentences: {}", getSentenceCount()); logger.info("#Tokens: {}", getTokenCount()); int totalNames = 0; for (Map.Entry counter : getNameCounters().entrySet()) { logger.info("# {} entities: {}", counter.getKey(), counter.getValue()); totalNames += counter.getValue(); } logger.info("# total: {}", totalNames); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000200 15217274217 032505 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000002461 15217274217 034042 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.namefind.NameSample; /** * Tool to convert multiple data formats into native OpenNLP name finder * training format. * * @see AbstractConverterTool * @see NameSample */ public class TokenNameFinderConverterTool extends AbstractConverterTool { public TokenNameFinderConverterTool() { super(NameSample.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000205 15217274217 032512 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000013256 15217274217 034046 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractCrossValidatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.namefind.TokenNameFinderCrossValidatorTool.CVToolParams; import opennlp.tools.cmdline.params.CVParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.namefind.BilouCodec; import opennlp.tools.namefind.BioCodec; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.NameSampleTypeFilter; import opennlp.tools.namefind.TokenNameFinderCrossValidator; import opennlp.tools.namefind.TokenNameFinderEvaluationMonitor; import opennlp.tools.namefind.TokenNameFinderFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.EvaluationMonitor; public final class TokenNameFinderCrossValidatorTool extends AbstractCrossValidatorTool { interface CVToolParams extends TrainingParams, CVParams, FineGrainedEvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(TokenNameFinderCrossValidatorTool.class); public TokenNameFinderCrossValidatorTool() { super(NameSample.class, CVToolParams.class); } @Override public String getShortDescription() { return "K-fold cross validator for the learnable Name Finder"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), true); if (mlParams == null) { mlParams = new TrainingParameters(); } byte[] featureGeneratorBytes = TokenNameFinderTrainerTool.openFeatureGeneratorBytes(params.getFeaturegen()); Map resources; try { resources = TokenNameFinderTrainerTool.loadResources(params.getResources(), params.getFeaturegen()); } catch (IOException e) { throw new TerminateToolException(-1,"IO error while loading resources", e); } if (params.getNameTypes() != null) { String[] nameTypes = params.getNameTypes().split(","); sampleStream = new NameSampleTypeFilter(nameTypes, sampleStream); } List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new NameEvaluationErrorListener()); } String sequenceCodecImplName = params.getSequenceCodec(); if ("BIO".equals(sequenceCodecImplName)) { sequenceCodecImplName = BioCodec.class.getName(); } else if ("BILOU".equals(sequenceCodecImplName)) { sequenceCodecImplName = BilouCodec.class.getName(); } SequenceCodec sequenceCodec; try { sequenceCodec = TokenNameFinderFactory.instantiateSequenceCodec(sequenceCodecImplName); } catch (InvalidFormatException e) { throw new TerminateToolException(-1, e.getMessage(), e); } TokenNameFinderFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new TokenNameFinderFineGrainedReportListener(sequenceCodec, reportOutputStream); listeners.add(reportListener); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "IO error while creating Name Finder fine-grained report file: " + e.getMessage()); } } TokenNameFinderFactory nameFinderFactory; try { nameFinderFactory = TokenNameFinderFactory.create(params.getFactory(), featureGeneratorBytes, resources, sequenceCodec); } catch (InvalidFormatException e) { throw new TerminateToolException(-1, e.getMessage(), e); } TokenNameFinderCrossValidator validator; try { validator = new TokenNameFinderCrossValidator(params.getLang(), params.getType(), mlParams, nameFinderFactory, listeners.toArray(new TokenNameFinderEvaluationMonitor[0])); validator.evaluate(sampleStream, params.getFolds()); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); if (reportFile != null) { reportListener.writeReport(); } logger.info(validator.getFMeasure().toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000213 15217274217 032511 xustar000000000 0000000 139 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderDetailedFMeasureListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000002413 15217274217 034037 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import opennlp.tools.cmdline.DetailedFMeasureListener; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.TokenNameFinderEvaluationMonitor; import opennlp.tools.util.Span; public class TokenNameFinderDetailedFMeasureListener extends DetailedFMeasureListener implements TokenNameFinderEvaluationMonitor { @Override protected Span[] asSpanArray(NameSample sample) { return sample.getNames(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000200 15217274217 032505 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000012244 15217274217 034042 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.namefind.TokenNameFinderEvaluatorTool.EvalToolParams; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.namefind.NameFinderME; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.NameSampleTypeFilter; import opennlp.tools.namefind.TokenNameFinderEvaluationMonitor; import opennlp.tools.namefind.TokenNameFinderEvaluator; import opennlp.tools.namefind.TokenNameFinderModel; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default {@link NameSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class TokenNameFinderEvaluatorTool extends AbstractEvaluatorTool { interface EvalToolParams extends EvaluatorParams, FineGrainedEvaluatorParams { @OptionalParameter @ParameterDescription(valueName = "types", description = "name types to use for evaluation") String getNameTypes(); } private static final Logger logger = LoggerFactory.getLogger(TokenNameFinderEvaluatorTool.class); public TokenNameFinderEvaluatorTool() { super(NameSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the NameFinder model with the reference data"; } @Override public void run(String format, String[] args) { super.run(format, args); TokenNameFinderModel model = new TokenNameFinderModelLoader().load(params.getModel()); List> listeners = new LinkedList<>(); if (params.getMisclassified()) { listeners.add(new NameEvaluationErrorListener()); } TokenNameFinderFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new TokenNameFinderFineGrainedReportListener(model.getSequenceCodec(), reportOutputStream); listeners.add(reportListener); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "IO error while creating Name Finder fine-grained report file: " + e.getMessage()); } } if (params.getNameTypes() != null) { String[] nameTypes = params.getNameTypes().split(","); sampleStream = new NameSampleTypeFilter(nameTypes, sampleStream); } TokenNameFinderEvaluator evaluator = new TokenNameFinderEvaluator( new NameFinderME(model), listeners.toArray(new TokenNameFinderEvaluationMonitor[0])); final PerformanceMonitor monitor = new PerformanceMonitor("sent"); try (ObjectStream measuredSampleStream = new ObjectStream<>() { @Override public NameSample read() throws IOException { monitor.incrementCounter(); return sampleStream.read(); } @Override public void reset() throws IOException { sampleStream.reset(); } @Override public void close() throws IOException { sampleStream.close(); } }) { monitor.startAndPrintThroughput(); evaluator.evaluate(measuredSampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } // sorry that this can fail monitor.stopAndPrintFinalResult(); if (reportFile != null) { reportListener.writeReport(); } logger.info(evaluator.getFMeasure().toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000214 15217274217 032512 xustar000000000 0000000 140 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderFineGrainedReportListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000006603 15217274217 034044 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.OutputStream; import java.util.Comparator; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.FineGrainedReportListener; import opennlp.tools.log.LogPrintStream; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.TokenNameFinderEvaluationMonitor; import opennlp.tools.util.SequenceCodec; /** * Generates a detailed report for the NameFinder. *

* It is possible to use it from an API and access the statistics using the * provided getters. */ public class TokenNameFinderFineGrainedReportListener extends FineGrainedReportListener implements TokenNameFinderEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(TokenNameFinderFineGrainedReportListener.class); private final SequenceCodec sequenceCodec; /** * Creates a listener that will print to the configured {@code logger}. */ public TokenNameFinderFineGrainedReportListener(SequenceCodec seqCodec) { this(seqCodec, new LogPrintStream(logger)); } /** * Creates a listener that prints to a given {@link OutputStream}. */ public TokenNameFinderFineGrainedReportListener(SequenceCodec seqCodec, OutputStream outputStream) { super(outputStream); this.sequenceCodec = seqCodec; } // methods inherited from EvaluationMonitor @Override public void misclassified(NameSample reference, NameSample prediction) { statsAdd(reference, prediction); } @Override public void correctlyClassified(NameSample reference, NameSample prediction) { statsAdd(reference, prediction); } private void statsAdd(NameSample reference, NameSample prediction) { String[] refTags = sequenceCodec.encode(reference.getNames(), reference.getSentence().length); String[] predTags = sequenceCodec.encode(prediction.getNames(), prediction.getSentence().length); // we don't want it to compute token frequency, so we pass an array of empty strings instead // of tokens getStats().add(new String[reference.getSentence().length], refTags, predTags); } @Override public Comparator getMatrixLabelComparator(Map confusionMatrix) { return new GroupedMatrixLabelComparator(confusionMatrix); } @Override public Comparator getLabelComparator(Map map) { return new GroupedLabelComparator(map); } @Override public void writeReport() { printGeneralStatistics(); printTagsErrorRank(); printGeneralConfusionTable(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000176 15217274217 032521 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000002737 15217274217 034050 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.namefind.TokenNameFinderModel; /** * Loads a {@link TokenNameFinderModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public final class TokenNameFinderModelLoader extends ModelLoader { public TokenNameFinderModelLoader() { super("Token Name Finder"); } @Override protected TokenNameFinderModel loadModel(InputStream modelIn) throws IOException { return new TokenNameFinderModel(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000167 15217274217 032521 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000007473 15217274217 034052 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.namefind.NameFinderME; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.TokenNameFinder; import opennlp.tools.namefind.TokenNameFinderModel; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; public final class TokenNameFinderTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(TokenNameFinderTool.class); @Override public String getShortDescription() { return "Learnable name finder"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model1 model2 ... modelN < sentences"; } @Override public void run(String[] args) { if (args.length == 0) { logger.info(getHelp()); } else { NameFinderME[] nameFinders = new NameFinderME[args.length]; for (int i = 0; i < nameFinders.length; i++) { TokenNameFinderModel model = new TokenNameFinderModelLoader().load(new File(args[i])); nameFinders[i] = new NameFinderME(model); } PerformanceMonitor perfMon = new PerformanceMonitor("sent"); perfMon.start(); try (ObjectStream untokenizedLineStream = new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { String line; while ((line = untokenizedLineStream.read()) != null) { String[] whitespaceTokenizerLine = WhitespaceTokenizer.INSTANCE.tokenize(line); // A new line indicates a new document, // adaptive data must be cleared for a new document if (whitespaceTokenizerLine.length == 0) { for (NameFinderME nameFinder : nameFinders) { nameFinder.clearAdaptiveData(); } } List names = new ArrayList<>(); for (TokenNameFinder nameFinder : nameFinders) { Collections.addAll(names, nameFinder.find(whitespaceTokenizerLine)); } // Simple way to drop intersecting spans, otherwise the // NameSample is invalid Span[] reducedNames = NameFinderME.dropOverlappingSpans( names.toArray(new Span[0])); NameSample nameSample = new NameSample(whitespaceTokenizerLine, reducedNames, false); logger.info(nameSample.toString()); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000176 15217274217 032521 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinderTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TokenNameFinder0100644 0000000 0000000 00000015644 15217274217 034051 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.namefind.TokenNameFinderTrainerTool.TrainerToolParams; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.namefind.BilouCodec; import opennlp.tools.namefind.BioCodec; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.NameSampleTypeFilter; import opennlp.tools.namefind.TokenNameFinderFactory; import opennlp.tools.namefind.TokenNameFinderModel; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.featuregen.GeneratorFactory; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.ModelUtil; public final class TokenNameFinderTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams { } public TokenNameFinderTrainerTool() { super(NameSample.class, TrainerToolParams.class); } @Override public String getShortDescription() { return "Trainer for the learnable name finder"; } static byte[] openFeatureGeneratorBytes(String featureGenDescriptorFile) { if (featureGenDescriptorFile != null) { return openFeatureGeneratorBytes(new File(featureGenDescriptorFile)); } return null; } public static byte[] openFeatureGeneratorBytes(File featureGenDescriptorFile) { byte[] featureGeneratorBytes = null; // load descriptor file into memory if (featureGenDescriptorFile != null) { try (InputStream bytesIn = new BufferedInputStream( CmdLineUtil.openInFile(featureGenDescriptorFile))) { featureGeneratorBytes = ModelUtil.read(bytesIn); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } } return featureGeneratorBytes; } /** * Load the resources, such as dictionaries, by reading the feature xml descriptor * and looking into the directory passed as argument. * * @param resourcePath The directory in which the resources are to be found. * @param featureGenDescriptor The feature xml descriptor. * @return A map consisting of the file name of the resource and its corresponding Object. */ public static Map loadResources(File resourcePath, File featureGenDescriptor) throws IOException { Map resources = new HashMap<>(); if (resourcePath != null) { Map> artifactSerializers = new HashMap<>(); if (featureGenDescriptor != null) { try (InputStream xmlDescriptorIn = new BufferedInputStream( CmdLineUtil.openInFile(featureGenDescriptor))) { artifactSerializers.putAll( GeneratorFactory.extractArtifactSerializerMappings(xmlDescriptorIn)); } } for (Map.Entry> serializerMapping : artifactSerializers.entrySet()) { String resourceName = serializerMapping.getKey(); try (InputStream resourceIn = new BufferedInputStream( CmdLineUtil.openInFile(new File(resourcePath, resourceName)))) { resources.put(resourceName, serializerMapping.getValue().create(resourceIn)); } } } return resources; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), true); if (mlParams == null) { mlParams = new TrainingParameters(); } File modelOutFile = params.getModel(); byte[] featureGeneratorBytes = openFeatureGeneratorBytes(params.getFeaturegen()); // TODO: Support Custom resources: // Must be loaded into memory, or written to tmp file until descriptor // is loaded which defines parses when model is loaded Map resources; try { resources = loadResources(params.getResources(), params.getFeaturegen()); } catch (IOException e) { throw new TerminateToolException(-1, e.getMessage(), e); } CmdLineUtil.checkOutputFile("name finder model", modelOutFile); if (params.getNameTypes() != null) { String[] nameTypes = params.getNameTypes().split(","); sampleStream = new NameSampleTypeFilter(nameTypes, sampleStream); } String sequenceCodecImplName = params.getSequenceCodec(); if ("BIO".equals(sequenceCodecImplName)) { sequenceCodecImplName = BioCodec.class.getName(); } else if ("BILOU".equals(sequenceCodecImplName)) { sequenceCodecImplName = BilouCodec.class.getName(); } SequenceCodec sequenceCodec; try { sequenceCodec = TokenNameFinderFactory.instantiateSequenceCodec(sequenceCodecImplName); } catch (InvalidFormatException e) { throw new TerminateToolException(-1, e.getMessage(), e); } TokenNameFinderFactory nameFinderFactory; try { nameFinderFactory = TokenNameFinderFactory.create(params.getFactory(), featureGeneratorBytes, resources, sequenceCodec); } catch (InvalidFormatException e) { throw new TerminateToolException(-1, e.getMessage(), e); } NameSampleCountersStream counters = new NameSampleCountersStream(sampleStream); sampleStream = counters; TokenNameFinderModel model; try { model = opennlp.tools.namefind.NameFinderME.train( params.getLang(), params.getType(), sampleStream, mlParams, nameFinderFactory); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } counters.printSummary(); CmdLineUtil.writeModel("name finder", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_namefind0100644 0000000 0000000 00000000162 15217274217 032514 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/namefind/TrainingParams.0100644 0000000 0000000 00000004234 15217274217 034026 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.namefind; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParameters for Name Finder. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "modelType", description = "The type of the token name finder model") @OptionalParameter String getType(); @ParameterDescription(valueName = "resourcesDir", description = "The resources directory") @OptionalParameter File getResources(); @ParameterDescription(valueName = "featuregenFile", description = "The feature generator descriptor file") @OptionalParameter File getFeaturegen(); @OptionalParameter @ParameterDescription(valueName = "types", description = "name types to use for training") String getNameTypes(); @OptionalParameter(defaultValue = "opennlp.tools.namefind.BioCodec") @ParameterDescription(valueName = "codec", description = "sequence codec used to code name spans") String getSequenceCodec(); @ParameterDescription(valueName = "factoryName", description = "A sub-class of TokenNameFinderFactory") @OptionalParameter String getFactory(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_B0100644 0000000 0000000 00000000163 15217274217 032460 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/BasicFormatParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/BasicFormatParams0100644 0000000 0000000 00000002204 15217274217 034064 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; /** * Common format parameters. */ public interface BasicFormatParams extends EncodingParameter { @ParameterDescription(valueName = "sampleData", description = "data to be used, usually a file name.") File getData(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_B0100644 0000000 0000000 00000000165 15217274217 032462 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/BasicTrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/BasicTrainingPara0100644 0000000 0000000 00000002457 15217274217 034061 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.commons.Internal; /** * Common training parameters. *

* Note: Do not use this class, internal use only! */ @Internal public interface BasicTrainingParams extends LanguageParams { @ParameterDescription(valueName = "paramsFile", description = "training parameters file.") @OptionalParameter() String getParams(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/CVParams.java0100644 0000000 0000000 00000002764 15217274217 033135 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.commons.Internal; /** * Common cross validator parameters. *

* Note: Do not use this class, internal use only! */ @Internal public interface CVParams { @ParameterDescription(valueName = "true|false", description = "if true will print false negatives and false positives.") @OptionalParameter(defaultValue = "false") Boolean getMisclassified(); @ParameterDescription(valueName = "num", description = "number of folds, default is 10.") @OptionalParameter(defaultValue = "10") Integer getFolds(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_D0100644 0000000 0000000 00000000166 15217274217 032465 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/DetokenizerParameter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/DetokenizerParame0100644 0000000 0000000 00000002112 15217274217 034135 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; public interface DetokenizerParameter { @ParameterDescription(valueName = "dictionary", description = "specifies the file with detokenizer dictionary.") String getDetokenizer(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_E0100644 0000000 0000000 00000000163 15217274217 032463 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/EncodingParameter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/EncodingParameter0100644 0000000 0000000 00000003010 15217274217 034111 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import java.nio.charset.Charset; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.commons.Internal; /** * Encoding parameter. The DEFAULT_CHARSET is handled by * {@link opennlp.tools.cmdline.ArgumentParser#parse(String[], Class)}. *

* Note: Do not use this class, internal use only! */ @Internal public interface EncodingParameter { @ParameterDescription(valueName = "charsetName", description = "encoding for reading and writing text, if absent the system default is used.") @OptionalParameter(defaultValue = OptionalParameter.DEFAULT_CHARSET) Charset getEncoding(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_E0100644 0000000 0000000 00000000161 15217274217 032461 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/EvaluatorParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/EvaluatorParams.j0100644 0000000 0000000 00000002741 15217274217 034072 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.commons.Internal; /** * Common evaluation parameters. *

* Note: Do not use this class, internal use only! */ @Internal public interface EvaluatorParams { @ParameterDescription(valueName = "model", description = "the model file to be evaluated.") File getModel(); @ParameterDescription(valueName = "true|false", description = "if true will print false negatives and false positives.") @OptionalParameter(defaultValue = "false") Boolean getMisclassified(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_F0100644 0000000 0000000 00000000174 15217274217 032466 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/FineGrainedEvaluatorParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/FineGrainedEvalua0100644 0000000 0000000 00000002436 15217274217 034046 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import java.io.File; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.commons.Internal; /** * Common evaluation parameters. *

* Note: Do not use this class, internal use only! */ @Internal public interface FineGrainedEvaluatorParams { @ArgumentParser.ParameterDescription(valueName = "outputFile", description = "the path of the fine-grained report file.") @ArgumentParser.OptionalParameter File getReportOutputFile(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_L0100644 0000000 0000000 00000000160 15217274217 032467 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/LanguageParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/LanguageParams.ja0100644 0000000 0000000 00000002052 15217274217 034007 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; public interface LanguageParams { @ParameterDescription(valueName = "language", description = "language which is being processed.") String getLang(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_params_T0100644 0000000 0000000 00000000164 15217274217 032503 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/TrainingToolParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/params/TrainingToolParam0100644 0000000 0000000 00000002350 15217274217 034122 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.params; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.commons.Internal; /** * Common training parameters. *

* Note: Do not use this class, internal use only! */ @Internal public interface TrainingToolParams extends BasicTrainingParams { @ParameterDescription(valueName = "modelFile", description = "output model file.") File getModel(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_B0100644 0000000 0000000 00000000167 15217274217 032475 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/BuildModelUpdaterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/BuildModelUpdater0100644 0000000 0000000 00000004727 15217274217 034120 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserEventTypeEnum; import opennlp.tools.parser.ParserModel; import opennlp.tools.parser.chunking.ParserEventStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.model.ModelUtil; public final class BuildModelUpdaterTool extends ModelUpdaterTool { private static final Logger logger = LoggerFactory.getLogger(BuildModelUpdaterTool.class); public String getShortDescription() { return "Trains and updates the build model in a parser model"; } @Override protected ParserModel trainAndUpdate(ParserModel originalModel, ObjectStream parseSamples, ModelUpdaterParams parameters) throws IOException { Dictionary mdict = ParserTrainerTool.buildDictionary(parseSamples, originalModel.getHeadRules(), 5); parseSamples.reset(); // TODO: training individual models should be in the chunking parser, not here // Training build logger.info("Training builder"); ObjectStream bes = new ParserEventStream(parseSamples, originalModel.getHeadRules(), ParserEventTypeEnum.BUILD, mdict); EventTrainer trainer = TrainerFactory.getEventTrainer( ModelUtil.createDefaultTrainingParameters(), null); MaxentModel buildModel = trainer.train(bes); parseSamples.close(); return originalModel.updateBuildModel(buildModel); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_C0100644 0000000 0000000 00000000167 15217274217 032476 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/CheckModelUpdaterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/CheckModelUpdater0100644 0000000 0000000 00000004772 15217274217 034076 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserEventTypeEnum; import opennlp.tools.parser.ParserModel; import opennlp.tools.parser.chunking.ParserEventStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.model.ModelUtil; /** * Trains a new check model. */ public final class CheckModelUpdaterTool extends ModelUpdaterTool { private static final Logger logger = LoggerFactory.getLogger(CheckModelUpdaterTool.class); @Override public String getShortDescription() { return "Trains and updates the check model in a parser model"; } @Override protected ParserModel trainAndUpdate(ParserModel originalModel, ObjectStream parseSamples, ModelUpdaterParams parameters) throws IOException { Dictionary mdict = ParserTrainerTool.buildDictionary(parseSamples, originalModel.getHeadRules(), 5); parseSamples.reset(); // TODO: Maybe that should be part of the ChunkingParser ... // Training build logger.info("Training check model"); ObjectStream bes = new ParserEventStream(parseSamples, originalModel.getHeadRules(), ParserEventTypeEnum.CHECK, mdict); EventTrainer trainer = TrainerFactory.getEventTrainer( ModelUtil.createDefaultTrainingParameters(), null); MaxentModel checkModel = trainer.train(bes); parseSamples.close(); return originalModel.updateCheckModel(checkModel); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_M0100644 0000000 0000000 00000000162 15217274217 032503 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ModelUpdaterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ModelUpdaterTool.0100644 0000000 0000000 00000005415 15217274217 034047 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.AbstractTypedParamTool; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.ObjectStreamFactory; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserModel; import opennlp.tools.util.ObjectStream; /** * Abstract base class for tools which update the parser model. */ abstract class ModelUpdaterTool extends AbstractTypedParamTool { interface ModelUpdaterParams extends TrainingToolParams { } protected ModelUpdaterTool() { super(Parse.class, ModelUpdaterParams.class); } protected abstract ParserModel trainAndUpdate(ParserModel originalModel, ObjectStream parseSamples, ModelUpdaterParams parameters) throws IOException; @Override public final void run(String format, String[] args) { ModelUpdaterParams params = validateAndParseParams( ArgumentParser.filter(args, ModelUpdaterParams.class), ModelUpdaterParams.class); // Load model to be updated File modelFile = params.getModel(); ParserModel originalParserModel = new ParserModelLoader().load(modelFile); ObjectStreamFactory factory = getStreamFactory(format); String[] fargs = ArgumentParser.filter(args, factory.getParameters()); validateFactoryArgs(factory, fargs); ParserModel updatedParserModel; try (ObjectStream sampleStream = factory.create(fargs)) { updatedParserModel = trainAndUpdate(originalParserModel, sampleStream, params); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } CmdLineUtil.writeModel("parser", modelFile, updatedParserModel); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_P0100644 0000000 0000000 00000000165 15217274217 032511 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserConverterTo0100644 0000000 0000000 00000002371 15217274217 034173 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.parser.Parse; /** * Tool to convert multiple data formats into native OpenNLP parser * format. * * @see AbstractConverterTool * @see Parse */ public class ParserConverterTool extends AbstractConverterTool { public ParserConverterTool() { super(Parse.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_P0100644 0000000 0000000 00000000165 15217274217 032511 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserEvaluatorTo0100644 0000000 0000000 00000005054 15217274217 034167 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.parser.Parse; import opennlp.tools.parser.Parser; import opennlp.tools.parser.ParserEvaluator; import opennlp.tools.parser.ParserFactory; import opennlp.tools.parser.ParserModel; /** * A default {@link Parse}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvaluatorParams */ public class ParserEvaluatorTool extends AbstractEvaluatorTool { private static final Logger logger = LoggerFactory.getLogger(ParserEvaluatorTool.class); public ParserEvaluatorTool() { super(Parse.class, EvaluatorParams.class); } @Override public String getShortDescription() { return "Measures the performance of the Parser model with the reference data"; } @Override public void run(String format, String[] args) { super.run(format, args); ParserModel model = new ParserModelLoader().load(params.getModel()); Parser parser = ParserFactory.create(model); ParserEvaluator evaluator = new ParserEvaluator(parser); logger.info("Evaluating ... "); try { evaluator.evaluate(sampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); logger.info(evaluator.getFMeasure().toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_P0100644 0000000 0000000 00000000163 15217274217 032507 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserModelLoader0100644 0000000 0000000 00000002741 15217274217 034111 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.parser.ParserModel; import opennlp.tools.util.InvalidFormatException; /** * Loads a {@link ParserModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public final class ParserModelLoader extends ModelLoader { public ParserModelLoader() { super("Parser"); } @Override protected ParserModel loadModel(InputStream modelIn) throws IOException, InvalidFormatException { return new ParserModel(modelIn); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserTool.java0100644 0000000 0000000 00000014444 15217274217 033562 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.File; import java.io.IOException; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.cmdline.tokenizer.TokenizerModelLoader; import opennlp.tools.parser.AbstractBottomUpParser; import opennlp.tools.parser.Parse; import opennlp.tools.parser.Parser; import opennlp.tools.parser.ParserFactory; import opennlp.tools.parser.ParserModel; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.tokenize.TokenizerME; import opennlp.tools.tokenize.TokenizerModel; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; public final class ParserTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(ParserTool.class); @Override public String getShortDescription() { return "Performs full syntactic parsing"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " [-bs n -ap n -k n -tk tok_model] model < sentences \n" + "-bs n: Use a beam size of n.\n" + "-ap f: Advance outcomes in with at least f% of the probability mass.\n" + "-k n: Show the top n parses. This will also display their log-probabilities.\n" + "-tk tok_model: Use the specified tokenizer model to tokenize the sentences. " + "Defaults to a WhitespaceTokenizer."; } private static final Pattern UNTOKENIZED_PAREN_PATTERN_1 = Pattern.compile("([^ ])([({)}])"); private static final Pattern UNTOKENIZED_PAREN_PATTERN_2 = Pattern.compile("([({)}])([^ ])"); public static Parse[] parseLine(String line, Parser parser, int numParses) { return parseLine( line, parser, WhitespaceTokenizer.INSTANCE, numParses ); } public static Parse[] parseLine(String line, Parser parser, Tokenizer tokenizer, int numParses) { // fix some parens patterns line = UNTOKENIZED_PAREN_PATTERN_1.matcher(line).replaceAll("$1 $2"); line = UNTOKENIZED_PAREN_PATTERN_2.matcher(line).replaceAll("$1 $2"); // tokenize String[] tokens = tokenizer.tokenize(line); return parseLine(tokens, parser, numParses); } /** * Parses the specified pre-tokenized sentence and returns the requested number of parses * or fewer. *

* This is a convenience method for cases where the input has already been tokenized * into individual tokens. It avoids re-tokenizing and the need to manually construct * the whitespace-separated text and compute character offsets. * * @param tokens The tokens of the sentence to parse. * @param parser The {@link Parser} to use. * @param numParses The number of parses desired. * @return The specified number of {@link Parse parses} for the given tokens. * @throws IllegalArgumentException if {@code tokens} is {@code null} or empty. */ public static Parse[] parseLine(String[] tokens, Parser parser, int numParses) { Parse p = Parse.createFromTokens(tokens); Parse[] parses; if (numParses == 1) { parses = new Parse[]{parser.parse(p)}; } else { parses = parser.parse(p, numParses); } return parses; } @Override public void run(String[] args) { if (args.length < 1) { logger.info(getHelp()); } else { ParserModel model = new ParserModelLoader().load(new File(args[args.length - 1])); Integer beamSize = CmdLineUtil.getIntParameter("-bs", args); if (beamSize == null) { beamSize = AbstractBottomUpParser.defaultBeamSize; } Integer numParses = CmdLineUtil.getIntParameter("-k", args); boolean showTopK; if (numParses == null) { numParses = 1; showTopK = false; } else { showTopK = true; } Double advancePercentage = CmdLineUtil.getDoubleParameter("-ap", args); if (advancePercentage == null) { advancePercentage = AbstractBottomUpParser.defaultAdvancePercentage; } Tokenizer tokenizer = WhitespaceTokenizer.INSTANCE; String tokenizerModelName = CmdLineUtil.getParameter( "-tk", args ); if (tokenizerModelName != null ) { TokenizerModel tokenizerModel = new TokenizerModelLoader().load(new File(tokenizerModelName)); tokenizer = new TokenizerME( tokenizerModel ); } Parser parser = ParserFactory.create(model, beamSize, advancePercentage); PerformanceMonitor perfMon = new PerformanceMonitor("sent"); try (ObjectStream lineStream = new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { perfMon.start(); String line; while ((line = lineStream.read()) != null) { if (line.trim().length() == 0) { logger.debug("empty line"); } else { Parse[] parses = parseLine(line, parser, tokenizer, numParses); for (int pi = 0, pn = parses.length; pi < pn; pi++) { if (showTopK) { logger.debug("{} {} ", pi, parses[pi].getProb()); } parses[pi].show(); perfMon.incrementCounter(); } } } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_P0100644 0000000 0000000 00000000163 15217274217 032507 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/ParserTrainerTool0100644 0000000 0000000 00000014647 15217274217 034174 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EncodingParameter; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.cmdline.parser.ParserTrainerTool.TrainerToolParams; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.parser.HeadRules; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserModel; import opennlp.tools.parser.ParserType; import opennlp.tools.parser.chunking.Parser; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.ModelUtil; public final class ParserTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams, EncodingParameter { } private static final Logger logger = LoggerFactory.getLogger(ParserTrainerTool.class); public ParserTrainerTool() { super(Parse.class, TrainerToolParams.class); } @Override public String getShortDescription() { return "Trains the learnable parser"; } static Dictionary buildDictionary(ObjectStream parseSamples, HeadRules headRules, int cutoff) { logger.info("Building dictionary ..."); Dictionary mdict; try { mdict = Parser. buildDictionary(parseSamples, headRules, cutoff); } catch (IOException e) { logger.error("Error while building dictionary.", e); mdict = null; } logger.info("done"); return mdict; } static ParserType parseParserType(String typeAsString) { ParserType type = null; if (typeAsString != null && typeAsString.length() > 0) { type = ParserType.parse(typeAsString); if (type == null) { throw new TerminateToolException(1, "ParserType training parameter '" + typeAsString + "' is invalid!"); } } return type; } static HeadRules createHeadRules(TrainerToolParams params) throws IOException { ArtifactSerializer headRulesSerializer; if (params.getHeadRulesSerializerImpl() != null) { headRulesSerializer = ExtensionLoader.instantiateExtension(ArtifactSerializer.class, params.getHeadRulesSerializerImpl()); } else { if ("en".equals(params.getLang()) || "eng".equals(params.getLang())) { headRulesSerializer = new opennlp.tools.parser.lang.en.HeadRules.HeadRulesSerializer(); } else if ("es".equals(params.getLang()) || "spa".equals(params.getLang())) { headRulesSerializer = new opennlp.tools.parser.lang.es.AncoraSpanishHeadRules.HeadRulesSerializer(); } else { // default for now, this case should probably cause an error ... headRulesSerializer = new opennlp.tools.parser.lang.en.HeadRules.HeadRulesSerializer(); } } Object headRulesObject = headRulesSerializer.create(new FileInputStream(params.getHeadRules())); if (headRulesObject instanceof HeadRules) { return (HeadRules) headRulesObject; } else { throw new TerminateToolException(-1, "HeadRules Artifact Serializer must create an object of type HeadRules!"); } } // TODO: Add param to train tree insert parser @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), true); if (mlParams != null) { if (!TrainerFactory.isValid(mlParams.getParameters("build"))) { throw new TerminateToolException(1, "Build training parameters are invalid!"); } if (!TrainerFactory.isValid(mlParams.getParameters("check"))) { throw new TerminateToolException(1, "Check training parameters are invalid!"); } if (!TrainerFactory.isValid(mlParams.getParameters("attach"))) { throw new TerminateToolException(1, "Attach training parameters are invalid!"); } if (!TrainerFactory.isValid(mlParams.getParameters("tagger"))) { throw new TerminateToolException(1, "Tagger training parameters are invalid!"); } if (!TrainerFactory.isValid(mlParams.getParameters("chunker"))) { throw new TerminateToolException(1, "Chunker training parameters are invalid!"); } } if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("parser model", modelOutFile); ParserModel model; try { HeadRules rules = createHeadRules(params); ParserType type = parseParserType(params.getParserType()); if (params.getFun()) { Parse.useFunctionTags(true); } if (ParserType.CHUNKING.equals(type)) { model = opennlp.tools.parser.chunking.Parser.train( params.getLang(), sampleStream, rules, mlParams); } else if (ParserType.TREEINSERT.equals(type)) { model = opennlp.tools.parser.treeinsert.Parser.train(params.getLang(), sampleStream, rules, mlParams); } else { throw new IllegalStateException(); } } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("parser", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_T0100644 0000000 0000000 00000000171 15217274217 032512 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/TaggerModelReplacerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/TaggerModelReplac0100644 0000000 0000000 00000004200 15217274217 034056 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.File; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.postag.POSModelLoader; import opennlp.tools.parser.ParserModel; import opennlp.tools.postag.POSModel; // user should train with the POS tool public final class TaggerModelReplacerTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(TaggerModelReplacerTool.class); @Override public String getShortDescription() { return "Replaces the tagger model in a parser model"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " parser.model tagger.model"; } @Override public void run(String[] args) { if (args.length != 2) { logger.info(getHelp()); } else { File parserModelInFile = new File(args[0]); ParserModel parserModel = new ParserModelLoader().load(parserModelInFile); File taggerModelInFile = new File(args[1]); POSModel taggerModel = new POSModelLoader().load(taggerModelInFile); ParserModel updatedParserModel = parserModel.updateTaggerModel(taggerModel); CmdLineUtil.writeModel("parser", parserModelInFile, updatedParserModel); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_parser_T0100644 0000000 0000000 00000000160 15217274217 032510 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/parser/TrainingParams.ja0100644 0000000 0000000 00000003631 15217274217 034054 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.parser; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParams for {@link opennlp.tools.parser.Parser}. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "CHUNKING|TREEINSERT", description = "one of CHUNKING or TREEINSERT, default is CHUNKING.") @OptionalParameter(defaultValue = "CHUNKING") String getParserType(); @ParameterDescription(valueName = "className", description = "head rules artifact serializer class name") @OptionalParameter String getHeadRulesSerializerImpl(); @ParameterDescription(valueName = "headRulesFile", description = "head rules file.") File getHeadRules(); @ParameterDescription(valueName = "true|false", description = "Learn to generate function tags.") @OptionalParameter(defaultValue = "false") Boolean getFun(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000174 15217274217 032512 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSEvaluationErro0100644 0000000 0000000 00000004005 15217274217 034062 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.log.LogPrintStream; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.POSTaggerEvaluationMonitor; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints * to an output stream. */ public class POSEvaluationErrorListener extends EvaluationErrorPrinter implements POSTaggerEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(POSEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public POSEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream}. */ public POSEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(POSSample reference, POSSample prediction) { printError(reference.getTags(), prediction.getTags(), reference, prediction, reference.getSentence()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000160 15217274217 032505 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSModelLoader.ja0100644 0000000 0000000 00000002577 15217274217 033717 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.postag.POSModel; /** * Loads a {@link POSModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public final class POSModelLoader extends ModelLoader { public POSModelLoader() { super("POS Tagger"); } @Override protected POSModel loadModel(InputStream modelIn) throws IOException { return new POSModel(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000170 15217274217 032506 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerConverte0100644 0000000 0000000 00000002450 15217274217 034044 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.postag.POSSample; /** * Tool to convert multiple data formats into native OpenNLP part of speech tagging * training format. * * @see AbstractConverterTool * @see POSSample */ public class POSTaggerConverterTool extends AbstractConverterTool { public POSTaggerConverterTool() { super(POSSample.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000175 15217274217 032513 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerCrossVal0100644 0000000 0000000 00000011045 15217274217 034013 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractCrossValidatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.namefind.TokenNameFinderTrainerTool; import opennlp.tools.cmdline.params.CVParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.cmdline.postag.POSTaggerCrossValidatorTool.CVToolParams; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.POSTaggerCrossValidator; import opennlp.tools.postag.POSTaggerEvaluationMonitor; import opennlp.tools.util.model.ModelUtil; public final class POSTaggerCrossValidatorTool extends AbstractCrossValidatorTool { interface CVToolParams extends CVParams, TrainingParams, FineGrainedEvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(POSTaggerCrossValidatorTool.class); public POSTaggerCrossValidatorTool() { super(POSSample.class, CVToolParams.class); } @Override public String getShortDescription() { return "K-fold cross validator for the learnable POS tagger"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } POSTaggerEvaluationMonitor missclassifiedListener = null; if (params.getMisclassified()) { missclassifiedListener = new POSEvaluationErrorListener(); } POSTaggerFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new POSTaggerFineGrainedReportListener( reportOutputStream); } catch (FileNotFoundException e) { throw createTerminationIOException(e); } } Map resources; try { resources = TokenNameFinderTrainerTool.loadResources(params.getResources(), params.getFeaturegen()); } catch (IOException e) { throw new TerminateToolException(-1,"IO error while loading resources", e); } byte[] featureGeneratorBytes = TokenNameFinderTrainerTool.openFeatureGeneratorBytes(params.getFeaturegen()); POSTaggerCrossValidator validator; try { validator = new POSTaggerCrossValidator(params.getLang(), mlParams, params.getDict(), featureGeneratorBytes, resources, params.getTagDictCutoff(), params.getFactory(), missclassifiedListener, reportListener); validator.evaluate(sampleStream, params.getFolds()); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); if (reportListener != null) { logger.info("Writing fine-grained report to {}", params.getReportOutputFile().getAbsolutePath()); reportListener.writeReport(); try { reportOutputStream.flush(); reportOutputStream.close(); } catch (IOException e) { // nothing to do } } logger.info("Accuracy: {}", validator.getWordAccuracy()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000170 15217274217 032506 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerEvaluato0100644 0000000 0000000 00000010144 15217274217 034036 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.cmdline.params.FineGrainedEvaluatorParams; import opennlp.tools.cmdline.postag.POSTaggerEvaluatorTool.EvalToolParams; import opennlp.tools.postag.POSEvaluator; import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.POSTaggerEvaluationMonitor; /** * A default {@link POSSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class POSTaggerEvaluatorTool extends AbstractEvaluatorTool { private static final Logger logger = LoggerFactory.getLogger(POSTaggerEvaluatorTool.class); interface EvalToolParams extends EvaluatorParams, FineGrainedEvaluatorParams { } public POSTaggerEvaluatorTool() { super(POSSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the POS tagger model with the reference data"; } @Override public void run(String format, String[] args) { super.run(format, args); POSModel model = new POSModelLoader().load(params.getModel()); POSTaggerEvaluationMonitor missclassifiedListener = null; if (params.getMisclassified()) { missclassifiedListener = new POSEvaluationErrorListener(); } POSTaggerFineGrainedReportListener reportListener = null; File reportFile = params.getReportOutputFile(); OutputStream reportOutputStream = null; if (reportFile != null) { CmdLineUtil.checkOutputFile("Report Output File", reportFile); try { reportOutputStream = new FileOutputStream(reportFile); reportListener = new POSTaggerFineGrainedReportListener( reportOutputStream); } catch (FileNotFoundException e) { throw new TerminateToolException(-1, "IO error while creating POS Tagger fine-grained report file: " + e.getMessage()); } } POSEvaluator evaluator = new POSEvaluator( new opennlp.tools.postag.POSTaggerME(model), missclassifiedListener, reportListener); logger.info("Evaluating ... "); try { evaluator.evaluate(sampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); if (reportListener != null) { logger.info("Writing fine-grained report to {}", params.getReportOutputFile().getAbsolutePath()); reportListener.writeReport(); try { reportOutputStream.flush(); reportOutputStream.close(); } catch (IOException e) { // nothing to do } } logger.info("Accuracy: {}", evaluator.getWordAccuracy()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000204 15217274217 032504 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerFineGrainedReportListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerFineGrai0100644 0000000 0000000 00000005126 15217274217 033746 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.FineGrainedReportListener; import opennlp.tools.log.LogPrintStream; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.POSTaggerEvaluationMonitor; /** * Generates a detailed report for the POS Tagger. *

* It is possible to use it from an API and access the statistics using the * provided getters * */ public class POSTaggerFineGrainedReportListener extends FineGrainedReportListener implements POSTaggerEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(POSTaggerFineGrainedReportListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public POSTaggerFineGrainedReportListener() { this(new LogPrintStream(logger)); } /** * Creates a listener that prints to a given {@link OutputStream}. */ public POSTaggerFineGrainedReportListener(OutputStream outputStream) { super(outputStream); } // methods inherited from EvaluationMonitor @Override public void misclassified(POSSample reference, POSSample prediction) { statsAdd(reference, prediction); } @Override public void correctlyClassified(POSSample reference, POSSample prediction) { statsAdd(reference, prediction); } private void statsAdd(POSSample reference, POSSample prediction) { getStats().add(reference.getSentence(), reference.getTags(), prediction.getTags()); } @Override public void writeReport() { printGeneralStatistics(); // token stats printTokenErrorRank(); printTokenOccurrencesRank(); // tag stats printTagsErrorRank(); // confusion tables printGeneralConfusionTable(); printDetailedConfusionMatrix(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000157 15217274217 032513 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerTool.jav0100644 0000000 0000000 00000005415 15217274217 033757 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.POSTaggerME; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; public final class POSTaggerTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(POSTaggerTool.class); @Override public String getShortDescription() { return "Learnable part of speech tagger"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < sentences"; } @Override public void run(String[] args) { if (args.length != 1) { logger.info(getHelp()); } else { POSModel model = new POSModelLoader().load(new File(args[0])); POSTaggerME tagger = new POSTaggerME(model); PerformanceMonitor perfMon = new PerformanceMonitor("sent"); try (ObjectStream lineStream = new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { perfMon.start(); String line; while ((line = lineStream.read()) != null) { String[] whitespaceTokenizerLine = WhitespaceTokenizer.INSTANCE.tokenize(line); String[] tags = tagger.tag(whitespaceTokenizerLine); POSSample sample = new POSSample(whitespaceTokenizerLine, tags); logger.info(sample.toString()); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_P0100644 0000000 0000000 00000000166 15217274217 032513 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/POSTaggerTrainerT0100644 0000000 0000000 00000011446 15217274217 034014 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.File; import java.io.IOException; import java.util.Map; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.namefind.TokenNameFinderTrainerTool; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.cmdline.postag.POSTaggerTrainerTool.TrainerToolParams; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.postag.MutableTagDictionary; import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.POSTaggerFactory; import opennlp.tools.postag.POSTaggerME; import opennlp.tools.postag.TagDictionary; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ModelUtil; public final class POSTaggerTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams { } public POSTaggerTrainerTool() { super(POSSample.class, TrainerToolParams.class); } @Override public String getShortDescription() { return "Trains a model for the part-of-speech tagger"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), true); if (mlParams != null && !TrainerFactory.isValid(mlParams)) { throw new TerminateToolException(1, "Training parameters file '" + params.getParams() + "' is invalid!"); } if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("pos tagger model", modelOutFile); Map resources; try { resources = TokenNameFinderTrainerTool.loadResources( params.getResources(), params.getFeaturegen()); } catch (IOException e) { throw new TerminateToolException(-1,"IO error while loading resources", e); } byte[] featureGeneratorBytes = TokenNameFinderTrainerTool.openFeatureGeneratorBytes(params.getFeaturegen()); POSTaggerFactory postaggerFactory; try { postaggerFactory = POSTaggerFactory.create(params.getFactory(), featureGeneratorBytes, resources, null); } catch (InvalidFormatException e) { throw new TerminateToolException(-1, e.getMessage(), e); } if (params.getDict() != null) { try { postaggerFactory.setTagDictionary(postaggerFactory .createTagDictionary(params.getDict())); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while loading POS Dictionary", e); } } if (params.getTagDictCutoff() != null) { try { TagDictionary dict = postaggerFactory.getTagDictionary(); if (dict == null) { dict = postaggerFactory.createEmptyTagDictionary(); postaggerFactory.setTagDictionary(dict); } if (dict instanceof MutableTagDictionary) { POSTaggerME.populatePOSDictionary(sampleStream, (MutableTagDictionary)dict, params.getTagDictCutoff()); } else { throw new IllegalArgumentException( "Can't extend a POSDictionary that does not implement MutableTagDictionary."); } sampleStream.reset(); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while creating/extending POS Dictionary: " + e.getMessage(), e); } } POSModel model; try { model = opennlp.tools.postag.POSTaggerME.train(params.getLang(), sampleStream, mlParams, postaggerFactory); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("pos tagger", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_postag_T0100644 0000000 0000000 00000000160 15217274217 032511 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/postag/TrainingParams.ja0100644 0000000 0000000 00000004063 15217274217 034055 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.postag; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParameters for Name Finder. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "featuregenFile", description = "The feature generator descriptor file") @OptionalParameter File getFeaturegen(); @ParameterDescription(valueName = "resourcesDir", description = "The resources directory") @OptionalParameter File getResources(); @ParameterDescription(valueName = "dictionaryPath", description = "The XML tag dictionary file") @OptionalParameter File getDict(); @ParameterDescription(valueName = "tagDictCutoff", description = "TagDictionary cutoff. If specified will create/expand a mutable TagDictionary") @OptionalParameter Integer getTagDictCutoff(); @ParameterDescription(valueName = "factoryName", description = "A sub-class of POSTaggerFactory where to get implementation and resources.") @OptionalParameter String getFactory(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000203 15217274217 032542 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetectorConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetec0100644 0000000 0000000 00000002515 15217274217 034123 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.sentdetect.SentenceSample; /** * Tool to convert multiple data formats into native OpenNLP sentence detector * training format. * * @see AbstractConverterTool * @see SentenceSample */ public class SentenceDetectorConverterTool extends AbstractConverterTool { public SentenceDetectorConverterTool() { super(SentenceSample.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000210 15217274217 032540 xustar000000000 0000000 136 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetectorCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetec0100644 0000000 0000000 00000006655 15217274217 034134 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractCrossValidatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.params.CVParams; import opennlp.tools.cmdline.sentdetect.SentenceDetectorCrossValidatorTool.CVToolParams; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.sentdetect.SDCrossValidator; import opennlp.tools.sentdetect.SentenceDetectorEvaluationMonitor; import opennlp.tools.sentdetect.SentenceDetectorFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.sentdetect.SentenceSampleStream; import opennlp.tools.util.eval.FMeasure; import opennlp.tools.util.model.ModelUtil; public final class SentenceDetectorCrossValidatorTool extends AbstractCrossValidatorTool { private static final Logger logger = LoggerFactory.getLogger(SentenceDetectorCrossValidatorTool.class); interface CVToolParams extends TrainingParams, CVParams { } public SentenceDetectorCrossValidatorTool() { super(SentenceSample.class, CVToolParams.class); } @Override public String getShortDescription() { return "K-fold cross validator for the learnable sentence detector"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } SDCrossValidator validator; SentenceDetectorEvaluationMonitor errorListener = null; if (params.getMisclassified()) { errorListener = new SentenceEvaluationErrorListener(); } char[] eos = null; if (params.getEosChars() != null) { String eosString = SentenceSampleStream.replaceNewLineEscapeTags(params.getEosChars()); eos = eosString.toCharArray(); } try { Dictionary abbreviations = SentenceDetectorTrainerTool.loadDict(params.getAbbDict()); SentenceDetectorFactory sdFactory = SentenceDetectorFactory.create( params.getFactory(), params.getLang(), true, abbreviations, eos); validator = new SDCrossValidator(params.getLang(), mlParams, sdFactory, errorListener); validator.evaluate(sampleStream, params.getFolds()); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } FMeasure result = validator.getFMeasure(); logger.info(result.toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000203 15217274217 032542 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetectorEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetec0100644 0000000 0000000 00000006036 15217274217 034125 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.cmdline.sentdetect.SentenceDetectorEvaluatorTool.EvalToolParams; import opennlp.tools.sentdetect.SentenceDetectorEvaluationMonitor; import opennlp.tools.sentdetect.SentenceDetectorEvaluator; import opennlp.tools.sentdetect.SentenceDetectorME; import opennlp.tools.sentdetect.SentenceModel; import opennlp.tools.sentdetect.SentenceSample; /** * A default {@link SentenceSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class SentenceDetectorEvaluatorTool extends AbstractEvaluatorTool { interface EvalToolParams extends EvaluatorParams { } private static final Logger logger = LoggerFactory.getLogger(SentenceDetectorEvaluatorTool.class); public SentenceDetectorEvaluatorTool() { super(SentenceSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the learnable sentence detector"; } @Override public void run(String format, String[] args) { super.run(format, args); SentenceModel model = new SentenceModelLoader().load(params.getModel()); SentenceDetectorEvaluationMonitor errorListener = null; if (params.getMisclassified()) { errorListener = new SentenceEvaluationErrorListener(); } SentenceDetectorEvaluator evaluator = new SentenceDetectorEvaluator( new SentenceDetectorME(model), errorListener); logger.info("Evaluating ... "); try { evaluator.evaluate(sampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading training data or indexing data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); logger.info(evaluator.getFMeasure().toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000172 15217274217 032547 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetectorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetec0100644 0000000 0000000 00000005632 15217274217 034126 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.sentdetect.SentenceDetectorME; import opennlp.tools.sentdetect.SentenceModel; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.ParagraphStream; import opennlp.tools.util.PlainTextByLineStream; /** * A sentence detector which uses a maxent model to predict the sentences. */ public final class SentenceDetectorTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(SentenceDetectorTool.class); @Override public String getShortDescription() { return "Learnable sentence detector"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < sentences"; } /** * Perform sentence detection on a stream of sentences. *

* A newline will be treated as a paragraph boundary. */ @Override public void run(String[] args) { if (args.length != 1) { logger.info(getHelp()); } else { SentenceModel model = new SentenceModelLoader().load(new File(args[0])); SentenceDetectorME sdetector = new SentenceDetectorME(model); PerformanceMonitor perfMon = new PerformanceMonitor("sent"); perfMon.start(); try (ObjectStream paraStream = new ParagraphStream(new PlainTextByLineStream( new SystemInputStreamFactory(), SystemInputStreamFactory.encoding()))) { String para; while ((para = paraStream.read()) != null) { String[] sents = sdetector.sentDetect(para); for (String sentence : sents) { logger.info(sentence); } perfMon.incrementCounter(sents.length); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000201 15217274217 032540 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetectorTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceDetec0100644 0000000 0000000 00000007414 15217274217 034126 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.cmdline.sentdetect.SentenceDetectorTrainerTool.TrainerToolParams; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.TrainerFactory.TrainerType; import opennlp.tools.sentdetect.SentenceDetectorFactory; import opennlp.tools.sentdetect.SentenceDetectorME; import opennlp.tools.sentdetect.SentenceModel; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.sentdetect.SentenceSampleStream; import opennlp.tools.util.model.ModelUtil; public final class SentenceDetectorTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams { } public SentenceDetectorTrainerTool() { super(SentenceSample.class, TrainerToolParams.class); } @Override public String getShortDescription() { return "Trainer for the learnable sentence detector"; } static Dictionary loadDict(File f) throws IOException { Dictionary dict = null; if (f != null) { CmdLineUtil.checkInputFile("abb dict", f); dict = new Dictionary(new BufferedInputStream(new FileInputStream(f))); } return dict; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams != null) { if (!TrainerType.EVENT_MODEL_TRAINER.equals(TrainerFactory.getTrainerType(mlParams))) { throw new TerminateToolException(1, "Sequence training is not supported!"); } } if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("sentence detector model", modelOutFile); char[] eos = null; if (params.getEosChars() != null) { String eosString = SentenceSampleStream.replaceNewLineEscapeTags( params.getEosChars()); eos = eosString.toCharArray(); } SentenceModel model; try { Dictionary dict = loadDict(params.getAbbDict()); SentenceDetectorFactory sdFactory = SentenceDetectorFactory.create( params.getFactory(), params.getLang(), params.getUseTokenEnd(), dict, eos); model = SentenceDetectorME.train(params.getLang(), sampleStream, sdFactory, mlParams); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("sentence detector", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000205 15217274217 032544 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceEvalu0100644 0000000 0000000 00000004125 15217274217 034152 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.log.LogPrintStream; import opennlp.tools.sentdetect.SentenceDetectorEvaluationMonitor; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints * to an output stream. */ public class SentenceEvaluationErrorListener extends EvaluationErrorPrinter implements SentenceDetectorEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(SentenceEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public SentenceEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream}. */ public SentenceEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(SentenceSample reference, SentenceSample prediction) { printError(reference.getSentences(), prediction.getSentences(), reference, prediction, reference.getDocument()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000171 15217274217 032546 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/SentenceModel0100644 0000000 0000000 00000002773 15217274217 034145 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.sentdetect.SentenceModel; import opennlp.tools.util.InvalidFormatException; /** * Loads a {@link SentenceModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal final class SentenceModelLoader extends ModelLoader { public SentenceModelLoader() { super("Sentence Detector"); } @Override protected SentenceModel loadModel(InputStream modelIn) throws IOException, InvalidFormatException { return new SentenceModel(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_sentdete0100644 0000000 0000000 00000000164 15217274217 032550 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/sentdetect/TrainingParam0100644 0000000 0000000 00000003667 15217274217 034157 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.sentdetect; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParams for Sentence Detector. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "path", description = "abbreviation dictionary in XML format.") @OptionalParameter File getAbbDict(); @ParameterDescription(valueName = "string", description = "EOS characters.") @OptionalParameter String getEosChars(); @ParameterDescription(valueName = "factoryName", description = "A sub-class of SentenceDetectorFactory where to get implementation and resources.") @OptionalParameter String getFactory(); @ParameterDescription(valueName = "useTokenEnd", description = "A boolean parameter to detect the start index of the next sentence in the test data.") @OptionalParameter(defaultValue = "true") Boolean getUseTokenEnd(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000171 15217274217 032563 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/CommandLineTokenizer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/CommandLineTok0100644 0000000 0000000 00000004442 15217274217 034127 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.tokenize.TokenizerStream; import opennlp.tools.tokenize.WhitespaceTokenStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; final class CommandLineTokenizer { private static final Logger logger = LoggerFactory.getLogger(CommandLineTokenizer.class); private final Tokenizer tokenizer; CommandLineTokenizer(Tokenizer tokenizer) { this.tokenizer = tokenizer; } void process() { ObjectStream untokenizedLineStream; ObjectStream tokenizedLineStream; PerformanceMonitor perfMon = new PerformanceMonitor("sent"); try { untokenizedLineStream = new PlainTextByLineStream(new SystemInputStreamFactory(), SystemInputStreamFactory.encoding()); tokenizedLineStream = new WhitespaceTokenStream( new TokenizerStream(tokenizer, untokenizedLineStream)); perfMon.start(); String tokenizedLine; while ((tokenizedLine = tokenizedLineStream.read()) != null) { logger.info(tokenizedLine); perfMon.incrementCounter(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } perfMon.stopAndPrintFinalResult(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000203 15217274217 032557 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/DetokenEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/DetokenEvaluat0100644 0000000 0000000 00000003730 15217274217 034175 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.log.LogPrintStream; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.tokenize.TokenizerEvaluationMonitor; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints * to an output stream. */ public class DetokenEvaluationErrorListener extends EvaluationErrorPrinter implements TokenizerEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(DetokenEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public DetokenEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream}. */ public DetokenEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(TokenSample reference, TokenSample prediction) { printError(reference, prediction); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000203 15217274217 032557 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/DetokenizationDictionaryLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/Detokenization0100644 0000000 0000000 00000002461 15217274217 034251 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.tokenize.DetokenizationDictionary; final class DetokenizationDictionaryLoader extends ModelLoader { DetokenizationDictionaryLoader() { super("detokenizer dictionary"); } @Override protected DetokenizationDictionary loadModel(InputStream modelIn) throws IOException { return new DetokenizationDictionary(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000176 15217274217 032570 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/DictionaryDetokenizerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/DictionaryDeto0100644 0000000 0000000 00000005522 15217274217 034204 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.PerformanceMonitor; import opennlp.tools.cmdline.SystemInputStreamFactory; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.tokenize.DictionaryDetokenizer; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; public final class DictionaryDetokenizerTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(DictionaryDetokenizerTool.class); @Override public String getShortDescription() { return "Normalizes tokenized text according to rules defined in a detokenizer dictionary"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " detokenizerDictionary"; } @Override public void run(String[] args) { if (args.length != 1) { logger.info(getHelp()); } else { try { Detokenizer detokenizer = new DictionaryDetokenizer( new DetokenizationDictionaryLoader().load(new File(args[0]))); try (ObjectStream tokenizedLineStream = new PlainTextByLineStream(new SystemInputStreamFactory(), SystemInputStreamFactory.encoding())) { PerformanceMonitor perfMon = new PerformanceMonitor("sent"); perfMon.start(); String tokenizedLine; while ((tokenizedLine = tokenizedLineStream.read()) != null) { // white space tokenize line String[] tokens = WhitespaceTokenizer.INSTANCE.tokenize(tokenizedLine); logger.info(detokenizer.detokenize(tokens, null)); perfMon.incrementCounter(); } perfMon.stopAndPrintFinalResult(); } } catch (IOException e) { CmdLineUtil.handleStdinIoError(e); } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000170 15217274217 032562 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/SimpleTokenizerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/SimpleTokenize0100644 0000000 0000000 00000003245 15217274217 034225 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; public final class SimpleTokenizerTool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(SimpleTokenizerTool.class); @Override public String getShortDescription() { return "Character class tokenizer"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " < sentences"; } @Override public boolean hasParams() { return false; } @Override public void run(String[] args) { if (args.length != 0) { logger.info(getHelp()); } else { CommandLineTokenizer tokenizer = new CommandLineTokenizer(opennlp.tools.tokenize.SimpleTokenizer.INSTANCE); tokenizer.process(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000201 15217274217 032555 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenEvaluationErrorListener.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenEvaluatio0100644 0000000 0000000 00000004044 15217274217 034213 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.EvaluationErrorPrinter; import opennlp.tools.log.LogPrintStream; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.tokenize.TokenizerEvaluationMonitor; import opennlp.tools.util.eval.EvaluationMonitor; /** * A default implementation of {@link EvaluationMonitor} that prints * to an output stream. */ public class TokenEvaluationErrorListener extends EvaluationErrorPrinter implements TokenizerEvaluationMonitor { private static final Logger logger = LoggerFactory.getLogger(TokenEvaluationErrorListener.class); /** * Creates a listener that will print to the configured {@code logger}. */ public TokenEvaluationErrorListener() { super(new LogPrintStream(logger)); } /** * Creates a listener that will print to a given {@link OutputStream}. */ public TokenEvaluationErrorListener(OutputStream outputStream) { super(outputStream); } @Override public void misclassified(TokenSample reference, TokenSample prediction) { printError(reference.getTokenSpans(), prediction.getTokenSpans(), reference, prediction, reference.getText()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000173 15217274217 032565 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerConverterTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerConve0100644 0000000 0000000 00000002460 15217274217 034226 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import opennlp.tools.cmdline.AbstractConverterTool; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.tokenize.TokenSample; /** * Tool to convert multiple data formats into native OpenNLP sentence detector * training format. * * @see AbstractConverterTool * @see TokenSample */ public class TokenizerConverterTool extends AbstractConverterTool { public TokenizerConverterTool() { super(TokenSample.class); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000200 15217274217 032554 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerCrossValidatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerCross0100644 0000000 0000000 00000006144 15217274217 034250 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractCrossValidatorTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.params.CVParams; import opennlp.tools.cmdline.tokenizer.TokenizerCrossValidatorTool.CVToolParams; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.tokenize.TokenizerCrossValidator; import opennlp.tools.tokenize.TokenizerEvaluationMonitor; import opennlp.tools.tokenize.TokenizerFactory; import opennlp.tools.util.eval.FMeasure; import opennlp.tools.util.model.ModelUtil; public final class TokenizerCrossValidatorTool extends AbstractCrossValidatorTool { interface CVToolParams extends CVParams, TrainingParams { } private static final Logger logger = LoggerFactory.getLogger(TokenizerCrossValidatorTool.class); public TokenizerCrossValidatorTool() { super(TokenSample.class, CVToolParams.class); } @Override public String getShortDescription() { return "K-fold cross validator for the learnable tokenizer"; } @Override public void run(String format, String[] args) { super.run(format, args); mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } TokenizerCrossValidator validator; TokenizerEvaluationMonitor listener = null; if (params.getMisclassified()) { listener = new TokenEvaluationErrorListener(); } try { Dictionary dict = TokenizerTrainerTool.loadDict(params.getAbbDict()); TokenizerFactory tokFactory = TokenizerFactory.create( params.getFactory(), params.getLang(), dict, params.getAlphaNumOpt(), null); validator = new opennlp.tools.tokenize.TokenizerCrossValidator(mlParams, tokFactory, listener); validator.evaluate(sampleStream, params.getFolds()); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } FMeasure result = validator.getFMeasure(); logger.info(result.toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000175 15217274217 032567 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerMEEvaluatorTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerMEEva0100644 0000000 0000000 00000005626 15217274217 034120 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.AbstractEvaluatorTool; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EvaluatorParams; import opennlp.tools.cmdline.tokenizer.TokenizerMEEvaluatorTool.EvalToolParams; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.tokenize.TokenizerEvaluationMonitor; import opennlp.tools.tokenize.TokenizerEvaluator; import opennlp.tools.tokenize.TokenizerModel; /** * A default {@link TokenSample}-centric implementation of {@link AbstractEvaluatorTool} * that prints to an output stream. * * @see AbstractEvaluatorTool * @see EvalToolParams */ public final class TokenizerMEEvaluatorTool extends AbstractEvaluatorTool { private static final Logger logger = LoggerFactory.getLogger(TokenizerMEEvaluatorTool.class); interface EvalToolParams extends EvaluatorParams { } public TokenizerMEEvaluatorTool() { super(TokenSample.class, EvalToolParams.class); } @Override public String getShortDescription() { return "Measures the performance of the learnable tokenizer"; } @Override public void run(String format, String[] args) { super.run(format, args); TokenizerModel model = new TokenizerModelLoader().load(params.getModel()); TokenizerEvaluationMonitor misclassifiedListener = null; if (params.getMisclassified()) { misclassifiedListener = new TokenEvaluationErrorListener(); } TokenizerEvaluator evaluator = new TokenizerEvaluator( new opennlp.tools.tokenize.TokenizerME(model), misclassifiedListener); logger.info("Evaluating ... "); try { evaluator.evaluate(sampleStream); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while reading test data: " + e.getMessage(), e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } logger.info("done"); logger.info(evaluator.getFMeasure().toString()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000164 15217274217 032565 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerMETool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerMEToo0100644 0000000 0000000 00000003356 15217274217 034144 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.File; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.cmdline.BasicCmdLineTool; import opennlp.tools.cmdline.CLI; import opennlp.tools.tokenize.TokenizerModel; public final class TokenizerMETool extends BasicCmdLineTool { private static final Logger logger = LoggerFactory.getLogger(TokenizerMETool.class); @Override public String getShortDescription() { return "Learnable tokenizer"; } @Override public String getHelp() { return "Usage: " + CLI.CMD + " " + getName() + " model < sentences"; } @Override public void run(String[] args) { if (args.length != 1) { logger.info(getHelp()); } else { TokenizerModel model = new TokenizerModelLoader().load(new File(args[0])); CommandLineTokenizer tokenizer = new CommandLineTokenizer(new opennlp.tools.tokenize.TokenizerME(model)); tokenizer.process(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000171 15217274217 032563 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerModelLoader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerModel0100644 0000000 0000000 00000002655 15217274217 034222 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.ModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.tokenize.TokenizerModel; /** * Loads a {@link TokenizerModel} for the command line tools. *

* Note: Do not use this class, internal use only! */ @Internal public final class TokenizerModelLoader extends ModelLoader { public TokenizerModelLoader() { super("Tokenizer"); } @Override protected TokenizerModel loadModel(InputStream modelIn) throws IOException { return new TokenizerModel(modelIn); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000171 15217274217 032563 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerTrainerTool.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TokenizerTrain0100644 0000000 0000000 00000007736 15217274217 034244 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import opennlp.tools.cmdline.AbstractTrainerTool; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.TrainingToolParams; import opennlp.tools.cmdline.tokenizer.TokenizerTrainerTool.TrainerToolParams; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.TrainerFactory.TrainerType; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.tokenize.TokenizerFactory; import opennlp.tools.tokenize.TokenizerModel; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.model.ModelUtil; public final class TokenizerTrainerTool extends AbstractTrainerTool { interface TrainerToolParams extends TrainingParams, TrainingToolParams { } public TokenizerTrainerTool() { super(TokenSample.class, TrainerToolParams.class); } @Override public String getShortDescription() { return "Trainer for the learnable tokenizer"; } static Dictionary loadDict(File f) throws IOException { Dictionary dict = null; if (f != null && f.exists()) { CmdLineUtil.checkInputFile("abb dict", f); try (InputStream in = new BufferedInputStream(new FileInputStream(f))) { if (in.available() == 0) { throw new InvalidFormatException("Encountered an empty dictionary file?!"); } else { dict = new Dictionary(in); } } } return dict; } @Override public void run(String format, String[] args) { super.run(format, args); if (null != params.getParams()) mlParams = CmdLineUtil.loadTrainingParameters(params.getParams(), false); else mlParams = TrainingParameters.setParams(args); if (mlParams != null) { if (!TrainerFactory.isValid(mlParams)) { throw new TerminateToolException(1, "Training parameters file '" + params.getParams() + "' is invalid!"); } if (!TrainerType.EVENT_MODEL_TRAINER.equals(TrainerFactory.getTrainerType(mlParams))) { throw new TerminateToolException(1, "Sequence training is not supported!"); } } if (mlParams == null) { mlParams = ModelUtil.createDefaultTrainingParameters(); } File modelOutFile = params.getModel(); CmdLineUtil.checkOutputFile("tokenizer model", modelOutFile); TokenizerModel model; try { Dictionary dict = loadDict(params.getAbbDict()); TokenizerFactory tokFactory = TokenizerFactory.create( params.getFactory(), params.getLang(), dict, params.getAlphaNumOpt(), null); model = opennlp.tools.tokenize.TokenizerME.train(sampleStream, tokFactory, mlParams); } catch (IOException e) { throw createTerminationIOException(e); } finally { try { sampleStream.close(); } catch (IOException e) { // sorry that this can fail } } CmdLineUtil.writeModel("tokenizer", modelOutFile, model); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_cmdline_tokenize0100644 0000000 0000000 00000000163 15217274217 032564 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TrainingParams.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/cmdline/tokenizer/TrainingParams0100644 0000000 0000000 00000004150 15217274217 034176 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.cmdline.tokenizer; import java.io.File; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.params.BasicTrainingParams; import opennlp.tools.commons.Internal; /** * TrainingParameters for Tokenizer. *

* Note: Do not use this class, internal use only! */ @Internal interface TrainingParams extends BasicTrainingParams { @ParameterDescription(valueName = "isAlphaNumOpt", description = "Optimization flag to skip alpha numeric tokens for further tokenization") @OptionalParameter(defaultValue = "false") Boolean getAlphaNumOpt(); @ParameterDescription(valueName = "path", description = "abbreviation dictionary in XML format.") @OptionalParameter File getAbbDict(); @ParameterDescription(valueName = "factoryName", description = "A sub-class of TokenizerFactory where to get implementation and resources.") @OptionalParameter String getFactory(); @ParameterDescription(valueName = "cutOffNum", description = "Minimal number of times a feature must be seen") @OptionalParameter String getCutoff(); @ParameterDescription(valueName = "iterationsNum", description = "Number of training iterations") @OptionalParameter String getIterations(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/commons/Internal.java0100644 0000000 0000000 00000002643 15217274217 032006 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.commons; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Classes, fields, or methods annotated {@code @Internal} are for OpenNLP * internal use only. Such elements are likely to be removed, have a different access level, * or might experience a signature change in upcoming releases of OpenNLP. */ @Documented @Retention(value = RetentionPolicy.RUNTIME) public @interface Internal { String value() default ""; /** * The OpenNLP release when an element was first declared internal. */ String since() default ""; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/commons/Sample.java0100644 0000000 0000000 00000001717 15217274217 031454 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.commons; import java.io.Serializable; /** * Represents a generic type of processable elements. */ public interface Sample extends Serializable { } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/commons/ThreadSafe.java0100644 0000000 0000000 00000004670 15217274217 032242 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.commons; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Classes, fields, or methods annotated {@code @ThreadSafe} are safe to use * in multithreading contexts. In general, classes that adhere to (one of) * the following concepts: *

    *
  • Statelessness: no methods relies on external state or * maintain state at all,
  • *
  • Immutability: all attributes are {@code final} so that * internal state can't be modified at all,
  • *
  • Thread locality: non-{@code final} fields are only * accessed via an independently initialized copy,
  • *
  • Atomicity: all operations on fields are perform via * {@link java.util.concurrent.atomic atomic data types}, or
  • *
  • Synchronization: all non-final methods, fields, or * method local variables are manipulated via locks, that is, in a * {@code synchronized} manner
  • *
* are safe to use from multiple threads. In addition, thread-safety can be * achieved by using the concepts of either *
    *
  • {@link java.util.concurrent.locks.ReentrantLock ReentrantLock}, or *
  • {@link java.util.concurrent.locks.ReadWriteLock ReadWriteLock} *
* in which a thread acquires the lock for write operations and protects * the locked object or data element from changes until the lock is released. */ @Documented @Retention(value = RetentionPolicy.RUNTIME) public @interface ThreadSafe { /** * The OpenNLP release when an element was first declared {@code thread-safe}. */ String since() default ""; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/commons/Trainer.java0100644 0000000 0000000 00000003561 15217274217 031636 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.commons; import java.util.Map; import opennlp.tools.util.TrainingConfiguration; import opennlp.tools.util.TrainingParameters; /** * Represents a common base for training implementations. */ public interface Trainer { /** * Conducts the initialization of an {@link Trainer} via * {@link TrainingParameters} and a {@link Map report map}. * * @param trainParams The {@link TrainingParameters} to use. * @param reportMap The {@link Map} instance used as report map. */ void init(TrainingParameters trainParams, Map reportMap); /** * Conducts the initialization of a {@link Trainer} via * {@link TrainingParameters}, {@link Map report map} and {@link TrainingConfiguration} * * @param trainParams The {@link TrainingParameters} to use. * @param reportMap The {@link Map} instance used as report map. * @param config The {@link TrainingConfiguration} to use. If null, suitable defaults will be used. */ void init(TrainingParameters trainParams, Map reportMap, TrainingConfiguration config); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/commons/package-info.java0100644 0000000 0000000 00000001615 15217274217 032554 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to common interfaces used in different contexts. */ package opennlp.tools.commons; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/Dictionary.java0100644 0000000 0000000 00000022313 15217274217 033025 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.dictionary; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.util.AbstractSet; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import opennlp.tools.dictionary.serializer.Attributes; import opennlp.tools.dictionary.serializer.DictionaryEntryPersistor; import opennlp.tools.dictionary.serializer.Entry; import opennlp.tools.util.StringList; import opennlp.tools.util.model.DictionarySerializer; import opennlp.tools.util.model.SerializableArtifact; /** * An iterable and serializable dictionary implementation. * * @see SerializableArtifact * @see Iterable */ public class Dictionary implements Iterable, SerializableArtifact { private final Set entrySet = new HashSet<>(); private final boolean isCaseSensitive; private int minTokenCount = 99999; private int maxTokenCount = 0; /** * Initializes an empty {@link Dictionary}. * By default, the resulting instance will not be case-sensitive. */ public Dictionary() { this(false); } /** * Initializes an empty {@link Dictionary}. * * @param caseSensitive Whether the new instance will operate case-sensitive, or not. */ public Dictionary(boolean caseSensitive) { isCaseSensitive = caseSensitive; } /** * Initializes the {@link Dictionary} from an existing dictionary resource. * * @param in The {@link InputStream} that references the dictionary content. * * @throws IOException Thrown if IO errors occurred. */ public Dictionary(InputStream in) throws IOException { isCaseSensitive = DictionaryEntryPersistor.create(in, entry -> put(entry.tokens())); } /** * Adds the tokens to the dictionary as one new entry. * * @param tokens the new entry */ public void put(StringList tokens) { entrySet.add(applyCaseSensitivity(tokens)); minTokenCount = StrictMath.min(minTokenCount, tokens.size()); maxTokenCount = StrictMath.max(maxTokenCount, tokens.size()); } public int getMinTokenCount() { return minTokenCount; } public int getMaxTokenCount() { return maxTokenCount; } /** * Checks if this dictionary has the given entry. * * @param tokens The query of tokens to be checked for. * @return {@code true} if it contains the entry, {@code false} otherwise. */ public boolean contains(StringList tokens) { return entrySet.contains(applyCaseSensitivity(tokens)); } /** * Removes the given tokens form the current instance. * * @param tokens The tokens to be filtered out (= removed). */ public void remove(StringList tokens) { entrySet.remove(applyCaseSensitivity(tokens)); } /** * @return Retrieves a token-{@link Iterator} over all elements. */ @Override public Iterator iterator() { final Iterator entries = entrySet.iterator(); return new Iterator<>() { @Override public boolean hasNext() { return entries.hasNext(); } @Override public StringList next() { return entries.next(); } @Override public void remove() { entries.remove(); } }; } /** * @return Retrieves the number of tokens in the current instance. */ public int size() { return entrySet.size(); } /** * Writes the current instance to the given {@link OutputStream}. * * @param out A valid {@link OutputStream}, ready for serialization. * @throws IOException Thrown if IO errors occurred. */ public void serialize(OutputStream out) throws IOException { Iterator entryIterator = new Iterator<>() { private final Iterator dictionaryIterator = Dictionary.this.iterator(); @Override public boolean hasNext() { return dictionaryIterator.hasNext(); } @Override public Entry next() { StringList tokens = dictionaryIterator.next(); return new Entry(tokens, new Attributes()); } @Override public void remove() { throw new UnsupportedOperationException(); } }; DictionaryEntryPersistor.serialize(out, entryIterator, isCaseSensitive); } @Override public boolean equals(Object obj) { boolean result; if (obj == this) { result = true; } else if (obj instanceof Dictionary dictionary) { result = entrySet.equals(dictionary.entrySet); } else { result = false; } return result; } @Override public int hashCode() { return entrySet.hashCode(); } @Override public String toString() { return entrySet.toString(); } /** * Reads a {@link Dictionary} which has one entry per line. * The tokens inside an entry are whitespace delimited. * * @param in A {@link Reader} instance used to parse the dictionary from. * @return The parsed {@link Dictionary} instance; guaranteed to be non-{@code null}. * @throws IOException Thrown if IO errors occurred during read and parse operations. */ public static Dictionary parseOneEntryPerLine(Reader in) throws IOException { BufferedReader lineReader = new BufferedReader(in); final Dictionary dictionary = new Dictionary(); String line; while ((line = lineReader.readLine()) != null) { StringTokenizer whiteSpaceTokenizer = new StringTokenizer(line, " "); String[] tokens = new String[whiteSpaceTokenizer.countTokens()]; if (tokens.length > 0) { int tokenIndex = 0; while (whiteSpaceTokenizer.hasMoreTokens()) { tokens[tokenIndex++] = whiteSpaceTokenizer.nextToken(); } dictionary.put(new StringList(tokens)); } } return dictionary; } /** * Converts this {@link Dictionary} to a {@link Set}. *

* Note: Only {@link AbstractSet#iterator()}, {@link AbstractSet#size()} and * {@link AbstractSet#contains(Object)} methods are implemented. *

* If this dictionary entries are multi tokens only the first token of the * entry will be part of the {@link Set}. * * @return A {@link Set} containing all entries of this {@link Dictionary}. */ public Set asStringSet() { return new AbstractSet<>() { @Override public Iterator iterator() { final Iterator entries = entrySet.iterator(); return new Iterator<>() { @Override public boolean hasNext() { return entries.hasNext(); } @Override public String next() { return entries.next().getToken(0); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public int size() { return entrySet.size(); } @Override public boolean contains(Object obj) { boolean result = false; if (obj instanceof String str) { result = entrySet.contains(new StringList(isCaseSensitive, str)); } return result; } @Override public boolean equals(Object o) { if (! (o instanceof Set)) { return false; } Set toCheck = (Set) o; if (entrySet.size() != toCheck.size()) { return false; } Iterator toCheckIter = toCheck.iterator(); for (StringList entry : entrySet) { if (isCaseSensitive) { if (!entry.equals(new StringList(true, toCheckIter.next()))) { return false; } } else { if (!entry.compareToIgnoreCase(new StringList(false, toCheckIter.next()))) { return false; } } } return true; } @Override public int hashCode() { return entrySet.hashCode(); } }; } /** * @return Retrieves the serializer class for {@link Dictionary} * * @see DictionarySerializer */ @Override public Class getArtifactSerializerClass() { return DictionarySerializer.class; } /** * @return {@code true}, if this {@link Dictionary} is case-sensitive. */ public boolean isCaseSensitive() { return isCaseSensitive; } private StringList applyCaseSensitivity(StringList list) { if (isCaseSensitive) { return list.toCaseSensitive(); } else { return list.toCaseInsensitive(); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/Index.java0100644 0000000 0000000 00000003637 15217274217 031777 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.dictionary; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import opennlp.tools.util.StringList; /** * This classes indexes {@link StringList string lists}. This makes it possible * to check if a certain token is contained in at least one of the * {@link StringList}s. */ public class Index { private final Set tokens = new HashSet<>(); /** * Initializes an {@link Index} with the given {@link Iterator} * over {@link StringList} elements. * * @param tokenLists The iterable {@link StringList} elements. */ public Index(Iterator tokenLists) { while (tokenLists.hasNext()) { StringList tokens = tokenLists.next(); for (int i = 0; i < tokens.size(); i++) { this.tokens.add(tokens.getToken(i)); } } } /** * Checks if at least one {@link StringList} contains the specified {@code token}. * * @param token The element to check for. * * @return {@code true} if the token is contained, {@code false} otherwise. */ public boolean contains(String token) { return tokens.contains(token); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/package-info.java0100644 0000000 0000000 00000001604 15217274217 033244 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to parsing and storing dictionaries. */ package opennlp.tools.dictionary; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_dictionary_seria0100644 0000000 0000000 00000000163 15217274217 032571 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/Attributes.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/Attributes0100644 0000000 0000000 00000004263 15217274217 034303 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.dictionary.serializer; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Objects; /** * The {@link Attributes} class stores name value pairs. *

* Problem: If a {@link HashMap} is used storing name-value pairs this results * in a very high memory footprint, replace it. */ public class Attributes { private final Map mNameValueMap = new HashMap<>(); /** * Retrieves the value for the given key or {@code null} if attribute it not set. * * @param key The key to get the desired value for. * * @return The value for the given key or {@code null} */ public String getValue(String key) { return mNameValueMap.get(key); } /** * Sets a key/value pair. * * @param key The key that uniquely identifies the specified {@code value}. * Must not be {@code null}. * @param value The value that shall be retrievable via its {@code key}. * Must not be {@code null}. */ public void setValue(String key, String value) { Objects.requireNonNull(key, "key must not be null"); Objects.requireNonNull(value, "value must not be null"); mNameValueMap.put(key, value); } /** * Iterates over the keys. * * @return Retrieves a key-based {@link Iterator}. */ public Iterator iterator() { return mNameValueMap.keySet().iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_dictionary_seria0100644 0000000 0000000 00000000201 15217274217 032562 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/DictionaryEntryPersistor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/Dictionary0100644 0000000 0000000 00000022757 15217274217 034272 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.dictionary.serializer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.StringList; import opennlp.tools.util.XmlUtil; import opennlp.tools.util.model.UncloseableInputStream; /** * A persistor used by for reading and writing {@link Dictionary dictionaries} * of all kinds. * * @see Dictionary */ public class DictionaryEntryPersistor { // TODO: should check for invalid format, make it save private static class DictionaryContenthandler implements ContentHandler { private final EntryInserter mInserter; private boolean mIsInsideTokenElement; private boolean mIsCaseSensitiveDictionary; private final List mTokenList = new LinkedList<>(); private final StringBuilder token = new StringBuilder(); private Attributes mAttributes; private DictionaryContenthandler(EntryInserter inserter) { mInserter = inserter; mIsCaseSensitiveDictionary = true; } /** * Not implemented. */ @Override public void processingInstruction(String target, String data) throws SAXException { } /** * Not implemented. */ @Override public void startDocument() throws SAXException { } @Override public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes atts) throws SAXException { if (DICTIONARY_ELEMENT.equals(localName)) { mAttributes = new Attributes(); for (int i = 0; i < atts.getLength(); i++) { mAttributes.setValue(atts.getLocalName(i), atts.getValue(i)); } /* get the attribute here ... */ if (mAttributes.getValue(ATTRIBUTE_CASE_SENSITIVE) != null) { mIsCaseSensitiveDictionary = Boolean.parseBoolean(mAttributes.getValue(ATTRIBUTE_CASE_SENSITIVE)); } mAttributes = null; } else if (ENTRY_ELEMENT.equals(localName)) { mAttributes = new Attributes(); for (int i = 0; i < atts.getLength(); i++) { mAttributes.setValue(atts.getLocalName(i), atts.getValue(i)); } } else if (TOKEN_ELEMENT.equals(localName)) { mIsInsideTokenElement = true; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (mIsInsideTokenElement) { token.append(ch, start, length); } } /** * Creates the Profile object after processing is complete * and switches mIsInsideNgramElement flag. */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (TOKEN_ELEMENT.equals(localName)) { mTokenList.add(token.toString().trim()); token.setLength(0); mIsInsideTokenElement = false; } else if (ENTRY_ELEMENT.equals(localName)) { String[] tokens = mTokenList.toArray( new String[0]); Entry entry = new Entry(new StringList(tokens), mAttributes); try { mInserter.insert(entry); } catch (InvalidFormatException e) { throw new SAXException("Invalid dictionary format!", e); } mTokenList.clear(); mAttributes = null; } } /** * Not implemented. */ @Override public void endDocument() throws SAXException { } /** * Not implemented. */ @Override public void endPrefixMapping(String prefix) throws SAXException { } /** * Not implemented. */ @Override public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { } /** * Not implemented. */ @Override public void setDocumentLocator(Locator locator) { } /** * Not implemented. */ @Override public void skippedEntity(String name) throws SAXException { } /** * Not implemented. */ @Override public void startPrefixMapping(String prefix, String uri) throws SAXException { } } private static final String DICTIONARY_ELEMENT = "dictionary"; private static final String ENTRY_ELEMENT = "entry"; private static final String TOKEN_ELEMENT = "token"; private static final String ATTRIBUTE_CASE_SENSITIVE = "case_sensitive"; /** * Creates {@link Entry}s from the given {@link InputStream} and * forwards these {@link Entry}s to the {@link EntryInserter}. *

* Note: * After creation is finished the provided {@link InputStream} is closed. * * @param in The open {@link InputStream} to read entries from. * @param inserter inserter to forward entries to * * @return The {@code isCaseSensitive} attribute of a {@link Dictionary}. * * @throws IOException Thrown if IO errors occurred. * @throws InvalidFormatException Thrown if parameters were invalid. */ public static boolean create(InputStream in, EntryInserter inserter) throws IOException { DictionaryContenthandler handler = new DictionaryContenthandler(inserter); XMLReader xmlReader; try { xmlReader = XmlUtil.createSaxParser().getXMLReader(); xmlReader.setContentHandler(handler); xmlReader.parse(new InputSource(new UncloseableInputStream(in))); } catch (SAXException e) { throw new InvalidFormatException("The profile data stream has " + "an invalid format!", e); } return handler.mIsCaseSensitiveDictionary; } /** * Serializes the given entries to the given {@link OutputStream}. *

* Note: * After the serialization is finished the provided * {@link OutputStream} remains open. * * @param out The {@link OutputStream} to serialize to. * @param entries The {@link Entry entries} to serialize. * @param casesensitive Indicates if the written dictionary should be * case-sensitive, or not. * * @throws IOException Thrown if IO errors occurred. * @throws InvalidFormatException Thrown if parameters were invalid. */ public static void serialize(OutputStream out, Iterator entries, boolean casesensitive) throws IOException { StreamResult streamResult = new StreamResult(out); SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); TransformerHandler hd; try { hd = tf.newTransformerHandler(); } catch (TransformerConfigurationException e) { throw new InvalidFormatException("The Transformer configuration must be valid!"); } Transformer serializer = hd.getTransformer(); serializer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name()); serializer.setOutputProperty(OutputKeys.INDENT, "yes"); hd.setResult(streamResult); try { hd.startDocument(); AttributesImpl dictionaryAttributes = new AttributesImpl(); dictionaryAttributes.addAttribute("", "", ATTRIBUTE_CASE_SENSITIVE, "", String.valueOf(casesensitive)); hd.startElement("", "", DICTIONARY_ELEMENT, dictionaryAttributes); while (entries.hasNext()) { Entry entry = entries.next(); serializeEntry(hd, entry); } hd.endElement("", "", DICTIONARY_ELEMENT); hd.endDocument(); } catch (SAXException e) { throw new IOException("Error during serialization: " + e.getMessage(), e); } } private static void serializeEntry(TransformerHandler hd, Entry entry) throws SAXException { AttributesImpl entryAttributes = new AttributesImpl(); for (Iterator it = entry.attributes().iterator(); it.hasNext();) { String key = it.next(); entryAttributes.addAttribute("", "", key, "", entry.attributes().getValue(key)); } hd.startElement("", "", ENTRY_ELEMENT, entryAttributes); StringList tokens = entry.tokens(); for (String token : tokens) { hd.startElement("", "", TOKEN_ELEMENT, new AttributesImpl()); hd.characters(token.toCharArray(), 0, token.length()); hd.endElement("", "", TOKEN_ELEMENT); } hd.endElement("", "", ENTRY_ELEMENT); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_dictionary_seria0100644 0000000 0000000 00000000156 15217274217 032573 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/Entry.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/Entry.java0100644 0000000 0000000 00000002265 15217274217 034176 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.dictionary.serializer; import opennlp.tools.util.StringList; /** * An {@link Entry} is a {@link StringList} which can * optionally be mapped to attributes. *

* {@link Entry entries} are read and written by the {@link DictionaryEntryPersistor}. * * @see DictionaryEntryPersistor * @see Attributes */ public record Entry(StringList tokens, Attributes attributes) { } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_dictionary_seria0100644 0000000 0000000 00000000166 15217274217 032574 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/EntryInserter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/dictionary/serializer/EntryInser0100644 0000000 0000000 00000002207 15217274217 034253 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.dictionary.serializer; import opennlp.tools.util.InvalidFormatException; public interface EntryInserter { /** * @param entry The {@link Entry} to insert. * * @throws InvalidFormatException Thrown if the {@code entry} has an invalid format. */ void insert(Entry entry) throws InvalidFormatException; } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_BagOfWord0100644 0000000 0000000 00000000164 15217274217 032371 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/BagOfWordsFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/BagOfWordsFeatureGenerato0100644 0000000 0000000 00000004156 15217274217 034073 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.Objects; import opennlp.tools.util.featuregen.StringPattern; /** * Generates a feature for each word in a document. */ public class BagOfWordsFeatureGenerator implements FeatureGenerator { private final boolean useOnlyAllLetterTokens; /** * Instantiates a default {@link BagOfWordsFeatureGenerator} instance. */ public BagOfWordsFeatureGenerator() { this(false); } /** * Instantiates a {@link BagOfWordsFeatureGenerator} instance. * * @param useOnlyAllLetterTokens Whether to use only all-letter tokens, or not. */ BagOfWordsFeatureGenerator(boolean useOnlyAllLetterTokens) { this.useOnlyAllLetterTokens = useOnlyAllLetterTokens; } @Override public Collection extractFeatures(String[] text, Map extraInformation) { Objects.requireNonNull(text, "text must not be null"); Collection bagOfWords = new ArrayList<>(text.length); for (String word : text) { if (useOnlyAllLetterTokens) { StringPattern pattern = StringPattern.recognize(word); if (pattern.isAllLetter()) bagOfWords.add("bow=" + word); } else { bagOfWords.add("bow=" + word); } } return bagOfWords; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_DoccatCro0100644 0000000 0000000 00000000156 15217274217 032421 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DoccatCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DoccatCrossValidator.java0100644 0000000 0000000 00000006775 15217274217 034103 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.io.IOException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.Mean; /** * Cross validator for {@link DocumentCategorizer}. */ public class DoccatCrossValidator { private final String languageCode; private final TrainingParameters params; private final Mean documentAccuracy = new Mean(); private final DoccatEvaluationMonitor[] listeners; private final DoccatFactory factory; /** * Instantiates a {@link DoccatCrossValidator} with the * given {@link FeatureGenerator generators}. * * @param languageCode An ISO conform language code. * @param mlParams The {@link TrainingParameters} for the context of cross validation. * @param factory The {@link DoccatFactory} for creating related objects. * @param listeners the {@link DoccatEvaluationMonitor evaluation listeners}. */ public DoccatCrossValidator(String languageCode, TrainingParameters mlParams, DoccatFactory factory, DoccatEvaluationMonitor ... listeners) { this.languageCode = languageCode; this.params = mlParams; this.listeners = listeners; this.factory = factory; } /** * Starts the evaluation. * * @param samples The {@link ObjectStream} of {@link DocumentSample samples} to train and test with. * @param nFolds Number of folds. It must be greater than zero. * * @throws IOException Thrown if IO errors occurred. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>( samples, nFolds); while (partitioner.hasNext()) { CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner .next(); DoccatModel model = DocumentCategorizerME.train(languageCode, trainingSampleStream, params, factory); DocumentCategorizerEvaluator evaluator = new DocumentCategorizerEvaluator( new DocumentCategorizerME(model), listeners); evaluator.evaluate(trainingSampleStream.getTestSampleStream()); documentAccuracy.add(evaluator.getAccuracy(), evaluator.getDocumentCount()); } } /** * @return Retrieves the accuracy for all iterations. */ public double getDocumentAccuracy() { return documentAccuracy.mean(); } /** * @return Retrieves the number of words which where validated over all iterations. * The result is the amount of folds multiplied by the total number of words. */ public long getDocumentCount() { return documentAccuracy.count(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_DoccatEva0100644 0000000 0000000 00000000161 15217274217 032405 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DoccatEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DoccatEvaluationMonitor.j0100644 0000000 0000000 00000002041 15217274217 034111 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link DocumentCategorizer doccat}. */ public interface DoccatEvaluationMonitor extends EvaluationMonitor { } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DoccatFactory.java0100644 0000000 0000000 00000012156 15217274217 032541 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ext.ExtensionLoader; /** * The factory that provides Doccat default implementations and resources. */ public class DoccatFactory extends BaseToolFactory { private static final String FEATURE_GENERATORS = "doccat.featureGenerators"; private FeatureGenerator[] featureGenerators; /** * Instantiates a {@link DoccatFactory} that provides the default implementation of * the resources. */ public DoccatFactory() {} /** * Instantiates a {@link DoccatFactory} that provides the default implementation of * the resources. * * @param featureGenerators The {@link FeatureGenerator featureGenerators} to use. */ public DoccatFactory(final FeatureGenerator[] featureGenerators) { init(featureGenerators); } protected void init(FeatureGenerator[] featureGenerators) { this.featureGenerators = featureGenerators; } @Override public Map createManifestEntries() { Map manifestEntries = super.createManifestEntries(); if (getFeatureGenerators() != null) { manifestEntries.put(FEATURE_GENERATORS, featureGeneratorsAsString()); } return manifestEntries; } private String featureGeneratorsAsString() { List fgs = Arrays.asList(getFeatureGenerators()); Iterator iter = fgs.iterator(); StringBuilder sb = new StringBuilder(); if (iter.hasNext()) { sb.append(iter.next().getClass().getCanonicalName()); while (iter.hasNext()) { sb.append(',').append(iter.next().getClass().getCanonicalName()); } } return sb.toString(); } @Override public void validateArtifactMap() throws InvalidFormatException { // nothing to validate } /** * Factory method the framework uses create a new {@link DoccatFactory}. * * @param subclassName The name of the class implementing the {@link DoccatFactory}. * @param featureGenerators The {@link FeatureGenerator featureGenerators} to use. * * @return A valid {@link DoccatFactory} instance. * * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the factory associated with {@code subclassName}. */ public static DoccatFactory create(String subclassName, FeatureGenerator[] featureGenerators) throws InvalidFormatException { if (subclassName == null) { // will create the default factory return new DoccatFactory(featureGenerators); } try { DoccatFactory theFactory = ExtensionLoader.instantiateExtension( DoccatFactory.class, subclassName); theFactory.init(featureGenerators); return theFactory; } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } } private FeatureGenerator[] loadFeatureGenerators(String classNames) { String[] classes = classNames.split(","); FeatureGenerator[] fgs = new FeatureGenerator[classes.length]; for (int i = 0; i < classes.length; i++) { fgs[i] = ExtensionLoader.instantiateExtension(FeatureGenerator.class, classes[i]); } return fgs; } /** * @return Retrieves the {@link FeatureGenerator generators} used. */ public FeatureGenerator[] getFeatureGenerators() { if (featureGenerators == null) { if (artifactProvider != null) { String classNames = artifactProvider .getManifestProperty(FEATURE_GENERATORS); if (classNames != null) { this.featureGenerators = loadFeatureGenerators(classNames); } } if (featureGenerators == null) { // could not load using artifact provider // load bag of words as default this.featureGenerators = new FeatureGenerator[]{new BagOfWordsFeatureGenerator()}; } } return featureGenerators; } /** * @param featureGenerators The {@link FeatureGenerator featureGenerators} to use. */ public void setFeatureGenerators(FeatureGenerator[] featureGenerators) { this.featureGenerators = featureGenerators; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DoccatModel.java0100644 0000000 0000000 00000010256 15217274217 032171 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Serial; import java.net.URL; import java.nio.file.Path; import java.util.Map; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.BaseModel; /** * A model for document categorization */ public class DoccatModel extends BaseModel { @Serial private static final long serialVersionUID = -1348944493118276133L; private static final String COMPONENT_NAME = "DocumentCategorizerME"; private static final String DOCCAT_MODEL_ENTRY_NAME = "doccat.model"; /** * Initializes a {@link DoccatModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param doccatModel A valid {@link MaxentModel} to be used. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link DoccatFactory} to be used. */ public DoccatModel(String languageCode, MaxentModel doccatModel, Map manifestInfoEntries, DoccatFactory factory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, factory); artifactMap.put(DOCCAT_MODEL_ENTRY_NAME, doccatModel); checkArtifactMap(); } /** * Initializes a {@link DoccatModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public DoccatModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link DoccatModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public DoccatModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link DoccatModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public DoccatModel(Path modelPath) throws IOException { this(modelPath.toFile()); } /** * Initializes a {@link DoccatModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public DoccatModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(DOCCAT_MODEL_ENTRY_NAME) instanceof AbstractModel)) { throw new InvalidFormatException("Doccat model is incomplete!"); } } /** * @return Retrieves the active {@link DoccatFactory}. */ public DoccatFactory getFactory() { return (DoccatFactory) this.toolFactory; } @Override protected Class getDefaultFactory() { return DoccatFactory.class; } /** * @return Retrieves the active {@link MaxentModel}. */ public MaxentModel getMaxentModel() { return (MaxentModel) artifactMap.get(DOCCAT_MODEL_ENTRY_NAME); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizer.java0100644 0000000 0000000 00000006406 15217274217 033772 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.Map; import java.util.Set; import java.util.SortedMap; /** * Interface for classes which categorize documents. */ public interface DocumentCategorizer { /** * Categorizes the given {@code text} provided as tokens along with * the provided {@code extraInformation}. * * @param text The tokens of text to categorize. * @param extraInformation The extra information used for this context. * @return The per category probabilities. */ double[] categorize(String[] text, Map extraInformation); /** * Categorizes the given {@code text}, provided in separate tokens. * * @param text The tokens of text to categorize. * @return The per category probabilities. */ double[] categorize(String[] text); /** * Retrieves the best category from previously generated {@code outcome} probabilities * * @param outcome An array of computed outcome probabilities. * @return The best category represented as String. */ String getBestCategory(double[] outcome); /** * Retrieves the index of a certain category. * * @param category The category for which the {@code index} is to be found. * @return The index. */ int getIndex(String category); /** * Retrieves the category at a given {@code index}. * * @param index The index for which the {@code category} shall be found. * @return The category represented as String. */ String getCategory(int index); /** * Retrieves the number of categories. * * @return The no. of categories. */ int getNumberOfCategories(); /** * Retrieves the name of the category associated with the given probabilities. * * @param results The probabilities of each category. * @return The name of the outcome. */ String getAllResults(double[] results); /** * Retrieves a {@link Map} in which the key is the category name and the value is the score. * * @param text The tokenized input text to classify. * @return A {@link Map} with the score as a key. */ Map scoreMap(String[] text); /** * Retrieves a {@link SortedMap} of the scores sorted in ascending order, * together with their associated categories. *

* Many categories can have the same score, hence the {@link Set} as value. * * @param text the input text to classify * @return A {@link SortedMap} with the score as a key. */ SortedMap> sortedScoreMap(String[] text); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_DocumentC0100644 0000000 0000000 00000000175 15217274217 032442 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerContex0100644 0000000 0000000 00000003446 15217274217 034234 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.Collection; import java.util.LinkedList; import java.util.Map; /** * Context generator for {@link DocumentCategorizer}. * * @see DocumentCategorizer */ class DocumentCategorizerContextGenerator { private final FeatureGenerator[] mFeatureGenerators; /** * Instantiates a {@link DocumentCategorizerContextGenerator} instance. * * @param featureGenerators The {@link FeatureGenerator featureGenerators} to use. */ DocumentCategorizerContextGenerator(FeatureGenerator... featureGenerators) { mFeatureGenerators = featureGenerators; } public String[] getContext(String[] text, Map extraInformation) { Collection context = new LinkedList<>(); for (FeatureGenerator mFeatureGenerator : mFeatureGenerators) { Collection extractedFeatures = mFeatureGenerator.extractFeatures(text, extraInformation); context.addAll(extractedFeatures); } return context.toArray(new String[0]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_DocumentC0100644 0000000 0000000 00000000166 15217274217 032442 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerEvaluator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerEvalua0100644 0000000 0000000 00000006003 15217274217 034201 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.Mean; /** * The {@link DocumentCategorizerEvaluator} measures the performance of * the given {@link DocumentCategorizer} with the provided reference * {@link DocumentSample samples}. * * @see DocumentCategorizer * @see DocumentSample * @see Evaluator */ public class DocumentCategorizerEvaluator extends Evaluator { private final DocumentCategorizer categorizer; private final Mean accuracy = new Mean(); /** * Initializes a {@link DocumentCategorizerEvaluator} instance. * * @param categorizer the {@link DocumentCategorizer} instance. * @param listeners the {@link DoccatEvaluationMonitor evaluation listeners}. */ public DocumentCategorizerEvaluator(DocumentCategorizer categorizer, DoccatEvaluationMonitor ... listeners) { super(listeners); this.categorizer = categorizer; } /** * Evaluates the given reference {@link DocumentSample sample}. *

* This is done by categorizing the document from the provided * {@link DocumentSample}. The detected category is then used * to calculate and update the score. * * @param sample The reference {@link TokenSample}. * @return The processed {@link TokenSample}. */ public DocumentSample processSample(DocumentSample sample) { String[] document = sample.getText(); double[] probs = categorizer.categorize(document); String cat = categorizer.getBestCategory(probs); if (sample.getCategory().equals(cat)) { accuracy.add(1); } else { accuracy.add(0); } return new DocumentSample(cat, sample.getText()); } /** * {@code accuracy = correctly categorized documents / total documents} * * @return Retrieves the accuracy of provided {@link DocumentCategorizer}. */ public double getAccuracy() { return accuracy.mean(); } public long getDocumentCount() { return accuracy.count(); } /** * Represents this object as human-readable {@link String}. */ @Override public String toString() { return "Accuracy: " + accuracy.mean() + "\n" + "Number of documents: " + accuracy.count(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_DocumentC0100644 0000000 0000000 00000000170 15217274217 032435 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerEventS0100644 0000000 0000000 00000005274 15217274217 034201 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.Iterator; import opennlp.tools.ml.model.Event; import opennlp.tools.util.AbstractEventStream; import opennlp.tools.util.ObjectStream; /** * Iterator-like class for modeling document classification events. */ public class DocumentCategorizerEventStream extends AbstractEventStream { private final DocumentCategorizerContextGenerator mContextGenerator; /** * Initializes a {@link DocumentCategorizerEventStream} via samples and * {@link FeatureGenerator feature generators}. * * @param samples {@link ObjectStream} of {@link DocumentSample samples}. * @param featureGenerators One or more {@link FeatureGenerator} to use. */ public DocumentCategorizerEventStream(ObjectStream samples, FeatureGenerator... featureGenerators) { super(samples); mContextGenerator = new DocumentCategorizerContextGenerator(featureGenerators); } /** * Initializes a {@link DocumentCategorizerEventStream} via samples. * {@link BagOfWordsFeatureGenerator} is used as feature generator. * * @param samples {@link ObjectStream} of {@link DocumentSample samples}. */ public DocumentCategorizerEventStream(ObjectStream samples) { super(samples); mContextGenerator = new DocumentCategorizerContextGenerator(new BagOfWordsFeatureGenerator()); } @Override protected Iterator createEvents(final DocumentSample sample) { return new Iterator<>() { private boolean isVirgin = true; @Override public boolean hasNext() { return isVirgin; } @Override public Event next() { isVirgin = false; return new Event(sample.getCategory(), mContextGenerator.getContext(sample.getText(), sample.getExtraInformation())); } public void remove() { throw new UnsupportedOperationException(); } }; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_DocumentC0100644 0000000 0000000 00000000157 15217274217 032442 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentCategorizerME.jav0100644 0000000 0000000 00000012211 15217274217 034042 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; /** * A Max-Ent based implementation of {@link DocumentCategorizer}. */ public class DocumentCategorizerME implements DocumentCategorizer { private final DoccatModel model; private final DocumentCategorizerContextGenerator mContextGenerator; /** * Initializes a {@link DocumentCategorizerME} instance with a doccat model. * Default feature generation is used. * * @param model the {@link DoccatModel} to be used for categorization. */ public DocumentCategorizerME(DoccatModel model) { this.model = model; this.mContextGenerator = new DocumentCategorizerContextGenerator(this.model .getFactory().getFeatureGenerators()); } /** * Categorize the given {@code text} provided as tokens along with * the provided extra information. * * @param text The text tokens to categorize. * @param extraInformation Additional information for context to be used by the feature generator. * @return The per category probabilities. */ @Override public double[] categorize(String[] text, Map extraInformation) { return model.getMaxentModel().eval( mContextGenerator.getContext(text, extraInformation)); } @Override public double[] categorize(String[] text) { return this.categorize(text, Collections.emptyMap()); } @Override public Map scoreMap(String[] text) { Map probDist = new HashMap<>(); double[] categorize = categorize(text); int catSize = getNumberOfCategories(); for (int i = 0; i < catSize; i++) { String category = getCategory(i); probDist.put(category, categorize[getIndex(category)]); } return probDist; } @Override public SortedMap> sortedScoreMap(String[] text) { SortedMap> descendingMap = new TreeMap<>(); double[] categorize = categorize(text); int catSize = getNumberOfCategories(); for (int i = 0; i < catSize; i++) { String category = getCategory(i); double score = categorize[getIndex(category)]; if (descendingMap.containsKey(score)) { descendingMap.get(score).add(category); } else { Set newset = new HashSet<>(); newset.add(category); descendingMap.put(score, newset); } } return descendingMap; } @Override public String getBestCategory(double[] outcome) { return model.getMaxentModel().getBestOutcome(outcome); } @Override public int getIndex(String category) { return model.getMaxentModel().getIndex(category); } @Override public String getCategory(int index) { return model.getMaxentModel().getOutcome(index); } @Override public int getNumberOfCategories() { return model.getMaxentModel().getNumOutcomes(); } @Override public String getAllResults(double[] results) { return model.getMaxentModel().getAllOutcomes(results); } /** * Starts a training of a {@link DoccatModel} with the given parameters. * * @param lang The ISO conform language code. * @param samples The {@link ObjectStream} of {@link DocumentSample} used as input for training. * @param mlParams The {@link TrainingParameters} for the context of the training. * @param factory The {@link DoccatFactory} for creating related objects defined via {@code mlParams}. * * @return A valid, trained {@link DoccatModel} instance. * @throws IOException Thrown if IO errors occurred. */ public static DoccatModel train(String lang, ObjectStream samples, TrainingParameters mlParams, DoccatFactory factory) throws IOException { Map manifestInfoEntries = new HashMap<>(); EventTrainer trainer = TrainerFactory.getEventTrainer( mlParams, manifestInfoEntries); MaxentModel model = trainer.train( new DocumentCategorizerEventStream(samples, factory.getFeatureGenerators())); return new DoccatModel(lang, model, manifestInfoEntries, factory); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentSample.java0100644 0000000 0000000 00000006602 15217274217 032733 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import opennlp.tools.commons.Sample; /** * Class which holds a classified document and its category. */ public class DocumentSample implements Sample { private static final long serialVersionUID = -1775688015002177141L; private final String category; private final List text; private final Map extraInformation; /** * Initializes a {@link DocumentSample instance}. * * @param category The category to be used. Must not be {@code null}. * @param text The plain text in a tokenized form. Must not be {@code null}. */ public DocumentSample(String category, String[] text) { this(category, text, null); } /** * Initializes a {@link DocumentSample instance}. * * @param category The category to be used.Must not be {@code null}. * @param text The plain text in a tokenized form. Must not be {@code null}. * @param extraInformation Additional information for context. */ public DocumentSample(String category, String[] text, Map extraInformation) { Objects.requireNonNull(text, "text must not be null"); this.category = Objects.requireNonNull(category, "category must not be null"); this.text = List.of(text); this.extraInformation = Objects.requireNonNullElse(extraInformation, Collections.emptyMap()); } /** * @return Retrieves the category. */ public String getCategory() { return category; } /** * @return Retrieves the text in a tokenized form. */ public String[] getText() { return text.toArray(new String[0]); } /** * @return Retrieves contextual extra information. */ public Map getExtraInformation() { return extraInformation; } @Override public String toString() { StringBuilder sampleString = new StringBuilder(); sampleString.append(category).append('\t'); for (String s : text) { sampleString.append(s).append(' '); } if (sampleString.length() > 0) { // remove last space sampleString.setLength(sampleString.length() - 1); } return sampleString.toString(); } @Override public int hashCode() { return Objects.hash(getCategory(), Arrays.hashCode(getText())); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof DocumentSample a) { return getCategory().equals(a.getCategory()) && Arrays.equals(getText(), a.getText()); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_DocumentS0100644 0000000 0000000 00000000156 15217274217 032461 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/DocumentSampleStream.java0100644 0000000 0000000 00000004647 15217274217 034116 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.io.IOException; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Reads in string encoded training samples, parses them and * outputs {@link DocumentSample} objects. *

* Format:
* Each line contains one sample document.
* The category is the first string in the line followed by a tab and whitespace * separated document tokens. *

* Sample line: * {@code category-string tab-char whitespace-separated-tokens line-break-char(s)} * * @see DocumentSample */ public class DocumentSampleStream extends FilterObjectStream { /** * Initializes a {@link DocumentSampleStream instance}. * * @param samples A plain text {@link ObjectStream line stream}. */ public DocumentSampleStream(ObjectStream samples) { super(samples); } @Override public DocumentSample read() throws IOException { String sampleString = samples.read(); if (sampleString != null) { // Whitespace tokenize entire string String[] tokens = WhitespaceTokenizer.INSTANCE.tokenize(sampleString); DocumentSample sample; if (tokens.length > 1) { String category = tokens[0]; String[] docTokens = new String[tokens.length - 1]; System.arraycopy(tokens, 1, docTokens, 0, tokens.length - 1); sample = new DocumentSample(category, docTokens); } else { throw new IOException("Empty lines, or lines with only a category string are not allowed!"); } return sample; } return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/FeatureGenerator.java0100644 0000000 0000000 00000002541 15217274217 033253 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.Collection; import java.util.Map; /** * Interface for generating features for document categorization. */ public interface FeatureGenerator { /** * Extracts features from given {@code text} fragments. * * @param text The text fragments to extract features from * @param extraInformation Optional extra information to be used by the {@link FeatureGenerator}. * @return A collection of features. */ Collection extractFeatures(String[] text, Map extraInformation); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_doccat_NGramFeat0100644 0000000 0000000 00000000157 15217274217 032365 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/NGramFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/NGramFeatureGenerator.jav0100644 0000000 0000000 00000005745 15217274217 034050 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.doccat; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import opennlp.tools.util.InvalidFormatException; /** * Generates ngram features for a document. * * @see FeatureGenerator */ public class NGramFeatureGenerator implements FeatureGenerator { private final int minGram; private final int maxGram; /** * Instantiates an {@link NGramFeatureGenerator} instance with configurable ngram parameters. * * @param minGram The minimum words in ngram features. * @param maxGram The maximum words in ngram features. * @throws InvalidFormatException Thrown if parameter values are invalid or inconsistent. */ public NGramFeatureGenerator(int minGram, int maxGram) throws InvalidFormatException { if (minGram > 0 && maxGram > 0) { if (minGram <= maxGram) { this.minGram = minGram; this.maxGram = maxGram; } else { throw new InvalidFormatException( "Minimum range value (minGram) should be less than or equal to maximum range value (maxGram)!"); } } else { throw new InvalidFormatException("Both minimum range value (minGram) & maximum " + "range value (maxGram) should be greater than or equal to 1!"); } } /** * Instantiates an {@link NGramFeatureGenerator} instance with a Bi grams config. * * @throws InvalidFormatException Thrown if parameter values are invalid or inconsistent. */ public NGramFeatureGenerator() throws InvalidFormatException { this(2, 2); } @Override public Collection extractFeatures(String[] text, Map extraInfo) { Objects.requireNonNull(text, "text must not be null"); List features = new ArrayList<>(); for (int i = 0; i <= text.length - minGram; i++) { final StringBuilder sb = new StringBuilder(); sb.append("ng="); for (int y = 0; y < maxGram && i + y < text.length; y++) { sb.append(":"); sb.append(text[i + y]); int gramCount = y + 1; if (maxGram >= gramCount && gramCount >= minGram) { features.add(sb.toString()); } } } return features; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/doccat/package-info.java0100644 0000000 0000000 00000001577 15217274217 032345 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package for classifying a document into a category. */ package opennlp.tools.doccat; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/BaseLink.java0100644 0000000 0000000 00000006672 15217274217 032776 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.entitylinker; import java.util.HashMap; import java.util.Map; import java.util.Objects; /** * Represents a minimal tuple of information. * Intended to be used with {@link LinkedSpan}. * * @see EntityLinker * @see LinkedSpan */ public abstract class BaseLink { private String itemParentID; private String itemID; private String itemName; private String itemType; private Map scoreMap = new HashMap<>(); public BaseLink(String itemParentID, String itemID, String itemName, String itemType) { this.itemParentID = itemParentID; this.itemID = itemID; this.itemName = itemName; this.itemType = itemType; } public String getItemParentID() { return itemParentID; } /** * @param itemParentID The parent ID of the linked item */ public void setItemParentID(String itemParentID) { this.itemParentID = itemParentID; } public String getItemID() { return itemID; } /** * @param itemID This field can store, for example, the primary key of * a now in an external/linked data source. */ public void setItemID(String itemID) { this.itemID = itemID; } public String getItemName() { return itemName; } /** * @param itemName An item name can be the native name (often a normalized * version of something) from an external linked data source. */ public void setItemName(String itemName) { this.itemName = itemName; } public String getItemType() { return itemType; } /** * * @param itemType An item type can be the native type from an external * linked database. For instance, a product type or code. */ public void setItemType(String itemType) { this.itemType = itemType; } public Map getScoreMap() { return scoreMap; } public void setScoreMap(Map scoreMap) { this.scoreMap = scoreMap; } @Override public String toString() { return "\tBaseLink" + "\n\titemParentID=" + itemParentID + ", \n\titemID=" + itemID + ", \n\titemName=" + itemName + ", \n\titemType=" + itemType + ", \n\tscoreMap=" + scoreMap + "\n"; } @Override public int hashCode() { return Objects.hash(itemParentID, itemID, itemName, itemType); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof BaseLink other) { return Objects.equals(itemParentID, other.itemParentID) && Objects.equals(itemID, other.itemID) && Objects.equals(itemName, other.itemName) && Objects.equals(itemType, other.itemType); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/EntityLinker.java0100644 0000000 0000000 00000012003 15217274217 033710 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.entitylinker; import java.io.IOException; import java.util.List; import opennlp.tools.util.Span; /** * EntityLinkers establish connections with external data to enrich extracted * entities. *

* For instance, for Location entities a linker can be developed to * look up each found location in a geonames gazetteer. Another example may be to * find peoples' names and look them up in a database or active directory. * Intended to return n best matches for any given search, but can also be * implemented as deterministic. * * @param A type that extends {@link Span}. {@link LinkedSpan} and {@link BaseLink} * are available to provide this signature. Use: * {@link EntityLinker}<LinkedSpan<BaseLink>> as a default. */ public interface EntityLinker { /** * Initializes an {@link EntityLinker} and allows for passing properties * through the {@link EntityLinkerFactory} into all impls dynamically. *

* {@link EntityLinker} impls should initialize reusable objects * used by the impl in this method. If this is done, any errors will be * captured and thrown by the {@link EntityLinkerFactory}. * * @param initializationData The {@link EntityLinkerProperties} that contains * properties needed by the impl, as well as any * other objects required. * @throws IOException Thrown if IO errors occurred. */ void init(EntityLinkerProperties initializationData) throws IOException; /** * Links an entire document of named entities to an external source. * * @param doctext The full text of the document. * @param sentences An array of {@link Span sentence spans}. * @param tokensBySentence An array of {@link Span tokens spans} that correspond to * each sentence. The outer array refers to the sentence, the inner * array is the tokens for the outer sentence. Similar * in nature to Map of SentenceIndex keys to List of * tokens as values. * @param namesBySentence An array of {@link Span name spans} that correspond to each * sentence. The outer array refers to the sentence, * the inner array refers to the tokens that for the * same sentence. Similar in nature to * Map<SentenceIndex,List<Name Spans For This * Sentence's Tokens>> @ return. * * @return A list of {@link T} instances. */ List find(String doctext, Span[] sentences, Span[][] tokensBySentence, Span[][] namesBySentence); /** * Links the names that correspond to the tokens[] spans. The {@code sentenceIndex} * can be used to get the sentence text and tokens from the text based on the * sentence and token spans. The text is available for additional context. * * @param doctext The full text of the document. * @param sentences An array of {@link Span sentence spans}. * @param tokensBySentence An array of {@link Span tokens spans} that correspond to each * sentence. The outer array refers to the sentence, the inner * array is the tokens for the outer sentence. Similar * in nature to Map of SentenceIndex keys to List of * tokens as values. * @param namesBySentence An array of {@link Span name spans} that correspond to each * sentence. The outer array refers to the sentence, * the inner array refers to the tokens that for the * same sentence. Similar in nature to * Map<SentenceIndex,List<Name Spans For This * Sentence's Tokens>> @ return. * @param sentenceIndex The index to the sentence span that the {@code tokensBySentence} * corresponds to. * * @return A list of {@link T} instances. */ List find(String doctext, Span[] sentences, Span[][] tokensBySentence, Span[][] namesBySentence, int sentenceIndex); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_entitylinker_Ent0100644 0000000 0000000 00000000163 15217274217 032570 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/EntityLinkerFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/EntityLinkerFactory0100644 0000000 0000000 00000010073 15217274217 034325 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.entitylinker; import java.io.IOException; import java.util.Objects; import opennlp.tools.util.ext.ExtensionLoader; /** * Generates a {@link EntityLinker} instances via a {@code properties} file configuration. *

* In the properties file, the linker implementation must be * provided using {@code "linker"} as the properties key, and the * full class name as value. */ public class EntityLinkerFactory { /** * Retrieves a {@link EntityLinker} instance matching the {@code properties} configuration. * * @param entityType The type of entity being linked to. This value is used to * retrieve the implementation of the {@link EntityLinker} from the * {@link EntityLinker} properties file. * Must not be {@code null}. * @param properties An object that extends {@link EntityLinkerProperties}. * This object will be passed into the * {@link EntityLinker#init(EntityLinkerProperties)} method, * so it is an appropriate place to put additional resources. * Must not be {@code null}. * * @return The {@link EntityLinker} instance for the {@code properties} configuration. * @throws IOException Thrown if IO errors occurred. * @throws IllegalArgumentException Thrown if parameters were invalid. */ public static synchronized EntityLinker getLinker(String entityType, EntityLinkerProperties properties) throws IOException { if (entityType == null || properties == null) { throw new IllegalArgumentException("Null argument in entityLinkerFactory"); } String linkerImplFullName = properties.getProperty("linker." + entityType, ""); if (linkerImplFullName == null || linkerImplFullName.isEmpty()) { throw new IllegalArgumentException("linker." + entityType + " property must be set!"); } EntityLinker linker = ExtensionLoader.instantiateExtension(EntityLinker.class, linkerImplFullName); linker.init(properties); return linker; } /** * Retrieves a {@link EntityLinker} instance matching the {@code properties} configuration. * * @param properties An object that extends {@link EntityLinkerProperties}. * This object will be passed into the * {@link EntityLinker#init(EntityLinkerProperties)} method, * so it is an appropriate place to put additional resources. * Must not be {@code null}. * * @return The {@link EntityLinker} instance for the {@code properties} configuration. * @throws IOException Thrown if IO errors occurred. * @throws IllegalArgumentException Thrown if parameters were invalid. */ public static synchronized EntityLinker getLinker(EntityLinkerProperties properties) throws IOException { Objects.requireNonNull(properties, "properties argument must not be null"); String linkerImplFullName = properties.getProperty("linker", ""); if (linkerImplFullName == null || linkerImplFullName.isEmpty()) { throw new IllegalArgumentException("\"linker\" property must be set!"); } EntityLinker linker = ExtensionLoader.instantiateExtension(EntityLinker.class, linkerImplFullName); linker.init(properties); return linker; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_entitylinker_Ent0100644 0000000 0000000 00000000166 15217274217 032573 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/EntityLinkerProperties.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/EntityLinkerPropert0100644 0000000 0000000 00000005557 15217274217 034364 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.entitylinker; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * Properties wrapper for {@link EntityLinker} implementations. * * @see EntityLinkerFactory */ public class EntityLinkerProperties { private Properties props; /** * Initializes {@link EntityLinkerProperties} via a {@link File} reference. * * @param propertiesFile The {@link File} that references the {@code *.properties} * configuration. * * @throws IOException Thrown if IO errors occurred. */ public EntityLinkerProperties(File propertiesFile) throws IOException { try (InputStream stream = new BufferedInputStream(new FileInputStream(propertiesFile))) { init(stream); } } /** * Initializes {@link EntityLinkerProperties} via a {@link InputStream} reference. * * @param propertiesIn The {@link InputStream} that references the {@code *.properties} * configuration. * * @throws IOException Thrown if IO errors occurred. */ public EntityLinkerProperties(InputStream propertiesIn) throws IOException { init(propertiesIn); } private void init(InputStream propertiesIn) throws IOException { props = new Properties(); props.load(propertiesIn); } /** * Retrieves a property value for a given {@code key}. * * @param key The key to the desired item in the properties configuration * {@code key=value} * @param defaultValue A default value in case the {@code key}, or the value are * missing * @return A property value as a {@link String}. * @throws IOException Thrown if the properties object was not initialized properly. */ public String getProperty(String key, String defaultValue) throws IOException { if (props != null) { return props.getProperty(key, defaultValue); } else { throw new IOException("EntityLinkerProperties was not successfully initialized"); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/LinkedSpan.java0100644 0000000 0000000 00000014344 15217274217 033331 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.entitylinker; import java.io.Serial; import java.util.ArrayList; import java.util.Objects; import opennlp.tools.util.Span; /** * A default, extended {@link Span} that holds additional information about a {@link Span}. * * @param The generic type that specializes a {@link BaseLink}. */ public class LinkedSpan extends Span { @Serial private static final long serialVersionUID = 2089863052379334449L; private ArrayList linkedEntries; private int sentenceid = 0; private String searchTerm; /** * Initializes a new {@link LinkedSpan}. Sets the prob to {@code 0} as default. * * @param linkedEntries The {@code n} best linked entries from * an external data source. * @param s The start position of a {@link Span}. * Must be equal to or greater than {@code 0}. * Must not be greater than {@code e}. * @param e The end position of a {@link Span}, which is {@code +1} * more than the last element in the span. * Must be equal to or greater than {@code 0}. * @param type The type of the span. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public LinkedSpan(ArrayList linkedEntries, int s, int e, String type) { this(linkedEntries, s, e, type, 0d); } /** * Initializes a new {@link LinkedSpan}. * * @param linkedEntries The {@code n} best linked entries from * an external data source. * @param s The start position of a {@link Span}. * Must be equal to or greater than {@code 0}. * Must not be greater than {@code e}. * @param e The end position of a {@link Span}, which is {@code +1} * more than the last element in the span. * Must be equal to or greater than {@code 0}. * @param type The type of the span. * @param prob The probability of the {@link Span}. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public LinkedSpan(ArrayList linkedEntries, int s, int e, String type, double prob) { super(s, e, type, prob); this.linkedEntries = linkedEntries; } /** * Initializes a new {@link LinkedSpan}. * * @param linkedEntries The {@code n} best linked entries from * an external data source. * @param s The start position of a {@link Span}. * Must be equal to or greater than {@code 0}. * Must not be greater than {@code e}. * @param e The end position of a {@link Span}, which is {@code +1} * more than the last element in the span. * Must be equal to or greater than {@code 0}. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public LinkedSpan(ArrayList linkedEntries, int s, int e) { super(s, e); this.linkedEntries = linkedEntries; } /** * Initializes a new {@link LinkedSpan} via an existing {@link Span} * which is shifted by the specified {@code offset}. * * @param linkedEntries The {@code n} best linked entries from * an external data source. * @param span The existing {@link Span}. * @param offset The positive or negative shift offset. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public LinkedSpan(ArrayList linkedEntries, Span span, int offset) { super(span, offset); this.linkedEntries = linkedEntries; } /** * @return Retrieves the {@code n} best linked entries from an external data source. * For instance, this will hold gazetteer entries for a search into a geonames * gazetteer. */ public ArrayList getLinkedEntries() { return linkedEntries; } /** * @param linkedEntries The {@code n} best linked entries from an external data source. * For instance, this will hold gazetteer entries for a search * into a geonames gazetteer. */ public void setLinkedEntries(ArrayList linkedEntries) { this.linkedEntries = linkedEntries; } /** * @return Retrieves the id or index of the sentence from which this span was extracted. */ public int getSentenceid() { return sentenceid; } /** * @param sentenceid The id or index of the sentence from which this span was extracted. */ public void setSentenceid(int sentenceid) { this.sentenceid = sentenceid; } /** * @return Retrieves the search term that was used to link this span to an external data * source. */ public String getSearchTerm() { return searchTerm; } /** * @param searchTerm The search term that is used to link this span to an external data * source. */ public void setSearchTerm(String searchTerm) { this.searchTerm = searchTerm; } @Override public String toString() { return "LinkedSpan\nsentenceid=" + sentenceid + "\nsearchTerm=" + searchTerm + "\nlinkedEntries=\n" + linkedEntries + "\n"; } @Override public int hashCode() { return Objects.hash(linkedEntries, sentenceid, searchTerm); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (obj instanceof LinkedSpan other) { return Objects.equals(this.linkedEntries, other.linkedEntries) && this.sentenceid == other.sentenceid && Objects.equals(this.searchTerm, other.searchTerm); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/entitylinker/package-info.java0100644 0000000 0000000 00000001617 15217274217 033624 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to linking entities to external data sources. */ package opennlp.tools.entitylinker; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Abstract0100644 0000000 0000000 00000000166 15217274217 032542 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/AbstractSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/AbstractSampleStreamFact0100644 0000000 0000000 00000006216 15217274217 034171 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.ObjectStreamFactory; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; /** * Base class for sample stream factories. */ public abstract class AbstractSampleStreamFactory implements ObjectStreamFactory { protected Class

params; private AbstractSampleStreamFactory() { } protected AbstractSampleStreamFactory(Class

params) { this.params = params; } public String getLang() { return "eng"; } public Class

getParameters() { return params; } /** * Creates an {@link ObjectStream} for the specified arguments and * the generic type {@code P}. * * @param args A set of command line arguments. * @return The created {@link ObjectStream} instance. */ protected

ObjectStream readData(String[] args, Class

parametersClass) { P params = validateBasicFormatParameters(args, parametersClass); ObjectStream lineStream = null; try { InputStreamFactory sampleDataIn = CmdLineUtil.createInputStreamFactory(params.getData()); lineStream = new PlainTextByLineStream(sampleDataIn, params.getEncoding()); } catch (IOException ex) { CmdLineUtil.handleCreateObjectStreamError(ex); } return lineStream; } /** * Validates the specified arguments ({@code args}) given the * context the generic type {@code P} which provides at least all * {@link BasicFormatParams}. * * @implNote Additional checks for the basic {@code -data} argument are conducted, that is * wether the file exists or not. * * @param args A set of command line arguments. * @return The parsed (basic format) parameter instance. */ protected

P validateBasicFormatParameters(String[] args, Class

clazz) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } P params = ArgumentParser.parse(args, clazz); CmdLineUtil.checkInputFile("Data", params.getData()); return params; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_BioNLP200100644 0000000 0000000 00000000165 15217274217 032223 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/BioNLP2004NameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/BioNLP2004NameSampleStre0100644 0000000 0000000 00000014031 15217274217 033476 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import opennlp.tools.commons.Internal; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; import opennlp.tools.util.StringUtil; /** * A {@link ObjectStream sample stream} for the training files of the * BioNLP/NLPBA 2004 shared task. *

* The data contains five named entity types: *

    *
  • {@code DNA}
  • *
  • {@code RNA}
  • *
  • {@code protein}
  • *
  • {@code cell_type}
  • *
  • {@code cell_line}
  • *
*

* Data can be found on this * website, * or in this * GitHub repository. *

* The BioNLP/NLPBA 2004 data were originally published * here, *

* yet this page was gone when last checked in December 2022. *

* Note: * Do not use this class, internal use only! */ @Internal public class BioNLP2004NameSampleStream implements ObjectStream { private static final String CODEC_TAG_O = "O"; private static final String CODEC_TAG_B = "B-"; private static final String CODEC_TAG_I = "I-"; public static final int GENERATE_DNA_ENTITIES = 0x01; public static final int GENERATE_PROTEIN_ENTITIES = 0x01 << 1; public static final int GENERATE_CELLTYPE_ENTITIES = 0x01 << 2; public static final int GENERATE_CELLLINE_ENTITIES = 0x01 << 3; public static final int GENERATE_RNA_ENTITIES = 0x01 << 4; private final int types; private final ObjectStream lineStream; /** * Initializes a {@link BioNLP2004NameSampleStream}. * * @param in The {@link InputStreamFactory} to use. * @param types The types to use. * * @throws IOException Thrown if IO errors occurred during initialization. */ public BioNLP2004NameSampleStream(InputStreamFactory in, int types) throws IOException { this.lineStream = new PlainTextByLineStream(in, StandardCharsets.UTF_8); this.types = types; } @Override public NameSample read() throws IOException { List sentence = new ArrayList<>(); List tags = new ArrayList<>(); boolean isClearAdaptiveData = false; // Empty line indicates end of sentence String line; while ((line = lineStream.read()) != null && !StringUtil.isEmpty(line.trim())) { if (line.startsWith("###MEDLINE:")) { isClearAdaptiveData = true; lineStream.read(); continue; } if (line.contains("ABSTRACT TRUNCATED")) continue; String[] fields = line.split("\t"); if (fields.length == 2) { sentence.add(fields[0]); tags.add(fields[1]); } else { throw new IOException("Expected two fields per line in training data, got " + fields.length + " for line '" + line + "'!"); } } if (!sentence.isEmpty()) { // convert name tags into spans List names = new ArrayList<>(); int beginIndex = -1; int endIndex = -1; for (int i = 0; i < tags.size(); i++) { String tag = tags.get(i); if (tag.endsWith("DNA") && (types & GENERATE_DNA_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.endsWith("protein") && (types & GENERATE_PROTEIN_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.endsWith("cell_type") && (types & GENERATE_CELLTYPE_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.endsWith("cell_line") && (types & GENERATE_CELLTYPE_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.endsWith("RNA") && (types & GENERATE_RNA_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.startsWith(CODEC_TAG_B)) { if (beginIndex != -1) { names.add(new Span(beginIndex, endIndex, tags.get(beginIndex).substring(2))); } beginIndex = i; endIndex = i + 1; } else if (tag.startsWith(CODEC_TAG_I)) { endIndex++; } else if (tag.equals(CODEC_TAG_O)) { if (beginIndex != -1) { names.add(new Span(beginIndex, endIndex, tags.get(beginIndex).substring(2))); beginIndex = -1; endIndex = -1; } } else { throw new IOException("Invalid tag: " + tag); } } // if one span remains, create it here if (beginIndex != -1) names.add(new Span(beginIndex, endIndex, tags.get(beginIndex).substring(2))); return new NameSample(sentence.toArray(new String[0]), names.toArray(new Span[0]), isClearAdaptiveData); } else if (line != null) { // Just filter out empty events, if two lines in a row are empty return read(); } else { // source stream is not returning anymore lines return null; } } @Override public void reset() throws IOException, UnsupportedOperationException { lineStream.reset(); } @Override public void close() throws IOException { lineStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_BioNLP200100644 0000000 0000000 00000000174 15217274217 032223 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/BioNLP2004NameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/BioNLP2004NameSampleStre0100644 0000000 0000000 00000005700 15217274217 033501 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; /** * @see BioNLP2004NameSampleStream */ public class BioNLP2004NameSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ParameterDescription(valueName = "DNA,protein,cell_type,cell_line,RNA") String getTypes(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "bionlp2004", new BioNLP2004NameSampleStreamFactory(Parameters.class)); } protected BioNLP2004NameSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); int typesToGenerate = 0; String types = params.getTypes(); if (types.contains("DNA")) { typesToGenerate = typesToGenerate | BioNLP2004NameSampleStream.GENERATE_DNA_ENTITIES; } if (types.contains("protein")) { typesToGenerate = typesToGenerate | BioNLP2004NameSampleStream.GENERATE_PROTEIN_ENTITIES; } if (types.contains("cell_type")) { typesToGenerate = typesToGenerate | BioNLP2004NameSampleStream.GENERATE_CELLTYPE_ENTITIES; } if (types.contains("cell_line")) { typesToGenerate = typesToGenerate | BioNLP2004NameSampleStream.GENERATE_CELLLINE_ENTITIES; } if (types.contains("RNA")) { typesToGenerate = typesToGenerate | BioNLP2004NameSampleStream.GENERATE_RNA_ENTITIES; } try { return new BioNLP2004NameSampleStream( CmdLineUtil.createInputStreamFactory(params.getData()), typesToGenerate); } catch (IOException ex) { CmdLineUtil.handleCreateObjectStreamError(ex); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ChunkerS0100644 0000000 0000000 00000000165 15217274217 032520 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ChunkerSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ChunkerSampleStreamFacto0100644 0000000 0000000 00000003451 15217274217 034202 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.chunker.ChunkSampleStream; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link ChunkSampleStream}s. */ public class ChunkerSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(ChunkSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new ChunkerSampleStreamFactory(Parameters.class)); } protected ChunkerSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new ChunkSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Conll02N0100644 0000000 0000000 00000000162 15217274217 032322 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll02NameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll02NameSampleStream.0100644 0000000 0000000 00000016460 15217274217 033722 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import opennlp.tools.commons.Internal; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; import opennlp.tools.util.StringUtil; /** * Parser for the Dutch and Spanish ner training files of the CONLL 2002 shared task. *

* The Dutch data has a {@link #DOCSTART} tag to mark article boundaries, * adaptive data in the feature generators will be cleared before every article.
* The Spanish data does not contain article boundaries, * adaptive data will be cleared for every sentence. *

* The data contains four named entity types: Person, Organization, Location and Misc.
*

* Data can be found on this * web site. *

* Note: * Do not use this class, internal use only! */ @Internal public class Conll02NameSampleStream implements ObjectStream { public enum LANGUAGE { NLD, SPA } public static final int GENERATE_PERSON_ENTITIES = 0x01; public static final int GENERATE_ORGANIZATION_ENTITIES = 0x01 << 1; public static final int GENERATE_LOCATION_ENTITIES = 0x01 << 2; public static final int GENERATE_MISC_ENTITIES = 0x01 << 3; public static final String DOCSTART = "-DOCSTART-"; private final LANGUAGE lang; private final ObjectStream lineStream; private final int types; /** * Initializes a {@link Conll02NameSampleStream}. * * @param lang The language of the CONLL 02 data. * @param lineStream An {@link ObjectStream} over the lines * in the CONLL 02 data file. * @param types The entity types to include in the Name Sample object stream. */ public Conll02NameSampleStream(LANGUAGE lang, ObjectStream lineStream, int types) { this.lang = lang; this.lineStream = lineStream; this.types = types; } /** * Initializes a {@link Conll02NameSampleStream}. * * @param lang The language of the CONLL 02 data. * @param in The {@link InputStreamFactory} for the input file. * @param types The entity types to include in the Name Sample object stream. * * @throws IOException Thrown if IO errors occurred. */ public Conll02NameSampleStream(LANGUAGE lang, InputStreamFactory in, int types) throws IOException { /* * NOTE: KEEP this encoding here! The original CONLL 2002 data is provided as: ISO_8859_1. */ this (lang, new PlainTextByLineStream(in, StandardCharsets.ISO_8859_1), types); /* * If related files are (incorrectly) interpreted as 'UTF-8' without prior conversion of * the train/test files, then á, é, ñ,.. will be misinterpreted during processing and in * resulting outcomes, e.g. produced via TokenNameFinderConverter. * * As a consequence, users of related tooling (OpenNLP Doc: CONLL 2002) will thus suffer * from corrupted intermediate files, as an out-of the box experience. * * Details see: https://issues.apache.org/jira/browse/OPENNLP-1512 */ } static Span extract(int begin, int end, String beginTag) throws InvalidFormatException { String type = beginTag.substring(2); type = switch (type) { case "PER" -> "person"; case "LOC" -> "location"; case "MISC" -> "misc"; case "ORG" -> "organization"; default -> throw new InvalidFormatException("Unknown type: " + type); }; return new Span(begin, end, type); } @Override public NameSample read() throws IOException { List sentence = new ArrayList<>(); List tags = new ArrayList<>(); boolean isClearAdaptiveData = false; // Empty line indicates end of sentence String line; while ((line = lineStream.read()) != null && !StringUtil.isEmpty(line)) { if (LANGUAGE.NLD.equals(lang) && line.startsWith(DOCSTART)) { isClearAdaptiveData = true; continue; } String[] fields = line.split(" "); if (fields.length == 3) { sentence.add(fields[0]); tags.add(fields[2]); } else { throw new IOException("Expected three fields per line in training data, got " + fields.length + " for line '" + line + "'!"); } } // Always clear adaptive data for spanish if (LANGUAGE.SPA.equals(lang)) isClearAdaptiveData = true; if (sentence.size() > 0) { // convert name tags into spans List names = new ArrayList<>(); int beginIndex = -1; int endIndex = -1; for (int i = 0; i < tags.size(); i++) { String tag = tags.get(i); if (tag.endsWith("PER") && (types & GENERATE_PERSON_ENTITIES) == 0) tag = "O"; if (tag.endsWith("ORG") && (types & GENERATE_ORGANIZATION_ENTITIES) == 0) tag = "O"; if (tag.endsWith("LOC") && (types & GENERATE_LOCATION_ENTITIES) == 0) tag = "O"; if (tag.endsWith("MISC") && (types & GENERATE_MISC_ENTITIES) == 0) tag = "O"; if (tag.startsWith("B-")) { if (beginIndex != -1) { names.add(extract(beginIndex, endIndex, tags.get(beginIndex))); beginIndex = -1; endIndex = -1; } beginIndex = i; endIndex = i + 1; } else if (tag.startsWith("I-")) { endIndex++; } else if (tag.equals("O")) { if (beginIndex != -1) { names.add(extract(beginIndex, endIndex, tags.get(beginIndex))); beginIndex = -1; endIndex = -1; } } else { throw new IOException("Invalid tag: " + tag); } } // if one span remains, create it here if (beginIndex != -1) names.add(extract(beginIndex, endIndex, tags.get(beginIndex))); return new NameSample(sentence.toArray(new String[0]), names.toArray(new Span[0]), isClearAdaptiveData); } else if (line != null) { // Just filter out empty events, if two lines in a row are empty return read(); } else { // source stream is not returning anymore lines return null; } } @Override public void reset() throws IOException, UnsupportedOperationException { lineStream.reset(); } @Override public void close() throws IOException { lineStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Conll02N0100644 0000000 0000000 00000000171 15217274217 032322 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll02NameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll02NameSampleStreamF0100644 0000000 0000000 00000006677 15217274217 033763 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.Conll02NameSampleStream.LANGUAGE; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see Conll02NameSampleStream */ @Internal public class Conll02NameSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ParameterDescription(valueName = "spa|nld") String getLang(); @ParameterDescription(valueName = "per,loc,org,misc") String getTypes(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "conll02", new Conll02NameSampleStreamFactory(Parameters.class)); } protected Conll02NameSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); LANGUAGE lang; if ("nl".equals(params.getLang()) || "nld".equals(params.getLang())) { lang = LANGUAGE.NLD; language = params.getLang(); } else if ("es".equals(params.getLang()) || "spa".equals(params.getLang())) { lang = LANGUAGE.SPA; language = params.getLang(); } else { throw new TerminateToolException(1, "Unsupported language: " + params.getLang()); } int typesToGenerate = 0; if (params.getTypes().contains("per")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_PERSON_ENTITIES; } if (params.getTypes().contains("org")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_ORGANIZATION_ENTITIES; } if (params.getTypes().contains("loc")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_LOCATION_ENTITIES; } if (params.getTypes().contains("misc")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_MISC_ENTITIES; } try { return new Conll02NameSampleStream(lang, CmdLineUtil.createInputStreamFactory(params.getData()), typesToGenerate); } catch (IOException e) { throw CmdLineUtil.createObjectStreamError(e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Conll03N0100644 0000000 0000000 00000000162 15217274217 032323 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll03NameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll03NameSampleStream.0100644 0000000 0000000 00000014714 15217274217 033723 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; import opennlp.tools.util.StringUtil; /** * An import stream which can parse the CONLL03 data. */ public class Conll03NameSampleStream implements ObjectStream { public enum LANGUAGE { EN, DE } private final LANGUAGE lang; private final ObjectStream lineStream; private final int types; /** * Initializes a {@link Conll03NameSampleStream}. * * @param lang The language of the CONLL 03 data. * @param lineStream An {@link ObjectStream} over the lines * in the CONLL 03 data file. * @param types The entity types to include in the Name Sample object stream. */ public Conll03NameSampleStream(LANGUAGE lang, ObjectStream lineStream, int types) { this.lang = lang; this.lineStream = lineStream; this.types = types; } /** * Initializes a {@link Conll03NameSampleStream}. * * @param lang The language of the CONLL 03 data. * @param in The {@link InputStreamFactory} for the input file. * @param types The entity types to include in the Name Sample object stream. * * @throws IOException Thrown if IO errors occurred. */ public Conll03NameSampleStream(LANGUAGE lang, InputStreamFactory in, int types) throws IOException { this(lang, new PlainTextByLineStream(in, StandardCharsets.UTF_8), types); } @Override public NameSample read() throws IOException { List sentence = new ArrayList<>(); List tags = new ArrayList<>(); boolean isClearAdaptiveData = false; // Empty line indicates end of sentence String line; while ((line = lineStream.read()) != null && !StringUtil.isEmpty(line)) { if (line.startsWith(Conll02NameSampleStream.DOCSTART)) { isClearAdaptiveData = true; String emptyLine = lineStream.read(); if (!StringUtil.isEmpty(emptyLine)) throw new IOException("Empty line after -DOCSTART- not empty: '" + emptyLine + "'!"); continue; } String[] fields = line.split(" "); // For English: WORD POS-TAG SC-TAG NE-TAG if (LANGUAGE.EN.equals(lang) && fields.length == 4) { sentence.add(fields[0]); tags.add(fields[3]); // 3 is NE-TAG } // For German: WORD LEMA-TAG POS-TAG SC-TAG NE-TAG else if (LANGUAGE.DE.equals(lang) && fields.length == 5) { sentence.add(fields[0]); tags.add(fields[4]); // 4 is NE-TAG } else { throw new IOException("Incorrect number of fields per line for language: '" + line + "'!"); } } if (sentence.size() > 0) { // convert name tags into spans List names = new ArrayList<>(); int beginIndex = -1; int endIndex = -1; for (int i = 0; i < tags.size(); i++) { String tag = tags.get(i); if (tag.endsWith("PER") && (types & Conll02NameSampleStream.GENERATE_PERSON_ENTITIES) == 0) tag = "O"; if (tag.endsWith("ORG") && (types & Conll02NameSampleStream.GENERATE_ORGANIZATION_ENTITIES) == 0) tag = "O"; if (tag.endsWith("LOC") && (types & Conll02NameSampleStream.GENERATE_LOCATION_ENTITIES) == 0) tag = "O"; if (tag.endsWith("MISC") && (types & Conll02NameSampleStream.GENERATE_MISC_ENTITIES) == 0) tag = "O"; if (tag.equals("O")) { // O means we don't have anything this round. if (beginIndex != -1) { names.add(Conll02NameSampleStream.extract(beginIndex, endIndex, tags.get(beginIndex))); beginIndex = -1; endIndex = -1; } } else if (tag.startsWith("B-")) { // B- prefix means we have two same entities next to each other if (beginIndex != -1) { names.add(Conll02NameSampleStream.extract(beginIndex, endIndex, tags.get(beginIndex))); } beginIndex = i; endIndex = i + 1; } else if (tag.startsWith("I-")) { // I- starts or continues a current name entity if (beginIndex == -1) { beginIndex = i; endIndex = i + 1; } else if (!tag.endsWith(tags.get(beginIndex).substring(1))) { // we have a new tag type following a tagged word series // also may not have the same I- starting the previous! names.add(Conll02NameSampleStream.extract(beginIndex, endIndex, tags.get(beginIndex))); beginIndex = i; endIndex = i + 1; } else { endIndex ++; } } else { throw new IOException("Invalid tag: " + tag); } } // if one span remains, create it here if (beginIndex != -1) names.add(Conll02NameSampleStream.extract(beginIndex, endIndex, tags.get(beginIndex))); return new NameSample(sentence.toArray(new String[0]), names.toArray(new Span[0]), isClearAdaptiveData); } else if (line != null) { // Just filter out empty events, if two lines in a row are empty return read(); } else { // source stream is not returning anymore lines return null; } } @Override public void reset() throws IOException, UnsupportedOperationException { lineStream.reset(); } @Override public void close() throws IOException { lineStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Conll03N0100644 0000000 0000000 00000000171 15217274217 032323 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll03NameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/Conll03NameSampleStreamF0100644 0000000 0000000 00000006504 15217274217 033751 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.formats.Conll03NameSampleStream.LANGUAGE; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; /** * @see Conll03NameSampleStream */ public class Conll03NameSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ParameterDescription(valueName = "eng|deu") String getLang(); @ParameterDescription(valueName = "per,loc,org,misc") String getTypes(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "conll03", new Conll03NameSampleStreamFactory(Parameters.class)); } protected Conll03NameSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); // TODO: support the other languages with this CoNLL. LANGUAGE lang; if ("eng".equals(params.getLang())) { lang = LANGUAGE.EN; language = params.getLang(); } else if ("deu".equals(params.getLang())) { lang = LANGUAGE.DE; language = params.getLang(); } else { throw new TerminateToolException(1, "Unsupported language: " + params.getLang()); } int typesToGenerate = 0; if (params.getTypes().contains("per")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_PERSON_ENTITIES; } if (params.getTypes().contains("org")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_ORGANIZATION_ENTITIES; } if (params.getTypes().contains("loc")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_LOCATION_ENTITIES; } if (params.getTypes().contains("misc")) { typesToGenerate = typesToGenerate | Conll02NameSampleStream.GENERATE_MISC_ENTITIES; } try { return new Conll03NameSampleStream(lang, CmdLineUtil.createInputStreamFactory(params.getData()), typesToGenerate); } catch (IOException e) { throw CmdLineUtil.createObjectStreamError(e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ConllXPO0100644 0000000 0000000 00000000160 15217274217 032427 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXPOSSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXPOSSampleStream.ja0100644 0000000 0000000 00000007347 15217274217 034010 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import opennlp.tools.commons.Internal; import opennlp.tools.postag.POSSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.ParagraphStream; import opennlp.tools.util.PlainTextByLineStream; /** * Parses the data from the CONLL 06 shared task into POS Samples. *

* More information about the data format can be found * here. *

* Note: * Do not use this class, internal use only! */ @Internal public class ConllXPOSSampleStream extends FilterObjectStream { /** * Initializes a {@link ConllXPOSSampleStream}. * * @param lineStream A {@link ObjectStream line stream} representing the input. */ public ConllXPOSSampleStream(ObjectStream lineStream) { super(new ParagraphStream(lineStream)); } /** * Initializes a {@link ConllXPOSSampleStream}. * * @param in The {@link InputStreamFactory} to use. * @param charset The {@link Charset} to interpret characters with. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ConllXPOSSampleStream(InputStreamFactory in, Charset charset) throws IOException { super(new ParagraphStream(new PlainTextByLineStream(in, charset))); } @Override public POSSample read() throws IOException { // The CONLL-X data has a word per line and each line is tab separated // in the following format: // ID, FORM, LEMMA, CPOSTAG, POSTAG, ... (max 10 fields) // One paragraph contains a whole sentence and, the token // and tag will be read from the FORM and POSTAG field. String paragraph = samples.read(); POSSample sample = null; if (paragraph != null) { // paragraph get lines BufferedReader reader = new BufferedReader(new StringReader(paragraph)); List tokens = new ArrayList<>(100); List tags = new ArrayList<>(100); String line; while ((line = reader.readLine()) != null) { final int minNumberOfFields = 5; String[] parts = line.split("\t"); if (parts.length >= minNumberOfFields) { tokens.add(parts[1]); tags.add(parts[4]); } else { throw new InvalidFormatException("Every non-empty line must have at least " + minNumberOfFields + " fields: '" + line + "'!"); } } // just skip empty samples and read next sample if (tokens.size() == 0) sample = read(); sample = new POSSample(tokens.toArray(new String[0]), tags.toArray(new String[0])); } return sample; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ConllXPO0100644 0000000 0000000 00000000167 15217274217 032436 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXPOSSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXPOSSampleStreamFac0100644 0000000 0000000 00000004423 15217274217 034021 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import java.nio.charset.StandardCharsets; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.postag.POSSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see POSSample * @see ConllXPOSSampleStream */ @Internal public class ConllXPOSSampleStreamFactory extends AbstractSampleStreamFactory { public static final String CONLLX_FORMAT = "conllx"; public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(POSSample.class, CONLLX_FORMAT, new ConllXPOSSampleStreamFactory(Parameters.class)); } protected ConllXPOSSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); try { InputStreamFactory inFactory = CmdLineUtil.createInputStreamFactory(params.getData()); return new ConllXPOSSampleStream(inFactory, StandardCharsets.UTF_8); } catch (IOException e) { CmdLineUtil.handleCreateObjectStreamError(e); return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ConllXSe0100644 0000000 0000000 00000000174 15217274217 032465 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXSentenceSampleStre0100644 0000000 0000000 00000004657 15217274217 034205 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.convert.POSToSentenceSampleStream; import opennlp.tools.postag.POSSample; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see SentenceSample * @see POSToSentenceSampleStream */ @Internal public class ConllXSentenceSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends ConllXPOSSampleStreamFactory.Parameters, DetokenizerParameter { // TODO: make chunk size configurable } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, ConllXPOSSampleStreamFactory.CONLLX_FORMAT, new ConllXSentenceSampleStreamFactory(Parameters.class)); } protected ConllXSentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream posSampleStream = StreamFactoryRegistry.getFactory(POSSample.class, ConllXPOSSampleStreamFactory.CONLLX_FORMAT).create( ArgumentParser.filter(args, ConllXPOSSampleStreamFactory.Parameters.class)); return new POSToSentenceSampleStream(createDetokenizer(params), posSampleStream, 30); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ConllXTo0100644 0000000 0000000 00000000171 15217274217 032475 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ConllXTokenSampleStreamF0100644 0000000 0000000 00000004510 15217274217 034131 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.convert.POSToTokenSampleStream; import opennlp.tools.postag.POSSample; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see TokenSample * @see POSToTokenSampleStream */ @Internal public class ConllXTokenSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends ConllXPOSSampleStreamFactory.Parameters, DetokenizerParameter { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, ConllXPOSSampleStreamFactory.CONLLX_FORMAT, new ConllXTokenSampleStreamFactory(Parameters.class)); } protected ConllXTokenSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream samples = StreamFactoryRegistry.getFactory(POSSample.class, ConllXPOSSampleStreamFactory.CONLLX_FORMAT).create( ArgumentParser.filter(args, ConllXPOSSampleStreamFactory.Parameters.class)); return new POSToTokenSampleStream(createDetokenizer(params), samples); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Detokeni0100644 0000000 0000000 00000000171 15217274217 032535 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/DetokenizerSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/DetokenizerSampleStreamF0100644 0000000 0000000 00000003453 15217274217 034221 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.tokenize.DetokenizationDictionary; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.tokenize.DictionaryDetokenizer; /** * Base class for factories which need a {@link Detokenizer}. */ public abstract class DetokenizerSampleStreamFactory extends AbstractSampleStreamFactory { protected DetokenizerSampleStreamFactory(Class

params) { super(params); } protected Detokenizer createDetokenizer(DetokenizerParameter p) { try { return new DictionaryDetokenizer(new DetokenizationDictionary( new BufferedInputStream(new FileInputStream(p.getDetokenizer())))); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while loading detokenizer dict: " + e.getMessage(), e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Director0100644 0000000 0000000 00000000160 15217274217 032544 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/DirectorySampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/DirectorySampleStream.ja0100644 0000000 0000000 00000007532 15217274217 034167 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Stack; import opennlp.tools.util.ObjectStream; /** * The directory sample stream allows for creating an {@link ObjectStream} * from a directory listing of files. */ public class DirectorySampleStream implements ObjectStream { private final List inputDirectories; private final boolean recursive; private final FileFilter fileFilter; private final Stack directories = new Stack<>(); private final Stack textFiles = new Stack<>(); /** * Initializes a {@link DirectorySampleStream}. * * @param dirs The {@link File directories} to read. * @param fileFilter The {@link FileFilter filter} to apply while enumerating files. * @param recursive Enables or disables recursive file listing. * * @throws IllegalArgumentException Thrown if one element in {@code dirs} is not a directory. */ public DirectorySampleStream(File[] dirs, FileFilter fileFilter, boolean recursive) { this.fileFilter = fileFilter; this.recursive = recursive; List inputDirectoryList = new ArrayList<>(dirs.length); for (File dir : dirs) { if (!dir.isDirectory()) { throw new IllegalArgumentException( "All passed in directories must be directories, but \"" + dir + "\" is not!"); } inputDirectoryList.add(dir); } inputDirectories = Collections.unmodifiableList(inputDirectoryList); directories.addAll(inputDirectories); } /** * Initializes a {@link DirectorySampleStream}. * * @param dir The {@link File directory} to read. * @param fileFilter The {@link FileFilter filter} to apply while enumerating files. * @param recursive Enables or disables recursive file listing. * * @throws IllegalArgumentException Thrown if {@code dir} is not a directory. */ public DirectorySampleStream(File dir, FileFilter fileFilter, boolean recursive) { this(new File[]{dir}, fileFilter, recursive); } @Override public File read() throws IOException { while (textFiles.isEmpty() && !directories.isEmpty()) { File dir = directories.pop(); File[] files; if (fileFilter != null) { files = dir.listFiles(fileFilter); } else { files = dir.listFiles(); } Arrays.sort(files); for (File file : files) { if (file.isFile()) { textFiles.push(file); } else if (recursive && file.isDirectory()) { directories.push(file); } } } if (!textFiles.isEmpty()) { return textFiles.pop(); } else { return null; } } @Override public void reset() { directories.clear(); textFiles.clear(); directories.addAll(inputDirectories); } /** * {@inheritDoc} * Calling this function has no effect on the stream. */ @Override public void close() throws IOException { } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Document0100644 0000000 0000000 00000000166 15217274217 032555 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/DocumentSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/DocumentSampleStreamFact0100644 0000000 0000000 00000003500 15217274217 034175 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.doccat.DocumentSampleStream; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link DocumentSampleStream}s. */ public class DocumentSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(DocumentSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new DocumentSampleStreamFactory(Parameters.class)); } protected DocumentSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new DocumentSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_EvalitaN0100644 0000000 0000000 00000000162 15217274217 032476 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/EvalitaNameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/EvalitaNameSampleStream.0100644 0000000 0000000 00000016302 15217274217 034071 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import opennlp.tools.commons.Internal; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; import opennlp.tools.util.StringUtil; /** * Parser for the Italian NER training files of the Evalita 2007 and 2009 NER shared tasks. *

* The data does not contain article boundaries, * adaptive data will be cleared for every sentence. *

* Named Entities are annotated in the IOB2 format (as used in CoNLL 2002 shared task) *

* The Named Entity tag consists of two parts: * 1. The IOB2 tag: 'B' (for 'begin') denotes the first token of a * Named Entity, I (for 'inside') is used for all other tokens in a * Named Entity, and 'O' (for 'outside') is used for all other words; * 2. The Entity type tag: PER (for Person), ORG (for Organization), * GPE (for Geo-Political Entity), or LOC (for Location). *

* Each file consists of four columns separated by a blank, containing respectively the token, the * Elsnet * PoS-tag, the Adige news story to which the token belongs, and the Named Entity tag. *

* Data can be found on this * web site. *

* Note: * Do not use this class, internal use only! */ @Internal public class EvalitaNameSampleStream implements ObjectStream { public static final String DOCSTART = "-DOCSTART-"; private static final String CODEC_TAG_O = "O"; private static final String CODEC_TAG_B = "B-"; private static final String CODEC_TAG_I = "I-"; private static final String ENT_TYPE_PER = "PER"; // Person private static final String ENT_TYPE_LOC = "LOC"; // Location private static final String ENT_TYPE_GPE = "GPE"; // Geo-Political Entity private static final String ENT_TYPE_ORG = "ORG"; // Organization public enum LANGUAGE { IT } public static final int GENERATE_PERSON_ENTITIES = 0x01; public static final int GENERATE_ORGANIZATION_ENTITIES = 0x01 << 1; public static final int GENERATE_LOCATION_ENTITIES = 0x01 << 2; public static final int GENERATE_GPE_ENTITIES = 0x01 << 3; private final LANGUAGE lang; private final ObjectStream lineStream; private final int types; public EvalitaNameSampleStream(LANGUAGE lang, ObjectStream lineStream, int types) { this.lang = lang; this.lineStream = lineStream; this.types = types; } public EvalitaNameSampleStream(LANGUAGE lang, InputStreamFactory in, int types) throws IOException { this(lang, new PlainTextByLineStream(in, StandardCharsets.UTF_8), types); } private static Span extract(int begin, int end, String beginTag) throws InvalidFormatException { String type = beginTag.substring(2); type = switch (type) { case ENT_TYPE_PER -> "person"; case ENT_TYPE_LOC -> "location"; case ENT_TYPE_GPE -> "gpe"; case ENT_TYPE_ORG -> "organization"; default -> throw new InvalidFormatException("Unknown type: " + type); }; return new Span(begin, end, type); } @Override public NameSample read() throws IOException { List sentence = new ArrayList<>(); List tags = new ArrayList<>(); boolean isClearAdaptiveData = false; // Empty line indicates end of sentence String line; while ((line = lineStream.read()) != null && !StringUtil.isEmpty(line)) { if (line.startsWith(DOCSTART)) { isClearAdaptiveData = true; String emptyLine = lineStream.read(); if (!StringUtil.isEmpty(emptyLine)) throw new IOException("Empty line after -DOCSTART- not empty: '" + emptyLine + "'!"); continue; } String[] fields = line.split(" "); // For Italian: WORD POS-TAG SC-TAG NE-TAG if (LANGUAGE.IT.equals(lang) && fields.length == 4) { sentence.add(fields[0]); tags.add(fields[3]); // 3 is NE-TAG } else { throw new IOException("Incorrect number of fields per line for language: '" + line + "'!"); } } // Always clear adaptive data for Italian if (LANGUAGE.IT.equals(lang)) isClearAdaptiveData = true; if (!sentence.isEmpty()) { // convert name tags into spans List names = new ArrayList<>(); int beginIndex = -1; int endIndex = -1; for (int i = 0; i < tags.size(); i++) { String tag = tags.get(i); if (tag.endsWith(ENT_TYPE_PER) && (types & GENERATE_PERSON_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.endsWith(ENT_TYPE_ORG) && (types & GENERATE_ORGANIZATION_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.endsWith(ENT_TYPE_LOC) && (types & GENERATE_LOCATION_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.endsWith(ENT_TYPE_GPE) && (types & GENERATE_GPE_ENTITIES) == 0) tag = CODEC_TAG_O; if (tag.startsWith(CODEC_TAG_B)) { if (beginIndex != -1) { names.add(extract(beginIndex, endIndex, tags.get(beginIndex))); } beginIndex = i; endIndex = i + 1; } else if (tag.startsWith(CODEC_TAG_I)) { endIndex++; } else if (tag.equals(CODEC_TAG_O)) { if (beginIndex != -1) { names.add(extract(beginIndex, endIndex, tags.get(beginIndex))); beginIndex = -1; endIndex = -1; } } else { throw new IOException("Invalid tag: " + tag); } } // if one span remains, create it here if (beginIndex != -1) names.add(extract(beginIndex, endIndex, tags.get(beginIndex))); return new NameSample(sentence.toArray(new String[0]), names.toArray(new Span[0]), isClearAdaptiveData); } else if (line != null) { // Just filter out empty events, if two lines in a row are empty return read(); } else { // source stream is not returning anymore lines return null; } } @Override public void reset() throws IOException, UnsupportedOperationException { lineStream.reset(); } @Override public void close() throws IOException { lineStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_EvalitaN0100644 0000000 0000000 00000000171 15217274217 032476 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/EvalitaNameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/EvalitaNameSampleStreamF0100644 0000000 0000000 00000006374 15217274217 034131 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.EvalitaNameSampleStream.LANGUAGE; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see EvalitaNameSampleStream */ @Internal public class EvalitaNameSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ParameterDescription(valueName = "it") String getLang(); @ParameterDescription(valueName = "per,loc,org,gpe") String getTypes(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "evalita", new EvalitaNameSampleStreamFactory(Parameters.class)); } protected EvalitaNameSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); LANGUAGE lang; if ("it".equals(params.getLang())) { lang = LANGUAGE.IT; language = params.getLang(); } else { throw new TerminateToolException(1, "Unsupported language: " + params.getLang()); } int typesToGenerate = 0; final String types = params.getTypes(); if (types.contains("per")) { typesToGenerate = typesToGenerate | EvalitaNameSampleStream.GENERATE_PERSON_ENTITIES; } if (types.contains("org")) { typesToGenerate = typesToGenerate | EvalitaNameSampleStream.GENERATE_ORGANIZATION_ENTITIES; } if (types.contains("loc")) { typesToGenerate = typesToGenerate | EvalitaNameSampleStream.GENERATE_LOCATION_ENTITIES; } if (types.contains("gpe")) { typesToGenerate = typesToGenerate | EvalitaNameSampleStream.GENERATE_GPE_ENTITIES; } try { return new EvalitaNameSampleStream(lang, CmdLineUtil.createInputStreamFactory(params.getData()), typesToGenerate); } catch (IOException e) { throw CmdLineUtil.createObjectStreamError(e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Language0100644 0000000 0000000 00000000176 15217274217 032523 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/LanguageDetectorSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/LanguageDetectorSampleSt0100644 0000000 0000000 00000003650 15217274217 034177 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.langdetect.LanguageDetectorSampleStream; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link LanguageDetectorSampleStream lang detector sample streams}. */ public class LanguageDetectorSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(LanguageSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new LanguageDetectorSampleStreamFactory(Parameters.class)); } protected LanguageDetectorSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new LanguageDetectorSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Language0100644 0000000 0000000 00000000166 15217274217 032522 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/LanguageSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/LanguageSampleStreamFact0100644 0000000 0000000 00000002235 15217274217 034146 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; /** * Stream factory for those streams which carry language. */ public abstract class LanguageSampleStreamFactory extends AbstractSampleStreamFactory { protected String language; protected LanguageSampleStreamFactory(Class

params) { super(params); } @Override public String getLang() { return language; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Lemmatiz0100644 0000000 0000000 00000000170 15217274217 032554 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/LemmatizerSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/LemmatizerSampleStreamFa0100644 0000000 0000000 00000003473 15217274217 034212 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.lemmatizer.LemmaSampleStream; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link LemmaSampleStream}s. */ public class LemmatizerSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(LemmaSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new LemmatizerSampleStreamFactory(Parameters.class)); } protected LemmatizerSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new LemmaSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_NameFind0100644 0000000 0000000 00000000167 15217274217 032461 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/NameFinderCensus90NameStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/NameFinderCensus90NameSt0100644 0000000 0000000 00000010434 15217274217 033761 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import java.nio.charset.Charset; import java.util.Locale; import opennlp.tools.commons.Internal; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.StringList; import opennlp.tools.util.StringUtil; /** * This class helps to read the US Census data from the files to build a * StringList for each dictionary entry in the name-finder dictionary. * The entries in the source file are as follows: *

* SMITH 1.006 1.006 1 *

    *
  • The first field is the name (in ALL CAPS). *
  • The next field is a frequency in percent. *
  • The next is a cumulative frequency in percent. *
  • The last is a ranking. *
*

* Note: * Do not use this class, internal use only! */ @Internal public class NameFinderCensus90NameStream implements ObjectStream { private final Locale locale; private final Charset encoding; private final ObjectStream lineStream; /** * Initializes a {@link NameFinderCensus90NameStream} via {@link ObjectStream}. * * @param lineStream An {@link ObjectStream} that represents the * input file to be attached to this class. */ public NameFinderCensus90NameStream(ObjectStream lineStream) { this.locale = new Locale("en"); // locale is English this.encoding = Charset.defaultCharset(); // todo how do we find the encoding for an already open ObjectStream() ? this.lineStream = lineStream; } /** * Initializes a {@link NameFinderCensus90NameStream} via an {@link InputStreamFactory} * and a {@link Charset}. * Opens an associated stream object with the specified encoding specified. * * @param in The {@link InputStreamFactory} for the input file. * @param encoding the {@link Charset} to apply to the input stream. * * @throws IOException Thrown if IO errors occurred. */ public NameFinderCensus90NameStream(InputStreamFactory in, Charset encoding) throws IOException { this.locale = new Locale("en"); // locale is English this.encoding = encoding; this.lineStream = new PlainTextByLineStream(in, this.encoding); } @Override public StringList read() throws IOException { String line = lineStream.read(); StringList name = null; if ((line != null) && (!StringUtil.isEmpty(line))) { String name2; // find the location of the name separator in the line of data. int pos = line.indexOf(' '); if ((pos != -1)) { String parsed = line.substring(0, pos); // the data is in ALL CAPS ... so the easiest way is to convert // back to standard mixed case. if ((parsed.length() > 2) && (parsed.startsWith("MC"))) { name2 = parsed.substring(0,1).toUpperCase(locale) + parsed.substring(1,2).toLowerCase(locale) + parsed.substring(2,3).toUpperCase(locale) + parsed.substring(3).toLowerCase(locale); } else { name2 = parsed.substring(0,1).toUpperCase(locale) + parsed.substring(1).toLowerCase(locale); } name = new StringList(new String[]{name2}); } } return name; } @Override public void reset() throws IOException, UnsupportedOperationException { lineStream.reset(); } @Override public void close() throws IOException { lineStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_NameSamp0100644 0000000 0000000 00000000166 15217274217 032500 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/NameSampleDataStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/NameSampleDataStreamFact0100644 0000000 0000000 00000003545 15217274217 034102 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.namefind.NameSample; import opennlp.tools.namefind.NameSampleDataStream; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link NameSampleDataStream}s. */ @Internal public class NameSampleDataStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new NameSampleDataStreamFactory(Parameters.class)); } protected NameSampleDataStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new NameSampleDataStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ParseSam0100644 0000000 0000000 00000000163 15217274217 032507 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ParseSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ParseSampleStreamFactory0100644 0000000 0000000 00000003407 15217274217 034231 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParseSampleStream; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link ParseSampleStream}s. */ public class ParseSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(Parse.class, StreamFactoryRegistry.DEFAULT_FORMAT, new ParseSampleStreamFactory(Parameters.class)); } protected ParseSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new ParseSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_Sentence0100644 0000000 0000000 00000000166 15217274217 032543 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/SentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/SentenceSampleStreamFact0100644 0000000 0000000 00000003505 15217274217 034170 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.sentdetect.SentenceSampleStream; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link SentenceSampleStream}s. */ public class SentenceSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new SentenceSampleStreamFactory(Parameters.class)); } protected SentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new SentenceSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_TokenSam0100644 0000000 0000000 00000000163 15217274217 032515 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/TokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/TokenSampleStreamFactory0100644 0000000 0000000 00000003443 15217274217 034237 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.tokenize.TokenSampleStream; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link TokenSampleStream}s. */ public class TokenSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new TokenSampleStreamFactory(Parameters.class)); } protected TokenSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new TokenSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_TwentyNe0100644 0000000 0000000 00000000166 15217274217 032554 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/TwentyNewsgroupSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/TwentyNewsgroupSampleStr0100644 0000000 0000000 00000005047 15217274217 034352 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.util.ObjectStream; /** * An {@link ObjectStream} implementation for the Twenty Newsgroups text corpus. *

* The document collection was created and donated by: Tom Mitchell, * School of Computer Science, Carnegie Mellon University. *

* Details and the data can be found via this DOI: * 10.24432/C5C323. */ public class TwentyNewsgroupSampleStream implements ObjectStream { private final Tokenizer tokenizer; private final Map catFileMap = new HashMap<>(); private Iterator> catFileTupleIterator; TwentyNewsgroupSampleStream(Tokenizer tokenizer, Path dataDir) throws IOException { this.tokenizer = tokenizer; for (Path dir : Files.newDirectoryStream(dataDir, Files::isDirectory)) { for (Path file : Files.newDirectoryStream(dir)) { catFileMap.put(file, dir.getFileName().toString()); } } reset(); } @Override public DocumentSample read() throws IOException { if (catFileTupleIterator.hasNext()) { Map.Entry catFileTuple = catFileTupleIterator.next(); String text = new String(Files.readAllBytes(catFileTuple.getKey())); return new DocumentSample(catFileTuple.getValue(), tokenizer.tokenize(text)); } return null; } @Override public void reset() throws IOException, UnsupportedOperationException { catFileTupleIterator = catFileMap.entrySet().iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_TwentyNe0100644 0000000 0000000 00000000175 15217274217 032554 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/TwentyNewsgroupSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/TwentyNewsgroupSampleStr0100644 0000000 0000000 00000007272 15217274217 034354 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EncodingParameter; import opennlp.tools.doccat.DocumentSample; import opennlp.tools.tokenize.SimpleTokenizer; import opennlp.tools.tokenize.ThreadSafeTokenizerME; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.tokenize.TokenizerModel; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see TwentyNewsgroupSampleStream */ public class TwentyNewsgroupSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends EncodingParameter { @ArgumentParser.ParameterDescription(valueName = "dataDir", description = "dir containing the 20newsgroup folders") File getDataDir(); @ArgumentParser.ParameterDescription(valueName = "modelFile") @ArgumentParser.OptionalParameter File getTokenizerModel(); @ArgumentParser.ParameterDescription(valueName = "name") @ArgumentParser.OptionalParameter String getRuleBasedTokenizer(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(DocumentSample.class, "20newsgroup", new TwentyNewsgroupSampleStreamFactory(TwentyNewsgroupSampleStreamFactory.Parameters.class)); } protected TwentyNewsgroupSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); Tokenizer tokenizer = WhitespaceTokenizer.INSTANCE; if (params.getTokenizerModel() != null) { try { tokenizer = new ThreadSafeTokenizerME(new TokenizerModel(params.getTokenizerModel())); } catch (IOException e) { throw new TerminateToolException(-1, "Failed to load tokenizer model!", e); } } else if (params.getRuleBasedTokenizer() != null) { String tokenizerName = params.getRuleBasedTokenizer(); if ("simple".equals(tokenizerName)) { tokenizer = SimpleTokenizer.INSTANCE; } else if ("whitespace".equals(tokenizerName)) { tokenizer = WhitespaceTokenizer.INSTANCE; } else { throw new TerminateToolException(-1, "Unknown tokenizer: " + tokenizerName); } } try { return new TwentyNewsgroupSampleStream(tokenizer, params.getDataDir().toPath()); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while opening sample data: " + e.getMessage(), e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_WordTagS0100644 0000000 0000000 00000000165 15217274217 032470 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/WordTagSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/WordTagSampleStreamFacto0100644 0000000 0000000 00000003525 15217274217 034154 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.postag.POSSample; import opennlp.tools.postag.WordTagSampleStream; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class WordTagSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(POSSample.class, StreamFactoryRegistry.DEFAULT_FORMAT, new WordTagSampleStreamFactory(Parameters.class)); } protected WordTagSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new WordTagSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADChu0100644 0000000 0000000 00000000161 15217274217 032362 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADChunkSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADChunkSampleStream.j0100644 0000000 0000000 00000021337 15217274217 033722 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.io.IOException; import java.util.ArrayList; import java.util.List; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.commons.Internal; import opennlp.tools.formats.ad.ADSentenceStream.Sentence; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.Leaf; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.Node; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.TreeElement; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.StringUtil; /** * Parser for Floresta Sita(c)tica Arvores Deitadas corpus, output to for the * Portuguese Chunker training. *

* The heuristic to extract chunks where based o paper 'A Machine Learning * Approach to Portuguese Clause Identification', (Eraldo Fernandes, Cicero * Santos and Ruy Milidiú).
*

* Data can be found on * this web site. * *

* Information about the format:
* Susana Afonso. * * "�rvores deitadas: Descrição do formato e das opções de análise na Floresta Sintáctica". *
* 12 de Fevereiro de 2006. *

* Detailed info about the * NER tagset. *

* Note: Do not use this class, internal use only! */ @Internal public class ADChunkSampleStream implements ObjectStream { protected final ObjectStream adSentenceStream; private int start = -1; private int end = -1; private int index = 0; public static final String OTHER = "O"; /** * Instantiates a {@link ADChunkSampleStream} stream from {@link ObjectStream}, * that could be a {@link PlainTextByLineStream} object. * * @param lineStream An {@link ObjectStream} as input. */ public ADChunkSampleStream(ObjectStream lineStream) { this.adSentenceStream = new ADSentenceStream(lineStream); } /** * Instantiates a {@link ADChunkSampleStream} stream from an {@link InputStreamFactory}. * * @param in The {@link InputStreamFactory} for the corpus. * @param charsetName The {@link java.nio.charset.Charset charset} to use * for reading of the corpus. */ public ADChunkSampleStream(InputStreamFactory in, String charsetName) throws IOException { this(new PlainTextByLineStream(in, charsetName)); } @Override public ChunkSample read() throws IOException { Sentence paragraph; while ((paragraph = this.adSentenceStream.read()) != null) { if (end > -1 && index >= end) { // leave return null; } if (start > -1 && index < start) { index++; // skip this one } else { Node root = paragraph.root(); List sentence = new ArrayList<>(); List tags = new ArrayList<>(); List target = new ArrayList<>(); processRoot(root, sentence, tags, target); if (!sentence.isEmpty()) { index++; return new ChunkSample(sentence, tags, target); } } } return null; } protected void processRoot(Node root, List sentence, List tags, List target) { if (root != null) { TreeElement[] elements = root.getElements(); for (TreeElement element : elements) { if (element.isLeaf()) { processLeaf((Leaf) element, false, OTHER, sentence, tags, target); } else { processNode((Node) element, sentence, tags, target, null); } } } } private void processNode(Node node, List sentence, List tags, List target, String inheritedTag) { String phraseTag = getChunkTag(node); boolean inherited = false; if (phraseTag.equals(OTHER) && inheritedTag != null) { phraseTag = inheritedTag; inherited = true; } TreeElement[] elements = node.getElements(); for (int i = 0; i < elements.length; i++) { if (elements[i].isLeaf()) { boolean isIntermediate = false; String tag = phraseTag; Leaf leaf = (Leaf) elements[i]; String localChunk = getChunkTag(leaf); if (localChunk != null && !tag.equals(localChunk)) { tag = localChunk; } if (isIntermediate(tags, target, tag) && (inherited || i > 0)) { isIntermediate = true; } if (!isIncludePunctuations() && leaf.getFunctionalTag() == null && ( !( i + 1 < elements.length && elements[i + 1].isLeaf() ) || !( i > 0 && elements[i - 1].isLeaf() ) ) ) { isIntermediate = false; tag = OTHER; } processLeaf(leaf, isIntermediate, tag, sentence, tags, target); } else { int before = target.size(); processNode((Node) elements[i], sentence, tags, target, phraseTag); // if the child node was of a different type we should break the chunk sequence for (int j = target.size() - 1; j >= before; j--) { if (!target.get(j).endsWith("-" + phraseTag)) { phraseTag = OTHER; break; } } } } } protected void processLeaf(Leaf leaf, boolean isIntermediate, String phraseTag, List sentence, List tags, List target) { String chunkTag; if (leaf.getFunctionalTag() != null && phraseTag.equals(OTHER)) { phraseTag = getPhraseTagFromPosTag(leaf.getFunctionalTag()); } if (!phraseTag.equals(OTHER)) { if (isIntermediate) { chunkTag = "I-" + phraseTag; } else { chunkTag = "B-" + phraseTag; } } else { chunkTag = phraseTag; } sentence.add(leaf.getLexeme()); if (leaf.getSyntacticTag() == null) { tags.add(leaf.getLexeme()); } else { tags.add(ADChunkSampleStream.convertFuncTag(leaf.getFunctionalTag(), false)); } target.add(chunkTag); } protected String getPhraseTagFromPosTag(String functionalTag) { if (functionalTag.equals("v-fin")) { return "VP"; } else if (functionalTag.equals("n")) { return "NP"; } return OTHER; } public static String convertFuncTag(String t, boolean useCGTags) { if (useCGTags) { if ("art".equals(t) || "pron-det".equals(t) || "pron-indef".equals(t)) { t = "det"; } } return t; } protected String getChunkTag(Leaf leaf) { String tag = leaf.getSyntacticTag(); if ("P".equals(tag)) { return "VP"; } return null; } protected String getChunkTag(Node node) { String tag = node.getSyntacticTag(); String phraseTag = tag.substring(tag.lastIndexOf(":") + 1); while (phraseTag.endsWith("-")) { phraseTag = phraseTag.substring(0, phraseTag.length() - 1); } // maybe we should use only np, vp and pp, but will keep ap and advp. if (phraseTag.equals("np") || phraseTag.equals("vp") || phraseTag.equals("pp") || phraseTag.equals("ap") || phraseTag.equals("advp") || phraseTag.equals("adjp")) { phraseTag = StringUtil.toUpperCase(phraseTag); } else { phraseTag = OTHER; } return phraseTag; } public void setStart(int aStart) { this.start = aStart; } public void setEnd(int aEnd) { this.end = aEnd; } @Override public void reset() throws IOException, UnsupportedOperationException { adSentenceStream.reset(); } @Override public void close() throws IOException { adSentenceStream.close(); } protected boolean isIncludePunctuations() { return false; } protected boolean isIntermediate(List tags, List target, String phraseTag) { return target.size() > 0 && target.get(target.size() - 1).endsWith("-" + phraseTag); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADChu0100644 0000000 0000000 00000000170 15217274217 032362 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADChunkSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADChunkSampleStreamFa0100644 0000000 0000000 00000006174 15217274217 033743 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.nio.charset.Charset; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.LanguageSampleStreamFactory; import opennlp.tools.util.ObjectStream; /** * A Factory to create a Arvores Deitadas ChunkStream from the command line * utility. *

* Note: * Do not use this class, internal use only! */ @Internal public class ADChunkSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { //all have to be repeated, because encoding is not optional, //according to the check if (encoding == null) { below (now removed) @ParameterDescription(valueName = "charsetName", description = "encoding for reading and writing text, if absent the system default is used.") Charset getEncoding(); @ParameterDescription(valueName = "language", description = "language which is being processed.") String getLang(); @ParameterDescription(valueName = "start", description = "index of first sentence") @OptionalParameter Integer getStart(); @ParameterDescription(valueName = "end", description = "index of last sentence") @OptionalParameter Integer getEnd(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(ChunkSample.class, "ad", new ADChunkSampleStreamFactory(Parameters.class)); } protected ADChunkSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream lineStream = readData(args, Parameters.class); ADChunkSampleStream sampleStream = new ADChunkSampleStream(lineStream); if (params.getStart() != null && params.getStart() > -1) { sampleStream.setStart(params.getStart()); } if (params.getEnd() != null && params.getEnd() > -1) { sampleStream.setEnd(params.getEnd()); } return sampleStream; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADNam0100644 0000000 0000000 00000000160 15217274217 032355 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADNameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADNameSampleStream.ja0100644 0000000 0000000 00000036403 15217274217 033673 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import opennlp.tools.commons.Internal; import opennlp.tools.formats.ad.ADSentenceStream.Sentence; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.Leaf; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.Node; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.TreeElement; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; /** * Parser for Floresta Sita(c)tica Arvores Deitadas corpus, output to for the * Portuguese NER training. *

* The data contains four named entity types: Person, Organization, Group, * Place, Event, ArtProd, Abstract, Thing, Time and Numeric.
*

* Data can be found on * this web site. * *

* Information about the format:
* Susana Afonso. * * "�rvores deitadas: Descrição do formato e das opções de análise na Floresta Sintáctica". *
* 12 de Fevereiro de 2006. *

* Detailed info about the * NER tagset. *

* Note: * Do not use this class, internal use only! */ @Internal public class ADNameSampleStream implements ObjectStream { /* * Pattern of a NER tag in Arvores Deitadas */ private static final Pattern TAG_PATTERN = Pattern.compile("<(NER:)?(.*?)>"); private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+"); private static final Pattern UNDERLINE_PATTERN = Pattern.compile("[_]+"); private static final Pattern HYPHEN_PATTERN = Pattern.compile("((\\p{L}+)-$)|(^-(\\p{L}+)(.*))|((\\p{L}+)-(\\p{L}+)(.*))"); private static final Pattern ALPHANUMERIC_PATTERN = Pattern.compile("^[\\p{L}\\p{Nd}]+$"); /* * Map to the Arvores Deitadas types to our types. It is read-only. */ private static final Map HAREM; static { Map harem = new HashMap<>(); final String person = "person"; harem.put("hum", person); harem.put("official", person); harem.put("member", person); final String organization = "organization"; harem.put("admin", organization); harem.put("org", organization); harem.put("inst", organization); harem.put("media", organization); harem.put("party", organization); harem.put("suborg", organization); final String group = "group"; harem.put("groupind", group); harem.put("groupofficial", group); final String place = "place"; harem.put("top", place); harem.put("civ", place); harem.put("address", place); harem.put("site", place); harem.put("virtual", place); harem.put("astro", place); final String event = "event"; harem.put("occ", event); harem.put("event", event); harem.put("history", event); final String artprod = "artprod"; harem.put("tit", artprod); harem.put("pub", artprod); harem.put("product", artprod); harem.put("V", artprod); harem.put("artwork", artprod); final String _abstract = "abstract"; harem.put("brand", _abstract); harem.put("genre", _abstract); harem.put("school", _abstract); harem.put("idea", _abstract); harem.put("plan", _abstract); harem.put("author", _abstract); harem.put("absname", _abstract); harem.put("disease", _abstract); final String thing = "thing"; harem.put("object", thing); harem.put("common", thing); harem.put("mat", thing); harem.put("class", thing); harem.put("plant", thing); harem.put("currency", thing); final String time = "time"; harem.put("date", time); harem.put("hour", time); harem.put("period", time); harem.put("cyclic", time); final String numeric = "numeric"; harem.put("quantity", numeric); harem.put("prednum", numeric); harem.put("currency", numeric); HAREM = Collections.unmodifiableMap(harem); } private final ObjectStream adSentenceStream; /* * To keep the last left contraction part */ private String leftContractionPart = null; private final boolean splitHyphenatedTokens; /** * Initializes a new {@link ADNameSampleStream} stream from a {@link ObjectStream}, * that could be a {@link PlainTextByLineStream} object. * * @param lineStream An {@link ObjectStream} as input. * @param splitHyphenatedTokens If {@code true} hyphenated tokens will be separated: * "carros-monstro" > "carros" "-" "monstro". */ public ADNameSampleStream(ObjectStream lineStream, boolean splitHyphenatedTokens) { this.adSentenceStream = new ADSentenceStream(lineStream); this.splitHyphenatedTokens = splitHyphenatedTokens; } /** * Initializes a new {@link ADNameSampleStream} from an {@link InputStreamFactory} * * @param in The Corpus {@link InputStreamFactory}. * @param charsetName The {@link java.nio.charset.Charset charset} to use * for reading of the corpus. * @param splitHyphenatedTokens If {@code true} hyphenated tokens will be separated: * "carros-monstro" > "carros" "-" "monstro". */ @Deprecated(forRemoval = true) public ADNameSampleStream(InputStreamFactory in, String charsetName, boolean splitHyphenatedTokens) throws IOException { this(new PlainTextByLineStream(in, charsetName), splitHyphenatedTokens); } private int textID = -1; @Override public NameSample read() throws IOException { Sentence paragraph; // we should look for text here. if ((paragraph = this.adSentenceStream.read()) != null) { int currentTextID = getTextID(paragraph); boolean clearData = false; if (currentTextID != textID) { clearData = true; textID = currentTextID; } Node root = paragraph.root(); List sentence = new ArrayList<>(); List names = new ArrayList<>(); process(root, sentence, names); return new NameSample(sentence.toArray(new String[0]), names.toArray(new Span[0]), clearData); } return null; } /** * Recursive method to process a {@link Node} in Arvores Deitadas format. * * @param node The {@link Node} to be processed. * @param sentence The {@link List sentence tokens} processed so far. * @param names The {@link List names} processed so far. */ private void process(Node node, List sentence, List names) { if (node != null) { for (TreeElement element : node.getElements()) { if (element.isLeaf()) { processLeaf((Leaf) element, sentence, names); } else { process((Node) element, sentence, names); } } } } /** * Processes a {@link Leaf} of Arvores Detaitadas format * * @param leaf The {@link Leaf} to be processed * @param sentence The {@link List sentence tokens} processed so far. * @param names The {@link List names} processed so far. */ private void processLeaf(Leaf leaf, List sentence, List names) { boolean alreadyAdded = false; if (leftContractionPart != null) { // will handle the contraction String right = leaf.getLexeme(); String c = PortugueseContractionUtility.toContraction( leftContractionPart, right); if (c != null) { String[] parts = WHITESPACE_PATTERN.split(c); sentence.addAll(Arrays.asList(parts)); alreadyAdded = true; } else { // contraction was missing! why? sentence.add(leftContractionPart); // keep alreadyAdded false. } leftContractionPart = null; } String namedEntityTag = null; int startOfNamedEntity = -1; String leafTag = leaf.getSecondaryTag(); boolean expandLastNER = false; // used when we find a tag if (leafTag != null) { if (leafTag.contains("") && !alreadyAdded) { String[] lexemes = UNDERLINE_PATTERN.split(leaf.getLexeme()); if (lexemes.length > 1) { sentence.addAll(Arrays.asList(lexemes).subList(0, lexemes.length - 1)); } leftContractionPart = lexemes[lexemes.length - 1]; return; } if (leafTag.contains("")) { // this one an be part of the last name expandLastNER = true; } namedEntityTag = getNER(leafTag); } if (namedEntityTag != null) { startOfNamedEntity = sentence.size(); } if (!alreadyAdded) { sentence.addAll(processLexeme(leaf.getLexeme())); } if (namedEntityTag != null) { names .add(new Span(startOfNamedEntity, sentence.size(), namedEntityTag)); } if (expandLastNER) { // if the current leaf has the tag , it can be the continuation of // a NER. // we check if it is true, and expand the last NER int lastIndex = names.size() - 1; if (names.size() > 0) { Span last = names.get(lastIndex); if (last.getEnd() == sentence.size() - 1) { names.set(lastIndex, new Span(last.getStart(), sentence.size(), last.getType())); } } } } private List processLexeme(String lexemeStr) { List out = new ArrayList<>(); String[] parts = UNDERLINE_PATTERN.split(lexemeStr); for (String tok : parts) { if (tok.length() > 1 && !ALPHANUMERIC_PATTERN.matcher(tok).matches()) { out.addAll(processTok(tok)); } else { out.add(tok); } } return out; } private List processTok(String tok) { boolean tokAdded = false; String original = tok; List out = new ArrayList<>(); LinkedList suffix = new LinkedList<>(); char first = tok.charAt(0); if (first == '«') { out.add(Character.toString(first)); tok = tok.substring(1); } char last = tok.charAt(tok.length() - 1); if (last == '»' || last == ':' || last == ',' || last == '!' ) { suffix.add(Character.toString(last)); tok = tok.substring(0, tok.length() - 1); } // lets split all hyphens if (this.splitHyphenatedTokens && tok.contains("-") && tok.length() > 1) { Matcher matcher = HYPHEN_PATTERN.matcher(tok); String firstTok = null; String hyphen = "-"; String secondTok = null; String rest = null; if (matcher.matches()) { if (matcher.group(1) != null) { firstTok = matcher.group(2); } else if (matcher.group(3) != null) { secondTok = matcher.group(4); rest = matcher.group(5); } else if (matcher.group(6) != null) { firstTok = matcher.group(7); secondTok = matcher.group(8); rest = matcher.group(9); } addIfNotEmpty(firstTok, out); addIfNotEmpty(hyphen, out); addIfNotEmpty(secondTok, out); addIfNotEmpty(rest, out); tokAdded = true; } } if (!tokAdded) { if (!original.equals(tok) && tok.length() > 1 && !ALPHANUMERIC_PATTERN.matcher(tok).matches()) { out.addAll(processTok(tok)); } else { out.add(tok); } } out.addAll(suffix); return out; } private void addIfNotEmpty(String firstTok, List out) { if (firstTok != null && firstTok.length() > 0) { out.addAll(processTok(firstTok)); } } /** * Parses a NER tag in Arvores Deitadas format. * * @param tags The NER tag in Arvores Deitadas format. * @return The NER tag, or {@code null} if not a NER tag in Arvores Deitadas format. */ private static String getNER(String tags) { if (tags.contains("")) { return null; } String[] tag = tags.split("\\s+"); for (String t : tag) { Matcher matcher = TAG_PATTERN.matcher(t); if (matcher.matches()) { String ner = matcher.group(2); if (HAREM.containsKey(ner)) { return HAREM.get(ner); } } } return null; } @Override public void reset() throws IOException, UnsupportedOperationException { adSentenceStream.reset(); } @Override public void close() throws IOException { adSentenceStream.close(); } enum Type { ama, cie, lit } // works for Amazonia // private static final Pattern meta1 = Pattern // .compile("^(?:[a-zA-Z\\-]*(\\d+)).*?p=(\\d+).*"); // // // works for selva cie // private static final Pattern meta2 = Pattern // .compile("^(?:[a-zA-Z\\-]*(\\d+)).*?p=(\\d+).*"); private int getTextID(Sentence paragraph) { final String meta = paragraph.metadata(); Type corpusType; Pattern metaPattern; int textIdMeta2 = -1; String textMeta2 = ""; if (meta.startsWith("LIT")) { corpusType = Type.lit; metaPattern = Pattern.compile("^([a-zA-Z\\-]+)(\\d+).*?p=(\\d+).*"); } else if (meta.startsWith("CIE")) { corpusType = Type.cie; metaPattern = Pattern.compile("^.*?source=\"(.*?)\".*"); } else { // ama corpusType = Type.ama; metaPattern = Pattern.compile("^(?:[a-zA-Z\\-]*(\\d+)).*?p=(\\d+).*"); } if (corpusType.equals(Type.lit)) { Matcher m2 = metaPattern.matcher(meta); if (m2.matches()) { String textId = m2.group(1); if (!textId.equals(textMeta2)) { textIdMeta2++; textMeta2 = textId; } return textIdMeta2; } else { throw new RuntimeException("Invalid metadata: " + meta); } } else if (corpusType.equals(Type.cie)) { Matcher m2 = metaPattern.matcher(meta); if (m2.matches()) { String textId = m2.group(1); if (!textId.equals(textMeta2)) { textIdMeta2++; textMeta2 = textId; } return textIdMeta2; } else { throw new RuntimeException("Invalid metadata: " + meta); } } else if (corpusType.equals(Type.ama)) { Matcher m2 = metaPattern.matcher(meta); if (m2.matches()) { return Integer.parseInt(m2.group(1)); // currentPara = Integer.parseInt(m.group(2)); } else { throw new RuntimeException("Invalid metadata: " + meta); } } return 0; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADNam0100644 0000000 0000000 00000000167 15217274217 032364 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADNameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADNameSampleStreamFac0100644 0000000 0000000 00000005572 15217274217 033717 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.nio.charset.Charset; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.LanguageSampleStreamFactory; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; /** * A Factory to create a Arvores Deitadas NameSampleDataStream from the command line * utility. *

* Note: * Do not use this class, internal use only! */ @Internal public class ADNameSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { //all have to be repeated, because encoding is not optional, //according to the check if (encoding == null) { below (now removed) @ParameterDescription(valueName = "charsetName", description = "encoding for reading and writing text, if absent the system default is used.") Charset getEncoding(); @ParameterDescription(valueName = "split", description = "if true all hyphenated tokens will be separated (default true)") @OptionalParameter(defaultValue = "true") Boolean getSplitHyphenatedTokens(); @ParameterDescription(valueName = "language", description = "language which is being processed.") String getLang(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "ad", new ADNameSampleStreamFactory(Parameters.class)); } protected ADNameSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); language = params.getLang(); ObjectStream lineStream = readData(args, Parameters.class); return new ADNameSampleStream(lineStream, params.getSplitHyphenatedTokens()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADPOS0100644 0000000 0000000 00000000157 15217274217 032311 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADPOSSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADPOSSampleStream.jav0100644 0000000 0000000 00000013217 15217274217 033640 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.util.regex.Pattern; import opennlp.tools.commons.Internal; import opennlp.tools.formats.ad.ADSentenceStream.Sentence; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.Leaf; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.Node; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.TreeElement; import opennlp.tools.postag.POSSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class ADPOSSampleStream implements ObjectStream { private static final Pattern WHITESPACES_PATTERN = Pattern.compile("\\s+"); private final ObjectStream adSentenceStream; private final boolean expandME; private final boolean isIncludeFeatures; /** * Creates a new {@link ADPOSSampleStream} stream from a {@link ObjectStream}, * that could be a {@link PlainTextByLineStream} object. * * @param lineStream A {@link ObjectStream} stream as input. * @param expandME If {@code true} will expand the multiword expressions, each word of the * expression will have the POS Tag that was attributed to the * expression plus the prefix {@code B-} or {@code I-} (CONLL convention). * @param includeFeatures If {@code true} will combine the POS Tag with the feature tags. */ public ADPOSSampleStream(ObjectStream lineStream, boolean expandME, boolean includeFeatures) { this.adSentenceStream = new ADSentenceStream(lineStream); this.expandME = expandME; this.isIncludeFeatures = includeFeatures; } /** * Creates a new {@link POSSample} stream from an {@link InputStreamFactory} * * @param in The {@link InputStreamFactory} for the corpus. * @param charsetName The {@link java.nio.charset.Charset charset} to use * for reading of the corpus. * @param expandME If {@code true} will expand the multiword expressions, each word of the * expression will have the POS Tag that was attributed to the * expression plus the prefix {@code B-} or {@code I-} (CONLL convention). * @param includeFeatures If {@code true} will combine the POS Tag with the feature tags. */ public ADPOSSampleStream(InputStreamFactory in, String charsetName, boolean expandME, boolean includeFeatures) throws IOException { this(new PlainTextByLineStream(in, charsetName), expandME, includeFeatures); } @Override public POSSample read() throws IOException { Sentence paragraph; if ((paragraph = this.adSentenceStream.read()) != null) { Node root = paragraph.root(); List sentence = new ArrayList<>(); List tags = new ArrayList<>(); process(root, sentence, tags); return new POSSample(sentence, tags); } return null; } private void process(Node node, List sentence, List tags) { if (node != null) { for (TreeElement element : node.getElements()) { if (element.isLeaf()) { processLeaf((Leaf) element, sentence, tags); } else { process((Node) element, sentence, tags); } } } } private void processLeaf(Leaf leaf, List sentence, List tags) { if (leaf != null) { String lexeme = leaf.getLexeme(); String tag = leaf.getFunctionalTag(); if (tag == null) { tag = leaf.getLexeme(); } if (isIncludeFeatures && leaf.getMorphologicalTag() != null) { tag += " " + leaf.getMorphologicalTag(); } tag = WHITESPACES_PATTERN.matcher(tag).replaceAll("="); if (tag == null) tag = lexeme; if (expandME && lexeme.contains("_")) { StringTokenizer tokenizer = new StringTokenizer(lexeme, "_"); if (tokenizer.countTokens() > 0) { List toks = new ArrayList<>(tokenizer.countTokens()); List tagsWithCont = new ArrayList<>( tokenizer.countTokens()); toks.add(tokenizer.nextToken()); tagsWithCont.add("B-" + tag); while (tokenizer.hasMoreTokens()) { toks.add(tokenizer.nextToken()); tagsWithCont.add("I-" + tag); } sentence.addAll(toks); tags.addAll(tagsWithCont); } else { sentence.add(lexeme); tags.add(tag); } } else { sentence.add(lexeme); tags.add(tag); } } } @Override public void reset() throws IOException, UnsupportedOperationException { adSentenceStream.reset(); } @Override public void close() throws IOException { adSentenceStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADPOS0100644 0000000 0000000 00000000166 15217274217 032311 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADPOSSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADPOSSampleStreamFact0100644 0000000 0000000 00000005471 15217274217 033662 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.nio.charset.Charset; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.LanguageSampleStreamFactory; import opennlp.tools.postag.POSSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class ADPOSSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ParameterDescription(valueName = "charsetName", description = "encoding for reading and writing text, if absent the system default is used.") Charset getEncoding(); @ParameterDescription(valueName = "language", description = "language which is being processed.") String getLang(); @ParameterDescription(valueName = "expandME", description = "expand multiword expressions.") @OptionalParameter(defaultValue = "false") Boolean getExpandME(); @ParameterDescription(valueName = "includeFeatures", description = "combine POS Tags with word features, like number and gender.") @OptionalParameter(defaultValue = "false") Boolean getIncludeFeatures(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(POSSample.class, "ad", new ADPOSSampleStreamFactory(Parameters.class)); } protected ADPOSSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); language = params.getLang(); ObjectStream lineStream = readData(args, Parameters.class); return new ADPOSSampleStream(lineStream, params.getExpandME(), params.getIncludeFeatures()); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADSen0100644 0000000 0000000 00000000164 15217274217 032373 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADSentenceSampleStrea0100644 0000000 0000000 00000013007 15217274217 034004 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import opennlp.tools.commons.Internal; import opennlp.tools.formats.ad.ADSentenceStream.Sentence; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.sentdetect.lang.Factory; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; import opennlp.tools.util.Span; /** * Note: * Do not use this class, internal use only! */ @Internal public class ADSentenceSampleStream implements ObjectStream { private final ObjectStream adSentenceStream; private int text = -1; private int para = -1; private boolean isSameText; private boolean isSamePara; private Sentence sent; private final boolean isIncludeTitles; private boolean isTitle; private final char[] ptEosCharacters; /** * Initializes a new {@link ADSentenceSampleStream} from a {@link ObjectStream}, * that could be a {@link PlainTextByLineStream} object. * * @param lineStream A stream of lines as {@link String}. * @param includeHeadlines If {@code true} will output the sentences marked * as news headlines. */ public ADSentenceSampleStream(ObjectStream lineStream, boolean includeHeadlines) { this.adSentenceStream = new ADSentenceStream(lineStream); ptEosCharacters = Factory.ptEosCharacters; Arrays.sort(ptEosCharacters); this.isIncludeTitles = includeHeadlines; } /** * Initializes a new {@link ADSentenceSampleStream}. * * @param in The {@link InputStreamFactory} for the corpus. * @param charsetName The {@link java.nio.charset.Charset charset} to use * for reading of the corpus. * @param includeHeadlines If {@code true} will output the sentences marked * as news headlines. * @throws IOException Thrown if IO errors occurred. */ public ADSentenceSampleStream(InputStreamFactory in, String charsetName, boolean includeHeadlines) throws IOException { this(new PlainTextByLineStream(in, charsetName), includeHeadlines); } // The Arvores Deitadas Corpus has information about texts and paragraphs. @Override public SentenceSample read() throws IOException { if (sent == null) { sent = this.adSentenceStream.read(); updateMeta(); if (sent == null) { return null; } } StringBuilder document = new StringBuilder(); List sentences = new ArrayList<>(); do { do { if (!isTitle || isIncludeTitles) { if (hasPunctuation(sent.text())) { int start = document.length(); document.append(sent.text()); sentences.add(new Span(start, document.length())); document.append(" "); } } sent = this.adSentenceStream.read(); updateMeta(); } while (isSamePara); // break; // got one paragraph! } while (isSameText); String doc; if (!document.isEmpty()) { doc = document.substring(0, document.length() - 1); } else { doc = document.toString(); } return new SentenceSample(doc, sentences.toArray(new Span[0])); } private boolean hasPunctuation(String text) { text = text.trim(); if (!text.isEmpty()) { char lastChar = text.charAt(text.length() - 1); return Arrays.binarySearch(ptEosCharacters, lastChar) >= 0; } return false; } // there are some different types of metadata depending on the corpus. // TODO Merge these patterns private static final Pattern META_1 = Pattern.compile("^(?:[a-zA-Z\\-]*(\\d+)).*?p=(\\d+).*"); private void updateMeta() { if (this.sent != null) { String meta = this.sent.metadata(); Matcher m = META_1.matcher(meta); int currentText; int currentPara; if (m.matches()) { currentText = Integer.parseInt(m.group(1)); currentPara = Integer.parseInt(m.group(2)); } else { throw new RuntimeException("Invalid metadata: " + meta); } isSamePara = isSameText = false; if (currentText == text) isSameText = true; if (isSameText && currentPara == para) isSamePara = true; isTitle = meta.contains("title"); text = currentText; para = currentPara; } else { this.isSamePara = this.isSameText = false; } } @Override public void reset() throws IOException, UnsupportedOperationException { adSentenceStream.reset(); } @Override public void close() throws IOException { adSentenceStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADSen0100644 0000000 0000000 00000000173 15217274217 032373 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADSentenceSampleStrea0100644 0000000 0000000 00000005223 15217274217 034005 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.nio.charset.Charset; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.LanguageSampleStreamFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class ADSentenceSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ParameterDescription(valueName = "charsetName", description = "encoding for reading and writing text.") Charset getEncoding(); @ParameterDescription(valueName = "language", description = "language which is being processed.") String getLang(); @ParameterDescription(valueName = "includeTitles", description = "if true will include sentences marked as headlines.") @OptionalParameter(defaultValue = "false") Boolean getIncludeTitles(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "ad", new ADSentenceSampleStreamFactory(Parameters.class)); } protected ADSentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); language = params.getLang(); boolean includeTitle = params.getIncludeTitles(); ObjectStream lineStream = readData(args, Parameters.class); return new ADSentenceSampleStream(lineStream, includeTitle); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADSen0100644 0000000 0000000 00000000156 15217274217 032374 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADSentenceStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADSentenceStream.java0100644 0000000 0000000 00000042753 15217274217 033751 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Internal; import opennlp.tools.formats.ad.ADSentenceStream.SentenceParser.Node; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Stream filter which merges text lines into sentences, following the Arvores * Deitadas syntax. *

* Information about the format:
* Susana Afonso. * * "�rvores deitadas: Descrição do formato e das opções de análise na Floresta Sintáctica". *
* 12 de Fevereiro de 2006. *

* Note: * Do not use this class, internal use only! */ @Internal public class ADSentenceStream extends FilterObjectStream { public record Sentence (String text, Node root, String metadata) { public static final String META_LABEL_FINAL = "final"; } /** * Parses a sample of AD corpus. A sentence in AD corpus is represented by a * Tree. In this class we declare some types to represent that tree. Today we get only * the first alternative (A1). */ public static class SentenceParser { private static final Logger logger = LoggerFactory.getLogger(SentenceParser.class); private static final Pattern NODE_PATTERN = Pattern .compile("([=-]*)([^:=]+:[^\\(\\s]+)(\\(([^\\)]+)\\))?\\s*(?:(\\((<.+>)\\))*)\\s*$"); private static final Pattern LEAF_PATTERN = Pattern .compile("^([=-]*)([^:=]+):([^\\(\\s]+)\\([\"'](.+)[\"']\\s*((?:<.+>)*)\\s*([^\\)]+)?\\)\\s+(.+)"); private static final Pattern BIZARRE_LEAF_PATTERN = Pattern .compile("^([=-]*)([^:=]+=[^\\(\\s]+)\\(([\"'].+[\"'])?\\s*([^\\)]+)?\\)\\s+(.+)"); private static final Pattern PUNCTUATION_PATTERN = Pattern.compile("^(=*)(\\W+)$"); private static final Pattern PUNCTUATION_DOT_PATTERN = Pattern.compile("\\»\\s+\\."); private static final Pattern PUNCTUATION_COMMA_PATTERN = Pattern.compile("\\»\\s+\\,"); private String text,meta; /** * Parses a sentence string into a {@link Sentence}. * * @param sentenceString The input string to parse. * @param isTitle {@code true} if it represents a title element, {@code false} otherwise. * @param para The parameter number. * @param isBox {@code true} if it represents a box element, {@code false} otherwise. * * @return A {@link Sentence} instance parsed from {@code sentenceString}. */ public Sentence parse(String sentenceString, int para, boolean isTitle, boolean isBox) { Sentence sentence; Node root = new Node(); try (BufferedReader reader = new BufferedReader(new StringReader(sentenceString))) { // first line is String line = reader.readLine(); boolean useSameTextAndMeta = false; // to handle cases where there are diff sug of parse (&&) // should find the source source while (!line.startsWith("SOURCE")) { if (line.equals("&&")) { // same sentence again! useSameTextAndMeta = true; break; } line = reader.readLine(); if (line == null) { return null; } } if (!useSameTextAndMeta) { // got source, get the metadata String metaFromSource = line.substring(7); line = reader.readLine(); // we should have the plain sentence // we remove the first token int start = line.indexOf(" "); text = line.substring(start + 1).trim(); text = fixPunctuation(text); String titleTag = ""; if (isTitle) titleTag = " title"; String boxTag = ""; if (isBox) boxTag = " box"; if (start > 0) { meta = line.substring(0, start) + " p=" + para + titleTag + boxTag + metaFromSource; } } sentence = new Sentence(text, root, meta); // now we look for the root node do { line = reader.readLine(); } while (line != null && line.startsWith("###")); // skip lines starting with ### // got the root. Add it to the stack Stack nodeStack = new Stack<>(); root.setSyntacticTag("ROOT"); root.setLevel(0); nodeStack.add(root); /* now we have to take care of the lastLevel. Every time it raises, we will add the leaf to the node at the top. If it decreases, we remove the top. */ while (line != null && line.length() != 0 && !line.startsWith("") && !line.equals("&&")) { TreeElement element = this.getElement(line); if (element != null) { // The idea here is to keep a stack of nodes that are candidates for // parenting the following elements (nodes and leafs). // 1) When we get a new element, we check its level and remove from // the top of the stack nodes that are brothers or nephews. while (!nodeStack.isEmpty() && element.getLevel() > 0 && element.getLevel() <= nodeStack.peek().getLevel()) { Node nephew = nodeStack.pop(); } if (element.isLeaf() ) { // 2a) If the element is a leaf and there is no parent candidate, // add it as a daughter of the root. if (nodeStack.isEmpty()) { root.addElement(element); } else { // 2b) There are parent candidates. // look for the node with the correct level Node peek = nodeStack.peek(); if (element.level == 0) { // add to the root nodeStack.firstElement().addElement(element); } else { Node parent = null; int index = nodeStack.size() - 1; while (parent == null) { if (peek.getLevel() < element.getLevel()) { parent = peek; } else { index--; if (index > -1) { peek = nodeStack.get(index); } else { parent = nodeStack.firstElement(); } } } parent.addElement(element); } } } else { // 3) Check if the element that is at the top of the stack is this // node parent, if yes add it as a son if (!nodeStack.isEmpty() && nodeStack.peek().getLevel() < element.getLevel()) { nodeStack.peek().addElement(element); } else { logger.warn("should not happen!"); } // 4) Add it to the stack so it is a parent candidate. nodeStack.push((Node) element); } } line = reader.readLine(); } } catch (Exception e) { logger.warn("Caught exception for the given sentence: '{}'", sentenceString, e); return null; } // second line should be SOURCE return sentence; } private String fixPunctuation(String text) { text = PUNCTUATION_DOT_PATTERN.matcher(text).replaceAll("»."); text = PUNCTUATION_COMMA_PATTERN.matcher(text).replaceAll("»,"); return text; } /** * Parse a tree element from a AD line * * @param line * the AD line * @return the tree element */ public TreeElement getElement(String line) { // Note: all levels are higher than 1, because 0 is reserved for the root. // try node Matcher nodeMatcher = NODE_PATTERN.matcher(line); if (nodeMatcher.matches()) { int level = nodeMatcher.group(1).length() + 1; String syntacticTag = nodeMatcher.group(2); Node node = new Node(); node.setLevel(level); node.setSyntacticTag(syntacticTag); return node; } Matcher leafMatcher = LEAF_PATTERN.matcher(line); if (leafMatcher.matches()) { int level = leafMatcher.group(1).length() + 1; String syntacticTag = leafMatcher.group(2); String funcTag = leafMatcher.group(3); String lemma = leafMatcher.group(4); String secondaryTag = leafMatcher.group(5); String morphologicalTag = leafMatcher.group(6); String lexeme = leafMatcher.group(7); Leaf leaf = new Leaf(); leaf.setLevel(level); leaf.setSyntacticTag(syntacticTag); leaf.setFunctionalTag(funcTag); leaf.setSecondaryTag(secondaryTag); leaf.setMorphologicalTag(morphologicalTag); leaf.setLexeme(lexeme); leaf.setLemma(lemma); return leaf; } Matcher punctuationMatcher = PUNCTUATION_PATTERN.matcher(line); if (punctuationMatcher.matches()) { int level = punctuationMatcher.group(1).length() + 1; String lexeme = punctuationMatcher.group(2); Leaf leaf = new Leaf(); leaf.setLevel(level); leaf.setLexeme(lexeme); return leaf; } // process the bizarre cases if (line.equals("_") || line.startsWith("].*")) { return null; } Leaf leaf = new Leaf(); leaf.setLevel(level + 1); leaf.setSyntacticTag(""); leaf.setMorphologicalTag(""); leaf.setFunctionalTag(""); leaf.setLexeme(lexeme); return leaf; } } logger.warn("Couldn't parse leaf: {}", line); Leaf leaf = new Leaf(); leaf.setLevel(1); leaf.setSyntacticTag(""); leaf.setMorphologicalTag(""); leaf.setFunctionalTag(""); leaf.setLexeme(line); return leaf; } /** Represents a tree element, Node or Leaf */ public abstract static class TreeElement { private String syntacticTag; private String morphologicalTag; private int level; public boolean isLeaf() { return false; } public void setSyntacticTag(String syntacticTag) { this.syntacticTag = syntacticTag; } public String getSyntacticTag() { return syntacticTag; } public void setLevel(int level) { this.level = level; } public int getLevel() { return level; } public void setMorphologicalTag(String morphologicalTag) { this.morphologicalTag = morphologicalTag; } public String getMorphologicalTag() { return morphologicalTag; } } /** Represents the AD node */ public static class Node extends TreeElement { private final List elems = new ArrayList<>(); public void addElement(TreeElement element) { elems.add(element); } public TreeElement[] getElements() { return elems.toArray(new TreeElement[0]); } @Override public String toString() { StringBuilder sb = new StringBuilder(); // print itself and its children sb.append("=".repeat(Math.max(0, this.getLevel()))); sb.append(this.getSyntacticTag()); if (this.getMorphologicalTag() != null) { sb.append(this.getMorphologicalTag()); } sb.append("\n"); for (TreeElement element : elems) { sb.append(element.toString()); } return sb.toString(); } } /** Represents the AD leaf */ public static class Leaf extends TreeElement { private String word; private String lemma; private String secondaryTag; private String functionalTag; @Override public boolean isLeaf() { return true; } public void setFunctionalTag(String funcTag) { this.functionalTag = funcTag; } public String getFunctionalTag() { return this.functionalTag; } public void setSecondaryTag(String secondaryTag) { this.secondaryTag = secondaryTag; } public String getSecondaryTag() { return this.secondaryTag; } public void setLexeme(String lexeme) { this.word = lexeme; } public String getLexeme() { return word; } private String emptyOrString(String value, String prefix, String suffix) { if (value == null) return ""; return prefix + value + suffix; } @Override public String toString() { StringBuilder sb = new StringBuilder(); // print itself and its children sb.append("=".repeat(Math.max(0, this.getLevel()))); if (this.getSyntacticTag() != null) { sb.append(this.getSyntacticTag()).append(":") .append(getFunctionalTag()).append("(") .append(emptyOrString(getLemma(), "'", "' ")) .append(emptyOrString(getSecondaryTag(), "", " ")) .append(this.getMorphologicalTag()).append(") "); } sb.append(this.word).append("\n"); return sb.toString(); } public void setLemma(String lemma) { this.lemma = lemma; } public String getLemma() { return lemma; } } } private static final Pattern SENT_START = Pattern.compile("]*>"); private static final Pattern SENT_END = Pattern.compile(""); private static final Pattern EXT_END = Pattern.compile(""); private static final Pattern TITLE_START = Pattern.compile("]*>"); private static final Pattern TITLE_END = Pattern.compile(""); private static final Pattern BOX_START = Pattern.compile("]*>"); private static final Pattern BOX_END = Pattern.compile(""); private static final Pattern PARA_START = Pattern.compile("]*>"); private static final Pattern TEXT_START = Pattern.compile("]*>"); private final SentenceParser parser; private int paraID = 0; private boolean isTitle = false; private boolean isBox = false; public ADSentenceStream(ObjectStream lineStream) { super(lineStream); parser = new SentenceParser(); } @Override public Sentence read() throws IOException { final StringBuilder sentence = new StringBuilder(); boolean sentenceStarted = false; while (true) { String line = samples.read(); if (line != null) { if (sentenceStarted) { if (SENT_END.matcher(line).matches() || EXT_END.matcher(line).matches()) { sentenceStarted = false; } else if (!line.startsWith("A1")) { sentence.append(line).append('\n'); } } else { if (SENT_START.matcher(line).matches()) { sentenceStarted = true; } else if (PARA_START.matcher(line).matches()) { paraID++; } else if (TITLE_START.matcher(line).matches()) { isTitle = true; } else if (TITLE_END.matcher(line).matches()) { isTitle = false; } else if (TEXT_START.matcher(line).matches()) { paraID = 0; } else if (BOX_START.matcher(line).matches()) { isBox = true; } else if (BOX_END.matcher(line).matches()) { isBox = false; } } if (!sentenceStarted && sentence.length() > 0) { return parser.parse(sentence.toString(), paraID, isTitle, isBox); } } else { // handle end of file if (sentenceStarted) { if (sentence.length() > 0) { return parser.parse(sentence.toString(), paraID, isTitle, isBox); } } else { return null; } } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_ADTok0100644 0000000 0000000 00000000170 15217274217 032400 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/ADTokenSampleStreamFa0100644 0000000 0000000 00000004370 15217274217 033747 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.formats.convert.NameToTokenSampleStream; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class ADTokenSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends ADNameSampleStreamFactory.Parameters, DetokenizerParameter { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, "ad", new ADTokenSampleStreamFactory(Parameters.class)); } protected ADTokenSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream samples = StreamFactoryRegistry.getFactory( NameSample.class, "ad").create( ArgumentParser.filter(args, ADNameSampleStreamFactory.Parameters.class)); return new NameToTokenSampleStream(createDetokenizer(params), samples); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ad_Portu0100644 0000000 0000000 00000000172 15217274217 032551 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/PortugueseContractionUtility.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/PortugueseContraction0100644 0000000 0000000 00000015712 15217274217 034245 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ad; import java.util.Collections; import java.util.HashMap; import java.util.Map; import opennlp.tools.commons.Internal; import opennlp.tools.util.StringUtil; /** * Utility class to handle Portuguese contractions. *

* Some Corpora split contractions in its parts, for example, "da" > "de" + * "a", but according to the phase of language processing, NER for instance, we * can't decide if to split a contraction or not, specially because contractions * inside names are not separated, but outside are. * *

* Note: * Do not use this class, internal use only! */ @Internal public class PortugueseContractionUtility { protected static final Map CONTRACTIONS; private static final String SYMBOL_PLUS = "+"; static { Map elems = new HashMap<>(); // 103 CONTRACTIONS. elems.put("a+a", "\u00e0"); elems.put("a+as", "\u00e0s"); elems.put("a+aquele", "\u00e0quele"); elems.put("a+aqueles", "\u00e0queles"); elems.put("a+aquela", "\u00e0quela"); elems.put("a+aquelas", "\u00e0quelas"); elems.put("a+aquilo", "\u00e0quilo"); elems.put("a+o", "ao"); elems.put("a+os", "aos"); elems.put("com+mim", "comigo"); elems.put("com+n\u00f2s", "conosco"); elems.put("com+si", "consigo"); elems.put("com+ti", "contigo"); elems.put("com+v\u00f2s", "convosco"); elems.put("de+a\u00ed", "da\u00ed"); elems.put("de+algu\u00e9m", "dalgu\u00e9m"); elems.put("de+algum", "dalgum"); elems.put("de+alguma", "dalguma"); elems.put("de+alguns", "dalguns"); elems.put("de+algumas", "dalgumas"); elems.put("de+ali", "dali"); elems.put("de+aqu\u00e9m", "daqu\u00e9m"); elems.put("de+aquele", "daquele"); elems.put("de+aquela", "daquela"); elems.put("de+aqueles", "daqueles"); elems.put("de+aquelas", "daquelas"); elems.put("de+aqui", "daqui"); elems.put("de+aquilo", "daquilo"); elems.put("de+ele", "dele"); elems.put("de+ela", "dela"); elems.put("de+eles", "deles"); elems.put("de+elas", "delas"); elems.put("de+entre", "dentre"); elems.put("de+esse", "desse"); elems.put("de+essa", "dessa"); elems.put("de+esses", "desses"); elems.put("de+essas", "dessas"); elems.put("de+este", "deste"); elems.put("de+esta", "desta"); elems.put("de+estes", "destes"); elems.put("de+estas", "destas"); elems.put("de+isso", "disso"); elems.put("de+isto", "disto"); elems.put("de+o", "do"); elems.put("de+a", "da"); elems.put("de+os", "dos"); elems.put("de+as", "das"); elems.put("de+outrem", "doutrem"); elems.put("de+outro", "doutro"); elems.put("de+outra", "doutra"); elems.put("de+outros", "doutros"); elems.put("de+outras", "doutras"); elems.put("de+um", "dum"); elems.put("de+uma", "duma"); elems.put("de+uns", "duns"); elems.put("de+umas", "dumas"); elems.put("esse+outro", "essoutro"); elems.put("essa+outra", "essoutra"); elems.put("este+outro", "estoutro"); elems.put("este+outra", "estoutra"); elems.put("ele+o", "lho"); elems.put("ele+a", "lha"); elems.put("ele+os", "lhos"); elems.put("ele+as", "lhas"); elems.put("em+algum", "nalgum"); elems.put("em+alguma", "nalguma"); elems.put("em+alguns", "nalguns"); elems.put("em+algumas", "nalgumas"); elems.put("em+aquele", "naquele"); elems.put("em+aquela", "naquela"); elems.put("em+aqueles", "naqueles"); elems.put("em+aquelas", "naquelas"); elems.put("em+aquilo", "naquilo"); elems.put("em+ele", "nele"); elems.put("em+ela", "nela"); elems.put("em+eles", "neles"); elems.put("em+elas", "nelas"); elems.put("em+esse", "nesse"); elems.put("em+essa", "nessa"); elems.put("em+esses", "nesses"); elems.put("em+essas", "nessas"); elems.put("em+este", "neste"); elems.put("em+esta", "nesta"); elems.put("em+estes", "nestes"); elems.put("em+estas", "nestas"); elems.put("em+isso", "nisso"); elems.put("em+isto", "nisto"); elems.put("em+o", "no"); elems.put("em+a", "na"); elems.put("em+os", "nos"); elems.put("em+as", "nas"); elems.put("em+outro", "noutro"); elems.put("em+outra", "noutra"); elems.put("em+outros", "noutros"); elems.put("em+outras", "noutras"); elems.put("em+um", "num"); elems.put("em+uma", "numa"); elems.put("em+uns", "nuns"); elems.put("em+umas", "numas"); elems.put("por+o", "pelo"); elems.put("por+a", "pela"); elems.put("por+os", "pelos"); elems.put("por+as", "pelas"); elems.put("para+a", "pra"); elems.put("para+o", "pro"); elems.put("para+as", "pras"); elems.put("para+os", "pros"); CONTRACTIONS = Collections.unmodifiableMap(elems); } /** * Merges a contraction. * * @param left The left component. * @param right The right component. * @return The merged contraction. */ public static String toContraction(String left, String right) { String key = left + SYMBOL_PLUS + right; if (CONTRACTIONS.containsKey(key)) { return CONTRACTIONS.get(key); } else { StringBuilder sb = new StringBuilder(); String[] parts = left.split("_"); for (int i = 0; i < parts.length - 1; i++) { sb.append(parts[i]).append(" "); } key = parts[parts.length - 1] + SYMBOL_PLUS + right; if (CONTRACTIONS.containsKey(key)) { sb.append(CONTRACTIONS.get(key)); return sb.toString(); } if (right.contains("_")) { parts = right.split("_"); key = left + SYMBOL_PLUS + parts[0]; if (CONTRACTIONS.containsKey(key)) { sb.append(CONTRACTIONS.get(key)).append(" "); for (int i = 1; i < parts.length; i++) { sb.append(parts[i]).append(" "); } return sb.toString(); } } String leftLower = StringUtil.toLowerCase(parts[parts.length - 1]); key = leftLower + SYMBOL_PLUS + right; if (CONTRACTIONS.containsKey(key)) { String r = CONTRACTIONS.get(key); String firstChar = r.substring(0, 1); r = StringUtil.toUpperCase(firstChar) + r.substring(1); sb.append(r); return sb.toString(); } } return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ad/package-info.java0100644 0000000 0000000 00000001633 15217274217 033140 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the {@code Arvores Deitadas corpus} format. */ package opennlp.tools.formats.ad; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Ann0100644 0000000 0000000 00000000167 15217274217 032524 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/AnnotationConfiguration.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/AnnotationConfigura0100644 0000000 0000000 00000012504 15217274217 034207 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import opennlp.tools.tokenize.WhitespaceTokenizer; /** * Encapsulates a type to class mapping for entities, relations, events, etc. *

* Details on how a annotation configuration file should be structured can be found * in the brat annotation configuration * section of the official BRAT documentation. */ public class AnnotationConfiguration { public static final String SPAN_TYPE = "Span"; public static final String ENTITY_TYPE = "Entity"; public static final String RELATION_TYPE = "Relation"; public static final String ATTRIBUTE_TYPE = "Attribute"; public static final String EVENT_TYPE = "Event"; private static final String SYMBOL_HASH = "#"; private static final String BRACKET_OPEN = "["; private static final String BRACKET_CLOSE = "]"; private final Map typeToClassMap; /** * Initializes an {@link AnnotationConfiguration} with the specified {@code typeToClassMap}. * @param typeToClassMap A type to class mapping. Must not be {@code null}. */ public AnnotationConfiguration(Map typeToClassMap) { this.typeToClassMap = Map.copyOf(typeToClassMap); } /** * @param type The type to get the type class for. * @return Retrieves the class for the specified {@code type}, {@code null} if not found. */ public String getTypeClass(String type) { return typeToClassMap.get(type); } /** * Parses a given {@link File annConfigFile} into a {@link AnnotationConfiguration}. * * @param in A valid {@link File annConfigFile} from which the config should * be read. Must not be {@code null} and must be in the correct format, * see: * Brat annotation configuration * * @return A valid {@link AnnotationConfiguration} instance. * @throws IOException Thrown if IO errors occurred during parsing. */ public static AnnotationConfiguration parse(InputStream in) throws IOException { Map typeToClassMap = new HashMap<>(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { // Note: This only supports entities and relations section String line; String sectionType = null; while ((line = reader.readLine()) != null) { line = line.trim(); if (!line.isEmpty()) { if (!line.startsWith(SYMBOL_HASH)) { if (line.startsWith(BRACKET_OPEN) && line.endsWith(BRACKET_CLOSE)) { sectionType = line.substring(line.indexOf('[') + 1, line.indexOf(']')); } else { String typeName = WhitespaceTokenizer.INSTANCE.tokenize(line)[0]; switch (sectionType) { case "entities": typeToClassMap.put(typeName, AnnotationConfiguration.ENTITY_TYPE); break; case "relations": typeToClassMap.put(typeName, AnnotationConfiguration.RELATION_TYPE); break; case "attributes": typeToClassMap.put(typeName, AnnotationConfiguration.ATTRIBUTE_TYPE); break; case "events": typeToClassMap.put(typeName, AnnotationConfiguration.EVENT_TYPE); break; default: break; } } } } } } return new AnnotationConfiguration(typeToClassMap); } /** * Parses a given {@link File annConfigFile} into a {@link AnnotationConfiguration}. * * @param annConfigFile A valid {@link File annConfigFile} from which the config should * be read. Must not be {@code null} and must be in the correct format, * see: * Brat annotation configuration * * @return A valid {@link AnnotationConfiguration} instance. * @throws IOException Thrown if IO errors occurred during parsing. */ public static AnnotationConfiguration parse(File annConfigFile) throws IOException { return parse(new BufferedInputStream(new FileInputStream(annConfigFile))); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Ann0100644 0000000 0000000 00000000167 15217274217 032524 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/AnnotatorNoteAnnotation.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/AnnotatorNoteAnnota0100644 0000000 0000000 00000002245 15217274217 034174 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; public class AnnotatorNoteAnnotation extends BratAnnotation { private final String attachedId; protected AnnotatorNoteAnnotation(String id, String attachedId, String note) { super(id, "#AnnotationNote"); this.attachedId = attachedId; this.setNote(note); } public String getAttachedId() { return attachedId; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Att0100644 0000000 0000000 00000000163 15217274217 032534 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/AttributeAnnotation.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/AttributeAnnotation0100644 0000000 0000000 00000002557 15217274217 034244 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; public class AttributeAnnotation extends BratAnnotation { private final String attachedTo; private final String value; protected AttributeAnnotation(String id, String type, String attachedTo, String value) { super(id, type); this.attachedTo = attachedTo; this.value = value; } public String getAttachedTo() { return attachedTo; } public String getValue() { return value; } @Override public String toString() { return super.toString() + " " + attachedTo + (value != null ? " " + value : ""); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Bra0100644 0000000 0000000 00000000156 15217274217 032512 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratAnnotation.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratAnnotation.java0100644 0000000 0000000 00000002671 15217274217 034106 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.util.Objects; public abstract class BratAnnotation { private final String id; private final String type; private String note; protected BratAnnotation(String id, String type) { this.id = Objects.requireNonNull(id); this.type = Objects.requireNonNull(type); this.note = ""; } public String getId() { return id; } public String getType() { return type; } public void setNote(String note) { this.note = note; } public String getNote() { return note; } @Override public String toString() { return (id + " " + type + " " + note).trim(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Bra0100644 0000000 0000000 00000000164 15217274217 032511 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratAnnotationStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratAnnotationStrea0100644 0000000 0000000 00000022377 15217274217 034172 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * Reads the annotations from the brat {@code .ann} annotation file. */ public class BratAnnotationStream implements ObjectStream { static abstract class BratAnnotationParser { static final int ID_OFFSET = 0; static final int TYPE_OFFSET = 1; static final String NOTES_TYPE = "AnnotatorNotes"; BratAnnotation parse(Span[] tokens, CharSequence line) throws IOException { return null; } protected int parseInt(String intString) throws InvalidFormatException { try { return Integer.parseInt(intString); } catch (NumberFormatException e) { throw new InvalidFormatException(e); } } } static class SpanAnnotationParser extends BratAnnotationParser { private static final int BEGIN_OFFSET = 2; private static final int END_OFFSET = 3; @Override BratAnnotation parse(Span[] values, CharSequence line) throws IOException { if (values.length > 4) { String type = values[BratAnnotationParser.TYPE_OFFSET].getCoveredText(line).toString(); int firstTextTokenIndex = -1; int beginIndex = parseInt(values[BEGIN_OFFSET].getCoveredText(line).toString()); List fragments = new ArrayList<>(); for (int i = END_OFFSET; i < values.length; i++) { int endOffset; int nextBeginOffset = -1; if (values[i].getCoveredText(line).toString().contains(";")) { String[] parts = values[i].getCoveredText(line).toString().split(";"); endOffset = parseInt(parts[0]); fragments.add(new Span(beginIndex, endOffset, type)); beginIndex = parseInt(parts[1]); } else { endOffset = parseInt(values[i].getCoveredText(line).toString()); firstTextTokenIndex = i + 1; fragments.add(new Span(beginIndex, endOffset, type)); break; } } String id = values[BratAnnotationParser.ID_OFFSET].getCoveredText(line).toString(); String coveredText = line.subSequence(values[firstTextTokenIndex].getStart(), values[values.length - 1].getEnd()).toString(); try { return new SpanAnnotation(id, type, fragments.toArray(new Span[0]), coveredText); } catch (IllegalArgumentException e) { throw new InvalidFormatException(e); } } else { throw new InvalidFormatException("Line must have at least 5 fields"); } } } static class RelationAnnotationParser extends BratAnnotationParser { private static final int ARG1_OFFSET = 2; private static final int ARG2_OFFSET = 3; private String parseArg(String arg) throws InvalidFormatException { if (arg.length() > 4) { return arg.substring(5).trim(); } else { throw new InvalidFormatException("Failed to parse argument: " + arg); } } @Override BratAnnotation parse(Span[] tokens, CharSequence line) throws IOException { return new RelationAnnotation(tokens[BratAnnotationParser.ID_OFFSET].getCoveredText(line).toString(), tokens[BratAnnotationParser.TYPE_OFFSET].getCoveredText(line).toString(), parseArg(tokens[ARG1_OFFSET].getCoveredText(line).toString()), parseArg(tokens[ARG2_OFFSET].getCoveredText(line).toString())); } } static class EventAnnotationParser extends BratAnnotationParser { @Override BratAnnotation parse(Span[] tokens, CharSequence line) throws IOException { String[] typeParts = tokens[TYPE_OFFSET].getCoveredText(line).toString().split(":"); if (typeParts.length != 2) { throw new InvalidFormatException(String.format( "Failed to parse [%s], type part must be in the format type:trigger", line)); } String type = typeParts[0]; String eventTrigger = typeParts[1]; Map arguments = new HashMap<>(); for (int i = TYPE_OFFSET + 1; i < tokens.length; i++) { String[] parts = tokens[i].getCoveredText(line).toString().split(":"); if (parts.length != 2) { throw new InvalidFormatException(String.format( "Failed to parse [%s], argument parts must be in form argument:value", line)); } arguments.put(parts[0], parts[1]); } return new EventAnnotation(tokens[ID_OFFSET].getCoveredText(line).toString(),type, eventTrigger, arguments); } } static class AttributeAnnotationParser extends BratAnnotationParser { private static final int ATTACHED_TO_OFFSET = 2; private static final int VALUE_OFFSET = 3; @Override BratAnnotation parse(Span[] values, CharSequence line) throws IOException { if (values.length == 3 || values.length == 4) { String value = null; if (values.length == 4) { value = values[VALUE_OFFSET].getCoveredText(line).toString(); } return new AttributeAnnotation(values[ID_OFFSET].getCoveredText(line).toString(), values[TYPE_OFFSET].getCoveredText(line).toString(), values[ATTACHED_TO_OFFSET].getCoveredText(line).toString(), value); } else { throw new InvalidFormatException("Line must have 3 or 4 fields"); } } } static class AnnotatorNoteParser extends BratAnnotationParser { private static final int ATTACH_TO_OFFSET = 2; private static final int START_VALUE_OFFSET = 3; @Override BratAnnotation parse(Span[] tokens, CharSequence line) throws IOException { Span noteSpan = new Span( tokens[START_VALUE_OFFSET].getStart(), tokens[tokens.length - 1].getEnd() ); return new AnnotatorNoteAnnotation(tokens[ID_OFFSET].getCoveredText(line).toString(), tokens[ATTACH_TO_OFFSET].getCoveredText(line).toString(), noteSpan.getCoveredText(line).toString()); } } private final AnnotationConfiguration config; private final BufferedReader reader; private final String id; BratAnnotationStream(AnnotationConfiguration config, String id, InputStream in) { this.config = config; this.id = id; reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); } @Override public BratAnnotation read() throws IOException { String line = reader.readLine(); if (line != null) { Span[] tokens = WhitespaceTokenizer.INSTANCE.tokenizePos(line); if (tokens.length > 2) { String annId = tokens[BratAnnotationParser.ID_OFFSET].getCoveredText(line).toString(); if (annId.length() == 0) { throw new InvalidFormatException("annotation id is empty"); } // The first letter of the annotation id marks the annotation type final BratAnnotationParser parser; switch (annId.charAt(0)) { case 'T': parser = new SpanAnnotationParser(); break; case 'R': parser = new RelationAnnotationParser(); break; case 'A': parser = new AttributeAnnotationParser(); break; case 'E': parser = new EventAnnotationParser(); break; case '#': // the # can be a Note or a comment... if a note, handle it, otherwise skip the unsupported type.. if ( tokens[BratAnnotationParser.TYPE_OFFSET].getCoveredText(line).toString().equals( BratAnnotationParser.NOTES_TYPE) ) { parser = new AnnotatorNoteParser(); } else { return read(); } break; default: // Skip it, do that for everything unsupported (e.g. "*" id) return read(); } try { return parser.parse(tokens, line); } catch (IOException e) { throw new IOException(String.format("Failed to parse ann document with id [%s.ann]", id), e); } } } return null; } @Override public void reset() throws IOException, UnsupportedOperationException { reader.reset(); } @Override public void close() throws IOException { reader.close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratDocument.java0100644 0000000 0000000 00000007550 15217274217 033553 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import opennlp.tools.util.ObjectStream; /** * Brat (brat rapid annotation tool) is based on the stav visualiser * which was originally made in order to visualise BioNLP'11 Shared Task data. *

* Data can be found on this * web site. *

* Information about the format are found on this * web site. */ public class BratDocument { private final AnnotationConfiguration config; private final String id; private final String text; private final Map annotationMap; public BratDocument(AnnotationConfiguration config, String id, String text, Collection annotations) { this.config = config; this.id = id; this.text = text; Map annMap = new HashMap<>(); List noteList = new ArrayList<>(); for (BratAnnotation annotation : annotations) { if (annotation instanceof AnnotatorNoteAnnotation) { noteList.add((AnnotatorNoteAnnotation)annotation); } else { annMap.put(annotation.getId(), annotation); } } // attach AnnotatorNote to the appropriate Annotation. // the note should ALWAYS have an appropriate id in the map, // but just to be safe, check for null. for (AnnotatorNoteAnnotation note: noteList) { BratAnnotation annotation = annMap.get(note.getAttachedId()); if (annotation != null) { annotation.setNote(note.getNote()); } } annotationMap = Collections.unmodifiableMap(annMap); } public AnnotationConfiguration getConfig() { return config; } public String getId() { return id; } public String getText() { return text; } public BratAnnotation getAnnotation(String id) { return annotationMap.get(id); } public Collection getAnnotations() { return annotationMap.values(); } public static BratDocument parseDocument(AnnotationConfiguration config, String id, InputStream txtIn, InputStream annIn) throws IOException { try (Reader txtReader = new InputStreamReader(txtIn, StandardCharsets.UTF_8); ObjectStream annStream = new BratAnnotationStream(config, id, annIn)) { StringBuilder text = new StringBuilder(); char[] cbuf = new char[1024]; int len; while ((len = txtReader.read(cbuf)) > 0) { text.append(cbuf, 0, len); } Collection annotations = new ArrayList<>(); BratAnnotation ann; while ((ann = annStream.read()) != null) { annotations.add(ann); } return new BratDocument(config, id, text.toString(), annotations); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Bra0100644 0000000 0000000 00000000162 15217274217 032507 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratDocumentParser.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratDocumentParser.0100644 0000000 0000000 00000015353 15217274217 034066 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.namefind.NameSample; import opennlp.tools.sentdetect.SentenceDetector; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.util.Span; public class BratDocumentParser { private static final Logger logger = LoggerFactory.getLogger(BratDocumentParser.class); private final SentenceDetector sentDetector; private final Tokenizer tokenizer; private final Set nameTypes; public BratDocumentParser(SentenceDetector sentenceDetector, Tokenizer tokenizer) { this(sentenceDetector, tokenizer, null); } public BratDocumentParser(SentenceDetector sentenceDetector, Tokenizer tokenizer, Set nameTypes) { if (nameTypes != null && nameTypes.size() == 0) { throw new IllegalArgumentException("nameTypes should be null or have one or more elements"); } this.sentDetector = sentenceDetector; this.tokenizer = tokenizer; this.nameTypes = nameTypes; } public List parse(BratDocument sample) { // Note: Some entities might not match sentence boundaries, // to be able to print warning a set of entities id must be maintained // to check if all entities have been used up after the matching is done Set entityIdSet = new HashSet<>(); Map coveredIndexes = new HashMap<>(); for (BratAnnotation ann : sample.getAnnotations()) { if (isSpanAnnotation(ann)) { entityIdSet.add(ann.getId()); for (Span span : ((SpanAnnotation) ann).getSpans()) { for (int i = span.getStart(); i < span.getEnd(); i++) { coveredIndexes.put(i, span); } } } } // Map spans to tokens, and merge fragments based on token // // Detect sentence and correct sentence spans assuming no split can be inside a name annotation List sentences = new ArrayList<>(); for (Span sentence : sentDetector.sentPosDetect(sample.getText())) { Span conflictingName = coveredIndexes.get(sentence.getStart()); if (sentences.size() > 0 && conflictingName != null && conflictingName.getStart() < sentence.getStart()) { Span lastSentence = sentences.remove(sentences.size() - 1); sentences.add(new Span(lastSentence.getStart(), sentence.getEnd())); logger.info("Correcting sentence segmentation in document {}", sample.getId()); } else { sentences.add(sentence); } } // TODO: Token breaks should be enforced on name span boundaries // a) Just split tokens // b) Implement a custom token split validator which can be injected into the Tokenizer // Currently we are missing all List samples = new ArrayList<>(sentences.size()); for (Span sentence : sentences) { String sentenceText = sentence.getCoveredText( sample.getText()).toString(); Span[] tokens = tokenizer.tokenizePos(sentenceText); // Note: // A begin and end token index can be identical, but map to different // tokens, to distinguish between between the two begin indexes are // stored with a negative sign, and end indexes are stored with a positive sign // in the tokenIndexMap. // The tokenIndexMap maps to the sentence local token index. Map tokenIndexMap = new HashMap<>(); for (int i = 0; i < tokens.length; i++) { tokenIndexMap.put(-(sentence.getStart() + tokens[i].getStart()), i); tokenIndexMap.put(sentence.getStart() + tokens[i].getEnd(), i + 1); } List names = new ArrayList<>(); for (BratAnnotation ann : sample.getAnnotations()) { if (isSpanAnnotation(ann)) { SpanAnnotation entity = (SpanAnnotation) ann; List mappedFragments = new ArrayList<>(); for (Span entitySpan : entity.getSpans()) { if (sentence.contains(entitySpan)) { entityIdSet.remove(ann.getId()); entitySpan = entitySpan.trim(sample.getText()); Integer nameBeginIndex = tokenIndexMap.get(-entitySpan.getStart()); Integer nameEndIndex = tokenIndexMap.get(entitySpan.getEnd()); if (nameBeginIndex != null && nameEndIndex != null) { mappedFragments.add(new Span(nameBeginIndex, nameEndIndex, entity.getType())); } else { logger.warn("Dropped entity {} ({}) in document {} as it is not matching " + "tokenization!", entity.getId(), entitySpan.getCoveredText(sample.getText()), sample.getId()); } } } Collections.sort(mappedFragments); for (int i = 1; i < mappedFragments.size(); i++) { if (mappedFragments.get(i - 1).getEnd() == mappedFragments.get(i).getStart()) { mappedFragments.set(i, new Span(mappedFragments.get(i - 1).getStart(), mappedFragments.get(i).getEnd(), mappedFragments.get(i).getType())); mappedFragments.set(i - 1, null); } } for (Span span : mappedFragments) { if (span != null ) { names.add(span); } } } } samples.add(new NameSample(sample.getId(), Span.spansToStrings(tokens, sentenceText), names.toArray(new Span[0]), null, samples.size() == 0)); } for (String id : entityIdSet) { logger.warn("Dropped entity {} in document {}" + ", is not matching sentence segmentation!", id, sample.getId()); } return samples; } private boolean isSpanAnnotation(BratAnnotation ann) { return ann instanceof SpanAnnotation && (nameTypes == null || nameTypes.contains(ann.getType())); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Bra0100644 0000000 0000000 00000000162 15217274217 032507 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratDocumentStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratDocumentStream.0100644 0000000 0000000 00000007727 15217274217 034073 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.io.BufferedInputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Stack; import opennlp.tools.util.ObjectStream; public class BratDocumentStream implements ObjectStream { private static final String SUFFIX_ANN = ".ann"; private static final String SUFFIX_TXT = ".txt"; private final AnnotationConfiguration config; private List documentIds = new LinkedList<>(); private Iterator documentIdIterator; /** * Creates a {@link BratDocumentStream} which reads the documents from the given input directory. * * @param config the annotation.conf from the brat project as an Annotation Configuration object * @param bratCorpusDirectory the directory containing all the brat training data files * @param searchRecursive specifies if the corpus directory should be traversed recursively * to find training data files. * @param fileFilter a custom file filter to filter out certain files or null to accept all files * * @throws IOException if reading from the brat directory fails in any way. */ public BratDocumentStream(AnnotationConfiguration config, File bratCorpusDirectory, boolean searchRecursive, FileFilter fileFilter) throws IOException { if (!bratCorpusDirectory.isDirectory()) { throw new IOException("Input corpus directory must be a directory " + "according to File.isDirectory()!"); } this.config = config; Stack directoryStack = new Stack<>(); directoryStack.add(bratCorpusDirectory); while (!directoryStack.isEmpty()) { final File[] files = directoryStack.pop().listFiles(fileFilter); Arrays.sort(files); for (File file : files) { if (file.isFile()) { String annFilePath = file.getAbsolutePath(); if (annFilePath.endsWith(SUFFIX_ANN)) { // cutoff last 4 chars ... String documentId = annFilePath.substring(0, annFilePath.length() - 4); File txtFile = new File(documentId + SUFFIX_TXT); if (txtFile.exists() && txtFile.isFile()) { documentIds.add(documentId); } } } else if (searchRecursive && file.isDirectory()) { directoryStack.push(file); } } } reset(); } @Override public BratDocument read() throws IOException { BratDocument doc = null; if (documentIdIterator.hasNext()) { String id = documentIdIterator.next(); try (InputStream txtIn = new BufferedInputStream(new FileInputStream(id + SUFFIX_TXT)); InputStream annIn = new BufferedInputStream(new FileInputStream(id + SUFFIX_ANN))) { doc = BratDocument.parseDocument(config, id, txtIn, annIn); } } return doc; } @Override public void reset() { documentIdIterator = documentIds.iterator(); } @Override public void close() { // No longer needed, make the object unusable documentIds = null; documentIdIterator = null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Bra0100644 0000000 0000000 00000000164 15217274217 032511 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratNameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratNameSampleStrea0100644 0000000 0000000 00000007701 15217274217 034074 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.io.IOException; import java.util.List; import java.util.Set; import opennlp.tools.namefind.NameSample; import opennlp.tools.sentdetect.SentenceDetector; import opennlp.tools.sentdetect.SentenceDetectorME; import opennlp.tools.sentdetect.SentenceModel; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.tokenize.TokenizerME; import opennlp.tools.tokenize.TokenizerModel; import opennlp.tools.util.ObjectStream; /** * Generates Name Sample objects for a Brat Document object. */ public class BratNameSampleStream extends SegmenterObjectStream { private final BratDocumentParser parser; /** * Initializes a new {@link BratNameSampleStream} with the specified parameters * based on a straem of {@link BratDocument documents}. * * @param sentDetector A valid {@link SentenceDetector} instance. * @param tokenizer A valid {@link Tokenizer} instance. * @param samples The {@link BratDocument} {@link ObjectStream} to process. */ public BratNameSampleStream(SentenceDetector sentDetector, Tokenizer tokenizer, ObjectStream samples) { this(sentDetector, tokenizer, samples, null); } /** * Initializes a new {@link BratNameSampleStream} with the specified (model) parameters. * * @param sentModel A valid {@link SentenceModel sentence detection model}. * @param tokenModel A valid {@link TokenizerModel tokenizer model}. * @param samples The {@link BratDocument} {@link ObjectStream} to process. */ public BratNameSampleStream(SentenceModel sentModel, TokenizerModel tokenModel, ObjectStream samples) { this(new SentenceDetectorME(sentModel), new TokenizerME(tokenModel), samples, null); } /** * Creates a new {@link BratNameSampleStream}. * @param sentDetector A valid {@link SentenceDetector} instance. * @param tokenizer A valid {@link Tokenizer} instance. * @param samples The {@link BratDocument} {@link ObjectStream} to process. * * @param nameTypes the name types to use or {@code null} if all name types. */ public BratNameSampleStream(SentenceDetector sentDetector, Tokenizer tokenizer, ObjectStream samples, Set nameTypes) { super(samples); this.parser = new BratDocumentParser(sentDetector, tokenizer, nameTypes); } /** * Creates a new {@link BratNameSampleStream}. * @param sentModel a {@link SentenceModel} model * @param tokenModel a {@link TokenizerModel} model * @param samples a {@link BratDocument} {@link ObjectStream} * @param nameTypes the name types to use or {@code null} if all name types */ public BratNameSampleStream(SentenceModel sentModel, TokenizerModel tokenModel, ObjectStream samples, Set nameTypes) { super(samples); // Hint: We can pass in custom validators here ... this.parser = new BratDocumentParser(new SentenceDetectorME(sentModel), new TokenizerME(tokenModel), nameTypes); } @Override protected List read(BratDocument sample) throws IOException { return parser.parse(sample); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Bra0100644 0000000 0000000 00000000173 15217274217 032511 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratNameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/BratNameSampleStrea0100644 0000000 0000000 00000013713 15217274217 034074 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.namefind.NameSample; import opennlp.tools.sentdetect.NewlineSentenceDetector; import opennlp.tools.sentdetect.SentenceDetector; import opennlp.tools.sentdetect.SentenceDetectorME; import opennlp.tools.sentdetect.SentenceModel; import opennlp.tools.tokenize.SimpleTokenizer; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.tokenize.TokenizerME; import opennlp.tools.tokenize.TokenizerModel; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see BratNameSampleStream */ public class BratNameSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters { @ParameterDescription(valueName = "bratDataDir", description = "location of brat data dir") File getBratDataDir(); @ParameterDescription(valueName = "annConfFile") File getAnnotationConfig(); @ParameterDescription(valueName = "modelFile") @OptionalParameter File getSentenceDetectorModel(); @ParameterDescription(valueName = "modelFile") @OptionalParameter File getTokenizerModel(); @ParameterDescription(valueName = "name") @OptionalParameter String getRuleBasedTokenizer(); @ParameterDescription(valueName = "value") @OptionalParameter(defaultValue = "false") Boolean getRecursive(); @ParameterDescription(valueName = "names") @OptionalParameter String getNameTypes(); } protected BratNameSampleStreamFactory() { super(Parameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "brat", new BratNameSampleStreamFactory()); } /** * Checks that non of the passed values are {@code null}. * * @param objects The objects to check for {@code null}. * @return {@code true} if at least one object is {@code null}, {@code false} otherwise. */ private boolean notNull(Object... objects) { for (Object obj : objects) { if (obj == null) return false; } return true; } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); if (notNull(params.getRuleBasedTokenizer(), params.getTokenizerModel())) { throw new TerminateToolException(-1, "Either use rule based or statistical tokenizer!"); } AnnotationConfiguration annConfig; try { annConfig = AnnotationConfiguration.parse(params.getAnnotationConfig()); } catch (IOException e) { throw new TerminateToolException(1, "Failed to parse annotation.conf file!"); } // TODO: Add an optional parameter to search recursive // TODO: How to handle the error here ? terminate the tool? not nice if used by API! ObjectStream samples; try { samples = new BratDocumentStream(annConfig, params.getBratDataDir(), params.getRecursive(), null); } catch (IOException e) { throw new TerminateToolException(-1, e.getMessage()); } SentenceDetector sentDetector; if (params.getSentenceDetectorModel() != null) { try { sentDetector = new SentenceDetectorME(new SentenceModel(params.getSentenceDetectorModel())); } catch (IOException e) { throw new TerminateToolException(-1, "Failed to load sentence detector model!", e); } } else { sentDetector = new NewlineSentenceDetector(); } Tokenizer tokenizer = WhitespaceTokenizer.INSTANCE; if (params.getTokenizerModel() != null) { try { tokenizer = new TokenizerME(new TokenizerModel(params.getTokenizerModel())); } catch (IOException e) { throw new TerminateToolException(-1, "Failed to load tokenizer model!", e); } } else if (params.getRuleBasedTokenizer() != null) { String tokenizerName = params.getRuleBasedTokenizer(); if ("simple".equals(tokenizerName)) { tokenizer = SimpleTokenizer.INSTANCE; } else if ("whitespace".equals(tokenizerName)) { tokenizer = WhitespaceTokenizer.INSTANCE; } else { throw new TerminateToolException(-1, "Unknown tokenizer: " + tokenizerName); } } Set nameTypes = null; if (params.getNameTypes() != null) { String[] nameTypesArr = params.getNameTypes().split(","); if (nameTypesArr.length > 0) { nameTypes = Arrays.stream(nameTypesArr).map(String::trim).collect(Collectors.toSet()); } } return new BratNameSampleStream(sentDetector, tokenizer, samples, nameTypes); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Eve0100644 0000000 0000000 00000000157 15217274217 032526 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/EventAnnotation.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/EventAnnotation.jav0100644 0000000 0000000 00000002577 15217274217 034143 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.util.Map; import java.util.Objects; public class EventAnnotation extends BratAnnotation { private final String eventTrigger; private final Map arguments; protected EventAnnotation(String id, String type, String eventTrigger, Map arguments) { super(id, type); this.eventTrigger = Objects.requireNonNull(eventTrigger); this.arguments = Map.copyOf(arguments); } public String getEventTrigger() { return eventTrigger; } public Map getArguments() { return arguments; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Rel0100644 0000000 0000000 00000000162 15217274217 032525 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/RelationAnnotation.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/RelationAnnotation.0100644 0000000 0000000 00000002463 15217274217 034130 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; public class RelationAnnotation extends BratAnnotation { private final String arg1; private final String arg2; protected RelationAnnotation(String id, String type, String arg1, String arg2) { super(id, type); this.arg1 = arg1; this.arg2 = arg2; } public String getArg1() { return arg1; } public String getArg2() { return arg2; } @Override public String toString() { return super.toString() + " arg1:" + getArg1() + " arg2:" + getArg2(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Seg0100644 0000000 0000000 00000000165 15217274217 032524 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/SegmenterObjectStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/SegmenterObjectStre0100644 0000000 0000000 00000003267 15217274217 034163 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.List; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public abstract class SegmenterObjectStream extends FilterObjectStream { private Iterator sampleIt = Collections.emptyIterator(); public SegmenterObjectStream(ObjectStream in) { super(in); } protected abstract List read(S sample) throws IOException; @Override public final T read() throws IOException { if (sampleIt.hasNext()) { return sampleIt.next(); } else { S inSample = samples.read(); if (inSample != null) { List outSamples = read(inSample); if (outSamples != null) { sampleIt = outSamples.iterator(); } return read(); } } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_brat_Spa0100644 0000000 0000000 00000000156 15217274217 032531 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/SpanAnnotation.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/SpanAnnotation.java0100644 0000000 0000000 00000002720 15217274217 034112 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.brat; import java.util.Arrays; import opennlp.tools.util.Span; public class SpanAnnotation extends BratAnnotation { private final Span[] spans; private final String coveredText; SpanAnnotation(String id, String type, Span[] spans, String coveredText) { super(id, type); this.spans = Arrays.copyOf(spans, spans.length); Arrays.sort(this.spans); this.coveredText = coveredText; } public Span[] getSpans() { return spans; } public String getCoveredText() { return coveredText; } @Override public String toString() { return super.toString() + " " + Arrays.toString(spans) + " " + getCoveredText(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/brat/package-info.java0100644 0000000 0000000 00000001664 15217274217 033510 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the corpus format used by the "brat rapid annotation tool" (brat). */ package opennlp.tools.formats.brat; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000171 15217274217 032531 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluLemmaSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluLemmaSample0100644 0000000 0000000 00000004153 15217274217 034156 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public class ConlluLemmaSampleStream extends FilterObjectStream { private final ConlluTagset tagset; /** * Initializes a {@link ConlluLemmaSampleStream}. * * @param samples The {@link ObjectStream samples} used as input. * @param tagset The {@link ConlluTagset} to use. Must not be {@code null}. */ public ConlluLemmaSampleStream(ObjectStream samples, ConlluTagset tagset) { super(samples); this.tagset = Objects.requireNonNull(tagset); } @Override public LemmaSample read() throws IOException { ConlluSentence sentence = samples.read(); if (sentence != null) { List tokens = new ArrayList<>(); List tags = new ArrayList<>(); List lemmas = new ArrayList<>(); for (ConlluWordLine line : sentence.getWordLines()) { tokens.add(line.getForm()); tags.add(line.getPosTag(tagset)); lemmas.add(line.getLemma()); } return new LemmaSample(tokens, tags, lemmas); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000200 15217274217 032522 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluLemmaSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluLemmaSample0100644 0000000 0000000 00000005552 15217274217 034162 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.lemmatizer.LemmaSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see LemmaSample * @see ConlluLemmaSampleStream */ @Internal public class ConlluLemmaSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "tagset", description = "u|x u for unified tags and x for language-specific part-of-speech tags") @ArgumentParser.OptionalParameter(defaultValue = "u") String getTagset(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(LemmaSample.class, ConlluPOSSampleStreamFactory.CONLLU_FORMAT, new ConlluLemmaSampleStreamFactory(Parameters.class)); } protected ConlluLemmaSampleStreamFactory(Class params) { super(params); } public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ConlluTagset tagset = switch (params.getTagset()) { case "u" -> ConlluTagset.U; case "x" -> ConlluTagset.X; default -> throw new TerminateToolException(-1, "Unknown tagset parameter: " + params.getTagset()); }; InputStreamFactory inFactory = CmdLineUtil.createInputStreamFactory(params.getData()); try { return new ConlluLemmaSampleStream(new ConlluStream(inFactory), tagset); } catch (IOException e) { CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000167 15217274217 032536 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluPOSSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluPOSSampleSt0100644 0000000 0000000 00000003775 15217274217 034104 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import opennlp.tools.postag.POSSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public class ConlluPOSSampleStream extends FilterObjectStream { private final ConlluTagset tagset; /** * Initializes a {@link ConlluPOSSampleStream}. * * @param samples The {@link ObjectStream samples} used as input. * @param tagset The {@link ConlluTagset} to use. Must not be {@code null}. */ public ConlluPOSSampleStream(ObjectStream samples, ConlluTagset tagset) { super(samples); this.tagset = Objects.requireNonNull(tagset); } @Override public POSSample read() throws IOException { ConlluSentence sentence = samples.read(); if (sentence != null) { List tokens = new ArrayList<>(); List tags = new ArrayList<>(); for (ConlluWordLine line : sentence.getWordLines()) { tokens.add(line.getForm()); tags.add(line.getPosTag(tagset)); } return new POSSample(tokens, tags); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000176 15217274217 032536 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluPOSSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluPOSSampleSt0100644 0000000 0000000 00000005557 15217274217 034104 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.postag.POSSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see POSSample * @see ConlluPOSSampleStream */ @Internal public class ConlluPOSSampleStreamFactory extends AbstractSampleStreamFactory { public static final String CONLLU_FORMAT = "conllu"; public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "tagset", description = "u|x u for unified tags and x for language-specific part-of-speech tags") @ArgumentParser.OptionalParameter(defaultValue = "u") String getTagset(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(POSSample.class, CONLLU_FORMAT, new ConlluPOSSampleStreamFactory(Parameters.class)); } protected ConlluPOSSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ConlluTagset tagset = switch (params.getTagset()) { case "u" -> ConlluTagset.U; case "x" -> ConlluTagset.X; default -> throw new TerminateToolException(-1, "Unknown tagset parameter: " + params.getTagset()); }; InputStreamFactory inFactory = CmdLineUtil.createInputStreamFactory(params.getData()); try { return new ConlluPOSSampleStream(new ConlluStream(inFactory), tagset); } catch (IOException e) { CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000160 15217274217 032527 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluSentence.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluSentence.ja0100644 0000000 0000000 00000005324 15217274217 034117 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; public class ConlluSentence { private final List wordLines; private final String sentenceIdComment; private final String textComment; private boolean newDocument; private String documentId; private boolean newParagraph; private String paragraphId; private Map textLang; private String translit; ConlluSentence(List wordLines, String sentenceIdComment, String textComment) { this.wordLines = wordLines; this.sentenceIdComment = sentenceIdComment; this.textComment = textComment; } public ConlluSentence(List wordLines, String sentenceIdComment, String textComment, boolean newDocument, String documentId, boolean newParagraph, String paragraphId, Map textLang, String translit) { this(wordLines, sentenceIdComment, textComment); this.newDocument = newDocument; this.documentId = documentId; this.newParagraph = newParagraph; this.paragraphId = paragraphId; this.textLang = textLang; this.translit = translit; } public List getWordLines() { return wordLines; } public String getSentenceIdComment() { return sentenceIdComment; } public String getTextComment() { return textComment; } public boolean isNewDocument() { return newDocument; } public Optional getDocumentId() { return Optional.ofNullable(documentId); } public boolean isNewParagraph() { return newParagraph; } public Optional getParagraphId() { return Optional.ofNullable(paragraphId); } public Optional> getTextLang() { return Optional.ofNullable(textLang); } public Optional getTranslit() { return Optional.ofNullable(translit); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000174 15217274217 032534 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluSentenceSam0100644 0000000 0000000 00000004446 15217274217 034173 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import java.util.ArrayList; import java.util.List; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; public class ConlluSentenceSampleStream extends FilterObjectStream { private final int sentencesPerSample; /** * Initializes a {@link ConlluSentenceSampleStream}. * * @param samples The {@link ObjectStream samples} used as input. * @param sentencesPerSample The number of sentences per sample. Must not be negative. */ public ConlluSentenceSampleStream(ObjectStream samples, int sentencesPerSample) { super(samples); this.sentencesPerSample = sentencesPerSample; } @Override public SentenceSample read() throws IOException { StringBuilder documentText = new StringBuilder(); List sentenceSpans = new ArrayList<>(); ConlluSentence sentence; for (int i = 0; i < sentencesPerSample && (sentence = samples.read()) != null; i++) { int startIndex = documentText.length(); documentText.append(sentence.getTextComment()).append(' '); sentenceSpans.add(new Span(startIndex, documentText.length() - 1)); } if (documentText.length() > 0) { documentText.setLength(documentText.length() - 1); return new SentenceSample(documentText, sentenceSpans.toArray(new Span[0])); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000203 15217274217 032525 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluSentenceSam0100644 0000000 0000000 00000005200 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see SentenceSample * @see ConlluSentenceSampleStream */ @Internal public class ConlluSentenceSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "sentencesPerSample", description = "number of sentences per sample") String getSentencesPerSample(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, ConlluPOSSampleStreamFactory.CONLLU_FORMAT, new ConlluSentenceSampleStreamFactory(ConlluSentenceSampleStreamFactory.Parameters.class)); } protected ConlluSentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); InputStreamFactory inFactory = CmdLineUtil.createInputStreamFactory(params.getData()); try { return new ConlluSentenceSampleStream(new ConlluStream(inFactory), Integer.parseInt(params.getSentencesPerSample())); } catch (IOException e) { CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000156 15217274217 032534 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluStream.java0100644 0000000 0000000 00000021156 15217274217 034136 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.ParagraphStream; import opennlp.tools.util.PlainTextByLineStream; /** * The CoNNL-U Format is specified * here. */ public class ConlluStream implements ObjectStream { private final ObjectStream sentenceStream; private static final Pattern regex = Pattern.compile("text_([a-z]{2,3})"); /** * Initializes a {@link ConlluStream}. * * @param in The {@link InputStreamFactory} to use. Characters will be interpreted in UTF-8. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ConlluStream(InputStreamFactory in) throws IOException { this.sentenceStream = new ParagraphStream(new PlainTextByLineStream(in, StandardCharsets.UTF_8)); } @Override public ConlluSentence read() throws IOException { String sentence = sentenceStream.read(); if (sentence != null) { List wordLines = new ArrayList<>(); BufferedReader reader = new BufferedReader(new StringReader(sentence)); boolean newDocument = false; boolean newParagraph = false; String documentId = null; String paragraphId = null; String sentenceId = null; String text = null; Map textLang = null; String translit = null; String line; while ((line = reader.readLine()) != null) { // # indicates a comment line and contains additional data if (line.trim().startsWith("#")) { String commentLine = line.trim().substring(1); int separator = commentLine.indexOf('='); if (separator != -1) { String firstPart = commentLine.substring(0, separator).trim(); String secondPart = commentLine.substring(separator + 1, commentLine.length()).trim(); if (!secondPart.isEmpty()) { switch (firstPart) { case "newdoc id": newDocument = true; documentId = secondPart; break; case "newpar id": newParagraph = true; paragraphId = secondPart; break; case "sent_id": sentenceId = secondPart; break; case "text": text = secondPart; break; case "translit": translit = secondPart; break; } } if (firstPart.startsWith("text_")) { if (textLang == null) { textLang = new HashMap<>(); } addTextLang(firstPart, secondPart, textLang); } } else { switch (commentLine.trim()) { case "newdoc": newDocument = true; break; case "newpar": newParagraph = true; break; } } } else { wordLines.add(new ConlluWordLine(line)); } } wordLines = postProcessContractions(wordLines); return new ConlluSentence(wordLines, sentenceId, text, newDocument, documentId, newParagraph, paragraphId, textLang, translit); } return null; } private List postProcessContractions(List lines) { // 1. Find contractions Map index = new HashMap<>(); Map> contractions = new HashMap<>(); List linesToDelete = new ArrayList<>(); for (int i = 0; i < lines.size(); i++) { ConlluWordLine line = lines.get(i); index.put(line.getId(), i); if (line.getId().contains("-")) { List expandedContractions = new ArrayList<>(); String[] ids = line.getId().split("-"); int start = Integer.parseInt(ids[0]); int end = Integer.parseInt(ids[1]); for (int j = start; j <= end; j++) { String js = Integer.toString(j); expandedContractions.add(js); linesToDelete.add(js); } contractions.put(line.getId(), expandedContractions); } } // 2. Merge annotation for (Entry> entry : contractions.entrySet()) { final String contractionId = entry.getKey(); final List expandedContractions = entry.getValue(); int contractionIndex = index.get(contractionId); ConlluWordLine contraction = lines.get(contractionIndex); List expandedParts = new ArrayList<>(); for (String id : expandedContractions) { expandedParts.add(lines.get(index.get(id))); } ConlluWordLine merged = mergeAnnotation(contraction, expandedParts); lines.set(contractionIndex, merged); } // 3. Delete the expanded parts for (int i = linesToDelete.size() - 1; i >= 0; i--) { lines.remove(index.get(linesToDelete.get(i)).intValue()); } return lines; } /** * Merges token level annotations. * * @param contraction The line that receives the annotation. * @param expandedParts The lines to get annotation. * * @return The {@link ConlluWordLine merged line}. */ private ConlluWordLine mergeAnnotation(ConlluWordLine contraction, List expandedParts) { String id = contraction.getId(); String form = contraction.getForm(); String lemma = expandedParts.stream() .filter(p -> !"_".equals(p.getLemma())) .map(ConlluWordLine::getLemma) .collect(Collectors.joining("+")); String uPosTag = expandedParts.stream() .filter(p -> !"_".equals(p.getPosTag(ConlluTagset.U))) .map(p -> p.getPosTag(ConlluTagset.U)) .collect(Collectors.joining("+")); String xPosTag = expandedParts.stream() .filter(p -> !"_".equals(p.getPosTag(ConlluTagset.X))) .map(p -> p.getPosTag(ConlluTagset.X)) .collect(Collectors.joining("+")); String feats = expandedParts.stream() .filter(p -> !"_".equals(p.getFeats())) .map(ConlluWordLine::getFeats) .collect(Collectors.joining("+")); String head = contraction.getHead(); String deprel = contraction.getDeprel(); String deps = contraction.getDeps(); String misc = contraction.getMisc(); return new ConlluWordLine(id, form, lemma, uPosTag, xPosTag, feats,head, deprel, deps, misc); } private Map addTextLang(String firstPart, String secondPart, Map textLang) throws InvalidFormatException { String lang = ""; try { Matcher regexMatcher = regex.matcher(firstPart); if (regexMatcher.find()) { lang = regexMatcher.group(1); } } catch (PatternSyntaxException e) { throw new InvalidFormatException(e); } if (!lang.isEmpty()) { textLang.put(new Locale(lang), secondPart); } else { throw new InvalidFormatException(String.format("Locale language code is invalid: %s", lang)); } return textLang; } @Override public void close() throws IOException { sentenceStream.close(); } @Override public void reset() throws IOException, UnsupportedOperationException { sentenceStream.reset(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000156 15217274217 032534 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluTagset.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluTagset.java0100644 0000000 0000000 00000001557 15217274217 034135 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; public enum ConlluTagset { U, X } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000171 15217274217 032531 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluTokenSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluTokenSample0100644 0000000 0000000 00000005261 15217274217 034204 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.StringUtil; public class ConlluTokenSampleStream extends FilterObjectStream { /** * Initializes a {@link ConlluTokenSampleStream}. * * @param samples The {@link ObjectStream samples} used as input. */ public ConlluTokenSampleStream(ObjectStream samples) { super(samples); } @Override public TokenSample read() throws IOException { ConlluSentence sentence = samples.read(); if (sentence != null) { if (sentence.getTextComment() != null) { StringBuilder text = new StringBuilder(sentence.getTextComment()); int searchIndex = 0; for (ConlluWordLine wordLine : sentence.getWordLines()) { // skip over inserted words which are not in the source text if (wordLine.getId().contains(".")) { continue; } String token = wordLine.getForm(); int tokenIndex = text.indexOf(token, searchIndex); if (tokenIndex == -1) { throw new IOException(String.format("Failed to match token [%s] in sentence [%s] with text [%s]", token, sentence.getSentenceIdComment(), text)); } searchIndex = tokenIndex + token.length(); if (searchIndex < text.length()) { if (!StringUtil.isWhitespace(text.charAt(searchIndex))) { text.insert(searchIndex, TokenSample.DEFAULT_SEPARATOR_CHARS); } } } return TokenSample.parse(text.toString(), TokenSample.DEFAULT_SEPARATOR_CHARS); } else { throw new IOException("Sentence is missing raw text sample!"); } } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000200 15217274217 032522 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluTokenSample0100644 0000000 0000000 00000004512 15217274217 034202 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import java.io.IOException; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.InputStreamFactory; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see TokenSample * @see ConlluTokenSampleStream */ @Internal public class ConlluTokenSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, ConlluPOSSampleStreamFactory.CONLLU_FORMAT, new ConlluTokenSampleStreamFactory(ConlluTokenSampleStreamFactory.Parameters.class)); } protected ConlluTokenSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); InputStreamFactory inFactory = CmdLineUtil.createInputStreamFactory(params.getData()); try { return new ConlluTokenSampleStream(new ConlluStream(inFactory)); } catch (IOException e) { CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_C0100644 0000000 0000000 00000000160 15217274217 032527 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluWordLine.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/ConlluWordLine.ja0100644 0000000 0000000 00000010006 15217274217 034067 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.conllu; import opennlp.tools.util.InvalidFormatException; public class ConlluWordLine { private final String id; private final String form; private final String lemma; private final String uPosTag; private final String xPosTag; private final String feats; private final String head; private final String deprel; private final String deps; private final String misc; ConlluWordLine(String id, String form, String lemma, String uPosTag, String xPosTag, String feats, String head, String deprel, String deps, String misc) { this.id = id; this.form = form; this.lemma = lemma; this.uPosTag = uPosTag; this.xPosTag = xPosTag; this.feats = feats; this.head = head; this.deprel = deprel; this.deps = deps; this.misc = misc; } ConlluWordLine(String line) throws InvalidFormatException { String[] fields = line.split("\t"); if (fields.length != 10) { throw new InvalidFormatException("Line [" + line + "] must have exactly 10 fields"); } id = fields[0]; form = fields[1]; lemma = fields[2]; uPosTag = fields[3]; xPosTag = fields[4]; feats = fields[5]; head = fields[6]; deprel = fields[7]; deps = fields[8]; misc = fields[9]; } /** * @return Retrieves the word index. An Integer starting at {@code 1} for each new sentence; * may be a range for multiword tokens; may be a decimal number for empty nodes. */ public String getId() { return id; } /** * @return Retrieves the word form or punctuation symbol. */ public String getForm() { return form; } /** * @return Retrieves the lemma or stem of the word form. */ public String getLemma() { return lemma; } /** * @param tagset The {@link ConlluTagset type of tag} to retrieve, either universal * ({@link ConlluTagset#U}) or language specific ({@link ConlluTagset#X}). * * @return Retrieves the Universal part-of-speech tag or the language-specific part-of-speech tag; * underscore if not available. * @throws IllegalStateException Thrown if a non-supported {@link ConlluTagset} was specified. */ public String getPosTag(ConlluTagset tagset) { return switch (tagset) { case U -> uPosTag; case X -> xPosTag; default -> throw new IllegalStateException("Unexpected tagset value: " + tagset); }; } /** * @return Retrieves morphological features from the universal feature inventory * or from a defined language-specific extension; underscore if not available. */ public String getFeats() { return feats; } /** * @return Retrieves the head of the current word, which is either a value of ID or zero (0). */ public String getHead() { return head; } /** * @return Retrieves the Universal dependency relation to the HEAD (root if HEAD = 0) * or a defined language-specific subtype of one. */ public String getDeprel() { return deprel; } /** * @return Retrieves the enhanced dependency graph in the form of a list of * head-deprel pairs. */ public String getDeps() { return deps; } /** * @return Retrieves any other annotation. */ public String getMisc() { return misc; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_conllu_p0100644 0000000 0000000 00000000156 15217274217 032611 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/conllu/package-info.java0100644 0000000 0000000 00000001607 15217274217 034051 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the CoNNL-U format. */ package opennlp.tools.formats.conllu; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000201 15217274217 032604 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/AbstractToSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/AbstractToSenten0100644 0000000 0000000 00000005320 15217274217 034210 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public abstract class AbstractToSentenceSampleStream extends FilterObjectStream { private final Detokenizer detokenizer; private final int chunkSize; /** * @param detokenizer The {@link Detokenizer} to use. Must not be {@code null}. * @param samples The {@link ObjectStream samples} as input. Must not be {@code null}. * @param chunkSize The size of chunks. Must be equal to or greater than {@code 0}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ AbstractToSentenceSampleStream(Detokenizer detokenizer, ObjectStream samples, int chunkSize) { super(samples); this.detokenizer = Objects.requireNonNull(detokenizer, "detokenizer must not be null"); if (chunkSize < 0) { throw new IllegalArgumentException("chunkSize must be zero or larger but was " + chunkSize + "!"); } if (chunkSize > 0) { this.chunkSize = chunkSize; } else { this.chunkSize = Integer.MAX_VALUE; } } protected abstract String[] toSentence(T sample); @Override public SentenceSample read() throws IOException { List sentences = new ArrayList<>(); T posSample; int chunks = 0; while ((posSample = samples.read()) != null && chunks < chunkSize) { sentences.add(toSentence(posSample)); chunks++; } if (sentences.size() > 0) { return new SentenceSample(detokenizer, sentences.toArray(new String[sentences.size()][])); } else if (posSample != null) { return read(); // filter out empty line } return null; // last sample was read } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000176 15217274217 032617 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/FileToByteArraySampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/FileToByteArrayS0100644 0000000 0000000 00000004204 15217274217 034115 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import opennlp.tools.commons.Internal; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class FileToByteArraySampleStream extends FilterObjectStream { /** * Initializes a {@link FileToByteArraySampleStream}. * * @param samples The {@link ObjectStream} containing the files. */ public FileToByteArraySampleStream(ObjectStream samples) { super(samples); } private static byte[] readFile(File file) throws IOException { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { byte[] buffer = new byte[1024]; int length; while ((length = in.read(buffer, 0, buffer.length)) > 0) { bytes.write(buffer, 0, length); } } return bytes.toByteArray(); } @Override public byte[] read() throws IOException { File sampleFile = samples.read(); if (sampleFile != null) { return readFile(sampleFile); } else { return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000173 15217274217 032614 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/FileToStringSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/FileToStringSamp0100644 0000000 0000000 00000005035 15217274217 034162 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import java.io.File; import java.io.IOException; import java.io.Reader; import java.nio.charset.Charset; import java.nio.file.Files; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Provides the ability to read the contents of files * contained in an object stream of files. */ public class FileToStringSampleStream extends FilterObjectStream { private final Charset encoding; /** * Initializes a {@link FileToStringSampleStream}. * * @param samples The {@link ObjectStream} containing the files. * @param encoding The {@link Charset} encoding of the files. */ public FileToStringSampleStream(ObjectStream samples, Charset encoding) { super(samples); this.encoding = encoding; } /** * Reads the contents of a {@code textFile} to a string. * * @param textFile The {@link File} to read. * @param encoding The {@link Charset} of the {@code textFile}. * * @return The string contents of the file. * @throws IOException Thrown if the file could not be read. */ private static String readFile(File textFile, Charset encoding) throws IOException { StringBuilder text = new StringBuilder(); try (Reader in = Files.newBufferedReader(textFile.toPath(), encoding)) { char[] buffer = new char[1024]; int length; while ((length = in.read(buffer, 0, buffer.length)) > 0) { text.append(buffer, 0, length); } } return text.toString(); } @Override public String read() throws IOException { File sampleFile = samples.read(); if (sampleFile != null) { return readFile(sampleFile, encoding); } else { return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000175 15217274217 032616 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToSentenceSa0100644 0000000 0000000 00000003515 15217274217 034125 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.commons.Internal; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class NameToSentenceSampleStream extends AbstractToSentenceSampleStream { /** * Initializes a {@link NameToSentenceSampleStream}. * * @param detokenizer The {@link Detokenizer} to use. Must not be {@code null}. * @param samples The {@link ObjectStream samples} as input. Must not be {@code null}. * @param chunkSize The size of chunks. Must be equal to or greater than {@code 0}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public NameToSentenceSampleStream(Detokenizer detokenizer, ObjectStream samples, int chunkSize) { super(detokenizer, samples, chunkSize); } @Override protected String[] toSentence(NameSample sample) { return sample.getSentence(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000204 15217274217 032607 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToSentenceSa0100644 0000000 0000000 00000004607 15217274217 034130 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.formats.NameSampleDataStreamFactory; import opennlp.tools.namefind.NameSample; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see NameToSentenceSampleStream */ @Internal public class NameToSentenceSampleStreamFactory extends DetokenizerSampleStreamFactory { interface Parameters extends NameSampleDataStreamFactory.Parameters, DetokenizerParameter { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "namefinder", new NameToSentenceSampleStreamFactory(Parameters.class)); } protected NameToSentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream nameSampleStream = StreamFactoryRegistry.getFactory( NameSample.class, StreamFactoryRegistry.DEFAULT_FORMAT).create( ArgumentParser.filter(args, NameSampleDataStreamFactory.Parameters.class)); return new NameToSentenceSampleStream(createDetokenizer(params), nameSampleStream, 30); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000172 15217274217 032613 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToTokenSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToTokenSampl0100644 0000000 0000000 00000004077 15217274217 034156 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import java.io.IOException; import opennlp.tools.commons.Internal; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class NameToTokenSampleStream extends FilterObjectStream { private final Detokenizer detokenizer; /** * Initializes a {@link NameToTokenSampleStream}. * * @param detokenizer The {@link Detokenizer} to use. Must not be {@code null}. * @param samples The {@link ObjectStream samples} as input. Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public NameToTokenSampleStream(Detokenizer detokenizer, ObjectStream samples) { super(samples); this.detokenizer = detokenizer; } @Override public TokenSample read() throws IOException { NameSample nameSample = samples.read(); TokenSample tokenSample = null; if (nameSample != null ) { tokenSample = new TokenSample(detokenizer, nameSample.getSentence()); } return tokenSample; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000201 15217274217 032604 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/NameToTokenSampl0100644 0000000 0000000 00000004552 15217274217 034154 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.formats.NameSampleDataStreamFactory; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see NameToTokenSampleStream */ @Internal public class NameToTokenSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends NameSampleDataStreamFactory.Parameters, DetokenizerParameter { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, "namefinder", new NameToTokenSampleStreamFactory(Parameters.class)); } protected NameToTokenSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream nameSampleStream = StreamFactoryRegistry.getFactory( NameSample.class, StreamFactoryRegistry.DEFAULT_FORMAT).create( ArgumentParser.filter(args, NameSampleDataStreamFactory.Parameters.class)); return new NameToTokenSampleStream(createDetokenizer(params), nameSampleStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000174 15217274217 032615 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToSentenceSam0100644 0000000 0000000 00000003540 15217274217 034061 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.commons.Internal; import opennlp.tools.postag.POSSample; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class POSToSentenceSampleStream extends AbstractToSentenceSampleStream { /** * Initializes a {@link POSToSentenceSampleStream}. * * @param detokenizer The {@link Detokenizer} to use. Must not be {@code null}. * @param samples The {@link ObjectStream samples} as input. Must not be {@code null}. * @param chunkSize The size of chunks. Must be equal to or greater than {@code 0}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public POSToSentenceSampleStream(Detokenizer detokenizer, ObjectStream samples, int chunkSize) { super(detokenizer, samples, chunkSize); } @Override protected String[] toSentence(POSSample sample) { return sample.getSentence(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000203 15217274217 032606 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToSentenceSam0100644 0000000 0000000 00000004566 15217274217 034072 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.formats.WordTagSampleStreamFactory; import opennlp.tools.postag.POSSample; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see POSToSentenceSampleStream */ @Internal public class POSToSentenceSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends WordTagSampleStreamFactory.Parameters, DetokenizerParameter { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "pos", new POSToSentenceSampleStreamFactory(Parameters.class)); } protected POSToSentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream posSampleStream = StreamFactoryRegistry.getFactory(POSSample.class, StreamFactoryRegistry.DEFAULT_FORMAT).create( ArgumentParser.filter(args, WordTagSampleStreamFactory.Parameters.class)); return new POSToSentenceSampleStream(createDetokenizer(params), posSampleStream, 30); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000171 15217274217 032612 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToTokenSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToTokenSample0100644 0000000 0000000 00000004203 15217274217 034073 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import java.io.IOException; import java.util.Objects; import opennlp.tools.commons.Internal; import opennlp.tools.postag.POSSample; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class POSToTokenSampleStream extends FilterObjectStream { private final Detokenizer detokenizer; /** * Initializes a {@link POSToTokenSampleStream}. * * @param detokenizer The {@link Detokenizer} to use. Must not be {@code null}. * @param samples The {@link ObjectStream samples} as input. Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public POSToTokenSampleStream(Detokenizer detokenizer, ObjectStream samples) { super(samples); this.detokenizer = Objects.requireNonNull(detokenizer, "detokenizer must not be null!"); } @Override public TokenSample read() throws IOException { POSSample posSample = samples.read(); TokenSample tokenSample = null; if (posSample != null ) { tokenSample = new TokenSample(detokenizer, posSample.getSentence()); } return tokenSample; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000200 15217274217 032603 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/POSToTokenSample0100644 0000000 0000000 00000004522 15217274217 034077 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.formats.WordTagSampleStreamFactory; import opennlp.tools.postag.POSSample; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see POSToTokenSampleStream */ @Internal public class POSToTokenSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends WordTagSampleStreamFactory.Parameters, DetokenizerParameter { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, "pos", new POSToTokenSampleStreamFactory(Parameters.class)); } protected POSToTokenSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream posSampleStream = StreamFactoryRegistry.getFactory(POSSample.class, StreamFactoryRegistry.DEFAULT_FORMAT).create( ArgumentParser.filter(args, WordTagSampleStreamFactory.Parameters.class)); return new POSToTokenSampleStream(createDetokenizer(params), posSampleStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000171 15217274217 032612 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToPOSSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToPOSSample0100644 0000000 0000000 00000004023 15217274217 034065 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import java.io.IOException; import java.util.ArrayList; import java.util.List; import opennlp.tools.commons.Internal; import opennlp.tools.parser.Parse; import opennlp.tools.postag.POSSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class ParseToPOSSampleStream extends FilterObjectStream { /** * Initializes a {@link ParseToPOSSampleStream}. * * @param samples The {@link ObjectStream samples} as input. Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public ParseToPOSSampleStream(ObjectStream samples) { super(samples); } @Override public POSSample read() throws IOException { Parse parse = samples.read(); if (parse != null) { List sentence = new ArrayList<>(); List tags = new ArrayList<>(); for (Parse tagNode : parse.getTagNodes()) { sentence.add(tagNode.getCoveredText()); tags.add(tagNode.getType()); } return new POSSample(sentence, tags); } else { return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000200 15217274217 032603 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToPOSSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToPOSSample0100644 0000000 0000000 00000004540 15217274217 034071 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.LanguageSampleStreamFactory; import opennlp.tools.formats.ParseSampleStreamFactory; import opennlp.tools.parser.Parse; import opennlp.tools.postag.POSSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see ParseToPOSSampleStream */ @Internal public class ParseToPOSSampleStreamFactory extends LanguageSampleStreamFactory { public interface Parameters extends ParseSampleStreamFactory.Parameters, DetokenizerParameter { } private ParseToPOSSampleStreamFactory() { super(ParseToPOSSampleStreamFactory.Parameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(POSSample.class, "parse", new ParseToPOSSampleStreamFactory()); } @Override public ObjectStream create(String[] args) { ParseSampleStreamFactory.Parameters params = validateBasicFormatParameters(args, ParseSampleStreamFactory.Parameters.class); ObjectStream parseSampleStream = StreamFactoryRegistry.getFactory(Parse.class, StreamFactoryRegistry.DEFAULT_FORMAT).create( ArgumentParser.filter(args, ParseSampleStreamFactory.Parameters.class)); return new ParseToPOSSampleStream(parseSampleStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000205 15217274217 032610 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToSentenceS0100644 0000000 0000000 00000004530 15217274217 034154 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.formats.ParseSampleStreamFactory; import opennlp.tools.parser.Parse; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class ParseToSentenceSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends ParseSampleStreamFactory.Parameters, DetokenizerParameter { } private ParseToSentenceSampleStreamFactory() { super(Parameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "parse", new ParseToSentenceSampleStreamFactory()); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream parseSampleStream = StreamFactoryRegistry.getFactory(Parse.class, StreamFactoryRegistry.DEFAULT_FORMAT).create( ArgumentParser.filter(args, ParseSampleStreamFactory.Parameters.class)); return new POSToSentenceSampleStream(createDetokenizer(params), new ParseToPOSSampleStream(parseSampleStream), 30); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_convert_0100644 0000000 0000000 00000000202 15217274217 032605 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/convert/ParseToTokenSamp0100644 0000000 0000000 00000004563 15217274217 034174 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.convert; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.DetokenizerParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.formats.ParseSampleStreamFactory; import opennlp.tools.formats.WordTagSampleStreamFactory; import opennlp.tools.parser.Parse; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal public class ParseToTokenSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends ParseSampleStreamFactory.Parameters, DetokenizerParameter { } private ParseToTokenSampleStreamFactory() { super(Parameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, "parse", new ParseToTokenSampleStreamFactory()); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); ObjectStream parseSampleStream = StreamFactoryRegistry.getFactory(Parse.class, StreamFactoryRegistry.DEFAULT_FORMAT).create( ArgumentParser.filter(args, WordTagSampleStreamFactory.Parameters.class)); return new POSToTokenSampleStream(createDetokenizer(params), new ParseToPOSSampleStream(parseSampleStream)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_frenchtr0100644 0000000 0000000 00000000200 15217274217 032577 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/ConstitDocumentHandler.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/ConstitDo0100644 0000000 0000000 00000013132 15217274217 034174 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.frenchtreebank; import java.util.LinkedList; import java.util.List; import java.util.Stack; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import opennlp.tools.parser.AbstractBottomUpParser; import opennlp.tools.parser.Constituent; import opennlp.tools.parser.Parse; import opennlp.tools.util.Span; class ConstitDocumentHandler extends DefaultHandler { private static final String SENT_ELEMENT_NAME = "SENT"; private static final String WORD_ELEMENT_NAME = "w"; private static final String SENT_TYPE_NAME = "S"; private final List parses; private boolean insideSentenceElement; /** * A token buffer, a token might be build up by multiple * {@link #characters(char[], int, int)} calls. */ private final StringBuilder tokenBuffer = new StringBuilder(); private final StringBuilder text = new StringBuilder(); private int offset; private final Stack stack = new Stack<>(); private final List cons = new LinkedList<>(); ConstitDocumentHandler(List parses) { this.parses = parses; } private String cat; private String subcat; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { String type = qName; if (SENT_ELEMENT_NAME.equals(qName)) { // Clear everything to be ready for the next sentence text.setLength(0); offset = 0; stack.clear(); cons.clear(); type = SENT_TYPE_NAME; insideSentenceElement = true; } else if (WORD_ELEMENT_NAME.equals(qName)) { // Note: // If there are compound words they are represented in a couple // of ways in the training data. // Many of them are marked with the compound attribute, but not // all of them. Thats why it is not used in the code to detect // a compound word. // Compounds are detected by the fact that a w tag is appearing // inside a w tag. // // The type of a compound word can be encoded either cat of the compound // plus the catint of each word of the compound. // Or all compound words have the cat plus subcat of the compound, in this // case they have an empty cat attribute. // // This implementation hopefully decodes these cases correctly! String newCat = attributes.getValue("cat"); if (newCat != null && newCat.length() > 0) { cat = newCat; } String newSubcat = attributes.getValue("subcat"); if (newSubcat != null && newSubcat.length() > 0) { subcat = newSubcat; } if (cat != null) { type = cat + (subcat != null ? subcat : ""); } else { String catint = attributes.getValue("catint"); if (catint != null) { type = cat + catint; } else { type = cat + subcat; } } } stack.push(new Constituent(type, new Span(offset, offset))); tokenBuffer.setLength(0); } @Override public void characters(char[] ch, int start, int length) throws SAXException { tokenBuffer.append(ch, start, length); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { boolean isCreateConstituent = true; if (insideSentenceElement) { if (WORD_ELEMENT_NAME.equals(qName)) { String token = tokenBuffer.toString().trim(); if (!token.isEmpty()) { cons.add(new Constituent(AbstractBottomUpParser.TOK_NODE, new Span(offset, offset + token.length()))); text.append(token).append(" "); offset += token.length() + 1; } else { isCreateConstituent = false; } } Constituent unfinishedCon = stack.pop(); if (isCreateConstituent) { int start = unfinishedCon.getSpan().getStart(); if (start < offset) { cons.add(new Constituent(unfinishedCon.getLabel(), new Span(start, offset - 1))); } } if (SENT_ELEMENT_NAME.equals(qName)) { // Finished parsing sentence, now put everything together and create // a Parse object String txt = text.toString(); int tokenIndex = -1; Parse p = new Parse(txt, new Span(0, txt.length()), AbstractBottomUpParser.TOP_NODE, 1,0); for (Constituent con : cons) { String type = con.getLabel(); if (!type.equals(AbstractBottomUpParser.TOP_NODE)) { if (AbstractBottomUpParser.TOK_NODE.equals(type)) { tokenIndex++; } Parse c = new Parse(txt, con.getSpan(), type, 1, tokenIndex); p.insert(c); } } parses.add(p); insideSentenceElement = false; } tokenBuffer.setLength(0); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_frenchtr0100644 0000000 0000000 00000000202 15217274217 032601 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/ConstitParseSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/ConstitPa0100644 0000000 0000000 00000004442 15217274217 034176 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.frenchtreebank; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.SAXParser; import org.xml.sax.SAXException; import opennlp.tools.parser.Parse; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.XmlUtil; public class ConstitParseSampleStream extends FilterObjectStream { private final SAXParser saxParser; private final List parses = new ArrayList<>(); /** * Initializes a {@link ConstitParseSampleStream}. * * @param samples The {@link ObjectStream byte[] samples} as input. Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ protected ConstitParseSampleStream(ObjectStream samples) { super(samples); saxParser = XmlUtil.createSaxParser(); } @Override public Parse read() throws IOException { if (parses.isEmpty()) { byte[] xmlbytes = samples.read(); if (xmlbytes != null) { List producedParses = new ArrayList<>(); try { saxParser.parse(new ByteArrayInputStream(xmlbytes), new ConstitDocumentHandler(producedParses)); } catch (SAXException e) { throw new IOException(e.getMessage(), e); } parses.addAll(producedParses); } } if (parses.size() > 0) { return parses.remove(0); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_frenchtr0100644 0000000 0000000 00000000211 15217274217 032601 xustar000000000 0000000 137 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/ConstitParseSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/ConstitPa0100644 0000000 0000000 00000004425 15217274217 034177 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.frenchtreebank; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.formats.DirectorySampleStream; import opennlp.tools.formats.convert.FileToByteArraySampleStream; import opennlp.tools.parser.Parse; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see Parse * @see ConstitParseSampleStream */ @Internal public class ConstitParseSampleStreamFactory extends AbstractSampleStreamFactory { // TODO: The parameters have an encoding, but the data is in xml interface Parameters extends BasicFormatParams { } private ConstitParseSampleStreamFactory() { super(Parameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(Parse.class, "frenchtreebank", new ConstitParseSampleStreamFactory()); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); return new ConstitParseSampleStream(new FileToByteArraySampleStream( new DirectorySampleStream(params.getData(), null, false))); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_frenchtr0100644 0000000 0000000 00000000166 15217274217 032612 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/frenchtreebank/package-i0100644 0000000 0000000 00000001627 15217274217 034115 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the French Treebank format. */ package opennlp.tools.formats.frenchtreebank; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_irishsen0100644 0000000 0000000 00000000206 15217274217 032616 xustar000000000 0000000 134 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishSentenceBankDocument.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishS0100644 0000000 0000000 00000024315 15217274217 034212 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.irishsentencebank; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilder; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.Span; import opennlp.tools.util.XmlUtil; /** * A structure to hold an Irish Sentence Bank document, which is a collection * of tokenized sentences. *

* The sentence bank can be downloaded from this * website. *

* It was originally published and described * * http://www.lexiconista.com/datasets/sentencebank-ga/, yet this * page was gone when last checked in December 2022. */ public class IrishSentenceBankDocument { public static class IrishSentenceBankFlex { final String surface; final String[] flex; public String getSurface() { return surface; } public String[] getFlex() { return flex; } public IrishSentenceBankFlex(String sf, String[] fl) { this.surface = sf; this.flex = fl; } } public static class IrishSentenceBankSentence { private final String source; private final String translation; private final String original; private final Span[] tokens; private final IrishSentenceBankFlex[] flex; public String getSource() { return source; } public String getTranslation() { return translation; } public String getOriginal() { return original; } public Span[] getTokens() { return tokens; } public IrishSentenceBankFlex[] getFlex() { return flex; } public TokenSample getTokenSample() { return new TokenSample(original, tokens); } public IrishSentenceBankSentence(String src, String trans, String orig, Span[] toks, IrishSentenceBankFlex[] flx) { this.source = src; this.translation = trans; this.original = orig; this.tokens = toks; this.flex = flx; } } private final List sentences; /** * Initializes an empty {@link IrishSentenceBankDocument}. */ public IrishSentenceBankDocument() { sentences = new ArrayList<>(); } /** * @param sent A {@link IrishSentenceBankSentence} to be added. */ public void add(IrishSentenceBankSentence sent) { this.sentences.add(sent); } /** * @return Retrieves an unmodifiable list of all {@link IrishSentenceBankSentence sentences}. */ public List getSentences() { return Collections.unmodifiableList(sentences); } /** * Helper to adjust the span of punctuation tokens: ignores spaces to the left of the string. * @param s The string to check. * @param start The offset of the start of the string. * * @return The offset adjusted to ignore spaces to the left. */ private static int advanceLeft(String s, int start) { int ret = start; for (char c : s.toCharArray()) { if (c == ' ') { ret++; } else { return ret; } } return ret; } /** * Helper to adjust the span of punctuation tokens: ignores spaces to the right of the string. * @param s The string to check. * @param start The offset of the start of the string. * * @return The offset of the end of the string, adjusted to ignore spaces to the right. */ private static int advanceRight(String s, int start) { int end = s.length() - 1; int ret = start + end + 1; for (int i = end; i > 0; i--) { if (s.charAt(i) == ' ') { ret--; } else { return ret; } } return ret; } /** * Parses the data provided via an {@link InputStream} into a * {@link IrishSentenceBankDocument}. * * @param is A valid, open {@link InputStream} ready for use. * * @return A valid {@link IrishSentenceBankDocument}. * @throws IOException Thrown if IO errors occurred. */ public static IrishSentenceBankDocument parse(InputStream is) throws IOException { IrishSentenceBankDocument document = new IrishSentenceBankDocument(); try { DocumentBuilder docBuilder = XmlUtil.createDocumentBuilder(); Document doc = docBuilder.parse(is); String root = doc.getDocumentElement().getNodeName(); if (!root.equalsIgnoreCase("sentences")) { throw new IOException("Expected root node " + root); } NodeList nl = doc.getDocumentElement().getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node sentnode = nl.item(i); if (sentnode.getNodeName().equals("sentence")) { String src = sentnode.getAttributes().getNamedItem("source").getNodeValue(); String trans = ""; Map toks = new HashMap<>(); Map> flx = new HashMap<>(); List spans = new ArrayList<>(); NodeList sentnl = sentnode.getChildNodes(); int flexes = 1; java.lang.StringBuilder orig = new java.lang.StringBuilder(); for (int j = 0; j < sentnl.getLength(); j++) { final String name = sentnl.item(j).getNodeName(); switch (name) { case "flex": String slottmpa = sentnl.item(j).getAttributes().getNamedItem("slot").getNodeValue(); Integer flexslot = Integer.parseInt(slottmpa); if (flexslot > flexes) { flexes = flexslot; } flx.computeIfAbsent(flexslot, k -> new ArrayList<>()); String tkn = sentnl.item(j).getAttributes().getNamedItem("lemma").getNodeValue(); flx.get(flexslot).add(tkn); break; case "translation": trans = sentnl.item(j).getFirstChild().getTextContent(); break; case "original": int last = 0; NodeList orignl = sentnl.item(j).getChildNodes(); for (int k = 0; k < orignl.getLength(); k++) { switch (orignl.item(k).getNodeName()) { case "token": String tmptok = orignl.item(k).getFirstChild().getTextContent(); spans.add(new Span(last, last + tmptok.length())); String slottmpb = orignl.item(k).getAttributes().getNamedItem("slot").getNodeValue(); int tokslot = Integer.parseInt(slottmpb); if (tokslot > flexes) { flexes = tokslot; } toks.put(tokslot, tmptok); orig.append(tmptok); last += tmptok.length(); break; case "#text": String tmptxt = orignl.item(k).getTextContent(); orig.append(tmptxt); if (!" ".equals(tmptxt)) { spans.add(new Span(advanceLeft(tmptxt, last), advanceRight(tmptxt, last))); } last += tmptxt.length(); break; default: throw new IOException("Unexpected node: " + orignl.item(k).getNodeName()); } } break; case "#text": case "#comment": break; default: throw new IOException("Unexpected node: " + name); } } IrishSentenceBankFlex[] flexa = new IrishSentenceBankFlex[flexes]; for (Entry entry : toks.entrySet()) { final Integer flexidx = entry.getKey(); final String left = entry.getValue(); if (flx.get(flexidx) == null) { flexa = null; break; } int rsize = flx.get(flexidx).size(); String[] right = new String[rsize]; right = flx.get(flexidx).toArray(right); flexa[flexidx - 1] = new IrishSentenceBankFlex(left, right); } Span[] spanout = new Span[spans.size()]; spanout = spans.toArray(spanout); document.add(new IrishSentenceBankSentence(src, trans, orig.toString(), spanout, flexa)); } else if (!sentnode.getNodeName().equals("#text") && !sentnode.getNodeName().equals("#comment")) { throw new IOException("Unexpected node: " + sentnode.getNodeName()); } } return document; } catch (SAXException e) { throw new IOException("Failed to parse IrishSentenceBank document", e); } } /** * Parses the data provided via a {@link File} into a * {@link IrishSentenceBankDocument}. * * @param file A valid {@link File} that holds the data to process. * * @return A valid {@link IrishSentenceBankDocument}. * @throws IOException Thrown if IO errors occurred. */ static IrishSentenceBankDocument parse(File file) throws IOException { try (InputStream in = new BufferedInputStream(Files.newInputStream(file.toPath()))) { return parse(in); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_irishsen0100644 0000000 0000000 00000000214 15217274217 032615 xustar000000000 0000000 140 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishSentenceBankSentenceStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishS0100644 0000000 0000000 00000004405 15217274217 034210 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.irishsentencebank; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; class IrishSentenceBankSentenceStream implements ObjectStream { private final IrishSentenceBankDocument source; private Iterator sentenceIt; IrishSentenceBankSentenceStream(IrishSentenceBankDocument source) { this.source = source; reset(); } @Override public SentenceSample read() throws IOException { StringBuilder sentencesString = new StringBuilder(); List sentenceSpans = new LinkedList<>(); while (sentenceIt.hasNext()) { IrishSentenceBankDocument.IrishSentenceBankSentence sentence = sentenceIt.next(); int begin = sentencesString.length(); if (sentence.getOriginal() != null) { sentencesString.append(sentence.getOriginal()); } sentenceSpans.add(new Span(begin, sentencesString.length())); sentencesString.append(' '); } // end of stream is reached, indicate that with null return value if (sentenceSpans.size() == 0) { return null; } return new SentenceSample(sentencesString.toString(), sentenceSpans.toArray(new Span[0])); } @Override public void reset() { sentenceIt = source.getSentences().iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_irishsen0100644 0000000 0000000 00000000223 15217274217 032615 xustar000000000 0000000 147 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishSentenceBankSentenceStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishS0100644 0000000 0000000 00000004500 15217274217 034204 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.irishsentencebank; import java.io.IOException; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see SentenceSample * @see IrishSentenceBankSentenceStream */ @Internal public class IrishSentenceBankSentenceStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "irishsentencebank", new IrishSentenceBankSentenceStreamFactory( IrishSentenceBankSentenceStreamFactory.Parameters.class)); } protected IrishSentenceBankSentenceStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); IrishSentenceBankDocument isbDoc = null; try { isbDoc = IrishSentenceBankDocument.parse(params.getData()); } catch (IOException ex) { CmdLineUtil.handleCreateObjectStreamError(ex); } return new IrishSentenceBankSentenceStream(isbDoc); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_irishsen0100644 0000000 0000000 00000000217 15217274217 032620 xustar000000000 0000000 143 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishSentenceBankTokenSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishS0100644 0000000 0000000 00000003413 15217274217 034206 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.irishsentencebank; import java.io.IOException; import java.util.Iterator; import opennlp.tools.commons.Internal; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! */ @Internal class IrishSentenceBankTokenSampleStream implements ObjectStream { private final IrishSentenceBankDocument source; private Iterator sentenceIt; IrishSentenceBankTokenSampleStream(IrishSentenceBankDocument source) { this.source = source; reset(); } @Override public TokenSample read() throws IOException { if (sentenceIt.hasNext()) { IrishSentenceBankDocument.IrishSentenceBankSentence sentence = sentenceIt.next(); return sentence.getTokenSample(); } else { return null; } } @Override public void reset() { sentenceIt = source.getSentences().iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_irishsen0100644 0000000 0000000 00000000226 15217274217 032620 xustar000000000 0000000 150 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishSentenceBankTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/IrishS0100644 0000000 0000000 00000004506 15217274217 034212 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.irishsentencebank; import java.io.IOException; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.DetokenizerSampleStreamFactory; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see TokenSample * @see IrishSentenceBankTokenSampleStream */ @Internal public class IrishSentenceBankTokenSampleStreamFactory extends DetokenizerSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, "irishsentencebank", new IrishSentenceBankTokenSampleStreamFactory( IrishSentenceBankTokenSampleStreamFactory.Parameters.class)); } protected IrishSentenceBankTokenSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); IrishSentenceBankDocument isbDoc = null; try { isbDoc = IrishSentenceBankDocument.parse(params.getData()); } catch (IOException ex) { CmdLineUtil.handleCreateObjectStreamError(ex); } return new IrishSentenceBankTokenSampleStream(isbDoc); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_irishsen0100644 0000000 0000000 00000000171 15217274217 032617 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/irishsentencebank/packag0100644 0000000 0000000 00000001636 15217274217 034240 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the Irish Sentence Bank format. */ package opennlp.tools.formats.irishsentencebank; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_leipzig_0100644 0000000 0000000 00000000176 15217274217 032602 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/LeipzigLanguageSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/LeipzigLanguageS0100644 0000000 0000000 00000015420 15217274217 034144 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.leipzig; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.langdetect.Language; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.MarkableFileInputStreamFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.PlainTextByLineStream; public class LeipzigLanguageSampleStream implements ObjectStream { private class LeipzigSentencesStream implements ObjectStream { private final String lang; private final Iterator lineIterator; /** * Initializes a {@link LeipzigSentencesStream}. * * @param lang An ISO language code. * @param sentencesFile The {@link File} which contains sentences to process. * @param sentencesPerSample The number of sentences per sample. * @param numberOfSamples The number of samples to process at maximum. * * @throws IOException Thrown if IO errors occurred. * @throws InvalidFormatException Thrown if {@code sentencesFile} has not enough lines to process. */ LeipzigSentencesStream(String lang, File sentencesFile, int sentencesPerSample, int numberOfSamples) throws IOException { this.lang = lang; // The file name contains the number of lines, but to make this more stable // the file is once scanned for the count even tough this is slower int totalLineCount = (int) Files.lines(sentencesFile.toPath()).count(); int requiredLines = sentencesPerSample * numberOfSamples; if (totalLineCount < requiredLines) throw new InvalidFormatException( String.format("%s does not contain enough lines (%d lines < %d required lines).", sentencesFile.getPath(), totalLineCount, requiredLines)); List indexes = IntStream.range(0, totalLineCount) .boxed().collect(Collectors.toList()); Collections.shuffle(indexes, random); Set selectedLines = new HashSet<>(indexes.subList(0, requiredLines)); List sentences = new ArrayList<>(); try (ObjectStream lineStream = new PlainTextByLineStream( new MarkableFileInputStreamFactory(sentencesFile), StandardCharsets.UTF_8)) { int lineIndex = 0; String line; while ((line = lineStream.read()) != null) { int tabIndex = line.indexOf('\t'); if (tabIndex != -1) { if (selectedLines.contains(lineIndex)) { sentences.add(line); } } lineIndex++; } } Collections.shuffle(sentences, random); lineIterator = sentences.iterator(); } @Override public LanguageSample read() throws IOException { StringBuilder sampleString = new StringBuilder(); int count = 0; while (count < sentencesPerSample && lineIterator.hasNext()) { String line = lineIterator.next(); int textStart = line.indexOf('\t') + 1; sampleString.append(line.substring(textStart)).append(" "); count++; } if (sampleString.length() > 0) { return new LanguageSample(new Language(lang), sampleString); } return null; } } private final int sentencesPerSample; private final Map langSampleCounts; private final File[] sentencesFiles; private Iterator sentencesFilesIt; private ObjectStream sampleStream; private final Random random; /** * Initializes a {@link LeipzigLanguageSampleStream}. * * @param leipzigFolder The {@link File directory} which contains files to process. * @param sentencesPerSample The number of sentences per sample. * @param samplesPerLanguage The number of samples per language to process at maximum. * * @throws IOException Thrown if IO errors occurred. */ public LeipzigLanguageSampleStream(File leipzigFolder, final int sentencesPerSample, final int samplesPerLanguage) throws IOException { this.sentencesPerSample = sentencesPerSample; sentencesFiles = leipzigFolder.listFiles(pathname -> !pathname.isHidden() && pathname.isFile() && pathname.getName().length() >= 3 && pathname.getName().substring(0,3).matches("[a-z]+")); if (null == sentencesFiles) { throw new TerminateToolException(-1 , "Directory " + leipzigFolder + " empty , No files to read!"); } Arrays.sort(sentencesFiles); Map langCounts = Arrays.stream(sentencesFiles) .map(file -> file.getName().substring(0, 3)) .collect(Collectors.groupingBy(String::toString, Collectors.summingInt(v -> 1))); langSampleCounts = langCounts.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> samplesPerLanguage / e.getValue())); random = new Random(23); reset(); } @Override public LanguageSample read() throws IOException { LanguageSample sample; if (sampleStream != null && (sample = sampleStream.read()) != null) { return sample; } else { if (sentencesFilesIt.hasNext()) { File sentencesFile = sentencesFilesIt.next(); String lang = sentencesFile.getName().substring(0, 3); sampleStream = new LeipzigSentencesStream(lang, sentencesFile, sentencesPerSample, langSampleCounts.get(lang)); return read(); } } return null; } @Override public void reset() throws IOException { sentencesFilesIt = Arrays.asList(sentencesFiles).iterator(); sampleStream = null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_leipzig_0100644 0000000 0000000 00000000205 15217274217 032573 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/LeipzigLanguageSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/LeipzigLanguageS0100644 0000000 0000000 00000006445 15217274217 034153 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.leipzig; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.ArgumentParser.OptionalParameter; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.EncodingParameter; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.langdetect.LanguageSample; import opennlp.tools.util.ObjectStream; /** * Note: * Do not use this class, internal use only! * * @see LeipzigLanguageSampleStream */ @Internal public class LeipzigLanguageSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends EncodingParameter { @ParameterDescription(valueName = "sentencesDir", description = "dir with Leipzig sentences to be used") File getSentencesDir(); @ParameterDescription(valueName = "sentencesPerSample", description = "number of sentences per sample") Integer getSentencesPerSample(); @ParameterDescription(valueName = "samplesPerLanguage", description = "number of samples per language") Integer getSamplesPerLanguage(); @ParameterDescription(valueName = "samplesToSkip", description = "number of samples to skip before returning") @OptionalParameter(defaultValue = "0") Integer getSamplesToSkip(); } protected LeipzigLanguageSampleStreamFactory(Class params) { super(params); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(LanguageSample.class, "leipzig", new LeipzigLanguageSampleStreamFactory(Parameters.class)); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters p = ArgumentParser.parse(args, Parameters.class); File sentencesFileDir = p.getSentencesDir(); try { return new SampleSkipStream<>(new SampleShuffleStream<>(new LeipzigLanguageSampleStream( sentencesFileDir, p.getSentencesPerSample(), p.getSamplesPerLanguage() + p.getSamplesToSkip())), p.getSamplesToSkip()); } catch (IOException e) { throw new TerminateToolException(-1, "IO error while opening sample data.", e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_leipzig_0100644 0000000 0000000 00000000166 15217274217 032601 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/SampleShuffleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/SampleShuffleStr0100644 0000000 0000000 00000004160 15217274217 034200 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.leipzig; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Random; import opennlp.tools.commons.Sample; import opennlp.tools.util.ObjectStream; /** * A specialization of {@link ObjectStream} that shuffles samples. * @param The template parameter which represents * the {@link Sample} type. */ class SampleShuffleStream implements ObjectStream { private final List bufferedSamples = new ArrayList<>(); private Iterator sampleIt; /** * Initializes a {@link SampleShuffleStream} with the specified parameters. * * @param samples The {@link ObjectStream} to process. * @throws IOException Thrown if IO errors occurred during skip operation. */ SampleShuffleStream(ObjectStream samples) throws IOException { T sample; while ((sample = samples.read()) != null) { bufferedSamples.add(sample); } Collections.shuffle(bufferedSamples, new Random(23)); reset(); } @Override public T read() throws IOException { if (sampleIt.hasNext()) { return sampleIt.next(); } return null; } @Override public void reset() throws IOException, UnsupportedOperationException { sampleIt = bufferedSamples.iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_leipzig_0100644 0000000 0000000 00000000163 15217274217 032576 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/SampleSkipStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/SampleSkipStream0100644 0000000 0000000 00000004114 15217274217 034174 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.leipzig; import java.io.IOException; import opennlp.tools.commons.Sample; import opennlp.tools.util.ObjectStream; /** * A specialization of {@link ObjectStream} that skips a number of samples. * @param The template parameter which represents * the {@link Sample} type. */ class SampleSkipStream implements ObjectStream { private final ObjectStream samples; private final int samplesToSkip; /** * Initializes a {@link SampleSkipStream} with the specified parameters. * * @param samples The {@link ObjectStream} to process. * @param samplesToSkip The number of samples to skip. Must be greater than {@code 0}. * @throws IOException Thrown if IO errors occurred during skip operation. */ SampleSkipStream(ObjectStream samples, int samplesToSkip) throws IOException { this.samples = samples; this.samplesToSkip = samplesToSkip; skipSamples(); } @Override public T read() throws IOException { return samples.read(); } @Override public void reset() throws IOException, UnsupportedOperationException { this.samples.reset(); skipSamples(); } private void skipSamples() throws IOException { int i = 0; while (i < samplesToSkip && (samples.read()) != null) { i++; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_leipzig_0100644 0000000 0000000 00000000157 15217274217 032601 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/leipzig/package-info.jav0100644 0000000 0000000 00000001627 15217274217 034061 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the {@code Leipzig} corpus format. */ package opennlp.tools.formats.leipzig; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_letsmt_D0100644 0000000 0000000 00000000200 15217274217 032537 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/DetokenizeSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/DetokenizeSentenc0100644 0000000 0000000 00000005422 15217274217 034241 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.letsmt; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; public class DetokenizeSentenceSampleStream extends FilterObjectStream { private final Detokenizer detokenizer; /** * Initializes a {@link DetokenizeSentenceSampleStream}. * * @param detokenizer The {@link Detokenizer} to use. Must not be {@code null}. * @param samples The {@link ObjectStream samples} as input. Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public DetokenizeSentenceSampleStream(Detokenizer detokenizer, ObjectStream samples) { super(samples); this.detokenizer = Objects.requireNonNull(detokenizer); } @Override public SentenceSample read() throws IOException { SentenceSample sample = samples.read(); if (sample != null) { List sentenceTexts = new ArrayList<>(); for (Span sentenceSpan : sample.getSentences()) { sentenceTexts.add(sample.getDocument().substring(sentenceSpan.getStart(), sentenceSpan.getEnd())); } StringBuilder documentText = new StringBuilder(); List newSentenceSpans = new ArrayList<>(); for (String sentenceText : sentenceTexts) { String[] tokens = WhitespaceTokenizer.INSTANCE.tokenize(sentenceText); int begin = documentText.length(); documentText.append(detokenizer.detokenize(tokens, null)); newSentenceSpans.add(new Span(begin, documentText.length())); documentText.append(' '); } return new SentenceSample(documentText, newSentenceSpans.toArray(new Span[0])); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_letsmt_L0100644 0000000 0000000 00000000160 15217274217 032554 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/LetsmtDocument.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/LetsmtDocument.ja0100644 0000000 0000000 00000012070 15217274217 034155 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.letsmt; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.xml.parsers.SAXParser; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import opennlp.tools.util.XmlUtil; /** * A structure to hold the letsmt document. The documents contain sentences and depending on the * source it either contains tokenized text (words) or an un-tokenized sentence string. *

* The format specification can be found * * here. */ public class LetsmtDocument { private static final String ORG_XML_FEATURES_DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl"; public static class LetsmtSentence { private String nonTokenizedText; private String[] tokens; public String getNonTokenizedText() { return nonTokenizedText; } public String[] getTokens() { if (tokens != null) { return Arrays.copyOf(tokens, tokens.length); } return null; } } /** * A {@link DefaultHandler content handler} to receive and process SAX events. */ public static class LetsmtDocumentHandler extends DefaultHandler { private final List sentences = new ArrayList<>(); private final StringBuilder chars = new StringBuilder(); private List tokens = new ArrayList<>(); @Override public void characters(char[] ch, int start, int length) throws SAXException { chars.append(ch, start, length); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); // Note: // words are optional in sentences, if there are no words just the chars have to be captured switch (qName) { case "w": tokens.add(chars.toString().trim()); chars.setLength(0); break; // TODO: The sentence should contain the id, so it can be tracked back to the // place it came from case "s": LetsmtSentence sentence = new LetsmtSentence(); if (tokens.size() > 0) { sentence.tokens = tokens.toArray(new String[0]); tokens = new ArrayList<>(); } else { sentence.nonTokenizedText = chars.toString().trim(); } sentences.add(sentence); chars.setLength(0); } } } private final List sentences; private LetsmtDocument(List sentences) { this.sentences = sentences; } /** * @return Retrieves the sentences of a {@link LetsmtDocument}. */ public List getSentences() { return Collections.unmodifiableList(sentences); } /** * @param letsmtXmlIn The {@link InputStream} referencing the document to parse. * * @return A valid {@link LetsmtDocument} instance. * @throws IOException Thrown if IO errors occurred during loading or parsing. */ static LetsmtDocument parse(InputStream letsmtXmlIn) throws IOException { SAXParser saxParser = XmlUtil.createSaxParser(); try { XMLReader xmlReader = saxParser.getXMLReader(); LetsmtDocumentHandler docHandler = new LetsmtDocumentHandler(); xmlReader.setContentHandler(docHandler); xmlReader.setFeature(ORG_XML_FEATURES_DISALLOW_DOCTYPE_DECL, true); xmlReader.parse(new InputSource(letsmtXmlIn)); return new LetsmtDocument(docHandler.sentences); } catch (SAXException e) { throw new IOException("Failed to parse letsmt xml!", e); } } /** * @param file The {@link File} referencing the document to parse. * * @return A valid {@link LetsmtDocument} instance. * @throws IOException Thrown if IO errors occurred during loading or parsing. */ static LetsmtDocument parse(File file) throws IOException { try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { return parse(in); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_letsmt_L0100644 0000000 0000000 00000000166 15217274217 032562 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/LetsmtSentenceStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/LetsmtSentenceStr0100644 0000000 0000000 00000004504 15217274217 034246 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.letsmt; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; class LetsmtSentenceStream implements ObjectStream { private final LetsmtDocument source; private Iterator sentenceIt; LetsmtSentenceStream(LetsmtDocument source) { this.source = source; reset(); } @Override public SentenceSample read() throws IOException { StringBuilder sentencesString = new StringBuilder(); List sentenceSpans = new LinkedList<>(); for (int i = 0; sentenceIt.hasNext() && i < 25 ; i++) { LetsmtDocument.LetsmtSentence sentence = sentenceIt.next(); int begin = sentencesString.length(); if (sentence.getTokens() != null) { sentencesString.append(String.join(" ", sentence.getTokens())); } else if (sentence.getNonTokenizedText() != null) { sentencesString.append(sentence.getNonTokenizedText()); } sentenceSpans.add(new Span(begin, sentencesString.length())); sentencesString.append(' '); } // end of stream is reached, indicate that with null return value if (sentenceSpans.size() == 0) { return null; } return new SentenceSample(sentencesString.toString(), sentenceSpans.toArray(new Span[0])); } @Override public void reset() { sentenceIt = source.getSentences().iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_letsmt_L0100644 0000000 0000000 00000000175 15217274217 032562 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/LetsmtSentenceStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/LetsmtSentenceStr0100644 0000000 0000000 00000006273 15217274217 034253 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.letsmt; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.tokenize.DetokenizationDictionary; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.tokenize.DictionaryDetokenizer; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see SentenceSample * @see LetsmtSentenceStream */ @Internal public class LetsmtSentenceStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "dictionary", description = "specifies the file with detokenizer dictionary.") @ArgumentParser.OptionalParameter File getDetokenizer(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "letsmt", new LetsmtSentenceStreamFactory(LetsmtSentenceStreamFactory.Parameters.class)); } protected LetsmtSentenceStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); LetsmtDocument letsmtDoc = null; try { letsmtDoc = LetsmtDocument.parse(params.getData()); } catch (IOException ex) { CmdLineUtil.handleCreateObjectStreamError(ex); } // TODO Implement a filter stream to remove splits which are not at an eos char ObjectStream samples = new LetsmtSentenceStream(letsmtDoc); if (params.getDetokenizer() != null) { try { Detokenizer detokenizer = new DictionaryDetokenizer( new DetokenizationDictionary(params.getDetokenizer())); samples = new DetokenizeSentenceSampleStream(detokenizer, samples); } catch (IOException e) { throw new TerminateToolException(-1, "Failed to load detokenizer rules!", e); } } return samples; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_letsmt_p0100644 0000000 0000000 00000000156 15217274217 032625 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/letsmt/package-info.java0100644 0000000 0000000 00000001625 15217274217 034065 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the {@code letsmt} corpus format. */ package opennlp.tools.formats.letsmt; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/Masc.java0100644 0000000 0000000 00000001750 15217274217 032036 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; /** * A simple marker interface for classes that support or refer to * the {@link #MASC_FORMAT}. */ public interface Masc { String MASC_FORMAT = "masc"; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascDocument.java0100644 0000000 0000000 00000040742 15217274217 033541 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.SAXParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; import opennlp.tools.util.Span; import opennlp.tools.util.XmlUtil; public class MascDocument { private static final Logger logger = LoggerFactory.getLogger(MascDocument.class); private final List sentences; private final String pathToFile; private Iterator sentenceIterator; private boolean hasPennTags = false; private boolean hasNamedEntities = false; public MascDocument(String path, List sentences) { this.pathToFile = path; this.sentences = sentences; this.sentenceIterator = sentences.iterator(); } /** * Initializes a {@link MascDocument} with all the stand-off annotations translated into the * internal structure. * * @param path The path where the document header is. * @param f_primary The {@link InputStream file} with the raw corpus text. * @param f_seg The {@link InputStream file} with segmentation into quarks. * @param f_ne The {@link InputStream file} with named entities. * @param f_penn The {@link InputStream file} with tokenization and Penn POS tags produced * by GATE-5.0 ANNIE application. * @param f_s The {@link InputStream file} with sentence boundaries. * @return A document containing the text and its annotations. Immutability is not guaranteed yet. * @throws IOException if the raw data cannot be read or the alignment of the raw data * with annotations fails */ public static MascDocument parseDocument(String path, InputStream f_primary, InputStream f_seg, InputStream f_penn, InputStream f_s, InputStream f_ne) throws IOException { String text = readText(f_primary); List words = parseWords(f_seg); List sentenceSpans = parseSentences(f_s); List sentences = combineAnnotations(text, sentenceSpans, words); final MascDocument doc = new MascDocument(path, sentences); // if the file has Penn POS tags, add them if (f_penn != null) { doc.addPennTags(parsePennTags(f_penn)); } if (f_ne != null) { doc.addNamedEntityTags(parseNamedEntity(f_ne)); } //TODO: make the annotations immutable //TODO: should we cleanup the document (e.g. remove sentences without tokens?) return doc; } /** * Reads in the corpus file text. * * @param stream A valid, open {@link InputStream stream} for a corpus file. * * @return The text of the file. * @throws IOException Thrown if IO errors occurred. */ private static String readText(InputStream stream) throws IOException { try (Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { StringBuilder contents = new StringBuilder(); char[] buffer = new char[8192]; int read; while ((read = reader.read(buffer, 0, buffer.length)) > 0) { contents.append(buffer, 0, read); } return contents.toString(); } } /** * Parses the word segmentation stand-off annotation * * @param f_seg A valid, open {@link InputStream stream} for a file with segmentation. * @return A list of individual quarks, expressed as MascWord-s * @throws IOException Thrown if IO errors occurred. */ private static List parseWords(InputStream f_seg) throws IOException { try (BufferedInputStream bStream = new BufferedInputStream(f_seg)) { SAXParser saxParser = XmlUtil.createSaxParser(); MascWordParser handler = new MascWordParser(); try { saxParser.parse(bStream, handler); } catch (SAXException e) { throw new IOException("Could not parse the region annotation file"); } return Collections.unmodifiableList(handler.getAnchors()); } } /** * Parses the sentence annotation file, align it with the raw text * * @param f_s A valid, open {@link InputStream stream} for a sentence annotation file. * @return The {@link List} delimiting each sentence. * @throws IOException if the sentence file cannot be parsed or closed */ private static List parseSentences(InputStream f_s) throws IOException { try (BufferedInputStream bStream = new BufferedInputStream(f_s)) { SAXParser saxParser = XmlUtil.createSaxParser(); MascSentenceParser handler = new MascSentenceParser(); try { saxParser.parse(bStream, handler); } catch (SAXException e) { throw new IOException("Could not parse the sentence annotation file"); } List anchors = handler.getAnchors(); /* * Filter out sentence overlaps. * Keep only those sentences where sentence.end < nextSentence.beginning * avoid deleting in the middle and repeatedly shifting the list by copying into a new list */ //TODO: can we know a priori, if we need this filtering? List filteredAnchors = new ArrayList<>(); for (int i = 0; i < anchors.size() - 1; i++) { if (anchors.get(i).getEnd() < anchors.get(i + 1).getStart()) { filteredAnchors.add(anchors.get(i)); } } filteredAnchors.add(anchors.get(anchors.size() - 1)); return Collections.unmodifiableList(filteredAnchors); } } /** * Parses the Penn-POS (GATE5-ANNIE) stand-off annotation. * * @param f_penn A valid, open {@link InputStream stream} for a file with Penn POS tags. * * @return A map of three sub-maps: tokenToTag, from Penn token ID (int) to Penn POS-tag, * tokenToBase, from Penn token ID (int) to the base and tokenToQuarks, from Penn token ID * (int) to a List of quark IDs contained in that token. * @throws IOException Thrown if IO errors occurred. */ private static Map> parsePennTags(InputStream f_penn) throws IOException { Map> tagsAndBases = new HashMap<>(); try (BufferedInputStream bStream = new BufferedInputStream(f_penn)) { SAXParser saxParser = XmlUtil.createSaxParser(); MascPennTagParser handler = new MascPennTagParser(); try { saxParser.parse(bStream, handler); } catch (SAXException e) { throw new IOException("Could not parse the Penn tag annotation file"); } tagsAndBases.put("tokenToTag", handler.getTags()); tagsAndBases.put("tokenToBase", handler.getBases()); tagsAndBases.put("tokenToQuarks", handler.getTokenToQuarks()); return tagsAndBases; } } /** * Parses the named entity stand-off annotation. * * @param f_ne A valid, open {@link InputStream stream} for a file with named entity annotations. * @return A map with two sub-maps, entityIDtoEntityType, mapping entity ID integers * to entity type Strings, and entityIDsToTokens, mapping entity ID integers to Penn * token ID integers. * @throws IOException Thrown if IO errors occurred. */ private static Map> parseNamedEntity(InputStream f_ne) throws IOException { try (BufferedInputStream bStream = new BufferedInputStream(f_ne)) { SAXParser saxParser = XmlUtil.createSaxParser(); MascNamedEntityParser handler = new MascNamedEntityParser(); try { saxParser.parse(bStream, handler); } catch (SAXException e) { throw new IOException("Could not parse the named entity annotation file", e); } Map entityIDtoEntityType = handler.getEntityIDtoEntityType(); Map> entityIDsToTokens = handler.getEntityIDsToTokens(); Map> results = new HashMap<>(); results.put("entityIDtoEntityType", entityIDtoEntityType); results.put("entityIDsToTokens", entityIDsToTokens); return results; } } /** * Combines the raw text with annotations that every file should have. * * @param text The raw text. * @param sentenceSpans The spans defining individual sentences. Overlaps are not permitted. * @param words The quarks of the raw text. * @return A list of sentences, each of which is a list of quarks. Some quarks may belong to * more than one sentence. Quarks which do not belong to a single sentence are silently dropped. * @throws IOException If sentences and quarks cannot be aligned. */ private static List combineAnnotations(String text, List sentenceSpans, List words) throws IOException { int wordIndex = 0; int wordCount = words.size(); List sentences = new ArrayList<>(); for (Span s : sentenceSpans) { if (s.getEnd() - s.getStart() > 0) { List quarks = new ArrayList<>(); int sentenceStart = s.getStart(); int sentenceEnd = s.getEnd(); // TODO: is it okay that quarks can cross sentence boundary? What are the implications? /* * Allow quarks to cross sentence boundary. * The decisive factor determining if a quark belongs to a sentence is if they overlap. * I.e. sent.getEnd() > quark.getStart() && sent.getStart() < quark.getEnd() */ MascWord nextWord = words.get(wordIndex); // Find sentence beginning, should not be needed unless overlaps occur while (sentenceStart < nextWord.getEnd() && wordIndex > 0) { wordIndex--; nextWord = words.get(wordIndex); } // TODO: can this be translated into Span's methods .crosses()/.contains()? // Find all quarks contained or crossing the span of that sentence boolean sentenceOver = false; while ((!sentenceOver) && wordIndex < wordCount) { nextWord = words.get(wordIndex); int nextWordStart = nextWord.getStart(); int nextWordEnd = nextWord.getEnd(); // word either ends or starts or ends & starts in the middle of sentence if (sentenceEnd > nextWordStart && sentenceStart < nextWordEnd) { quarks.add(nextWord); if (sentenceEnd == nextWordEnd) { sentenceOver = true; } wordIndex++; } else if (sentenceEnd <= nextWordStart) { sentenceOver = true; } else { wordIndex++; } } // If we are at the end of words, but not in the last sentence, throw an error if (!sentenceOver && sentences.size() != sentenceSpans.size() - 1) { throw new IOException("Sentence ends and word ends do not match." + "First sentence not completed ends at character: " + sentenceEnd); } MascSentence sentence = new MascSentence(sentenceStart, sentenceEnd, text, quarks, words); sentences.add(sentence); } } return Collections.unmodifiableList(sentences); } /** * Attaches the named entity labels to individual tokens. * * @param namedEntities A map with two sub-maps, entityIDtoEntityType, mapping entity ID integers * to entity type Strings, and entityIDsToTokens, mapping entity ID integers to Penn * token ID integers */ @SuppressWarnings("unchecked") private void addNamedEntityTags(Map> namedEntities) { try { Map entityIDtoEntityType = (Map) namedEntities.get("entityIDtoEntityType"); Map> entityIDsToTokens = (Map>) namedEntities.get("entityIDsToTokens"); for (MascSentence s : sentences) { boolean success = s.addNamedEntities(entityIDtoEntityType, entityIDsToTokens); if (!success) { logger.warn("Issues occurred in the file: {}", pathToFile); } } hasNamedEntities = true; } catch (IOException e) { logger.error("Failed connecting tokens and named entities. " + "The error occurred in the file: {}", pathToFile, e); } } /** * Attach tags and bases to MascWords in each of the sentences. * * @param tagMaps A map of three sub-maps: tokenToTag, from Penn token ID (int) to Penn POS-tag, * * tokenToBase, from Penn token ID (int) to the base and tokenToQuarks, from Penn token ID * * (int) to a List of quark IDs contained in that token. */ @SuppressWarnings("unchecked") private void addPennTags(Map> tagMaps) throws IOException { try { // Extract individual mappings Map tokenToTag = (Map) tagMaps.get("tokenToTag"); Map tokenToBase = (Map) tagMaps.get("tokenToBase"); Map tokenToQuarks = (Map) tagMaps.get("tokenToQuarks"); //Check that all tokens have at least one quark. for (Map.Entry token : tokenToQuarks.entrySet()) { if (token.getValue().length == 0) { logger.warn("Token without quarks: {}", token.getKey()); } } Map quarkToTokens = new HashMap<>(); for (Map.Entry tokenAndQuarks : tokenToQuarks.entrySet()) { int token = tokenAndQuarks.getKey(); int[] quarks = tokenAndQuarks.getValue(); for (int quark : quarks) { //very rarely, one quark may belong to several token //this is probably a mistake in the corpus annotation if (quarkToTokens.containsKey(quark)) { int[] tokens = quarkToTokens.get(quark); int[] newTokens = new int[tokens.length + 1]; newTokens[0] = token; System.arraycopy(tokens, 0, newTokens, 1, tokens.length); logger.warn("One quark belongs to several tokens. f-seg ID: {}.", quark); logger.warn("The error occurred in file: {}", pathToFile); quarkToTokens.put(quark, newTokens); } else { quarkToTokens.put(quark, new int[] {token}); } } } for (MascSentence s : sentences) { boolean success = s.tokenizePenn(tokenToQuarks, quarkToTokens, tokenToBase, tokenToTag); if (!success) { logger.warn("Issues occurred in the file: {}", pathToFile); } } hasPennTags = true; } catch (Exception e) { throw new IOException("Could not attach POS tags to words. " + e.getMessage() + Arrays.toString(e.getStackTrace())); } } /** * Checks whether there is Penn tagging produced by GATE-5.0 ANNIE. * * @return {@code true} if this file has aligned tags/tokens, {@code false} otherwise. */ public boolean hasPennTags() { return hasPennTags; } /** * Checks whether there is NER by GATE-5.0 ANNIE. * * @return {@code true} if this file has named entities, {@code false} otherwise. */ public boolean hasNamedEntities() { return hasNamedEntities; } /** * @return Retrieves the next sentence or {@code null} if end of document reached. */ public MascSentence read() { MascSentence next = null; if (sentenceIterator.hasNext()) { next = sentenceIterator.next(); } return next; } /** * Resets the reading of sentences to the beginning of the document. */ public void reset() { this.sentenceIterator = this.sentences.iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000162 15217274217 032516 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascDocumentStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascDocumentStream.0100644 0000000 0000000 00000017312 15217274217 034050 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.BufferedInputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Stack; import javax.xml.parsers.SAXParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.XmlUtil; public class MascDocumentStream implements ObjectStream { private static final Logger logger = LoggerFactory.getLogger(MascDocumentStream.class); /** * A helper class to parse the header (.hdr) files. */ private static class HeaderHandler extends DefaultHandler { private HashMap annotationFiles = null; private String file = null; private String fType = null; protected HashMap getPathList() { return annotationFiles; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // create a new annotation file and put it in map // initialize File object and set path attribute if (qName.equalsIgnoreCase("annotation") || qName.equalsIgnoreCase("primaryData")) { file = attributes.getValue("loc"); fType = attributes.getValue("f.id"); // initialize list if (annotationFiles == null) { annotationFiles = new HashMap<>(); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // add annotation object to list if (qName.equalsIgnoreCase("annotation") || qName.equalsIgnoreCase("primaryData")) { annotationFiles.put(fType, file); } } } private final List documents = new LinkedList<>(); private Iterator documentIterator; private final SAXParser saxParser; public MascDocumentStream(File mascCorpusDirectory) throws IOException { this(mascCorpusDirectory, true, pathname -> pathname.getName().contains("")); } /** * Creates a MascDocumentStream to read the documents from a given directory. * Works iff all annotation files mentioned in the headers are present. * * @param mascCorpusDirectory the directory containing all the MASC files * @param searchRecursive whether the search should go through subdirectories * @param fileFilter a custom file filter to filter out some files or * null to accept anything * @throws IOException if any stage of the stream creation fails */ public MascDocumentStream(File mascCorpusDirectory, boolean searchRecursive, FileFilter fileFilter) throws IOException { saxParser = XmlUtil.createSaxParser(); if (!mascCorpusDirectory.isDirectory()) { throw new IOException("Input corpus directory must be a directory " + "according to File.isDirectory()!"); } int failedLoads = 0; Stack directoryStack = new Stack<>(); directoryStack.add(mascCorpusDirectory); while (!directoryStack.isEmpty()) { for (File file : directoryStack.pop().listFiles(fileFilter)) { if (file.isFile()) { String hdrFilePath = file.getAbsolutePath(); // look for the header files if (hdrFilePath.endsWith(".hdr")) { HashMap fileGroup = checkAnnotations(hdrFilePath); InputStream f_primary = new BufferedInputStream( new FileInputStream(fileGroup.get("f.text"))); InputStream f_seg = (fileGroup.containsKey("f.seg")) ? new BufferedInputStream(new FileInputStream(fileGroup.get("f.seg"))) : null; InputStream f_penn = (fileGroup.containsKey("f.penn")) ? new BufferedInputStream(new FileInputStream(fileGroup.get("f.penn"))) : null; InputStream f_s = (fileGroup.containsKey("f.s")) ? new BufferedInputStream(new FileInputStream(fileGroup.get("f.s"))) : null; InputStream f_ne = (fileGroup.containsKey("f.ne")) ? new BufferedInputStream(new FileInputStream(fileGroup.get("f.ne"))) : null; try { documents.add(MascDocument.parseDocument(hdrFilePath, f_primary, f_seg, f_penn, f_s, f_ne)); } catch (IOException e) { logger.error("Failed to parse the file: {}", hdrFilePath, e); failedLoads++; } } } else if (searchRecursive && file.isDirectory()) { directoryStack.push(file); } } } logger.info("Documents loaded: {}", documents.size()); if (failedLoads > 0) { logger.info("Failed loading {} documents.", failedLoads); } reset(); } /** * Check that all annotation files mentioned in the header are present * * @param path The path to header * @throws IOException If corpus integrity is violated */ private HashMap checkAnnotations(String path) throws IOException { HeaderHandler handler = new HeaderHandler(); HashMap fileGroup = new HashMap<>(); File hdrFile = new File(path); try { saxParser.parse(hdrFile, handler); } catch (SAXException e) { throw new IOException("Invalid corpus format. " + "Could not parse the header: " + path); } HashMap annotationFiles = handler.getPathList(); String pathToFolder = hdrFile.getParentFile().getAbsolutePath(); for (Map.Entry annotation : annotationFiles.entrySet()) { File file = new File(pathToFolder, annotation.getValue()); if (!(file.isFile() && file.exists())) { throw new IOException("Corpus integrity violated. " + "Annotation file " + file.getAbsolutePath() + " is missing."); } fileGroup.put(annotation.getKey(), file); } return fileGroup; } /** * Reset the reading of all documents to the first sentence. * Reset the corpus to the first document. */ @Override public void reset() { for (MascDocument doc : documents) { doc.reset(); } documentIterator = documents.iterator(); } /** * Return the next document. Client needs to check if this document has the necessary annotations. * * @return A corpus document with all its annotations. * @throws IOException if anything goes wrong. */ @Override public MascDocument read() throws IOException { MascDocument doc = null; if (documentIterator.hasNext()) { doc = documentIterator.next(); } return doc; } /** * Remove the corpus from the memory. */ @Override public void close() { documentIterator = null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000165 15217274217 032521 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascNamedEntityParser.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascNamedEntityPars0100644 0000000 0000000 00000007663 15217274217 034117 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * A class to process the MASC Named entity stand-off annotation file */ public class MascNamedEntityParser extends DefaultHandler { private static final Logger logger = LoggerFactory.getLogger(MascNamedEntityParser.class); private final Map entityIDtoEntityType = new HashMap<>(); private final Map> entityIDsToTokens = new HashMap<>(); private final Map tokenToEntity = new HashMap<>(); public Map getEntityIDtoEntityType() { return entityIDtoEntityType; } public Map> getEntityIDsToTokens() { return entityIDsToTokens; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { if (qName.equals("a")) { int entityID = Integer.parseInt( attributes.getValue("ref").replaceFirst("ne-n", "")); String label = attributes.getValue("label"); if (entityIDtoEntityType.containsKey(entityID)) { throw new SAXException("Multiple labels for one named entity"); } else { entityIDtoEntityType.put(entityID, label); } } if (qName.equals("edge")) { int entityID = Integer.parseInt( attributes.getValue("from").replaceFirst("ne-n", "")); int tokenID = Integer.parseInt( attributes.getValue("to").replaceFirst("penn-n", "")); if (!entityIDsToTokens.containsKey(entityID)) { List tokens = new ArrayList<>(); tokens.add(tokenID); entityIDsToTokens.put(entityID, tokens); } else { entityIDsToTokens.get(entityID).add(tokenID); } /* Not sure what to do with this. There might be multiple entity links to one token. E.g. Colorado will be one token with the entities "city" and "province". For now, we'll only raise alarm when one TokenID should be assigned to different top-level labels, e.g. person & location (since we are dropping the low-level annotations at the moment). To make this work in OpenNLP (does not allow overlaps), we'll keep only the first named entity type. */ //todo: Do we want to give the user control over which types have priority? String type = entityIDtoEntityType.get(entityID); if (tokenToEntity.containsKey(tokenID) && !type.equals(tokenToEntity.get(tokenID))) { logger.warn("One token assigned to different named entity types.\n" + "\tPenn-TokenID: {}\n\tToken types: \"{}\", \"{}\"\n\tKeeping only " + "\"type\"", tokenID, type, tokenToEntity.get(tokenID)); } tokenToEntity.put(tokenID, type); } } catch (Exception e) { throw new SAXException("Could not parse the named entity annotation file.\n" + e.getMessage(), e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000173 15217274217 032520 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascNamedEntitySampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascNamedEntitySamp0100644 0000000 0000000 00000006313 15217274217 034101 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.IOException; import java.util.List; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; public class MascNamedEntitySampleStream extends FilterObjectStream { private MascDocument buffer; /** * Initializes {@link MascNamedEntitySampleStream} from a stream of {@link MascDocument documents}. * * @param samples A {@link ObjectStream} of samples. * @throws IOException Thrown if none of the documents has NE labels. */ public MascNamedEntitySampleStream(ObjectStream samples) throws IOException { super(samples); try { do { buffer = samples.read(); } while (!buffer.hasNamedEntities()); } catch (Exception e) { throw new IOException("None of the documents has named entity labels" + e.getMessage()); } } /** * Reads the next sample of named entities. * * @return One {@link NameSample sentence together with its named entity annotation}. * @throws IOException Thrown if the sample cannot be extracted */ @Override public NameSample read() throws IOException { /* * Read the documents one sentence at a time * If the document is over, move to the next one * If both document stream and sentence stream are over, return null */ try { MascSentence sentence = buffer.read(); while (sentence == null) { buffer = samples.read(); if (buffer == null) { return null; } if (buffer.hasNamedEntities()) { sentence = buffer.read(); } } List tokens = sentence.getTokenStrings(); String[] tokensArray = new String[tokens.size()]; tokens.toArray(tokensArray); List namedEntities = sentence.getNamedEntities(); Span[] namedEntitiesArray = new Span[namedEntities.size()]; namedEntities.toArray(namedEntitiesArray); // TODO: should the user decide about clearAdaptiveData? return new NameSample(tokensArray, namedEntitiesArray, true); } catch (IOException e) { throw new IOException("Could not get a sample of named entities from the data."); } } @Override public void reset() throws IOException, UnsupportedOperationException { samples.reset(); buffer = samples.read(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000202 15217274217 032511 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascNamedEntitySampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascNamedEntitySamp0100644 0000000 0000000 00000005555 15217274217 034110 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.FileFilter; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see NameSample * @see MascPOSSampleStream */ @Internal public class MascNamedEntitySampleStreamFactory extends AbstractSampleStreamFactory implements Masc { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "recurrentSearch", description = "search through files recursively") Boolean getRecurrentSearch(); @ArgumentParser.ParameterDescription(valueName = "fileFilterString", description = "only include files which contain a given string in their name") String getFileFilter(); } protected MascNamedEntitySampleStreamFactory(Class params) { super(params); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, MASC_FORMAT, new MascNamedEntitySampleStreamFactory(MascNamedEntitySampleStreamFactory.Parameters.class)); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); try { FileFilter fileFilter = pathname -> pathname.getName().contains(params.getFileFilter()); return new MascNamedEntitySampleStream( new MascDocumentStream(params.getData(), params.getRecurrentSearch(), fileFilter)); } catch (IOException e) { CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000163 15217274217 032517 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascPOSSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascPOSSampleStream0100644 0000000 0000000 00000005510 15217274217 034014 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.IOException; import java.util.List; import opennlp.tools.postag.POSSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public class MascPOSSampleStream extends FilterObjectStream { private MascDocument buffer; /** * Initializes {@link MascPOSSampleStream} from a stream of {@link MascDocument documents}. * * @param samples A {@link ObjectStream} of samples. * @throws IOException Thrown if none of the documents has POS tags. */ public MascPOSSampleStream(ObjectStream samples) throws IOException { super(samples); try { do { buffer = samples.read(); } while (!buffer.hasPennTags()); // For now, we'll always use Penn tags } catch (Exception e) { throw new IOException("None of the documents has POS tags" + e.getMessage()); } } /** * Reads the next sample. * * @return One {@link POSSample sentence together with its POS tags}. * @throws IOException Thrown if the sample cannot be extracted. */ @Override public POSSample read() throws IOException { /* * Read the documents one sentence at a time * If the document is over, move to the next one * If both document stream and sentence stream are over, return null */ try { MascSentence sentence = buffer.read(); while (sentence == null) { buffer = samples.read(); if (buffer == null) { return null; } if (buffer.hasPennTags()) { sentence = buffer.read(); } } List tokens = sentence.getTokenStrings(); List POStags = sentence.getTags(); return new POSSample(tokens, POStags); } catch (IOException e) { throw new IOException("Could not get a sample of POS tags from the data."); } } @Override public void reset() throws IOException, UnsupportedOperationException { samples.reset(); buffer = samples.read(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000172 15217274217 032517 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascPOSSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascPOSSampleStream0100644 0000000 0000000 00000005477 15217274217 034030 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.FileFilter; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.postag.POSSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see POSSample * @see MascPOSSampleStream */ @Internal public class MascPOSSampleStreamFactory extends AbstractSampleStreamFactory implements Masc { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "recurrentSearch", description = "search through files recursively") Boolean getRecurrentSearch(); @ArgumentParser.ParameterDescription(valueName = "fileFilterString", description = "only include files which contain a given string in their name") String getFileFilter(); } protected MascPOSSampleStreamFactory(Class params) { super(params); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(POSSample.class, MASC_FORMAT, new MascPOSSampleStreamFactory(Parameters.class)); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); try { FileFilter fileFilter = pathname -> pathname.getName().contains(params.getFileFilter()); return new MascPOSSampleStream( new MascDocumentStream(params.getData(), params.getRecurrentSearch(), fileFilter)); } catch (IOException e) { // That will throw an exception CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000161 15217274217 032515 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascPennTagParser.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascPennTagParser.j0100644 0000000 0000000 00000006755 15217274217 034012 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.util.HashMap; import java.util.Map; import java.util.Stack; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * A class for parsing MASC's Penn tagging/tokenization stand-off annotation */ public class MascPennTagParser extends DefaultHandler { private final Map tokenToQuarks = new HashMap<>(); private final Map tokenToTag = new HashMap<>(); private final Map tokenToBase = new HashMap<>(); private final Stack tokenStack = new Stack<>(); private final Stack tokenStackTag = new Stack<>(); public Map getTags() { return tokenToTag; } public Map getBases() { return tokenToBase; } public Map getTokenToQuarks() { return tokenToQuarks; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { //get the link between region and Penn tag if (qName.equals("node")) { tokenStack.push(Integer.parseInt(attributes.getValue("xml:id") .replaceFirst("penn-n", ""))); } if (qName.equals("link")) { if (tokenStack.isEmpty()) { throw new SAXException("The linking of tokens to quarks is broken."); } String[] targets = attributes.getValue("targets") .replace("seg-r", "").split(" "); int[] regions = new int[targets.length]; for (int i = 0; i < targets.length; i++) { int region = Integer.parseInt(targets[i]); regions[i] = region; } tokenToQuarks.put(tokenStack.pop(), regions); } if (qName.equals("a")) { tokenStackTag.push(Integer.parseInt(attributes.getValue("ref") .replaceFirst("penn-n", ""))); } if (qName.equals("f")) { String type = attributes.getValue("name"); if (tokenStackTag.isEmpty()) { throw new SAXException("The linking of tokens to their tags/bases is broken."); } if (type.equals("msd")) { tokenToTag.put(tokenStackTag.peek(), attributes.getValue("value")); } else if (type.equals("base")) { tokenToBase.put(tokenStackTag.peek(), attributes.getValue("value")); } } } catch (Exception e) { throw new SAXException("Could not parse the Penn-POS annotation file.\n" + e.getMessage(), e); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // we can forget the current node if (qName.equals("a")) { tokenStackTag.pop(); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascSentence.java0100644 0000000 0000000 00000027114 15217274217 033525 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.IOException; import java.io.Serial; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.Span; public class MascSentence extends Span { @Serial private static final long serialVersionUID = 6295507533472650848L; private static final Logger logger = LoggerFactory.getLogger(MascSentence.class); /** * A helper class to extract the extract a quark from the corpus file even if it is beyond the * bounds of the sentence. * * @param wordsById Quarks of the sentence organized by their id * @param allDocumentWords Quarks of the document organized by their id */ private record QuarkExtractor(Map wordsById, List allDocumentWords) { /** * Extract a quark by its key * * @param key The quark's ID * @return The {@link MascWord quark reference}. * @throws IOException Thrown if the {@code key} was not found in the document. */ private MascWord get(int key) throws IOException { // First, check if this word is in the sentence // TODO: evaluate the necessity: HashMaps are O(1), right? if (wordsById.containsKey(key)) { return wordsById.get(key); } else { for (MascWord wordFromWholeDocument : allDocumentWords) { if (wordFromWholeDocument.getId() == key) { return wordFromWholeDocument; } } } throw new IOException("Word" + key + " not found in the document."); } } private final List allDocumentWords; private final String text; private final List words; private final Map wordsById; private List sentenceTokens = null; private final Map tokensById = new HashMap<>(); private List namedEntities = new ArrayList<>(); /** * Initializes a {@link MascSentence} containing its associated text and quarks * * @param s Start of the sentence within the corpus file * @param e End of the sentence within the corpus file * @param text The reference to text of the corpus file * @param sentenceQuarks The quarks found in that sentence * @param allQuarks The reference to a list of all quarks in the file */ public MascSentence(int s, int e, String text, List sentenceQuarks, List allQuarks) { super(s, e); this.text = text; this.words = sentenceQuarks; this.allDocumentWords = allQuarks; // We'll create a map of word ID's and the word ref's to speed up the tokenization HashMap idToWordMap = new HashMap<>(); for (MascWord w : sentenceQuarks) { idToWordMap.put(w.getId(), w); } wordsById = idToWordMap; } /** * Add the Penn tokenization and POS tagging to the sentence. * * @param tokenToQuarks A map from token ID to quarks in that token. * @param quarkToTokens A map of quark IDs and the token IDs containing that quark. * @param tokenToBase Token ID to the token base. * @param tokenToTag Token ID to the POS tag. * * @return {@code true} if no issue encountered, {@code false} if tokens cross sentence boundaries. * @throws IOException Thrown if IO errors occurred. */ boolean tokenizePenn(Map tokenToQuarks, Map quarkToTokens, Map tokenToBase, Map tokenToTag) throws IOException { boolean fileWithoutIssues = true; QuarkExtractor extractor = new QuarkExtractor(wordsById, allDocumentWords); sentenceTokens = new ArrayList<>(); Map tokensProcessed = new HashMap<>(); for (MascWord w : words) { int currentQuarkId = w.getId(); //extract the node to which this word belongs int[] tokens = quarkToTokens.get(currentQuarkId); //Only continue, if the word belongs to at least one node if (tokens != null) { for (int token : tokens) { //check if we already have the token if (!tokensProcessed.containsKey(token)) { int[] quarksOfToken = tokenToQuarks.get(token); // Get the quark IDs contained in the token if (quarksOfToken == null) { logger.warn("Token without quarks found: {}", token); } for (int quark : quarksOfToken) { if (!wordsById.containsKey(quark)) { fileWithoutIssues = false; logger.warn("Some tokens cross sentence boundaries." + "\n\tQuark ID: {}" + "\n\tPenn token ID: {}", quark, token ); } } /*Because there are some quarks which are parts of tokens outside a sentence We need to check every time if that quark was actually assigned to the sentence If not, we need to extract it manually from the whole document*/ MascWord[] quarks = new MascWord[quarksOfToken.length]; //Get the actual quark references for (int currentQuark = 0; currentQuark < quarks.length; currentQuark++) { quarks[currentQuark] = extractor.get(quarksOfToken[currentQuark]); } int start = extractor.get(quarksOfToken[0]).getStart(); int end = extractor.get(quarksOfToken[quarksOfToken.length - 1]).getEnd(); //only insert tokens with non-zero length, apparently some of them exist in the corpus if (end - start > 0) { sentenceTokens.add(new MascToken(start, end, token, tokenToTag.get(token), tokenToBase.get(token), quarks)); tokensProcessed.put(token, true); } } } } } for (int i = 0; i < sentenceTokens.size(); i++) { MascToken t = sentenceTokens.get(i); tokensById.put(t.getTokenId(), i); } sentenceTokens = Collections.unmodifiableList(sentenceTokens); return fileWithoutIssues; } /** * Add the named entity annotation to the tokenized sentence * * @param entityIDtoEntityType Maps the named entity ID to its type * @param entityIDsToTokens A list of tokens covered by each named entity * * @return {@code true} if all went well, {@code false} if named entities overlap. * @throws IOException Thrown if IO errors occurred. */ boolean addNamedEntities(Map entityIDtoEntityType, Map> entityIDsToTokens) throws IOException { boolean fileWithoutIssues = true; if (sentenceTokens == null) { throw new IOException("Named entity labels provided for an un-tokenized sentence."); } //for each named entity identify its span for (Map.Entry> namedEntity : entityIDsToTokens.entrySet()) { int entityID = namedEntity.getKey(); String type = entityIDtoEntityType.get(entityID); List tokenIDs = namedEntity.getValue(); int start = sentenceTokens.size(); int end = 0; boolean entityInThisSentence = false; for (int tokenID : tokenIDs) { if (tokensById.containsKey(tokenID)) { entityInThisSentence = true; if (tokensById.get(tokenID) < start) { start = tokensById.get(tokenID); } if (tokensById.get(tokenID) > end) { end = tokensById.get(tokenID) + 1; } } } if (entityInThisSentence) { namedEntities.add(new Span(start, end, type)); } } Comparator compareByStart = Comparator.comparingInt(Span::getStart); namedEntities.sort(compareByStart); Set overlaps = new HashSet<>(); int leftIndex = 0; int rightIndex = leftIndex + 1; while (rightIndex < namedEntities.size()) { Span leftSpan = namedEntities.get(leftIndex); Span rightSpan = namedEntities.get(rightIndex); if (leftSpan.contains(rightSpan) || leftSpan.crosses(rightSpan)) { logger.warn("Named entities overlap. This is forbidden in OpenNLP." + "\n\tKeeping the longer of them."); if (rightSpan.length() > leftSpan.length()) { overlaps.add(leftIndex); } else { overlaps.add(rightIndex); } fileWithoutIssues = false; rightIndex++; } else { leftIndex++; } } if (!fileWithoutIssues) { List namedEntitiesNoOverlaps = new ArrayList<>(); for (int i = 0; i < namedEntities.size() - 1; i++) { if (!overlaps.contains(i)) { namedEntitiesNoOverlaps.add(namedEntities.get(i)); } } namedEntities = Collections.unmodifiableList(namedEntitiesNoOverlaps); } return fileWithoutIssues; } /** * @return Retrieves the {@link List named entities}, e.g. {@code Span(1,3, "org")} for tokens [1,3). */ public List getNamedEntities() { return namedEntities; } /** * @return Retrieves text of the sentence as defined by the sentence segmentation annotation. */ public String getSentDetectText() { return text.substring(getStart(), getEnd()); } /** * @return Retrieves text of the sentence as defined by the tokens in it. */ public String getTokenText() { if (sentenceTokens.isEmpty()) { return ""; } return text.substring(sentenceTokens.get(0).getStart(), sentenceTokens.get(sentenceTokens.size() - 1).getEnd()); } /** * @return The texts of the individual tokens in the sentence */ public List getTokenStrings() { List tokenArray = new ArrayList<>(); for (MascToken t : sentenceTokens) { tokenArray.add(text.substring(t.getStart(), t.getEnd())); } return Collections.unmodifiableList(tokenArray); } /** * Retrieves the boundaries of individual tokens. * * @return The {@link List spans} representing the tokens of the sentence, * according to Penn tokenization. */ public List getTokensSpans() { List tokenSpans = new ArrayList<>(); int offset = sentenceTokens.isEmpty() ? 0 : sentenceTokens.get(0).getStart(); for (MascToken i : sentenceTokens) { tokenSpans.add(new Span(i.getStart() - offset, i.getEnd() - offset)); } return Collections.unmodifiableList(tokenSpans); } /** * @return Get the (individual) tags of tokens in the sentence. * * @throws IOException Thrown if used on an un-tokenized sentence. */ public List getTags() throws IOException { List tags = new ArrayList<>(); for (MascToken t : sentenceTokens) { tags.add(t.getPos()); } return tags; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000162 15217274217 032516 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascSentenceParser.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascSentenceParser.0100644 0000000 0000000 00000003553 15217274217 034041 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import opennlp.tools.util.Span; /** * A class to parse the sentence segmentation stand-off annotation. */ class MascSentenceParser extends DefaultHandler { private final List sentenceAnchors = new ArrayList<>(); public List getAnchors() { return sentenceAnchors; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { // create a sentence and put it into the list of sentences if (qName.equalsIgnoreCase("region")) { String[] anchors = attributes.getValue("anchors").split(" "); int left = Integer.parseInt(anchors[0]); int right = Integer.parseInt(anchors[1]); sentenceAnchors.add(new Span(left, right)); } } catch (Exception e) { throw new SAXException("Could not parse the sentence annotation file."); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000170 15217274217 032515 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascSentenceSampleS0100644 0000000 0000000 00000006153 15217274217 034072 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.IOException; import java.util.ArrayList; import java.util.List; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; public class MascSentenceSampleStream extends FilterObjectStream { private final int sentencesPerSample; private MascDocument buffer; public MascSentenceSampleStream(ObjectStream samples, int sentencesPerSample) throws IOException { super(samples); this.sentencesPerSample = sentencesPerSample; buffer = samples.read(); } /** * Reads a new {@link SentenceSample sample of sentences}. * * @return The {@link SentenceSample specified number of sentences}. * If fewer left, then return whatever is left. * * @throws IOException Thrown if IO errors occurred during read operation. */ @Override public SentenceSample read() throws IOException { try { StringBuilder documentText = new StringBuilder(); List sentenceSpans = new ArrayList<>(); for (int i = 0; i < sentencesPerSample; i++) { MascSentence sentence = buffer.read(); if (sentence != null) { // Current document still has sentences int startIndex = documentText.length(); documentText.append(sentence.getSentDetectText()).append(' '); sentenceSpans.add(new Span(startIndex, documentText.length() - 1)); } else if ((buffer = samples.read()) != null) { documentText.append('\n'); // Current document exhausted, but we can still move on to the next one i--; // This round does not count } else { // We exhausted all sentences in all documents break; } } if (documentText.length() > 0) { documentText.setLength(documentText.length() - 1); return new SentenceSample(documentText, sentenceSpans.toArray(new Span[0])); } return null; } catch (IOException e) { throw new IOException("You are reading an empty document stream. " + "Did you close it?"); } } @Override public void reset() throws IOException, UnsupportedOperationException { samples.reset(); buffer = samples.read(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000177 15217274217 032524 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascSentenceSampleS0100644 0000000 0000000 00000006141 15217274217 034067 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.FileFilter; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see SentenceSample * @see MascSentenceSampleStream */ @Internal public class MascSentenceSampleStreamFactory extends AbstractSampleStreamFactory implements Masc { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "sentencesPerSample", description = "number of sentences per sample") String getSentencesPerSample(); @ArgumentParser.ParameterDescription(valueName = "recurrentSearch", description = "search through files recursively") Boolean getRecurrentSearch(); @ArgumentParser.ParameterDescription(valueName = "fileFilterString", description = "only include files which contain a given string in their name") String getFileFilter(); } protected MascSentenceSampleStreamFactory(Class params) { super(params); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, MASC_FORMAT, new MascSentenceSampleStreamFactory(Parameters.class)); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); try { FileFilter fileFilter = pathname -> pathname.getName().contains(params.getFileFilter()); return new MascSentenceSampleStream( new MascDocumentStream(params.getData(), params.getRecurrentSearch(), fileFilter), Integer.parseInt(params.getSentencesPerSample())); } catch (IOException e) { // That will throw an exception CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascToken.java0100644 0000000 0000000 00000004756 15217274217 033050 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.Serial; import opennlp.tools.util.Span; /** * A specialized {@link Span} to express tokens in {@link MascDocument documents}. */ public class MascToken extends Span { @Serial private static final long serialVersionUID = -780646706788037041L; private final String pos; private final String base; private final int tokenId; private final MascWord[] quarks; /** * Initializes a {@link MascToken} which may combine multiple quarks. * * @param s The start of the token in the corpus file. * Must be equal to or greater than {@code 0}. * @param e The end of the token in the corpus file. * Must be equal to or greater than {@code 0} and be greater than {@code s}. * @param pennId The ID of the token as assigned by the Penn stand-off annotation. * @param pos The POS-tag. * @param base The base form. * @param quarks The {@link MascWord array of Quarks} contained in the token. * * @throws IllegalArgumentException Thrown if one of the parameters are invalid. */ public MascToken(int s, int e, int pennId, String pos, String base, MascWord[] quarks) { super(s, e); this.pos = pos; this.base = base; this.tokenId = pennId; this.quarks = quarks; } /** * @return Retrieves the ID of the token. */ public int getTokenId() { return tokenId; } /** * @return Retrieves the base form. */ public String getBase() { return base; } /** * @return Retrieves the POS tag. */ public String getPos() { return pos; } /** * @return Retrieves quarks of the token. */ public MascWord[] getQuarks() { return quarks; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000165 15217274217 032521 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascTokenSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascTokenSampleStre0100644 0000000 0000000 00000007332 15217274217 034121 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.IOException; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; public class MascTokenSampleStream extends FilterObjectStream { private static final Logger logger = LoggerFactory.getLogger(MascTokenSampleStream.class); private MascDocument buffer; /** * Initializes a {@link MascTokenSampleStream}. * * @param samples The {@link ObjectStream} samples to process. * @throws IOException Thrown if non of the {@link MascDocument documents} had Penn tokenization. */ public MascTokenSampleStream(ObjectStream samples) throws IOException { super(samples); try { do { buffer = samples.read(); } while (!buffer.hasPennTags()); // For now, we only use Penn tokenization } catch (Exception e) { throw new IOException("None of the documents has Penn tokenization" + e.getMessage()); } } @Override public TokenSample read() throws IOException { /* * Read the documents one sentence at a time * If the document is over, move to the next one * If both document stream and sentence stream are over, return null */ try { boolean sentenceFound = true; String sentenceString; List tokenSpans; MascSentence sentence; do { sentence = buffer.read(); while (sentence == null) { buffer = samples.read(); if (buffer == null) { return null; } if (buffer.hasPennTags()) { sentence = buffer.read(); } } sentenceString = sentence.getTokenText(); tokenSpans = sentence.getTokensSpans(); if (sentenceString.length() == 0) { logger.warn("Zero sentence found. There is a sentence " + "without any tokens. sentence: {}, spans: {}", sentenceString, tokenSpans); sentenceFound = false; } for (int i = 0; i < tokenSpans.size(); i++) { Span t = tokenSpans.get(i); if (t.getEnd() - t.getStart() == 0) { logger.warn("Zero token found. There is a token without any quarks." + " sentence: {}, spans: {}", sentenceString, tokenSpans); sentenceFound = false; } } } while (!sentenceFound); Span[] tokensSpansArray = new Span[tokenSpans.size()]; tokenSpans.toArray(tokensSpansArray); return new TokenSample(sentenceString, tokensSpansArray); } catch (IOException e) { throw new IOException("Could not get a sample of tokens from the data."); } } @Override public void reset() throws IOException, UnsupportedOperationException { samples.reset(); buffer = samples.read(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000174 15217274217 032521 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascTokenSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascTokenSampleStre0100644 0000000 0000000 00000006002 15217274217 034112 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.FileFilter; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see TokenSample * @see MascTokenSampleStream */ @Internal public class MascTokenSampleStreamFactory extends AbstractSampleStreamFactory implements Masc { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "sentencesPerSample", description = "number of sentences per sample") String getSentencesPerSample(); @ArgumentParser.ParameterDescription(valueName = "recurrentSearch", description = "search through files recursively") Boolean getRecurrentSearch(); @ArgumentParser.ParameterDescription(valueName = "fileFilterString", description = "only include files which contain a given string in their name") String getFileFilter(); } protected MascTokenSampleStreamFactory(Class params) { super(params); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(TokenSample.class, MASC_FORMAT, new MascTokenSampleStreamFactory(Parameters.class)); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); try { FileFilter fileFilter = pathname -> pathname.getName().contains(params.getFileFilter()); return new MascTokenSampleStream( new MascDocumentStream(params.getData(), params.getRecurrentSearch(), fileFilter)); } catch (IOException e) { // That will throw an exception CmdLineUtil.handleCreateObjectStreamError(e); } return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascWord.java0100644 0000000 0000000 00000003227 15217274217 032673 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.io.Serial; import opennlp.tools.util.Span; public class MascWord extends Span { @Serial private static final long serialVersionUID = 2133473549058189775L; private final int id; /** * Holds one of MASC's quarks, that is: basic-level units (may be sub-word). * * @param s The beginning of the word in the corpus file. * Must be equal to or greater than {@code 0}. * @param e The end of the word in the corpus file. * Must be equal to or greater than {@code 0} and be greater than {@code s}. * @param id The id as assigned by the stand-off annotation. * * @throws IllegalArgumentException Thrown if one of the parameters are invalid. */ public MascWord(int s, int e, int id) { super(s, e); this.id = id; } public int getId() { return id; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_masc_Mas0100644 0000000 0000000 00000000156 15217274217 032521 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascWordParser.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/MascWordParser.java0100644 0000000 0000000 00000003653 15217274217 034053 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.masc; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Class to parse the word ("quark") segmentation stand-off annotation. */ class MascWordParser extends DefaultHandler { private final List wordAnchors = new ArrayList<>(); public List getAnchors() { return wordAnchors; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { // create a word and put it into the list of words if (qName.equalsIgnoreCase("region")) { int id = Integer.parseInt(attributes.getValue("xml:id").replaceFirst("seg-r", "")); String[] anchors = attributes.getValue("anchors").split(" "); int left = Integer.parseInt(anchors[0]); int right = Integer.parseInt(anchors[1]); wordAnchors.add(new MascWord(left, right, id)); } } catch (Exception e) { throw new SAXException("Could not parse the word segmentation annotation file."); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/masc/package-info.java0100644 0000000 0000000 00000001621 15217274217 033474 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the {@code MASC} corpus format. */ package opennlp.tools.formats.masc; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_moses_Mo0100644 0000000 0000000 00000000172 15217274217 032555 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/moses/MosesSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/moses/MosesSentenceSampl0100644 0000000 0000000 00000005013 15217274217 034202 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.moses; import java.io.IOException; import java.util.LinkedList; import java.util.List; import opennlp.tools.sentdetect.EmptyLinePreprocessorStream; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * Moses is a statistical machine translation system that allows you * to automatically train translation models for any language pair. *

* Details are found on the * official website. */ public class MosesSentenceSampleStream extends FilterObjectStream { /** * Initializes a {@link MosesSentenceSampleStream}. * * @param sentences The {@link ObjectStream samples} as input. * Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public MosesSentenceSampleStream(ObjectStream sentences) { super(new EmptyLinePreprocessorStream(sentences)); } @Override public SentenceSample read() throws IOException { StringBuilder sentencesString = new StringBuilder(); List sentenceSpans = new LinkedList<>(); String sentence; for (int i = 0; i < 25 && (sentence = samples.read()) != null; i++) { int begin = sentencesString.length(); sentence = sentence.trim(); sentencesString.append(sentence); int end = sentencesString.length(); sentenceSpans.add(new Span(begin, end)); sentencesString.append(' '); } if (!sentenceSpans.isEmpty()) { return new SentenceSample(sentencesString.toString(), sentenceSpans.toArray(new Span[0])); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_moses_Mo0100644 0000000 0000000 00000000201 15217274217 032546 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/moses/MosesSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/moses/MosesSentenceSampl0100644 0000000 0000000 00000004004 15217274217 034201 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.moses; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Factory producing OpenNLP {@link MosesSentenceSampleStream} objects. *

* Note: Do not use this class, internal use only! * * @see SentenceSample * @see MosesSentenceSampleStream */ @Internal public class MosesSentenceSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "moses", new MosesSentenceSampleStreamFactory(Parameters.class)); } protected MosesSentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { ObjectStream lineStream = readData(args, Parameters.class); return new MosesSentenceSampleStream(lineStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_muc_Docu0100644 0000000 0000000 00000000165 15217274217 032534 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/DocumentSplitterStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/DocumentSplitterStre0100644 0000000 0000000 00000004721 15217274217 034240 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.muc; import java.io.IOException; import java.util.ArrayList; import java.util.List; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; class DocumentSplitterStream extends FilterObjectStream { private static final String DOC_START_ELEMENT = ""; private static final String DOC_END_ELEMENT = ""; private final List docs = new ArrayList<>(); DocumentSplitterStream(ObjectStream samples) { super(samples); } @Override public String read() throws IOException { if (docs.isEmpty()) { String newDocs = samples.read(); if (newDocs != null) { int docStartOffset = 0; while (true) { int startDocElement = newDocs.indexOf(DOC_START_ELEMENT, docStartOffset); int endDocElement = newDocs.indexOf(DOC_END_ELEMENT, docStartOffset); if (startDocElement != -1 && endDocElement != -1) { if (startDocElement < endDocElement) { docs.add(newDocs.substring(startDocElement, endDocElement + DOC_END_ELEMENT.length())); docStartOffset = endDocElement + DOC_END_ELEMENT.length(); } else { throw new InvalidFormatException(" element is not closed!"); } } else if (startDocElement != endDocElement) { throw new InvalidFormatException("Missing or element!"); } else { break; } } } } if (!docs.isEmpty()) { return docs.remove(0); } else { return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_muc_Muc60100644 0000000 0000000 00000000172 15217274217 032452 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/Muc6NameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/Muc6NameSampleStream0100644 0000000 0000000 00000006156 15217274217 034032 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.muc; import java.io.File; import java.nio.charset.StandardCharsets; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.cmdline.tokenizer.TokenizerModelLoader; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.formats.DirectorySampleStream; import opennlp.tools.formats.convert.FileToStringSampleStream; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.ThreadSafeTokenizerME; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.tokenize.TokenizerModel; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.StringUtil; /** * @see NameSample * @see MucNameSampleStream */ @Internal public class Muc6NameSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ParameterDescription(valueName = "modelFile") File getTokenizerModel(); } protected Muc6NameSampleStreamFactory() { super(Parameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "muc6", new Muc6NameSampleStreamFactory()); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } Parameters params = ArgumentParser.parse(args, Parameters.class); if (!params.getData().isDirectory() || !params.getData().exists()) { throw new TerminateToolException(-1, "The specified data directory is not valid!"); } TokenizerModel tokenizerModel = new TokenizerModelLoader().load(params.getTokenizerModel()); Tokenizer tokenizer = new ThreadSafeTokenizerME(tokenizerModel); ObjectStream mucDocStream = new FileToStringSampleStream( new DirectorySampleStream(params.getData(), file -> StringUtil.toLowerCase(file.getName()).endsWith(".sgm"), false), StandardCharsets.UTF_8); return new MucNameSampleStream(tokenizer, mucDocStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_muc_MucE0100644 0000000 0000000 00000000156 15217274217 032473 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/MucElementNames.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/MucElementNames.java0100644 0000000 0000000 00000002571 15217274217 034040 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.muc; import java.util.Set; class MucElementNames { static final String DOC_ELEMENT = "DOC"; static final String HEADLINE_ELEMENT = "HL"; static final String DATELINE_ELEMENT = "DATELINE"; static final String DD_ELEMENT = "DD"; static final String SENTENCE_ELEMENT = "s"; static final Set CONTENT_ELEMENTS; static { CONTENT_ELEMENTS = Set.of( MucElementNames.HEADLINE_ELEMENT, MucElementNames.DATELINE_ELEMENT, MucElementNames.DD_ELEMENT, MucElementNames.SENTENCE_ELEMENT); } private MucElementNames() { } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_muc_MucN0100644 0000000 0000000 00000000164 15217274217 032503 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/MucNameContentHandler.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/MucNameContentHandle0100644 0000000 0000000 00000007765 15217274217 034104 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.muc; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Stack; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.Span; public class MucNameContentHandler extends SgmlParser.ContentHandler { private static final String ENTITY_ELEMENT_NAME = "ENAMEX"; private static final String TIME_ELEMENT_NAME = "TIMEX"; private static final String NUM_ELEMENT_NAME = "NUMEX"; private static final Set NAME_ELEMENT_NAMES; private static final Set EXPECTED_TYPES; static { EXPECTED_TYPES = Set.of("PERSON", "ORGANIZATION", "LOCATION", "DATE", "TIME", "MONEY", "PERCENT"); NAME_ELEMENT_NAMES = Set.of(ENTITY_ELEMENT_NAME, TIME_ELEMENT_NAME, NUM_ELEMENT_NAME); } private final Tokenizer tokenizer; private final List storedSamples; private boolean isInsideContentElement = false; private final List text = new ArrayList<>(); private boolean isClearAdaptiveData = false; private final Stack incompleteNames = new Stack<>(); private final List names = new ArrayList<>(); /** * Initializes a {@link MucNameContentHandler}. * * @param tokenizer The {@link Tokenizer} to use. Must not be {@code null}. * @param storedSamples The {@link List samples} as input. * Must not be {@code null}. */ public MucNameContentHandler(Tokenizer tokenizer, List storedSamples) { this.tokenizer = tokenizer; this.storedSamples = storedSamples; } @Override public void startElement(String name, Map attributes) throws InvalidFormatException { if (MucElementNames.DOC_ELEMENT.equals(name)) { isClearAdaptiveData = true; } if (MucElementNames.CONTENT_ELEMENTS.contains(name)) { isInsideContentElement = true; } if (NAME_ELEMENT_NAMES.contains(name)) { String nameType = attributes.get("TYPE"); if (!EXPECTED_TYPES.contains(nameType)) { throw new InvalidFormatException("Unknown timex, numex or namex type: " + nameType + ", expected one of " + EXPECTED_TYPES); } incompleteNames.add(new Span(text.size(), text.size(), nameType.toLowerCase(Locale.ENGLISH))); } } @Override public void characters(CharSequence chars) { if (isInsideContentElement) { String[] tokens = tokenizer.tokenize(chars.toString()); text.addAll(Arrays.asList(tokens)); } } @Override public void endElement(String name) { if (NAME_ELEMENT_NAMES.contains(name)) { Span nameSpan = incompleteNames.pop(); nameSpan = new Span(nameSpan.getStart(), text.size(), nameSpan.getType()); names.add(nameSpan); } if (MucElementNames.CONTENT_ELEMENTS.contains(name)) { storedSamples.add(new NameSample(text.toArray(new String[0]), names.toArray(new Span[0]), isClearAdaptiveData)); if (isClearAdaptiveData) { isClearAdaptiveData = false; } text.clear(); names.clear(); isInsideContentElement = false; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_muc_MucN0100644 0000000 0000000 00000000162 15217274217 032501 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/MucNameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/MucNameSampleStream.0100644 0000000 0000000 00000004464 15217274217 034022 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.muc; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public class MucNameSampleStream extends FilterObjectStream { private final Tokenizer tokenizer; private final List storedSamples = new ArrayList<>(); /** * Initializes a {@link MucNameSampleStream}. * * @param tokenizer The {@link Tokenizer} to use. Must not be {@code null}. * @param samples The {@link ObjectStream samples} as input. * Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ protected MucNameSampleStream(Tokenizer tokenizer, ObjectStream samples) { super(samples); this.tokenizer = tokenizer; } @Override public NameSample read() throws IOException { if (storedSamples.isEmpty()) { String document = samples.read(); if (document != null) { // Note: This is a hack to fix invalid formatting in // some MUC files ... document = document.replace(">>", ">"); new SgmlParser().parse(new StringReader(document), new MucNameContentHandler(tokenizer, storedSamples)); } } if (!storedSamples.isEmpty()) { return storedSamples.remove(0); } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/SgmlParser.java0100644 0000000 0000000 00000014506 15217274217 033076 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.muc; import java.io.IOException; import java.io.Reader; import java.util.HashMap; import java.util.Map; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.StringUtil; /** * A SAX style SGML parser. * * @implNote The implementation is very limited, but good enough to parse the * MUC corpora. * Its must very likely be extended/improved/fixed to parse a different SGML corpora. */ public class SgmlParser { private static final char SYMBOL_CLOSE = '>'; private static final char SYMBOL_OPEN = '<'; private static final char SYMBOL_SLASH = '/'; private static final char SYMBOL_EQUALS = '='; private static final char SYMBOL_QUOT = '"'; /** * Defines methods to handle content produced by a {@link SgmlParser}. * A concrete implementation interprets the document specific details. */ public static abstract class ContentHandler { /** * Handles a SGML start element. * * @param name The name of the element's start tag. * @param attributes The attributes supplied with the start tag. It may be empty. * @throws InvalidFormatException Thrown if parameters were invalid. */ public abstract void startElement(String name, Map attributes) throws InvalidFormatException; /** * Handles a set of characters between SGML start and end tag. * * @param chars The characters to process. * @throws InvalidFormatException Thrown if parameters were invalid. */ public abstract void characters(CharSequence chars) throws InvalidFormatException; /** * Handles a SGML end element. * @param name The name of the element's end tag. */ public abstract void endElement(String name); } private static String extractTagName(CharSequence tagChars) throws InvalidFormatException { int fromOffset = 1; if (tagChars.length() > 1 && tagChars.charAt(1) == SYMBOL_SLASH) { fromOffset = 2; } for (int ci = 1; ci < tagChars.length(); ci++) { if (tagChars.charAt(ci) == SYMBOL_CLOSE || StringUtil.isWhitespace(tagChars.charAt(ci))) { return tagChars.subSequence(fromOffset, ci).toString(); } } throw new InvalidFormatException("Failed to extract tag name!"); } private static Map getAttributes(CharSequence tagChars) { // format: // space // key // = // " <- begin // value chars // " <- end Map attributes = new HashMap<>(); StringBuilder key = new StringBuilder(); StringBuilder value = new StringBuilder(); boolean extractKey = false; boolean extractValue = false; for (int i = 0; i < tagChars.length(); i++) { // White space indicates begin of new key name if (StringUtil.isWhitespace(tagChars.charAt(i)) && !extractValue) { extractKey = true; } // Equals sign indicated end of key name else if (extractKey && (SYMBOL_EQUALS == tagChars.charAt(i) || StringUtil.isWhitespace(tagChars.charAt(i)))) { extractKey = false; } // Inside key name, extract all chars else if (extractKey) { key.append(tagChars.charAt(i)); } // " Indicates begin or end of value chars else if (SYMBOL_QUOT == tagChars.charAt(i)) { if (extractValue) { attributes.put(key.toString(), value.toString()); // clear key and value buffers key.setLength(0); value.setLength(0); } extractValue = !extractValue; } // Inside value, extract all chars else if (extractValue) { value.append(tagChars.charAt(i)); } } return attributes; } /** * Parses an SGML document available via the input in {@link Reader}. * The specified {@link ContentHandler} is responsible of how to interpret the document * specific details. * * @param in A {@link Reader} that provides the data of the SGML document. * @param handler The {@link ContentHandler} to interpret the document with. * * @throws IOException Thrown if IO errors occurred. * @throws InvalidFormatException Thrown if parameters were invalid. */ public void parse(Reader in, ContentHandler handler) throws IOException { StringBuilder buffer = new StringBuilder(); boolean isInsideTag = false; boolean isStartTag = true; int lastChar = -1; int c; while ((c = in.read()) != -1) { if (SYMBOL_OPEN == c) { if (isInsideTag) { throw new InvalidFormatException("Did not expect < char!"); } if (!buffer.toString().trim().isEmpty()) { handler.characters(buffer.toString().trim()); } buffer.setLength(0); isInsideTag = true; isStartTag = true; } buffer.appendCodePoint(c); if (SYMBOL_SLASH == c && lastChar == SYMBOL_OPEN) { isStartTag = false; } if (SYMBOL_CLOSE == c) { if (!isInsideTag) { throw new InvalidFormatException("Did not expect > char!"); } if (isStartTag) { handler.startElement(extractTagName(buffer), getAttributes(buffer)); } else { handler.endElement(extractTagName(buffer)); } buffer.setLength(0); isInsideTag = false; } lastChar = c; } if (isInsideTag) { throw new InvalidFormatException("Did not find matching > char!"); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/muc/package-info.java0100644 0000000 0000000 00000001617 15217274217 033342 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the {@code MUC} corpus format. */ package opennlp.tools.formats.muc; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_nkjp_NKJ0100644 0000000 0000000 00000000170 15217274217 032436 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPSegmentationDocument.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPSegmentationDoc0100644 0000000 0000000 00000020473 15217274217 034023 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.nkjp; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.LinkedHashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import opennlp.tools.util.Span; import opennlp.tools.util.XmlUtil; public class NKJPSegmentationDocument { private static final String XML_ID = "xml:id"; private static final String SEG = "seg"; private static final String CHOICE = "choice"; private static final String NKJP_PAREN = "nkjp:paren"; private static final String NKJP_REJECTED = "nkjp:rejected"; private static final String NKJP_NPS = "nkjp:nps"; public static class Pointer { final String doc; final String id; final int offset; final int length; final boolean space_after; public Pointer(String doc, String id, int offset, int length, boolean space_after) { this.doc = doc; this.id = id; this.offset = offset; this.length = length; this.space_after = space_after; } public Span toSpan() { return new Span(this.offset, this.offset + this.length); } @Override public String toString() { return doc + "#string-range(" + id + "," + offset + "," + length + ")"; } } public Map> getSegments() { return segments; } Map> segments; NKJPSegmentationDocument() { this.segments = new LinkedHashMap<>(); } NKJPSegmentationDocument(Map> segments) { this(); this.segments = segments; } public static NKJPSegmentationDocument parse(InputStream is) throws IOException { Map> sentences = new LinkedHashMap<>(); try { DocumentBuilder docBuilder = XmlUtil.createDocumentBuilder(); Document doc = docBuilder.parse(is); XPathFactory xPathfactory = XPathFactory.newInstance(); XPath xpath = xPathfactory.newXPath(); final XPathExpression SENT_NODES = xpath.compile("/teiCorpus/TEI/text/body/p/s"); final XPathExpression SEG_NODES = xpath.compile("./seg|./choice"); final XPathExpression SEG_NODES_ONLY = xpath.compile("./seg"); NodeList nl = (NodeList) SENT_NODES.evaluate(doc, XPathConstants.NODESET); for (int i = 0; i < nl.getLength(); i++) { Node sentnode = nl.item(i); String sentid = null; if (sentnode.getAttributes().getNamedItem(XML_ID) != null) { sentid = sentnode.getAttributes().getNamedItem(XML_ID).getTextContent(); } Map segments = new LinkedHashMap<>(); NodeList segnl = (NodeList) SEG_NODES.evaluate(sentnode, XPathConstants.NODESET); for (int j = 0; j < segnl.getLength(); j++) { Node n = segnl.item(j); if (n.getNodeName().equals(SEG)) { String segid = xmlID(n); Pointer pointer = fromSeg(n); segments.put(segid, pointer); } else if (n.getNodeName().equals(CHOICE)) { NodeList choices = n.getChildNodes(); for (int k = 0; k < choices.getLength(); k++) { Node choice = choices.item(k); if (choice.getNodeName().equals(NKJP_PAREN)) { if (!checkRejectedParen(choice)) { NodeList paren_segs = (NodeList) SEG_NODES_ONLY.evaluate(choice, XPathConstants.NODESET); for (int l = 0; l < paren_segs.getLength(); l++) { String segid = xmlID(paren_segs.item(l)); Pointer pointer = fromSeg(paren_segs.item(l)); segments.put(segid, pointer); } } } else if (choice.getNodeName().equals(SEG)) { if (!checkRejected(choice)) { String segid = xmlID(choice); Pointer pointer = fromSeg(choice); segments.put(segid, pointer); } } } } } sentences.put(sentid, segments); } } catch (SAXException | XPathExpressionException | IOException e) { throw new IOException("Failed to parse NKJP document", e); } return new NKJPSegmentationDocument(sentences); } static boolean checkRejected(Node n) { NamedNodeMap attrs = n.getAttributes(); if (attrs == null) { return false; } if (attrs.getNamedItem(NKJP_REJECTED) == null) { return false; } return attrs.getNamedItem(NKJP_REJECTED).getTextContent().equals("true"); } static boolean checkRejectedParen(Node n) { if (n.getChildNodes().getLength() == 0) { return false; } else { for (int i = 0; i < n.getChildNodes().getLength(); i++) { Node m = n.getChildNodes().item(i); if (m.getNodeName().equals(SEG)) { if (!checkRejected(m)) { return false; } } } return true; } } static String xmlID(Node n) throws IOException { NamedNodeMap attr = n.getAttributes(); if (attr == null || attr.getLength() < 1) { throw new IOException("Missing required attributes"); } String id = null; if (attr.getNamedItem(XML_ID) != null) { id = attr.getNamedItem(XML_ID).getTextContent(); } if (id == null) { throw new IOException("Missing xml:id attribute"); } return id; } static Pointer fromSeg(Node n) throws IOException { if (n.getAttributes() == null || n.getAttributes().getLength() < 2) { throw new IOException("Missing required attributes"); } String ptr = null; if (n.getAttributes().getNamedItem("corresp") != null) { ptr = n.getAttributes().getNamedItem("corresp").getTextContent(); } String spacing = ""; if (n.getAttributes().getNamedItem(NKJP_NPS) != null) { spacing = n.getAttributes().getNamedItem(NKJP_NPS).getTextContent(); } if (ptr == null) { throw new IOException("Missing required attribute"); } boolean space_after = (ptr.equals("yes")); if (!ptr.contains("#") || !ptr.contains("(") || ptr.charAt(ptr.length() - 1) != ')') { throw new IOException("String " + ptr + " does not appear to be a valid NKJP corresp attribute"); } int docend = ptr.indexOf('#'); String document = ptr.substring(0, docend); int pointer_start = ptr.indexOf('(') + 1; String[] pieces = ptr.substring(pointer_start, ptr.length() - 1).split(","); if (pieces.length < 3 || pieces.length > 4) { throw new IOException("String " + ptr + " does not appear to be a valid NKJP corresp attribute"); } String docid = pieces[0]; int offset; int length; if (pieces.length == 3) { offset = Integer.parseInt(pieces[1]); length = Integer.parseInt(pieces[2]); } else { int os1 = Integer.parseInt(pieces[1]); int os2 = Integer.parseInt(pieces[2]); offset = (os1 * 1000) + os2; length = Integer.parseInt(pieces[3]); } return new Pointer(document, docid, offset, length, space_after); } static NKJPSegmentationDocument parse(File file) throws IOException { try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { return parse(in); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_nkjp_NKJ0100644 0000000 0000000 00000000170 15217274217 032436 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPSentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPSentenceSampleS0100644 0000000 0000000 00000007056 15217274217 033773 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.nkjp; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; public class NKJPSentenceSampleStream implements ObjectStream { private final NKJPSegmentationDocument segments; private final NKJPTextDocument text; private Iterator>> segmentIt; NKJPSentenceSampleStream(NKJPSegmentationDocument segments, NKJPTextDocument text) { this.segments = segments; this.text = text; reset(); } @Override public SentenceSample read() throws IOException { StringBuilder sentencesString = new StringBuilder(); List sentenceSpans = new LinkedList<>(); Map paragraphs = text.getParagraphs(); while (segmentIt.hasNext()) { Map.Entry> segment = segmentIt.next(); int start = 0; int end = 0; boolean started = false; String lastParagraphId = ""; String currentParagraph = ""; for (String s : segment.getValue().keySet()) { NKJPSegmentationDocument.Pointer currentPointer = segment.getValue().get(s); Span currentSpan = currentPointer.toSpan(); if (!started) { start = currentSpan.getStart(); started = true; lastParagraphId = currentPointer.id; currentParagraph = paragraphs.get(currentPointer.id); } if (!lastParagraphId.equals(currentPointer.id)) { int new_start = sentencesString.length(); sentencesString.append(currentParagraph.substring(start, end)); int new_end = sentencesString.length(); sentenceSpans.add(new Span(new_start, new_end)); sentencesString.append(' '); start = currentSpan.getStart(); end = currentSpan.getEnd(); lastParagraphId = currentPointer.id; currentParagraph = paragraphs.get(currentPointer.id); } else { end = currentSpan.getEnd(); } } int new_start = sentencesString.length(); sentencesString.append(currentParagraph.substring(start, end)); int new_end = sentencesString.length(); sentenceSpans.add(new Span(new_start, new_end)); sentencesString.append(' '); } // end of stream is reached, indicate that with null return value if (sentenceSpans.isEmpty()) { return null; } return new SentenceSample(sentencesString.toString(), sentenceSpans.toArray(new Span[0])); } @Override public void reset() { segmentIt = segments.getSegments().entrySet().iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_nkjp_NKJ0100644 0000000 0000000 00000000177 15217274217 032445 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPSentenceSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPSentenceSampleS0100644 0000000 0000000 00000005142 15217274217 033765 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.nkjp; import java.io.File; import java.io.IOException; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.params.BasicFormatParams; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.sentdetect.SentenceSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see SentenceSample * @see NKJPSentenceSampleStream */ @Internal public class NKJPSentenceSampleStreamFactory extends AbstractSampleStreamFactory { public interface Parameters extends BasicFormatParams { @ArgumentParser.ParameterDescription(valueName = "text", description = "file containing NKJP text") File getTextFile(); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(SentenceSample.class, "nkjp", new NKJPSentenceSampleStreamFactory(NKJPSentenceSampleStreamFactory.Parameters.class)); } protected NKJPSentenceSampleStreamFactory(Class params) { super(params); } @Override public ObjectStream create(String[] args) { Parameters params = validateBasicFormatParameters(args, Parameters.class); CmdLineUtil.checkInputFile("Text", params.getTextFile()); NKJPSegmentationDocument segDoc = null; NKJPTextDocument textDoc = null; try { segDoc = NKJPSegmentationDocument.parse(params.getData()); textDoc = NKJPTextDocument.parse(params.getTextFile()); } catch (IOException ex) { CmdLineUtil.handleCreateObjectStreamError(ex); } return new NKJPSentenceSampleStream(segDoc, textDoc); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_nkjp_NKJ0100644 0000000 0000000 00000000160 15217274217 032435 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPTextDocument.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/NKJPTextDocument.ja0100644 0000000 0000000 00000015565 15217274217 033762 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.nkjp; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import opennlp.tools.util.XmlUtil; /** * The National corpus of Polish (NKJP) format. *

* Information about the format are found on this * web site. *

* A 1-million word corpus can be found on this * * web site. *

* The NKJP schema can be found * here. */ public class NKJPTextDocument { private Map divtypes; private Map>> texts; NKJPTextDocument() { divtypes = new HashMap<>(); texts = new HashMap<>(); } NKJPTextDocument(Map divtypes, Map>> texts) { this(); this.divtypes = divtypes; this.texts = texts; } public static NKJPTextDocument parse(InputStream is) throws IOException { Map divtypes = new HashMap<>(); Map>> texts = new HashMap<>(); try { DocumentBuilder docBuilder = XmlUtil.createDocumentBuilder(); Document doc = docBuilder.parse(is); XPathFactory xPathfactory = XPathFactory.newInstance(); XPath xpath = xPathfactory.newXPath(); final XPathExpression TEXT_NODES_EXAMPLE = xpath.compile("/teiCorpus/TEI/text/group/text"); final XPathExpression TEXT_NODES_SAMPLE = xpath.compile("/teiCorpus/TEI/text"); final XPathExpression DIV_NODES = xpath.compile("./body/div"); final XPathExpression PARA_NODES = xpath.compile("./p|./ab"); doc.getDocumentElement().normalize(); String root = doc.getDocumentElement().getNodeName(); if (!root.equalsIgnoreCase("teiCorpus")) { throw new IOException("Expected root node " + root); } String current_text = ""; NodeList textnl = (NodeList) TEXT_NODES_EXAMPLE.evaluate(doc, XPathConstants.NODESET); if (textnl.getLength() == 0) { textnl = (NodeList) TEXT_NODES_SAMPLE.evaluate(doc, XPathConstants.NODESET); } for (int i = 0; i < textnl.getLength(); i++) { Node textnode = textnl.item(i); current_text = attrib(textnode, "xml:id", true); Map> current_divs = new HashMap<>(); NodeList divnl = (NodeList) DIV_NODES.evaluate(textnode, XPathConstants.NODESET); for (int j = 0; j < divnl.getLength(); j++) { Node divnode = divnl.item(j); String divtype = attrib(divnode, "type", false); String divid = attrib(divnode, "xml:id", true); divtypes.put(divid, divtype); Map current_paras = new HashMap<>(); NodeList paranl = (NodeList) PARA_NODES.evaluate(divnode, XPathConstants.NODESET); for (int k = 0; k < paranl.getLength(); k++) { Node pnode = paranl.item(k); String pid = attrib(pnode, "xml:id", true); if (pnode.getChildNodes().getLength() != 1 && !pnode.getFirstChild().getNodeName().equals("#text")) { throw new IOException("Unexpected content in p element " + pid); } String ptext = pnode.getTextContent(); current_paras.put(pid, ptext); } current_divs.put(divid, current_paras); } texts.put(current_text, current_divs); } } catch (SAXException | XPathExpressionException | IOException e) { throw new IOException("Failed to parse NKJP document", e); } return new NKJPTextDocument(divtypes, texts); } static NKJPTextDocument parse(File file) throws IOException { try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { return parse(in); } } Map getDivtypes() { return Collections.unmodifiableMap(this.divtypes); } Map>> getTexts() { return Collections.unmodifiableMap(this.texts); } /** * Segmentation etc. is done only in relation to the paragraph, * which are unique within a document. This is to simplify * working with the paragraphs within the document * * @return A map of paragraph IDs and their text. */ Map getParagraphs() { Map paragraphs = new HashMap<>(); for (String dockey : texts.keySet()) { for (String divkey : texts.get(dockey).keySet()) { for (String pkey : texts.get(dockey).get(divkey).keySet()) { paragraphs.put(pkey, texts.get(dockey).get(divkey).get(pkey)); } } } return paragraphs; } /** * Helper method to get the value of an attribute. * * @param n The {@link Node} to be processed. * @param attrib The name of the attribute. * @param required Whether the attribute is required or not. * * @return The value of the attribute, or null if not required and not present * @throws IOException Thrown if IO errors occurred. */ private static String attrib(Node n, String attrib, boolean required) throws IOException { if (required && (n.getAttributes() == null || n.getAttributes().getLength() == 0)) { throw new IOException("Missing required attributes in node " + n.getNodeName()); } if (n.getAttributes().getNamedItem(attrib) != null) { return n.getAttributes().getNamedItem(attrib).getTextContent(); } else { if (required) { throw new IOException("Required attribute \"" + attrib + "\" missing in node " + n.getNodeName()); } else { return null; } } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/nkjp/package-info.java0100644 0000000 0000000 00000001644 15217274217 033520 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the National corpus of Polish {@code NKJP} format. */ package opennlp.tools.formats.nkjp; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000171 15217274217 032640 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/DocumentToLineStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/DocumentToLine0100644 0000000 0000000 00000003570 15217274217 034233 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ontonotes; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import opennlp.tools.formats.brat.SegmenterObjectStream; import opennlp.tools.util.ObjectStream; /** * Reads a plain text file and return each line as a {@link String} object. */ public class DocumentToLineStream extends SegmenterObjectStream { /** * Initializes a {@link DocumentToLineStream}. * * @param samples The {@link ObjectStream samples} as input. * Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public DocumentToLineStream(ObjectStream samples) { super(samples); } @Override protected List read(String sample) throws IOException { List lines = Arrays.asList(sample.split("\n")); // documents must be empty line terminated if (!lines.get(lines.size() - 1).trim().isEmpty()) { lines = new ArrayList<>(lines); lines.add(""); } return lines; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000176 15217274217 032645 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesFormatParameters.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesForma0100644 0000000 0000000 00000002040 15217274217 034246 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ontonotes; import opennlp.tools.cmdline.ArgumentParser.ParameterDescription; public interface OntoNotesFormatParameters { @ParameterDescription(valueName = "OntoNotes 4.0 corpus directory") String getOntoNotesDir(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000176 15217274217 032645 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesNameSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesNameS0100644 0000000 0000000 00000013406 15217274217 034215 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ontonotes; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import opennlp.tools.namefind.NameSample; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; import opennlp.tools.util.StringUtil; /** * Name Sample Stream parser for the OntoNotes 4.0 named entity files. */ public class OntoNotesNameSampleStream extends FilterObjectStream { private static final String TAG_DOC_OPEN = " tokenConversionMap; private final List nameSamples = new LinkedList<>(); /** * Initializes a {@link OntoNotesNameSampleStream}. * * @param samples The {@link ObjectStream samples} as input. * Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public OntoNotesNameSampleStream(ObjectStream samples) { super(samples); Map tokenConversionMap = new HashMap<>(); tokenConversionMap.put("-LRB-", "("); tokenConversionMap.put("-RRB-", ")"); tokenConversionMap.put("-LSB-", "["); tokenConversionMap.put("-RSB-", "]"); tokenConversionMap.put("-LCB-", "{"); tokenConversionMap.put("-RCB-", "}"); tokenConversionMap.put("-AMP-", "&"); this.tokenConversionMap = Collections.unmodifiableMap(tokenConversionMap); } private String convertToken(String token) { StringBuilder convertedToken = new StringBuilder(token); int startTagEndIndex = convertedToken.indexOf(SYMBOL_CLOSE); if (token.contains("=\"") && startTagEndIndex != -1) { convertedToken.delete(0, startTagEndIndex + 1); } int endTagBeginIndex = convertedToken.indexOf(SYMBOL_OPEN); int endTagEndIndex = convertedToken.indexOf(SYMBOL_CLOSE); if (endTagBeginIndex != -1 && endTagEndIndex != -1) { convertedToken.delete(endTagBeginIndex, endTagEndIndex + 1); } String cleanedToken = convertedToken.toString(); if (tokenConversionMap.get(cleanedToken) != null) { cleanedToken = tokenConversionMap.get(cleanedToken); } return cleanedToken; } @Override public NameSample read() throws IOException { if (nameSamples.isEmpty()) { String doc = samples.read(); if (doc != null) { boolean clearAdaptiveData = true; String line; try (BufferedReader docIn = new BufferedReader(new StringReader(doc))) { while ((line = docIn.readLine()) != null) { if (line.startsWith(TAG_DOC_OPEN)) { continue; } if (line.equals(TAG_DOC_CLOSE)) { break; } String[] tokens = WhitespaceTokenizer.INSTANCE.tokenize(line); List entities = new LinkedList<>(); List cleanedTokens = new ArrayList<>(tokens.length); int tokenIndex = 0; int entityBeginIndex = -1; String entityType = null; boolean insideStartEnmaxTag = false; for (String token : tokens) { // Split here, next part of tag is in new token if (token.startsWith(TAG_ENAMEX_OPEN)) { insideStartEnmaxTag = true; continue; } if (insideStartEnmaxTag) { String typeBegin = TYPE; if (token.startsWith(typeBegin)) { int typeEnd = token.indexOf("\"", typeBegin.length()); entityType = StringUtil.toLowerCase(token.substring(typeBegin.length(), typeEnd)); } if (token.contains(SYMBOL_CLOSE)) { entityBeginIndex = tokenIndex; insideStartEnmaxTag = false; } else { continue; } } if (token.endsWith(TAG_ENAMEX_CLOSE)) { entities.add(new Span(entityBeginIndex, tokenIndex + 1, entityType)); entityBeginIndex = -1; } cleanedTokens.add(convertToken(token)); tokenIndex++; } nameSamples.add(new NameSample(cleanedTokens.toArray(new String[0]), entities.toArray(new Span[0]), clearAdaptiveData)); clearAdaptiveData = false; } } } } if (!nameSamples.isEmpty()) { return nameSamples.remove(0); } else { return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000205 15217274217 032636 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesNameSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesNameS0100644 0000000 0000000 00000005316 15217274217 034216 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ontonotes; import java.io.File; import java.nio.charset.StandardCharsets; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.formats.DirectorySampleStream; import opennlp.tools.formats.convert.FileToStringSampleStream; import opennlp.tools.namefind.NameSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see OntoNotesNameSampleStream */ @Internal public class OntoNotesNameSampleStreamFactory extends AbstractSampleStreamFactory { public static void registerFactory() { StreamFactoryRegistry.registerFactory(NameSample.class, "ontonotes", new OntoNotesNameSampleStreamFactory()); } public OntoNotesNameSampleStreamFactory() { super(OntoNotesFormatParameters.class); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } OntoNotesFormatParameters params = ArgumentParser.parse(args, OntoNotesFormatParameters.class); final File ontoDir = new File(params.getOntoNotesDir()); if (!ontoDir.isDirectory() || !ontoDir.exists()) { throw new TerminateToolException(-1, "The specified OntoNotes directory is not valid!"); } ObjectStream documentStream = new DirectorySampleStream(new File( params.getOntoNotesDir()), file -> { if (file.isFile()) { return file.getName().endsWith(".name"); } return file.isDirectory(); }, true); return new OntoNotesNameSampleStream( new FileToStringSampleStream(documentStream, StandardCharsets.UTF_8)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000204 15217274217 032635 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesPOSSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesPOSSa0100644 0000000 0000000 00000004113 15217274217 034132 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ontonotes; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.formats.convert.ParseToPOSSampleStream; import opennlp.tools.parser.Parse; import opennlp.tools.postag.POSSample; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see ParseToPOSSampleStream */ @Internal public class OntoNotesPOSSampleStreamFactory extends AbstractSampleStreamFactory { private final OntoNotesParseSampleStreamFactory parseSampleStreamFactory = new OntoNotesParseSampleStreamFactory(); protected OntoNotesPOSSampleStreamFactory() { super(OntoNotesFormatParameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(POSSample.class, "ontonotes", new OntoNotesPOSSampleStreamFactory()); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } ObjectStream parseSampleStream = parseSampleStreamFactory.create(args); return new ParseToPOSSampleStream(parseSampleStream); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000177 15217274217 032646 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesParseSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesParse0100644 0000000 0000000 00000003735 15217274217 034270 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ontonotes; import java.io.IOException; import opennlp.tools.parser.Parse; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; // Should be possible with this one, to train the parser and pos tagger! public class OntoNotesParseSampleStream extends FilterObjectStream { /** * Initializes a {@link OntoNotesParseSampleStream}. * * @param samples The {@link ObjectStream samples} as input. * Must not be {@code null}. * * @throws IllegalArgumentException Thrown if parameters are invalid. */ public OntoNotesParseSampleStream(ObjectStream samples) { super(samples); } @Override public Parse read() throws IOException { StringBuilder parseString = new StringBuilder(); while (true) { String parse = samples.read(); if (parse != null) { parse = parse.trim(); } if (parse == null || parse.isEmpty()) { if (!parseString.isEmpty()) { return Parse.parseParse(parseString.toString()); } else { return null; } } parseString.append(parse).append(" "); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000206 15217274217 032637 xustar000000000 0000000 134 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesParseSampleStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/OntoNotesParse0100644 0000000 0000000 00000005701 15217274217 034263 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.formats.ontonotes; import java.io.File; import java.nio.charset.StandardCharsets; import opennlp.tools.cmdline.ArgumentParser; import opennlp.tools.cmdline.StreamFactoryRegistry; import opennlp.tools.cmdline.TerminateToolException; import opennlp.tools.commons.Internal; import opennlp.tools.formats.AbstractSampleStreamFactory; import opennlp.tools.formats.DirectorySampleStream; import opennlp.tools.formats.convert.FileToStringSampleStream; import opennlp.tools.parser.Parse; import opennlp.tools.util.ObjectStream; /** * Note: Do not use this class, internal use only! * * @see OntoNotesParseSampleStream */ @Internal public class OntoNotesParseSampleStreamFactory extends AbstractSampleStreamFactory { protected OntoNotesParseSampleStreamFactory() { super(OntoNotesFormatParameters.class); } public static void registerFactory() { StreamFactoryRegistry.registerFactory(Parse.class, "ontonotes", new OntoNotesParseSampleStreamFactory()); } @Override public ObjectStream create(String[] args) { if (args == null) { throw new IllegalArgumentException("Passed args must not be null!"); } OntoNotesFormatParameters params = ArgumentParser.parse(args, OntoNotesFormatParameters.class); final File ontoDir = new File(params.getOntoNotesDir()); if (!ontoDir.isDirectory() || !ontoDir.exists()) { throw new TerminateToolException(-1, "The specified OntoNotes directory is not valid!"); } ObjectStream documentStream = new DirectorySampleStream(new File( params.getOntoNotesDir()), file -> { if (file.isFile()) { return file.getName().endsWith(".parse"); } return file.isDirectory(); }, true); // We need file to line here ... and that is probably best doen with the plain text stream // lets copy it over here, refactor it, and then at some point we replace the current version // with the refactored version return new OntoNotesParseSampleStream(new DocumentToLineStream( new FileToStringSampleStream(documentStream, StandardCharsets.UTF_8))); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_formats_ontonote0100644 0000000 0000000 00000000161 15217274217 032637 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/ontonotes/package-info.j0100644 0000000 0000000 00000001620 15217274217 034110 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to the OntoNotes 4.0 format. */ package opennlp.tools.formats.ontonotes; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/formats/package-info.java0100644 0000000 0000000 00000001632 15217274217 032553 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Experimental package related to converting various corpora to OpenNLP Format. */ package opennlp.tools.formats; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Defau0100644 0000000 0000000 00000000205 15217274217 032454 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/DefaultLanguageDetectorContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/DefaultLanguageDetect0100644 0000000 0000000 00000005220 15217274217 034124 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.Serial; import java.util.ArrayList; import java.util.Collection; import opennlp.tools.ngram.NGramCharModel; import opennlp.tools.util.normalizer.AggregateCharSequenceNormalizer; import opennlp.tools.util.normalizer.CharSequenceNormalizer; /** * A context generator for {@link LanguageDetectorContextGenerator language detector}. */ public class DefaultLanguageDetectorContextGenerator implements LanguageDetectorContextGenerator { @Serial private static final long serialVersionUID = 8891936509865460799L; protected final int minLength; protected final int maxLength; protected final CharSequenceNormalizer normalizer; /** * Creates a customizable {@link DefaultLanguageDetectorContextGenerator} that computes ngrams from text. * * @param minLength The min number of ngrams characters. Must be greater than {@code 0}. * @param maxLength The max number of ngrams characters. Must be greater than {@code 0} * and must be greater than {@code minLength}. * @param normalizers Zero or more normalizers to be applied in to the text before extracting ngrams. */ public DefaultLanguageDetectorContextGenerator(int minLength, int maxLength, CharSequenceNormalizer... normalizers) { this.minLength = minLength; this.maxLength = maxLength; this.normalizer = new AggregateCharSequenceNormalizer(normalizers); } @Override @SuppressWarnings("unchecked") public T[] getContext(CharSequence document) { Collection context = new ArrayList<>(); NGramCharModel model = new NGramCharModel(); model.add(normalizer.normalize(document), minLength, maxLength); for (CharSequence token : model) { context.add(token); } return (T[]) context.toArray(new CharSequence[0]); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/Language.java0100644 0000000 0000000 00000004035 15217274217 032411 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.Serializable; import java.util.Objects; /** * Class for holding the document language and its confidence */ public class Language implements Serializable { private static final long serialVersionUID = -2692630786925291644L; private final String lang; private final double confidence; /** * @param lang The language identifier. */ public Language(String lang) { this(lang, 0); } /** * @param lang The language identifier. * @param confidence The confidence computed during language detection. */ public Language(String lang, double confidence) { Objects.requireNonNull(lang, "lang must not be null"); this.lang = lang; this.confidence = confidence; } public String getLang() { return lang; } public double getConfidence() { return confidence; } @Override public String toString() { return getLang() + " (" + this.confidence + ")"; } @Override public int hashCode() { return Objects.hash(getLang(), getConfidence()); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof Language a) { return getLang().equals(a.getLang()); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000156 15217274217 032503 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetector.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetector.java0100644 0000000 0000000 00000003246 15217274217 034106 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; /** * The interface for {@link LanguageDetector} which predicts the {@link Language} for a context. */ public interface LanguageDetector { /** * Predicts the {@link Language languages} for the full {@code content} length. * * @param content The textual content to detect potential {@link Language languages} from. * @return the predicted languages */ Language[] predictLanguages(CharSequence content); /** * Predicts the {@link Language} for the full {@code content} length. * * @param content The textual content to detect potential {@link Language languages} from. * @return the language with the highest confidence */ Language predictLanguage(CharSequence content); /** * @return Retrieves an array of language (codes) that are supported by a {@link LanguageDetector}. */ String[] getSupportedLanguages(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000164 15217274217 032502 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorConfig.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorConfi0100644 0000000 0000000 00000006535 15217274217 034151 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; public class LanguageDetectorConfig { public static final int DEFAULT_MAX_LENGTH = 10000; public static final int DEFAULT_CHUNK_SIZE = 200; public static final int DEFAULT_MIN_CONSEC_IMPROVEMENTS = 2; public static final double DEFAULT_MIN_DIFF = 0.20; public static final LanguageDetectorConfig DEFAULT_LANGUAGE_DETECTOR_CONFIG = new ImmutableLanguageDetectorConfig(); private int maxLength = DEFAULT_MAX_LENGTH; private int chunkSize = DEFAULT_CHUNK_SIZE; private int minConsecImprovements = DEFAULT_MIN_CONSEC_IMPROVEMENTS; private double minDiff = DEFAULT_MIN_DIFF; /** * @return The maximum length in codepoints of text to process. */ public int getMaxLength() { return maxLength; } public void setMaxLength(int maxLength) { this.maxLength = maxLength; } /** * After processing a chunk of this size, the probing * detection will compute probabilities and determine * if there is enough confidence to stop. * * @return The size in codepoints of chunk to process at each step for * the probing detection. */ public int getChunkSize() { return chunkSize; } public void setChunkSize(int chunkSize) { this.chunkSize = chunkSize; } /** * If this value equals {@code 0}, probing detection will * rely solely on {@link #getMinDiff()} * * @return The minimum number of consecutive increased probabilities * for the top language required in probing detection * to stop early. */ public int getMinConsecImprovements() { return minConsecImprovements; } public void setMinConsecImprovements(int minConsecImprovements) { this.minConsecImprovements = minConsecImprovements; } /** * If this value equals {@code 0}, probing detection will * rely solely on {@link #getMinConsecImprovements()} * * @return The minimum difference in confidence between the top predicted * language and the next most likely language. */ public double getMinDiff() { return minDiff; } public void setMinDiff(double minDiff) { this.minDiff = minDiff; } private static class ImmutableLanguageDetectorConfig extends LanguageDetectorConfig { @Override public void setMaxLength(int maxLength) { //no-op } @Override public void setChunkSize(int chunkSize) { //no-op } @Override public void setMinConsecImprovements(int minConsecImprovements) { //no-op } @Override public void setMinDiff(double minDiff) { //no-op } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000176 15217274217 032505 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorConte0100644 0000000 0000000 00000002446 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.Serializable; /** * A context generator interface for {@link LanguageDetector}. */ public interface LanguageDetectorContextGenerator extends Serializable { /** * Retrieves the contexts for a {@code document} using character ngrams. * * @param document The textual input used to extract context from. * * @return An array of contexts on which a model basis its decisions. */ T[] getContext(CharSequence document); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000174 15217274217 032503 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorCross0100644 0000000 0000000 00000006777 15217274217 034214 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.IOException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.Mean; /** * Cross validator for {@link LanguageDetector}. */ public class LanguageDetectorCrossValidator { private final TrainingParameters params; private final Mean documentAccuracy = new Mean(); private final LanguageDetectorEvaluationMonitor[] listeners; private final LanguageDetectorFactory factory; /** * Initializes a {@link LanguageDetectorCrossValidator} with the * given {@link TrainingParameters parameters}. * * @param mlParams The {@link TrainingParameters} for the context of cross validation. * @param factory The {@link LanguageDetectorFactory} for creating related objects. * @param listeners the {@link LanguageDetectorEvaluationMonitor evaluation listeners}. */ public LanguageDetectorCrossValidator(TrainingParameters mlParams, LanguageDetectorFactory factory, LanguageDetectorEvaluationMonitor ... listeners) { this.params = mlParams; this.listeners = listeners; this.factory = factory; } /** * Starts the evaluation. * * @param samples The {@link ObjectStream} of {@link LanguageSample samples} to train and test with. * @param nFolds Number of folds. It must be greater than zero. * * @throws IOException Thrown if IO errors occurred. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>(samples, nFolds); while (partitioner.hasNext()) { CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner.next(); LanguageDetectorModel model = LanguageDetectorME.train( trainingSampleStream, params, factory); LanguageDetectorEvaluator evaluator = new LanguageDetectorEvaluator( new LanguageDetectorME(model), listeners); evaluator.evaluate(trainingSampleStream.getTestSampleStream()); documentAccuracy.add(evaluator.getAccuracy(), evaluator.getDocumentCount()); } } /** * @return Retrieves the word accuracy for all iterations. */ public double getDocumentAccuracy() { return documentAccuracy.mean(); } /** * @return Retrieves the number of words which where validated over all iterations. * The result is the amount of folds multiplied by the total number of words. */ public long getDocumentCount() { return documentAccuracy.count(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000177 15217274217 032506 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorEvalu0100644 0000000 0000000 00000002064 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link LanguageDetector language detectors}. */ public interface LanguageDetectorEvaluationMonitor extends EvaluationMonitor { } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000167 15217274217 032505 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorEvaluator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorEvalu0100644 0000000 0000000 00000006033 15217274217 034160 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import opennlp.tools.doccat.DocumentCategorizer; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.Mean; /** * The {@link LanguageDetectorEvaluator} measures the performance of * the given {@link LanguageDetector} with the provided reference * {@link LanguageSample}s. * * @see LanguageDetector * @see LanguageSample */ public class LanguageDetectorEvaluator extends Evaluator { private final LanguageDetector languageDetector; private final Mean accuracy = new Mean(); /** * Initializes an instance to evaluate a {@link LanguageDetector}. * * @param langDetect the {@link LanguageDetector} to evaluate. * @param listeners the {@link LanguageDetectorEvaluationMonitor evaluation listeners}. */ public LanguageDetectorEvaluator(LanguageDetector langDetect, LanguageDetectorEvaluationMonitor ... listeners) { super(listeners); this.languageDetector = langDetect; } /** * Evaluates the given reference {@link LanguageSample} object. * This is achieved by categorizing the document of the provided * {@link LanguageSample}. The detected language is then used * to calculate and update the score. * * @param sample the reference {@link LanguageSample}. * @return The processed {@link LanguageSample}. */ public LanguageSample processSample(LanguageSample sample) { CharSequence document = sample.context(); Language predicted = languageDetector.predictLanguage(document); if (sample.language().getLang().equals(predicted.getLang())) { accuracy.add(1); } else { accuracy.add(0); } return new LanguageSample(predicted, sample.context()); } /** * @return Retrieves the accuracy of provided {@link DocumentCategorizer}. * Here: {@code accuracy = correctly categorized documents / total documents}. */ public double getAccuracy() { return accuracy.mean(); } public long getDocumentCount() { return accuracy.count(); } /** * Represents this object as human-readable {@link String}. */ @Override public String toString() { return "Accuracy: " + accuracy.mean() + "\n" + "Number of documents: " + accuracy.count(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000171 15217274217 032500 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorEvent0100644 0000000 0000000 00000004322 15217274217 034164 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.util.Iterator; import opennlp.tools.ml.model.Event; import opennlp.tools.util.AbstractEventStream; import opennlp.tools.util.ObjectStream; /** * Iterator-like class for modeling an event stream of {@link LanguageSample samples}. */ public class LanguageDetectorEventStream extends AbstractEventStream { private final LanguageDetectorContextGenerator mContextGenerator; /** * Initializes an instance via samples and feature generators. * * @param data An {@link ObjectStream} of {@link LanguageSample samples} as input data. * @param cg A {@link LanguageDetectorContextGenerator} used for the event stream {@code data}. */ public LanguageDetectorEventStream(ObjectStream data, LanguageDetectorContextGenerator cg) { super(data); mContextGenerator = cg; } @Override protected Iterator createEvents(final LanguageSample sample) { return new Iterator<>() { private boolean isVirgin = true; @Override public boolean hasNext() { return isVirgin; } @Override public Event next() { isVirgin = false; return new Event(sample.language().getLang(), mContextGenerator.getContext(sample.context().toString())); } public void remove() { throw new UnsupportedOperationException(); } }; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000165 15217274217 032503 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorFacto0100644 0000000 0000000 00000007514 15217274217 034145 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.normalizer.EmojiCharSequenceNormalizer; import opennlp.tools.util.normalizer.NumberCharSequenceNormalizer; import opennlp.tools.util.normalizer.ShrinkCharSequenceNormalizer; import opennlp.tools.util.normalizer.TwitterCharSequenceNormalizer; import opennlp.tools.util.normalizer.UrlCharSequenceNormalizer; /** * Default factory used by {@link LanguageDetector}. *

* Extend this class to change the Language Detector behaviour, * such as the {@link LanguageDetectorContextGenerator}. * The default {@link DefaultLanguageDetectorContextGenerator} will use char n-grams of * size 1 to 3 and the following normalizers: *

    *
  • {@link EmojiCharSequenceNormalizer} *
  • {@link UrlCharSequenceNormalizer} *
  • {@link TwitterCharSequenceNormalizer} *
  • {@link NumberCharSequenceNormalizer} *
  • {@link ShrinkCharSequenceNormalizer} *
*/ public class LanguageDetectorFactory extends BaseToolFactory { /** * @return Retrieves a {@link LanguageDetectorContextGenerator}. */ public LanguageDetectorContextGenerator getContextGenerator() { return new DefaultLanguageDetectorContextGenerator(1, 3, EmojiCharSequenceNormalizer.getInstance(), UrlCharSequenceNormalizer.getInstance(), TwitterCharSequenceNormalizer.getInstance(), NumberCharSequenceNormalizer.getInstance(), ShrinkCharSequenceNormalizer.getInstance()); } /** * Instantiates a {@link LanguageDetectorFactory} via a given {@code subclassName}. * * @param subclassName The class name used for instantiation. If {@code null}, an * instance of {@link LanguageDetectorFactory} will be returned * per default. Otherwise, the {@link ExtensionLoader} mechanism * is applied to load the requested {@code subclassName}. * * @return A valid {@link LanguageDetectorFactory} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the factory associated with {@code subclassName}. */ public static LanguageDetectorFactory create(String subclassName) throws InvalidFormatException { if (subclassName == null) { // will create the default factory return new LanguageDetectorFactory(); } try { LanguageDetectorFactory theFactory = ExtensionLoader.instantiateExtension( LanguageDetectorFactory.class, subclassName); theFactory.init(); return theFactory; } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } } public void init() { // nothing to do } @Override public void validateArtifactMap() throws InvalidFormatException { // nothing to validate } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000160 15217274217 032476 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorME.ja0100644 0000000 0000000 00000025432 15217274217 034002 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import opennlp.tools.ml.AbstractEventTrainer; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.MutableInt; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; /** * Implements a learnable {@link LanguageDetector}. * *

* This will process the entire string when called with * {@link #predictLanguage(CharSequence)} or * {@link #predictLanguages(CharSequence)}. *

*

* If you want this to stop early, use {@link #probingPredictLanguages(CharSequence)} * or {@link #probingPredictLanguages(CharSequence, LanguageDetectorConfig)}. * When run in probing mode, this starts at the beginning of the char sequence * and runs language detection on chunks of text. If the end of the * string is reached or there are {@link LanguageDetectorConfig#getMinConsecImprovements()} * consecutive predictions for the best language and the confidence * increases over those last predictions and if the difference * in confidence between the highest confidence language * and the second highest confidence language is greater than * {@link LanguageDetectorConfig#getMinDiff()}, the language detector will * stop and report the results. *

*

* The authors wish to thank Ken Krugler and * Yalder} * for the inspiration for many of the design components of this detector. * */ public class LanguageDetectorME implements LanguageDetector { protected final LanguageDetectorModel model; private final LanguageDetectorContextGenerator mContextGenerator; /** * Initializes an instance with a specific {@link LanguageDetectorModel}. * Default feature generation is used. * * @param model the {@link LanguageDetectorModel} to be used. */ public LanguageDetectorME(LanguageDetectorModel model) { this.model = model; this.mContextGenerator = model.getFactory().getContextGenerator(); } @Override public Language[] predictLanguages(CharSequence content) { return predict(arrayToCounts(mContextGenerator.getContext(content))); } @Override public Language predictLanguage(CharSequence content) { return predictLanguages(content)[0]; } @Override public String[] getSupportedLanguages() { int numberLanguages = model.getMaxentModel().getNumOutcomes(); String[] languages = new String[numberLanguages]; for (int i = 0; i < numberLanguages; i++) { languages[i] = model.getMaxentModel().getOutcome(i); } return languages; } /** * This will stop processing early if the stopping criteria * specified in {@link LanguageDetectorConfig#DEFAULT_LANGUAGE_DETECTOR_CONFIG} * are met. * * @param content content to be processed * @return A computed {@link ProbingLanguageDetectionResult}. */ public ProbingLanguageDetectionResult probingPredictLanguages(CharSequence content) { return probingPredictLanguages(content, LanguageDetectorConfig.DEFAULT_LANGUAGE_DETECTOR_CONFIG); } /** * This will stop processing early if the stopping criteria * specified in {@link LanguageDetectorConfig#DEFAULT_LANGUAGE_DETECTOR_CONFIG} * are met. * * @param content The textual content to process. * @param config The {@link LanguageDetectorConfig} to customize detection. * * @return A computed {@link ProbingLanguageDetectionResult}. */ public ProbingLanguageDetectionResult probingPredictLanguages(CharSequence content, LanguageDetectorConfig config) { //list of the languages that received the highest //confidence over the last n chunk detections List predictions = new LinkedList<>(); int start = 0;//where to start the next chunk in codepoints Language[] currPredictions = null; //cache ngram counts across chunks Map ngramCounts = new HashMap<>(); while (true) { int actualChunkSize = (start + config.getChunkSize() > config.getMaxLength()) ? config.getMaxLength() - start : config.getChunkSize(); StringCPLengthPair chunk = chunk(content, start, actualChunkSize); if (chunk.length() == 0) { if (currPredictions == null) { return new ProbingLanguageDetectionResult(predict(ngramCounts), start); } else { return new ProbingLanguageDetectionResult(currPredictions, start); } } start += chunk.length(); updateCounts(mContextGenerator.getContext(chunk.s), ngramCounts); currPredictions = predict(ngramCounts); if (seenEnough(predictions, currPredictions, ngramCounts, config)) { return new ProbingLanguageDetectionResult(currPredictions, start); } } } private void updateCounts(CharSequence[] context, Map ngrams) { for (CharSequence ngram : context) { MutableInt i = ngrams.get(ngram); if (i == null) { i = new MutableInt(1); ngrams.put(ngram, i); } else { i.increment(); } } } private Map arrayToCounts(CharSequence[] context) { Map ngrams = new HashMap<>(); updateCounts(context, ngrams); return ngrams; } private Language[] predict(Map ngramCounts) { String[] allGrams = new String[ngramCounts.size()]; float[] counts = new float[ngramCounts.size()]; int i = 0; for (Map.Entry e : ngramCounts.entrySet()) { allGrams[i] = e.getKey().toString(); // TODO -- once OPENNLP-1261 is fixed, // change this to e.getValue().getValue(). counts[i] = 1; i++; } double[] eval = model.getMaxentModel().eval(allGrams, counts); Language[] arr = new Language[eval.length]; for (int j = 0; j < eval.length; j++) { arr[j] = new Language(model.getMaxentModel().getOutcome(j), eval[j]); } Arrays.sort(arr, (o1, o2) -> Double.compare(o2.getConfidence(), o1.getConfidence())); return arr; } /** * Overriding this for different behavior to determine if there is enough * confidence in the predictions to stop. * * @param predictionsQueue queue of earlier predictions * @param newPredictions most recent predictions * @param ngramCounts -- not currently used, but might be useful * @return {@code true} if enough text has been processed to make a determination, * else {@code false}. */ boolean seenEnough(List predictionsQueue, Language[] newPredictions, Map ngramCounts, LanguageDetectorConfig config) { if (predictionsQueue.size() < config.getMinConsecImprovements()) { predictionsQueue.add(newPredictions); return false; } else if (predictionsQueue.size() > config.getMinConsecImprovements() && predictionsQueue.size() > 0) { predictionsQueue.remove(0); } predictionsQueue.add(newPredictions); if (config.getMinDiff() > 0.0 && newPredictions[0].getConfidence() - newPredictions[1].getConfidence() < config.getMinDiff()) { return false; } String lastLang = null; double lastConf = -1.0; //iterate through the last predictions //and check that the lang with the highest confidence //hasn't changed, and that the confidence in it //hasn't decreased for (Language[] predictions : predictionsQueue) { if (lastLang == null) { lastLang = predictions[0].getLang(); lastConf = predictions[0].getConfidence(); continue; } else { if (!lastLang.equals(predictions[0].getLang())) { return false; } if (lastConf > predictions[0].getConfidence()) { return false; } } lastLang = predictions[0].getLang(); lastConf = predictions[0].getConfidence(); } return true; } private StringCPLengthPair chunk(CharSequence content, int start, int chunkSize) { if (start == 0 && chunkSize > content.length()) { String s = content.toString(); int codePointLength = s.codePointCount(0, s.length()); return new StringCPLengthPair(s, codePointLength); } int[] codepoints = content.codePoints().skip(start).limit(chunkSize).toArray(); return new StringCPLengthPair( new String(codepoints, 0, codepoints.length), codepoints.length); } /** * Starts a training of a {@link LanguageDetectorModel} with the given parameters. * * @param samples The {@link ObjectStream} of {@link LanguageSample} used as input for training. * @param mlParams The {@link TrainingParameters} for the context of the training. * @param factory The {@link LanguageDetectorFactory} for creating related objects defined * via {@code mlParams}. * * @return A valid, trained {@link LanguageDetectorModel} instance. * @throws IOException Thrown if IO errors occurred. */ public static LanguageDetectorModel train(ObjectStream samples, TrainingParameters mlParams, LanguageDetectorFactory factory) throws IOException { Map manifestInfoEntries = new HashMap<>(); mlParams.putIfAbsent(AbstractEventTrainer.DATA_INDEXER_PARAM, AbstractEventTrainer.DATA_INDEXER_ONE_PASS_VALUE); EventTrainer trainer = TrainerFactory.getEventTrainer(mlParams, manifestInfoEntries); MaxentModel model = trainer.train( new LanguageDetectorEventStream(samples, factory.getContextGenerator())); return new LanguageDetectorModel(model, manifestInfoEntries, factory); } private record StringCPLengthPair(String s, int length) { String getString() { return s; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000163 15217274217 032501 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorModel0100644 0000000 0000000 00000010102 15217274217 034134 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Serial; import java.net.URL; import java.util.Map; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.BaseModel; /** * The {@link LanguageDetectorModel} is the model used by a learnable {@link LanguageDetector}. * * @see LanguageDetectorME */ public class LanguageDetectorModel extends BaseModel { @Serial private static final long serialVersionUID = -8894047401677394181L; private static final String COMPONENT_NAME = "LanguageDetectorME"; private static final String LANGDETECT_MODEL_ENTRY_NAME = "langdetect.model"; /** * Initializes a {@link LanguageDetectorModel} instance via given parameters. * * @param langdetectModel A valid {@link MaxentModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link LanguageDetectorFactory} for creating related objects. */ public LanguageDetectorModel(MaxentModel langdetectModel, Map manifestInfoEntries, LanguageDetectorFactory factory) { super(COMPONENT_NAME, "und", manifestInfoEntries, factory); artifactMap.put(LANGDETECT_MODEL_ENTRY_NAME, langdetectModel); checkArtifactMap(); } /** * Initializes a {@link LanguageDetectorModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public LanguageDetectorModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link LanguageDetectorModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public LanguageDetectorModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link LanguageDetectorModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public LanguageDetectorModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(LANGDETECT_MODEL_ENTRY_NAME) instanceof AbstractModel)) { throw new InvalidFormatException("Language detector model is incomplete!"); } } /** * @return Retrieves the active {@link LanguageDetectorFactory}. */ public LanguageDetectorFactory getFactory() { return (LanguageDetectorFactory) this.toolFactory; } @Override protected Class getDefaultFactory() { return LanguageDetectorFactory.class; } /** * @return Retrieves a {@link MaxentModel}. */ public MaxentModel getMaxentModel() { return (MaxentModel) artifactMap.get(LANGDETECT_MODEL_ENTRY_NAME); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Langu0100644 0000000 0000000 00000000172 15217274217 032501 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageDetectorSampl0100644 0000000 0000000 00000004113 15217274217 034155 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.IOException; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * This class reads in string encoded {@link ObjectStream training samples}, parses them * and outputs {@link LanguageSample} objects. *

* Format:
* Each line contains one sample document.
* The language is the first string in the line followed by a tab and the document content.
* Sample line: category-string tab-char document line-break-char(s)
*/ public class LanguageDetectorSampleStream extends FilterObjectStream { /** * Initializes a {@link LanguageDetectorSampleStream instance}. * * @param samples A plain text {@link ObjectStream line stream}. */ public LanguageDetectorSampleStream(ObjectStream samples) { super(samples); } @Override public LanguageSample read() throws IOException { String sampleString; while ((sampleString = samples.read()) != null) { int tabIndex = sampleString.indexOf("\t"); if (tabIndex > 0) { String lang = sampleString.substring(0, tabIndex); String context = sampleString.substring(tabIndex + 1); return new LanguageSample(new Language(lang), context); } } return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/LanguageSample.java0100644 0000000 0000000 00000002722 15217274217 033554 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import java.io.Serial; import java.io.Serializable; import java.util.Objects; /** * Holds a classified document and its {@link Language}. */ public record LanguageSample(Language language, CharSequence context) implements Serializable { @Serial private static final long serialVersionUID = -4791295976215940258L; public LanguageSample(Language language, CharSequence context) { this.language = Objects.requireNonNull(language, "language must not be null"); this.context = Objects.requireNonNull(context, "context must not be null"); } @Override public String toString() { return language.getLang() + '\t' + context; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Probi0100644 0000000 0000000 00000000174 15217274217 032510 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/ProbingLanguageDetectionResult.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/ProbingLanguageDetect0100644 0000000 0000000 00000002137 15217274217 034144 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; /** * A data container encapsulating language detection results. * * @param languages The {@link Language languages} detected. * @param length The length in codepoints of text processed. */ public record ProbingLanguageDetectionResult(Language[] languages, int length) { } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_langdetect_Threa0100644 0000000 0000000 00000000172 15217274217 032476 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/ThreadSafeLanguageDetectorME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/ThreadSafeLanguageDet0100644 0000000 0000000 00000005255 15217274217 034062 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.langdetect; import opennlp.tools.commons.ThreadSafe; /** * A thread-safe version of the {@link LanguageDetectorME}. Using it is completely transparent. * You can use it in a single-threaded context as well, it only incurs a minimal overhead. *

* Note:
* This implementation uses a {@link ThreadLocal}. Although the implementation is * lightweight because the model is not duplicated, if you have many long-running threads, * you may run into memory problems. *

* Be careful when using this in a Jakarta EE application, for example. *

* The user is responsible for clearing the {@link ThreadLocal} * via calling {@link #close()}. * * @see LanguageDetector * @see LanguageDetectorME */ @ThreadSafe public class ThreadSafeLanguageDetectorME implements LanguageDetector, AutoCloseable { private final LanguageDetectorModel model; private final ThreadLocal threadLocal = new ThreadLocal<>(); /** * Initializes a {@link ThreadSafeLanguageDetectorME} with the specified {@code model}. * * @param model A valid {@link LanguageDetectorModel}. */ public ThreadSafeLanguageDetectorME(LanguageDetectorModel model) { super(); this.model = model; } private LanguageDetectorME getLanguageDetector() { LanguageDetectorME ld = threadLocal.get(); if (ld == null) { ld = new LanguageDetectorME(model); threadLocal.set(ld); } return ld; } @Override public Language[] predictLanguages(CharSequence content) { return getLanguageDetector().predictLanguages(content); } @Override public Language predictLanguage(CharSequence content) { return getLanguageDetector().predictLanguage(content); } @Override public String[] getSupportedLanguages() { return getLanguageDetector().getSupportedLanguages(); } @Override public void close() { threadLocal.remove(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/langdetect/package-info.java0100644 0000000 0000000 00000001615 15217274217 033213 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to predicting languages from samples of text. */ package opennlp.tools.langdetect; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_languagemodel_La0100644 0000000 0000000 00000000156 15217274217 032463 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/languagemodel/LanguageModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/languagemodel/LanguageModel.java0100644 0000000 0000000 00000003155 15217274217 034066 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.languagemodel; /** * A language model can calculate the probability p (between 0 and 1) of a * certain {@link opennlp.tools.util.StringList sequence of tokens}, given its underlying vocabulary. */ public interface LanguageModel { /** * Calculate the probability of a series of tokens (e.g. a sentence), given a vocabulary. * * @param tokens the text tokens to calculate the {@code probability} for. * * @return the probability of the given text tokens in the vocabulary */ double calculateProbability(String... tokens); /** * Predict the most probable output sequence of tokens, given an input sequence of {@code tokens}. * * @param tokens a sequence of tokens * @return the most probable subsequent token sequence */ String[] predictNextTokens(String... tokens); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_languagemodel_NG0100644 0000000 0000000 00000000163 15217274217 032431 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/languagemodel/NGramLanguageModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/languagemodel/NGramLanguageModel0100644 0000000 0000000 00000012370 15217274217 034072 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.languagemodel; import java.io.IOException; import java.io.InputStream; import opennlp.tools.ngram.NGramModel; import opennlp.tools.ngram.NGramUtils; import opennlp.tools.util.StringList; /** * A {@link LanguageModel} based on a {@link NGramModel} using Stupid Backoff to get * the probabilities of the ngrams. */ public class NGramLanguageModel extends NGramModel implements LanguageModel { private static final int DEFAULT_N = 3; private final int n; /** * Initializes an {@link NGramLanguageModel} with {@link #DEFAULT_N}. */ public NGramLanguageModel() { this(DEFAULT_N); } /** * Initializes an {@link NGramLanguageModel} with the given {@code n} for the ngram size. * * @param n The size of the ngrams to be used. Must be greater than {@code 0}. * * @throws IllegalArgumentException Thrown if one of the arguments was invalid. */ public NGramLanguageModel(int n) { if (n <= 0) { throw new IllegalArgumentException("Parameter 'n' must be greater than 0."); } this.n = n; } /** * Initializes a {@link NGramLanguageModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. * @throws IllegalArgumentException Thrown if one of the arguments was invalid. */ public NGramLanguageModel(InputStream in) throws IOException { this(in, DEFAULT_N); } /** * Initializes a {@link NGramLanguageModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * @param n The size of the ngrams to be used. Must be greater than {@code 0}. * * @throws IOException Thrown if IO errors occurred during initialization. * @throws IllegalArgumentException Thrown if one of the arguments was invalid. */ public NGramLanguageModel(InputStream in, int n) throws IOException { super(in); if (n <= 0) { throw new IllegalArgumentException("Parameter 'n' must be greater than 0."); } this.n = n; } /** * Adds further tokens. * * @param tokens Text elements to add to the {@link NGramLanguageModel}. */ public void add(String... tokens) { add(new StringList(tokens), 1, n); } @Override public double calculateProbability(String... tokens) { double probability = 0d; if (size() > 0) { for (String[] ngram : NGramUtils.getNGrams(tokens, n)) { double score = stupidBackoff(new StringList(ngram)); probability += StrictMath.log(score); if (Double.isNaN(probability)) { probability = 0d; break; } } probability = StrictMath.exp(probability); } return probability; } private double calculateProbability(StringList tokens) { double probability = 0d; if (size() > 0) { for (StringList ngram : NGramUtils.getNGrams(tokens, n)) { double score = stupidBackoff(ngram); probability += StrictMath.log(score); if (Double.isNaN(probability)) { probability = 0d; break; } } probability = StrictMath.exp(probability); } return probability; } @Override public String[] predictNextTokens(String... tokens) { double maxProb = Double.NEGATIVE_INFINITY; String[] token = null; for (StringList ngram : this) { String[] sequence = new String[ngram.size() + tokens.length]; System.arraycopy(tokens, 0, sequence, 0, tokens.length); for (int i = 0; i < ngram.size(); i++) { sequence[i + tokens.length] = ngram.getToken(i); } double v = calculateProbability(sequence); if (v > maxProb) { maxProb = v; token = new String[ngram.size()]; for (int i = 0; i < ngram.size(); i++) { token[i] = ngram.getToken(i); } } } return token; } private double stupidBackoff(StringList ngram) { int count = getCount(ngram); StringList nMinusOneToken = NGramUtils.getNMinusOneTokenFirst(ngram); if (nMinusOneToken == null || nMinusOneToken.size() == 0) { return (double) count / (double) size(); } else if (count > 0) { double countM1 = getCount(nMinusOneToken); if (countM1 == 0d) { countM1 = size(); // to avoid Infinite if n-1grams do not exist } return (double) count / countM1; } else { return 0.4 * stupidBackoff(NGramUtils.getNMinusOneTokenLast(ngram)); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/languagemodel/package-info.java0100644 0000000 0000000 00000001565 15217274217 033711 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to language models */ package opennlp.tools.languagemodel; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Defau0100644 0000000 0000000 00000000177 15217274217 032523 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/DefaultLemmatizerContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/DefaultLemmatizerCont0100644 0000000 0000000 00000006676 15217274217 034264 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; /** * Simple feature generator for learning statistical lemmatizers. *

* Features based on Grzegorz Chrupała. 2008. * * Towards a Machine-Learning Architecture for Lexical Functional Grammar Parsing. * PhD dissertation, Dublin City University */ public class DefaultLemmatizerContextGenerator implements LemmatizerContextGenerator { private static final int PREFIX_LENGTH = 5; private static final int SUFFIX_LENGTH = 7; private static final Pattern PATTERN_HAS_CAP = Pattern.compile("[A-Z]"); private static final Pattern PATTERN_HAS_NUM = Pattern.compile("[0-9]"); public DefaultLemmatizerContextGenerator() { } protected static String[] getPrefixes(String lex) { String[] prefs = new String[PREFIX_LENGTH]; for (int li = 1; li < PREFIX_LENGTH; li++) { prefs[li] = lex.substring(0, StrictMath.min(li + 1, lex.length())); } return prefs; } protected static String[] getSuffixes(String lex) { String[] suffs = new String[SUFFIX_LENGTH]; for (int li = 1; li < SUFFIX_LENGTH; li++) { suffs[li] = lex.substring(StrictMath.max(lex.length() - li - 1, 0)); } return suffs; } @Override public String[] getContext(int index, String[] sequence, String[] priorDecisions, Object[] additionalContext) { return getContext(index, sequence, (String[]) additionalContext[0], priorDecisions); } @Override public String[] getContext(int index, String[] toks, String[] tags, String[] preds) { // Word String w0; // Tag String t0; // Previous prediction String p_1; String lex = toks[index]; if (index < 1) { p_1 = "p_1=bos"; } else { p_1 = "p_1=" + preds[index - 1]; } w0 = "w0=" + toks[index]; t0 = "t0=" + tags[index]; List features = new ArrayList<>(); features.add(w0); features.add(t0); features.add(p_1); features.add(p_1 + t0); features.add(p_1 + w0); // do some basic suffix analysis String[] suffs = getSuffixes(lex); for (String suff : suffs) { features.add("suf=" + suff); } String[] prefs = getPrefixes(lex); for (String pref : prefs) { features.add("pre=" + pref); } // see if the word has any special characters if (lex.indexOf('-') != -1) { features.add("h"); } if (PATTERN_HAS_CAP.matcher(lex).find()) { features.add("c"); } if (PATTERN_HAS_NUM.matcher(lex).find()) { features.add("d"); } return features.toArray(new String[0]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Defau0100644 0000000 0000000 00000000200 15217274217 032506 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/DefaultLemmatizerSequenceValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/DefaultLemmatizerSequ0100644 0000000 0000000 00000002252 15217274217 034260 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import opennlp.tools.util.SequenceValidator; /** * The default lemmatizer {@link SequenceValidator} implementation. */ public class DefaultLemmatizerSequenceValidator implements SequenceValidator { //TODO implement this @Override public boolean validSequence(int i, String[] sequence, String[] s, String outcome) { return true; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Dicti0100644 0000000 0000000 00000000162 15217274217 032525 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/DictionaryLemmatizer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/DictionaryLemmatizer.0100644 0000000 0000000 00000021035 15217274217 034221 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * A {@link Lemmatizer} implementation that works by simple dictionary lookup into * a {@link Map} built from a file containing, for each line: *

* {@code word\tabpostag\tablemma}. */ public class DictionaryLemmatizer implements Lemmatizer { /* * The hashmap containing the dictionary. */ private final Map, List> dictMap = new HashMap<>(); /** * Initializes a {@link DictionaryLemmatizer} and related {@link HashMap} * from the input tab separated dictionary. *

* The input file should have, for each line, {@code word\tabpostag\tablemma}. * Alternatively, if multiple lemmas are possible for each word-postag pair, * then the format should be {@code word\tab\postag\tablemma01#lemma02#lemma03}. * * @param dictionaryStream The dictionary referenced by an open {@link InputStream}. * @param charset The {@link Charset character encoding} of the dictionary. * * @throws IOException Thrown if IO errors occurred while reading in from * {@code dictionaryStream}. */ public DictionaryLemmatizer(final InputStream dictionaryStream, Charset charset) throws IOException { init(dictionaryStream, charset); } /** * Initializes a {@link DictionaryLemmatizer} and related {@link HashMap} * from the input tab separated dictionary. *

* The input file should have, for each line, {@code word\tabpostag\tablemma}. * Alternatively, if multiple lemmas are possible for each word-postag pair, * then the format should be {@code word\tab\postag\tablemma01#lemma02#lemma03}. * * @param dictionaryStream The dictionary referenced by an open {@link InputStream}. * * @throws IOException Thrown if IO errors occurred while reading in from * {@code dictionaryStream}. */ public DictionaryLemmatizer(final InputStream dictionaryStream) throws IOException { this(dictionaryStream, StandardCharsets.UTF_8); } /** * Initializes a {@link DictionaryLemmatizer} and related {@link HashMap} * from the input tab separated dictionary. *

* The input file should have, for each line, {@code word\tabpostag\tablemma}. * Alternatively, if multiple lemmas are possible for each word-postag pair, * then the format should be {@code word\tab\postag\tablemma01#lemma02#lemma03}. * * @param dictionaryFile The dictionary referenced by a valid, readable {@link File}. * * @throws IOException Thrown if IO errors occurred while reading in from * {@code dictionaryFile}. */ public DictionaryLemmatizer(File dictionaryFile) throws IOException { this(dictionaryFile, StandardCharsets.UTF_8); } /** * Initializes a {@link DictionaryLemmatizer} and related {@link HashMap} * from the input tab separated dictionary. *

* The input file should have, for each line, {@code word\tabpostag\tablemma}. * Alternatively, if multiple lemmas are possible for each word-postag pair, * then the format should be {@code word\tab\postag\tablemma01#lemma02#lemma03}. * * @param dictionaryFile The dictionary referenced by a valid, readable {@link File}. * @param charset The {@link Charset character encoding} of the dictionary. * * @throws IOException Thrown if IO errors occurred while reading in from * {@code dictionaryFile}. */ public DictionaryLemmatizer(File dictionaryFile, Charset charset) throws IOException { try (InputStream in = new BufferedInputStream(new FileInputStream(dictionaryFile))) { init(in, charset); } } /** * Initializes a {@link DictionaryLemmatizer} and related {@link HashMap} * from the input tab separated dictionary. *

* The input file should have, for each line, {@code word\tabpostag\tablemma}. * Alternatively, if multiple lemmas are possible for each word-postag pair, * then the format should be {@code word\tab\postag\tablemma01#lemma02#lemma03}. * * @param dictionaryPath The dictionary referenced via a valid, readable {@link Path}. * * @throws IOException Thrown if IO errors occurred while reading in from * {@code dictionaryPath}. */ public DictionaryLemmatizer(Path dictionaryPath) throws IOException { init(Files.newInputStream(dictionaryPath), StandardCharsets.UTF_8); } private void init(InputStream dictionary, Charset charset) throws IOException { final BufferedReader breader = new BufferedReader( new InputStreamReader(dictionary, charset)); String line; while ((line = breader.readLine()) != null) { final String[] elems = line.split("\t"); final String[] lemmas = elems[2].split("#"); this.dictMap.put(Arrays.asList(elems[0], elems[1]), Arrays.asList(lemmas)); } } /** * @return Retrieves the {@link Map} containing the dictionary. */ public Map, List> getDictMap() { return this.dictMap; } /** * @param word The surface form word. * @param postag The assigned postag. * * @return Retrieves the dictionary keys (word and postag). */ private List getDictKeys(final String word, final String postag) { return new ArrayList<>(Arrays.asList(word.toLowerCase(Locale.ROOT), postag)); } @Override public String[] lemmatize(final String[] tokens, final String[] postags) { List lemmas = new ArrayList<>(); for (int i = 0; i < tokens.length; i++) { lemmas.add(this.lemmatize(tokens[i], postags[i])); } return lemmas.toArray(new String[0]); } @Override public List> lemmatize(final List tokens, final List posTags) { List> allLemmas = new ArrayList<>(); for (int i = 0; i < tokens.size(); i++) { allLemmas.add(this.getAllLemmas(tokens.get(i), posTags.get(i))); } return allLemmas; } /** * Lookup lemma in a dictionary. Outputs {@code "0"} if no lemma could be found * for the specified {@code word}. * * @param word The token to look up the lemma for. * @param postag The postag. * * @return The corresponding lemma, or {@code "0"} if no lemma for {@code word} * could be found. */ private String lemmatize(final String word, final String postag) { String lemma; final List keys = this.getDictKeys(word, postag); // lookup lemma as value of the map final List keyValues = this.dictMap.get(keys); if ( keyValues != null && !keyValues.isEmpty()) { lemma = keyValues.get(0); } else { lemma = "O"; } return lemma; } /** * Lookup every lemma for a word,pos tag in a dictionary. Outputs {@code "0"} if no * lemmas could be found for the specified {@code word}. * * @param word The token to look up the lemma for. * @param postag The postag. * * @return A list of relevant lemmas. */ private List getAllLemmas(final String word, final String postag) { List lemmasList = new ArrayList<>(); final List keys = this.getDictKeys(word, postag); // lookup lemma as value of the map final List keyValues = this.dictMap.get(keys); if (keyValues != null && !keyValues.isEmpty()) { lemmasList.addAll(keyValues); } else { lemmasList.add("O"); } return lemmasList; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmaSample.java0100644 0000000 0000000 00000007235 15217274217 033127 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.util.Arrays; import java.util.List; import java.util.Objects; import opennlp.tools.commons.Sample; /** * Represents a lemmatized sentence. */ public class LemmaSample implements Sample { private static final long serialVersionUID = -7956607496164605337L; private final List tokens; private final List tags; private final List lemmas; /** * Initializes a {@link LemmaSample} instance with the given parameters. * * @param tokens The tokens. * @param tags The postags. * @param lemmas The lemmas for {@code tokens}. */ public LemmaSample(String[] tokens, String[] tags, String[] lemmas) { this(Arrays.asList(tokens), Arrays.asList(tags), Arrays.asList(lemmas)); } /** * Initializes a {@link LemmaSample} instance with the given parameters. * * @param tokens The tokens. * @param tags The postags. * @param lemmas The lemmas for {@code tokens}. */ public LemmaSample(List tokens, List tags, List lemmas) { validateArguments(tokens.size(), tags.size(), lemmas.size()); this.tokens = List.copyOf(tokens); this.tags = List.copyOf(tags); this.lemmas = List.copyOf(lemmas); } /** * @return Retrieves the tokens of a {@link LemmaSample}. */ public String[] getTokens() { return tokens.toArray(new String[0]); } /** * @return Retrieves the postags of a {@link LemmaSample}. */ public String[] getTags() { return tags.toArray(new String[0]); } /** * @return Retrieves the lemmas of a {@link LemmaSample}. */ public String[] getLemmas() { return lemmas.toArray(new String[0]); } private void validateArguments(int tokensSize, int tagsSize, int lemmasSize) throws IllegalArgumentException { if (tokensSize != tagsSize || tagsSize != lemmasSize) { throw new IllegalArgumentException( "All arrays must have the same length: " + "sentenceSize: " + tokensSize + ", tagsSize: " + tagsSize + ", predsSize: " + lemmasSize + "!"); } } @Override public String toString() { StringBuilder lemmaString = new StringBuilder(); for (int ci = 0; ci < lemmas.size(); ci++) { lemmaString.append(tokens.get(ci)).append("\t").append(tags.get(ci)) .append("\t").append(lemmas.get(ci)).append("\n"); } return lemmaString.toString(); } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(getTokens()), Arrays.hashCode(getTags()), Arrays.hashCode(getLemmas())); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof LemmaSample a) { return Arrays.equals(getTokens(), a.getTokens()) && Arrays.equals(getTags(), a.getTags()) && Arrays.equals(getLemmas(), a.getLemmas()); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Lemma0100644 0000000 0000000 00000000164 15217274217 032526 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmaSampleEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmaSampleEventStrea0100644 0000000 0000000 00000004615 15217274217 034207 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import opennlp.tools.ml.model.Event; import opennlp.tools.util.AbstractEventStream; import opennlp.tools.util.ObjectStream; /** * Class for creating an event stream out of data files for training a probabilistic {@link Lemmatizer}. */ public class LemmaSampleEventStream extends AbstractEventStream { private final LemmatizerContextGenerator contextGenerator; /** * Creates a new event stream based on the specified data stream using a * {@link LemmatizerContextGenerator}. * * @param d The data stream for this event stream. * @param cg The {@link LemmatizerContextGenerator} which should be used in the * creation of events for this event stream {@code d}. */ public LemmaSampleEventStream(ObjectStream d, LemmatizerContextGenerator cg) { super(d); this.contextGenerator = cg; } @Override protected Iterator createEvents(LemmaSample sample) { if (sample != null) { List events = new ArrayList<>(); String[] toksArray = sample.getTokens(); String[] tagsArray = sample.getTags(); String[] lemmasArray = LemmatizerME.encodeLemmas(toksArray,sample.getLemmas()); for (int ei = 0, el = sample.getTokens().length; ei < el; ei++) { events.add(new Event(lemmasArray[ei], contextGenerator.getContext(ei,toksArray,tagsArray,lemmasArray))); } return events.iterator(); } else { return Collections.emptyListIterator(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Lemma0100644 0000000 0000000 00000000167 15217274217 032531 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmaSampleSequenceStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmaSampleSequenceSt0100644 0000000 0000000 00000005154 15217274217 034205 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.io.IOException; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.Sequence; import opennlp.tools.ml.model.SequenceStream; import opennlp.tools.util.ObjectStream; /** * A {@link SequenceStream} implementation encapsulating {@link LemmaSample samples}. */ public class LemmaSampleSequenceStream implements SequenceStream { private final ObjectStream samples; private final LemmatizerContextGenerator contextGenerator; public LemmaSampleSequenceStream(ObjectStream samples, LemmatizerContextGenerator contextGenerator) { this.samples = samples; this.contextGenerator = contextGenerator; } @Override public Sequence read() throws IOException { LemmaSample sample = samples.read(); if (sample != null) { String[] sentence = sample.getTokens(); String[] tags = sample.getTags(); String[] preds = sample.getLemmas(); Event[] events = new Event[sentence.length]; for (int i = 0; i < sentence.length; i++) { // it is safe to pass the tags as previous tags because // the context generator does not look for non predicted tags String[] context = contextGenerator.getContext(i, sentence, tags, preds); events[i] = new Event(tags[i], context); } return new Sequence<>(events,sample); } return null; } @Override public Event[] updateContext(Sequence sequence, AbstractModel model) { // TODO: Should be implemented for Perceptron sequence learning ... return null; } @Override public void reset() throws IOException, UnsupportedOperationException { samples.reset(); } @Override public void close() throws IOException { samples.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Lemma0100644 0000000 0000000 00000000157 15217274217 032530 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmaSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmaSampleStream.jav0100644 0000000 0000000 00000004437 15217274217 034143 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * Reads data for training and testing the {@link Lemmatizer}. *

* The format consists of: * {@code word\tpostag\tlemma}. */ public class LemmaSampleStream extends FilterObjectStream { private static final Logger logger = LoggerFactory.getLogger(LemmaSampleStream.class); /** * Initializes a {@link LemmaSampleStream instance}. * * @param samples A plain text {@link ObjectStream line stream}. */ public LemmaSampleStream(ObjectStream samples) { super(samples); } @Override public LemmaSample read() throws IOException { List toks = new ArrayList<>(); List tags = new ArrayList<>(); List preds = new ArrayList<>(); for (String line = samples.read(); line != null && !line.isEmpty(); line = samples.read()) { String[] parts = line.split("\t"); if (parts.length != 3) { logger.warn("Skipping corrupt line: {}", line); } else { toks.add(parts[0]); tags.add(parts[1]); preds.add(parts[2]); } } if (toks.size() > 0) { return new LemmaSample(toks.toArray(new String[0]), tags.toArray(new String[0]), preds.toArray(new String[0])); } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/Lemmatizer.java0100644 0000000 0000000 00000003007 15217274217 033034 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.util.List; /** * The common interface for lemmatizers. */ public interface Lemmatizer { /** * Generates lemmas for the word and postag. * * @param toks An array of the tokens * @param tags an array of the pos tags * * @return An array of possible lemmas for each token in the {@code toks} sequence. */ String[] lemmatize(String[] toks, String[] tags); /** * Generates lemma tags for the word and postag. * * @param toks An array of the tokens * @param tags An array of the pos tags * @return A list of every possible lemma for each token in the {@code toks} sequence. */ List> lemmatize(List toks, List tags); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Lemma0100644 0000000 0000000 00000000170 15217274217 032523 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerContextGene0100644 0000000 0000000 00000003413 15217274217 034261 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import opennlp.tools.util.BeamSearchContextGenerator; /** * Interface for the context generator used for probabilistic {@link Lemmatizer}. */ public interface LemmatizerContextGenerator extends BeamSearchContextGenerator { /** * Returns the contexts for lemmatizing of the specified index. * * @param i The index of the token in the specified {@code toks} array for which * the context should be constructed. * @param toks The tokens of the sentence. The {@code toString()} methods of * these objects should return the token text. * @param tags The POS tags for the specified {@code toks}. * @param lemmas The previous decisions made in the tagging of this sequence. * Only indices less than {@code i} will be examined. * @return An array of predictive contexts on which a model basis its decisions. */ String[] getContext(int i, String[] toks, String[] tags, String[] lemmas); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Lemma0100644 0000000 0000000 00000000171 15217274217 032524 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerEvaluationM0100644 0000000 0000000 00000002036 15217274217 034262 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link Lemmatizer lemmatizers}. */ public interface LemmatizerEvaluationMonitor extends EvaluationMonitor { } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Lemma0100644 0000000 0000000 00000000161 15217274217 032523 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerEvaluator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerEvaluator.j0100644 0000000 0000000 00000006150 15217274217 034231 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.Mean; /** * The {@link LemmatizerEvaluator} measures the performance of * the given {@link Lemmatizer} with the provided reference * {@link LemmaSample samples}. */ public class LemmatizerEvaluator extends Evaluator { private final Lemmatizer lemmatizer; private final Mean wordAccuracy = new Mean(); /** * Initializes a {@link LemmatizerEvaluator} instance with the given {@link Lemmatizer}. * * @param aLemmatizer The {@link Lemmatizer} to evaluate. * @param listeners The {@link LemmatizerEvaluationMonitor evaluation listeners}. */ public LemmatizerEvaluator(Lemmatizer aLemmatizer, LemmatizerEvaluationMonitor ... listeners) { super(listeners); this.lemmatizer = aLemmatizer; } /** * Evaluates the given reference {@link LemmaSample} object. *

* This is done by tagging the sentence from the reference * {@link LemmaSample} with the {@link Lemmatizer}. The * tags are then used to update the word accuracy score. * * @param reference the reference {@link LemmaSample}. * * @return The predicted {@link LemmaSample}. */ @Override protected LemmaSample processSample(LemmaSample reference) { String[] predictedLemmas = lemmatizer.lemmatize(reference.getTokens(), reference.getTags()); String[] referenceLemmas = reference.getLemmas(); for (int i = 0; i < referenceLemmas.length; i++) { if (referenceLemmas[i].equals(predictedLemmas[i])) { wordAccuracy.add(1); } else { wordAccuracy.add(0); } } return new LemmaSample(reference.getTokens(), reference.getTags(), predictedLemmas); } /** * Accuracy is defined as: * {@code word accuracy = correctly detected tags / total words} * * @return Retrieves the word accuracy. */ public double getWordAccuracy() { return wordAccuracy.mean(); } /** * @return Retrieves the total number of words considered in the evaluation. */ public long getWordCount() { return wordAccuracy.count(); } /** * Returns this object's human-readable {@link String} representation. */ @Override public String toString() { return "Accuracy:" + wordAccuracy.mean() + " Number of Samples: " + wordAccuracy.count(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Lemma0100644 0000000 0000000 00000000157 15217274217 032530 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerFactory.jav0100644 0000000 0000000 00000005460 15217274217 034230 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.ext.ExtensionLoader; /** * The factory that provides {@link Lemmatizer} default implementation and * resources. */ public class LemmatizerFactory extends BaseToolFactory { /** * Instantiates a {@link LemmatizerFactory} that provides the default implementation * of the resources. */ public LemmatizerFactory() { } /** * Instantiates a {@link LemmatizerFactory} via a given {@code subclassName}. * * @param subclassName The class name used for instantiation. If {@code null}, an * instance of {@link LemmatizerFactory} will be returned * per default. Otherwise, the {@link ExtensionLoader} mechanism * is applied to load the requested {@code subclassName}. * * @return A valid {@link LemmatizerFactory} instance. */ public static LemmatizerFactory create(String subclassName) throws InvalidFormatException { if (subclassName == null) { // will create the default factory return new LemmatizerFactory(); } try { return ExtensionLoader.instantiateExtension(LemmatizerFactory.class, subclassName); } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } } @Override public void validateArtifactMap() throws InvalidFormatException { // no additional artifacts } /** * @return Retrieves a new {@link SequenceValidator} instance. */ public SequenceValidator getSequenceValidator() { return new DefaultLemmatizerSequenceValidator(); } /** * @return Retrieves a new {@link LemmatizerContextGenerator} instance. */ public LemmatizerContextGenerator getContextGenerator() { return new DefaultLemmatizerContextGenerator(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerME.java0100644 0000000 0000000 00000027304 15217274217 033264 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.EventModelSequenceTrainer; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.Probabilistic; import opennlp.tools.ml.SequenceTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.TrainerFactory.TrainerType; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Sequence; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.StringUtil; import opennlp.tools.util.TrainingParameters; /** * A probabilistic {@link Lemmatizer} implementation. *

* Tries to predict the induced permutation class for each word depending on * its surrounding context. *

* Based on Grzegorz Chrupała. 2008. * * Towards a Machine-Learning Architecture for Lexical Functional Grammar Parsing. * PhD dissertation, Dublin City University * * @see Lemmatizer * @see Probabilistic */ public class LemmatizerME implements Lemmatizer, Probabilistic { public static final int LEMMA_NUMBER = 29; public static final int DEFAULT_BEAM_SIZE = 3; protected final int beamSize; private Sequence bestSequence; private final SequenceClassificationModel model; private final LemmatizerContextGenerator contextGenerator; private final SequenceValidator sequenceValidator; /** * Initializes a {@link LemmatizerME} with the provided * {@link LemmatizerModel model} and a default * {@code beam size} of {@code 3}. * * @param model The {@link LemmatizerModel} to be used. */ public LemmatizerME(LemmatizerModel model) { LemmatizerFactory factory = model.getFactory(); int defaultBeamSize = LemmatizerME.DEFAULT_BEAM_SIZE; String beamSizeString = model.getManifestProperty(BeamSearch.BEAM_SIZE_PARAMETER); if (beamSizeString != null) { defaultBeamSize = Integer.parseInt(beamSizeString); } contextGenerator = factory.getContextGenerator(); beamSize = defaultBeamSize; sequenceValidator = factory.getSequenceValidator(); if (model.getLemmatizerSequenceModel() != null) { this.model = model.getLemmatizerSequenceModel(); } else { this.model = new opennlp.tools.ml.BeamSearch(beamSize, (MaxentModel) model.getLemmatizerSequenceModel(), 0); } } @Override public String[] lemmatize(String[] toks, String[] tags) { String[] ses = predictSES(toks, tags); return decodeLemmas(toks, ses); } @Override public List> lemmatize(List toks, List tags) { String[] tokens = toks.toArray(new String[0]); String[] posTags = tags.toArray(new String[0]); String[][] allLemmas = predictLemmas(LEMMA_NUMBER, tokens, posTags); List> predictedLemmas = new ArrayList<>(); for (String[] allLemma : allLemmas) { predictedLemmas.add(Arrays.asList(allLemma)); } return predictedLemmas; } /** * Predict Short Edit Script (automatically induced lemma class). * * @param toks An array of tokens. * @param tags An array of postags. * * @return An array of possible lemma classes for each token in {@code toks}. */ public String[] predictSES(String[] toks, String[] tags) { bestSequence = model.bestSequence(toks, new Object[] {tags}, contextGenerator, sequenceValidator); List ses = bestSequence.getOutcomes(); return ses.toArray(new String[0]); } /** * Predict all possible lemmas (using a default upper bound). * * @param numLemmas The default number of lemmas * @param toks An array of tokens. * @param tags An array of postags. * * @return A 2-dimensional array containing all possible lemmas for each token and postag pair. */ public String[][] predictLemmas(int numLemmas, String[] toks, String[] tags) { Sequence[] bestSequences = model.bestSequences(numLemmas, toks, new Object[] {tags}, contextGenerator, sequenceValidator); String[][] allLemmas = new String[bestSequences.length][]; for (int i = 0; i < allLemmas.length; i++) { List ses = bestSequences[i].getOutcomes(); String[] sesArray = ses.toArray(new String[0]); allLemmas[i] = decodeLemmas(toks,sesArray); } return allLemmas; } /** * Decodes the lemma from the word and the induced lemma class. * * @param toks An array of tokens. * @param preds An array of predicted lemma classes. * * @return The array of decoded lemmas. */ public static String[] decodeLemmas(String[] toks, String[] preds) { List lemmas = new ArrayList<>(); for (int i = 0; i < toks.length; i++) { String lemma = StringUtil.decodeShortestEditScript(toks[i].toLowerCase(Locale.ROOT), preds[i]); if (lemma.length() == 0) { lemma = "_"; } lemmas.add(lemma); } return lemmas.toArray(new String[0]); } /** * Encodes the word given its lemmas. * * @param toks An array of tokens. * @param lemmas An array of lemmas. * * @return The array of lemma classes. */ public static String[] encodeLemmas(String[] toks, String[] lemmas) { List sesList = new ArrayList<>(); for (int i = 0; i < toks.length; i++) { String ses = StringUtil.getShortestEditScript(toks[i], lemmas[i]); if (ses.length() == 0) { ses = "_"; } sesList.add(ses); } return sesList.toArray(new String[0]); } /** * @param sentence An array of tokens. * @param tags An array of postags. * * @return Retrieves the top-k {@link Sequence sequences}. */ public Sequence[] topKSequences(String[] sentence, String[] tags) { return model.bestSequences(DEFAULT_BEAM_SIZE, sentence, new Object[] { tags }, contextGenerator, sequenceValidator); } /** * @param sentence An array of tokens. * @param tags An array of postags. * @param minSequenceScore The minimum score to be achieved. * * @return Retrieves the top-k {@link Sequence sequences}. */ public Sequence[] topKSequences(String[] sentence, String[] tags, double minSequenceScore) { return model.bestSequences(DEFAULT_BEAM_SIZE, sentence, new Object[] { tags }, minSequenceScore, contextGenerator, sequenceValidator); } /** * Populates the specified array with the probabilities of the last decoded sequence. * The sequence was determined based on the previous call to * {@link #lemmatize(String[], String[])}. *

* The specified array should be at least as large as the number of tokens in the * previous call to {@link #lemmatize(String[], String[])}. * * @param probs An array used to hold the probabilities of the last decoded sequence. */ public void probs(double[] probs) { bestSequence.getProbs(probs); } /** * {@inheritDoc} * * The sequence was determined based on the previous call to * {@link #lemmatize(String[], String[])}. * * @return An array with the same number of probabilities as tokens were sent to * {@link #lemmatize(String[], String[])} when it was last called. */ @Override public double[] probs() { return bestSequence.getProbs(); } /** * Starts a training of a {@link LemmatizerModel} with the given parameters. * * @param languageCode The ISO conform language code. * @param samples The {@link ObjectStream} of {@link LemmaSample} used as input for training. * @param params The {@link TrainingParameters} for the context of the training. * @param factory The {@link LemmatizerFactory} for creating related objects defined * via {@code params}. * * @return A valid, trained {@link LemmatizerModel} instance. * @throws IOException Thrown if IO errors occurred. */ public static LemmatizerModel train(String languageCode, ObjectStream samples, TrainingParameters params, LemmatizerFactory factory) throws IOException { LemmatizerContextGenerator contextGenerator = factory.getContextGenerator(); Map manifestInfoEntries = new HashMap<>(); TrainerType trainerType = TrainerFactory.getTrainerType(params); MaxentModel lemmatizerModel = null; SequenceClassificationModel seqLemmatizerModel = null; if (TrainerType.EVENT_MODEL_TRAINER.equals(trainerType)) { ObjectStream es = new LemmaSampleEventStream(samples, contextGenerator); EventTrainer trainer = TrainerFactory.getEventTrainer(params, manifestInfoEntries); lemmatizerModel = trainer.train(es); } else if (TrainerType.EVENT_MODEL_SEQUENCE_TRAINER.equals(trainerType)) { LemmaSampleSequenceStream ss = new LemmaSampleSequenceStream(samples, contextGenerator); EventModelSequenceTrainer trainer = TrainerFactory.getEventModelSequenceTrainer(params, manifestInfoEntries); lemmatizerModel = trainer.train(ss); } else if (TrainerType.SEQUENCE_TRAINER.equals(trainerType)) { SequenceTrainer trainer = TrainerFactory.getSequenceModelTrainer( params, manifestInfoEntries); // TODO: This will probably cause issue, since the feature generator uses the outcomes array LemmaSampleSequenceStream ss = new LemmaSampleSequenceStream(samples, contextGenerator); seqLemmatizerModel = trainer.train(ss); } else { throw new IllegalArgumentException("Trainer type is not supported: " + trainerType); } int beamSize = params.getIntParameter(BeamSearch.BEAM_SIZE_PARAMETER, LemmatizerME.DEFAULT_BEAM_SIZE); if (lemmatizerModel != null) { return new LemmatizerModel(languageCode, lemmatizerModel, beamSize, manifestInfoEntries, factory); } else { return new LemmatizerModel(languageCode, seqLemmatizerModel, manifestInfoEntries, factory); } } /** * @param sentence An array of tokens. * @param tags An array of postags. * * @return Retrieves the top-k {@link Sequence lemma classes}. */ public Sequence[] topKLemmaClasses(String[] sentence, String[] tags) { return model.bestSequences(DEFAULT_BEAM_SIZE, sentence, new Object[] { tags }, contextGenerator, sequenceValidator); } /** * @param sentence An array of tokens. * @param tags An array of postags. * @param minSequenceScore The minimum score to be achieved. * * @return Retrieves the top-k {@link Sequence lemma classes}. */ public Sequence[] topKLemmaClasses(String[] sentence, String[] tags, double minSequenceScore) { return model.bestSequences(DEFAULT_BEAM_SIZE, sentence, new Object[] { tags }, minSequenceScore, contextGenerator, sequenceValidator); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/LemmatizerModel.java0100644 0000000 0000000 00000016301 15217274217 034016 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Serial; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.Properties; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.BaseModel; /** * The {@link LemmatizerModel} is the model used by a learnable {@link Lemmatizer}. * * @see LemmatizerME */ public class LemmatizerModel extends BaseModel { @Serial private static final long serialVersionUID = -3362902631186156673L; private static final String COMPONENT_NAME = "StatisticalLemmatizer"; private static final String LEMMATIZER_MODEL_ENTRY_NAME = "lemmatizer.model"; /** * Initializes a {@link LemmatizerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param lemmatizerModel A valid {@link SequenceClassificationModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link LemmatizerFactory} for creating related objects. */ public LemmatizerModel(String languageCode, SequenceClassificationModel lemmatizerModel, Map manifestInfoEntries, LemmatizerFactory factory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, factory); artifactMap.put(LEMMATIZER_MODEL_ENTRY_NAME, lemmatizerModel); checkArtifactMap(); } /** * Initializes a {@link LemmatizerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param lemmatizerModel A valid {@link MaxentModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link LemmatizerFactory} for creating related objects. */ public LemmatizerModel(String languageCode, MaxentModel lemmatizerModel, Map manifestInfoEntries, LemmatizerFactory factory) { this(languageCode, lemmatizerModel, LemmatizerME.DEFAULT_BEAM_SIZE, manifestInfoEntries, factory); } /** * Initializes a {@link LemmatizerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param lemmatizerModel A valid {@link MaxentModel}. * @param beamSize The size of the beam that should be used when decoding sequences. * @param manifestInfoEntries Additional information kept in the manifest. * @param factory The {@link LemmatizerFactory} for creating related objects. */ public LemmatizerModel(String languageCode, MaxentModel lemmatizerModel, int beamSize, Map manifestInfoEntries, LemmatizerFactory factory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, factory); artifactMap.put(LEMMATIZER_MODEL_ENTRY_NAME, lemmatizerModel); Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); manifest.put(BeamSearch.BEAM_SIZE_PARAMETER, Integer.toString(beamSize)); checkArtifactMap(); } /** * Initializes a {@link LemmatizerModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param lemmatizerModel A valid {@link MaxentModel}. * @param factory The {@link LemmatizerFactory} for creating related objects. */ public LemmatizerModel(String languageCode, MaxentModel lemmatizerModel, LemmatizerFactory factory) { this(languageCode, lemmatizerModel, null, factory); } /** * Initializes a {@link LemmatizerModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public LemmatizerModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link LemmatizerModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public LemmatizerModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link LemmatizerModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public LemmatizerModel(Path modelPath) throws IOException { super(COMPONENT_NAME, Files.newInputStream(modelPath)); } /** * Initializes a {@link LemmatizerModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public LemmatizerModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(LEMMATIZER_MODEL_ENTRY_NAME) instanceof AbstractModel)) { throw new InvalidFormatException("Lemmatizer model is incomplete!"); } } /** * @return Retrieves a {@link SequenceClassificationModel} instance. */ public SequenceClassificationModel getLemmatizerSequenceModel() { Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); if (artifactMap.get(LEMMATIZER_MODEL_ENTRY_NAME) instanceof MaxentModel) { String beamSizeString = manifest.getProperty(BeamSearch.BEAM_SIZE_PARAMETER); int beamSize = LemmatizerME.DEFAULT_BEAM_SIZE; if (beamSizeString != null) { beamSize = Integer.parseInt(beamSizeString); } return new BeamSearch(beamSize, (MaxentModel) artifactMap.get(LEMMATIZER_MODEL_ENTRY_NAME)); } else if (artifactMap.get(LEMMATIZER_MODEL_ENTRY_NAME) instanceof SequenceClassificationModel) { return (SequenceClassificationModel) artifactMap.get(LEMMATIZER_MODEL_ENTRY_NAME); } else { return null; } } @Override protected Class getDefaultFactory() { return LemmatizerFactory.class; } /** * @return Retrieves the active {@link LemmatizerFactory}. */ public LemmatizerFactory getFactory() { return (LemmatizerFactory) this.toolFactory; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_lemmatizer_Threa0100644 0000000 0000000 00000000164 15217274217 032536 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/ThreadSafeLemmatizerME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/ThreadSafeLemmatizerM0100644 0000000 0000000 00000005166 15217274217 034170 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.lemmatizer; import java.util.List; import opennlp.tools.commons.ThreadSafe; import opennlp.tools.ml.Probabilistic; /** * A thread-safe version of the {@link LemmatizerME}. Using it is completely transparent. * You can use it in a single-threaded context as well, it only incurs a minimal overhead. *

* Note:
* This implementation uses a {@link ThreadLocal}. Although the implementation is * lightweight because the model is not duplicated, if you have many long-running threads, * you may run into memory problems. *

* Be careful when using this in a Jakarta EE application, for example. *

* The user is responsible for clearing the {@link ThreadLocal} * via calling {@link #close()}. * * @see Lemmatizer * @see LemmatizerME */ @ThreadSafe public class ThreadSafeLemmatizerME implements Lemmatizer, Probabilistic, AutoCloseable { private final LemmatizerModel model; private final ThreadLocal threadLocal = new ThreadLocal<>(); /** * Initializes a {@link ThreadSafeLemmatizerME} with the specified {@code model}. * * @param model A valid {@link LemmatizerModel}. */ public ThreadSafeLemmatizerME(LemmatizerModel model) { super(); this.model = model; } private LemmatizerME getLemmatizer() { LemmatizerME l = threadLocal.get(); if (l == null) { l = new LemmatizerME(model); threadLocal.set(l); } return l; } @Override public String[] lemmatize(String[] toks, String[] tags) { return getLemmatizer().lemmatize(toks, tags); } @Override public List> lemmatize(List toks, List tags) { return getLemmatizer().lemmatize(toks, tags); } @Override public double[] probs() { return getLemmatizer().probs(); } @Override public void close() { threadLocal.remove(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/lemmatizer/package-info.java0100644 0000000 0000000 00000001600 15217274217 033244 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to the lemmatizer functionality. */ package opennlp.tools.lemmatizer; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/log/LogPrintStream.java0100644 0000000 0000000 00000004643 15217274217 032254 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.log; import java.io.PrintStream; import java.util.Objects; import org.slf4j.Logger; import org.slf4j.event.Level; import opennlp.tools.commons.Internal; /** * This class serves as an adapter for a {@link Logger} used within a {@link PrintStream}. */ @Internal public class LogPrintStream extends PrintStream { private final Logger logger; private final Level level; /** * Creates a {@link LogPrintStream} for the given {@link Logger}. * * @param logger must not be {@code null} */ public LogPrintStream(Logger logger) { this(logger, Level.INFO); } /** * Creates a {@link LogPrintStream} for the given {@link Logger}, which logs at the specified * {@link Level level}. * * @param logger must not be {@code null} * @param level must not be {@code null} */ public LogPrintStream(Logger logger, Level level) { super(nullOutputStream()); Objects.requireNonNull(logger, "logger must not be NULL."); Objects.requireNonNull(level, "log level must not be NULL."); this.logger = logger; this.level = level; } @Override public PrintStream printf(String format, Object... args) { log(String.format(format, args)); return this; } @Override public void println(String msg) { log(msg); } private void log(String msg) { switch (level) { case TRACE: logger.trace(msg); break; case DEBUG: logger.debug(msg); break; case INFO: logger.info(msg); break; case WARN: logger.warn(msg); break; case ERROR: logger.error(msg); break; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/log/package-info.java0100644 0000000 0000000 00000001626 15217274217 031664 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package contains a {@link java.io.PrintStream} adapter for internal use only. */ package opennlp.tools.log; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_AbstractEvent0100644 0000000 0000000 00000000167 15217274217 032502 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/AbstractEventModelSequenceTrainer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/AbstractEventModelSequenceTra0100644 0000000 0000000 00000003226 15217274217 034133 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.io.IOException; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceStream; import opennlp.tools.util.TrainingParameters; /** * A basic {@link EventModelSequenceTrainer} implementation that processes {@link Event events}. */ public abstract class AbstractEventModelSequenceTrainer extends AbstractTrainer implements EventModelSequenceTrainer { public AbstractEventModelSequenceTrainer() { } public abstract MaxentModel doTrain(SequenceStream events) throws IOException; @Override public final MaxentModel train(SequenceStream events) throws IOException { validate(); MaxentModel model = doTrain(events); addToReport(TrainingParameters.TRAINER_TYPE_PARAM, EventModelSequenceTrainer.SEQUENCE_VALUE); return model; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/AbstractEventTrainer.java0100644 0000000 0000000 00000006440 15217274217 033260 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.io.IOException; import opennlp.tools.ml.model.AbstractDataIndexer; import opennlp.tools.ml.model.ChecksumEventStream; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.ml.model.DataIndexerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.InsufficientTrainingDataException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; /** * A basic {@link EventTrainer} implementation. */ public abstract class AbstractEventTrainer extends AbstractTrainer implements EventTrainer { public static final String DATA_INDEXER_PARAM = "DataIndexer"; public static final String DATA_INDEXER_ONE_PASS_VALUE = "OnePass"; public static final String DATA_INDEXER_TWO_PASS_VALUE = "TwoPass"; public static final String DATA_INDEXER_ONE_PASS_REAL_VALUE = "OnePassRealValue"; public AbstractEventTrainer() { } public AbstractEventTrainer(TrainingParameters parameters) { super(parameters); } @Override public void validate() { super.validate(); } public abstract boolean isSortAndMerge(); public DataIndexer getDataIndexer(ObjectStream events) throws IOException { trainingParameters.put(AbstractDataIndexer.SORT_PARAM, isSortAndMerge()); // If the cutoff was set, don't overwrite the value. if (trainingParameters.getIntParameter(TrainingParameters.CUTOFF_PARAM, -1) == -1) { trainingParameters.put(TrainingParameters.CUTOFF_PARAM, TrainingParameters.CUTOFF_DEFAULT_VALUE); } DataIndexer indexer = DataIndexerFactory.getDataIndexer(trainingParameters, reportMap); indexer.index(events); return indexer; } public abstract MaxentModel doTrain(DataIndexer indexer) throws IOException; @Override public final MaxentModel train(DataIndexer indexer) throws IOException { validate(); if (indexer.getOutcomeLabels().length <= 1) { throw new InsufficientTrainingDataException("Training data must contain more than one outcome"); } MaxentModel model = doTrain(indexer); addToReport(TrainingParameters.TRAINER_TYPE_PARAM, EventTrainer.EVENT_VALUE); return model; } @Override public final MaxentModel train(ObjectStream events) throws IOException { validate(); ChecksumEventStream hses = new ChecksumEventStream(events); DataIndexer indexer = getDataIndexer(hses); addToReport("Training-Eventhash", String.valueOf(hses.calculateChecksum())); return train(indexer); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/AbstractMLModelWriter.java0100644 0000000 0000000 00000010731 15217274217 033336 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.model.AbstractModelWriter; import opennlp.tools.ml.model.ComparablePredicate; import opennlp.tools.ml.model.Context; public abstract class AbstractMLModelWriter extends AbstractModelWriter { private static final Logger logger = LoggerFactory.getLogger(AbstractMLModelWriter.class); protected Context[] PARAMS; protected String[] OUTCOME_LABELS; protected String[] PRED_LABELS; protected int numOutcomes; /** * Sorts and optimizes the model parameters. Thereby, parameters with * {@code 0} weight and predicates with no parameters are removed. * * @return A {@link ComparablePredicate[]}. */ protected abstract ComparablePredicate[] sortValues(); /** * Computes outcome patterns via {@link ComparablePredicate[] predicates}. * * @return A {@link List} of {@link List} that represent * the outcomes patterns. */ protected List> computeOutcomePatterns(ComparablePredicate[] sorted) { ComparablePredicate cp = sorted[0]; List> outcomePatterns = new ArrayList<>(); List newGroup = new ArrayList<>(); for (ComparablePredicate predicate : sorted) { if (cp.compareTo(predicate) == 0) { newGroup.add(predicate); } else { cp = predicate; outcomePatterns.add(newGroup); newGroup = new ArrayList<>(); newGroup.add(predicate); } } outcomePatterns.add(newGroup); logger.info("{} outcome patterns", outcomePatterns.size()); return outcomePatterns; } /** * Compresses outcome patterns. * * @return A {@link List} of {@link List} that represent * the remaining outcomes patterns. */ protected List> compressOutcomes(ComparablePredicate[] sorted) { List> outcomePatterns = new ArrayList<>(); if (sorted.length > 0) { ComparablePredicate cp = sorted[0]; List newGroup = new ArrayList<>(); for (ComparablePredicate comparablePredicate : sorted) { if (cp.compareTo(comparablePredicate) == 0) { newGroup.add(comparablePredicate); } else { cp = comparablePredicate; outcomePatterns.add(newGroup); newGroup = new ArrayList<>(); newGroup.add(comparablePredicate); } } outcomePatterns.add(newGroup); } return outcomePatterns; } @Override public void persist() throws IOException { // the mapping from outcomes to their integer indexes writeInt(OUTCOME_LABELS.length); for (String label : OUTCOME_LABELS) { writeUTF(label); } // the mapping from predicates to the outcomes they contributed to. // The sorting is done so that we actually can write this out more // compactly than as the entire list. ComparablePredicate[] sorted = sortValues(); List> compressed = computeOutcomePatterns(sorted); writeInt(compressed.size()); for (List a : compressed) { writeUTF(a.size() + a.get(0).toString()); } // the mapping from predicate names to their integer indexes writeInt(sorted.length); for (ComparablePredicate s : sorted) { writeUTF(s.name); } // write out the parameters for (ComparablePredicate comparablePredicate : sorted) for (int j = 0; j < comparablePredicate.params.length; j++) writeDouble(comparablePredicate.params[j]); close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/AbstractTrainer.java0100644 0000000 0000000 00000010513 15217274217 032252 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.util.HashMap; import java.util.Map; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.maxent.GISTrainer; import opennlp.tools.util.TrainingConfiguration; import opennlp.tools.util.TrainingParameters; public abstract class AbstractTrainer implements Trainer { protected TrainingParameters trainingParameters; protected Map reportMap; protected TrainingConfiguration trainingConfiguration; public AbstractTrainer() { } /** * Initializes a {@link AbstractTrainer} via {@link TrainingParameters}. * * @param trainParams The {@link TrainingParameters} to use. */ public AbstractTrainer(TrainingParameters trainParams) { init(trainParams,new HashMap<>()); } /** * Initializes a {@link AbstractTrainer} via {@link TrainingParameters} and * a {@link Map report map}. * * @param trainParams The {@link TrainingParameters} to use. * @param reportMap The {@link Map} instance used as report map. */ @Override public void init(TrainingParameters trainParams, Map reportMap) { this.trainingParameters = trainParams; if (reportMap == null) reportMap = new HashMap<>(); this.reportMap = reportMap; } /** * {@inheritDoc} */ @Override public void init(TrainingParameters trainParams, Map reportMap, TrainingConfiguration config) { init(trainParams, reportMap); this.trainingConfiguration = config; } /** * @return Retrieves the configured {@link TrainingParameters#ALGORITHM_PARAM} value. */ public String getAlgorithm() { return trainingParameters.getStringParameter(TrainingParameters.ALGORITHM_PARAM, GISTrainer.MAXENT_VALUE); } /** * @return Retrieves the configured {@link TrainingParameters#CUTOFF_PARAM} value. */ public int getCutoff() { return trainingParameters.getIntParameter(TrainingParameters.CUTOFF_PARAM, TrainingParameters.CUTOFF_DEFAULT_VALUE); } /** * @return Retrieves the configured {@link TrainingParameters#ITERATIONS_PARAM} value. */ public int getIterations() { return trainingParameters.getIntParameter(TrainingParameters.ITERATIONS_PARAM, TrainingParameters.ITERATIONS_DEFAULT_VALUE); } /** * Checks the configured {@link TrainingParameters parameters}. * If a subclass overrides this, it should call {@code super.validate();}. * * @throws IllegalArgumentException Thrown if default training parameters are invalid. */ public void validate() { // TODO: Need to validate all parameters correctly ... error prone?! // should validate if algorithm is set? What about the Parser? try { trainingParameters.getIntParameter(TrainingParameters.CUTOFF_PARAM, TrainingParameters.CUTOFF_DEFAULT_VALUE); trainingParameters.getIntParameter(TrainingParameters.ITERATIONS_PARAM, TrainingParameters.ITERATIONS_DEFAULT_VALUE); } catch (NumberFormatException e) { throw new IllegalArgumentException(e); } } /** * Adds the key-value pair to the report map. * @param key The identifying string associated with a certain training parameter. * @param value The parameter value associated with {@code key}. */ protected void addToReport(String key, String value) { reportMap.put(key, value); } /** * Retrieves the {@link TrainingConfiguration} associated with an {@link AbstractTrainer}. * @return {@link TrainingConfiguration} */ public TrainingConfiguration getTrainingConfiguration() { return trainingConfiguration; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/ArrayMath.java0100644 0000000 0000000 00000011322 15217274217 031051 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.util.List; import opennlp.tools.ml.model.Context; /** * Utility class for simple vector arithmetic. */ public class ArrayMath { public static double innerProduct(double[] vecA, double[] vecB) { if (vecA == null || vecB == null || vecA.length != vecB.length) return Double.NaN; double product = 0.0; for (int i = 0; i < vecA.length; i++) { product += vecA[i] * vecB[i]; } return product; } /** * Computes the L1-norm for a vector {@code v}. * * @param v The vector of {@code double} values. * @return The computed L1-norm. */ public static double l1norm(double[] v) { double norm = 0; for (double value : v) norm += StrictMath.abs(value); return norm; } /** * Computes the L2-norm for a vector {@code v}. * * @param v The vector of {@code double} values. * @return The computed L2-norm. */ public static double l2norm(double[] v) { return StrictMath.sqrt(innerProduct(v, v)); } /** * Computes the Inverse L2-norm for a vector {@code v}. * * @param v The vector of {@code double} values. * @return The computed Inverse L2-norm. */ public static double invL2norm(double[] v) { return 1 / l2norm(v); } /** * Computes {@code \log(\sum_{i=1}^n e^{x_i})} using a maximum-element trick * to avoid arithmetic overflow. * * @param x The vector of {@code double} values. * @return The log-sum of exponentials of vector elements. */ public static double logSumOfExps(double[] x) { double max = max(x); double sum = 0.0; for (double v : x) { if (v != Double.NEGATIVE_INFINITY) sum += StrictMath.exp(v - max); } return max + StrictMath.log(sum); } /** * Finds the maximum element in a vector {@code x}. * @param x The vector of {@code double} values. * @return The maximum element in {@code x}. */ public static double max(double[] x) { int maxIdx = argmax(x); return x[maxIdx]; } /** * Finds the index of the maximum element in a vector {@code x} * @param x The vector of {@code double} values. * @return The index of the maximum element. Index of the first * maximum element is returned if multiple maximums are found. */ public static int argmax(double[] x) { if (x == null || x.length == 0) { throw new IllegalArgumentException("Vector x is null or empty"); } int maxIdx = 0; for (int i = 1; i < x.length; i++) { if (x[maxIdx] < x[i]) maxIdx = i; } return maxIdx; } public static void sumFeatures(Context[] context, float[] values, double[] prior) { for (int ci = 0; ci < context.length; ci++) { if (context[ci] != null) { Context predParams = context[ci]; int[] activeOutcomes = predParams.getOutcomes(); double[] activeParameters = predParams.getParameters(); double value = 1; if (values != null) { value = values[ci]; } for (int ai = 0; ai < activeOutcomes.length; ai++) { int oid = activeOutcomes[ai]; prior[oid] += activeParameters[ai] * value; } } } } // === Not really related to math === /** * Convert a list of {@link Double} objects into an array of primitive doubles. * * @param list The input vector of {@link Double values}. * @return The {@code double[]}. */ public static double[] toDoubleArray(List list) { double[] arr = new double[list.size()]; for (int i = 0; i < arr.length; i++) { arr[i] = list.get(i); } return arr; } /** * Convert a list of {@link Integer} objects into an array of primitive integers. * * @param list The input vector of {@link Integer values}. * @return The {@code int[]}. */ public static int[] toIntArray(List list) { int[] arr = new int[list.size()]; for (int i = 0; i < arr.length; i++) { arr[i] = list.get(i); } return arr; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/BeamSearch.java0100644 0000000 0000000 00000026145 15217274217 031164 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.util.Arrays; import java.util.PriorityQueue; import java.util.Queue; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.util.BeamSearchContextGenerator; import opennlp.tools.util.Cache; import opennlp.tools.util.Sequence; import opennlp.tools.util.SequenceValidator; /** * Performs k-best search over a sequence. *

* This is based on the description in Ratnaparkhi (1998), * PhD diss, Univ. of Pennsylvania. * * @see Sequence * @see SequenceValidator * @see BeamSearchContextGenerator */ public class BeamSearch implements SequenceClassificationModel { public static final String BEAM_SIZE_PARAMETER = "BeamSize"; private static final Object[] EMPTY_ADDITIONAL_CONTEXT = new Object[0]; protected final int size; protected final MaxentModel model; private final double[] probs; private Cache contextsCache; private static final int zeroLog = -100000; /** * Immutable node in a backward-linked chain of outcome candidates, used only inside * {@link #bestSequences(int, Object[], Object[], double, BeamSearchContextGenerator, SequenceValidator)}. * A node stores its own outcome plus a parent link, so extending a candidate is O(1); * the full outcome array is materialized only when a candidate is expanded. * Score accumulation ({@code parent.score + StrictMath.log(prob)}) mirrors * {@link Sequence#Sequence(Sequence, String, double)}, and descending score order * mirrors {@link Sequence#compareTo(Sequence)}, so search results stay bit-identical * to a search over {@link Sequence} instances. */ private static final class SearchNode implements Comparable { private final SearchNode parent; private final String outcome; // null on the root private final double prob; private final double score; private final int size; /** * Creates the root node: the empty candidate with score {@code 0}. */ private SearchNode() { this.parent = null; this.outcome = null; this.prob = 0d; this.score = 0d; this.size = 0; } /** * Creates a candidate extending {@code parent} by one outcome. * * @param parent The candidate to extend. Must not be {@code null}. * @param outcome The outcome to append. * @param prob The probability of {@code outcome}. */ private SearchNode(SearchNode parent, String outcome, double prob) { this.parent = parent; this.outcome = outcome; this.prob = prob; this.score = parent.score + StrictMath.log(prob); this.size = parent.size + 1; } /** * @return The outcomes on the path from the root to this node, in sequence order. */ private String[] outcomes() { final String[] outcomes = new String[size]; SearchNode node = this; for (int i = size - 1; i >= 0; i--) { outcomes[i] = node.outcome; node = node.parent; } return outcomes; } /** * Orders nodes by descending score, as {@link Sequence#compareTo(Sequence)} does; * nodes with equal scores keep the order of the queue that holds them. */ @Override public int compareTo(SearchNode other) { return Double.compare(other.score, this.score); } } /** * Initializes a {@link BeamSearch} instance. * * @param size The size of the beam (k). * @param model The {@link MaxentModel} for assigning probabilities to the sequence outcomes. */ public BeamSearch(int size, MaxentModel model) { this(size, model, 0); } /** * Initializes a {@link BeamSearch} instance. * * @param size The size of the beam (k). * @param model The {@link MaxentModel} for assigning probabilities to the sequence outcomes. * @param cacheSize The capacity of the {@link Cache} to use. */ public BeamSearch(int size, MaxentModel model, int cacheSize) { this.size = size; this.model = model; if (cacheSize > 0) { contextsCache = new Cache<>(cacheSize); } this.probs = new double[model.getNumOutcomes()]; } /** * Computes the best sequence of outcomes based on the {@link MaxentModel}. * * @param numSequences The number of sequences. * @param sequence The input {@link T} sequence. * @param additionalContext An {@link Object[]} of additional context. * This is passed to the context generator blindly with the * assumption that the context are appropriate. * @param minSequenceScore The minimum sequence score to use. * @param cg The {@link BeamSearchContextGenerator context generator} to use. * @param validator The {@link SequenceValidator} to validate sequences. * * @return The top ranked {@link Sequence} of outcomes or {@code null} * if no sequence could be found. */ @Override public Sequence[] bestSequences(int numSequences, T[] sequence, Object[] additionalContext, double minSequenceScore, BeamSearchContextGenerator cg, SequenceValidator validator) { Queue prev = new PriorityQueue<>(size); Queue next = new PriorityQueue<>(size); Queue tmp; prev.add(new SearchNode()); if (additionalContext == null) { additionalContext = EMPTY_ADDITIONAL_CONTEXT; } for (int i = 0; i < sequence.length; i++) { int sz = StrictMath.min(size, prev.size()); for (int sc = 0; prev.size() > 0 && sc < sz; sc++) { final SearchNode top = prev.remove(); final String[] outcomes = top.outcomes(); final String[] contexts = cg.getContext(i, sequence, outcomes, additionalContext); final double[] scores; if (contextsCache != null) { scores = contextsCache.computeIfAbsent(contexts, c -> { // eval() writes into probs; cache values must be immutable copies for reuse. double[] res = model.eval(c, probs); double[] copy = new double[res.length]; System.arraycopy(res, 0, copy, 0, res.length); return copy; }); } else { scores = model.eval(contexts, probs); } double[] temp_scores = new double[scores.length]; System.arraycopy(scores, 0, temp_scores, 0, scores.length); Arrays.sort(temp_scores); double min = temp_scores[StrictMath.max(0,scores.length - size)]; for (int p = 0; p < scores.length; p++) { if (scores[p] >= min) { String out = model.getOutcome(p); if (validator.validSequence(i, sequence, outcomes, out)) { final SearchNode ns = new SearchNode(top, out, scores[p]); if (ns.score > minSequenceScore) { next.add(ns); } } } } if (next.size() == 0) { //if no advanced sequences, advance all valid for (int p = 0; p < scores.length; p++) { String out = model.getOutcome(p); if (validator.validSequence(i, sequence, outcomes, out)) { final SearchNode ns = new SearchNode(top, out, scores[p]); if (ns.score > minSequenceScore) { next.add(ns); } } } } } // make prev = next; and re-init next (we reuse existing prev set once we clear it) prev.clear(); tmp = prev; prev = next; next = tmp; } int numSeq = StrictMath.min(numSequences, prev.size()); Sequence[] topSequences = new Sequence[numSeq]; for (int seqIndex = 0; seqIndex < numSeq; seqIndex++) { final SearchNode winner = prev.remove(); final String[] outs = new String[winner.size]; final double[] winnerProbs = new double[winner.size]; SearchNode node = winner; for (int j = winner.size - 1; j >= 0; j--) { outs[j] = node.outcome; winnerProbs[j] = node.prob; node = node.parent; } // Sequence.add accumulates score += StrictMath.log(p) per element, so rebuilding in // chain order yields a score bit-identical to the node's accumulated score. final Sequence seq = new Sequence(); for (int j = 0; j < outs.length; j++) { seq.add(outs[j], winnerProbs[j]); } topSequences[seqIndex] = seq; } return topSequences; } /** * Computes the best sequence of outcomes based on the {@link MaxentModel}. * * @param numSequences The number of sequences. * @param sequence The input {@link T} sequence. * @param additionalContext An {@link Object[]} of additional context. * This is passed to the context generator blindly with the * assumption that the context are appropriate. * @param cg The {@link BeamSearchContextGenerator context generator} to use. * @param validator The {@link SequenceValidator} to validate sequences. * * @return The top ranked {@link Sequence} of outcomes or {@code null} * if no sequence could be found. */ @Override public Sequence[] bestSequences(int numSequences, T[] sequence, Object[] additionalContext, BeamSearchContextGenerator cg, SequenceValidator validator) { return bestSequences(numSequences, sequence, additionalContext, zeroLog, cg, validator); } /** * Computes the best sequence of outcomes based on the {@link MaxentModel}. * * @param sequence The input {@link T} sequence. * @param additionalContext An {@link Object[]} of additional context. * This is passed to the context generator blindly with the * assumption that the context are appropriate. * @param cg The {@link BeamSearchContextGenerator context generator} to use. * @param validator The {@link SequenceValidator} to validate sequences. * * @return The top ranked {@link Sequence} of outcomes or {@code null} * if no sequence could be found. */ @Override public Sequence bestSequence(T[] sequence, Object[] additionalContext, BeamSearchContextGenerator cg, SequenceValidator validator) { Sequence[] sequences = bestSequences(1, sequence, additionalContext, cg, validator); if (sequences.length > 0) return sequences[0]; else return null; } @Override public String[] getOutcomes() { String[] outcomes = new String[model.getNumOutcomes()]; for (int i = 0; i < model.getNumOutcomes(); i++) { outcomes[i] = model.getOutcome(i); } return outcomes; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_EventModelSeq0100644 0000000 0000000 00000000157 15217274217 032447 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/EventModelSequenceTrainer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/EventModelSequenceTrainer.jav0100644 0000000 0000000 00000003130 15217274217 034076 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.io.IOException; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceStream; /** * A specialized {@link Trainer} that is based on a 'EventModelSequence' approach. * @param The generic type of elements to process via a {@link SequenceStream}. */ public interface EventModelSequenceTrainer extends Trainer { String SEQUENCE_VALUE = "EventModelSequence"; /** * Trains a {@link MaxentModel} for given {@link SequenceStream events}. * * @param events The input {@link SequenceStream events}. * * @return The trained {@link MaxentModel}. * @throws IOException Thrown if IO errors occurred. */ MaxentModel train(SequenceStream events) throws IOException; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/EventTrainer.java0100644 0000000 0000000 00000003550 15217274217 031573 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.io.IOException; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.ObjectStream; /** * A specialized {@link Trainer} that is based on an {@link Event} approach. */ public interface EventTrainer extends Trainer { String EVENT_VALUE = "Event"; /** * Trains a {@link MaxentModel} for given {@link ObjectStream events}. * * @param events The input {@link ObjectStream events}. * * @return The trained {@link MaxentModel}. * @throws IOException Thrown if IO errors occurred. */ MaxentModel train(ObjectStream events) throws IOException; /** * Trains a {@link MaxentModel} for given {@link ObjectStream events}. * * @param indexer The input {@link DataIndexer indexer} to use. * * @return The trained {@link MaxentModel}. * @throws IOException Thrown if IO errors occurred. */ MaxentModel train(DataIndexer indexer) throws IOException; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/Probabilistic.java0100644 0000000 0000000 00000002242 15217274217 031750 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; /** * A marker interface for classes with probabilistic capabilities. */ public interface Probabilistic { /** * Retrieves the probabilities of the last decoded sequence. * * @return An array with the same number of probabilities as tokens were sent to * the computational method when it was last called. */ double[] probs(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/SequenceTrainer.java0100644 0000000 0000000 00000003035 15217274217 032260 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.io.IOException; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.ml.model.SequenceStream; public interface SequenceTrainer extends Trainer { String SEQUENCE_VALUE = "Sequence"; /** * Trains a {@link SequenceClassificationModel} for given {@link SequenceStream events}. * * @param events The input {@link SequenceStream events}. * @param The generic type of elements to process via the {@link SequenceStream}. * * @return The trained {@link SequenceClassificationModel}. * @throws IOException Thrown if IO errors occurred. */ SequenceClassificationModel train(SequenceStream events) throws IOException; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/TrainerFactory.java0100644 0000000 0000000 00000025156 15217274217 032127 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml; import java.lang.reflect.Constructor; import java.util.Map; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.maxent.GISTrainer; import opennlp.tools.ml.maxent.quasinewton.QNTrainer; import opennlp.tools.ml.naivebayes.NaiveBayesTrainer; import opennlp.tools.ml.perceptron.PerceptronTrainer; import opennlp.tools.ml.perceptron.SimplePerceptronSequenceTrainer; import opennlp.tools.monitoring.DefaultTrainingProgressMonitor; import opennlp.tools.util.TrainingConfiguration; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.ext.ExtensionNotLoadedException; /** * A factory to initialize {@link Trainer} instances depending on a trainer type * configured via {@link TrainingParameters}. */ public class TrainerFactory { public enum TrainerType { EVENT_MODEL_TRAINER, EVENT_MODEL_SEQUENCE_TRAINER, SEQUENCE_TRAINER } // built-in trainers private static final Map> BUILTIN_TRAINERS; /* * Initialize the built-in trainers */ static { BUILTIN_TRAINERS = Map.of( GISTrainer.MAXENT_VALUE, GISTrainer.class, QNTrainer.MAXENT_QN_VALUE, QNTrainer.class, PerceptronTrainer.PERCEPTRON_VALUE, PerceptronTrainer.class, SimplePerceptronSequenceTrainer.PERCEPTRON_SEQUENCE_VALUE, SimplePerceptronSequenceTrainer.class, NaiveBayesTrainer.NAIVE_BAYES_VALUE, NaiveBayesTrainer.class); } /** * Determines the {@link TrainerType} based on the * {@link TrainingParameters#ALGORITHM_PARAM} value. * * @param trainParams - A mapping of {@link TrainingParameters training parameters}. * @return The {@link TrainerType} or {@code null} if the type couldn't be determined. */ public static TrainerType getTrainerType(TrainingParameters trainParams) { String algorithmValue = trainParams.getStringParameter(TrainingParameters.ALGORITHM_PARAM, null); // Check if it is defaulting to the MAXENT trainer if (algorithmValue == null) { return TrainerType.EVENT_MODEL_TRAINER; } Class trainerClass = BUILTIN_TRAINERS.get(algorithmValue); if (trainerClass != null) { if (EventTrainer.class.isAssignableFrom(trainerClass)) { return TrainerType.EVENT_MODEL_TRAINER; } else if (EventModelSequenceTrainer.class.isAssignableFrom(trainerClass)) { return TrainerType.EVENT_MODEL_SEQUENCE_TRAINER; } else if (SequenceTrainer.class.isAssignableFrom(trainerClass)) { return TrainerType.SEQUENCE_TRAINER; } } // Try to load the different trainers, and return the type on success try { ExtensionLoader.instantiateExtension(EventTrainer.class, algorithmValue); return TrainerType.EVENT_MODEL_TRAINER; } catch (ExtensionNotLoadedException ignored) { // this is ignored } try { ExtensionLoader.instantiateExtension(EventModelSequenceTrainer.class, algorithmValue); return TrainerType.EVENT_MODEL_SEQUENCE_TRAINER; } catch (ExtensionNotLoadedException ignored) { // this is ignored } try { ExtensionLoader.instantiateExtension(SequenceTrainer.class, algorithmValue); return TrainerType.SEQUENCE_TRAINER; } catch (ExtensionNotLoadedException ignored) { // this is ignored } return null; } /** * Retrieves a {@link SequenceTrainer} that fits the given parameters. * * @param trainParams The {@link TrainingParameters} to check for the trainer type. * Note: The entry {@link TrainingParameters#ALGORITHM_PARAM} is used * to determine the type. * @param reportMap A {@link Map} that shall be used during initialization of * the {@link SequenceTrainer}. * @return A valid {@link SequenceTrainer} for the configured {@code trainParams}. * @throws IllegalArgumentException Thrown if the trainer type could not be determined. */ public static SequenceTrainer getSequenceModelTrainer( TrainingParameters trainParams, Map reportMap) { String trainerType = trainParams.getStringParameter(TrainingParameters.ALGORITHM_PARAM, null); if (trainerType != null) { final SequenceTrainer trainer; if (BUILTIN_TRAINERS.containsKey(trainerType)) { trainer = TrainerFactory.createBuiltinTrainer(BUILTIN_TRAINERS.get(trainerType)); } else { trainer = ExtensionLoader.instantiateExtension(SequenceTrainer.class, trainerType); } trainer.init(trainParams, reportMap); return trainer; } else { throw new IllegalArgumentException("Trainer type couldn't be determined!"); } } /** * Retrieves an {@link EventModelSequenceTrainer} that fits the given parameters. * * @param trainParams The {@link TrainingParameters} to check for the trainer type. * Note: The entry {@link TrainingParameters#ALGORITHM_PARAM} is used * to determine the type. * @param reportMap A {@link Map} that shall be used during initialization of * the {@link EventModelSequenceTrainer}. * @return A valid {@link EventModelSequenceTrainer} for the configured {@code trainParams}. * @throws IllegalArgumentException Thrown if the trainer type could not be determined. */ public static EventModelSequenceTrainer getEventModelSequenceTrainer( TrainingParameters trainParams, Map reportMap) { String trainerType = trainParams.getStringParameter(TrainingParameters.ALGORITHM_PARAM, null); if (trainerType != null) { final EventModelSequenceTrainer trainer; if (BUILTIN_TRAINERS.containsKey(trainerType)) { trainer = TrainerFactory.createBuiltinTrainer(BUILTIN_TRAINERS.get(trainerType)); } else { trainer = ExtensionLoader.instantiateExtension(EventModelSequenceTrainer.class, trainerType); } trainer.init(trainParams, reportMap); return trainer; } else { throw new IllegalArgumentException("Trainer type couldn't be determined!"); } } /** * Works just like {@link TrainerFactory#getEventTrainer(TrainingParameters, Map, TrainingConfiguration)} * except that {@link TrainingConfiguration} is initialized with default values. */ public static EventTrainer getEventTrainer( TrainingParameters trainParams, Map reportMap) { TrainingConfiguration trainingConfiguration = new TrainingConfiguration(new DefaultTrainingProgressMonitor(), null); return getEventTrainer(trainParams, reportMap, trainingConfiguration); } /** * Retrieves an {@link EventTrainer} that fits the given parameters. * * @param trainParams The {@link TrainingParameters} to check for the trainer type. * Note: The entry {@link TrainingParameters#ALGORITHM_PARAM} is used * to determine the type. If the type is not defined, the * {@link GISTrainer#MAXENT_VALUE} will be used. * @param reportMap A {@link Map} that shall be used during initialization of * the {@link EventTrainer}. * @param config The {@link TrainingConfiguration} to be used. * @return A valid {@link EventTrainer} for the configured {@code trainParams}. */ public static EventTrainer getEventTrainer( TrainingParameters trainParams, Map reportMap, TrainingConfiguration config) { // if the trainerType is not defined -- use the GISTrainer. String trainerType = trainParams.getStringParameter( TrainingParameters.ALGORITHM_PARAM, GISTrainer.MAXENT_VALUE); final EventTrainer trainer; if (BUILTIN_TRAINERS.containsKey(trainerType)) { trainer = TrainerFactory.createBuiltinTrainer(BUILTIN_TRAINERS.get(trainerType)); } else { trainer = ExtensionLoader.instantiateExtension(EventTrainer.class, trainerType); } trainer.init(trainParams, reportMap, config); return trainer; } /** * @param trainParams The {@link TrainingParameters} to validate. Must not be {@code null}. * @return {@code true} if the {@code trainParams} could be validated, {@code false} otherwise. */ public static boolean isValid(TrainingParameters trainParams) { // TODO: Need to validate all parameters correctly ... error prone?! String algorithmName = trainParams.getStringParameter(TrainingParameters.ALGORITHM_PARAM, null); // If a trainer type can be determined, then the trainer is valid! if (algorithmName != null && !(BUILTIN_TRAINERS.containsKey(algorithmName) || getTrainerType(trainParams) != null)) { return false; } try { // require that the Cutoff and the number of iterations be an integer. // if they are not set, the default values will be ok. trainParams.getIntParameter(TrainingParameters.CUTOFF_PARAM, TrainingParameters.CUTOFF_DEFAULT_VALUE); trainParams.getIntParameter(TrainingParameters.ITERATIONS_PARAM, TrainingParameters.ITERATIONS_DEFAULT_VALUE); } catch (NumberFormatException e) { return false; } // no reason to require that the dataIndexer be a 1-pass or 2-pass data indexer. trainParams.getStringParameter(AbstractEventTrainer.DATA_INDEXER_PARAM, null); // TODO: Check data indexing ... return true; } @SuppressWarnings("unchecked") private static T createBuiltinTrainer(Class trainerClass) { Trainer theTrainer = null; if (trainerClass != null) { try { Constructor c = trainerClass.getConstructor(); theTrainer = c.newInstance(); } catch (Exception e) { String msg = "Could not instantiate the " + trainerClass.getCanonicalName() + ". The initialization threw an exception."; throw new IllegalArgumentException(msg, e); } } return (T) theTrainer; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/AllEnglishAffixes.txt0100644 0000000 0000000 00000004352 15217274217 033710 0ustar00rootroot0000000 0000000 -'s -able -acea -aceae -aceous -ad -ade -aemia -age -agogue -al -ales -algia -amine -an -ana -ance -ancy -and -androus -andry -ane -ant -ar -arch -archy -ard -arian -arium -art -ary -ase -asis -aster -ate -atic -ation -ative -ator -atory -bashing -biosis -blast -bodied -branch -cade -carp -carpic -carpous -cele -cene -centric -cephalic -cephalus -chore -chrome -chroous -cide -clase -cle -cline -colous -cracy -crat -cule -cy -cyst -cyte -decker -derm -diene -dom -drome -dromous -ean -ectomy -ed -ee -eer -eme -emia -en -ence -enchyma -ency -ene -ent -eous -er -ery -es -escent -ese -esque -ess -est -et -eth -ette -ey -facient -favoured -featured -fer -ferous -fic -fid -florous -fold -footed -form -free -fuge -ful -fy -gaited -gamy -gen -gene -genesis -genic -genous -geny -gerous -gnathous -gnosis -gon -gonium -gony -grade -gram -graph -grapher -graphy -gynous -haemia -haired -handed -hearted -hedron -hemia -hood -i -i- -ia -ial -ian -iana -iasis -iatrics -iatry -ible -ic -ical -ician -ics -id -idae -ide -ie -ier -ify -ile -in -inae -ine -ing -ion -ious -ise -ish -ism -ist -istic -ite -itis -itol -ity -ium -ive -ize -ji -kin -lalia -lashed -latry -lepsy -less -let -like -ling -lipped -lite -lith -lithic -lived -log -logue -logy -ly -lysis -lyte -lytic -mancy -mania -mantic -mas -masted -ment -mer -mere -merous -meter -metry -mo -morph -most -motored -mycete -n't -nasty -naut -ness -nik -nomy -o -o- -ock -ode -odont -oid -oidea -ol -ole -oma -ome -on -one -onym -opia -opsis -or -ory -ose -osis -otic -our -ous -parous -path -pathy -ped -pede -person -petal -phage -phagy -phane -phany -phasia -phile -philia -philous -phobe -phobia -phone -phony -phore -phoresis -phyll -phyllous -phyte -plasia -plasm -plast -plastic -plasty -plegia -ploid -pod -podium -podous -poiesis -pounder -prone -proof -pterous -rhoea -rigged -rrhagia -rrhoea -ry -s -s' -saur -scape -scope -scopy -sect -sepalous -shaped -ship -sided -some -sophy -sperm -sphere -sporous -st -stat -ster -stichous -stome -stomous -stomy -stress -tactic -taxis -taxy -termer -th -thermy -thymia -tion -to-be -tome -tomy -trix -tron -trope -trophy -tropic -tropism -tropous -tude -ty -type -ule -ulent -ure -uret -urgy -uria -ville -visaged -vorous -ward -wards -ways -wise -witted -y -yl -yne -zoa -zoon ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_BasicC0100644 0000000 0000000 00000000162 15217274217 032430 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/BasicContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/BasicContextGenerator.0100644 0000000 0000000 00000003151 15217274217 034051 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent; /** * A {@link ContextGenerator} implementation for maxent decisions, assuming that the input * given to the {@link #getContext(String)} method is a String containing contextual * predicates separated by spaces, for instance: *

* {@code cp_1 cp_2 ... cp_n} *

*/ public class BasicContextGenerator implements ContextGenerator { private String separator = " "; public BasicContextGenerator() {} /** * Initializes a {@link BasicContextGenerator} with a different separator char. * This overwrites the default whitespace separator. * * @param sep The {@link String separator character} to use. */ public BasicContextGenerator(String sep) { separator = sep; } @Override public String[] getContext(String o) { return o.split(separator); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/ContextGenerator.java0100644 0000000 0000000 00000002136 15217274217 033753 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent; /** * Represents a generator of contexts for maxent decisions. */ public interface ContextGenerator { /** * Builds up the list of contextual predicates given an {@link T object}. * * @param o The {@link T object} used as input. */ String[] getContext(T o); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/DataStream.java0100644 0000000 0000000 00000003050 15217274217 032501 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent; /** * An interface for objects which can deliver a stream of training data to be * supplied to an EventStream. It is not necessary to use a {@link DataStream} in a * Maxent application, but it can be used to support a wider variety of formats * in which your training data can be held. */ public interface DataStream { /** * Returns the next slice of data held in this {@link DataStream}. * * @return The Object representing the data which is next in this {@link DataStream}. */ Object nextToken(); /** * Test whether there are any events remaining in this {@link DataStream}. * * @return {@code true} if this {@link DataStream} has more data tokens, {@code false} otherwise. */ boolean hasNext(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/GISFormat0100644 0000000 0000000 00000002351 15217274217 031332 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Format for the GIS maxent info (.mei) files. GIS (model type identifier) 1. # of parameters (int) 2. the correction constant (int) 3. the correction constant parameter (double) 4. # of outcomes (int) * list of outcome names (String) 5. # of different types of outcome patterns (int) * list of (int int[]) [# of predicates for which outcome pattern is true] [outcome pattern] 6. # of predicates (int) * list of predicate names (String) apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/GISModel.java0100644 0000000 0000000 00000017617 15217274217 032075 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent; import java.util.Objects; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.EvalParameters; import opennlp.tools.ml.model.Prior; import opennlp.tools.ml.model.UniformPrior; /** * A maximum entropy model which has been trained using the Generalized * Iterative Scaling (GIS) procedure. * * @see AbstractModel */ public final class GISModel extends AbstractModel { /** * Initializes a {@link GISModel} with the specified parameters, outcome names, and * predicate/feature labels. * * @param params The {@link Context parameters} of the model. * @param predLabels The names of the predicates used in this model. * @param outcomeNames The names of the outcomes this model predicts. */ public GISModel(Context[] params, String[] predLabels, String[] outcomeNames) { this(params, predLabels, outcomeNames, new UniformPrior()); } /** * Initializes a {@link GISModel} with the specified parameters, outcome names, and * predicate/feature labels. * * @param params The {@link Context parameters} of the model. * @param predLabels The names of the predicates used in this model. * @param outcomeNames The names of the outcomes this model predicts. * @param prior The {@link Prior} to be used with this model. */ public GISModel(Context[] params, String[] predLabels, String[] outcomeNames, Prior prior) { super(params, predLabels, outcomeNames); this.prior = prior; prior.setLabels(outcomeNames, predLabels); modelType = ModelType.Maxent; } /** * Evaluates a context and return an array of the likelihood * of each outcome given that context. * * @param context * The names of the predicates which have been observed at the * present decision point. * @return The normalized probabilities for the outcomes given the context. * The indexes of the double[] are the outcome ids, and the actual * string representation of the outcomes can be obtained from the * method {@link #getOutcome(int)}. */ @Override public double[] eval(String[] context) { return (eval(context, new double[evalParams.getNumOutcomes()])); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, float[] values) { return (eval(context, values, new double[evalParams.getNumOutcomes()])); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, double[] outsums) { return eval(context, null, outsums); } /** * Evaluates a context and return an array of the likelihood * of each outcome given that context. * * @param context * The names of the predicates which have been observed at the * present decision point. * @param outsums * This is where the distribution is stored. * @return The normalized probabilities for the outcomes given the context. * The indexes of the double[] are the outcome ids, and the actual * string representation of the outcomes can be obtained from the * method {@link #getOutcome(int)}. */ public double[] eval(String[] context, float[] values, double[] outsums) { Context[] scontexts = new Context[context.length]; for (int i = 0; i < context.length; i++) { scontexts[i] = pmap.get(context[i]); } prior.logPrior(outsums, scontexts, values); return GISModel.eval(scontexts, values, outsums, evalParams); } /** * Evaluates a context and return an array of the likelihood * of each outcome given the specified context and the specified parameters. * * @param context * The integer values of the predicates which have been observed at * the present decision point. * @param prior * The prior distribution for the specified context. * @param model * The set of parameters used in this computation. * @return The normalized probabilities for the outcomes given the context. * The indexes of the double[] are the outcome ids, and the actual * string representation of the outcomes can be obtained from the * method {@link #getOutcome(int)}. */ public static double[] eval(int[] context, double[] prior, EvalParameters model) { return eval(context, null, prior, model); } /** * Evaluates a context and return an array of the likelihood * of each outcome given the specified context and the specified parameters. * * @param context * The integer values of the predicates which have been observed at * the present decision point. * @param values * The values for each of the parameters. * @param prior * The prior distribution for the specified context. * @param model * The set of parameters used in this computation. * @return The normalized probabilities for the outcomes given the context. * The indexes of the double[] are the outcome ids, and the actual * string representation of the outcomes can be obtained from the * method {@link #getOutcome(int)}. */ static double[] eval(int[] context, float[] values, double[] prior, EvalParameters model) { Context[] scontexts = new Context[context.length]; for (int i = 0; i < context.length; i++) { scontexts[i] = model.getParams()[context[i]]; } return GISModel.eval(scontexts, values, prior, model); } /** * Evaluates a context and return an array of the likelihood * of each outcome given the specified context and the specified parameters. * * @param context * The integer values of the predicates which have been observed at * the present decision point. * @param values * The values for each of the parameters. * @param prior * The prior distribution for the specified context. * @param model * The set of parameters used in this computation. * @return The normalized probabilities for the outcomes given the context. * The indexes of the double[] are the outcome ids, and the actual * string representation of the outcomes can be obtained from the * method {@link #getOutcome(int)}. */ static double[] eval(Context[] context, float[] values, double[] prior, EvalParameters model) { ArrayMath.sumFeatures(context, values, prior); double normal = 0.0; for (int oid = 0; oid < model.getNumOutcomes(); oid++) { prior[oid] = StrictMath.exp(prior[oid]); normal += prior[oid]; } for (int oid = 0; oid < model.getNumOutcomes(); oid++) { prior[oid] /= normal; } return prior; } @Override public int hashCode() { return super.hashCode(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof GISModel model) { return pmap.equals(model.pmap) && Objects.deepEquals(outcomeNames, model.outcomeNames) && Objects.equals(prior, model.prior); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/GISTrainer.java0100644 0000000 0000000 00000070670 15217274217 032437 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.AbstractEventTrainer; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.ml.model.EvalParameters; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.MutableContext; import opennlp.tools.ml.model.OnePassDataIndexer; import opennlp.tools.ml.model.Prior; import opennlp.tools.ml.model.UniformPrior; import opennlp.tools.monitoring.DefaultTrainingProgressMonitor; import opennlp.tools.monitoring.LogLikelihoodThresholdBreached; import opennlp.tools.monitoring.StopCriteria; import opennlp.tools.monitoring.TrainingMeasure; import opennlp.tools.monitoring.TrainingProgressMonitor; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingConfiguration; import opennlp.tools.util.TrainingParameters; /** * An implementation of Generalized Iterative Scaling (GIS). *

* The reference paper for this implementation was Adwait Ratnaparkhi's tech report at the * University of Pennsylvania's Institute for Research in Cognitive Science, * and is available at * ftp://ftp.cis.upenn.edu/pub/ircs/tr/97-08.ps.Z. *

* The slack parameter used in the above implementation has been removed by default * from the computation and a method for updating with Gaussian smoothing has been * added per Investigating GIS and Smoothing for Maximum Entropy Taggers, Clark and Curran (2002). * http://acl.ldc.upenn.edu/E/E03/E03-1071.pdf. *

* The slack parameter can be used by setting {@code useSlackParameter} to {@code true}. * Gaussian smoothing can be used by setting {@code useGaussianSmoothing} to {@code true}. *

* A {@link Prior} can be used to train models which converge to the distribution which minimizes the * relative entropy between the distribution specified by the empirical constraints of the training * data and the specified prior. By default, the uniform distribution is used as the prior. */ public class GISTrainer extends AbstractEventTrainer { private static final Logger logger = LoggerFactory.getLogger(GISTrainer.class); public static final String LOG_LIKELIHOOD_THRESHOLD_PARAM = "LLThreshold"; public static final double LOG_LIKELIHOOD_THRESHOLD_DEFAULT = 0.0001; private double llThreshold = 0.0001; /** * Specifies whether unseen context/outcome pairs should be estimated as occur very infrequently. */ private boolean useSimpleSmoothing = false; /** * Specified whether parameter updates should prefer a distribution of parameters which * is gaussian. */ private boolean useGaussianSmoothing = false; private double sigma = 2.0; // If we are using smoothing, this is used as the "number" of // times we want the trainer to imagine that it saw a feature that it // actually didn't see. Defaulted to 0.1. private double _smoothingObservation = 0.1; /** * Number of unique events which occurred in the event set. */ private int numUniqueEvents; /** * Number of predicates. */ private int numPreds; /** * Number of outcomes. */ private int numOutcomes; /** * Records the array of predicates seen in each event. */ private int[][] contexts; /** * The value associated with each context. If null then context values are assumes to be 1. */ private float[][] values; /** * List of outcomes for each event i, in context[i]. */ private int[] outcomeList; /** * Records the num of times an event has been seen for each event i, in context[i]. */ private int[] numTimesEventsSeen; /** * Stores the String names of the outcomes. The GIS only tracks outcomes as * ints, and so this array is needed to save the model to disk and thereby * allow users to know what the outcome was in human understandable terms. */ private String[] outcomeLabels; /** * Stores the String names of the predicates. The GIS only tracks predicates * as ints, and so this array is needed to save the model to disk and thereby * allow users to know what the outcome was in human understandable terms. */ private String[] predLabels; /** * Stores the observed expected values of the features based on training data. */ private MutableContext[] observedExpects; /** * Stores the estimated parameter value of each predicate during iteration */ private MutableContext[] params; /** * Stores the expected values of the features based on the current models */ private MutableContext[][] modelExpects; /** * This is the prior distribution that the model uses for training. */ private Prior prior; /** * Initial probability for all outcomes. */ private EvalParameters evalParams; public static final String MAXENT_VALUE = "MAXENT"; /** * If we are using smoothing, this is used as the "number" of times we want * the trainer to imagine that it saw a feature that it actually didn't see. * Defaulted to 0.1. */ private static final String SMOOTHING_PARAM = "Smoothing"; private static final boolean SMOOTHING_DEFAULT = false; private static final String SMOOTHING_OBSERVATION_PARAM = "SmoothingObservation"; private static final double SMOOTHING_OBSERVATION = 0.1; private static final String GAUSSIAN_SMOOTHING_PARAM = "GaussianSmoothing"; private static final boolean GAUSSIAN_SMOOTHING_DEFAULT = false; private static final String GAUSSIAN_SMOOTHING_SIGMA_PARAM = "GaussianSmoothingSigma"; private static final double GAUSSIAN_SMOOTHING_SIGMA_DEFAULT = 2.0; /** * Initializes a {@link GISTrainer}. *

* Note:
* The resulting instance does not print progress messages about training to STDOUT. */ public GISTrainer() { } /** * {@inheritDoc} */ @Override public boolean isSortAndMerge() { return true; } /** * {@inheritDoc} */ @Override public void init(TrainingParameters trainingParameters, Map reportMap) { super.init(trainingParameters, reportMap); llThreshold = trainingParameters.getDoubleParameter(LOG_LIKELIHOOD_THRESHOLD_PARAM, LOG_LIKELIHOOD_THRESHOLD_DEFAULT); useSimpleSmoothing = trainingParameters.getBooleanParameter(SMOOTHING_PARAM, SMOOTHING_DEFAULT); if (useSimpleSmoothing) { _smoothingObservation = trainingParameters.getDoubleParameter(SMOOTHING_OBSERVATION_PARAM, SMOOTHING_OBSERVATION); } useGaussianSmoothing = trainingParameters.getBooleanParameter(GAUSSIAN_SMOOTHING_PARAM, GAUSSIAN_SMOOTHING_DEFAULT); if (useGaussianSmoothing) { sigma = trainingParameters.getDoubleParameter( GAUSSIAN_SMOOTHING_SIGMA_PARAM, GAUSSIAN_SMOOTHING_SIGMA_DEFAULT); } if (useSimpleSmoothing && useGaussianSmoothing) throw new RuntimeException("Cannot set both Gaussian smoothing and Simple smoothing"); } /** * {@inheritDoc} */ @Override public MaxentModel doTrain(DataIndexer indexer) throws IOException { int iterations = getIterations(); int threads = trainingParameters.getIntParameter(TrainingParameters.THREADS_PARAM, 1); return trainModel(iterations, indexer, threads); } /** * Sets whether this trainer will use smoothing while training the model. *

* Note:
* This can improve model accuracy, though training will potentially take * longer and use more memory. Model size will also be larger. * * @param smooth {@code true} if smoothing is desired, {@code false} if not. */ public void setSmoothing(boolean smooth) { useSimpleSmoothing = smooth; } /** * Sets whether this trainer will use smoothing while training the model. *

* Note:
* This can improve model accuracy, though training will potentially take * longer and use more memory. Model size will also be larger. * * @param timesSeen The "number" of times we want the trainer to imagine * it saw a feature that it actually didn't see */ public void setSmoothingObservation(double timesSeen) { _smoothingObservation = timesSeen; } /** * Sets whether this trainer will use smoothing while training the model. *

* Note:
* This can improve model accuracy, though training will potentially take * longer and use more memory. Model size will also be larger. * * @param sigmaValue The Gaussian sigma value used for smoothing. */ public void setGaussianSigma(double sigmaValue) { useGaussianSmoothing = true; sigma = sigmaValue; } /** * Trains a model using the GIS algorithm, assuming 100 iterations and no * cutoff. * * @param eventStream The {@link ObjectStream eventStream} holding the data * on which this model will be trained. * * @return A trained {@link GISModel} which can be used immediately or saved to * disk using an {@link opennlp.tools.ml.maxent.io.GISModelWriter}. */ public GISModel trainModel(ObjectStream eventStream) throws IOException { return trainModel(eventStream, 100, 0); } /** * Trains a GIS model on the event in the specified event stream, using the specified number * of iterations and the specified count cutoff. * * @param eventStream A {@link ObjectStream stream} of all events. * @param iterations The number of iterations to use for GIS. * @param cutoff The number of times a feature must occur to be included. * * @return A trained {@link GISModel} which can be used immediately or saved to * disk using an {@link opennlp.tools.ml.maxent.io.GISModelWriter}. */ public GISModel trainModel(ObjectStream eventStream, int iterations, int cutoff) throws IOException { DataIndexer indexer = new OnePassDataIndexer(); TrainingParameters indexingParameters = new TrainingParameters(); indexingParameters.put(TrainingParameters.CUTOFF_PARAM, cutoff); indexingParameters.put(TrainingParameters.ITERATIONS_PARAM, iterations); Map reportMap = new HashMap<>(); indexer.init(indexingParameters, reportMap); indexer.index(eventStream); return trainModel(iterations, indexer); } /** * Trains a model using the GIS algorithm. * * @param iterations The number of GIS iterations to perform. * @param di The {@link DataIndexer} used to compress events in memory. * * @return A trained {@link GISModel} which can be used immediately or saved to * disk using an {@link opennlp.tools.ml.maxent.io.GISModelWriter}. * @throws IllegalArgumentException Thrown if parameters were invalid. */ public GISModel trainModel(int iterations, DataIndexer di) { return trainModel(iterations, di, new UniformPrior(), 1); } /** * Trains a model using the GIS algorithm. * * @param iterations The number of GIS iterations to perform. * @param di The {@link DataIndexer} used to compress events in memory. * @param threads The number of thread to train with. Must be greater than {@code 0}. * * @return A trained {@link GISModel} which can be used immediately or saved to * disk using an {@link opennlp.tools.ml.maxent.io.GISModelWriter}. * @throws IllegalArgumentException Thrown if parameters were invalid. */ public GISModel trainModel(int iterations, DataIndexer di, int threads) { return trainModel(iterations, di, new UniformPrior(), threads); } /** * Trains a model using the GIS algorithm. * * @param iterations The number of GIS iterations to perform. * @param di The {@link DataIndexer} used to compress events in memory. * @param modelPrior The {@link Prior} distribution used to train this model. * * @return A trained {@link GISModel} which can be used immediately or saved to * disk using an {@link opennlp.tools.ml.maxent.io.GISModelWriter}. * @throws IllegalArgumentException Thrown if parameters were invalid. */ public GISModel trainModel(int iterations, DataIndexer di, Prior modelPrior, int threads) { if (threads <= 0) { throw new IllegalArgumentException("threads must be at least one or greater but is " + threads + "!"); } modelExpects = new MutableContext[threads][]; /* Incorporate all of the needed info *****/ logger.info("Incorporating indexed data for training..."); contexts = di.getContexts(); values = di.getValues(); /* The number of times a predicate occurred in the training data. */ int[] predicateCounts = di.getPredCounts(); numTimesEventsSeen = di.getNumTimesEventsSeen(); numUniqueEvents = contexts.length; this.prior = modelPrior; //printTable(contexts); // determine the correction constant and its inverse double correctionConstant = 0; for (int ci = 0; ci < contexts.length; ci++) { if (values == null || values[ci] == null) { if (contexts[ci].length > correctionConstant) { correctionConstant = contexts[ci].length; } } else { float cl = values[ci][0]; for (int vi = 1; vi < values[ci].length; vi++) { cl += values[ci][vi]; } if (cl > correctionConstant) { correctionConstant = cl; } } } logger.info("done."); outcomeLabels = di.getOutcomeLabels(); outcomeList = di.getOutcomeList(); numOutcomes = outcomeLabels.length; predLabels = di.getPredLabels(); prior.setLabels(outcomeLabels, predLabels); numPreds = predLabels.length; logger.info("\tNumber of Event Tokens: {} " + "\n\t Number of Outcomes: {} " + "\n\t Number of Predicates: {}", numUniqueEvents, numOutcomes, numPreds); // set up feature arrays float[][] predCount = new float[numPreds][numOutcomes]; for (int ti = 0; ti < numUniqueEvents; ti++) { for (int j = 0; j < contexts[ti].length; j++) { if (values != null && values[ti] != null) { predCount[contexts[ti][j]][outcomeList[ti]] += numTimesEventsSeen[ti] * values[ti][j]; } else { predCount[contexts[ti][j]][outcomeList[ti]] += numTimesEventsSeen[ti]; } } } // A fake "observation" to cover features which are not detected in // the data. The default is to assume that we observed "1/10th" of a // feature during training. final double smoothingObservation = _smoothingObservation; // Get the observed expectations of the features. Strictly speaking, // we should divide the counts by the number of Tokens, but because of // the way the model's expectations are approximated in the // implementation, this is cancelled out when we compute the next // iteration of a parameter, making the extra divisions wasteful. params = new MutableContext[numPreds]; for (int i = 0; i < modelExpects.length; i++) { modelExpects[i] = new MutableContext[numPreds]; } observedExpects = new MutableContext[numPreds]; // The model does need the correction constant and the correction feature. The correction constant // is only needed during training, and the correction feature is not necessary. // For compatibility reasons the model contains form now on a correction constant of 1, // and a correction param 0. evalParams = new EvalParameters(params, numOutcomes); int[] activeOutcomes = new int[numOutcomes]; int[] outcomePattern; int[] allOutcomesPattern = new int[numOutcomes]; for (int oi = 0; oi < numOutcomes; oi++) { allOutcomesPattern[oi] = oi; } int numActiveOutcomes; for (int pi = 0; pi < numPreds; pi++) { numActiveOutcomes = 0; if (useSimpleSmoothing) { numActiveOutcomes = numOutcomes; outcomePattern = allOutcomesPattern; } else { //determine active outcomes for (int oi = 0; oi < numOutcomes; oi++) { if (predCount[pi][oi] > 0) { activeOutcomes[numActiveOutcomes] = oi; numActiveOutcomes++; } } if (numActiveOutcomes == numOutcomes) { outcomePattern = allOutcomesPattern; } else { outcomePattern = new int[numActiveOutcomes]; System.arraycopy(activeOutcomes, 0, outcomePattern, 0, numActiveOutcomes); } } params[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); for (int i = 0; i < modelExpects.length; i++) { modelExpects[i][pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); } observedExpects[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); for (int aoi = 0; aoi < numActiveOutcomes; aoi++) { int oi = outcomePattern[aoi]; params[pi].setParameter(aoi, 0.0); for (MutableContext[] modelExpect : modelExpects) { modelExpect[pi].setParameter(aoi, 0.0); } if (predCount[pi][oi] > 0) { observedExpects[pi].setParameter(aoi, predCount[pi][oi]); } else if (useSimpleSmoothing) { observedExpects[pi].setParameter(aoi, smoothingObservation); } } } logger.info("...done."); /* Find the parameters *****/ if (threads == 1) { logger.info("Computing model parameters ..."); } else { logger.info("Computing model parameters in {} threads...", threads); } findParameters(iterations, correctionConstant); // Create and return the model return new GISModel(params, predLabels, outcomeLabels); } /* Estimate and return the model parameters. */ private void findParameters(int iterations, double correctionConstant) { int threads = modelExpects.length; ExecutorService executor = Executors.newFixedThreadPool(threads, runnable -> { Thread thread = new Thread(runnable); thread.setName("opennlp.tools.ml.maxent.ModelExpectationComputeTask.nextIteration()"); thread.setDaemon(true); return thread; }); CompletionService completionService = new ExecutorCompletionService<>(executor); double prevLL = 0.0; double currLL; //Get the Training Progress Monitor and the StopCriteria. TrainingProgressMonitor progressMonitor = getTrainingProgressMonitor(trainingConfiguration); StopCriteria stopCriteria = getStopCriteria(trainingConfiguration); logger.info("Performing {} iterations.", iterations); for (int i = 1; i <= iterations; i++) { currLL = nextIteration(correctionConstant, completionService, i); if (i > 1) { if (prevLL > currLL) { logger.warn("Model Diverging: loglikelihood decreased"); break; } if (stopCriteria.test(currLL - prevLL)) { progressMonitor.finishedTraining(iterations, stopCriteria); break; } } prevLL = currLL; } //At this point, all iterations have finished successfully. if (!progressMonitor.isTrainingFinished()) { progressMonitor.finishedTraining(iterations, null); } progressMonitor.display(true); // kill a bunch of these big objects now that we don't need them observedExpects = null; modelExpects = null; numTimesEventsSeen = null; contexts = null; executor.shutdown(); } //modeled on implementation in Zhang Le's maxent kit private double gaussianUpdate(int predicate, int oid, double correctionConstant) { double param = params[predicate].getParameters()[oid]; double x0 = 0.0; double modelValue = modelExpects[0][predicate].getParameters()[oid]; double observedValue = observedExpects[predicate].getParameters()[oid]; for (int i = 0; i < 50; i++) { double tmp = modelValue * StrictMath.exp(correctionConstant * x0); double f = tmp + (param + x0) / sigma - observedValue; double fp = tmp * correctionConstant + 1 / sigma; if (fp == 0) { break; } double x = x0 - f / fp; if (StrictMath.abs(x - x0) < 0.000001) { x0 = x; break; } x0 = x; } return x0; } /* Compute one iteration of GIS and return log-likelihood.*/ private double nextIteration(double correctionConstant, CompletionService completionService, int iteration) { // compute contribution of p(a|b_i) for each feature and the new // correction parameter double loglikelihood = 0.0; int numEvents = 0; int numCorrect = 0; // Each thread gets equal number of tasks, if the number of tasks // is not divisible by the number of threads, the first "leftOver" // threads have one extra task. int numberOfThreads = modelExpects.length; int taskSize = numUniqueEvents / numberOfThreads; int leftOver = numUniqueEvents % numberOfThreads; // submit all tasks to the completion service. for (int i = 0; i < numberOfThreads; i++) { if (i < leftOver) { completionService.submit(new ModelExpectationComputeTask(i, i * taskSize + i, taskSize + 1)); } else { completionService.submit(new ModelExpectationComputeTask(i, i * taskSize + leftOver, taskSize)); } } for (int i = 0; i < numberOfThreads; i++) { ModelExpectationComputeTask finishedTask; try { finishedTask = completionService.take().get(); } catch (InterruptedException e) { // TODO: We got interrupted, but that is currently not really supported! // For now we fail hard. We hopefully soon // handle this case properly! throw new IllegalStateException("Interruption is not supported!", e); } catch (ExecutionException e) { // Only runtime exception can be thrown during training, if one was thrown // it should be re-thrown. That could for example be a NullPointerException // which is caused through a bug in our implementation. throw new RuntimeException("Exception during training: " + e.getMessage(), e); } // When they are done, retrieve the results ... numEvents += finishedTask.getNumEvents(); numCorrect += finishedTask.getNumCorrect(); loglikelihood += finishedTask.getLoglikelihood(); } // merge the results of the two computations for (int pi = 0; pi < numPreds; pi++) { int[] activeOutcomes = params[pi].getOutcomes(); for (int aoi = 0; aoi < activeOutcomes.length; aoi++) { for (int i = 1; i < modelExpects.length; i++) { modelExpects[0][pi].updateParameter(aoi, modelExpects[i][pi].getParameters()[aoi]); } } } // compute the new parameter values for (int pi = 0; pi < numPreds; pi++) { double[] observed = observedExpects[pi].getParameters(); double[] model = modelExpects[0][pi].getParameters(); int[] activeOutcomes = params[pi].getOutcomes(); for (int aoi = 0; aoi < activeOutcomes.length; aoi++) { if (useGaussianSmoothing) { params[pi].updateParameter(aoi, gaussianUpdate(pi, aoi, correctionConstant)); } else { if (model[aoi] == 0) { logger.warn("Model expects == 0 for {} {}", predLabels[pi], outcomeLabels[aoi]); } //params[pi].updateParameter(aoi,(StrictMath.log(observed[aoi]) - StrictMath.log(model[aoi]))); params[pi].updateParameter(aoi, ((StrictMath.log(observed[aoi]) - StrictMath.log(model[aoi])) / correctionConstant)); } for (MutableContext[] modelExpect : modelExpects) { modelExpect[pi].setParameter(aoi, 0.0); // re-initialize to 0.0's } } } getTrainingProgressMonitor(trainingConfiguration). finishedIteration(iteration, numCorrect, numEvents, TrainingMeasure.LOG_LIKELIHOOD, loglikelihood); return loglikelihood; } private class ModelExpectationComputeTask implements Callable { private final int startIndex; private final int length; final private int threadIndex; private double loglikelihood = 0; private int numEvents = 0; private int numCorrect = 0; // startIndex to compute, number of events to compute ModelExpectationComputeTask(int threadIndex, int startIndex, int length) { this.startIndex = startIndex; this.length = length; this.threadIndex = threadIndex; } public ModelExpectationComputeTask call() { final double[] modelDistribution = new double[numOutcomes]; for (int ei = startIndex; ei < startIndex + length; ei++) { // TODO: check interruption status here, if interrupted set a poisoned flag and return if (values != null) { prior.logPrior(modelDistribution, contexts[ei], values[ei]); GISModel.eval(contexts[ei], values[ei], modelDistribution, evalParams); } else { prior.logPrior(modelDistribution, contexts[ei]); GISModel.eval(contexts[ei], modelDistribution, evalParams); } for (int j = 0; j < contexts[ei].length; j++) { int pi = contexts[ei][j]; int[] activeOutcomes = modelExpects[threadIndex][pi].getOutcomes(); for (int aoi = 0; aoi < activeOutcomes.length; aoi++) { int oi = activeOutcomes[aoi]; // numTimesEventsSeen must also be thread safe if (values != null && values[ei] != null) { modelExpects[threadIndex][pi].updateParameter(aoi, modelDistribution[oi] * values[ei][j] * numTimesEventsSeen[ei]); } else { modelExpects[threadIndex][pi].updateParameter(aoi, modelDistribution[oi] * numTimesEventsSeen[ei]); } } } loglikelihood += StrictMath.log(modelDistribution[outcomeList[ei]]) * numTimesEventsSeen[ei]; numEvents += numTimesEventsSeen[ei]; int max = ArrayMath.argmax(modelDistribution); if (max == outcomeList[ei]) { numCorrect += numTimesEventsSeen[ei]; } } return this; } synchronized int getNumEvents() { return numEvents; } synchronized int getNumCorrect() { return numCorrect; } synchronized double getLoglikelihood() { return loglikelihood; } } /** * Get the {@link StopCriteria} associated with this {@link Trainer}. * * @param trainingConfig {@link TrainingConfiguration} * @return {@link StopCriteria}. If {@link TrainingConfiguration} is {@code null} or * {@link TrainingConfiguration#stopCriteria()} is {@code null}, * then return the default {@link StopCriteria}. */ private StopCriteria getStopCriteria(TrainingConfiguration trainingConfig) { return trainingConfig != null && trainingConfig.stopCriteria() != null ? trainingConfig.stopCriteria() : new LogLikelihoodThresholdBreached(trainingParameters); } /** * Get the {@link TrainingProgressMonitor} associated with this {@link Trainer}. * * @param trainingConfig {@link TrainingConfiguration}. * @return {@link TrainingProgressMonitor}. If {@link TrainingConfiguration} is {@code null} or * {@link TrainingConfiguration#progMon()} is {@code null}, * then return the default {@link TrainingProgressMonitor}. */ private TrainingProgressMonitor getTrainingProgressMonitor(TrainingConfiguration trainingConfig) { return trainingConfig != null && trainingConfig.progMon() != null ? trainingConfig.progMon() : new DefaultTrainingProgressMonitor(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_RealBa0100644 0000000 0000000 00000000161 15217274217 032431 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/RealBasicEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/RealBasicEventStream.j0100644 0000000 0000000 00000004326 15217274217 033776 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent; import java.io.IOException; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.RealValueFileEventStream; import opennlp.tools.util.ObjectStream; /** * Class for real-valued {@link Event events} as an * {@link ObjectStream event stream}. * . * @see Event * @see ObjectStream */ public class RealBasicEventStream implements ObjectStream { private final ObjectStream ds; public RealBasicEventStream(ObjectStream ds) { this.ds = ds; } /** * {@inheritDoc} * * @throws IOException Thrown if there is an error during reading. * @throws RuntimeException Thrown if negative real values are detected in the input data. */ @Override public Event read() throws IOException { String eventString = ds.read(); if (eventString != null) { return createEvent(eventString); } return null; } private Event createEvent(String obs) { int si = obs.indexOf(' '); if (si == -1) return null; else { String outcome = obs.substring(0, si); String[] contexts = obs.substring(si + 1).split("\\s+"); float[] values = RealValueFileEventStream.parseContexts(contexts); return new Event(outcome,contexts,values); } } @Override public void reset() throws IOException, UnsupportedOperationException { ds.reset(); } @Override public void close() throws IOException { ds.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_io_Bin0100644 0000000 0000000 00000000164 15217274217 032505 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryGISModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryGISModelReade0100644 0000000 0000000 00000002626 15217274217 033664 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.DataInputStream; import opennlp.tools.ml.model.BinaryFileDataReader; /** * A {@link GISModelReader} that reads models from a binary format. */ public class BinaryGISModelReader extends GISModelReader { /** * Instantiates {@link BinaryGISModelReader} via a {@link DataInputStream} * containing the model contents. * * @param dis The {@link DataInputStream} containing the model information. * It must be open and have bytes available. */ public BinaryGISModelReader(DataInputStream dis) { super(new BinaryFileDataReader(dis)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_io_Bin0100644 0000000 0000000 00000000164 15217274217 032505 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryGISModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryGISModelWrite0100644 0000000 0000000 00000006204 15217274217 033732 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.ModelParameterChunker; /** * A {@link GISModelWriter} that writes models in a binary format. * * @see opennlp.tools.ml.maxent.GISModel */ public class BinaryGISModelWriter extends GISModelWriter { private final DataOutputStream output; /** * Instantiates {@link BinaryGISModelWriter} via an * {@link AbstractModel GIS model} and a {@link File}. *

* Prepares writing of a {@code model} to the file. * Based on whether the file's suffix contains {@code .gz}, it detects whether * the file is gzipped or not. * * @param model The {@link AbstractModel GIS model} which is to be persisted. * @param f The {@link File} in which the model is to be persisted. * * @throws IOException Thrown if IO errors occurred. * @see opennlp.tools.ml.maxent.GISModel */ public BinaryGISModelWriter(AbstractModel model, File f) throws IOException { super(model); if (f.getName().endsWith(".gz")) { output = new DataOutputStream(new GZIPOutputStream( new FileOutputStream(f))); } else { output = new DataOutputStream(new FileOutputStream(f)); } } /** * Instantiates {@link BinaryGISModelWriter} via * an {@link AbstractModel GIS model} and a {@link DataOutputStream}. * * @param model The {@link AbstractModel GIS model} which is to be persisted. * @param dos The {@link DataOutputStream} which is used to persist the {@code model}. * The {@code dos} must be opened. */ public BinaryGISModelWriter(AbstractModel model, DataOutputStream dos) { super(model); output = dos; } /** * {@inheritDoc} */ @Override public void writeUTF(String s) throws java.io.IOException { ModelParameterChunker.writeUTF(output, s); } /** * {@inheritDoc} */ @Override public void writeInt(int i) throws java.io.IOException { output.writeInt(i); } /** * {@inheritDoc} */ @Override public void writeDouble(double d) throws java.io.IOException { output.writeDouble(d); } @Override public void close() throws java.io.IOException { output.flush(); output.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_io_Bin0100644 0000000 0000000 00000000163 15217274217 032504 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryQNModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryQNModelReader0100644 0000000 0000000 00000002617 15217274217 033742 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.DataInputStream; import opennlp.tools.ml.model.BinaryFileDataReader; /** * A {@link QNModelReader} that reads models from a binary format. */ public class BinaryQNModelReader extends QNModelReader { /** * Instantiates {@link BinaryQNModelReader} via a {@link DataInputStream} * containing the model contents. * * @param dis The {@link DataInputStream} containing the model information. * It must be open and have bytes available. */ public BinaryQNModelReader(DataInputStream dis) { super(new BinaryFileDataReader(dis)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_io_Bin0100644 0000000 0000000 00000000163 15217274217 032504 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryQNModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/BinaryQNModelWriter0100644 0000000 0000000 00000006263 15217274217 034015 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.ModelParameterChunker; /** * A {@link QNModelWriter} that writes models in a binary format. * * @see opennlp.tools.ml.maxent.quasinewton.QNModel */ public class BinaryQNModelWriter extends QNModelWriter { protected DataOutputStream output; /** * Instantiates {@link BinaryQNModelWriter} via an * {@link AbstractModel QN model} and a {@link File}. *

* Prepares writing of a {@code model} to the file. * Based on whether the file's suffix contains {@code .gz}, it detects whether * the file is gzipped or not. * * @param model The {@link AbstractModel QN model} which is to be persisted. * @param f The {@link File} in which the model is to be persisted. * * @throws IOException Thrown if IO errors occurred. * @see opennlp.tools.ml.maxent.quasinewton.QNModel */ public BinaryQNModelWriter(AbstractModel model, File f) throws IOException { super(model); if (f.getName().endsWith(".gz")) { output = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(f))); } else { output = new DataOutputStream(new FileOutputStream(f)); } } /** * Instantiates {@link BinaryQNModelWriter} via * an {@link AbstractModel QN model} and a {@link DataOutputStream}. * * @param model The {@link AbstractModel QN model} which is to be persisted. * @param dos The {@link DataOutputStream} which is used to persist the {@code model}. * The {@code dos} must be opened. * @see opennlp.tools.ml.maxent.quasinewton.QNModel */ public BinaryQNModelWriter(AbstractModel model, DataOutputStream dos) { super(model); output = dos; } /** * {@inheritDoc} */ @Override public void writeUTF(String s) throws IOException { ModelParameterChunker.writeUTF(output, s); } /** * {@inheritDoc} */ @Override public void writeInt(int i) throws IOException { output.writeInt(i); } /** * {@inheritDoc} */ @Override public void writeDouble(double d) throws IOException { output.writeDouble(d); } /** * {@inheritDoc} */ @Override public void close() throws IOException { output.flush(); output.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_io_GIS0100644 0000000 0000000 00000000156 15217274217 032420 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/GISModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/GISModelReader.java0100644 0000000 0000000 00000007237 15217274217 033624 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.maxent.GISModel; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.AbstractModelReader; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.DataReader; /** * The base class for readers of {@link GISModel GIS models}. *

* Format for the GIS maxent info (.mei) files: *

*
GIS (model type identifier) *
1. # of parameters ({@code int}) *
2. the correction constant ({@code int}) *
3. the correction constant parameter ({@code double}) *
4. # of outcomes ({@code int}) *
* list of outcome names ({@code String}) *
5. # of different types of outcome patterns ({@code int}) *
* list of ({@code int} {@code int[]}) *
[# of predicates for which outcome pattern is true] [outcome pattern] *
6. # of predicates ({@code int}) *
* list of predicate names ({@code String}) * * @see GISModel * @see AbstractModelReader */ public class GISModelReader extends AbstractModelReader { private static final Logger logger = LoggerFactory.getLogger(GISModelReader.class); /** * Initializes a {@link GISModelReader} via a {@link File}. * * @param file The {@link File} that references the model to be read. * * @throws IOException Thrown if IO errors occurred. */ public GISModelReader(File file) throws IOException { super(file); } /** * Initializes a {@link GISModelReader} via a {@link DataReader}. * * @param dataReader The {@link DataReader} that references the model to be read. */ public GISModelReader(DataReader dataReader) { super(dataReader); } /** * Retrieves a model from disk. * *

* If you are creating a reader for a format which won't work with this * (perhaps a database or xml file), override this method and ignore the other * methods provided in this abstract class. * * @return The {@link GISModel} stored in the format and location specified to this * {@link GISModelReader} (usually via its constructor). */ @Override public AbstractModel constructModel() throws IOException { // read correction constant (not used anymore) readInt(); // read correction params (not used anymore) readDouble(); String[] outcomeLabels = getOutcomes(); int[][] outcomePatterns = getOutcomePatterns(); String[] predLabels = getPredicates(); Context[] params = getParameters(outcomePatterns); return new GISModel(params, predLabels, outcomeLabels); } @Override public void checkModelType() throws java.io.IOException { String modelType = readUTF(); if (!modelType.equals("GIS")) logger.error("Attempting to load a {}" + " model as a GIS model. You should expect problems.", modelType); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_io_GIS0100644 0000000 0000000 00000000156 15217274217 032420 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/GISModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/GISModelWriter.java0100644 0000000 0000000 00000011632 15217274217 033670 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; import opennlp.tools.ml.AbstractMLModelWriter; import opennlp.tools.ml.maxent.GISModel; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.AbstractModelWriter; import opennlp.tools.ml.model.ComparablePredicate; import opennlp.tools.ml.model.Context; /** * The base class for writers of {@link GISModel GIS models}. *

* It provides the {@link #persist()} method which takes care of the structure of a * stored document, and requires an extending class to define precisely how * the data should be stored. * * @see GISModel * @see AbstractModelWriter * @see AbstractMLModelWriter */ public abstract class GISModelWriter extends AbstractMLModelWriter { /** * Initializes a {@link GISModelWriter} for a {@link AbstractModel GIS model}. * * @param model The {@link AbstractModel GIS model} to be written. */ public GISModelWriter(AbstractModel model) { Object[] data = model.getDataStructures(); @SuppressWarnings("unchecked") Map pmap = (Map) data[1]; OUTCOME_LABELS = (String[]) data[2]; PARAMS = new Context[pmap.size()]; PRED_LABELS = new String[pmap.size()]; int i = 0; for (Map.Entry pred : pmap.entrySet()) { PRED_LABELS[i] = pred.getKey(); PARAMS[i] = pred.getValue(); i++; } } /** * {@inheritDoc} */ @Override protected ComparablePredicate[] sortValues() { ComparablePredicate[] sortPreds = new ComparablePredicate[PARAMS.length]; int numParams = 0; for (int pid = 0; pid < PARAMS.length; pid++) { int[] predkeys = PARAMS[pid].getOutcomes(); // Arrays.sort(predkeys); int numActive = predkeys.length; double[] activeParams = PARAMS[pid].getParameters(); numParams += numActive; /* * double[] activeParams = new double[numActive]; * * int id = 0; for (int i=0; i < predkeys.length; i++) { int oid = * predkeys[i]; activeOutcomes[id] = oid; activeParams[id] = * PARAMS[pid].getParams(oid); id++; } */ sortPreds[pid] = new ComparablePredicate(PRED_LABELS[pid], predkeys, activeParams); } Arrays.sort(sortPreds); return sortPreds; } /** * Writes the {@link AbstractModel GIS model}, using the * {@link #writeUTF(String)}, {@link #writeDouble(double)}, or {@link #writeInt(int)}} * methods implemented by extending classes. * *

If you wish to create a {@link GISModelWriter} which uses a different * structure, it will be necessary to override the {@link #persist()} method in * addition to implementing the {@code writeX(..)} methods. * * @throws IOException Thrown if IO errors occurred. */ @Override public void persist() throws IOException { // the type of model (GIS) writeUTF("GIS"); // the value of the correction constant (not used anymore) writeInt(1); // the value of the correction params (not used anymore) writeDouble(1); // the mapping from outcomes to their integer indexes writeInt(OUTCOME_LABELS.length); for (String OUTCOME_LABEL : OUTCOME_LABELS) { writeUTF(OUTCOME_LABEL); } // the mapping from predicates to the outcomes they contributed to. // The sorting is done so that we actually can write this out more // compactly than as the entire list. ComparablePredicate[] sorted = sortValues(); List> compressed = compressOutcomes(sorted); writeInt(compressed.size()); for (List aCompressed : compressed) { writeUTF(aCompressed.size() + ((List) aCompressed).get(0).toString()); } // the mapping from predicate names to their integer indexes writeInt(PARAMS.length); for (ComparablePredicate aSorted : sorted) { writeUTF(aSorted.name); } // write out the parameters for (ComparablePredicate aSorted : sorted) { for (int j = 0; j < aSorted.params.length; j++) { writeDouble(aSorted.params[j]); } } close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/QNModelReader.java0100644 0000000 0000000 00000005472 15217274217 033517 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.maxent.quasinewton.QNModel; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.DataReader; /** * The base class for readers of {@link QNModel QN models}. * * @see QNModel * @see GISModelReader */ public class QNModelReader extends GISModelReader { private static final Logger logger = LoggerFactory.getLogger(QNModelReader.class); /** * Initializes a {@link QNModelReader} via a {@link DataReader}. * * @param dataReader The {@link DataReader} that references the model to be read. */ public QNModelReader(DataReader dataReader) { super(dataReader); } /** * Initializes a {@link QNModelReader} via a {@link File}. * * @param file The {@link File} that references the model to be read. * * @throws IOException Thrown if IO errors occurred. */ public QNModelReader(File file) throws IOException { super(file); } @Override public void checkModelType() throws IOException { String modelType = readUTF(); if (!modelType.equals("QN")) logger.error("Attempting to load a {}" + " model as a MAXENT_QN model. You should expect problems.", modelType); } /** * Retrieves a model from disk. * *

* If you are creating a reader for a format which won't work with this * (perhaps a database or xml file), override this method and ignore the other * methods provided in this abstract class. * * @return The {@link QNModel} stored in the format and location specified to this * {@link QNModelReader} (usually via its constructor). */ @Override public QNModel constructModel() throws IOException { String[] outcomeLabels = getOutcomes(); int[][] outcomePatterns = getOutcomePatterns(); String[] predLabels = getPredicates(); Context[] params = getParameters(outcomePatterns); return new QNModel(params, predLabels, outcomeLabels); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/QNModelWriter.java0100644 0000000 0000000 00000005756 15217274217 033576 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.io; import java.io.IOException; import java.util.List; import opennlp.tools.ml.maxent.quasinewton.QNModel; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.ComparablePredicate; /** * The base class for writers of {@link QNModel models}. *

* It provides the {@link #persist()} method which takes care of the structure of a * stored document, and requires an extending class to define precisely how * the data should be stored. */ public abstract class QNModelWriter extends GISModelWriter { public QNModelWriter(AbstractModel model) { super(model); } /** * Writes the {@link AbstractModel QN model}, using the * {@link #writeUTF(String)}, {@link #writeDouble(double)}, or {@link #writeInt(int)}} * methods implemented by extending classes. * *

If you wish to create a {@link QNModelWriter} which uses a different * structure, it will be necessary to override the {@code #persist()} method in * addition to implementing the {@code writeX(..)} methods. * * @throws IOException Thrown if IO errors occurred. */ @Override public void persist() throws IOException { // the type of model (QN) writeUTF("QN"); // the mapping from outcomes to their integer indexes writeInt(OUTCOME_LABELS.length); for (String outcomeLabel : OUTCOME_LABELS) writeUTF(outcomeLabel); // the mapping from predicates to the outcomes they contributed to. // The sorting is done so that we actually can write this out more // compactly than as the entire list. ComparablePredicate[] sorted = sortValues(); List> compressed = compressOutcomes(sorted); writeInt(compressed.size()); for (List a : compressed) { writeUTF(a.size() + a.get(0).toString()); } // the mapping from predicate names to their integer indexes writeInt(PARAMS.length); for (ComparablePredicate predicate : sorted) writeUTF(predicate.name); // write out the parameters for (ComparablePredicate comparablePredicate : sorted) for (int j = 0; j < comparablePredicate.params.length; j++) writeDouble(comparablePredicate.params[j]); close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/package-info.java0100644 0000000 0000000 00000001714 15217274217 033414 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to the I/O functionality of the maxent package including reading * and writing models in several formats. */ package opennlp.tools.ml.maxent.io; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/io/package.html0100644 0000000 0000000 00000002032 15217274217 032500 0ustar00rootroot0000000 0000000 Provides the I/O functionality of the maxent package including reading and writing models in several formats. apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/package-info.java0100644 0000000 0000000 00000001624 15217274217 033005 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to ML by means of the Maximum Entropy (ME) algorithm. */ package opennlp.tools.ml.maxent; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/package.html0100644 0000000 0000000 00000002041 15217274217 032071 0ustar00rootroot0000000 0000000 Provides main functionality of the maxent package including data structures and algorithms for parameter estimation. ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000161 15217274217 032603 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/Function.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/Function.j0100644 0000000 0000000 00000003314 15217274217 034131 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.quasinewton; /** * Interface for a function. */ public interface Function { /** * @return Retrieves the dimension value. */ int getDimension(); /** * Computes the function value for {@code x}. * * @param x The input vector. * @return Returns the computed value for {@code x}. * * @apiNote The parameter {@code x} should be validated and if inconsistencies are encountered * an appropriate exception should be raised, e.g. {@link IllegalArgumentException}. */ double valueAt(double[] x); /** * Computes the gradient for {@code x}. * * @param x The input vector. * @return Returns the computed gradient for {@code x}. * * @apiNote The parameter {@code x} should be validated and if inconsistencies are encountered * an appropriate exception should be raised, e.g. {@link IllegalArgumentException}. */ double[] gradientAt(double[] x); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000163 15217274217 032605 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/LineSearch.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/LineSearch0100644 0000000 0000000 00000030562 15217274217 034136 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.quasinewton; import opennlp.tools.ml.ArrayMath; /** * Performs line search to find a minimum. * * @see * Nocedal & Wright 2006, Numerical Optimization, p. 37) */ public class LineSearch { private static final double C = 0.0001; private static final double RHO = 0.5; // decrease of step size (must be from 0 to 1) /** * Conducts a backtracking line search. * * @param function The {@link Function} to apply. * @param direction The {@code double[]} representing the direction to search into. * @param lsr The {@link LineSearchResult} to transport results in. * @param initialStepSize The initial step size to apply. Must be greater than {@code 0}. */ public static void doLineSearch(Function function, double[] direction, LineSearchResult lsr, double initialStepSize) { double stepSize = initialStepSize; int currFctEvalCount = lsr.getFctEvalCount(); double[] x = lsr.getNextPoint(); double[] gradAtX = lsr.getGradAtNext(); double valueAtX = lsr.getValueAtNext(); int dimension = x.length; // Retrieve current points and gradient for array reuse purpose double[] nextPoint = lsr.getCurrPoint(); double[] gradAtNextPoint = lsr.getGradAtCurr(); double valueAtNextPoint; double dirGradientAtX = ArrayMath.innerProduct(direction, gradAtX); // To avoid recomputing in the loop double cachedProd = C * dirGradientAtX; while (true) { // Get next point for (int i = 0; i < dimension; i++) { nextPoint[i] = x[i] + direction[i] * stepSize; } // New value valueAtNextPoint = function.valueAt(nextPoint); currFctEvalCount++; // Check Armijo condition if (valueAtNextPoint <= valueAtX + cachedProd * stepSize) break; // Shrink step size stepSize *= RHO; } // Compute and save gradient at the new point System.arraycopy(function.gradientAt(nextPoint), 0, gradAtNextPoint, 0, gradAtNextPoint.length); // Update line search result lsr.setAll(stepSize, valueAtX, valueAtNextPoint, gradAtX, gradAtNextPoint, x, nextPoint, currFctEvalCount); } /** * Conducts a constrained line search (see section 3.2 in the paper "Scalable Training * of L1-Regularized Log-Linear Models", Andrew et al. 2007) * * @param function The {@link Function} to apply. * @param direction The {@code double[]} representing the direction to search into. * @param lsr The {@link LineSearchResult} to transport results in. * @param l1Cost The L1-regularization costs. Must be equal or greater than {@code 0}. * @param initialStepSize The initial step size to apply. Must be greater than {@code 0}. */ public static void doConstrainedLineSearch(Function function, double[] direction, LineSearchResult lsr, double l1Cost, double initialStepSize) { double stepSize = initialStepSize; int currFctEvalCount = lsr.getFctEvalCount(); double[] x = lsr.getNextPoint(); double[] signX = lsr.getSignVector(); // existing sign vector double[] gradAtX = lsr.getGradAtNext(); double[] pseudoGradAtX = lsr.getPseudoGradAtNext(); double valueAtX = lsr.getValueAtNext(); int dimension = x.length; // Retrieve current points and gradient for array reuse purpose double[] nextPoint = lsr.getCurrPoint(); double[] gradAtNextPoint = lsr.getGradAtCurr(); double valueAtNextPoint; double dirGradientAtX; // New sign vector for (int i = 0; i < dimension; i++) { signX[i] = x[i] == 0 ? -pseudoGradAtX[i] : x[i]; } while (true) { // Get next point for (int i = 0; i < dimension; i++) { nextPoint[i] = x[i] + direction[i] * stepSize; } // Projection for (int i = 0; i < dimension; i++) { if (nextPoint[i] * signX[i] <= 0) nextPoint[i] = 0; } // New value valueAtNextPoint = function.valueAt(nextPoint) + l1Cost * ArrayMath.l1norm(nextPoint); currFctEvalCount++; dirGradientAtX = 0; for (int i = 0; i < dimension; i++) { dirGradientAtX += (nextPoint[i] - x[i]) * pseudoGradAtX[i]; } // Check the sufficient decrease condition if (valueAtNextPoint <= valueAtX + C * dirGradientAtX) break; // Shrink step size stepSize *= RHO; } // Compute and save gradient at the new point System.arraycopy(function.gradientAt(nextPoint), 0, gradAtNextPoint, 0, gradAtNextPoint.length); // Update line search result lsr.setAll(stepSize, valueAtX, valueAtNextPoint, gradAtX, gradAtNextPoint, pseudoGradAtX, x, nextPoint, signX, currFctEvalCount); } // ------------------------------------------------------------------------------------- // /** * Represents a {@link LineSearch} result encapsulating the relevant data * at a point in time during computation. */ public static class LineSearchResult { private int fctEvalCount; private double stepSize; private double valueAtCurr; private double valueAtNext; private double[] gradAtCurr; private double[] gradAtNext; private double[] pseudoGradAtNext; private double[] currPoint; private double[] nextPoint; private double[] signVector; /** * Initializes a {@link LineSearchResult} object with the specified parameters. */ public LineSearchResult(double stepSize, double valueAtCurr, double valueAtNext, double[] gradAtCurr, double[] gradAtNext, double[] currPoint, double[] nextPoint, int fctEvalCount) { setAll(stepSize, valueAtCurr, valueAtNext, gradAtCurr, gradAtNext, currPoint, nextPoint, fctEvalCount); } /** * Initializes a {@link LineSearchResult} object with the specified parameters. */ public LineSearchResult(double stepSize, double valueAtCurr, double valueAtNext, double[] gradAtCurr, double[] gradAtNext, double[] pseudoGradAtNext, double[] currPoint, double[] nextPoint, double[] signVector, int fctEvalCount) { setAll(stepSize, valueAtCurr, valueAtNext, gradAtCurr, gradAtNext, pseudoGradAtNext, currPoint, nextPoint, signVector, fctEvalCount); } /** * Updates line search elements. */ public void setAll(double stepSize, double valueAtCurr, double valueAtNext, double[] gradAtCurr, double[] gradAtNext, double[] currPoint, double[] nextPoint, int fctEvalCount) { setAll(stepSize, valueAtCurr, valueAtNext, gradAtCurr, gradAtNext, null, currPoint, nextPoint, null, fctEvalCount); } /** * Updates line search elements. */ public void setAll(double stepSize, double valueAtCurr, double valueAtNext, double[] gradAtCurr, double[] gradAtNext, double[] pseudoGradAtNext, double[] currPoint, double[] nextPoint, double[] signVector, int fctEvalCount) { this.stepSize = stepSize; this.valueAtCurr = valueAtCurr; this.valueAtNext = valueAtNext; this.gradAtCurr = gradAtCurr; this.gradAtNext = gradAtNext; this.pseudoGradAtNext = pseudoGradAtNext; this.currPoint = currPoint; this.nextPoint = nextPoint; this.signVector = signVector; this.fctEvalCount = fctEvalCount; } public double getFuncChangeRate() { return (valueAtCurr - valueAtNext) / valueAtCurr; } public double getStepSize() { return stepSize; } public void setStepSize(double stepSize) { this.stepSize = stepSize; } public double getValueAtCurr() { return valueAtCurr; } public void setValueAtCurr(double valueAtCurr) { this.valueAtCurr = valueAtCurr; } public double getValueAtNext() { return valueAtNext; } public void setValueAtNext(double valueAtNext) { this.valueAtNext = valueAtNext; } public double[] getGradAtCurr() { return gradAtCurr; } public void setGradAtCurr(double[] gradAtCurr) { this.gradAtCurr = gradAtCurr; } public double[] getGradAtNext() { return gradAtNext; } public void setGradAtNext(double[] gradAtNext) { this.gradAtNext = gradAtNext; } public double[] getPseudoGradAtNext() { return pseudoGradAtNext; } public void setPseudoGradAtNext(double[] pseudoGradAtNext) { this.pseudoGradAtNext = pseudoGradAtNext; } public double[] getCurrPoint() { return currPoint; } public void setCurrPoint(double[] currPoint) { this.currPoint = currPoint; } public double[] getNextPoint() { return nextPoint; } public void setNextPoint(double[] nextPoint) { this.nextPoint = nextPoint; } public double[] getSignVector() { return signVector; } public void setSignVector(double[] signVector) { this.signVector = signVector; } public int getFctEvalCount() { return fctEvalCount; } public void setFctEvalCount(int fctEvalCount) { this.fctEvalCount = fctEvalCount; } /** * Initial linear search object for L1-regularization. * * @param valueAtX The value at {@code x}. * @param gradAtX The gradient at {@code x}. * @param x The input {@code double[]} vector. * * @return The {@link LineSearchResult} holding the results. */ public static LineSearchResult getInitialObject(double valueAtX, double[] gradAtX, double[] x) { return getInitialObject(valueAtX, gradAtX, null, x, null, 0); } /** * Initial linear search object for L1-regularization. * * @param valueAtX The value at {@code x}. * @param gradAtX The gradient at {@code x}. * @param pseudoGradAtX The pseudo-gradient at {@code x}. * @param x The input {@code double[]} vector. * * @return The {@link LineSearchResult} holding the results. */ public static LineSearchResult getInitialObjectForL1(double valueAtX, double[] gradAtX, double[] pseudoGradAtX, double[] x) { return getInitialObject(valueAtX, gradAtX, pseudoGradAtX, x, new double[x.length], 0); } /** * Initial linear search object for L1-regularization. * * @param valueAtX The value at {@code x}. * @param gradAtX The gradient at {@code x}. * @param pseudoGradAtX The pseudo-gradient at {@code x}. * @param x The input {@code double[]} vector. * @param signX The sign {@code double[]} vector for {@code x}. * @param fctEvalCount The number of function evaluations. * Must be equal to or greater than {@code 0}. * * @return The {@link LineSearchResult} holding the results. */ public static LineSearchResult getInitialObject(double valueAtX, double[] gradAtX, double[] pseudoGradAtX, double[] x, double[] signX, int fctEvalCount) { return new LineSearchResult(0.0, 0.0, valueAtX, new double[x.length], gradAtX, pseudoGradAtX, new double[x.length], x, signX, fctEvalCount); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000171 15217274217 032604 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/NegLogLikelihood.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/NegLogLike0100644 0000000 0000000 00000012601 15217274217 034073 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.quasinewton; import java.util.Arrays; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.ml.model.OnePassRealValueDataIndexer; /** * Evaluates negative log-likelihood and its gradient from {@link DataIndexer}. * * @see Function */ public class NegLogLikelihood implements Function { protected final int dimension; protected final int numOutcomes; protected final int numFeatures; protected final int numContexts; // Information from data index protected final float[][] values; protected final int[][] contexts; protected final int[] outcomeList; protected final int[] numTimesEventsSeen; // For calculating negLogLikelihood and gradient protected final double[] tempSums; protected final double[] expectation; protected final double[] gradient; /** * @param indexer The {@link DataIndexer} to use as input provider. */ public NegLogLikelihood(DataIndexer indexer) { // Get data from indexer. if (indexer instanceof OnePassRealValueDataIndexer) { this.values = indexer.getValues(); } else { this.values = null; } this.contexts = indexer.getContexts(); this.outcomeList = indexer.getOutcomeList(); this.numTimesEventsSeen = indexer.getNumTimesEventsSeen(); this.numOutcomes = indexer.getOutcomeLabels().length; this.numFeatures = indexer.getPredLabels().length; this.numContexts = this.contexts.length; this.dimension = numOutcomes * numFeatures; this.expectation = new double[numOutcomes]; this.tempSums = new double[numOutcomes]; this.gradient = new double[dimension]; } /** * @return Retrieves the dimension value. */ @Override public int getDimension() { return this.dimension; } /** * @return Retrieves the initial point as {@code double} array. */ public double[] getInitialPoint() { return new double[dimension]; } /** * Computes the negative log-likelihood. * * @param x The input. * @return Returns the computed negative log-likelihood. * @throws IllegalArgumentException Thrown if parameters were invalid. */ @Override public double valueAt(double[] x) { if (x.length != dimension) throw new IllegalArgumentException( "x is invalid, its dimension is not equal to domain dimension."); int ci, oi, ai, vectorIndex, outcome; double predValue, logSumOfExps; double negLogLikelihood = 0; for (ci = 0; ci < numContexts; ci++) { for (oi = 0; oi < numOutcomes; oi++) { tempSums[oi] = 0; for (ai = 0; ai < contexts[ci].length; ai++) { vectorIndex = indexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; tempSums[oi] += predValue * x[vectorIndex]; } } logSumOfExps = ArrayMath.logSumOfExps(tempSums); outcome = outcomeList[ci]; negLogLikelihood -= (tempSums[outcome] - logSumOfExps) * numTimesEventsSeen[ci]; } return negLogLikelihood; } /** * Computes the gradient. * * @param x The input. * @return Returns the computed gradient. * @throws IllegalArgumentException Thrown if parameters were invalid. */ @Override public double[] gradientAt(double[] x) { if (x.length != dimension) throw new IllegalArgumentException( "x is invalid, its dimension is not equal to the function."); int ci, oi, ai, vectorIndex; double predValue, logSumOfExps; int empirical; // Reset gradient Arrays.fill(gradient, 0); for (ci = 0; ci < numContexts; ci++) { for (oi = 0; oi < numOutcomes; oi++) { expectation[oi] = 0; for (ai = 0; ai < contexts[ci].length; ai++) { vectorIndex = indexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; expectation[oi] += predValue * x[vectorIndex]; } } logSumOfExps = ArrayMath.logSumOfExps(expectation); for (oi = 0; oi < numOutcomes; oi++) { expectation[oi] = StrictMath.exp(expectation[oi] - logSumOfExps); } for (oi = 0; oi < numOutcomes; oi++) { empirical = outcomeList[ci] == oi ? 1 : 0; for (ai = 0; ai < contexts[ci].length; ai++) { vectorIndex = indexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; gradient[vectorIndex] += predValue * (expectation[oi] - empirical) * numTimesEventsSeen[ci]; } } } return gradient; } protected int indexOf(int outcomeId, int featureId) { return outcomeId * numFeatures + featureId; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000201 15217274217 032576 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/ParallelNegLogLikelihood.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/ParallelNe0100644 0000000 0000000 00000020535 15217274217 034137 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.quasinewton; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.DataIndexer; /** * Evaluates {@link NegLogLikelihood negative log-likelihood} and * its gradient in parallel. * * @see Function */ public class ParallelNegLogLikelihood extends NegLogLikelihood { private static final Logger logger = LoggerFactory.getLogger(ParallelNegLogLikelihood.class); // Number of threads private final int threads; // Partial value of negative log-likelihood to be computed by each thread private final double[] negLogLikelihoodThread; // Partial gradient private final double[][] gradientThread; /** * @param indexer The {@link DataIndexer} to use as input provider. * @param threads The number of thread to compute with in parallel. * Must be greater than {@code 0}. * @throws IllegalArgumentException Thrown if parameters were invalid. */ public ParallelNegLogLikelihood(DataIndexer indexer, int threads) { super(indexer); if (threads <= 0) throw new IllegalArgumentException( "Number of threads must 1 or larger"); this.threads = threads; this.negLogLikelihoodThread = new double[threads]; this.gradientThread = new double[threads][dimension]; } /** * Computes the function value for {@code x}. * * @param x The input. * @return Returns the computed negative log-likelihood. * @throws IllegalArgumentException Thrown if parameters were invalid. */ @Override public double valueAt(double[] x) { if (x.length != dimension) throw new IllegalArgumentException( "x is invalid, its dimension is not equal to domain dimension."); // Compute partial value of negative log-likelihood in each thread computeInParallel(x, NegLLComputeTask.class); double negLogLikelihood = 0; for (int t = 0; t < threads; t++) { negLogLikelihood += negLogLikelihoodThread[t]; } return negLogLikelihood; } /** * Computes the gradient for {@code x}. * * @param x The input. * @return Returns the computed gradient. * @throws IllegalArgumentException Thrown if parameters were invalid. */ @Override public double[] gradientAt(double[] x) { if (x.length != dimension) throw new IllegalArgumentException( "x is invalid, its dimension is not equal to the function."); // Compute partial gradient in each thread computeInParallel(x, GradientComputeTask.class); // Accumulate gradient for (int i = 0; i < dimension; i++) { gradient[i] = 0; for (int t = 0; t < threads; t++) { gradient[i] += gradientThread[t][i]; } } return gradient; } /** * Computes the specified tasks in parallel. */ private void computeInParallel(double[] x, Class taskClass) { ExecutorService executor = Executors.newFixedThreadPool(threads, runnable -> { Thread thread = new Thread(runnable); thread.setName( "opennlp.tools.ml.maxent.quasinewton.ParallelNegLogLikelihood.computeInParallel()"); thread.setDaemon(true); return thread; }); int taskSize = numContexts / threads; int leftOver = numContexts % threads; try { Constructor cons = taskClass.getConstructor( ParallelNegLogLikelihood.class, int.class, int.class, int.class, double[].class); List> futures = new ArrayList<>(); for (int i = 0; i < threads; i++) { if (i != threads - 1) futures.add(executor.submit( cons.newInstance(this, i, i * taskSize, taskSize, x))); else futures.add(executor.submit( cons.newInstance(this, i, i * taskSize, taskSize + leftOver, x))); } for (Future future: futures) future.get(); } catch (Exception e) { logger.error(e.getLocalizedMessage(), e); } executor.shutdown(); } /** * A {@link ComputeTask} that is computed in parallel. */ static abstract class ComputeTask implements Callable { final int threadIndex; // Start index of contexts to compute final int startIndex; // Number of contexts to compute final int length; final double[] x; public ComputeTask(int threadIndex, int startIndex, int length, double[] x) { this.threadIndex = threadIndex; this.startIndex = startIndex; this.length = length; this.x = x; } } /** * A {@link ComputeTask} for computing partial value of negative log-likelihood. */ class NegLLComputeTask extends ComputeTask { final double[] tempSums; public NegLLComputeTask(int threadIndex, int startIndex, int length, double[] x) { super(threadIndex, startIndex, length, x); this.tempSums = new double[numOutcomes]; } @Override public NegLLComputeTask call() { int ci, oi, ai, vectorIndex, outcome; double predValue, logSumOfExps; negLogLikelihoodThread[threadIndex] = 0; for (ci = startIndex; ci < startIndex + length; ci++) { for (oi = 0; oi < numOutcomes; oi++) { tempSums[oi] = 0; for (ai = 0; ai < contexts[ci].length; ai++) { vectorIndex = indexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; tempSums[oi] += predValue * x[vectorIndex]; } } logSumOfExps = ArrayMath.logSumOfExps(tempSums); outcome = outcomeList[ci]; negLogLikelihoodThread[threadIndex] -= (tempSums[outcome] - logSumOfExps) * numTimesEventsSeen[ci]; } return this; } } /** * A {@link ComputeTask} for computing partial gradient. */ class GradientComputeTask extends ComputeTask { final double[] expectation; public GradientComputeTask(int threadIndex, int startIndex, int length, double[] x) { super(threadIndex, startIndex, length, x); this.expectation = new double[numOutcomes]; } @Override public GradientComputeTask call() { int ci, oi, ai, vectorIndex; double predValue, logSumOfExps; int empirical; // Reset gradientThread Arrays.fill(gradientThread[threadIndex], 0); for (ci = startIndex; ci < startIndex + length; ci++) { for (oi = 0; oi < numOutcomes; oi++) { expectation[oi] = 0; for (ai = 0; ai < contexts[ci].length; ai++) { vectorIndex = indexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; expectation[oi] += predValue * x[vectorIndex]; } } logSumOfExps = ArrayMath.logSumOfExps(expectation); for (oi = 0; oi < numOutcomes; oi++) { expectation[oi] = StrictMath.exp(expectation[oi] - logSumOfExps); } for (oi = 0; oi < numOutcomes; oi++) { empirical = outcomeList[ci] == oi ? 1 : 0; for (ai = 0; ai < contexts[ci].length; ai++) { vectorIndex = indexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; gradientThread[threadIndex][vectorIndex] += predValue * (expectation[oi] - empirical) * numTimesEventsSeen[ci]; } } } return this; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000164 15217274217 032606 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/QNMinimizer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/QNMinimize0100644 0000000 0000000 00000042241 15217274217 034136 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.quasinewton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.maxent.quasinewton.LineSearch.LineSearchResult; /** * Implementation of the * Limited memory Broyden-Fletcher-Goldfarb-Shanno algorithm (L-BFGS) which * supports L1-, L2-regularization and Elastic Net for solving convex optimization problems. * *

* Usage example: *

 *  // Quadratic function f(x) = (x-1)^2 + 10
 *  // f obtains its minimum value 10 at x = 1
 *  Function f = new Function() {
 *
 *    {@literal @}Override
 *    public int getDimension() {
 *      return 1;
 *    }
 *
 *    {@literal @}Override
 *    public double valueAt(double[] x) {
 *      return StrictMath.pow(x[0]-1, 2) + 10;
 *    }
 *
 *    {@literal @}Override
 *    public double[] gradientAt(double[] x) {
 *      return new double[] { 2*(x[0]-1) };
 *    }
 *
 *  };
 *
 *  QNMinimizer minimizer = new QNMinimizer();
 *  double[] x = minimizer.minimize(f);
 *  double min = f.valueAt(x);
 * 
* * @see * Quasi-Newton Methods in: * Nocedal J, Wright SJ. Numerical optimization. 2nd ed. New York: Springer; 2006. */ public class QNMinimizer { private static final Logger logger = LoggerFactory.getLogger(QNMinimizer.class); // Function change rate tolerance public static final double CONVERGE_TOLERANCE = 1e-4; // Relative gradient norm tolerance public static final double REL_GRAD_NORM_TOL = 1e-4; /** The initial step size: {@code 1.0}. */ public static final double INITIAL_STEP_SIZE = 1.0; /** The minimum step size: {@code 1e-10}. */ public static final double MIN_STEP_SIZE = 1e-10; /** The default L1-cost value is {@code 0.0d}. */ public static final double L1COST_DEFAULT = 0; /** The default L2-cost value is {@code 0.0d}. */ public static final double L2COST_DEFAULT = 0; /** By default the number of iterations is {@code 100}. */ public static final int NUM_ITERATIONS_DEFAULT = 100; /** The default number of Hessian updates to store is {@code 15}. */ public static final int M_DEFAULT = 15; /** The default maximum number of function evaluations is {@code 30,000}. */ public static final int MAX_FCT_EVAL_DEFAULT = 30000; // L1-regularization cost private final double l1Cost; // L2-regularization cost private final double l2Cost; // Maximum number of iterations private final int iterations; // Number of Hessian updates to store private final int m; // Maximum number of function evaluations private final int maxFctEval; // Objective function's dimension private int dimension; // Hessian updates private UpdateInfo updateInfo; // For evaluating quality of training parameters. // This is optional and can be omitted. private Evaluator evaluator; /** * Initializes a {@link QNMinimizer} with default parameters * (see: {@link #L1COST_DEFAULT} and {@link #L2COST_DEFAULT}). */ public QNMinimizer() { this(L1COST_DEFAULT, L2COST_DEFAULT); } /** * Initializes a {@link QNMinimizer}. * * @param l1Cost The L1-regularization cost. Must be equal to or greater than {@code 0}. * @param l2Cost The L2-regularization cost. Must be equal to or greater than {@code 0}. * * @throws IllegalArgumentException Thrown if parameters were invalid. */ public QNMinimizer(double l1Cost, double l2Cost) { this(l1Cost, l2Cost, NUM_ITERATIONS_DEFAULT); } /** * Initializes a {@link QNMinimizer} with L1 and L2 parameters. * * @param l1Cost The L1-regularization cost. Must be equal to or greater than {@code 0}. * @param l2Cost The L2-regularization cost. Must be equal to or greater than {@code 0}. * @param iterations The maximum number of iterations. Must be greater than {@code 0}. * * @throws IllegalArgumentException Thrown if parameters were invalid. */ public QNMinimizer(double l1Cost, double l2Cost, int iterations) { this(l1Cost, l2Cost, iterations, M_DEFAULT, MAX_FCT_EVAL_DEFAULT); } /** * Initializes a {@link QNMinimizer}. * * @param l1Cost The L1-regularization cost. Must be equal to or greater than {@code 0}. * @param l2Cost The L2-regularization cost. Must be equal to or greater than {@code 0}. * @param iterations The maximum number of iterations. Must be greater than {@code 0}. * @param m The number of Hessian updates to store. Must be greater than {@code 0}. * @param maxFctEval The maximum number of function evaluations. Must be greater than {@code 0}. * * @throws IllegalArgumentException Thrown if parameters were invalid. */ public QNMinimizer(double l1Cost, double l2Cost, int iterations, int m, int maxFctEval) { // Check arguments if (l1Cost < 0 || l2Cost < 0) throw new IllegalArgumentException( "L1-cost and L2-cost must not be less than zero"); if (iterations <= 0) throw new IllegalArgumentException( "Number of iterations must be larger than zero"); if (m <= 0) throw new IllegalArgumentException( "Number of Hessian updates must be larger than zero"); if (maxFctEval <= 0) throw new IllegalArgumentException( "Maximum number of function evaluations must be larger than zero"); this.l1Cost = l1Cost; this.l2Cost = l2Cost; this.iterations = iterations; this.m = m; this.maxFctEval = maxFctEval; } public Evaluator getEvaluator() { return evaluator; } public void setEvaluator(Evaluator evaluator) { this.evaluator = evaluator; } /** * Finds the parameters that minimize the objective function. * * @param function The objective {@link Function}. * @return The minimizing parameters. */ public double[] minimize(Function function) { Function l2RegFunction = new L2RegFunction(function, l2Cost); this.dimension = l2RegFunction.getDimension(); this.updateInfo = new UpdateInfo(this.m, this.dimension); // Current point is at the origin double[] currPoint = new double[dimension]; double currValue = l2RegFunction.valueAt(currPoint); // Gradient at the current point double[] currGrad = new double[dimension]; System.arraycopy(l2RegFunction.gradientAt(currPoint), 0, currGrad, 0, dimension); // Pseudo-gradient - only use when L1-regularization is enabled double[] pseudoGrad = null; if (l1Cost > 0) { currValue += l1Cost * ArrayMath.l1norm(currPoint); pseudoGrad = new double[dimension]; computePseudoGrad(currPoint, currGrad, pseudoGrad); } LineSearchResult lsr; if (l1Cost > 0) { lsr = LineSearchResult.getInitialObjectForL1( currValue, currGrad, pseudoGrad, currPoint); } else { lsr = LineSearchResult.getInitialObject( currValue, currGrad, currPoint); } if (logger.isDebugEnabled()) { logger.debug("Solving convex optimization problem."); logger.debug("Objective function has {} variable(s).", dimension); logger.debug("Performing {} iterations with L1Cost={} and L2Cost={}", iterations, l1Cost, l2Cost); } double[] direction = new double[dimension]; long startTime = System.currentTimeMillis(); // Initial step size for the 1st iteration double initialStepSize = l1Cost > 0 ? ArrayMath.invL2norm(lsr.getPseudoGradAtNext()) : ArrayMath.invL2norm(lsr.getGradAtNext()); for (int iter = 1; iter <= iterations; iter++) { // Find direction if (l1Cost > 0) { System.arraycopy(lsr.getPseudoGradAtNext(), 0, direction, 0, direction.length); } else { System.arraycopy(lsr.getGradAtNext(), 0, direction, 0, direction.length); } computeDirection(direction); // Line search if (l1Cost > 0) { // Constrain the search direction pseudoGrad = lsr.getPseudoGradAtNext(); for (int i = 0; i < dimension; i++) { if (direction[i] * pseudoGrad[i] >= 0) { direction[i] = 0; } } LineSearch.doConstrainedLineSearch(l2RegFunction, direction, lsr, l1Cost, initialStepSize); computePseudoGrad(lsr.getNextPoint(), lsr.getGradAtNext(), pseudoGrad); lsr.setPseudoGradAtNext(pseudoGrad); } else { LineSearch.doLineSearch(l2RegFunction, direction, lsr, initialStepSize); } // Save Hessian updates updateInfo.update(lsr); if (logger.isDebugEnabled()) { if (evaluator != null) { logger.debug("{}: \t{}\t{}\t{}", iter, lsr.getValueAtNext(), lsr.getFuncChangeRate(),evaluator.evaluate(lsr.getNextPoint())); } else { logger.debug("{}: \t {}\t{}\n", iter, lsr.getValueAtNext(), lsr.getFuncChangeRate()); } } if (isConverged(lsr)) break; initialStepSize = INITIAL_STEP_SIZE; } // Undo L2-shrinkage if Elastic Net is used (since // in that case, the shrinkage is done twice) if (l1Cost > 0 && l2Cost > 0) { double[] x = lsr.getNextPoint(); for (int i = 0; i < dimension; i++) { x[i] = StrictMath.sqrt(1 + l2Cost) * x[i]; } } long endTime = System.currentTimeMillis(); long duration = endTime - startTime; logger.info("Running time: {}s\n", (duration / 1000.)); // Release memory this.updateInfo = null; System.gc(); // Avoid returning the reference to LineSearchResult's member so that GC can // collect memory occupied by lsr after this function completes (is it necessary?) double[] parameters = new double[dimension]; System.arraycopy(lsr.getNextPoint(), 0, parameters, 0, dimension); return parameters; } /** * Conducts pseudo-gradient for L1-regularization. * * @implNote See equation 4 in * "Scalable Training of L1-Regularized Log-Linear Models", by Andrew and Gao, 2007) * * @param x The current point * @param g The gradient at {@code x}. * @param pg The pseudo-gradient at {@code x} which is to be computed. */ private void computePseudoGrad(double[] x, double[] g, double[] pg) { for (int i = 0; i < dimension; i++) { if (x[i] < 0) { pg[i] = g[i] - l1Cost; } else if (x[i] > 0) { pg[i] = g[i] + l1Cost; } else { if (g[i] < -l1Cost) { // right partial derivative pg[i] = g[i] + l1Cost; } else if (g[i] > l1Cost) { // left partial derivative pg[i] = g[i] - l1Cost; } else { pg[i] = 0; } } } } /** * L-BFGS two-loop recursion, see * * Nocedal & Wright 2006, Numerical Optimization, p. 178) */ private void computeDirection(double[] direction) { // Implemented two-loop Hessian update method. int k = updateInfo.kCounter; double[] rho = updateInfo.rho; double[] alpha = updateInfo.alpha; // just to avoid recreating alpha double[][] S = updateInfo.S; double[][] Y = updateInfo.Y; // First loop for (int i = k - 1; i >= 0; i--) { alpha[i] = rho[i] * ArrayMath.innerProduct(S[i], direction); for (int j = 0; j < dimension; j++) { direction[j] = direction[j] - alpha[i] * Y[i][j]; } } // Second loop for (int i = 0; i < k; i++) { double beta = rho[i] * ArrayMath.innerProduct(Y[i], direction); for (int j = 0; j < dimension; j++) { direction[j] = direction[j] + S[i][j] * (alpha[i] - beta); } } for (int i = 0; i < dimension; i++) { direction[i] = -direction[i]; } } private boolean isConverged(LineSearchResult lsr) { // Check function's change rate if (lsr.getFuncChangeRate() < CONVERGE_TOLERANCE) { if (logger.isDebugEnabled()) logger.debug("Function change rate is smaller than the threshold {}. " + "Training will stop.", CONVERGE_TOLERANCE); return true; } // Check gradient's norm using the criteria: ||g(x)|| / max(1, ||x||) < threshold double xNorm = StrictMath.max(1, ArrayMath.l2norm(lsr.getNextPoint())); double gradNorm = l1Cost > 0 ? ArrayMath.l2norm(lsr.getPseudoGradAtNext()) : ArrayMath.l2norm(lsr.getGradAtNext()); if (gradNorm / xNorm < REL_GRAD_NORM_TOL) { if (logger.isDebugEnabled()) logger.debug("Relative L2-norm of the gradient is smaller than the threshold {}. " + "Training will stop.", REL_GRAD_NORM_TOL); return true; } // Check step size if (lsr.getStepSize() < MIN_STEP_SIZE) { if (logger.isDebugEnabled()) logger.debug("Step size is smaller than the minimum step size {}. " + "Training will stop.", MIN_STEP_SIZE); return true; } // Check number of function evaluations if (lsr.getFctEvalCount() > this.maxFctEval) { if (logger.isDebugEnabled()) logger.debug("Maximum number of function evaluations has exceeded the threshold {}. " + "Training will stop.", this.maxFctEval); return true; } return false; } /** * Class to store vectors for Hessian approximation update. */ private class UpdateInfo { private final double[][] S; private final double[][] Y; private final double[] rho; private final double[] alpha; private final int m; private int kCounter; // Constructor UpdateInfo(int numCorrection, int dimension) { this.m = numCorrection; this.kCounter = 0; S = new double[this.m][dimension]; Y = new double[this.m][dimension]; rho = new double[this.m]; alpha = new double[this.m]; } public void update(LineSearchResult lsr) { double[] currPoint = lsr.getCurrPoint(); double[] gradAtCurr = lsr.getGradAtCurr(); double[] nextPoint = lsr.getNextPoint(); double[] gradAtNext = lsr.getGradAtNext(); // Inner product of S_k and Y_k double SYk = 0.0; // Add new ones. if (kCounter < m) { for (int j = 0; j < dimension; j++) { S[kCounter][j] = nextPoint[j] - currPoint[j]; Y[kCounter][j] = gradAtNext[j] - gradAtCurr[j]; SYk += S[kCounter][j] * Y[kCounter][j]; } rho[kCounter] = 1.0 / SYk; } else { // Discard oldest vectors and add new ones. for (int i = 0; i < m - 1; i++) { S[i] = S[i + 1]; Y[i] = Y[i + 1]; rho[i] = rho[i + 1]; } for (int j = 0; j < dimension; j++) { S[m - 1][j] = nextPoint[j] - currPoint[j]; Y[m - 1][j] = gradAtNext[j] - gradAtCurr[j]; SYk += S[m - 1][j] * Y[m - 1][j]; } rho[m - 1] = 1.0 / SYk; } if (kCounter < m) kCounter++; } } /** * L2-regularized objective {@link Function}. */ public static class L2RegFunction implements Function { private final Function f; private final double l2Cost; public L2RegFunction(Function f, double l2Cost) { this.f = f; this.l2Cost = l2Cost; } @Override public int getDimension() { return f.getDimension(); } @Override public double valueAt(double[] x) { checkDimension(x); double value = f.valueAt(x); if (l2Cost > 0) { value += l2Cost * ArrayMath.innerProduct(x, x); } return value; } @Override public double[] gradientAt(double[] x) { checkDimension(x); double[] gradient = f.gradientAt(x); if (l2Cost > 0) { for (int i = 0; i < x.length; i++) { gradient[i] += 2 * l2Cost * x[i]; } } return gradient; } private void checkDimension(double[] x) { if (x.length != getDimension()) throw new IllegalArgumentException( "x's dimension is not the same as function's dimension"); } } /** * Evaluate the quality of training parameters. For example, * it can be used to report model's training accuracy when * we train a Maximum Entropy classifier. */ public interface Evaluator { /** * Measure quality of the training parameters. * * @param parameters The parameters used for training. * @return The evaluated result. */ double evaluate(double[] parameters); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000160 15217274217 032602 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/QNModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/QNModel.ja0100644 0000000 0000000 00000011504 15217274217 034004 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.quasinewton; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.MaxentModel; /** * A {@link MaxentModel maximum entropy model} which has been trained via the * L-BFGS algorithm , * which belongs to the group of Quasi Newton (QN) algorithms. * * @see AbstractModel * @see MaxentModel * @see QNTrainer */ public class QNModel extends AbstractModel { /** * Initializes a {@link QNModel} with the specified parameters, * predicate/feature labels, and outcome names. * * @param params The {@link Context parameters} of the model. * @param predLabels The names of the predicates used in this model. * @param outcomeNames The names of the outcomes this model predicts. */ public QNModel(Context[] params, String[] predLabels, String[] outcomeNames) { super(params, predLabels, outcomeNames); this.modelType = ModelType.MaxentQn; } /** * {@inheritDoc} */ @Override public int getNumOutcomes() { return this.outcomeNames.length; } private Context getPredIndex(String predicate) { return pmap.get(predicate); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context) { return eval(context, new double[evalParams.getNumOutcomes()]); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, double[] probs) { return eval(context, null, probs); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, float[] values) { return eval(context, values, new double[evalParams.getNumOutcomes()]); } /** * Evaluates which should be used during inference. * * @param context The predicates which have been observed at the present * decision point. * @param values The weights of the predicates which have been observed at * the present decision point. * @param probs The probability for outcomes. * @return Normalized probabilities for the outcomes given the context. */ private double[] eval(String[] context, float[] values, double[] probs) { for (int ci = 0; ci < context.length; ci++) { Context pred = getPredIndex(context[ci]); if (pred != null) { double predValue = 1.0; if (values != null) predValue = values[ci]; double[] parameters = pred.getParameters(); int[] outcomes = pred.getOutcomes(); for (int i = 0; i < outcomes.length; i++) { int oi = outcomes[i]; probs[oi] += predValue * parameters[i]; } } } double logSumExp = ArrayMath.logSumOfExps(probs); for (int oi = 0; oi < outcomeNames.length; oi++) { probs[oi] = StrictMath.exp(probs[oi] - logSumExp); } return probs; } /** * Evaluates which should be used during training to report model accuracy. * @param context The indices of the predicates which have been observed at the present * decision point. * @param values The weights of the predicates which have been observed at * the present decision point. * @param probs The probability for outcomes. * @param nOutcomes The number of outcomes. * @param nPredLabels The number of unique predicates. * @param parameters The model parameters. * @return Normalized probabilities for the outcomes given the context. */ static double[] eval(int[] context, float[] values, double[] probs, int nOutcomes, int nPredLabels, double[] parameters) { for (int i = 0; i < context.length; i++) { int predIdx = context[i]; double predValue = values != null ? values[i] : 1.0; for (int oi = 0; oi < nOutcomes; oi++) { probs[oi] += predValue * parameters[oi * nPredLabels + predIdx]; } } double logSumExp = ArrayMath.logSumOfExps(probs); for (int oi = 0; oi < nOutcomes; oi++) { probs[oi] = StrictMath.exp(probs[oi] - logSumExp); } return probs; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000162 15217274217 032604 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/QNTrainer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/QNTrainer.0100644 0000000 0000000 00000021635 15217274217 034043 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.maxent.quasinewton; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.AbstractEventTrainer; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.maxent.quasinewton.QNMinimizer.Evaluator; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.util.TrainingParameters; /** * A Maxent model {@link Trainer trainer} using the * L-BFGS algorithm. * * @see AbstractEventTrainer * @see QNMinimizer * @see QNModel * @see Trainer */ public class QNTrainer extends AbstractEventTrainer { private static final Logger logger = LoggerFactory.getLogger(QNTrainer.class); public static final String MAXENT_QN_VALUE = "MAXENT_QN"; public static final String THREADS_PARAM = "Threads"; public static final int THREADS_DEFAULT = 1; public static final String L1COST_PARAM = "L1Cost"; /** The default L1-cost value is {@code 0.1d}. */ public static final double L1COST_DEFAULT = 0.1; public static final String L2COST_PARAM = "L2Cost"; /** The default L2-cost value is {@code 0.1d}. */ public static final double L2COST_DEFAULT = 0.1; // Number of Hessian updates to store public static final String M_PARAM = "NumOfUpdates"; /** The default number of Hessian updates to store is {@code 15}. */ public static final int M_DEFAULT = 15; // Maximum number of function evaluations public static final String MAX_FCT_EVAL_PARAM = "MaxFctEval"; /** The default maximum number of function evaluations is {@code 30,000}. */ public static final int MAX_FCT_EVAL_DEFAULT = 30000; // Number of threads private int threads; // L1-regularization cost private double l1Cost; // L2-regularization cost private double l2Cost; // Settings for QNMinimizer private int m; private int maxFctEval; /** * Initializes a {@link QNTrainer}. * * @implNote * The resulting instance does not print progress messages about training to STDOUT. */ public QNTrainer() { this(M_DEFAULT); } /** * Initializes a {@link QNTrainer} with the specified {@code parameters}. * * @param parameters The {@link TrainingParameters} to use. */ public QNTrainer(TrainingParameters parameters) { super(parameters); } /** * Initializes a {@link QNTrainer} with the specified parameter {@code m}. * * @param m The number of hessian updates to store. */ public QNTrainer(int m) { this(m, MAX_FCT_EVAL_DEFAULT); } /** * Initializes a {@link QNTrainer} with the specified parameters. * * @param m The number of hessian updates to store. */ public QNTrainer(int m, int maxFctEval) { this.m = m < 0 ? M_DEFAULT : m; this.maxFctEval = maxFctEval < 0 ? MAX_FCT_EVAL_DEFAULT : maxFctEval; this.threads = THREADS_DEFAULT; this.l1Cost = L1COST_DEFAULT; this.l2Cost = L2COST_DEFAULT; } // >> Members related to AbstractEventTrainer @Override public void init(TrainingParameters trainingParameters, Map reportMap) { super.init(trainingParameters,reportMap); this.m = trainingParameters.getIntParameter(M_PARAM, M_DEFAULT); this.maxFctEval = trainingParameters.getIntParameter(MAX_FCT_EVAL_PARAM, MAX_FCT_EVAL_DEFAULT); this.threads = trainingParameters.getIntParameter(THREADS_PARAM, THREADS_DEFAULT); this.l1Cost = trainingParameters.getDoubleParameter(L1COST_PARAM, L1COST_DEFAULT); this.l2Cost = trainingParameters.getDoubleParameter(L2COST_PARAM, L2COST_DEFAULT); } @Override public void validate() { super.validate(); String algorithmName = getAlgorithm(); if (algorithmName != null && !(MAXENT_QN_VALUE.equals(algorithmName))) { throw new IllegalArgumentException("algorithmName must be " + MAXENT_QN_VALUE); } // Number of Hessian updates to remember if (m <= 0) { throw new IllegalArgumentException( "Number of Hessian updates to remember must be >= 0"); } // Maximum number of function evaluations if (maxFctEval <= 0) { throw new IllegalArgumentException( "Maximum number of function evaluations must be >= 0"); } // Number of threads must be >= 1 if (threads < 1) { throw new IllegalArgumentException("Number of threads must be >= 1"); } // Regularization costs must be >= 0 if (l1Cost < 0) { throw new IllegalArgumentException("Regularization costs must be >= 0"); } if (l2Cost < 0) { throw new IllegalArgumentException("Regularization costs must be >= 0"); } } @Override public boolean isSortAndMerge() { return true; } @Override public AbstractModel doTrain(DataIndexer indexer) throws IOException { int iterations = getIterations(); return trainModel(iterations, indexer); } /** * Trains a {@link QNModel model} using the QN algorithm. * * @param iterations The number of QN iterations to perform. * @param indexer The {@link DataIndexer} used to compress events in memory. * * @return A trained {@link QNModel} which can be used immediately or saved to * disk using an {@link opennlp.tools.ml.maxent.io.QNModelWriter}. * @throws IllegalArgumentException Thrown if parameters were invalid. */ public QNModel trainModel(int iterations, DataIndexer indexer) { // Train model's parameters Function objectiveFunction; if (threads == 1) { logger.info("Computing model parameters ..."); objectiveFunction = new NegLogLikelihood(indexer); } else { logger.info("Computing model parameters with {} threads...", threads); objectiveFunction = new ParallelNegLogLikelihood(indexer, threads); } QNMinimizer minimizer = new QNMinimizer( l1Cost, l2Cost, iterations, m, maxFctEval); minimizer.setEvaluator(new ModelEvaluator(indexer)); double[] parameters = minimizer.minimize(objectiveFunction); // Construct model with trained parameters String[] predLabels = indexer.getPredLabels(); int nPredLabels = predLabels.length; String[] outcomeNames = indexer.getOutcomeLabels(); int nOutcomes = outcomeNames.length; Context[] params = new Context[nPredLabels]; for (int ci = 0; ci < params.length; ci++) { List outcomePattern = new ArrayList<>(nOutcomes); List alpha = new ArrayList<>(nOutcomes); for (int oi = 0; oi < nOutcomes; oi++) { double val = parameters[oi * nPredLabels + ci]; outcomePattern.add(oi); alpha.add(val); } params[ci] = new Context(ArrayMath.toIntArray(outcomePattern), ArrayMath.toDoubleArray(alpha)); } return new QNModel(params, predLabels, outcomeNames); } /** * For measuring model's training accuracy. * * @param indexer A valid {@link DataIndexer} instance. */ private record ModelEvaluator(DataIndexer indexer) implements Evaluator { /** * Evaluate the current model on training data set * * @return model's training accuracy */ @Override public double evaluate(double[] parameters) { int[][] contexts = indexer.getContexts(); float[][] values = indexer.getValues(); int[] nEventsSeen = indexer.getNumTimesEventsSeen(); int[] outcomeList = indexer.getOutcomeList(); int nOutcomes = indexer.getOutcomeLabels().length; int nPredLabels = indexer.getPredLabels().length; int nCorrect = 0; int nTotalEvents = 0; for (int ei = 0; ei < contexts.length; ei++) { int[] context = contexts[ei]; float[] value = values == null ? null : values[ei]; double[] probs = new double[nOutcomes]; QNModel.eval(context, value, probs, nOutcomes, nPredLabels, parameters); int outcome = ArrayMath.argmax(probs); if (outcome == outcomeList[ei]) { nCorrect += nEventsSeen[ei]; } nTotalEvents += nEventsSeen[ei]; } return (double) nCorrect / nTotalEvents; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_maxent_quasin0100644 0000000 0000000 00000000165 15217274217 032607 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/maxent/quasinewton/package-in0100644 0000000 0000000 00000001635 15217274217 034117 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to ML by means of the Quasi Newton (QN) algorithm. */ package opennlp.tools.ml.maxent.quasinewton; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Abstrac0100644 0000000 0000000 00000000157 15217274217 032473 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/AbstractDataIndexer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/AbstractDataIndexer.jav0100644 0000000 0000000 00000017464 15217274217 034011 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.InsufficientTrainingDataException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; /** * Abstract {@link DataIndexer} implementation for collecting * event and context counts used in training. * * @see DataIndexer */ public abstract class AbstractDataIndexer implements DataIndexer { private static final Logger logger = LoggerFactory.getLogger(AbstractDataIndexer.class); public static final String SORT_PARAM = "sort"; public static final boolean SORT_DEFAULT = true; protected TrainingParameters trainingParameters; protected Map reportMap; /** * {@inheritDoc} */ @Override public void init(TrainingParameters indexingParameters, Map reportMap) { this.reportMap = reportMap; if (this.reportMap == null) reportMap = new HashMap<>(); trainingParameters = indexingParameters; } private int numEvents; /** The integer contexts associated with each unique event. */ protected int[][] contexts; /** The integer outcome associated with each unique event. */ protected int[] outcomeList; /** The number of times an event occurred in the training data. */ protected int[] numTimesEventsSeen; /** The predicate/context names. */ protected String[] predLabels; /** The names of the outcomes. */ protected String[] outcomeLabels; /** The number of times each predicate occurred. */ protected int[] predCounts; /** * {@inheritDoc} */ @Override public int[][] getContexts() { return contexts; } /** * {@inheritDoc} */ @Override public int[] getNumTimesEventsSeen() { return numTimesEventsSeen; } /** * {@inheritDoc} */ @Override public int[] getOutcomeList() { return outcomeList; } /** * {@inheritDoc} */ @Override public String[] getPredLabels() { return predLabels; } /** * {@inheritDoc} */ @Override public String[] getOutcomeLabels() { return outcomeLabels; } /** * {@inheritDoc} */ @Override public int[] getPredCounts() { return predCounts; } /** * {@inheritDoc} */ @Override public int getNumEvents() { return numEvents; } /** * Sorts and uniques the array of comparable events and return the number of unique events. * This method will alter the {@code eventsToCompare} list. *

* It does an in place sort, followed by an in place edit to remove duplicates. * * @param eventsToCompare The {@link List} events used as input. * @param sort Whether to use sorting, or not. * * @return The number of unique events in the specified list. * @throws InsufficientTrainingDataException Thrown if not enough events are provided * @since maxent 1.2.6 */ protected int sortAndMerge(List eventsToCompare, boolean sort) throws InsufficientTrainingDataException { int numUniqueEvents = 1; numEvents = eventsToCompare.size(); if (sort && eventsToCompare.size() > 0) { Collections.sort(eventsToCompare); ComparableEvent ce = eventsToCompare.get(0); for (int i = 1; i < numEvents; i++) { ComparableEvent ce2 = eventsToCompare.get(i); if (ce.compareTo(ce2) == 0) { ce.seen++; // increment the seen count eventsToCompare.set(i, null); // kill the duplicate } else { ce = ce2; // a new champion emerges... numUniqueEvents++; // increment the # of unique events } } } else { numUniqueEvents = eventsToCompare.size(); } if (numUniqueEvents == 0) { throw new InsufficientTrainingDataException("Insufficient training data to create model."); } if (sort) logger.info("done. Reduced {} events to {}.", numEvents, numUniqueEvents); contexts = new int[numUniqueEvents][]; outcomeList = new int[numUniqueEvents]; numTimesEventsSeen = new int[numUniqueEvents]; for (int i = 0, j = 0; i < numEvents; i++) { ComparableEvent evt = eventsToCompare.get(i); if (null == evt) { continue; // this was a dupe, skip over it. } numTimesEventsSeen[j] = evt.seen; outcomeList[j] = evt.outcome; contexts[j] = evt.predIndexes; ++j; } return numUniqueEvents; } /** * Performs the data indexing. *

* Note: * Make sure the {@link #init(TrainingParameters, Map)} method is called first. * * @param events A {@link ObjectStream} of events used as input. * @param predicateIndex A {@link Map} providing the data of a predicate index. * * @throws IOException Thrown if IO errors occurred during indexing. */ protected List index(ObjectStream events, Map predicateIndex) throws IOException { Map omap = new HashMap<>(); List eventsToCompare = new ArrayList<>(); Event ev; while ((ev = events.read()) != null) { omap.putIfAbsent(ev.getOutcome(), omap.size()); int[] cons = Arrays.stream(ev.getContext()) .map(predicateIndex::get) .filter(Objects::nonNull) .mapToInt(i -> i).toArray(); // drop events with no active features if (cons.length > 0) { int ocID = omap.get(ev.getOutcome()); eventsToCompare.add(new ComparableEvent(ocID, cons, ev.getValues())); } else { logger.info("Dropped event {}:{}", ev.getOutcome(), Arrays.asList(ev.getContext())); } } outcomeLabels = toIndexedStringArray(omap); predLabels = toIndexedStringArray(predicateIndex); return eventsToCompare; } /** * Updates the {@link Map} of predicates and counter with the specified event contexts. * * @param ec The contexts/features which occur in an event. * @param counter The predicate counters in form of a {@link Map}. */ protected static void update(String[] ec, Map counter) { for (String s : ec) { counter.merge(s, 1, (value, one) -> value + one); } } /** * Utility method for creating a {@code String[]} from a map whose * keys are labels (Strings) to be stored in the array and whose * values are the indices (Integers) at which the corresponding * labels should be inserted. * * @param labelToIndexMap A {@link Map} that holds labels to index positions. * @return The resulting {@code String[]}. */ protected static String[] toIndexedStringArray(Map labelToIndexMap) { return labelToIndexMap.entrySet().stream() .sorted(Comparator.comparingInt(Map.Entry::getValue)) .map(Map.Entry::getKey).toArray(String[]::new); } @Override public float[][] getValues() { return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/AbstractModel.java0100644 0000000 0000000 00000015236 15217274217 033015 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; import opennlp.tools.ml.ArrayMath; /** * A basic {@link MaxentModel} implementation. */ public abstract class AbstractModel implements MaxentModel { private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0000", DecimalFormatSymbols.getInstance(Locale.ROOT)); /** Mapping between predicates/contexts and an integer representing them. */ protected Map pmap; /** The names of the outcomes. */ protected String[] outcomeNames; /** Parameters for the model. */ protected EvalParameters evalParams; /** Prior distribution for this model. */ protected Prior prior; public enum ModelType { Maxent,Perceptron,MaxentQn,NaiveBayes } /** The type of the model. */ protected ModelType modelType; /** * Initializes an {@link AbstractModel}. * * @param params The {@link Context[] parameters} to set. * @param predLabels The predicted labels. * @param pmap A {@link Map} that provides a mapping between predicates and contexts. * @param outcomeNames The names of the outcomes. */ protected AbstractModel(Context[] params, String[] predLabels, Map pmap, String[] outcomeNames) { this.pmap = pmap; this.outcomeNames = outcomeNames; this.evalParams = new EvalParameters(params,outcomeNames.length); } /** * Initializes an {@link AbstractModel}. * * @param params The {@link Context parameters} to set. * @param predLabels The predicted labels. * @param outcomeNames The names of the outcomes. */ public AbstractModel(Context[] params, String[] predLabels, String[] outcomeNames) { init(predLabels, params, outcomeNames); this.evalParams = new EvalParameters(params, outcomeNames.length); } private void init(String[] predLabels, Context[] params, String[] outcomeNames) { this.pmap = new LinkedHashMap<>(predLabels.length); for (int i = 0; i < predLabels.length; i++) { pmap.put(predLabels[i], params[i]); } this.outcomeNames = outcomeNames; } /** * Return the name of the outcome corresponding to the highest likelihood * in the parameter ocs. * * @param ocs A {@code double[]} as returned by the {@link #eval(String[]) method}. * @return The name of the most likely outcome. */ @Override public final String getBestOutcome(double[] ocs) { return outcomeNames[ArrayMath.argmax(ocs)]; } /** * @return Retrieves the {@link ModelType}. */ public ModelType getModelType() { return modelType; } /** * Retrieves a string matching all the outcome names with all the * probabilities produced by the {@link #eval(String[])} method. * * @param ocs A {@code double[]} as returned by the * {@link #eval(String[])} method. * @return String containing outcome names paired with the normalized * probability (contained in the {@code double[] ocs}) * for each one. */ @Override public final String getAllOutcomes(double[] ocs) { if (ocs.length != outcomeNames.length) { return "The double array sent as a parameter to AbstractModel.getAllOutcomes() " + "must not have been produced by this model."; } else { StringBuilder sb = new StringBuilder(ocs.length * 2); sb.append(outcomeNames[0]).append("[").append(DECIMAL_FORMAT.format(ocs[0])).append("]"); for (int i = 1; i < ocs.length; i++) { sb.append(" ").append(outcomeNames[i]).append("[").append(DECIMAL_FORMAT.format(ocs[i])).append("]"); } return sb.toString(); } } /** * @param i An outcome id. * @return Retrieves the name of the outcome associated with {@code id}. */ @Override public final String getOutcome(int i) { return outcomeNames[i]; } /** * @param outcome The String name of the outcome for which the index is desired. * * @return Retrieves the index if the given {@code outcome} label exists for this * model, {@code -1} if it does not. **/ @Override public int getIndex(String outcome) { for (int i = 0; i < outcomeNames.length; i++) { if (outcomeNames[i].equals(outcome)) return i; } return -1; } @Override public int getNumOutcomes() { return evalParams.getNumOutcomes(); } /** * Provides the fundamental data structures which encode the {@link MaxentModel} * information. * *

* The following values are held in the {@code Object[]} which is returned by this method: *

    *
  • index 0: {@link Context} array containing the model parameters.
  • *
  • index 1: {@link Map} containing the mapping of model predicates * to unique integers.
  • *
  • index 2: {@link String} array containing the names of the outcomes, * stored in the index of the array which represents their * unique ids in the model.
  • *
* * @return An {@link Object} array with the values as described above. * * @implNote : This method will usually only be needed by * {@link opennlp.tools.ml.maxent.io.GISModelWriter GIS model writers}. */ public final Object[] getDataStructures() { Object[] data = new Object[3]; data[0] = evalParams.getParams(); data[1] = pmap; data[2] = outcomeNames; return data; } @Override public int hashCode() { return Objects.hash(pmap, Arrays.hashCode(outcomeNames), evalParams, prior); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof AbstractModel model) { return pmap.equals(model.pmap) && Objects.deepEquals(outcomeNames, model.outcomeNames) && Objects.equals(prior, model.prior); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Abstrac0100644 0000000 0000000 00000000157 15217274217 032473 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/AbstractModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/AbstractModelReader.jav0100644 0000000 0000000 00000020774 15217274217 034002 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.StringTokenizer; import java.util.zip.GZIPInputStream; /** * An abstract, basic implementation of a model reader. */ public abstract class AbstractModelReader { /** * System property for overriding the maximum number of entries (outcomes, predicates, * outcome patterns, chunk counts) that may be read from a model file or training data. * Set at JVM startup, e.g. {@code -DOPENNLP_MAX_ENTRIES=5000000}. * Falls back to {@code 10_000_000} if absent or invalid. */ public static final String MAX_ENTRIES_PROPERTY = "OPENNLP_MAX_ENTRIES"; /** * Upper bound on count fields read from a model file. * Prevents OOM on crafted inputs with oversized array size declarations. * Configurable via the {@link #MAX_ENTRIES_PROPERTY} system property. */ static final int MAX_ENTRIES = initMaxEntries(); private static int initMaxEntries() { String prop = System.getProperty(MAX_ENTRIES_PROPERTY, "").trim(); if (!prop.isEmpty()) { try { int val = Integer.parseInt(prop); if (val > 0) return val; } catch (NumberFormatException ignore) { } } return 10_000_000; } /** * The number of predicates contained in a model. */ protected int NUM_PREDS; protected DataReader dataReader; /** * Initializes a {@link AbstractModelReader} via a {@link File}. * * @param f The {@link File} that references the model to be read. * * @throws IOException Thrown if IO errors occurred. */ public AbstractModelReader(File f) throws IOException { String filename = f.getName(); InputStream input; // handle the zipped/not zipped distinction if (filename.endsWith(".gz")) { input = new GZIPInputStream(new FileInputStream(f)); filename = filename.substring(0,filename.length() - 3); } else { input = new FileInputStream(f); } // handle the different formats if (filename.endsWith(".bin")) { this.dataReader = new BinaryFileDataReader(input); } else { // filename ends with ".txt" this.dataReader = new PlainTextFileDataReader(input); } } /** * Initializes a {@link AbstractModelReader} via a {@link DataReader}. * * @param dataReader The {@link DataReader} that references the model to be read. */ public AbstractModelReader(DataReader dataReader) { super(); this.dataReader = dataReader; } /** * Implement as needed for the format the model is stored in. * * @return Reads in an {@code int} value from the underlying {@link DataReader}. */ public int readInt() throws IOException { return dataReader.readInt(); } /** * Implement as needed for the format the model is stored in. * * @return Reads in a {@code double} value from the underlying {@link DataReader}. */ public double readDouble() throws IOException { return dataReader.readDouble(); } /** * Implement as needed for the format the model is stored in. * * @return Reads in an {@code UTF-encoded String} * value from the underlying {@link DataReader}. */ public String readUTF() throws IOException { return dataReader.readUTF(); } /** * @return Retrieves the read {@link AbstractModel} instance. * @throws IOException Thrown if IO errors occurred constructing the model. */ public AbstractModel getModel() throws IOException { checkModelType(); return constructModel(); } /** * Checks the model type via the the underlying {@link DataReader}. * * @throws IOException Thrown if IO errors occurred checking the model type. */ public abstract void checkModelType() throws IOException; /** * Constructs a {@link AbstractModel model}. * * @return A {@link AbstractModel} reconstructed from a model's (read) attributes. * @throws IOException Thrown if IO errors occurred during (re-)construction. */ public abstract AbstractModel constructModel() throws IOException; /** * @return Reads and retrieves the {@code outcome labels} from the model. * @throws IOException Thrown if IO errors occurred. * @throws IllegalArgumentException Thrown if the outcome count is negative or * exceeds {@link #MAX_ENTRIES}. */ protected String[] getOutcomes() throws IOException { int numOutcomes = readInt(); if (numOutcomes < 0 || numOutcomes > MAX_ENTRIES) { throw new IllegalArgumentException( "Outcome count " + numOutcomes + " exceeds safe limit of " + MAX_ENTRIES); } String[] outcomeLabels = new String[numOutcomes]; for (int i = 0; i < numOutcomes; i++) outcomeLabels[i] = readUTF(); return outcomeLabels; } /** * @return Reads and retrieves the {@code outcome patterns} from the model. * @throws IOException Thrown if IO errors occurred. * @throws IllegalArgumentException Thrown if the outcome pattern count is negative or * exceeds {@link #MAX_ENTRIES}. */ protected int[][] getOutcomePatterns() throws IOException { int numOCTypes = readInt(); if (numOCTypes < 0 || numOCTypes > MAX_ENTRIES) { throw new IllegalArgumentException( "Outcome pattern count " + numOCTypes + " exceeds safe limit of " + MAX_ENTRIES); } int[][] outcomePatterns = new int[numOCTypes][]; for (int i = 0; i < numOCTypes; i++) { StringTokenizer tok = new StringTokenizer(readUTF(), " "); int[] infoInts = new int[tok.countTokens()]; for (int j = 0; tok.hasMoreTokens(); j++) { infoInts[j] = Integer.parseInt(tok.nextToken()); } outcomePatterns[i] = infoInts; } return outcomePatterns; } /** * @return Reads and retrieves the {@code predicates} from the model. * @throws IOException Thrown if IO errors occurred. * @throws IllegalArgumentException Thrown if the predicate count is negative or * exceeds {@link #MAX_ENTRIES}. */ protected String[] getPredicates() throws IOException { NUM_PREDS = readInt(); if (NUM_PREDS < 0 || NUM_PREDS > MAX_ENTRIES) { throw new IllegalArgumentException( "Predicate count " + NUM_PREDS + " exceeds safe limit of " + MAX_ENTRIES); } String[] predLabels = new String[NUM_PREDS]; for (int i = 0; i < NUM_PREDS; i++) predLabels[i] = readUTF(); return predLabels; } /** * Reads the parameters from a file and populates an array of {@link Context} objects. * * @param outcomePatterns The outcome patterns for the model. The first index refers to which * outcome pattern (a set of outcomes that occurs with a context) is being specified. The * second index specifies the number of contexts which use this pattern at index {@code 0}, * and the index of each outcome which make up this pattern in indices {@code 1-n}. * @return An array of {@link Context} objects. * @throws IOException Thrown when the model file does not match the outcome patterns or can not be read. */ protected Context[] getParameters(int[][] outcomePatterns) throws IOException { Context[] params = new Context[NUM_PREDS]; int pid = 0; for (int[] pattern : outcomePatterns) { //construct outcome pattern int[] outcomePattern = new int[pattern.length - 1]; System.arraycopy(pattern, 1, outcomePattern, 0, pattern.length - 1); //populate parameters for each context which uses this outcome pattern. for (int j = 0; j < pattern[0]; j++) { double[] contextParameters = new double[pattern.length - 1]; for (int k = 1; k < pattern.length; k++) { contextParameters[k - 1] = readDouble(); } params[pid] = new Context(outcomePattern, contextParameters); pid++; } } return params; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Abstrac0100644 0000000 0000000 00000000157 15217274217 032473 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/AbstractModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/AbstractModelWriter.jav0100644 0000000 0000000 00000004432 15217274217 034045 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.DataOutputStream; import java.io.IOException; /** * An abstract, basic implementation of a model writer. */ public abstract class AbstractModelWriter { public AbstractModelWriter() { super(); } /** * Writes a {@link String} to the underlying {@link DataOutputStream}. * * @param s The {@link String UTF encoded} characters. * @throws IOException Thrown if IO errors occurred. */ public abstract void writeUTF(String s) throws IOException; /** * Writes a single {@code int} to the underlying {@link DataOutputStream}. * * @param i The {@code int} value. * @throws IOException Thrown if IO errors occurred. */ public abstract void writeInt(int i) throws IOException; /** * Writes a single {@code double} to the underlying {@link DataOutputStream}. * * @param d The {@code double} value. * @throws IOException Thrown if IO errors occurred. */ public abstract void writeDouble(double d) throws IOException; /** * Closes the underlying {@link DataOutputStream}. * * @throws IOException Thrown if IO errors occurred. */ public abstract void close() throws IOException; /** * Serializes the {@link AbstractModel model} using the * {@link #writeUTF(String)}, {@link #writeDouble(double)}, * or {@link #writeInt(int)}} methods implemented by * extending classes. * * @throws IOException Thrown if IO errors occurred. */ public abstract void persist() throws IOException; } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_BinaryF0100644 0000000 0000000 00000000160 15217274217 032440 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/BinaryFileDataReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/BinaryFileDataReader.ja0100644 0000000 0000000 00000005431 15217274217 033677 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.GZIPInputStream; /** * A {@link DataReader} that reads files from a binary format. */ public class BinaryFileDataReader implements DataReader { private final DataInputStream input; /** * Instantiates {@link BinaryFileDataReader} via a {@link File} and creates * a {@link DataInputStream} for it. * Based on whether the file's suffix contains {@code .gz}, * it detects whether the file is gzipped or not. * * @param f The {@link File} that references the model to be read. */ public BinaryFileDataReader(File f) throws IOException { if (f.getName().endsWith(".gz")) { input = new DataInputStream(new BufferedInputStream( new GZIPInputStream(new BufferedInputStream(new FileInputStream(f))))); } else { input = new DataInputStream(new BufferedInputStream(new FileInputStream(f))); } } /** * Instantiates {@link BinaryFileDataReader} via an {@link InputStream} and creates * a {@link DataInputStream} for it. * * @param in The {@link InputStream} that references the model to be read. */ public BinaryFileDataReader(InputStream in) { this(new DataInputStream(in)); } /** * Instantiates {@link BinaryFileDataReader} via an {@link DataInputStream}. * * @param in The {@link DataInputStream} that references the model to be read. */ public BinaryFileDataReader(DataInputStream in) { input = in; } /** * {@inheritDoc} */ @Override public double readDouble() throws IOException { return input.readDouble(); } /** * {@inheritDoc} */ @Override public int readInt() throws IOException { return input.readInt(); } /** * {@inheritDoc} */ @Override public String readUTF() throws IOException { return ModelParameterChunker.readUTF(input); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Checksu0100644 0000000 0000000 00000000157 15217274217 032501 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ChecksumEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ChecksumEventStream.jav0100644 0000000 0000000 00000004521 15217274217 034043 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.zip.CRC32C; import java.util.zip.Checksum; import opennlp.tools.util.AbstractObjectStream; import opennlp.tools.util.ObjectStream; /** * A {@link Checksum}-based {@link AbstractObjectStream event stream} implementation. * Computes the checksum while consuming the event stream. * By default, this implementation will use {@link CRC32C} for checksum calculations * as it can use of CPU-specific acceleration instructions at runtime. * * @see Event * @see Checksum * @see AbstractObjectStream */ public class ChecksumEventStream extends AbstractObjectStream { private final Checksum checksum; /** * Initializes an {@link ChecksumEventStream}. * * @param eventStream The {@link ObjectStream} that provides the {@link Event} samples. */ public ChecksumEventStream(ObjectStream eventStream) { super(eventStream); // CRC32C supports CPU-specific acceleration instructions checksum = new CRC32C(); } @Override public Event read() throws IOException { Event event = super.read(); if (event != null) { checksum.update(event.toString().getBytes(StandardCharsets.UTF_8)); } return event; } /** * Calculates and returns the (current) checksum. *

* Note: This should be called once the underlying stream has been (fully) consumed. * * @return The calculated checksum as {@code long}. */ public long calculateChecksum() { return checksum.getValue(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ComparableEvent.java0100644 0000000 0000000 00000006633 15217274217 033341 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.Arrays; import java.util.Objects; /** * A maxent event representation which we can use to sort based on the * predicates indexes contained in the events. */ public class ComparableEvent implements Comparable { public final int outcome; public final int[] predIndexes; public int seen = 1; // the number of times this event has been seen. public final float[] values; public ComparableEvent(int oc, int[] pids, float[] values) { outcome = oc; this.values = values; predIndexes = pids; } public ComparableEvent(int oc, int[] pids) { this(oc, pids, null); } @Override public int compareTo(ComparableEvent ce) { int compareOutcome = Integer.compare(outcome, ce.outcome); if (compareOutcome != 0) { return compareOutcome; } int smallerLength = StrictMath.min(predIndexes.length, ce.predIndexes.length); for (int i = 0; i < smallerLength; i++) { int comparePredIndexes = Integer.compare(predIndexes[i], ce.predIndexes[i]); if (comparePredIndexes != 0) { return comparePredIndexes; } if (values != null && ce.values != null) { float compareValues = Float.compare(values[i], ce.values[i]); if (!Float.valueOf(compareValues).equals(0.0f)) { return (int) compareValues; } } else if (values != null) { float compareValues = Float.compare(values[i], 1.0f); if (!Float.valueOf(compareValues).equals(0.0f)) { return (int) compareValues; } } else if (ce.values != null) { float compareValues = Float.compare(1.0f, ce.values[i]); if (!Float.valueOf(compareValues).equals(0.0f)) { return (int) compareValues; } } } return Integer.compare(predIndexes.length, ce.predIndexes.length); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj instanceof ComparableEvent other) { return outcome == other.outcome && Arrays.equals(predIndexes, other.predIndexes) && seen == other.seen && Arrays.equals(values, other.values); } return false; } @Override public int hashCode() { return Objects.hash(outcome, Arrays.hashCode(predIndexes), seen, Arrays.hashCode(values)); } @Override public String toString() { StringBuilder s = new StringBuilder().append(outcome).append(":"); for (int i = 0; i < predIndexes.length; i++) { s.append(" ").append(predIndexes[i]); if (values != null) { s.append("=").append(values[i]); } } return s.toString(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Compara0100644 0000000 0000000 00000000157 15217274217 032476 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ComparablePredicate.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ComparablePredicate.jav0100644 0000000 0000000 00000004561 15217274217 034015 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.Arrays; import java.util.Objects; /** * A maxent predicate representation which we can use to sort based on the * outcomes. This allows us to make the mapping of features to their parameters * much more compact. */ public class ComparablePredicate implements Comparable { public final String name; public final int[] outcomes; public final double[] params; public ComparablePredicate(String n, int[] ocs, double[] ps) { name = n; outcomes = ocs; params = ps; } @Override public int compareTo(ComparablePredicate cp) { int smallerLength = StrictMath.min(outcomes.length, cp.outcomes.length); for (int i = 0; i < smallerLength; i++) { int compareOutcomes = Integer.compare(outcomes[i], cp.outcomes[i]); if (compareOutcomes != 0) { return compareOutcomes; } } return Integer.compare(outcomes.length, cp.outcomes.length); } @Override public int hashCode() { return Objects.hash(name, Arrays.hashCode(outcomes), Arrays.hashCode(params)); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj instanceof ComparablePredicate other) { return Objects.equals(name, other.name) && Arrays.equals(outcomes, other.outcomes) && Arrays.equals(params, other.params); } return false; } @Override public String toString() { StringBuilder s = new StringBuilder(); for (int outcome : outcomes) { s.append(" ").append(outcome); } return s.toString(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/Context.java0100644 0000000 0000000 00000004671 15217274217 031716 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.Arrays; import java.util.Objects; /** * Class which associates a real valued parameter or expected value with a particular contextual * predicate or feature. This is used to store maxent model parameters as well as model and empirical * expected values. */ public class Context { /** The real valued parameters or expected values for this context. */ protected final double[] parameters; /** The outcomes which occur with this context. */ protected final int[] outcomes; /** * Creates a new parameters object with the specified parameters associated with the specified * outcome pattern. * @param outcomePattern Array of outcomes for which parameters exists for this context. * @param parameters Parameters for the outcomes specified. */ public Context(int[] outcomePattern, double[] parameters) { this.outcomes = outcomePattern; this.parameters = parameters; } /** * @return Retrieves the array of outcomes for which parameters exists for this context. */ public int[] getOutcomes() { return outcomes; } /** * @return Retrieves the array of parameters for the outcomes of this context. */ public double[] getParameters() { return parameters; } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(parameters), Arrays.hashCode(outcomes)); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Context context) { return Arrays.equals(parameters, context.parameters) && Arrays.equals(outcomes, context.outcomes); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/DataIndexer.java0100644 0000000 0000000 00000005732 15217274217 032461 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.IOException; import java.util.Map; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; /** * Represents an indexer which compresses events in memory and performs feature selection. * * @see ObjectStream * @see TrainingParameters */ public interface DataIndexer { /** * @return Retrieves a 2-dimensional array whose first dimension is the event * index and array this refers to contains the contexts for that event. */ int[][] getContexts(); /** * @return Retrieves an array indexed by the event index indicating * the number of times a particular event was seen. */ int[] getNumTimesEventsSeen(); /** * @return Retrieves an array indicating the outcome index for each event. */ int[] getOutcomeList(); /** * @return Retrieves an array of predicate/context names indexed by context index. * These indices are the value of the array returned by {@link #getContexts()}. */ String[] getPredLabels(); /** * @return Retrieves an array of the count of each predicate in the events. */ int[] getPredCounts(); /** * @return Retrieves an array of outcome names indexed by outcome index. */ String[] getOutcomeLabels(); /** * @return Retrieves the values associated with each event context or * {@code null} if integer values are to be used. */ float[][] getValues(); /** * @return Retrieves the number of total events indexed. */ int getNumEvents(); /** * Sets parameters used during the data indexing. * * @param trainParams The {@link TrainingParameters} to be used. * @param reportMap The {@link Map} used for reporting. */ void init(TrainingParameters trainParams, Map reportMap); /** * Performs the data indexing. *

* Note: * Make sure the {@link #init(TrainingParameters, Map)} method is called first. * * @param eventStream A {@link ObjectStream} of events used as input. * * @throws IOException Thrown if IO errors occurred during indexing. */ void index(ObjectStream eventStream) throws IOException; } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_DataInd0100644 0000000 0000000 00000000156 15217274217 032417 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/DataIndexerFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/DataIndexerFactory.java0100644 0000000 0000000 00000005356 15217274217 034013 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.HashMap; import java.util.Map; import opennlp.tools.ml.AbstractEventTrainer; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.ext.ExtensionNotLoadedException; /** * A factory that produces {@link DataIndexer} instances. * * @see DataIndexer */ public class DataIndexerFactory { /** * Instantiates a {@link DataIndexer} configured via {@link TrainingParameters}. * * @param parameters The {@link TrainingParameters} used for configuration. * @param reportMap The {@link Map} used for reporting. * @return A ready to use {@link DataIndexer} instance. * * @throws ExtensionNotLoadedException Thrown if a class name was configured for the indexer, yet * the extension could not be loaded. * @see ExtensionLoader */ public static DataIndexer getDataIndexer(TrainingParameters parameters, Map reportMap) { // The default is currently a 2-Pass data index. Is this what we really want? String indexerParam = parameters.getStringParameter(AbstractEventTrainer.DATA_INDEXER_PARAM, AbstractEventTrainer.DATA_INDEXER_TWO_PASS_VALUE); // allow the user to pass in a report map. If the don't, create one. if (reportMap == null) { reportMap = new HashMap<>(); } DataIndexer indexer = switch (indexerParam) { case AbstractEventTrainer.DATA_INDEXER_ONE_PASS_VALUE -> new OnePassDataIndexer(); case AbstractEventTrainer.DATA_INDEXER_TWO_PASS_VALUE -> new TwoPassDataIndexer(); case AbstractEventTrainer.DATA_INDEXER_ONE_PASS_REAL_VALUE -> new OnePassRealValueDataIndexer(); default -> // if the user passes in a class name for the indexer, try to instantiate the class. ExtensionLoader.instantiateExtension(DataIndexer.class, indexerParam); }; indexer.init(parameters, reportMap); return indexer; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/DataReader.java0100644 0000000 0000000 00000003044 15217274217 032257 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.DataInputStream; import java.io.IOException; /** * Describes generic ways to read data from a {@link DataInputStream}. */ public interface DataReader { /** * @return Reads and returns a {@code double} value. * @throws IOException Thrown if IO errors occurred during read operation. */ double readDouble() throws IOException; /** * @return Reads and returns an {@code int} value. * @throws IOException Thrown if IO errors occurred during read operation. */ int readInt() throws IOException; /** * @return Reads and returns {@link String UTF-encoded characters}. * @throws IOException Thrown if IO errors occurred during read operation. */ String readUTF() throws IOException; } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Dynamic0100644 0000000 0000000 00000000161 15217274217 032473 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/DynamicEvalParameters.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/DynamicEvalParameters.j0100644 0000000 0000000 00000003207 15217274217 034014 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.List; public class DynamicEvalParameters { /** Mapping between outcomes and parameter values for each context. * The integer representation of the context can be found using pmap.*/ private final List params; /** The number of outcomes being predicted. */ private final int numOutcomes; /** * Creates a set of parameters which can be evaluated with the eval method. * * @param params The parameters of the model. * @param numOutcomes The number of outcomes. */ public DynamicEvalParameters(List params, int numOutcomes) { this.params = params; this.numOutcomes = numOutcomes; } public Context[] getParams() { return params.toArray(new Context[0]); } public int getNumOutcomes() { return numOutcomes; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/EvalParameters.java0100644 0000000 0000000 00000004412 15217274217 033176 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.Arrays; import java.util.Objects; /** * This class encapsulates the variables used in producing probabilities from a model * and facilitates passing these variables to the eval method. */ public class EvalParameters { /** * Mapping between outcomes and parameter values for each context. * The integer representation of the context can be found using pmap. */ private final Context[] params; /** * The number of outcomes being predicted. */ private final int numOutcomes; /** * The maximum number of features fired in an event. Usually referred to as C. * This is used to normalize the number of features which occur in an event. */ private double correctionConstant; public EvalParameters(Context[] params, int numOutcomes) { this.params = params; this.numOutcomes = numOutcomes; } public Context[] getParams() { return params; } public int getNumOutcomes() { return numOutcomes; } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(params), numOutcomes, correctionConstant); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof EvalParameters evalParameters) { return Arrays.equals(params, evalParameters.params) && numOutcomes == evalParameters.numOutcomes && correctionConstant == evalParameters.correctionConstant; } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/Event.java0100644 0000000 0000000 00000006503 15217274217 031347 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.Objects; /** * The context of a decision point during training. * This includes contextual predicates and an outcome. */ public class Event { private final String outcome; private final String[] context; private final float[] values; /** * Instantiates an {@link Event}. * * @param outcome The outcome to use. Must not be {@code null}. * @param context The {@link String array} of context elements. Must not be {@code null}. */ public Event(String outcome, CharSequence[] context) { this(outcome,context,null); } /** * Instantiates an {@link Event}. * * @param outcome The outcome to use. Must not be {@code null}. * @param context The {@link String array} of context elements. Must not be {@code null}. * @param values The {@code float} array to use. */ public Event(String outcome, String[] context, float[] values) { this.outcome = Objects.requireNonNull(outcome, "outcome must not be null"); this.context = Objects.requireNonNull(context, "context must not be null"); this.values = values; } /** * Instantiates an {@link Event}. * * @param outcome The outcome to use. Must not be {@code null}. * @param context The {@link CharSequence array} of context elements. Must not be {@code null}. * @param values The {@code float} array to use. */ public Event(String outcome, CharSequence[] context, float[] values) { this.outcome = Objects.requireNonNull(outcome, "outcome must not be null"); final String[] ctx = new String[context.length]; for (int i = 0; i < context.length; i++) { ctx[i] = context[i].toString(); } this.context = ctx; this.values = values; } /** * @return Retrieves the outcome. */ public String getOutcome() { return outcome; } /** * @return Retrieves the {@link String array} of context elements. */ public String[] getContext() { return context; } /** * @return Retrieves the {@code float} array. */ public float[] getValues() { return values; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(outcome).append(" ["); if (context.length > 0) { sb.append(context[0]); if (values != null) { sb.append("=").append(values[0]); } } for (int ci = 1; ci < context.length; ci++) { sb.append(" ").append(context[ci]); if (values != null) { sb.append("=").append(values[ci]); } } sb.append("]"); return sb.toString(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/FileEventStream.java0100644 0000000 0000000 00000011162 15217274217 033320 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; import java.util.StringTokenizer; import opennlp.tools.util.ObjectStream; /** * Class for using a file of {@link Event events} as an {@link ObjectStream event stream}. * The format of the file is one event per line with * each line consisting of outcome followed by contexts (space delimited). * * @see Event * @see ObjectStream */ public class FileEventStream implements ObjectStream { private static final String LINE_SEPARATOR = System.lineSeparator(); protected final BufferedReader reader; /** * Instantiates a {@link FileEventStream} from the specified file name. * * @param fileName The name fo the file containing the events. * @param encoding The name of the {@link java.nio.charset.Charset character encoding}. * * @throws IOException Thrown if the specified file can not be read. */ public FileEventStream(String fileName, String encoding) throws IOException { this(encoding == null ? new FileReader(fileName) : new InputStreamReader(new FileInputStream(fileName), encoding)); } /** * Instantiates a {@link FileEventStream} from the specified file name. * * @param fileName The name fo the file containing the events. * * @throws IOException Thrown if the specified file can not be read. */ public FileEventStream(String fileName) throws IOException { this(fileName,null); } /** * Instantiates a {@link FileEventStream} via a {@link Reader}. * * @param reader The {@link Reader} that holds events. * * @throws IOException Thrown if the specified file can not be read. */ public FileEventStream(Reader reader) throws IOException { this.reader = new BufferedReader(reader); } /** * Instantiates a {@link FileEventStream} via a {@link File}. * * @param file The {@link File} that holds events. * * @throws IOException Thrown if the specified file can not be read. */ public FileEventStream(File file) throws IOException { reader = new BufferedReader(new InputStreamReader( new FileInputStream(file), StandardCharsets.UTF_8)); } /** * Returns the next {@link Event} object. Calling this method repeatedly until it returns * {@code null} will return each object from the underlying source exactly once. * * @return The next object or {@code null} to signal that the stream is exhausted. * * @throws IOException Thrown if there is an error during reading. */ @Override public Event read() throws IOException { String line; if ((line = reader.readLine()) != null) { StringTokenizer st = new StringTokenizer(line); String outcome = st.nextToken(); int count = st.countTokens(); String[] context = new String[count]; for (int ci = 0; ci < count; ci++) { context[ci] = st.nextToken(); } return new Event(outcome, context); } else { return null; } } @Override public void close() throws IOException { reader.close(); } /** * Generates a string representing the specified event. * * @param event The {@link Event} for which a string representation is needed. * @return A string representing the specified event. */ public static String toLine(Event event) { StringBuilder sb = new StringBuilder(); sb.append(event.getOutcome()); String[] context = event.getContext(); for (String s : context) { sb.append(" ").append(s); } sb.append(LINE_SEPARATOR); return sb.toString(); } @Override public void reset() throws IOException, UnsupportedOperationException { throw new UnsupportedOperationException(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Generic0100644 0000000 0000000 00000000156 15217274217 032467 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/GenericModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/GenericModelReader.java0100644 0000000 0000000 00000005103 15217274217 033741 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.File; import java.io.IOException; import opennlp.tools.ml.maxent.io.GISModelReader; import opennlp.tools.ml.maxent.io.QNModelReader; import opennlp.tools.ml.naivebayes.NaiveBayesModelReader; import opennlp.tools.ml.perceptron.PerceptronModelReader; /** * An generic {@link AbstractModelReader} implementation. * * @see AbstractModelReader */ public class GenericModelReader extends AbstractModelReader { private AbstractModelReader delegateModelReader; /** * Initializes a {@link GenericModelReader} via a {@link File}. * * @param f The {@link File} that references the model to be read. * * @throws IOException Thrown if IO errors occurred. */ public GenericModelReader(File f) throws IOException { super(f); } /** * Initializes a {@link GenericModelReader} via a {@link DataReader}. * * @param dataReader The {@link DataReader} that references the model to be read. */ public GenericModelReader(DataReader dataReader) { super(dataReader); } @Override public void checkModelType() throws IOException { String modelType = readUTF(); switch (modelType) { case "Perceptron": delegateModelReader = new PerceptronModelReader(this.dataReader); break; case "GIS": delegateModelReader = new GISModelReader(this.dataReader); break; case "QN": delegateModelReader = new QNModelReader(this.dataReader); break; case "NaiveBayes": delegateModelReader = new NaiveBayesModelReader(this.dataReader); break; default: throw new IOException("Unknown model format: " + modelType); } } @Override public AbstractModel constructModel() throws IOException { return delegateModelReader.constructModel(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Generic0100644 0000000 0000000 00000000156 15217274217 032467 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/GenericModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/GenericModelWriter.java0100644 0000000 0000000 00000007323 15217274217 034021 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; import opennlp.tools.ml.maxent.io.BinaryGISModelWriter; import opennlp.tools.ml.maxent.io.BinaryQNModelWriter; import opennlp.tools.ml.model.AbstractModel.ModelType; import opennlp.tools.ml.naivebayes.BinaryNaiveBayesModelWriter; import opennlp.tools.ml.perceptron.BinaryPerceptronModelWriter; /** * An generic {@link AbstractModelWriter} implementation. * * @see AbstractModelWriter */ public class GenericModelWriter extends AbstractModelWriter { private AbstractModelWriter delegateWriter; /** * Initializes a {@link GenericModelWriter} for an {@link AbstractModel} * with an associated {@link File} the model shall be written to. * * @param model The {@link AbstractModel model} to write out. * @param file The {@link File} that used to be written to. * * @throws IOException Thrown if IO errors occurred. */ public GenericModelWriter(AbstractModel model, File file) throws IOException { String filename = file.getName(); OutputStream os; // handle the zipped/not zipped distinction if (filename.endsWith(".gz")) { os = new GZIPOutputStream(new FileOutputStream(file)); filename = filename.substring(0, filename.length() - 3); } else { os = new FileOutputStream(file); } init(model, new DataOutputStream(os)); } /** * Initializes a {@link GenericModelWriter} for an {@link AbstractModel} * with an associated {@link DataOutputStream} the model shall be written to. * * @param model The {@link AbstractModel model} to write out. * @param dos The {@link DataOutputStream} that used to be written to. */ public GenericModelWriter(AbstractModel model, DataOutputStream dos) { init(model, dos); } private void init(AbstractModel model, DataOutputStream dos) { if (model.getModelType() == ModelType.Perceptron) { delegateWriter = new BinaryPerceptronModelWriter(model, dos); } else if (model.getModelType() == ModelType.Maxent) { delegateWriter = new BinaryGISModelWriter(model, dos); } else if (model.getModelType() == ModelType.MaxentQn) { delegateWriter = new BinaryQNModelWriter(model, dos); } if (model.getModelType() == ModelType.NaiveBayes) { delegateWriter = new BinaryNaiveBayesModelWriter(model, dos); } } @Override public void close() throws IOException { delegateWriter.close(); } @Override public void persist() throws IOException { delegateWriter.persist(); } @Override public void writeDouble(double d) throws IOException { delegateWriter.writeDouble(d); } @Override public void writeInt(int i) throws IOException { delegateWriter.writeInt(i); } @Override public void writeUTF(String s) throws IOException { delegateWriter.writeUTF(s); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/MaxentModel.java0100644 0000000 0000000 00000007405 15217274217 032505 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; /** * Interface for maximum entropy models. **/ public interface MaxentModel { /** * Evaluates a {@code context}. * * @param context An array of String names of the contextual predicates * which are to be evaluated together. * @return An array of the probabilities for each of the different * outcomes, all of which sum to {@code 1}. * **/ double[] eval(String[] context); /** * Evaluates a {@code context}. * * @param context An array of String names of the contextual predicates * which are to be evaluated together. * @param probs An array which is populated with the probabilities for each of the different * outcomes, all of which sum to 1. * @return An array of the probabilities for each of the different * outcomes, all of which sum to {@code 1}. **/ double[] eval(String[] context, double[] probs); /** * Evaluates a {@code context} with the specified context {@code values}. * * @param context An array of String names of the contextual predicates * which are to be evaluated together. * @param values The values associated with each context. * @return An array of the probabilities for each of the different * outcomes, all of which sum to {@code 1}. */ double[] eval(String[] context, float[] values); /** * Retrieves the outcome associated with the index * containing the highest probability in the double[]. * * @param outcomes A {@code double[]} as returned by the * {@link #eval(String[])} method. * @return The String name of the best outcome. **/ String getBestOutcome(double[] outcomes); /** * Retrieves a string matching all the outcome names with all the * probabilities produced by the {@link #eval(String[])} method. * * @param outcomes A {@code double[]} as returned by the * {@link #eval(String[])} method. * @return String containing outcome names paired with the normalized * probability (contained in the {@code double[] ocs}) * for each one. **/ // TODO: This should be removed, can't be used anyway without format spec String getAllOutcomes(double[] outcomes); /** * Retrieves the String name of the outcome associated with the index {@code i}. * * @param i The index for which the name of the associated outcome is * desired. * @return The String name of the outcome **/ String getOutcome(int i); /** * Retrieves the index associated with the String name of the given * outcome. * * @param outcome The String name of the outcome for which the * index is desired, * @return The index if the given outcome label exists for this * model, {@code -1} if it does not. **/ int getIndex(String outcome); /** * @return Retrieves the number of outcomes for this model. **/ int getNumOutcomes(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_ModelPa0100644 0000000 0000000 00000000161 15217274217 032430 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ModelParameterChunker.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ModelParameterChunker.j0100644 0000000 0000000 00000014171 15217274217 034017 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.UTFDataFormatException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; /** * A helper class that handles Strings with more than 64k (65535 bytes) in length. * This is achieved via the signature {@link #SIGNATURE_CHUNKED_PARAMS} at the beginning of * the String instance to be written to a {@link DataOutputStream}. *

* Background: In OpenNLP, for large(r) corpora, we train models whose (UTF String) parameters will exceed * the {@link #MAX_CHUNK_SIZE_BYTES} bytes limit set in {@link DataOutputStream}. * For writing and reading those models, we have to chunk up those string instances in 64kB blocks and * recombine them correctly upon reading a (binary) model file. *

* The problem was raised in ticket OPENNLP-1366. *

* Solution strategy: *

    *
  • If writing parameters to a {@link DataOutputStream} blows up with a {@link UTFDataFormatException} a * large String instance is chunked up and written as appropriate blocks.
  • *
  • To indicate that chunking was conducted, we start with the {@link #SIGNATURE_CHUNKED_PARAMS} indicator, * directly followed by the number of chunks used. This way, when reading in chunked model parameters, * recombination is achieved transparently.
  • *
*

* Note: Both, existing (binary) model files and newly trained models which don't require the chunking * technique, will be supported like in previous OpenNLP versions. * * @author Martin Wiesner * @author Mark Struberg */ public final class ModelParameterChunker { /* * A signature that denotes the start of a String that required chunking. * * Semantics: * If a model parameter (String) carries the below signature at the very beginning, this indicates * that 'n > 1' chunks must be processed to obtain the whole model parameters. Otherwise, those would not be * written to the binary model files (as reported in OPENNLP-1366) if the training occurs on large corpora * as used, for instance, in the context of (very large) German NLP models. */ public static final String SIGNATURE_CHUNKED_PARAMS = "CHUNKED-MODEL-PARAMS:"; // followed by no of chunks! private static final int MAX_CHUNK_SIZE_BYTES = 65535; // the maximum 'utflen' DataOutputStream can handle private ModelParameterChunker() { // private utility class ct s } /** * Reads model parameters from {@code dis}. In case the stream start with {@link #SIGNATURE_CHUNKED_PARAMS}, * the number of chunks is detected and the original large parameter string is reconstructed from several * chunks. * * @param dis The stream which will be used to read the model parameter from. */ public static String readUTF(DataInputStream dis) throws IOException { String data = dis.readUTF(); if (data.startsWith(SIGNATURE_CHUNKED_PARAMS)) { String chunkElements = data.replace(SIGNATURE_CHUNKED_PARAMS, ""); int chunkSize = Integer.parseInt(chunkElements); StringBuilder sb = new StringBuilder(); for (int i = 0; i < chunkSize; i++) { sb.append(dis.readUTF()); } return sb.toString(); // the reconstructed model parameter string } else { // default case: no chunked data -> just return the read data / parameter information return data; } } /** * Writes the model parameter {@code s} to {@code dos}. In case {@code s} does exceed * {@link #MAX_CHUNK_SIZE_BYTES} in length, the chunking mechanism is used; otherwise the parameter is * written 'as is'. * * @param dos The {@link DataOutputStream} stream which will be used to persist the model. * @param s The input string that is checked for length and chunked if {@link #MAX_CHUNK_SIZE_BYTES} is * exceeded. */ public static void writeUTF(DataOutputStream dos, String s) throws IOException { try { dos.writeUTF(s); } catch (UTFDataFormatException dfe) { // we definitely have to chunk the given model parameter 's' as it exceeds the bytes allowed for 1 chunk final String[] chunks = splitByByteLength(s); // write the signature string with the amount of chunks for reading the model file correctly dos.writeUTF(SIGNATURE_CHUNKED_PARAMS + chunks.length); // add number of required chunks for (String c: chunks) { dos.writeUTF(c); } } } private static String[] splitByByteLength(String input) { CharBuffer in = CharBuffer.wrap(input); ByteBuffer out = ByteBuffer.allocate(MAX_CHUNK_SIZE_BYTES); // output buffer of required size CharsetEncoder coder = StandardCharsets.UTF_8.newEncoder(); List chunks = new ArrayList<>(); int pos = 0; while (true) { CoderResult cr = coder.encode(in, out, true); int nPos = input.length() - in.length(); String s = input.substring(pos, nPos); chunks.add(s); pos = nPos; out.rewind(); if (! cr.isOverflow()) { break; } } return chunks.toArray(new String[0]); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/MutableContext.java0100644 0000000 0000000 00000004411 15217274217 033220 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.Arrays; /** * An extension of {@link Context} used to store parameters or expected values * associated with this context which can be updated or assigned. * * @see Context */ public class MutableContext extends Context { /** * Creates a new parameters object with the specified parameters associated with the specified * outcome pattern. * * @param outcomePattern Array of outcomes for which parameters exists for this context. * @param parameters Parameters for the outcomes specified. */ public MutableContext(int[] outcomePattern, double[] parameters) { super(outcomePattern, parameters); } /** * Assigns the parameter or expected value at the specified outcomeIndex the specified value. * * @param outcomeIndex The index of the parameter or expected value to be updated. * @param value The value to be assigned. */ public void setParameter(int outcomeIndex, double value) { parameters[outcomeIndex] = value; } /** * Updated the parameter or expected value at the specified outcomeIndex by * adding the specified value to its current value. * * @param outcomeIndex The index of the parameter or expected value to be updated. * @param value The value to be added. */ public void updateParameter(int outcomeIndex, double value) { parameters[outcomeIndex] += value; } public boolean contains(int outcome) { return Arrays.binarySearch(outcomes,outcome) >= 0; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/ObjectDataReader.java0100644 0000000 0000000 00000003154 15217274217 033410 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.IOException; import java.io.ObjectInputStream; /** * A {@link DataReader} implementation based on {@link ObjectInputStream}. */ public class ObjectDataReader implements DataReader { protected final ObjectInputStream ois; /** * Instantiates an {@link ObjectDataReader}. * * @param ois The open {@link ObjectInputStream} to use. */ public ObjectDataReader(ObjectInputStream ois) { this.ois = ois; } /** * {@inheritDoc} */ @Override public double readDouble() throws IOException { return ois.readDouble(); } /** * {@inheritDoc} */ @Override public int readInt() throws IOException { return ois.readInt(); } /** * {@inheritDoc} */ @Override public String readUTF() throws IOException { return ois.readUTF(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_OnePass0100644 0000000 0000000 00000000156 15217274217 032463 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/OnePassDataIndexer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/OnePassDataIndexer.java0100644 0000000 0000000 00000007633 15217274217 033754 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.IOException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.ObjectStreamUtils; import opennlp.tools.util.TrainingParameters; /** * A {@link DataIndexer} for maxent model data which handles cutoffs for uncommon * contextual predicates and provides a unique integer index for each of the * predicates. * * @see DataIndexer * @see AbstractDataIndexer */ public class OnePassDataIndexer extends AbstractDataIndexer { private static final Logger logger = LoggerFactory.getLogger(OnePassDataIndexer.class); public OnePassDataIndexer() {} /** * {@inheritDoc} */ @Override public void index(ObjectStream eventStream) throws IOException { int cutoff = trainingParameters.getIntParameter(TrainingParameters.CUTOFF_PARAM, TrainingParameters.CUTOFF_DEFAULT_VALUE); boolean sort = trainingParameters.getBooleanParameter(SORT_PARAM, SORT_DEFAULT); long start = System.currentTimeMillis(); logger.info("Indexing events with OnePass using cutoff of {}", cutoff); logger.info("Computing event counts..."); Map predicateIndex = new HashMap<>(); List events = computeEventCounts(eventStream, predicateIndex, cutoff); logger.info("done. {} events", events.size()); logger.info("Indexing... "); List eventsToCompare = index(ObjectStreamUtils.createObjectStream(events), predicateIndex); logger.info("done."); logger.info("Sorting and merging events... "); sortAndMerge(eventsToCompare, sort); logger.info(String.format("Done indexing in %.2f s.", (System.currentTimeMillis() - start) / 1000d)); } /** * Reads events from eventStream into a linked list. The predicates * associated with each event are counted and any which occur at least * cutoff times are added to the predicatesInOut map along * with a unique integer index. * * @param eventStream * an EventStream value * @param predicatesInOut * a TObjectIntHashMap value * @param cutoff * an int value * @return a TLinkedList value */ private List computeEventCounts(ObjectStream eventStream, Map predicatesInOut, int cutoff) throws IOException { Map counter = new HashMap<>(); List events = new LinkedList<>(); Event ev; while ((ev = eventStream.read()) != null) { events.add(ev); update(ev.getContext(), counter); } String[] predicateSet = counter.entrySet().stream() .filter(entry -> entry.getValue() >= cutoff) .map(Map.Entry::getKey).sorted() .toArray(String[]::new); predCounts = new int[predicateSet.length]; for (int i = 0; i < predicateSet.length; i++) { predCounts[i] = counter.get(predicateSet[i]); predicatesInOut.put(predicateSet[i], i); } return events; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_OnePass0100644 0000000 0000000 00000000167 15217274217 032465 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/OnePassRealValueDataIndexer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/OnePassRealValueDataInd0100644 0000000 0000000 00000003640 15217274217 033743 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.List; import opennlp.tools.util.InsufficientTrainingDataException; /** * A {@link DataIndexer} for maxent model data which handles cutoffs for uncommon * contextual predicates and provides a unique integer index for each of the * predicates and maintains event values. * * @see DataIndexer * @see AbstractDataIndexer */ public class OnePassRealValueDataIndexer extends OnePassDataIndexer { private float[][] values; public OnePassRealValueDataIndexer() { } @Override public float[][] getValues() { return values; } @Override protected int sortAndMerge(List eventsToCompare, boolean sort) throws InsufficientTrainingDataException { int numUniqueEvents = super.sortAndMerge(eventsToCompare,sort); values = new float[numUniqueEvents][]; int numEvents = eventsToCompare.size(); for (int i = 0, j = 0; i < numEvents; i++) { ComparableEvent evt = eventsToCompare.get(i); if (null == evt) { continue; // this was a dupe, skip over it. } values[j++] = evt.values; } return numUniqueEvents; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_PlainTe0100644 0000000 0000000 00000000163 15217274217 032445 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/PlainTextFileDataReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/PlainTextFileDataReader0100644 0000000 0000000 00000005441 15217274217 033773 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.zip.GZIPInputStream; /** * A generic {@link DataReader} implementation for plain text files. * * @see DataReader */ public class PlainTextFileDataReader implements DataReader { private final BufferedReader input; /** * Initializes a {@link PlainTextFileDataReader} via a {@link File}. * * @param f The {@link File} that references the model to be read. * * @throws IOException Thrown if IO errors occurred. */ public PlainTextFileDataReader(File f) throws IOException { if (f.getName().endsWith(".gz")) { input = new BufferedReader(new InputStreamReader(new BufferedInputStream( new GZIPInputStream(new BufferedInputStream(new FileInputStream(f)))))); } else { input = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(f)))); } } /** * Initializes a {@link PlainTextFileDataReader} via a {@link InputStream}. * * @param in The {@link InputStream} that references the file to be read. */ public PlainTextFileDataReader(InputStream in) { input = new BufferedReader(new InputStreamReader(in)); } /** * Initializes a {@link PlainTextFileDataReader} via a {@link BufferedReader}. * * @param in The {@link BufferedReader} that references the file to be read. */ public PlainTextFileDataReader(BufferedReader in) { input = in; } /** * {@inheritDoc} */ @Override public double readDouble() throws IOException { return Double.parseDouble(input.readLine()); } /** * {@inheritDoc} */ @Override public int readInt() throws IOException { return Integer.parseInt(input.readLine()); } /** * {@inheritDoc} */ @Override public String readUTF() throws IOException { return input.readLine(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/Prior.java0100644 0000000 0000000 00000005353 15217274217 031363 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; /** * This interface allows one to implement a prior distribution for use in * maximum entropy model training. */ public interface Prior { /** * Populates the specified array with the log of the distribution for the specified context. * The returned array will be overwritten and needs to be re-initialized with every call to this method. * @param dist An array to be populated with the log of the prior distribution. * @param context The indices of the contextual predicates for an event. */ void logPrior(double[] dist, int[] context); /** * Populates the specified array with the log of the distribution for the specified context. * The returned array will be overwritten and needs to be re-initialized with every call to this method. * @param dist An array to be populated with the log of the prior distribution. * @param context The indices of the contextual predicates for an event. * @param values The values associated with the context. */ void logPrior(double[] dist, int[] context, float[] values); /** * Populates the specified array with the log of the distribution for the specified context. * The returned array will be overwritten and needs to be re-initialized with every call to this method. * @param dist An array to be populated with the log of the prior distribution. * @param context The indices of the contextual predicates for an event. * @param values The values associated with the context. */ void logPrior(double[] dist, Context[] context, float[] values); /** * Method to specify the label for the outcomes and contexts. This is used to map * integer outcomes and contexts to their string values. This method is called prior * to any call to {@link #logPrior}. * @param outcomeLabels An array of each outcome label. * @param contextLabels An array of each context label. */ void setLabels(String[] outcomeLabels, String[] contextLabels); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_RealVal0100644 0000000 0000000 00000000164 15217274217 032440 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/RealValueFileEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/RealValueFileEventStrea0100644 0000000 0000000 00000011463 15217274217 034030 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.File; import java.io.IOException; import java.io.Reader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.ObjectStream; /** * Class for using a file of real-valued {@link Event events} as an * {@link ObjectStream event stream}. * The format of the file is one event per line with * each line consisting of outcome followed by contexts (space delimited). * * @see Event * @see FileEventStream */ public class RealValueFileEventStream extends FileEventStream { private static final Logger logger = LoggerFactory.getLogger(RealValueFileEventStream.class); /** * Instantiates a {@link RealValueFileEventStream} from the specified file name. * * @param fileName The name fo the file containing the events. * * @throws IOException Thrown if the specified file can not be read. */ public RealValueFileEventStream(String fileName) throws IOException { super(fileName); } /** * Instantiates a {@link RealValueFileEventStream} from the specified file name. * * @param fileName The name fo the file containing the events. * @param encoding The name of the {@link java.nio.charset.Charset character encoding}. * * @throws IOException Thrown if the specified file can not be read. */ public RealValueFileEventStream(String fileName, String encoding) throws IOException { super(fileName, encoding); } /** * Instantiates a {@link RealValueFileEventStream} via a {@link File}. * * @param file The {@link File} that holds events. * * @throws IOException Thrown if the specified file can not be read. */ public RealValueFileEventStream(File file) throws IOException { super(file); } /** * Instantiates a {@link RealValueFileEventStream} via a {@link Reader}. * * @param reader The {@link Reader} that holds events. * * @throws IOException Thrown if the specified file can not be read. */ public RealValueFileEventStream(Reader reader) throws IOException { super(reader); } /** * Parses the specified {@code contexts} and re-populates context array with features * and returns the values for these features. If all values are unspecified, * then {@code null} is returned. * * @param contexts The contexts with real values specified. * @return The value for each context or {@code null} if all values are unspecified. * * @throws RuntimeException Thrown if negative real values are detected in the input data. */ public static float[] parseContexts(String[] contexts) { boolean hasRealValue = false; float[] values = new float[contexts.length]; for (int ci = 0; ci < contexts.length; ci++) { int ei = contexts[ci].lastIndexOf("="); if (ei > 0 && ei + 1 < contexts[ci].length()) { boolean gotReal = true; try { values[ci] = Float.parseFloat(contexts[ci].substring(ei + 1)); } catch (NumberFormatException e) { gotReal = false; logger.error("Unable to determine value in context: {}", contexts[ci]); values[ci] = 1; } if (gotReal) { if (values[ci] < 0) { throw new RuntimeException("Negative values are not allowed: " + contexts[ci]); } contexts[ci] = contexts[ci].substring(0, ei); hasRealValue = true; } } else { values[ci] = 1; } } if (!hasRealValue) { values = null; } return values; } /** * {@inheritDoc} * * @throws IOException Thrown if there is an error during reading. * @throws RuntimeException Thrown if negative real values are detected in the input data. */ @Override public Event read() throws IOException { String line; if ((line = reader.readLine()) != null) { int si = line.indexOf(' '); String outcome = line.substring(0, si); String[] contexts = line.substring(si + 1).split("\\s+"); float[] values = parseContexts(contexts); return new Event(outcome, contexts, values); } return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/Sequence.java0100644 0000000 0000000 00000003455 15217274217 032041 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; /** * Class which models a sequence. * @param The type of the object which is the source of this sequence. */ public class Sequence { private final Event[] events; private final T source; /** * Initializes {@link Sequence} made up of the specified events and derived from the * specified source. * * @param events The {@link Event events} of the sequence. * @param source The {@link T source object} for this sequence. */ public Sequence(Event[] events, T source) { this.events = events; this.source = source; } /** * @return Retrieves the events which make up this sequence. */ public Event[] getEvents() { return events; } /** * This object is used when the events for this sequence need to be re-derived such * as in a call to {@link SequenceStream#updateContext(Sequence, AbstractModel)}. * * @return Retrieves an object from which this sequence can be derived. */ public T getSource() { return source; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Sequenc0100644 0000000 0000000 00000000167 15217274217 032520 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/SequenceClassificationModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/SequenceClassificationM0100644 0000000 0000000 00000006213 15217274217 034105 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import opennlp.tools.util.BeamSearchContextGenerator; import opennlp.tools.util.Sequence; import opennlp.tools.util.SequenceValidator; /** * A classification model that can label an input {@link Sequence}. */ public interface SequenceClassificationModel { /** * Finds the {@link Sequence} with the highest probability. * * @param sequence The {@link T sequence} used as input. * @param additionalContext An array that provides additional information (context). * @param cg The {@link BeamSearchContextGenerator} to use. * @param validator The {@link SequenceValidator} to validate with. * * @return The {@link Sequence} with the highest probability. */ Sequence bestSequence(T[] sequence, Object[] additionalContext, BeamSearchContextGenerator cg, SequenceValidator validator); /** * Finds the n most probable {@link Sequence sequences} with the highest probability. * * @param numSequences The number of sequences to compute. * @param sequence The {@link T sequence} used as input. * @param additionalContext An array that provides additional information (context). * @param minSequenceScore The minimum score to achieve. * @param cg The {@link BeamSearchContextGenerator} to use. * @param validator The {@link SequenceValidator} to validate with. * * @return The {@link Sequence sequences} with the highest probability. */ Sequence[] bestSequences(int numSequences, T[] sequence, Object[] additionalContext, double minSequenceScore, BeamSearchContextGenerator cg, SequenceValidator validator); /** * Finds the n most probable {@link Sequence sequences} with the highest probability. * * @param numSequences The number of sequences to compute. * @param sequence The {@link T sequence} used as input. * @param additionalContext An array that provides additional information (context). * @param cg The {@link BeamSearchContextGenerator} to use. * @param validator The {@link SequenceValidator} to validate with. * * @return The {@link Sequence sequences} with the highest probability. */ Sequence[] bestSequences(int numSequences, T[] sequence, Object[] additionalContext, BeamSearchContextGenerator cg, SequenceValidator validator); /** * @return Retrieves all possible outcomes. */ String[] getOutcomes(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/SequenceStream.java0100644 0000000 0000000 00000002714 15217274217 033212 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import opennlp.tools.util.ObjectStream; /** * Interface for streams of {@link Sequence sequences} used to train sequence models. * * @see Event * @see ObjectStream */ public interface SequenceStream extends ObjectStream> { /** * Creates a new event array based on the outcomes predicted by the specified parameters * for the specified {@link Sequence}. * * @param sequence The {@link Sequence} to be evaluated. * @param model The {@link AbstractModel model} to use. * * @return The resulting {@link Event} array. */ Event[] updateContext(Sequence sequence, AbstractModel model); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_Sequenc0100644 0000000 0000000 00000000165 15217274217 032516 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/SequenceStreamEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/SequenceStreamEventStre0100644 0000000 0000000 00000003754 15217274217 034137 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import opennlp.tools.util.ObjectStream; /** * Class which turns a {@link SequenceStream} into an event stream. * * @see Event * @see ObjectStream */ public class SequenceStreamEventStream implements ObjectStream { private final SequenceStream sequenceStream; private Iterator eventIt = Collections.emptyListIterator(); public SequenceStreamEventStream(SequenceStream sequenceStream) { this.sequenceStream = sequenceStream; } @Override public Event read() throws IOException { while (!eventIt.hasNext()) { Sequence sequence = sequenceStream.read(); if (sequence == null) { return null; } eventIt = Arrays.asList(sequence.getEvents()).iterator(); } return eventIt.next(); } @Override public void reset() throws IOException, UnsupportedOperationException { eventIt = Collections.emptyListIterator(); sequenceStream.reset(); } @Override public void close() throws IOException { eventIt = Collections.emptyListIterator(); sequenceStream.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_model_TwoPass0100644 0000000 0000000 00000000156 15217274217 032513 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/TwoPassDataIndexer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/TwoPassDataIndexer.java0100644 0000000 0000000 00000016407 15217274217 034003 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.CRC32C; import java.util.zip.CheckedInputStream; import java.util.zip.CheckedOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; /** * Collecting event and context counts by making two passes over the events. *

* The first pass determines which contexts will be used by the model, and the * second pass creates the events in memory containing only the contexts which * will be used. This greatly reduces the amount of memory required for storing * the events. During the first pass a temporary event file is created which * is read during the second pass. * * @see DataIndexer * @see AbstractDataIndexer */ public class TwoPassDataIndexer extends AbstractDataIndexer { private static final Logger logger = LoggerFactory.getLogger(TwoPassDataIndexer.class); public TwoPassDataIndexer() {} /** * {@inheritDoc} */ @Override public void index(ObjectStream eventStream) throws IOException { int cutoff = trainingParameters.getIntParameter(TrainingParameters.CUTOFF_PARAM, TrainingParameters.CUTOFF_DEFAULT_VALUE); boolean sort = trainingParameters.getBooleanParameter(SORT_PARAM, SORT_DEFAULT); logger.info("Indexing events with TwoPass using cutoff of {}", cutoff); logger.info("Computing event counts..."); long start = System.currentTimeMillis(); Map predicateIndex = new HashMap<>(); File tmp = Files.createTempFile("events", null).toFile(); tmp.deleteOnExit(); int numEvents; long writeChecksum; try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(tmp)); CheckedOutputStream writeStream = new CheckedOutputStream(out, new CRC32C()); DataOutputStream dos = new DataOutputStream(writeStream)) { numEvents = computeEventCounts(eventStream, dos, predicateIndex, cutoff); writeChecksum = writeStream.getChecksum().getValue(); logger.info("done. {} events", numEvents); } List eventsToCompare; long readChecksum; try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(tmp)); CheckedInputStream readStream = new CheckedInputStream(in, new CRC32C()); EventStream readEventsStream = new EventStream(new DataInputStream(readStream))) { logger.info("Indexing..."); eventsToCompare = index(readEventsStream, predicateIndex); readChecksum = readStream.getChecksum().getValue(); } tmp.delete(); if (readChecksum != writeChecksum) { throw new IOException("Checksum for writing and reading events did not match."); } else { logger.info("done."); if (sort) { logger.info("Sorting and merging events... "); } else { logger.info("Collecting events... "); } sortAndMerge(eventsToCompare,sort); logger.info(String.format("Done indexing in %.2f s.", (System.currentTimeMillis() - start) / 1000d)); } } /** * Reads events from eventStream into a linked list. The * predicates associated with each event are counted and any which * occur at least cutoff times are added to the * predicatesInOut map along with a unique integer index. *

* Protocol: * 1 - (utf string) - Event outcome * 2 - (int) - Event context array length * 3+ - (utf string) - Event context string * 4 - (int) - Event values array length * 5+ - (float) - Event value * * @param eventStream an EventStream value * @param eventStore a writer to which the events are written to for later processing. * @param predicatesInOut a TObjectIntHashMap value * @param cutoff an int value */ private int computeEventCounts(ObjectStream eventStream, DataOutputStream eventStore, Map predicatesInOut, int cutoff) throws IOException { Map counter = new HashMap<>(); int eventCount = 0; Event ev; while ((ev = eventStream.read()) != null) { eventCount++; eventStore.writeUTF(ev.getOutcome()); eventStore.writeInt(ev.getContext().length); String[] ec = ev.getContext(); update(ec, counter); for (String ctxString : ec) eventStore.writeUTF(ctxString); if (ev.getValues() == null) { eventStore.writeInt(0); } else { eventStore.writeInt(ev.getValues().length); for (float value : ev.getValues()) eventStore.writeFloat(value); } } String[] predicateSet = counter.entrySet().stream() .filter(entry -> entry.getValue() >= cutoff) .map(Map.Entry::getKey).sorted() .toArray(String[]::new); predCounts = new int[predicateSet.length]; for (int i = 0; i < predicateSet.length; i++) { predCounts[i] = counter.get(predicateSet[i]); predicatesInOut.put(predicateSet[i], i); } return eventCount; } private static class EventStream implements ObjectStream { private final DataInputStream inputStream; public EventStream(DataInputStream dataInputStream) { this.inputStream = dataInputStream; } @Override public Event read() throws IOException { if (inputStream.available() != 0) { String outcome = inputStream.readUTF(); int contextLength = inputStream.readInt(); String[] context = new String[contextLength]; for (int i = 0; i < contextLength; i++) context[i] = inputStream.readUTF(); int valuesLength = inputStream.readInt(); float[] values = null; if (valuesLength > 0) { values = new float[valuesLength]; for (int i = 0; i < valuesLength; i++) values[i] = inputStream.readFloat(); } return new Event(outcome, context, values); } else { return null; } } @Override public void reset() throws IOException, UnsupportedOperationException { throw new UnsupportedOperationException(); } @Override public void close() throws IOException { inputStream.close(); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/UniformPrior.java0100644 0000000 0000000 00000003613 15217274217 032720 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.model; import java.util.Objects; /** * Provide a maximum entropy model with a uniform {@link Prior}. */ public class UniformPrior implements Prior { private int numOutcomes; private double r; @Override public void logPrior(double[] dist, int[] context, float[] values) { for (int oi = 0; oi < numOutcomes; oi++) { dist[oi] = r; } } @Override public void logPrior(double[] dist, Context[] context, float[] values) { logPrior(dist, (int[]) null, values); } @Override public void logPrior(double[] dist, int[] context) { logPrior(dist,context,null); } @Override public void setLabels(String[] outcomeLabels, String[] contextLabels) { this.numOutcomes = outcomeLabels.length; r = StrictMath.log(1.0 / numOutcomes); } @Override public int hashCode() { return Objects.hash(numOutcomes, r); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof UniformPrior prior) { return numOutcomes == prior.numOutcomes && r == prior.r; } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/model/package-info.java0100644 0000000 0000000 00000001614 15217274217 032610 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to ML models and feature selection techniques. */ package opennlp.tools.ml.model; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Bi0100644 0000000 0000000 00000000174 15217274217 032473 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/BinaryNaiveBayesModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/BinaryNaiveBayesMo0100644 0000000 0000000 00000003555 15217274217 034067 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import opennlp.tools.ml.model.BinaryFileDataReader; /** * A {@link NaiveBayesModelReader} that reads models from a binary format. */ public class BinaryNaiveBayesModelReader extends NaiveBayesModelReader { /** * Instantiates {@link BinaryNaiveBayesModelReader} via a {@link DataInputStream} * containing the model contents. * * @param dis The {@link DataInputStream} containing the model information. * It must be open and have bytes available. */ public BinaryNaiveBayesModelReader(DataInputStream dis) { super(new BinaryFileDataReader(dis)); } /** * Instantiates {@link BinaryNaiveBayesModelReader} via a {@link File} and creates * a reader for it. Based on whether the file's suffix contains {@code .gz}, * it detects whether the file is gzipped or not. * * @param f The {@link File} that references the model to be read. */ public BinaryNaiveBayesModelReader(File f) throws IOException { super(f); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Bi0100644 0000000 0000000 00000000174 15217274217 032473 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/BinaryNaiveBayesModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/BinaryNaiveBayesMo0100644 0000000 0000000 00000006021 15217274217 034056 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.ModelParameterChunker; /** * A {@link NaiveBayesModelWriter} that writes models in a binary format. */ public class BinaryNaiveBayesModelWriter extends NaiveBayesModelWriter { private final DataOutputStream output; /** * Instantiates {@link BinaryNaiveBayesModelWriter} via an * {@link AbstractModel naive bayes model} and a {@link File}. * Prepares writing of a {@code model} to the file. * Based on whether the file's suffix contains {@code .gz}, it detects whether * the file is gzipped or not. * * @param model The {@link AbstractModel naive bayes model} which is to be persisted. * @param f The {@link File} in which the model is to be persisted. * * @throws IOException Thrown if IO errors occurred. * @see NaiveBayesModel */ public BinaryNaiveBayesModelWriter(AbstractModel model, File f) throws IOException { super(model); if (f.getName().endsWith(".gz")) { output = new DataOutputStream( new GZIPOutputStream(new FileOutputStream(f))); } else { output = new DataOutputStream(new FileOutputStream(f)); } } /** * Instantiates {@link BinaryNaiveBayesModelWriter} via * an {@link AbstractModel naive bayes model} and a {@link DataOutputStream}. * * @param model The {@link AbstractModel naive bayes model} which is to be persisted. * @param dos The {@link DataOutputStream} which is used to persist the {@code model}. * The {@code dos} must be opened. */ public BinaryNaiveBayesModelWriter(AbstractModel model, DataOutputStream dos) { super(model); output = dos; } @Override public void writeUTF(String s) throws IOException { ModelParameterChunker.writeUTF(output, s); } @Override public void writeInt(int i) throws IOException { output.writeInt(i); } @Override public void writeDouble(double d) throws IOException { output.writeDouble(d); } @Override public void close() throws IOException { output.flush(); output.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Lo0100644 0000000 0000000 00000000161 15217274217 032507 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/LogProbabilities.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/LogProbabilities.j0100644 0000000 0000000 00000014437 15217274217 034063 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.util.ArrayList; import java.util.Map; import java.util.Map.Entry; /** * Class implementing the probability distribution over labels returned by * a classifier as a log of probabilities. *

* This is necessary because floating point precision in Java does not allow for high-accuracy * representation of very low probabilities such as would occur in a text categorizer. * * @param the label (category) class * * @see Probabilities */ public class LogProbabilities extends Probabilities { /** * Assigns a {@code probability} to a label {@code t}, * discarding any previously assigned probability. * * @param t The label to which the probability is being assigned. * @param probability The probability to assign. */ @Override public void set(T t, double probability) { isNormalised = false; map.put(t, log(probability)); } /** * Assigns a {@code probability} to a label {@code t}, * discarding any previously assigned probability. * * @param t The label to which the probability is being assigned. * @param probability The {@link Probability} to assign. */ @Override public void set(T t, Probability probability) { isNormalised = false; map.put(t, probability.getLog()); } /** * Assigns a {@code probability} to a label {@code t}, * discarding any previously assigned probability, * if the new probability is greater than the old one. * * @param t The label to which the probability is being assigned. * @param probability The probability to assign. */ @Override public void setIfLarger(T t, double probability) { double logProbability = log(probability); Double p = map.get(t); if (p == null || logProbability > p) { isNormalised = false; map.put(t, logProbability); } } /** * Assigns a log {@code probability} to a label {@code t}, * discarding any previously assigned probability. * * @param t The label to which the log probability is being assigned. * @param probability The log {@code probability} to assign. */ @Override public void setLog(T t, double probability) { isNormalised = false; map.put(t, probability); } /** * Compounds the existing {@code probability} mass on the label {@code t} * with the new probability passed in to the method. * * @param t The label whose {@code probability} mass is being updated. * @param probability The probability weight to add. * @param count The amplifying factor for the {@code probability} compounding. */ @Override public void addIn(T t, double probability, int count) { isNormalised = false; Double p = map.get(t); if (p == null) p = 0.0; probability = log(probability) * count; map.put(t, p + probability); } private Map normalize() { if (isNormalised) return normalised; Map temp = createMapDataStructure(); double highestLogProbability = Double.NEGATIVE_INFINITY; for (Entry entry : map.entrySet()) { final Double p = entry.getValue(); if (p != null && p > highestLogProbability) { highestLogProbability = p; } } double sum = 0; for (Entry entry : map.entrySet()) { T t = entry.getKey(); Double p = entry.getValue(); if (p != null) { double temp_p = StrictMath.exp(p - highestLogProbability); if (!Double.isNaN(temp_p)) { sum += temp_p; temp.put(t, temp_p); } } } for (Entry entry : temp.entrySet()) { final T t = entry.getKey(); final Double p = entry.getValue(); if (p != null && sum > Double.MIN_VALUE) { temp.put(t, p / sum); } } normalised = temp; isNormalised = true; return temp; } private double log(double prob) { return StrictMath.log(prob); } /** * @param t The label whose probability shall be returned. * @return Retrieves the probability associated with the label {@code t}. */ @Override public Double get(T t) { Double d = normalize().get(t); if (d == null) return 0.0; return d; } /** * @param t The label whose log probability shall be returned. * @return Retrieves the log probability associated with the label {@code t}. */ @Override public Double getLog(T t) { Double d = map.get(t); if (d == null) return Double.NEGATIVE_INFINITY; return d; } @Override public void discardCountsBelow(double i) { i = StrictMath.log(i); ArrayList labelsToRemove = new ArrayList<>(); for (Entry entry : map.entrySet()) { final T label = entry.getKey(); Double sum = entry.getValue(); if (sum == null) sum = Double.NEGATIVE_INFINITY; if (sum < i) labelsToRemove.add(label); } for (T label : labelsToRemove) { map.remove(label); } } /** * @return Retrieves a {@link Map} of all labels and their probabilities. */ @Override public Map getAll() { return normalize(); } /** * @return Retrieves the label that has the highest associated probability */ @Override public T getMax() { double max = Double.NEGATIVE_INFINITY; T maxT = null; for (Entry entry : map.entrySet()) { final T t = entry.getKey(); final Double temp = entry.getValue(); if (temp >= max) { max = temp; maxT = t; } } return maxT; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Lo0100644 0000000 0000000 00000000157 15217274217 032514 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/LogProbability.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/LogProbability.jav0100644 0000000 0000000 00000007414 15217274217 034077 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; /** * A class implementing the logarithmic {@link Probability} for a label. * * @param The label (category) class. * */ public class LogProbability extends Probability { public LogProbability(T label) { super(label); set(1.0); } /** * Assigns a {@code probability} to a label, discarding any previously assigned probability. * * @param probability The probability to assign. */ @Override public void set(double probability) { this.probability = StrictMath.log(probability); } /** * Assigns a {@code probability} to a label, discarding any previously assigned probability. * * @param probability The {@link Probability} to assign. */ @Override public void set(Probability probability) { this.probability = probability.getLog(); } /** * Assigns a {@code probability} to a label, discarding any previously assigned probability, * if the new probability is greater than the old one. * * @param probability The probability to assign. */ @Override public void setIfLarger(double probability) { double logP = StrictMath.log(probability); if (this.probability < logP) { this.probability = logP; } } /** * Assigns a {@code probability} to a label, discarding any previously assigned probability, * if the new probability is greater than the old one. * * @param probability The {@link Probability} to assign. */ @Override public void setIfLarger(Probability probability) { if (this.probability < probability.getLog()) { this.probability = probability.getLog(); } } /** * @param probability the probability to check * @return {@code true} if a probability is greater than the old one, {@code false} otherwise. */ @Override public boolean isLarger(Probability probability) { return this.probability < probability.getLog(); } /** * Assigns a log {@code probability} to a label, discarding any previously assigned probability. * * @param probability The log probability to assign. */ @Override public void setLog(double probability) { this.probability = probability; } /** * Compounds the existing {@code probability} mass on the label with the new * probability passed in to the method. * * @param probability The probability weight to add. */ @Override public void addIn(double probability) { setLog(this.probability + StrictMath.log(probability)); } /** * @return Retrieves the probability associated with a label. */ @Override public Double get() { return StrictMath.exp(probability); } /** * @return Retrieves the log probability associated with a label. */ @Override public Double getLog() { return probability; } /** * @return Retrieves the probabilities associated with all labels, */ @Override public T getLabel() { return label; } @Override public String toString() { return label + ":" + probability; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Na0100644 0000000 0000000 00000000171 15217274217 032474 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesEvalParameters.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesEvalPara0100644 0000000 0000000 00000003063 15217274217 034034 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.EvalParameters; /** * Specialized {@link EvalParameters parameters} for the evaluation of a naive bayes classifier * * @see EvalParameters */ public class NaiveBayesEvalParameters extends EvalParameters { protected final double[] outcomeTotals; protected final long vocabulary; public NaiveBayesEvalParameters(Context[] params, int numOutcomes, double[] outcomeTotals, long vocabulary) { super(params, numOutcomes); this.outcomeTotals = outcomeTotals; this.vocabulary = vocabulary; } public double[] getOutcomeTotals() { return outcomeTotals; } public long getVocabulary() { return vocabulary; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Na0100644 0000000 0000000 00000000160 15217274217 032472 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesModel.ja0100644 0000000 0000000 00000017224 15217274217 033776 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.util.Map; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.EvalParameters; import opennlp.tools.ml.model.MaxentModel; /** * A {@link MaxentModel} implementation of the multinomial Naive Bayes classifier model. * * @see AbstractModel * @see MaxentModel */ public class NaiveBayesModel extends AbstractModel { protected final double[] outcomeTotals; protected long vocabulary; /** * Initializes a {@link NaiveBayesModel}. * * @param params The {@link Context parameters} to set. * @param predLabels The predicted labels. * @param pmap A {@link Map} that provides a mapping between predicates and contexts. * @param outcomeNames The names of the outcomes. */ NaiveBayesModel(Context[] params, String[] predLabels, Map pmap, String[] outcomeNames) { super(params, predLabels, pmap, outcomeNames); outcomeTotals = initOutcomeTotals(outcomeNames, params); this.evalParams = new NaiveBayesEvalParameters(params, outcomeNames.length, outcomeTotals, predLabels.length); modelType = ModelType.NaiveBayes; } /** * Initializes a {@link NaiveBayesModel}. * * @param params The {@link Context parameters} to set. * @param predLabels The predicted labels. * @param outcomeNames The names of the outcomes. */ public NaiveBayesModel(Context[] params, String[] predLabels, String[] outcomeNames) { super(params, predLabels, outcomeNames); outcomeTotals = initOutcomeTotals(outcomeNames, params); this.evalParams = new NaiveBayesEvalParameters(params, outcomeNames.length, outcomeTotals, predLabels.length); modelType = ModelType.NaiveBayes; } protected double[] initOutcomeTotals(String[] outcomeNames, Context[] params) { double[] outcomeTotals = new double[outcomeNames.length]; for (Context context : params) { for (int j = 0; j < context.getOutcomes().length; ++j) { int outcome = context.getOutcomes()[j]; double count = context.getParameters()[j]; outcomeTotals[outcome] += count; } } return outcomeTotals; } /** * {@inheritDoc} */ @Override public double[] eval(String[] context) { return eval(context, new double[evalParams.getNumOutcomes()]); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, float[] values) { return eval(context, values, new double[evalParams.getNumOutcomes()]); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, double[] probs) { return eval(context, null, probs); } public double[] eval(String[] context, float[] values, double[] outsums) { Context[] scontexts = new Context[context.length]; java.util.Arrays.fill(outsums, 0); for (int i = 0; i < context.length; i++) { scontexts[i] = pmap.get(context[i]); } return eval(scontexts, values, outsums, evalParams, true); } /** * Evaluates a {@link NaiveBayesModel}. * * @param context The context parameters as {@code int[]}. * @param prior The data prior to the evaluation as {@code double[]}. * @param model The {@link EvalParameters} used for evaluation. * * @return The resulting evaluation data as {@code double[]}. */ public static double[] eval(int[] context, double[] prior, EvalParameters model) { return eval(context, null, prior, model, true); } /** * Evaluates a {@link NaiveBayesModel}. * * @param context The {@link Context[] parameters} to set.. * @param values The {@code float[]} values to be used. * @param prior The data prior to the evaluation as {@code double[]}. * @param model The {@link EvalParameters} used for evaluation. * @param normalize Whether to normalize, or not. * * @return The resulting evaluation data as {@code double[]}. */ static double[] eval(Context[] context, float[] values, double[] prior, EvalParameters model, boolean normalize) { Probabilities probabilities = new LogProbabilities<>(); double[] outcomeTotals = model instanceof NaiveBayesEvalParameters ? ((NaiveBayesEvalParameters) model).getOutcomeTotals() : new double[prior.length]; long vocabulary = model instanceof NaiveBayesEvalParameters ? ((NaiveBayesEvalParameters) model).getVocabulary() : 0; double[] activeParameters; int[] activeOutcomes; double value = 1; for (int ci = 0; ci < context.length; ci++) { if (context[ci] != null) { Context predParams = context[ci]; activeOutcomes = predParams.getOutcomes(); activeParameters = predParams.getParameters(); if (values != null) { value = values[ci]; } int ai = 0; for (int i = 0; i < outcomeTotals.length && ai < activeOutcomes.length; ++i) { int oid = activeOutcomes[ai]; double numerator = oid == i ? activeParameters[ai++] * value : 0; double denominator = outcomeTotals[i]; probabilities.addIn(i, getProbability(numerator, denominator, vocabulary, true), 1); } } } double total = 0; for (double outcomeTotal : outcomeTotals) { total += outcomeTotal; } for (int i = 0; i < outcomeTotals.length; ++i) { double numerator = outcomeTotals[i]; probabilities.addIn(i, numerator / total, 1); } for (int i = 0; i < outcomeTotals.length; ++i) { prior[i] = probabilities.get(i); } return prior; } /** * Evaluates a {@link NaiveBayesModel}. * * @param context The context parameters as {@code int[]}. * @param values The {@code float[]} values to be used. * @param prior The data prior to the evaluation as {@code double[]}. * @param model The {@link EvalParameters} used for evaluation. * @param normalize Whether to normalize, or not. * * @return The resulting evaluation data as {@code double[]}. */ static double[] eval(int[] context, float[] values, double[] prior, EvalParameters model, boolean normalize) { Context[] scontexts = new Context[context.length]; for (int i = 0; i < context.length; i++) { scontexts[i] = model.getParams()[context[i]]; } return eval(scontexts, values, prior, model, normalize); } private static double getProbability(double numerator, double denominator, double vocabulary, boolean isSmoothed) { if (isSmoothed) return getSmoothedProbability(numerator, denominator, vocabulary); else if (denominator == 0 || denominator <= Double.MIN_VALUE) return 0; else return numerator / denominator; } private static double getSmoothedProbability(double numerator, double denominator, double vocabulary) { final double delta = 0.05; // Lidstone smoothing return (numerator + delta) / (denominator + delta * vocabulary); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Na0100644 0000000 0000000 00000000166 15217274217 032500 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesModelRea0100644 0000000 0000000 00000007256 15217274217 034041 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.AbstractModelReader; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.DataReader; /** * The base class for readers of {@link NaiveBayesModel models}. * It assumes that models are saved in the following sequence: * *
NaiveBayes (model type identifier) *
1. # of parameters ({@code int}) *
2. # of outcomes ({@code int}) *
* list of outcome names ({@code String}) *
3. # of different types of outcome patterns ({@code int}) *
* list of ({@code int} {@code int[]}) *
[# of predicates for which outcome pattern is true] [outcome pattern] *
4. # of predicates ({@code int}) *
* list of predicate names ({@code String}) * * @see NaiveBayesModel * @see AbstractModelReader */ public class NaiveBayesModelReader extends AbstractModelReader { private static final Logger logger = LoggerFactory.getLogger(NaiveBayesModelReader.class); /** * Initializes a {@link NaiveBayesModelReader} via a {@link File}. * * @param file The {@link File} that references the model to be read. * * @throws IOException Thrown if IO errors occurred. */ public NaiveBayesModelReader(File file) throws IOException { super(file); } /** * Initializes a {@link NaiveBayesModelReader} via a {@link DataReader}. * * @param dataReader The {@link DataReader} that references the model to be read. */ public NaiveBayesModelReader(DataReader dataReader) { super(dataReader); } /** * Constructs a {@link AbstractModel model}. *

* If you are creating a reader for a format which won't work with this * (perhaps a database or {@code xml} file), override this method and ignore the * other methods provided in this abstract class. * * @return A {@link NaiveBayesModel} reconstructed from a model's (read) attributes. * @throws IOException Thrown if IO errors occurred during (re-)construction. */ @Override public AbstractModel constructModel() throws IOException { String[] outcomeLabels = getOutcomes(); int[][] outcomePatterns = getOutcomePatterns(); String[] predLabels = getPredicates(); Context[] params = getParameters(outcomePatterns); return new NaiveBayesModel(params, predLabels, outcomeLabels); } /** * Reads the mode type from the underlying reader and informs if it not a * {@code Naive Bayes} model. * * @throws IOException Thrown if IO errors occurred. */ @Override public void checkModelType() throws IOException { String modelType = readUTF(); if (!modelType.equals("NaiveBayes")) logger.error("Attempting to load a {}" + " model as a NaiveBayes model." + " You should expect problems.", modelType); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Na0100644 0000000 0000000 00000000166 15217274217 032500 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesModelWri0100644 0000000 0000000 00000007500 15217274217 034063 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.io.IOException; import java.util.Arrays; import java.util.Map; import opennlp.tools.ml.AbstractMLModelWriter; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.AbstractModelWriter; import opennlp.tools.ml.model.ComparablePredicate; import opennlp.tools.ml.model.Context; /** * The base class for {@link NaiveBayesModel} writers. *

* It provides the {@link #persist()} method which takes care of the structure * of a stored document, and requires an extending class to define precisely * how the data should be stored. * * @see NaiveBayesModel * @see AbstractModelWriter * @see AbstractMLModelWriter */ public abstract class NaiveBayesModelWriter extends AbstractMLModelWriter { /** * Initializes a {@link NaiveBayesModelWriter} for a * {@link AbstractModel NaiveBayes model}. * * @param model The {@link AbstractModel NaiveBayes model} to be written. */ public NaiveBayesModelWriter(AbstractModel model) { super(); Object[] data = model.getDataStructures(); this.numOutcomes = model.getNumOutcomes(); PARAMS = (Context[]) data[0]; @SuppressWarnings("unchecked") Map pmap = (Map) data[1]; OUTCOME_LABELS = (String[]) data[2]; PARAMS = new Context[pmap.size()]; PRED_LABELS = new String[pmap.size()]; int i = 0; for (Map.Entry pred : pmap.entrySet()) { PRED_LABELS[i] = pred.getKey(); PARAMS[i] = pred.getValue(); i++; } } /** * {@inheritDoc} */ @Override protected ComparablePredicate[] sortValues() { ComparablePredicate[] sortPreds = new ComparablePredicate[PARAMS.length]; int numParams = 0; for (int pid = 0; pid < PARAMS.length; pid++) { int[] predkeys = PARAMS[pid].getOutcomes(); // Arrays.sort(predkeys); int numActive = predkeys.length; double[] activeParams = PARAMS[pid].getParameters(); numParams += numActive; /* * double[] activeParams = new double[numActive]; * * int id = 0; for (int i=0; i < predkeys.length; i++) { int oid = * predkeys[i]; activeOutcomes[id] = oid; activeParams[id] = * PARAMS[pid].getParams(oid); id++; } */ sortPreds[pid] = new ComparablePredicate(PRED_LABELS[pid], predkeys, activeParams); } Arrays.sort(sortPreds); return sortPreds; } /** * Writes the {@link AbstractModel perceptron model}, using the * {@link #writeUTF(String)}, {@link #writeDouble(double)}, or {@link #writeInt(int)}} * methods implemented by extending classes. * *

If you wish to create a {@link NaiveBayesModelWriter} which uses a different * structure, it will be necessary to override the {@link #persist()} method in * addition to implementing the {@code writeX(..)} methods. * * @throws IOException Thrown if IO errors occurred. */ @Override public void persist() throws IOException { // the type of model (NaiveBayes) writeUTF("NaiveBayes"); super.persist(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Na0100644 0000000 0000000 00000000162 15217274217 032474 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesTrainer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/NaiveBayesTrainer.0100644 0000000 0000000 00000016353 15217274217 034031 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.AbstractEventTrainer; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.ml.model.EvalParameters; import opennlp.tools.ml.model.MutableContext; import opennlp.tools.util.TrainingParameters; /** * Trains {@link NaiveBayesModel models} using the combination of EM algorithm * and Naive Bayes classifier which is described in: *

* Text Classification from Labeled and Unlabeled Documents using EM * Nigam, McCallum, et al. paper of 2000 * * @see NaiveBayesModel * @see AbstractEventTrainer */ public class NaiveBayesTrainer extends AbstractEventTrainer { private static final Logger logger = LoggerFactory.getLogger(NaiveBayesTrainer.class); public static final String NAIVE_BAYES_VALUE = "NAIVEBAYES"; /** * Number of unique events which occurred in the event set. */ private int numUniqueEvents; /** * Number of events in the event set. */ private int numEvents; /** * Number of predicates. */ private int numPreds; /** * Number of outcomes. */ private int numOutcomes; /** * Records the array of predicates seen in each event. */ private int[][] contexts; /** * The value associates with each context. If null then context values are assumes to be 1. */ private float[][] values; /** * List of outcomes for each event i, in context[i]. */ private int[] outcomeList; /** * Records the num of times an event has been seen for each event i, in context[i]. */ private int[] numTimesEventsSeen; /** * Stores the String names of the outcomes. The NaiveBayes only tracks outcomes * as ints, and so this array is needed to save the model to disk and * thereby allow users to know what the outcome was in human * understandable terms. */ private String[] outcomeLabels; /** * Stores the String names of the predicates.The NaiveBayes only tracks * predicates as ints, and so this array is needed to save the model to * disk and thereby allow users to know what the outcome was in human * understandable terms. */ private String[] predLabels; /** * Instantiates a {@link NaiveBayesTrainer} with default training parameters. */ public NaiveBayesTrainer() { } /** * Instantiates a {@link NaiveBayesTrainer} with specific * {@link TrainingParameters}. * * @param parameters The {@link TrainingParameters parameter} to use. */ public NaiveBayesTrainer(TrainingParameters parameters) { super(parameters); } @Override public boolean isSortAndMerge() { return false; } @Override public AbstractModel doTrain(DataIndexer indexer) throws IOException { return this.trainModel(indexer); } // << members related to AbstractEventTrainer /** * Trains a {@link NaiveBayesModel} with given parameters. * * @param di The {@link DataIndexer} used as data input. * * @return A valid, trained {@link AbstractModel Naive Bayes model}. */ public AbstractModel trainModel(DataIndexer di) { logger.info("Incorporating indexed data for training..."); contexts = di.getContexts(); values = di.getValues(); numTimesEventsSeen = di.getNumTimesEventsSeen(); numEvents = di.getNumEvents(); numUniqueEvents = contexts.length; outcomeLabels = di.getOutcomeLabels(); outcomeList = di.getOutcomeList(); predLabels = di.getPredLabels(); numPreds = predLabels.length; numOutcomes = outcomeLabels.length; logger.info("done."); logger.info("\tNumber of Event Tokens: {} " + "\n\t Number of Outcomes: {} " + "\n\t Number of Predicates: {}", numUniqueEvents, numOutcomes, numPreds); logger.info("Computing model parameters..."); MutableContext[] finalParameters = findParameters(); logger.info("...done."); /* Create and return the model ****/ return new NaiveBayesModel(finalParameters, predLabels, outcomeLabels); } private MutableContext[] findParameters() { int[] allOutcomesPattern = new int[numOutcomes]; for (int oi = 0; oi < numOutcomes; oi++) allOutcomesPattern[oi] = oi; /* Stores the estimated parameter value of each predicate during iteration. */ MutableContext[] params = new MutableContext[numPreds]; for (int pi = 0; pi < numPreds; pi++) { params[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]); for (int aoi = 0; aoi < numOutcomes; aoi++) params[pi].setParameter(aoi, 0.0); } double[] outcomeTotals = new double[outcomeLabels.length]; for (Context context : params) { for (int j = 0; j < context.getOutcomes().length; ++j) { int outcome = context.getOutcomes()[j]; double count = context.getParameters()[j]; outcomeTotals[outcome] += count; } } EvalParameters evalParams = new NaiveBayesEvalParameters( params, outcomeLabels.length, outcomeTotals, predLabels.length); double stepSize = 1; for (int ei = 0; ei < numUniqueEvents; ei++) { int targetOutcome = outcomeList[ei]; for (int ni = 0; ni < this.numTimesEventsSeen[ei]; ni++) { for (int ci = 0; ci < contexts[ei].length; ci++) { int pi = contexts[ei][ci]; if (values == null) { params[pi].updateParameter(targetOutcome, stepSize); } else { params[pi].updateParameter(targetOutcome, stepSize * values[ei][ci]); } } } } // Output the final training stats. trainingStats(evalParams); return params; } private double trainingStats(EvalParameters evalParams) { int numCorrect = 0; for (int ei = 0; ei < numUniqueEvents; ei++) { for (int ni = 0; ni < this.numTimesEventsSeen[ei]; ni++) { double[] modelDistribution = new double[numOutcomes]; if (values != null) NaiveBayesModel.eval(contexts[ei], values[ei], modelDistribution, evalParams, false); else NaiveBayesModel.eval(contexts[ei], null, modelDistribution, evalParams, false); int max = ArrayMath.argmax(modelDistribution); if (max == outcomeList[ei]) numCorrect++; } } double trainingAccuracy = (double) numCorrect / numEvents; logger.info("Stats: ({}/{}) {}", numCorrect, numEvents, trainingAccuracy); return trainingAccuracy; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Pl0100644 0000000 0000000 00000000177 15217274217 032517 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/PlainTextNaiveBayesModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/PlainTextNaiveBaye0100644 0000000 0000000 00000003641 15217274217 034070 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import opennlp.tools.ml.model.PlainTextFileDataReader; /** * A {@link NaiveBayesModelReader} that reads models from a plain text format. * * @see NaiveBayesModelReader */ public class PlainTextNaiveBayesModelReader extends NaiveBayesModelReader { /** * Instantiates {@link PlainTextNaiveBayesModelReader} via a {@link BufferedReader} * containing the model contents. * * @param br The {@link BufferedReader} containing the model information. * It must be open and have bytes available. */ public PlainTextNaiveBayesModelReader(BufferedReader br) { super(new PlainTextFileDataReader(br)); } /** * Instantiates {@link PlainTextNaiveBayesModelReader} via a {@link File} and creates * a reader for it. Based on whether the file's suffix contains {@code .gz}, * it detects whether the file is gzipped or not. * * @param f The {@link File} that references the model to be read. */ public PlainTextNaiveBayesModelReader(File f) throws IOException { super(f); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Pl0100644 0000000 0000000 00000000177 15217274217 032517 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/PlainTextNaiveBayesModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/PlainTextNaiveBaye0100644 0000000 0000000 00000006423 15217274217 034071 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.zip.GZIPOutputStream; import opennlp.tools.ml.model.AbstractModel; /** * A {@link NaiveBayesModelWriter} that writes models in a plain text format. */ public class PlainTextNaiveBayesModelWriter extends NaiveBayesModelWriter { private final BufferedWriter output; /** * Instantiates {@link PlainTextNaiveBayesModelWriter} via an * {@link AbstractModel naive bayes model} and a {@link File}. * Prepares writing of a {@code model} to the file. * Based on whether the file's suffix contains {@code .gz}, it detects whether * the file is gzipped or not. * * @param model The {@link AbstractModel naive bayes model} which is to be persisted. * @param f The {@link File} in which the model is to be persisted. * * @throws IOException Thrown if IO errors occurred. * @see NaiveBayesModel */ public PlainTextNaiveBayesModelWriter(AbstractModel model, File f) throws IOException { super(model); if (f.getName().endsWith(".gz")) { output = new BufferedWriter(new OutputStreamWriter( new GZIPOutputStream(new FileOutputStream(f)))); } else { output = new BufferedWriter(new FileWriter(f)); } } /** * Instantiates {@link PlainTextNaiveBayesModelWriter} via * an {@link AbstractModel naive bayes model} and a {@link BufferedWriter}. * Prepares writing a {@code model} to the file. * Based on whether the file's suffix contains {@code .gz}, it detects whether * the file is gzipped or not. * * @param model The {@link AbstractModel naive bayes model} which is to be persisted. * @param bw The {@link BufferedWriter} which is used to persist the {@code model}. * The {@code bw} must be opened. */ public PlainTextNaiveBayesModelWriter(AbstractModel model, BufferedWriter bw) { super(model); output = bw; } @Override public void writeUTF(String s) throws IOException { output.write(s); output.newLine(); } @Override public void writeInt(int i) throws IOException { output.write(Integer.toString(i)); output.newLine(); } @Override public void writeDouble(double d) throws IOException { output.write(Double.toString(d)); output.newLine(); } @Override public void close() throws IOException { output.flush(); output.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_naivebayes_Pr0100644 0000000 0000000 00000000156 15217274217 032522 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/Probabilities.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/Probabilities.java0100644 0000000 0000000 00000014774 15217274217 034115 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * Class implementing the probability distribution over labels returned by a classifier. * * @param The label (category) class. * */ public abstract class Probabilities { protected final Map map = new HashMap<>(); protected transient boolean isNormalised = false; protected Map normalised; protected double confidence = 0.0; /** * Assigns a probability to a label {@code t}, * discarding any previously assigned probability. * * @param t The label to which the probability is being assigned. * @param probability The probability to assign. */ public void set(T t, double probability) { isNormalised = false; map.put(t, probability); } /** * Assigns a probability to a label {@code t}, * discarding any previously assigned probability. * * @param t The label to which the probability is being assigned. * @param probability The probability to assign. */ public void set(T t, Probability probability) { isNormalised = false; map.put(t, probability.get()); } /** * Assigns a probability to a label {@code t}, * discarding any previously assigned probability, * if the new probability is greater than the old one. * * @param t The label to which the probability is being assigned. * @param probability The probability to assign. */ public void setIfLarger(T t, double probability) { Double p = map.get(t); if (p == null || probability > p) { isNormalised = false; map.put(t, probability); } } /** * Assigns a log probability to a label {@code t}, * discarding any previously assigned probability. * * @param t The label to which the log probability is being assigned. * @param probability The log probability to assign. */ public void setLog(T t, double probability) { set(t, StrictMath.exp(probability)); } /** * Compounds the existing probability mass on the label {@code t} * with the new probability passed in to the method. * * @param t The label whose probability mass is being updated. * @param probability The probability weight to add. * @param count The amplifying factor for the probability compounding. */ public void addIn(T t, double probability, int count) { isNormalised = false; Double p = map.get(t); if (p == null) p = 1.0; probability = StrictMath.pow(probability, count); map.put(t, p * probability); } /** * @param t The label whose probability needs to be returned. * @return Retrieves the probability associated with the label. */ public Double get(T t) { Double d = normalize().get(t); if (d == null) return 0.0; return d; } /** * @param t The label whose log probability should be returned. * @return Retrieves the log probability associated with the label */ public Double getLog(T t) { return StrictMath.log(get(t)); } /** * @return Retrieves the probabilities associated with all labels */ public Set getKeys() { return map.keySet(); } /** * @return Retrieves a {@link Map} of labels and their probabilities */ public Map getAll() { return normalize(); } private Map normalize() { if (isNormalised) return normalised; Map temp = createMapDataStructure(); double sum = 0; for (Entry entry : map.entrySet()) { Double p = entry.getValue(); if (p != null) { sum += p; } } for (Entry entry : temp.entrySet()) { T t = entry.getKey(); Double p = entry.getValue(); if (p != null) { temp.put(t, p / sum); } } normalised = temp; isNormalised = true; return temp; } protected Map createMapDataStructure() { return new HashMap<>(); } /** * @return Retrieves the label that has the highest associated probability. */ public T getMax() { double max = 0; T maxT = null; for (Entry entry : map.entrySet()) { final T t = entry.getKey(); final Double temp = entry.getValue(); if (temp >= max) { max = temp; maxT = t; } } return maxT; } /** * @return Retrieves the probability of the most likely label */ public double getMaxValue() { return get(getMax()); } public void discardCountsBelow(double i) { List labelsToRemove = new ArrayList<>(); for (Entry entry : map.entrySet()) { T label = entry.getKey(); Double sum = entry.getValue(); if (sum == null) sum = 0.0; if (sum < i) labelsToRemove.add(label); } for (T label : labelsToRemove) { map.remove(label); } } /** * @return Retrieves the best confidence with which this set of probabilities has been calculated. * This is a function of the amount of data that supports the assertion. * It is also a measure of the accuracy of the estimator of the probability. */ public double getConfidence() { return confidence; } /** * Sets the best confidence with which this set of probabilities has been calculated. * This is a function of the amount of data that supports the assertion. * It is also a measure of the accuracy of the estimator of the probability. * * @param confidence The confidence in the probabilities. */ public void setConfidence(double confidence) { this.confidence = confidence; } @Override public String toString() { return getAll().toString(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/Probability.java0100644 0000000 0000000 00000007361 15217274217 033577 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.naivebayes; /** * Class implementing the probability for a label. * * @param The label (category) class. * */ public class Probability { protected final T label; protected double probability = 1.0; /** * Instantiates a {@link Probability} with a given {@code label}. * * @param label The {@link T label} to assign probabilities to. */ public Probability(T label) { this.label = label; } /** * Assigns a probability to a label, discarding any previously assigned probability. * * @param probability The probability to assign. */ public void set(double probability) { this.probability = probability; } /** * Assigns a probability to a label, discarding any previously assigned probability. * * @param probability The probability to assign. */ public void set(Probability probability) { this.probability = probability.get(); } /** * Assigns a probability to a label, discarding any previously assigned probability, * if the new probability is greater than the old one. * * @param probability The probability to assign. */ public void setIfLarger(double probability) { if (this.probability < probability) { this.probability = probability; } } /** * Assigns a probability to a label, discarding any previously assigned probability, * if the new probability is greater than the old one. * * @param probability The probability to assign. */ public void setIfLarger(Probability probability) { if (this.probability < probability.get()) { this.probability = probability.get(); } } /** * Checks if a probability is greater than the old one. * * @param probability The probability to assign. * @return {@code true} if a probability is greater than the old one, {@code false} otherwise. */ public boolean isLarger(Probability probability) { return this.probability < probability.get(); } /** * Assigns a log probability to a label, discarding any previously assigned probability. * * @param probability The log probability to assign. */ public void setLog(double probability) { set(StrictMath.exp(probability)); } /** * Compounds the existing probability mass on the label with the new probability passed in to the method. * * @param probability The probability weight to add. */ public void addIn(double probability) { set(this.probability * probability); } /** * @return Retrieves the probability associated with a label. */ public Double get() { return probability; } /** * @return Retrieves the log probability associated with a label. */ public Double getLog() { return StrictMath.log(get()); } /** * @return Retrieves the probabilities associated with all labels. */ public T getLabel() { return label; } public String toString() { return label == null ? "" + probability : label + ":" + probability; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/naivebayes/package-info.java0100644 0000000 0000000 00000001617 15217274217 033641 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to ML by means of the Naive Bayes algorithm. */ package opennlp.tools.ml.naivebayes; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/package-info.java0100644 0000000 0000000 00000001652 15217274217 031512 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to Machine Learning (ML) features of OpenNLP, the related ML models, and trainers. */ package opennlp.tools.ml; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_perceptron_Bi0100644 0000000 0000000 00000000174 15217274217 032526 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/BinaryPerceptronModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/BinaryPerceptronMo0100644 0000000 0000000 00000003555 15217274217 034215 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.perceptron; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import opennlp.tools.ml.model.BinaryFileDataReader; /** * A {@link PerceptronModelReader} that reads models from a binary format. */ public class BinaryPerceptronModelReader extends PerceptronModelReader { /** * Instantiates {@link BinaryPerceptronModelReader} via a {@link DataInputStream} * containing the model contents. * * @param dis The {@link DataInputStream} containing the model information. * It must be open and have bytes available. */ public BinaryPerceptronModelReader(DataInputStream dis) { super(new BinaryFileDataReader(dis)); } /** * Instantiates {@link BinaryPerceptronModelReader} via a {@link File} and creates * a reader for it. Based on whether the file's suffix contains {@code .gz}, * it detects whether the file is gzipped or not. * * @param f The {@link File} that references the model to be read. */ public BinaryPerceptronModelReader(File f) throws IOException { super(f); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_perceptron_Bi0100644 0000000 0000000 00000000174 15217274217 032526 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/BinaryPerceptronModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/BinaryPerceptronMo0100644 0000000 0000000 00000006167 15217274217 034217 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.perceptron; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.ModelParameterChunker; /** * A {@link PerceptronModelWriter} that writes models in a binary format. */ public class BinaryPerceptronModelWriter extends PerceptronModelWriter { private final DataOutputStream output; /** * Instantiates {@link BinaryPerceptronModelWriter} via an {@link AbstractModel perceptron model} * and a {@link File}. Prepares writing of the {@code model} to the file. * Based on whether the file's suffix contains {@code .gz}, it detects whether * the file is gzipped or not. * * @param model The {@link AbstractModel perceptron model} which is to be persisted. * @param f The {@link File} in which the model is to be persisted. * * @see PerceptronModel */ public BinaryPerceptronModelWriter(AbstractModel model, File f) throws IOException { super(model); if (f.getName().endsWith(".gz")) { output = new DataOutputStream( new GZIPOutputStream(new FileOutputStream(f))); } else { output = new DataOutputStream(new FileOutputStream(f)); } } /** * Instantiates {@link BinaryPerceptronModelWriter} via an {@link AbstractModel perceptron model} * and a {@link DataOutputStream}. Prepares writing a {@code model} to the file. * Based on whether the file's suffix contains {@code .gz}, it detects whether * the file is gzipped or not. * * @param model The {@link AbstractModel perceptron model} which is to be persisted. * @param dos The {@link DataOutputStream} which is used to persist the {@code model}. * The {@code dos} must be opened. */ public BinaryPerceptronModelWriter(AbstractModel model, DataOutputStream dos) { super(model); output = dos; } @Override public void writeUTF(String s) throws IOException { ModelParameterChunker.writeUTF(output, s); } @Override public void writeInt(int i) throws IOException { output.writeInt(i); } @Override public void writeDouble(double d) throws IOException { output.writeDouble(d); } @Override public void close() throws IOException { output.flush(); output.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_perceptron_Pe0100644 0000000 0000000 00000000160 15217274217 032533 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronModel.ja0100644 0000000 0000000 00000014415 15217274217 034123 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.perceptron; import java.util.Arrays; import java.util.Objects; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.EvalParameters; import opennlp.tools.ml.model.MaxentModel; /** * A {@link MaxentModel model} implementation based one the perceptron algorithm. *

* Each outcome is represented as a binary perceptron classifier. * This supports standard (integer) weighting as well average weighting as described in: * Discriminative Training Methods for Hidden Markov Models: Theory and Experiments * with the Perceptron Algorithm. Michael Collins, EMNLP 2002. */ public class PerceptronModel extends AbstractModel { /** * Initializes a {@link PerceptronModel}. * * @param params The {@link Context parameters} to set. * @param predLabels The predicted labels. * @param outcomeNames The names of the outcomes. */ public PerceptronModel(Context[] params, String[] predLabels, String[] outcomeNames) { super(params,predLabels,outcomeNames); modelType = ModelType.Perceptron; } /** * {@inheritDoc} */ @Override public double[] eval(String[] context) { return eval(context,new double[evalParams.getNumOutcomes()]); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, float[] values) { return eval(context,values,new double[evalParams.getNumOutcomes()]); } /** * {@inheritDoc} */ @Override public double[] eval(String[] context, double[] probs) { return eval(context,null,probs); } public double[] eval(String[] context, float[] values, double[] outsums) { Context[] scontexts = new Context[context.length]; java.util.Arrays.fill(outsums, 0); for (int i = 0; i < context.length; i++) { scontexts[i] = pmap.get(context[i]); } return eval(scontexts,values,outsums,evalParams,true); } /** * Evaluates a {@link PerceptronModel}. * * @param context The context parameters as {@code int[]}. * @param prior The data prior to the evaluation as {@code double[]}. * @param model The {@link EvalParameters} used for evaluation. * * @return The resulting evaluation data as {@code double[]}. */ public static double[] eval(int[] context, double[] prior, EvalParameters model) { return eval(context,null,prior,model,true); } /** * Evaluates a {@link PerceptronModel}. * * @param context The context parameters as {@code int[]}. * @param values The {@code float[]} values to be used. * @param prior The data prior to the evaluation as {@code double[]}. * @param model The {@link EvalParameters} used for evaluation. * @param normalize Whether to normalize, or not. * * @return The resulting evaluation data as {@code double[]}. */ static double[] eval(int[] context, float[] values, double[] prior, EvalParameters model, boolean normalize) { Context[] scontexts = new Context[context.length]; for (int i = 0; i < context.length; i++) { scontexts[i] = model.getParams()[context[i]]; } return eval(scontexts, values, prior, model, normalize); } /** * Evaluates a {@link PerceptronModel}. * * @param context The {@link Context[] parameters} to set.. * @param values The {@code float[]} values to be used. * @param prior The data prior to the evaluation as {@code double[]}. * @param model The {@link EvalParameters} used for evaluation. * @param normalize Whether to normalize, or not. * * @return The resulting evaluation data as {@code double[]}. */ static double[] eval(Context[] context, float[] values, double[] prior, EvalParameters model, boolean normalize) { ArrayMath.sumFeatures(context, values, prior); if (normalize) { int numOutcomes = model.getNumOutcomes(); double maxPrior = 1; for (int oid = 0; oid < numOutcomes; oid++) { if (maxPrior < StrictMath.abs(prior[oid])) maxPrior = StrictMath.abs(prior[oid]); } double normal = 0.0; for (int oid = 0; oid < numOutcomes; oid++) { prior[oid] = StrictMath.exp(prior[oid] / maxPrior); normal += prior[oid]; } for (int oid = 0; oid < numOutcomes; oid++) { prior[oid] /= normal; } } return prior; } @Override public int hashCode() { /* * Note: * The hashcode for 'pmap' can not be used here, as PerceptronModelWriter * uses compressions during sortValues() operation, quote: * "remove parameters with 0 weight and predicates with no parameters" * * This leads to fewer entries in 'pmap' for serialized PerceptronModel instances * that were trained from scratch. */ return Objects.hash(Arrays.hashCode(outcomeNames), evalParams, prior); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof PerceptronModel model) { /* * Note: * The comparison 'pmap.equals(model.pmap)' can not be made here, as PerceptronModelWriter * uses compressions during sortValues() operation, quote: * "remove parameters with 0 weight and predicates with no parameters" * * This leads to fewer entries in 'pmap' for serialized PerceptronModel instances * that were trained from scratch. */ return Objects.deepEquals(outcomeNames, model.outcomeNames) && Objects.equals(prior, model.prior); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_perceptron_Pe0100644 0000000 0000000 00000000166 15217274217 032541 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronModelReader.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronModelRea0100644 0000000 0000000 00000007270 15217274217 034163 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.perceptron; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.AbstractModelReader; import opennlp.tools.ml.model.Context; import opennlp.tools.ml.model.DataReader; /** * The base class for readers of {@link PerceptronModel models}. * It assumes that models are saved in the following sequence: * *
Perceptron (model type identifier) *
1. # of parameters ({@code int}) *
2. # of outcomes ({@code int}) *
* list of outcome names ({@code String}) *
3. # of different types of outcome patterns ({@code int}) *
* list of ({@code int} {@code int[]}) *
[# of predicates for which outcome pattern is true] [outcome pattern] *
4. # of predicates ({@code int}) *
* list of predicate names ({@code String}) * * @see PerceptronModel * @see AbstractModelReader */ public class PerceptronModelReader extends AbstractModelReader { private static final Logger logger = LoggerFactory.getLogger(PerceptronModelReader.class); /** * Initializes a {@link PerceptronModelReader} via a {@link File}. * * @param file The {@link File} that references the model to be read. * * @throws IOException Thrown if IO errors occurred. */ public PerceptronModelReader(File file) throws IOException { super(file); } /** * Initializes a {@link PerceptronModelReader} via a {@link DataReader}. * * @param dataReader The {@link DataReader} that references the model to be read. */ public PerceptronModelReader(DataReader dataReader) { super(dataReader); } /** * Constructs a {@link AbstractModel model}. *

* If you are creating a reader for a format which won't work with this * (perhaps a database or {@code xml} file), override this method and ignore the * other methods provided in this abstract class. * * @return A {@link PerceptronModel} reconstructed from a model's (read) attributes. * @throws IOException Thrown if IO errors occurred during (re-)construction. */ @Override public AbstractModel constructModel() throws IOException { String[] outcomeLabels = getOutcomes(); int[][] outcomePatterns = getOutcomePatterns(); String[] predLabels = getPredicates(); Context[] params = getParameters(outcomePatterns); return new PerceptronModel(params, predLabels, outcomeLabels); } /** * Reads the mode type from the underlying reader and informs if it not a * {@code Perceptron} model. * * @throws IOException Thrown if IO errors occurred. */ @Override public void checkModelType() throws IOException { String modelType = readUTF(); if (!modelType.equals("Perceptron")) logger.error("Attempting to load a {} " + " model as a Perceptron model." + " You should expect problems.", modelType); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_perceptron_Pe0100644 0000000 0000000 00000000166 15217274217 032541 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronModelWriter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronModelWri0100644 0000000 0000000 00000011034 15217274217 034206 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.perceptron; import java.io.IOException; import java.util.Arrays; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.AbstractMLModelWriter; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.AbstractModelWriter; import opennlp.tools.ml.model.ComparablePredicate; import opennlp.tools.ml.model.Context; /** * The base class for {@link PerceptronModel} writers. *

* It provides the {@link #persist()} method which takes care of the structure * of a stored document, and requires an extending class to define precisely * how the data should be stored. * * @see PerceptronModel * @see AbstractModelWriter * @see AbstractMLModelWriter */ public abstract class PerceptronModelWriter extends AbstractMLModelWriter { private static final Logger logger = LoggerFactory.getLogger(PerceptronModelWriter.class); /** * Initializes a {@link PerceptronModelWriter} for a * {@link AbstractModel perceptron model}. * * @param model The {@link AbstractModel perceptron model} to be written. */ public PerceptronModelWriter(AbstractModel model) { super(); Object[] data = model.getDataStructures(); numOutcomes = model.getNumOutcomes(); PARAMS = (Context[]) data[0]; @SuppressWarnings("unchecked") Map pmap = (Map) data[1]; OUTCOME_LABELS = (String[]) data[2]; PARAMS = new Context[pmap.size()]; PRED_LABELS = new String[pmap.size()]; int i = 0; for (Map.Entry pred : pmap.entrySet()) { PRED_LABELS[i] = pred.getKey(); PARAMS[i] = pred.getValue(); i++; } } /** * {@inheritDoc} */ @Override protected ComparablePredicate[] sortValues() { ComparablePredicate[] sortPreds; ComparablePredicate[] tmpPreds = new ComparablePredicate[PARAMS.length]; int[] tmpOutcomes = new int[numOutcomes]; double[] tmpParams = new double[numOutcomes]; int numPreds = 0; // remove parameters with 0 weight and predicates with no parameters for (int pid = 0; pid < PARAMS.length; pid++) { int numParams = 0; double[] predParams = PARAMS[pid].getParameters(); int[] outcomePattern = PARAMS[pid].getOutcomes(); for (int pi = 0; pi < predParams.length; pi++) { if (predParams[pi] != 0d) { tmpOutcomes[numParams] = outcomePattern[pi]; tmpParams[numParams] = predParams[pi]; numParams++; } } int[] activeOutcomes = new int[numParams]; double[] activeParams = new double[numParams]; for (int pi = 0; pi < numParams; pi++) { activeOutcomes[pi] = tmpOutcomes[pi]; activeParams[pi] = tmpParams[pi]; } if (numParams != 0) { tmpPreds[numPreds] = new ComparablePredicate(PRED_LABELS[pid],activeOutcomes,activeParams); numPreds++; } } logger.info("Compressed {} parameters to {}", PARAMS.length , numPreds); sortPreds = new ComparablePredicate[numPreds]; System.arraycopy(tmpPreds, 0, sortPreds, 0, numPreds); Arrays.sort(sortPreds); return sortPreds; } /** * Writes the {@link AbstractModel perceptron model}, using the * {@link #writeUTF(String)}, {@link #writeDouble(double)}, or {@link #writeInt(int)}} * methods implemented by extending classes. * *

If you wish to create a {@link PerceptronModelWriter} which uses a different * structure, it will be necessary to override the {@link #persist()} method in * addition to implementing the {@code writeX(..)} methods. * * @throws IOException Thrown if IO errors occurred. */ @Override public void persist() throws IOException { // the type of model (Perceptron) writeUTF("Perceptron"); super.persist(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_perceptron_Pe0100644 0000000 0000000 00000000162 15217274217 032535 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronTrainer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/PerceptronTrainer.0100644 0000000 0000000 00000041534 15217274217 034156 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.perceptron; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Trainer; import opennlp.tools.ml.AbstractEventTrainer; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.ml.model.EvalParameters; import opennlp.tools.ml.model.MutableContext; import opennlp.tools.monitoring.DefaultTrainingProgressMonitor; import opennlp.tools.monitoring.IterDeltaAccuracyUnderTolerance; import opennlp.tools.monitoring.StopCriteria; import opennlp.tools.monitoring.TrainingMeasure; import opennlp.tools.monitoring.TrainingProgressMonitor; import opennlp.tools.util.TrainingConfiguration; import opennlp.tools.util.TrainingParameters; /** * Trains {@link PerceptronModel models} using the perceptron algorithm. *

* Each outcome is represented as a binary perceptron classifier. * This supports standard (integer) weighting as well average weighting as described in: *

* Discriminative Training Methods for Hidden Markov Models: Theory and Experiments * with the Perceptron Algorithm. Michael Collins, EMNLP 2002. * * @see PerceptronModel * @see AbstractEventTrainer */ public class PerceptronTrainer extends AbstractEventTrainer { private static final Logger logger = LoggerFactory.getLogger(PerceptronTrainer.class); public static final String PERCEPTRON_VALUE = "PERCEPTRON"; public static final double TOLERANCE_DEFAULT = .00001; /** Number of unique events which occurred in the event set. */ private int numUniqueEvents; /** Number of events in the event set. */ private int numEvents; /** Number of predicates. */ private int numPreds; /** Number of outcomes. */ private int numOutcomes; /** Records the array of predicates seen in each event. */ private int[][] contexts; /** The value associates with each context. If null then context values are assumes to be 1. */ private float[][] values; /** List of outcomes for each event i, in context[i]. */ private int[] outcomeList; /** Records the num of times an event has been seen for each event i, in context[i]. */ private int[] numTimesEventsSeen; /** Stores the String names of the outcomes. The GIS only tracks outcomes as ints, and so this array is needed to save the model to disk and thereby allow users to know what the outcome was in human understandable terms. */ private String[] outcomeLabels; /** Stores the String names of the predicates. The GIS only tracks predicates as ints, and so this array is needed to save the model to disk and thereby allow users to know what the outcome was in human understandable terms. */ private String[] predLabels; private double tolerance = TOLERANCE_DEFAULT; private Double stepSizeDecrease; private boolean useSkippedlAveraging; /** * Instantiates a {@link PerceptronTrainer} with default training parameters. */ public PerceptronTrainer() { } /** * Instantiates a {@link PerceptronTrainer} with specific * {@link TrainingParameters}. * * @param parameters The {@link TrainingParameters parameter} to use. */ public PerceptronTrainer(TrainingParameters parameters) { super(parameters); } /** * {@inheritDoc} * * @throws IllegalArgumentException Thrown if the algorithm name is not equal to * {@link #PERCEPTRON_VALUE}. */ @Override public void validate() { super.validate(); String algorithmName = getAlgorithm(); if (algorithmName != null) { if (!PERCEPTRON_VALUE.equals(algorithmName)) { throw new IllegalArgumentException("algorithmName must be PERCEPTRON"); } } } @Override public boolean isSortAndMerge() { return false; } @Override public AbstractModel doTrain(DataIndexer indexer) throws IOException { int iterations = getIterations(); int cutoff = getCutoff(); boolean useAverage = trainingParameters.getBooleanParameter("UseAverage", true); boolean useSkippedAveraging = trainingParameters.getBooleanParameter("UseSkippedAveraging", false); // overwrite otherwise it might not work if (useSkippedAveraging) useAverage = true; double stepSizeDecrease = trainingParameters.getDoubleParameter("StepSizeDecrease", 0); double tolerance = trainingParameters.getDoubleParameter("Tolerance", PerceptronTrainer.TOLERANCE_DEFAULT); this.setSkippedAveraging(useSkippedAveraging); if (stepSizeDecrease > 0) this.setStepSizeDecrease(stepSizeDecrease); this.setTolerance(tolerance); return this.trainModel(iterations, indexer, cutoff, useAverage); } // << members related to AbstractEventTrainer /** * Specifies the tolerance. If the change in training set accuracy * is less than this, stop iterating. * * @param tolerance The level of tolerance. * Must not be negative. * @throws IllegalArgumentException Thrown if parameters are invalid. */ public void setTolerance(double tolerance) { if (tolerance < 0) { throw new IllegalArgumentException("tolerance must be a positive number but is " + tolerance + "!"); } this.tolerance = tolerance; } /** * Enables and sets step size decrease. The step size is * decreased every iteration by the specified value. * * @param decrease The step size decrease in percent. * Must not be negative. * @throws IllegalArgumentException Thrown if parameters are invalid. */ public void setStepSizeDecrease(double decrease) { if (decrease < 0 || decrease > 100) { throw new IllegalArgumentException("decrease must be between 0 and 100 but is " + decrease + "!"); } stepSizeDecrease = decrease; } /** * Enables skipped averaging, this flag changes the standard * averaging to special averaging instead. *

* If we are doing averaging, and the current iteration is one * of the first 20, or if it is a perfect square, then updated the * summed parameters. *

* The reason we don't take all of them is that the parameters change * less toward the end of training, so they drown out the contributions * of the more volatile early iterations. The use of perfect * squares allows us to sample from successively farther apart iterations. * * @param averaging Whether to skip 'averaging', or not. */ public void setSkippedAveraging(boolean averaging) { useSkippedlAveraging = averaging; } /** * Trains a {@link PerceptronModel} with given parameters. * * @param iterations The number of iterations to use for training. * @param di The {@link DataIndexer} used as data input. * @param cutoff The {@link TrainingParameters#CUTOFF_PARAM} value to use for training. * * @return A valid, trained {@link AbstractModel perceptron model}. */ public AbstractModel trainModel(int iterations, DataIndexer di, int cutoff) { return trainModel(iterations,di,cutoff,true); } /** * Trains a {@link PerceptronModel} with given parameters. * * @param iterations The number of iterations to use for training. * @param di The {@link DataIndexer} used as data input. * @param cutoff The {@link TrainingParameters#CUTOFF_PARAM} value to use for training. * @param useAverage Whether to use 'averaging', or not. * See {@link #setSkippedAveraging(boolean)} for details. * * @return A valid, trained {@link AbstractModel perceptron model}. */ public AbstractModel trainModel(int iterations, DataIndexer di, int cutoff, boolean useAverage) { logger.info("Incorporating indexed data for training... "); contexts = di.getContexts(); values = di.getValues(); numTimesEventsSeen = di.getNumTimesEventsSeen(); numEvents = di.getNumEvents(); numUniqueEvents = contexts.length; outcomeLabels = di.getOutcomeLabels(); outcomeList = di.getOutcomeList(); predLabels = di.getPredLabels(); numPreds = predLabels.length; numOutcomes = outcomeLabels.length; logger.info("done."); logger.info("\tNumber of Event Tokens: {} " + "\n\t Number of Outcomes: {} " + "\n\t Number of Predicates: {}", numUniqueEvents, numOutcomes, numPreds); logger.info("Computing model parameters..."); MutableContext[] finalParameters = findParameters(iterations, useAverage); logger.info("...done."); /* Create and return the model *************/ return new PerceptronModel(finalParameters, predLabels, outcomeLabels); } private MutableContext[] findParameters(int iterations, boolean useAverage) { logger.info("Performing {} iterations.", iterations); int[] allOutcomesPattern = new int[numOutcomes]; for (int oi = 0; oi < numOutcomes; oi++) allOutcomesPattern[oi] = oi; /* Stores the estimated parameter value of each predicate during iteration. */ MutableContext[] params = new MutableContext[numPreds]; for (int pi = 0; pi < numPreds; pi++) { params[pi] = new MutableContext(allOutcomesPattern,new double[numOutcomes]); for (int aoi = 0; aoi < numOutcomes; aoi++) params[pi].setParameter(aoi, 0.0); } EvalParameters evalParams = new EvalParameters(params, numOutcomes); /* Stores the sum of parameter values of each predicate over many iterations. */ MutableContext[] summedParams = new MutableContext[numPreds]; if (useAverage) { for (int pi = 0; pi < numPreds; pi++) { summedParams[pi] = new MutableContext(allOutcomesPattern,new double[numOutcomes]); for (int aoi = 0; aoi < numOutcomes; aoi++) summedParams[pi].setParameter(aoi, 0.0); } } //Get the Training Progress Monitor and the StopCriteria. TrainingProgressMonitor progressMonitor = getTrainingProgressMonitor(trainingConfiguration); StopCriteria stopCriteria = getStopCriteria(trainingConfiguration); // Keep track of the previous three accuracies. The difference of // the mean of these and the current training set accuracy is used // with tolerance to decide whether to stop. double prevAccuracy1 = 0.0; double prevAccuracy2 = 0.0; double prevAccuracy3 = 0.0; // A counter for the denominator for averaging. int numTimesSummed = 0; double stepsize = 1; for (int i = 1; i <= iterations; i++) { // Decrease the stepsize by a small amount. if (stepSizeDecrease != null) stepsize *= 1 - stepSizeDecrease; int numCorrect = 0; for (int ei = 0; ei < numUniqueEvents; ei++) { int targetOutcome = outcomeList[ei]; for (int ni = 0; ni < this.numTimesEventsSeen[ei]; ni++) { // Compute the model's prediction according to the current parameters. double[] modelDistribution = new double[numOutcomes]; if (values != null) PerceptronModel.eval(contexts[ei], values[ei], modelDistribution, evalParams, false); else PerceptronModel.eval(contexts[ei], null, modelDistribution, evalParams, false); int maxOutcome = ArrayMath.argmax(modelDistribution); // If the predicted outcome is different from the target // outcome, do the standard update: boost the parameters // associated with the target and reduce those associated // with the incorrect predicted outcome. if (maxOutcome != targetOutcome) { for (int ci = 0; ci < contexts[ei].length; ci++) { int pi = contexts[ei][ci]; if (values == null) { params[pi].updateParameter(targetOutcome, stepsize); params[pi].updateParameter(maxOutcome, -stepsize); } else { params[pi].updateParameter(targetOutcome, stepsize * values[ei][ci]); params[pi].updateParameter(maxOutcome, -stepsize * values[ei][ci]); } } } // Update the counts for accuracy. if (maxOutcome == targetOutcome) numCorrect++; } } // Calculate the training accuracy. double trainingAccuracy = (double) numCorrect / numEvents; if (i < 10 || (i % 10) == 0) { progressMonitor.finishedIteration(i, numCorrect, numEvents, TrainingMeasure.ACCURACY, trainingAccuracy); } // TODO: Make averaging configurable !!! boolean doAveraging; doAveraging = useAverage && useSkippedlAveraging && (i < 20 || isPerfectSquare(i)) || useAverage; if (doAveraging) { numTimesSummed++; for (int pi = 0; pi < numPreds; pi++) for (int aoi = 0; aoi < numOutcomes; aoi++) summedParams[pi].updateParameter(aoi, params[pi].getParameters()[aoi]); } // If the tolerance is greater than the difference between the // current training accuracy and all of the previous three // training accuracies, stop training. if (stopCriteria.test(prevAccuracy1 - trainingAccuracy) && stopCriteria.test(prevAccuracy2 - trainingAccuracy) && stopCriteria.test(prevAccuracy3 - trainingAccuracy)) { progressMonitor.finishedTraining(iterations, stopCriteria); break; } // Update the previous training accuracies. prevAccuracy1 = prevAccuracy2; prevAccuracy2 = prevAccuracy3; prevAccuracy3 = trainingAccuracy; } //At this point, all iterations have finished successfully. if (!progressMonitor.isTrainingFinished()) { progressMonitor.finishedTraining(iterations, null); } progressMonitor.display(true); // Output the final training stats. trainingStats(evalParams); // Create averaged parameters if (useAverage) { for (int pi = 0; pi < numPreds; pi++) for (int aoi = 0; aoi < numOutcomes; aoi++) summedParams[pi].setParameter(aoi, summedParams[pi].getParameters()[aoi] / numTimesSummed); return summedParams; } else { return params; } } private double trainingStats(EvalParameters evalParams) { int numCorrect = 0; for (int ei = 0; ei < numUniqueEvents; ei++) { for (int ni = 0; ni < this.numTimesEventsSeen[ei]; ni++) { double[] modelDistribution = new double[numOutcomes]; if (values != null) PerceptronModel.eval(contexts[ei], values[ei], modelDistribution, evalParams,false); else PerceptronModel.eval(contexts[ei], null, modelDistribution, evalParams, false); int max = ArrayMath.argmax(modelDistribution); if (max == outcomeList[ei]) numCorrect++; } } double trainingAccuracy = (double) numCorrect / numEvents; logger.info("Stats: ({}/{}) {}", numCorrect, numEvents, trainingAccuracy); return trainingAccuracy; } // See whether a number is a perfect square. // Inefficient, but fine for our purposes. private static boolean isPerfectSquare(int n) { int root = (int) StrictMath.sqrt(n); return root * root == n; } /** * Get the {@link StopCriteria} associated with this {@link Trainer}. * * @param trainingConfig {@link TrainingConfiguration} * @return {@link StopCriteria}. If {@link TrainingConfiguration} is {@code null} or * {@link TrainingConfiguration#stopCriteria()} is {@code null}, * then return the default {@link StopCriteria}. */ private StopCriteria getStopCriteria(TrainingConfiguration trainingConfig) { return trainingConfig != null && trainingConfig.stopCriteria() != null ? trainingConfig.stopCriteria() : new IterDeltaAccuracyUnderTolerance(trainingParameters); } /** * Get the {@link TrainingProgressMonitor} associated with this {@link Trainer}. * * @param trainingConfig {@link TrainingConfiguration}. * @return {@link TrainingProgressMonitor}. If {@link TrainingConfiguration} is {@code null} or * {@link TrainingConfiguration#progMon()} is {@code null}, * then return the default {@link TrainingProgressMonitor}. */ private TrainingProgressMonitor getTrainingProgressMonitor(TrainingConfiguration trainingConfig) { return trainingConfig != null && trainingConfig.progMon() != null ? trainingConfig.progMon() : new DefaultTrainingProgressMonitor(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_ml_perceptron_Si0100644 0000000 0000000 00000000200 15217274217 032535 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/SimplePerceptronSequenceTrainer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/SimplePerceptronSe0100644 0000000 0000000 00000034473 15217274217 034221 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ml.perceptron; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.AbstractEventModelSequenceTrainer; import opennlp.tools.ml.model.AbstractDataIndexer; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.DataIndexer; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MutableContext; import opennlp.tools.ml.model.OnePassDataIndexer; import opennlp.tools.ml.model.Sequence; import opennlp.tools.ml.model.SequenceStream; import opennlp.tools.ml.model.SequenceStreamEventStream; import opennlp.tools.util.TrainingParameters; /** * Trains {@link PerceptronModel models} with sequences using the perceptron algorithm. *

* Each outcome is represented as a binary perceptron classifier. * This supports standard (integer) weighting as well average weighting. *

* Sequence information is used in a simplified was to that described in: * Discriminative Training Methods for Hidden Markov Models: Theory and Experiments * with the Perceptron Algorithm. Michael Collins, EMNLP 2002. *

* Specifically only updates are applied to tokens which were incorrectly tagged by a sequence tagger * rather than to all feature across the sequence which differ from the training sequence. * * @see PerceptronModel * @see AbstractEventModelSequenceTrainer */ public class SimplePerceptronSequenceTrainer extends AbstractEventModelSequenceTrainer { private static final Logger logger = LoggerFactory.getLogger(SimplePerceptronSequenceTrainer.class); public static final String PERCEPTRON_SEQUENCE_VALUE = "PERCEPTRON_SEQUENCE"; private int iterations; private SequenceStream sequenceStream; /** * Number of events in the event set. */ private int numEvents; /** * Number of predicates. */ private int numPreds; private int numOutcomes; /** * List of outcomes for each event i, in context[i]. */ private int[] outcomeList; private String[] outcomeLabels; /** * Stores the average parameter values of each predicate during iteration. */ private MutableContext[] averageParams; /** * Mapping between context and an integer */ private Map pmap; private Map omap; /** * Stores the estimated parameter value of each predicate during iteration. */ private MutableContext[] params; private boolean useAverage; private int[][][] updates; private static final int VALUE = 0; private static final int ITER = 1; private static final int EVENT = 2; private String[] predLabels; private int numSequences; /** * Instantiates a {@link SimplePerceptronSequenceTrainer} with a default * configuration of training parameters. */ public SimplePerceptronSequenceTrainer() { } /** * {@inheritDoc} * * @throws IllegalArgumentException Thrown if the algorithm name is not equal to * {{@link #PERCEPTRON_SEQUENCE_VALUE}}. */ @Override public void validate() { super.validate(); String algorithmName = getAlgorithm(); if (algorithmName != null) { if (!PERCEPTRON_SEQUENCE_VALUE.equals(algorithmName)) { throw new IllegalArgumentException("algorithmName must be PERCEPTRON_SEQUENCE"); } } } @Override public AbstractModel doTrain(SequenceStream events) throws IOException { int iterations = getIterations(); int cutoff = getCutoff(); boolean useAverage = trainingParameters.getBooleanParameter("UseAverage", true); return trainModel(iterations, events, cutoff, useAverage); } // << members related to AbstractSequenceTrainer /** * Trains a {@link PerceptronModel} with given parameters. * * @param iterations The number of iterations to use for training. * @param sequenceStream The {@link SequenceStream} used as data input. * @param cutoff The {{@link TrainingParameters#CUTOFF_PARAM}} value to use for training. * @param useAverage Whether to use 'averaging', or not. * @return A valid, trained {@link AbstractModel perceptron model}. */ public AbstractModel trainModel(int iterations, SequenceStream sequenceStream, int cutoff, boolean useAverage) throws IOException { this.iterations = iterations; this.sequenceStream = sequenceStream; trainingParameters.put(TrainingParameters.CUTOFF_PARAM, cutoff); trainingParameters.put(AbstractDataIndexer.SORT_PARAM, false); DataIndexer di = new OnePassDataIndexer(); di.init(trainingParameters, reportMap); di.index(new SequenceStreamEventStream(sequenceStream)); numSequences = 0; sequenceStream.reset(); while (sequenceStream.read() != null) { numSequences++; } outcomeList = di.getOutcomeList(); predLabels = di.getPredLabels(); pmap = new HashMap<>(); for (int i = 0; i < predLabels.length; i++) { pmap.put(predLabels[i], i); } logger.info("Incorporating indexed data for training... "); this.useAverage = useAverage; numEvents = di.getNumEvents(); this.iterations = iterations; outcomeLabels = di.getOutcomeLabels(); omap = new HashMap<>(); for (int oli = 0; oli < outcomeLabels.length; oli++) { omap.put(outcomeLabels[oli], oli); } outcomeList = di.getOutcomeList(); numPreds = predLabels.length; numOutcomes = outcomeLabels.length; if (useAverage) { updates = new int[numPreds][numOutcomes][3]; } logger.info("done."); logger.info("\tNumber of Event Tokens: {} " + "\n\t Number of Outcomes: {} " + "\n\t Number of Predicates: {}", numEvents, numOutcomes, numPreds); params = new MutableContext[numPreds]; if (useAverage) { averageParams = new MutableContext[numPreds]; } int[] allOutcomesPattern = new int[numOutcomes]; for (int oi = 0; oi < numOutcomes; oi++) { allOutcomesPattern[oi] = oi; } for (int pi = 0; pi < numPreds; pi++) { params[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]); if (useAverage) { averageParams[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]); } for (int aoi = 0; aoi < numOutcomes; aoi++) { params[pi].setParameter(aoi, 0.0); if (useAverage) { averageParams[pi].setParameter(aoi, 0.0); } } } logger.info("Computing model parameters..."); findParameters(iterations); logger.info("...done."); /* Create and return the model ****/ String[] updatedPredLabels = predLabels; if (useAverage) { return new PerceptronModel(averageParams, updatedPredLabels, outcomeLabels); } else { return new PerceptronModel(params, updatedPredLabels, outcomeLabels); } } private void findParameters(int iterations) throws IOException { logger.info("Performing {} iterations.\n", iterations); for (int i = 1; i <= iterations; i++) { nextIteration(i); } if (useAverage) { trainingStats(averageParams); } else { trainingStats(params); } } public void nextIteration(int iteration) throws IOException { iteration--; //move to 0-based index int numCorrect = 0; int oei = 0; int si = 0; List> featureCounts = new ArrayList<>(numOutcomes); for (int oi = 0; oi < numOutcomes; oi++) { featureCounts.add(new HashMap<>()); } PerceptronModel model = new PerceptronModel(params, predLabels, outcomeLabels); sequenceStream.reset(); Sequence sequence; while ((sequence = sequenceStream.read()) != null) { Event[] taggerEvents = sequenceStream.updateContext(sequence, model); Event[] events = sequence.getEvents(); boolean update = false; for (int ei = 0; ei < events.length; ei++, oei++) { if (!taggerEvents[ei].getOutcome().equals(events[ei].getOutcome())) { update = true; //break; } else { numCorrect++; } } if (update) { for (int oi = 0; oi < numOutcomes; oi++) { featureCounts.get(oi).clear(); } if (logger.isTraceEnabled()) { final StringBuilder sb = new StringBuilder(); for (Event event : events) { sb.append(" ").append(event.getOutcome()); } logger.trace("train: {}", sb); } //training feature count computation for (int ei = 0; ei < events.length; ei++, oei++) { String[] contextStrings = events[ei].getContext(); float[] values = events[ei].getValues(); int oi = omap.get(events[ei].getOutcome()); for (int ci = 0; ci < contextStrings.length; ci++) { float value = 1; if (values != null) { value = values[ci]; } Float c = featureCounts.get(oi).get(contextStrings[ci]); if (c == null) { c = value; } else { c += value; } featureCounts.get(oi).put(contextStrings[ci], c); } } //evaluation feature count computation if (logger.isTraceEnabled()) { final StringBuilder sb = new StringBuilder(); for (Event taggerEvent : taggerEvents) { sb.append(" ").append(taggerEvent.getOutcome()); } logger.trace("test: {}", sb); } for (Event taggerEvent : taggerEvents) { String[] contextStrings = taggerEvent.getContext(); float[] values = taggerEvent.getValues(); int oi = omap.get(taggerEvent.getOutcome()); for (int ci = 0; ci < contextStrings.length; ci++) { float value = 1; if (values != null) { value = values[ci]; } Float c = featureCounts.get(oi).get(contextStrings[ci]); if (c == null) { c = -1 * value; } else { c -= value; } if (c == 0f) { featureCounts.get(oi).remove(contextStrings[ci]); } else { featureCounts.get(oi).put(contextStrings[ci], c); } } } for (int oi = 0; oi < numOutcomes; oi++) { for (String feature : featureCounts.get(oi).keySet()) { int pi = pmap.getOrDefault(feature, -1); if (pi != -1) { if (logger.isTraceEnabled()) { logger.trace("{} {} {} {}", si, outcomeLabels[oi], feature, featureCounts.get(oi).get(feature)); } params[pi].updateParameter(oi, featureCounts.get(oi).get(feature)); if (useAverage) { if (updates[pi][oi][VALUE] != 0) { averageParams[pi].updateParameter(oi, updates[pi][oi][VALUE] * (numSequences * (iteration - updates[pi][oi][ITER]) + (si - updates[pi][oi][EVENT]))); if (logger.isTraceEnabled()) { logger.trace("p avp[{}].{}={}", pi, oi, averageParams[pi].getParameters()[oi]); } } if (logger.isTraceEnabled()) { logger.trace("p updates[{}]{{}]=({},{},{})({},{},{}) -> {}", pi, oi, updates[pi][oi][ITER], updates[pi][oi][EVENT], updates[pi][oi][VALUE], iteration, oei, params[pi].getParameters()[oi], averageParams[pi].getParameters()[oi]); } updates[pi][oi][VALUE] = (int) params[pi].getParameters()[oi]; updates[pi][oi][ITER] = iteration; updates[pi][oi][EVENT] = si; } } } } model = new PerceptronModel(params, predLabels, outcomeLabels); } si++; } //finish average computation double totIterations = (double) iterations * si; if (useAverage && iteration == iterations - 1) { for (int pi = 0; pi < numPreds; pi++) { double[] predParams = averageParams[pi].getParameters(); for (int oi = 0; oi < numOutcomes; oi++) { if (updates[pi][oi][VALUE] != 0) { predParams[oi] += updates[pi][oi][VALUE] * (numSequences * (iterations - updates[pi][oi][ITER]) - updates[pi][oi][EVENT]); } if (predParams[oi] != 0) { predParams[oi] /= totIterations; averageParams[pi].setParameter(oi, predParams[oi]); if (logger.isTraceEnabled()) { logger.trace("updates[{}][{}]=({},{},{})({},{},{}) -> {}", pi, oi, updates[pi][oi][ITER], updates[pi][oi][EVENT], updates[pi][oi][VALUE], iterations, 0, params[pi].getParameters()[oi], averageParams[pi].getParameters()[oi]); } } } } } logger.info("{}. ({}/{}) {}", iteration, numCorrect, numEvents, ((double) numCorrect / numEvents)); } private void trainingStats(MutableContext[] params) throws IOException { int numCorrect = 0; int oei = 0; sequenceStream.reset(); Sequence sequence; while ((sequence = sequenceStream.read()) != null) { Event[] taggerEvents = sequenceStream.updateContext(sequence, new PerceptronModel(params, predLabels, outcomeLabels)); for (int ei = 0; ei < taggerEvents.length; ei++, oei++) { int max = omap.get(taggerEvents[ei].getOutcome()); if (max == outcomeList[oei]) { numCorrect++; } } } logger.info(". ({}/{}) {}", numCorrect, numEvents, ((double) numCorrect / numEvents)); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ml/perceptron/package-info.java0100644 0000000 0000000 00000001616 15217274217 033673 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to ML by means of the perceptron algorithm. */ package opennlp.tools.ml.perceptron; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/models/ModelType.java0100644 0000000 0000000 00000002324 15217274217 031740 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.models; /** * A model type to pattern enumeration. */ public enum ModelType { LEMMATIZER("lemma"), TOKENIZER("token"), SENTENCE_DETECTOR("sent"), POS("pos-perceptron"), POS_GENERIC("pos"), NAME_FINDER("ner"), CHUNKER("chunker"), PARSER("parser-chunking"); private final String name; ModelType(String name) { this.name = name; } public String getName() { return name; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_monitoring_Defau0100644 0000000 0000000 00000000174 15217274217 032534 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/DefaultTrainingProgressMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/DefaultTrainingProgre0100644 0000000 0000000 00000005273 15217274217 034265 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.monitoring; import java.util.LinkedList; import java.util.List; import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static opennlp.tools.monitoring.StopCriteria.FINISHED; /** * The default implementation of {@link TrainingProgressMonitor}. * This publishes model training progress to the chosen logging destination. */ public class DefaultTrainingProgressMonitor implements TrainingProgressMonitor { private static final Logger logger = LoggerFactory.getLogger(DefaultTrainingProgressMonitor.class); /** * Keeps a track of whether training was already finished. */ private volatile boolean isTrainingFinished; /** * An underlying list to capture training progress events. */ private final List progress; public DefaultTrainingProgressMonitor() { this.progress = new LinkedList<>(); } /** * {@inheritDoc} */ @Override public synchronized void finishedIteration(int iteration, int numberCorrectEvents, int totalEvents, TrainingMeasure measure, double measureValue) { progress.add(String.format("%s: (%s/%s) %s : %s", iteration, numberCorrectEvents, totalEvents, measure.getMeasureName(), measureValue)); } /** * {@inheritDoc} */ @Override public synchronized void finishedTraining(int iterations, StopCriteria stopCriteria) { if (!Objects.isNull(stopCriteria)) { progress.add(stopCriteria.getMessageIfSatisfied()); } else { progress.add(String.format(FINISHED, iterations)); } isTrainingFinished = true; } /** * {@inheritDoc} */ @Override public synchronized void display(boolean clear) { progress.stream().forEach(logger::info); if (clear) { progress.clear(); } } /** * {@inheritDoc} */ @Override public boolean isTrainingFinished() { return isTrainingFinished; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_monitoring_IterD0100644 0000000 0000000 00000000175 15217274217 032520 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/IterDeltaAccuracyUnderTolerance.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/IterDeltaAccuracyUnde0100644 0000000 0000000 00000003630 15217274217 034165 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.monitoring; import opennlp.tools.ml.perceptron.PerceptronTrainer; import opennlp.tools.util.TrainingParameters; /** * A {@link StopCriteria} implementation to identify whether the absolute * difference between the training accuracy of current and previous iteration is under the defined tolerance. */ public class IterDeltaAccuracyUnderTolerance implements StopCriteria { public static final String STOP = "Stopping: change in training set accuracy less than {%s}"; private final TrainingParameters trainingParameters; public IterDeltaAccuracyUnderTolerance(TrainingParameters trainingParameters) { this.trainingParameters = trainingParameters; } @Override public String getMessageIfSatisfied() { return String.format(STOP, getTolerance()); } @Override public boolean test(Double deltaAccuracy) { return StrictMath.abs(deltaAccuracy) < getTolerance(); } private double getTolerance() { return trainingParameters != null ? trainingParameters.getDoubleParameter("Tolerance", PerceptronTrainer.TOLERANCE_DEFAULT) : PerceptronTrainer.TOLERANCE_DEFAULT; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_monitoring_LogLi0100644 0000000 0000000 00000000174 15217274217 032516 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/LogLikelihoodThresholdBreached.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/LogLikelihoodThreshol0100644 0000000 0000000 00000004064 15217274217 034261 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.monitoring; import opennlp.tools.util.TrainingParameters; import static opennlp.tools.ml.maxent.GISTrainer.LOG_LIKELIHOOD_THRESHOLD_DEFAULT; import static opennlp.tools.ml.maxent.GISTrainer.LOG_LIKELIHOOD_THRESHOLD_PARAM; /** * A {@link StopCriteria} implementation to identify whether the * difference between the log likelihood of current and previous iteration is under the defined threshold. */ public class LogLikelihoodThresholdBreached implements StopCriteria { public static String STOP = "Stopping: Difference between log likelihood of current" + " and previous iteration is less than threshold %s ."; private final TrainingParameters trainingParameters; public LogLikelihoodThresholdBreached(TrainingParameters trainingParameters) { this.trainingParameters = trainingParameters; } @Override public String getMessageIfSatisfied() { return String.format(STOP, getThreshold()); } @Override public boolean test(Double currVsPrevLLDiff) { return currVsPrevLLDiff < getThreshold(); } private double getThreshold() { return trainingParameters != null ? trainingParameters.getDoubleParameter(LOG_LIKELIHOOD_THRESHOLD_PARAM, LOG_LIKELIHOOD_THRESHOLD_DEFAULT) : LOG_LIKELIHOOD_THRESHOLD_DEFAULT; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/StopCriteria.java0100644 0000000 0000000 00000002432 15217274217 033350 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.monitoring; import java.util.function.Predicate; /** * Stop criteria for model training. If the predicate is met, then the training is aborted. * * @see Predicate */ public interface StopCriteria extends Predicate { String FINISHED = "Training finished after completing %s iterations successfully."; /** * @return A detailed message captured upon hitting the {@link StopCriteria} during model training. */ String getMessageIfSatisfied(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/TrainingMeasure.java0100644 0000000 0000000 00000002207 15217274217 034035 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.monitoring; /** * Enumeration of Training measures. */ public enum TrainingMeasure { ACCURACY("Training Accuracy"), LOG_LIKELIHOOD("Log Likelihood"); private String measureName; TrainingMeasure(String measureName) { this.measureName = measureName; } public String getMeasureName() { return measureName; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_monitoring_Train0100644 0000000 0000000 00000000165 15217274217 032565 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/TrainingProgressMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/monitoring/TrainingProgressMonit0100644 0000000 0000000 00000004620 15217274217 034330 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.monitoring; import opennlp.tools.ml.model.AbstractModel; /** * An interface to capture training progress of an {@link AbstractModel}. */ public interface TrainingProgressMonitor { /** * Captures the Iteration progress. * * @param iteration The completed iteration number. * @param numberCorrectEvents Number of correctly predicted events in this iteration. * @param totalEvents Total count of events processed in this iteration. * @param measure {@link TrainingMeasure}. * @param measureValue measure value corresponding to the applicable {@link TrainingMeasure}. */ void finishedIteration(int iteration, int numberCorrectEvents, int totalEvents, TrainingMeasure measure, double measureValue); /** * Captures the training completion progress. * * @param iterations Total number of iterations configured for the training. * @param stopCriteria {@link StopCriteria} for the training. */ void finishedTraining(int iterations, StopCriteria stopCriteria); /** * Checks whether the training has finished. * * @return {@code true} if the training has finished, {@code false} if the training is not yet completed. */ boolean isTrainingFinished(); /** * Displays the training progress and optionally clears the recorded progress (to save memory). * Callers of this method can invoke it periodically * during training, to avoid holding too much progress related data in memory. * * @param clear Set to true to clear the recorded progress. */ void display(boolean clear); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/BilouCodec.java0100644 0000000 0000000 00000013746 15217274217 032356 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.Span; /** * The default {@link SequenceCodec} implementation according to the {@code BILOU} scheme. *

    *
  • B: 'beginning' of a NE
  • *
  • I: 'inside', the word is inside a NE
  • *
  • L: 'last', the last (I) word inside a NE
  • *
  • O: 'outside', the word is a regular word outside a NE
  • *
  • U: 'unit', any standalone token following words outside of NE
  • *
* * See paper by Roth D. and Ratinov L. (2009): * * Design Challenges and Misconceptions in Named Entity Recognition. * * @see SequenceCodec * @see BioCodec */ public class BilouCodec implements SequenceCodec { public static final String START = "start"; public static final String CONTINUE = "cont"; public static final String LAST = "last"; public static final String UNIT = "unit"; public static final String OTHER = "other"; @Override public Span[] decode(List c) { int start = -1; int end = -1; List spans = new ArrayList<>(c.size()); for (int li = 0; li < c.size(); li++) { String chunkTag = c.get(li); if (chunkTag.endsWith(BilouCodec.START)) { start = li; end = li + 1; } else if (chunkTag.endsWith(BilouCodec.CONTINUE)) { end = li + 1; } else if (chunkTag.endsWith(LAST)) { if (start != -1) { spans.add(new Span(start, end + 1, BioCodec.extractNameType(c.get(li - 1)))); start = -1; end = -1; } } else if (chunkTag.endsWith(UNIT)) { spans.add(new Span(li, li + 1, BioCodec.extractNameType(c.get(li)))); } } return spans.toArray(new Span[0]); } @Override public String[] encode(Span[] names, int length) { String[] outcomes = new String[length]; Arrays.fill(outcomes, BilouCodec.OTHER); for (Span name : names) { if (name.length() > 1) { if (name.getType() == null) { outcomes[name.getStart()] = DEFAULT_PREFIX + BilouCodec.START; } else { outcomes[name.getStart()] = name.getType() + "-" + BilouCodec.START; } // now iterate from begin + 1 till end for (int i = name.getStart() + 1; i < name.getEnd() - 1; i++) { if (name.getType() == null) { outcomes[i] = DEFAULT_PREFIX + BilouCodec.CONTINUE; } else { outcomes[i] = name.getType() + "-" + BilouCodec.CONTINUE; } } if (name.getType() == null) { outcomes[name.getEnd() - 1] = DEFAULT_PREFIX + BilouCodec.LAST; } else { outcomes[name.getEnd() - 1] = name.getType() + "-" + BilouCodec.LAST; } } else { if (name.getType() == null) { outcomes[name.getEnd() - 1] = DEFAULT_PREFIX + BilouCodec.UNIT; } else { outcomes[name.getEnd() - 1] = name.getType() + "-" + BilouCodec.UNIT; } } } return outcomes; } @Override public SequenceValidator createSequenceValidator() { return new BilouNameFinderSequenceValidator(); } /** * {@code * B requires CL or L, * C requires BL, * L requires B, * O requires any valid combo/unit, * U requires none. * } * * @param outcomes All potential model outcomes check. * * @return {@code true}, if model outcomes are compatible, {@code false} otherwise. */ @Override public boolean areOutcomesCompatible(String[] outcomes) { Set start = new HashSet<>(); Set cont = new HashSet<>(); Set last = new HashSet<>(); Set unit = new HashSet<>(); for (String outcome : outcomes) { if (outcome.endsWith(BilouCodec.START)) { start.add(outcome.substring(0, outcome.length() - BilouCodec.START.length())); } else if (outcome.endsWith(BilouCodec.CONTINUE)) { cont.add(outcome.substring(0, outcome.length() - BilouCodec.CONTINUE.length())); } else if (outcome.endsWith(BilouCodec.LAST)) { last.add(outcome.substring(0, outcome.length() - BilouCodec.LAST.length())); } else if (outcome.endsWith(BilouCodec.UNIT)) { unit.add(outcome.substring(0, outcome.length() - BilouCodec.UNIT.length())); } else if (!outcome.equals(BilouCodec.OTHER)) { return false; } } if (start.isEmpty() && unit.isEmpty()) { return false; } else { // Start, must have matching Last for (String startPrefix : start) { if (!last.contains(startPrefix)) { return false; } } // Cont, must have matching Start and Last for (String contPrefix : cont) { if (!start.contains(contPrefix) && !last.contains(contPrefix)) { return false; } } // Last, must have matching Start for (String lastPrefix : last) { if (!start.contains(lastPrefix)) { return false; } } } return true; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_BilouNa0100644 0000000 0000000 00000000174 15217274217 032435 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/BilouNameFinderSequenceValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/BilouNameFinderSequence0100644 0000000 0000000 00000005267 15217274217 034121 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.util.SequenceValidator; /** * A {@link SequenceValidator} implementation for the {@link BilouCodec}. * * @see BilouCodec */ public class BilouNameFinderSequenceValidator implements SequenceValidator { @Override public boolean validSequence(int i, String[] inputSequence, String[] outcomesSequence, String outcome) { if (outcome.endsWith(BilouCodec.CONTINUE) || outcome.endsWith(BilouCodec.LAST)) { int li = outcomesSequence.length - 1; if (li == -1) { return false; } else if (outcomesSequence[li].endsWith(BilouCodec.OTHER) || outcomesSequence[li].endsWith(BilouCodec.UNIT)) { return false; } else if (outcomesSequence[li].endsWith(BilouCodec.LAST) && (outcome.endsWith(BilouCodec.CONTINUE) || outcome.endsWith(BilouCodec.LAST))) { return false; } else if (outcomesSequence[li].endsWith(BilouCodec.CONTINUE) || outcomesSequence[li].endsWith(BilouCodec.START)) { // if it is continue, we have to check if previous match was of the same type String previousNameType = NameFinderME.extractNameType(outcomesSequence[li]); String nameType = NameFinderME.extractNameType(outcome); if (previousNameType != null || nameType != null) { if (nameType != null) { return nameType.equals(previousNameType); } return false; // outcomes types are not equal } } } if (outcomesSequence.length > 0) { if (outcome.endsWith(BilouCodec.START) || outcome.endsWith(BilouCodec.OTHER) || outcome.endsWith(BilouCodec.UNIT)) { return !outcomesSequence[outcomesSequence.length - 1].endsWith(BilouCodec.START) && !outcomesSequence[outcomesSequence.length - 1].endsWith(BilouCodec.CONTINUE); } } return true; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/BioCodec.java0100644 0000000 0000000 00000011620 15217274217 032002 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.Span; /** * The default {@link SequenceCodec} implementation according to the {@code BIO} scheme: *
    *
  • B: 'beginning' of a NE
  • *
  • I: 'inside', the word is inside a NE
  • *
  • O: 'outside', the word is a regular word outside a NE
  • *
* * See also the paper by Roth D. and Ratinov L.: * * Design Challenges and Misconceptions in Named Entity Recognition. * * @see SequenceCodec * @see BilouCodec */ public class BioCodec implements SequenceCodec { public static final String START = "start"; public static final String CONTINUE = "cont"; public static final String OTHER = "other"; private static final Pattern TYPED_OUTCOME_PATTERN = Pattern.compile("(.+)-\\w+"); static String extractNameType(String outcome) { Matcher matcher = TYPED_OUTCOME_PATTERN.matcher(outcome); if (matcher.matches()) { return matcher.group(1); } return null; } @Override public Span[] decode(List c) { int start = -1; int end = -1; List spans = new ArrayList<>(c.size()); for (int li = 0; li < c.size(); li++) { String chunkTag = c.get(li); if (chunkTag.endsWith(BioCodec.START)) { if (start != -1) { spans.add(new Span(start, end, extractNameType(c.get(li - 1)))); } start = li; end = li + 1; } else if (chunkTag.endsWith(BioCodec.CONTINUE)) { end = li + 1; } else if (chunkTag.endsWith(BioCodec.OTHER)) { if (start != -1) { spans.add(new Span(start, end, extractNameType(c.get(li - 1)))); start = -1; end = -1; } } } if (start != -1) { spans.add(new Span(start, end, extractNameType(c.get(c.size() - 1)))); } return spans.toArray(new Span[0]); } @Override public String[] encode(Span[] names, int length) { String[] outcomes = new String[length]; Arrays.fill(outcomes, BioCodec.OTHER); for (Span name : names) { if (name.getType() == null) { outcomes[name.getStart()] = DEFAULT_PREFIX + BioCodec.START; } else { outcomes[name.getStart()] = name.getType() + "-" + BioCodec.START; } // now iterate from begin + 1 till end for (int i = name.getStart() + 1; i < name.getEnd(); i++) { if (name.getType() == null) { outcomes[i] = DEFAULT_PREFIX + BioCodec.CONTINUE; } else { outcomes[i] = name.getType() + "-" + BioCodec.CONTINUE; } } } return outcomes; } @Override public NameFinderSequenceValidator createSequenceValidator() { return new NameFinderSequenceValidator(); } @Override public boolean areOutcomesCompatible(String[] outcomes) { // We should have *optionally* one outcome named "other", some named xyz-start and sometimes // they have a pair xyz-cont. We should not have any other outcome // To validate the model we check if we have one outcome named "other", at least // one outcome with suffix start. After that we check if all outcomes that ends with // "cont" have a pair that ends with "start". List start = new ArrayList<>(); List cont = new ArrayList<>(); for (String outcome : outcomes) { if (outcome.endsWith(BioCodec.START)) { start.add(outcome.substring(0, outcome.length() - BioCodec.START.length())); } else if (outcome.endsWith(BioCodec.CONTINUE)) { cont.add(outcome.substring(0, outcome.length() - BioCodec.CONTINUE.length())); } else if (!outcome.equals(BioCodec.OTHER)) { // got unexpected outcome return false; } } if (start.isEmpty()) { return false; } else { for (String contPreffix : cont) { if (!start.contains(contPreffix)) { return false; } } } return true; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_Default0100644 0000000 0000000 00000000167 15217274217 032472 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/DefaultNameContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/DefaultNameContextGener0100644 0000000 0000000 00000010425 15217274217 034130 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.util.ArrayList; import java.util.List; import java.util.Objects; import opennlp.tools.util.featuregen.AdaptiveFeatureGenerator; import opennlp.tools.util.featuregen.FeatureGeneratorUtil; /** * A {@link NameContextGenerator} implementation for determining contextual features * for a {@code tag-chunk} style named-entity recognizer. */ public class DefaultNameContextGenerator implements NameContextGenerator { protected AdaptiveFeatureGenerator[] featureGenerators; /** * Creates a name context generator with the specified * {@link AdaptiveFeatureGenerator feature generators}. * * @param featureGenerators One or more {@link AdaptiveFeatureGenerator feature generators}. */ public DefaultNameContextGenerator(AdaptiveFeatureGenerator... featureGenerators) { this.featureGenerators = Objects.requireNonNull( featureGenerators, "Please specify at least one featureGenerator"); } @Override public void addFeatureGenerator(AdaptiveFeatureGenerator generator) { AdaptiveFeatureGenerator[] generators = featureGenerators; featureGenerators = new AdaptiveFeatureGenerator[featureGenerators.length + 1]; System.arraycopy(generators, 0, featureGenerators, 0, generators.length); featureGenerators[featureGenerators.length - 1] = generator; } @Override public void updateAdaptiveData(String[] tokens, String[] outcomes) { if (tokens != null && outcomes != null && tokens.length != outcomes.length) { throw new IllegalArgumentException( "The tokens and outcome arrays MUST have the same size!"); } for (AdaptiveFeatureGenerator featureGenerator : featureGenerators) { featureGenerator.updateAdaptiveData(tokens, outcomes); } } @Override public void clearAdaptiveData() { for (AdaptiveFeatureGenerator featureGenerator : featureGenerators) { featureGenerator.clearAdaptiveData(); } } /** * Finds the context for finding names at the specified index. * * @param index The index of the token in the specified {@code tokens} for which the * context should be constructed. * @param tokens The tokens of the sentence. The {@code toString()} methods * of these objects should return the token text. * @param preds The previous decisions made in the tagging of this sequence. * Only indices less than {@code index} will be examined. * @param additionalContext Addition features which may be based on a context outside the sentence. * * @return The context for finding names at the specified {@code index}. */ @Override public String[] getContext(int index, String[] tokens, String[] preds, Object[] additionalContext) { List features = new ArrayList<>(); for (AdaptiveFeatureGenerator featureGenerator : featureGenerators) { featureGenerator.createFeatures(features, tokens, index, preds); } //previous outcome features String po = NameFinderME.OTHER; String ppo = NameFinderME.OTHER; // TODO: These should be moved out here in its own feature generator! if (preds != null) { if (index > 1) { ppo = preds[index - 2]; } if (index > 0) { po = preds[index - 1]; } features.add("po=" + po); features.add("pow=" + po + "," + tokens[index]); features.add("powf=" + po + "," + FeatureGeneratorUtil.tokenFeature(tokens[index])); features.add("ppo=" + ppo); } return features.toArray(new String[0]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_Diction0100644 0000000 0000000 00000000160 15217274217 032470 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/DictionaryNameFinder.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/DictionaryNameFinder.ja0100644 0000000 0000000 00000006666 15217274217 034060 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.util.LinkedList; import java.util.List; import java.util.Objects; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.util.Span; import opennlp.tools.util.StringList; /** * This is a {@link Dictionary} based {@link TokenNameFinder name finder}. * It scans text for names inside a provided dictionary. */ public class DictionaryNameFinder implements TokenNameFinder { private static final String DEFAULT_TYPE = "default"; private final Dictionary mDictionary; private final String type; /** * Initializes a {@link DictionaryNameFinder} with the provided {@link Dictionary} * and a {@code type}. * * @param dictionary The {@link Dictionary} to use. Must not be {@code null}. * @param type the name type used for the produced spans. Must not be {@code null}. */ public DictionaryNameFinder(Dictionary dictionary, String type) { this.mDictionary = Objects.requireNonNull(dictionary, "dictionary must not be null"); this.type = Objects.requireNonNull(type, "type must not be null"); } /** * Initializes a {@link DictionaryNameFinder} with the provided {@link Dictionary} * and {@link #DEFAULT_TYPE}. * * @param dictionary The {@link Dictionary} to use. Must not be {@code null}. */ public DictionaryNameFinder(Dictionary dictionary) { this(dictionary, DEFAULT_TYPE); } @Override public Span[] find(String[] textTokenized) { List namesFound = new LinkedList<>(); final boolean caseSensitive = mDictionary.isCaseSensitive(); final int maxTokenCount = mDictionary.getMaxTokenCount(); for (int offsetFrom = 0; offsetFrom < textTokenized.length; offsetFrom++) { Span nameFound = null; String[] tokensSearching; for (int offsetTo = offsetFrom; offsetTo < textTokenized.length; offsetTo++) { int lengthSearching = offsetTo - offsetFrom + 1; if (lengthSearching > maxTokenCount) { break; } else { tokensSearching = new String[lengthSearching]; System.arraycopy(textTokenized, offsetFrom, tokensSearching, 0, lengthSearching); StringList entryForSearch = new StringList(caseSensitive, tokensSearching); if (mDictionary.contains(entryForSearch)) { nameFound = new Span(offsetFrom, offsetTo + 1, type); } } } if (nameFound != null) { namesFound.add(nameFound); // skip over the found tokens for the next search offsetFrom += nameFound.length() - 1; } } return namesFound.toArray(new Span[0]); } @Override public void clearAdaptiveData() { // nothing to clear } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_Documen0100644 0000000 0000000 00000000156 15217274217 032476 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/DocumentNameFinder.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/DocumentNameFinder.java0100644 0000000 0000000 00000003343 15217274217 034045 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.util.Span; /** * Interface for processing an entire document allowing a {@link TokenNameFinder} to use context * from the entire document. *

* EXPERIMENTAL: * This interface has been added as part of a work in progress and might change without notice. */ public interface DocumentNameFinder { /** * Finds tokens {@link Span spans} for the specified document of sentences and their tokens. *

* Span start and end indices are relative to the sentence they are in. * For example, a span identifying a name consisting of the first and second word * of the second sentence would be {@code 0..2} and be referenced as {@code spans[1][0]}. * * @param document A 2-dimensional array of tokens for each sentence of a document. * @return The {@link Span token spans} for each sentence of the specified document. */ Span[][] find(String[][] document); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_NameCon0100644 0000000 0000000 00000000160 15217274217 032417 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameContextGenerator.ja0100644 0000000 0000000 00000003771 15217274217 034110 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.util.BeamSearchContextGenerator; import opennlp.tools.util.featuregen.AdaptiveFeatureGenerator; /** * Interface for generating the context for a {@link TokenNameFinder name finder} by * specifying a set of feature generators. * * @see BeamSearchContextGenerator * @see AdaptiveFeatureGenerator */ public interface NameContextGenerator extends BeamSearchContextGenerator { /** * Adds a feature generator. * * @param generator The {@link AdaptiveFeatureGenerator feature generator} to add. */ void addFeatureGenerator(AdaptiveFeatureGenerator generator); /** * Informs all the feature generators that the specified {@code tokens} * have been classified with the corresponds set of specified {@code outcomes}. * * @param tokens The tokens of a sentence or another text unit which has been processed. * @param outcomes The outcomes associated with the specified {@code tokens}. */ void updateAdaptiveData(String[] tokens, String[] outcomes); /** * Informs all the feature generators that the context of the adaptive * data (typically a document) is no longer valid and should be cleared. */ void clearAdaptiveData(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_NameFin0100644 0000000 0000000 00000000161 15217274217 032415 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameFinderEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameFinderEventStream.j0100644 0000000 0000000 00000015015 15217274217 034033 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import opennlp.tools.ml.model.Event; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.Span; import opennlp.tools.util.featuregen.AdditionalContextFeatureGenerator; import opennlp.tools.util.featuregen.WindowFeatureGenerator; /** * Class for creating an event stream out of data files for training an {@link TokenNameFinder}. */ public class NameFinderEventStream extends opennlp.tools.util.AbstractEventStream { private final NameContextGenerator contextGenerator; private final AdditionalContextFeatureGenerator additionalContextFeatureGenerator = new AdditionalContextFeatureGenerator(); private final SequenceCodec codec; private final String defaultType; /** * Initializes a {@link NameFinderEventStream} using the specified {@code dataStream} and * {@link NameContextGenerator}. * * @param dataStream The {@link ObjectStream data stream} of events. * @param type {@code null} or overrides the type parameter in the provided samples. * @param contextGenerator The {@link NameContextGenerator} used to generate features for the event stream. * @param codec The {@link SequenceCodec} to use. */ public NameFinderEventStream(ObjectStream dataStream, String type, NameContextGenerator contextGenerator, SequenceCodec codec) { super(dataStream); this.codec = Objects.requireNonNullElseGet(codec, BioCodec::new); this.contextGenerator = contextGenerator; this.contextGenerator.addFeatureGenerator( new WindowFeatureGenerator(additionalContextFeatureGenerator, 8, 8)); this.defaultType = type; } /** * Generates the name tag outcomes ({@code start}, {@code continue}, {@code other}) for each * token in a sentence with the specified {@code length} using the specified {@link Span names}. * * @param names Token {@link Span spans} for each of the names. * @param type {@code null} or overrides the type parameter in the provided samples * @param length The length of the sentence. * * @return An array of {@code start}, {@code continue}, {@code other} outcomes based on the * specified names and sentence {@code length}. * * @deprecated use the {@link BioCodec} implementation of the SequenceValidator instead! */ @Deprecated(forRemoval = true) public static String[] generateOutcomes(Span[] names, String type, int length) { String[] outcomes = new String[length]; Arrays.fill(outcomes, NameFinderME.OTHER); for (Span name : names) { if (name.getType() == null) { outcomes[name.getStart()] = type + "-" + NameFinderME.START; } else { outcomes[name.getStart()] = name.getType() + "-" + NameFinderME.START; } // now iterate from begin + 1 till end for (int i = name.getStart() + 1; i < name.getEnd(); i++) { if (name.getType() == null) { outcomes[i] = type + "-" + NameFinderME.CONTINUE; } else { outcomes[i] = name.getType() + "-" + NameFinderME.CONTINUE; } } } return outcomes; } /** * Generates {@link Event events} for each token in a {@code sentence} * with the specified {@code outcomes} using the specified {@link NameContextGenerator}. * * @param sentence Token representing a sentence. * @param outcomes An array of outcomes. * @param cg The {@link NameContextGenerator} to use. * * @return A list of {@link Event events} generated. */ public static List generateEvents(String[] sentence, String[] outcomes, NameContextGenerator cg) { List events = new ArrayList<>(outcomes.length); for (int i = 0; i < outcomes.length; i++) { events.add(new Event(outcomes[i], cg.getContext(i, sentence, outcomes,null))); } cg.updateAdaptiveData(sentence, outcomes); return events; } @Override protected Iterator createEvents(NameSample sample) { if (sample.isClearAdaptiveDataSet()) { contextGenerator.clearAdaptiveData(); } Span[] names = sample.getNames(); if (!Objects.isNull(this.defaultType)) { overrideType(names); } String[] outcomes = codec.encode(names, sample.getSentence().length); // String outcomes[] = generateOutcomes(sample.getNames(), type, sample.getSentence().length); additionalContextFeatureGenerator.setCurrentContext(sample.getAdditionalContext()); String[] tokens = new String[sample.getSentence().length]; for (int i = 0; i < sample.getSentence().length; i++) { tokens[i] = sample.getSentence()[i]; } return generateEvents(tokens, outcomes, contextGenerator).iterator(); } private void overrideType(Span[] names) { for (int i = 0; i < names.length; i++) { Span n = names[i]; names[i] = new Span(n.getStart(), n.getEnd(), this.defaultType, n.getProb()); } } /** * Generated previous decision features for each token based on contents of the * specified {@code prevMap}. * * @param tokens The token for which the context is generated. * @param prevMap A mapping of tokens to their previous decisions. * @return A 2-dimensional array with additional context with features for each token. */ public static String[][] additionalContext(String[] tokens, Map prevMap) { String[][] ac = new String[tokens.length][1]; for (int ti = 0; ti < tokens.length; ti++) { String pt = prevMap.get(tokens[ti]); ac[ti][0] = "pd=" + pt; } return ac; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameFinderME.java0100644 0000000 0000000 00000026313 15217274217 032572 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.EventModelSequenceTrainer; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.Probabilistic; import opennlp.tools.ml.SequenceTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.TrainerFactory.TrainerType; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.ml.perceptron.PerceptronTrainer; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Sequence; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.Span; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.featuregen.AdditionalContextFeatureGenerator; import opennlp.tools.util.featuregen.WindowFeatureGenerator; /** * A maximum-entropy-based {@link TokenNameFinder name finder} implementation. * * @see Probabilistic * @see TokenNameFinder */ public class NameFinderME implements TokenNameFinder, Probabilistic { private static final String[][] EMPTY = new String[0][0]; public static final int DEFAULT_BEAM_SIZE = 3; private static final Pattern typedOutcomePattern = Pattern.compile("(.+)-\\w+"); public static final String START = "start"; public static final String CONTINUE = "cont"; public static final String OTHER = "other"; private final SequenceCodec seqCodec; protected final SequenceClassificationModel model; protected final NameContextGenerator contextGenerator; private Sequence bestSequence; private final AdditionalContextFeatureGenerator additionalContextFeatureGenerator = new AdditionalContextFeatureGenerator(); private final SequenceValidator sequenceValidator; /** * Initializes a {@link NameFinderME} with a {@link TokenNameFinderModel}. * * @param model The {@link TokenNameFinderModel} to initialize with. */ public NameFinderME(TokenNameFinderModel model) { TokenNameFinderFactory factory = model.getFactory(); seqCodec = factory.createSequenceCodec(); sequenceValidator = seqCodec.createSequenceValidator(); this.model = model.getNameFinderSequenceModel(); contextGenerator = factory.createContextGenerator(); // TODO: We should deprecate this. And come up with a better solution! contextGenerator.addFeatureGenerator( new WindowFeatureGenerator(additionalContextFeatureGenerator, 8, 8)); } @Override public Span[] find(String[] tokens) { return find(tokens, EMPTY); } /** * Generates name tags for the given sequence, typically a sentence, returning * {@link Span token spans} for any identified names. * * @param tokens An array of the tokens or words of a sequence, typically a sentence. * @param additionalContext Features which are based on context outside of the * sentence but which should also be used. * * @return An array of {@link Span token spans} for each of the names identified. */ public Span[] find(String[] tokens, String[][] additionalContext) { additionalContextFeatureGenerator.setCurrentContext(additionalContext); bestSequence = model.bestSequence(tokens, additionalContext, contextGenerator, sequenceValidator); List c = bestSequence.getOutcomes(); contextGenerator.updateAdaptiveData(tokens, c.toArray(new String[0])); Span[] spans = seqCodec.decode(c); spans = setProbs(spans); return spans; } @Override public void clearAdaptiveData() { contextGenerator.clearAdaptiveData(); } /** * Populates the specified array with the probabilities of the last decoded * sequence. The sequence was determined based on the previous call to * {@link #find(String[])}. The specified array should be at least as large as the * number of tokens in the previous call to {@link #find(String[])}. * * @param probs An array with the probabilities of the last decoded sequence. */ public void probs(double[] probs) { bestSequence.getProbs(probs); } /** * {@inheritDoc} * * The sequence was determined based on the previous call to {@link #find(String[])}. * * @return An array with the same number of probabilities as tokens were sent * to {@link #find(String[])} when it was last called. */ @Override public double[] probs() { return bestSequence.getProbs(); } /** * Sets probabilities for the spans. * * @param spans The {@link Span spans} to set probabilities. * * @return The {@link Span spans} with populated values. */ private Span[] setProbs(Span[] spans) { double[] probs = probs(spans); if (probs != null) { for (int i = 0; i < probs.length; i++) { double prob = probs[i]; spans[i] = new Span(spans[i], prob); } } return spans; } /** * Retrieves an array of probabilities for each of the specified spans which is * the arithmetic mean of the probabilities for each of the outcomes which * make up the span. * * @param spans The {@link Span spans} of the names for which probabilities * are requested. * * @return An array of probabilities for each of the specified spans. */ public double[] probs(Span[] spans) { double[] sprobs = new double[spans.length]; double[] probs = bestSequence.getProbs(); for (int si = 0; si < spans.length; si++) { double p = 0; for (int oi = spans[si].getStart(); oi < spans[si].getEnd(); oi++) { p += probs[oi]; } p /= spans[si].length(); sprobs[si] = p; } return sprobs; } /** * Starts a training of a {@link TokenNameFinderModel} with the given parameters. * * @param languageCode The ISO conform language code. * @param type The type to use. * @param samples The {@link ObjectStream} of {@link NameSample} used as input for training. * @param params The {@link TrainingParameters} for the context of the training. * @param factory The {@link TokenNameFinderFactory} for creating related objects defined * via {@code params}. * * @return A valid, trained {@link TokenNameFinderModel} instance. * @throws IOException Thrown if IO errors occurred during training. */ public static TokenNameFinderModel train(String languageCode, String type, ObjectStream samples, TrainingParameters params, TokenNameFinderFactory factory) throws IOException { params.putIfAbsent(TrainingParameters.ALGORITHM_PARAM, PerceptronTrainer.PERCEPTRON_VALUE); params.putIfAbsent(TrainingParameters.CUTOFF_PARAM, 0); params.putIfAbsent(TrainingParameters.ITERATIONS_PARAM, 300); int beamSize = params.getIntParameter(BeamSearch.BEAM_SIZE_PARAMETER, NameFinderME.DEFAULT_BEAM_SIZE); Map manifestInfoEntries = new HashMap<>(); MaxentModel nameFinderModel = null; SequenceClassificationModel seqModel = null; TrainerType trainerType = TrainerFactory.getTrainerType(params); if (TrainerType.EVENT_MODEL_TRAINER.equals(trainerType)) { ObjectStream eventStream = new NameFinderEventStream(samples, type, factory.createContextGenerator(), factory.createSequenceCodec()); EventTrainer trainer = TrainerFactory.getEventTrainer(params, manifestInfoEntries); nameFinderModel = trainer.train(eventStream); } // TODO: Maybe it is not a good idea, that these two don't use the context generator ?! // These also don't use the sequence codec ?! else if (TrainerType.EVENT_MODEL_SEQUENCE_TRAINER.equals(trainerType)) { NameSampleSequenceStream ss = new NameSampleSequenceStream(samples, factory.createContextGenerator()); EventModelSequenceTrainer trainer = TrainerFactory.getEventModelSequenceTrainer( params, manifestInfoEntries); nameFinderModel = trainer.train(ss); } else if (TrainerType.SEQUENCE_TRAINER.equals(trainerType)) { SequenceTrainer trainer = TrainerFactory.getSequenceModelTrainer( params, manifestInfoEntries); NameSampleSequenceStream ss = new NameSampleSequenceStream(samples, factory.createContextGenerator(), false); seqModel = trainer.train(ss); } else { throw new IllegalStateException("Unexpected trainer type!"); } if (seqModel != null) { return new TokenNameFinderModel(languageCode, seqModel, factory.getFeatureGenerator(), factory.getResources(), manifestInfoEntries, factory.getSequenceCodec(), factory); } else { return new TokenNameFinderModel(languageCode, nameFinderModel, beamSize, factory.getFeatureGenerator(), factory.getResources(), manifestInfoEntries, factory.getSequenceCodec(), factory); } } /** * Extracts the name type from the {@code outcome}. * * @param outcome The outcome * @return The name type, or {@code null} if not set. */ static String extractNameType(String outcome) { Matcher matcher = typedOutcomePattern.matcher(outcome); if (matcher.matches()) { return matcher.group(1); } return null; } /** * Removes {@link Span spans} with are intersecting or crossing in any way. * *

* The following rules are used to remove the spans:
* Identical spans: The first span in the array after sorting it remains.
* Intersecting spans: The first span after sorting remains.
* Contained spans: All spans which are contained by another are removed.
* * @param spans The input {@link Span spans}. * * @return The resulting non-overlapping {@link Span spans}. */ public static Span[] dropOverlappingSpans(Span[] spans) { List sortedSpans = new ArrayList<>(spans.length); Collections.addAll(sortedSpans, spans); Collections.sort(sortedSpans); Iterator it = sortedSpans.iterator(); Span lastSpan = null; while (it.hasNext()) { Span span = it.next(); if (lastSpan != null) { if (lastSpan.intersects(span)) { it.remove(); span = lastSpan; } } lastSpan = span; } return sortedSpans.toArray(new Span[0]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_NameFin0100644 0000000 0000000 00000000167 15217274217 032423 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameFinderSequenceValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameFinderSequenceValid0100644 0000000 0000000 00000004250 15217274217 034075 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.util.SequenceValidator; /** * The default name finder {@link SequenceValidator} implementation. * Created by the {@link BioCodec}. * * @see TokenNameFinder * @see BioCodec */ public class NameFinderSequenceValidator implements SequenceValidator { @Override public boolean validSequence(int i, String[] inputSequence, String[] outcomesSequence, String outcome) { // outcome is formatted like "cont" or "sometype-cont", so we // can check if it ends with "cont". if (outcome.endsWith(BioCodec.CONTINUE)) { int li = outcomesSequence.length - 1; if (li == -1) { return false; } else if (outcomesSequence[li].endsWith(BioCodec.OTHER)) { return false; } else if (outcomesSequence[li].endsWith(BioCodec.CONTINUE) || outcomesSequence[li].endsWith(BioCodec.START)) { // if it is continue or start, we have to check if previous match was of the same type String previousNameType = NameFinderME.extractNameType(outcomesSequence[li]); String nameType = NameFinderME.extractNameType(outcome); if (previousNameType != null || nameType != null ) { if (nameType != null ) { return nameType.equals(previousNameType); } return false; // outcomes types are not equal } } } return true; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameSample.java0100644 0000000 0000000 00000026140 15217274217 032360 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import opennlp.tools.commons.Sample; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.Span; /** * Encapsulates names for a single unit of text. */ public class NameSample implements Sample { private static final long serialVersionUID = 1655333056555270688L; private final String id; private final List sentence; private final List names; private final String[][] additionalContext; private final boolean isClearAdaptiveData; /** The default type value when there is no type in training data. */ public static final String DEFAULT_TYPE = "default"; /** * Initializes a {@link NameSample} instance with given parameters. * * @param id The identifier to use. * @param sentence The tokens representing a training sentence. Must not be {@code null}. * @param names The {@link Span names} to use. * @param additionalContext Additional context in a 2-dimensional array. * @param clearAdaptiveData If {@code true} the adaptive data of the feature generators is cleared. * * @throws RuntimeException Thrown if name spans are overlapping. */ public NameSample(String id, String[] sentence, Span[] names, String[][] additionalContext, boolean clearAdaptiveData) { this.id = id; Objects.requireNonNull(sentence, "sentence must not be null"); if (names == null) { names = new Span[0]; } this.sentence = List.of(sentence); List namesList = Arrays.asList(names); Collections.sort(namesList); this.names = Collections.unmodifiableList(namesList); if (additionalContext != null) { this.additionalContext = new String[additionalContext.length][]; for (int i = 0; i < additionalContext.length; i++) { this.additionalContext[i] = new String[additionalContext[i].length]; System.arraycopy(additionalContext[i], 0, this.additionalContext[i], 0, additionalContext[i].length); } } else { this.additionalContext = null; } isClearAdaptiveData = clearAdaptiveData; // Check that name spans are not overlapping, otherwise throw exception if (this.names.size() > 1) { for (int i = 1; i < this.names.size(); i++) { if (this.names.get(i).getStart() < this.names.get(i - 1).getEnd()) { throw new RuntimeException(String.format("name spans %s and %s are overlapped in file: %s," + " sentence: %s", this.names.get(i - 1), this.names.get(i), id, this.sentence.toString())); } } } } /** * Initializes a {@link NameSample} instance with given parameters. * * @param sentence The tokens representing a sentence. Must not be {@code null}. * @param names The {@link Span names} to use. * @param additionalContext Additional context in a 2-dimensional array. * @param clearAdaptiveData If {@code true} the adaptive data of the feature generators is cleared. * * @throws RuntimeException Thrown if name spans are overlapping. */ public NameSample(String[] sentence, Span[] names, String[][] additionalContext, boolean clearAdaptiveData) { this(null, sentence, names, additionalContext, clearAdaptiveData); } /** * Initializes a {@link NameSample} instance with given parameters. * * @param sentence The tokens representing a sentence. Must not be {@code null}. * @param names The {@link Span names} to use. * @param clearAdaptiveData If {@code true} the adaptive data of the feature generators is cleared. * * @throws RuntimeException Thrown if name spans are overlapping. */ public NameSample(String[] sentence, Span[] names, boolean clearAdaptiveData) { this(sentence, names, null, clearAdaptiveData); } /** * @return Retrieves the current identifier. May be {@code null}. */ public String getId() { return id; } /** * @return Retrieves the sentence in tokenized form. */ public String[] getSentence() { return sentence.toArray(new String[0]); } /** * @return Retrieves the {@link Span names}. */ public Span[] getNames() { return names.toArray(new Span[0]); } /** * @return Retrieves additional context. May be {@code null}. */ public String[][] getAdditionalContext() { return additionalContext; } /** * @return {@code true} if the adaptive data of the feature generators are cleared, * {@code false} otherwise. */ public boolean isClearAdaptiveDataSet() { return isClearAdaptiveData; } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(getSentence()), Arrays.hashCode(getNames()), Arrays.hashCode(getAdditionalContext()), isClearAdaptiveDataSet()); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof NameSample a) { return Arrays.equals(getSentence(), a.getSentence()) && Arrays.equals(getNames(), a.getNames()) && Arrays.equals(getAdditionalContext(), a.getAdditionalContext()) && isClearAdaptiveDataSet() == a.isClearAdaptiveDataSet(); } return false; } @Override public String toString() { StringBuilder result = new StringBuilder(); // If adaptive data must be cleared insert an empty line // before the sample sentence line if (isClearAdaptiveDataSet()) result.append("\n"); for (int tokenIndex = 0; tokenIndex < sentence.size(); tokenIndex++) { // token for (Span name : names) { if (name.getStart() == tokenIndex) { // check if nameTypes is null, or if the nameType for this specific // entity is empty. If it is, we leave the nameType blank. if (name.getType() == null) { result.append(NameSampleDataStream.START_TAG).append(' '); } else { result.append(NameSampleDataStream.START_TAG_PREFIX).append(name.getType()).append("> "); } } if (name.getEnd() == tokenIndex) { result.append(NameSampleDataStream.END_TAG).append(' '); } } result.append(sentence.get(tokenIndex)).append(' '); } if (sentence.size() > 1) result.setLength(result.length() - 1); for (Span name : names) { if (name.getEnd() == sentence.size()) { result.append(' ').append(NameSampleDataStream.END_TAG); } } return result.toString(); } private static String errorTokenWithContext(String[] sentence, int index) { StringBuilder errorString = new StringBuilder(); // two token before if (index > 1) errorString.append(sentence[index - 2]).append(" "); if (index > 0) errorString.append(sentence[index - 1]).append(" "); // token itself errorString.append("###"); errorString.append(sentence[index]); errorString.append("###").append(" "); // two token after if (index + 1 < sentence.length) errorString.append(sentence[index + 1]).append(" "); if (index + 2 < sentence.length) errorString.append(sentence[index + 2]); return errorString.toString(); } private static final Pattern START_TAG_PATTERN = Pattern.compile("\\s]*))?>"); /** * Parses given input into a {@link NameSample}. * * @param taggedTokens The input data to parse. * @param clearAdaptiveData {@code true} if the adaptive data of the feature generators should be cleared, * {@code false} otherwise. * @return A {@link NameSample} instance resulting from the parsing. * @throws IOException Thrown if IO errors occurred during parsing. */ public static NameSample parse(String taggedTokens, boolean clearAdaptiveData) throws IOException { return parse(taggedTokens, DEFAULT_TYPE, clearAdaptiveData); } /** * Parses given input into a {@link NameSample}. * * @param taggedTokens The input data to parse. * @param defaultType The type to set by default. * @param clearAdaptiveData {@code true} if the adaptive data of the feature generators should be cleared, * {@code false} otherwise. * @return A {@link NameSample} instance resulting from the parsing. * @throws IOException Thrown if IO errors occurred during parsing. */ // TODO: Should throw another exception, and then convert it into an IOException in the stream public static NameSample parse(String taggedTokens, String defaultType, boolean clearAdaptiveData) throws IOException { String[] parts = WhitespaceTokenizer.INSTANCE.tokenize(taggedTokens); List tokenList = new ArrayList<>(parts.length); List nameList = new ArrayList<>(); String nameType = defaultType; int startIndex = -1; int wordIndex = 0; // we check if at least one name has the a type. If no one has, we will // leave the NameType property of NameSample null. boolean catchingName = false; for (int pi = 0; pi < parts.length; pi++) { Matcher startMatcher = START_TAG_PATTERN.matcher(parts[pi]); if (startMatcher.matches()) { if (catchingName) { throw new IOException("Found unexpected annotation" + " while handling a name sequence: " + errorTokenWithContext(parts, pi)); } catchingName = true; startIndex = wordIndex; String nameTypeFromSample = startMatcher.group(2); if (nameTypeFromSample != null) { if (nameTypeFromSample.length() == 0) { throw new IOException("Missing a name type: " + errorTokenWithContext(parts, pi)); } nameType = nameTypeFromSample; } } else if (parts[pi].equals(NameSampleDataStream.END_TAG)) { if (!catchingName) { throw new IOException("Found unexpected annotation: " + errorTokenWithContext(parts, pi)); } catchingName = false; // create name nameList.add(new Span(startIndex, wordIndex, nameType)); } else { tokenList.add(parts[pi]); wordIndex++; } } String[] sentence = tokenList.toArray(new String[0]); Span[] names = nameList.toArray(new Span[0]); return new NameSample(sentence, names, clearAdaptiveData); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_NameSam0100644 0000000 0000000 00000000160 15217274217 032420 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameSampleDataStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameSampleDataStream.ja0100644 0000000 0000000 00000004405 15217274217 033777 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.IOException; import opennlp.tools.ml.maxent.DataStream; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * The {@link NameSampleDataStream} class converts tagged tokens * provided by a {@link DataStream} to {@link NameSample} objects. *

* It uses text that is one-sentence per line and tokenized * with names identified by:
* <{@code START}> and <{@code END}>tags. */ public class NameSampleDataStream extends FilterObjectStream { public static final String START_TAG_PREFIX = " in) { super(in); } @Override public NameSample read() throws IOException { String token = samples.read(); boolean isClearAdaptiveData = false; // An empty line indicates the start of a new article // for which the adaptive data in the feature generators // must be cleared while (token != null && token.trim().isEmpty()) { isClearAdaptiveData = true; token = samples.read(); } if (token != null) { return NameSample.parse(token, isClearAdaptiveData); } else { return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_NameSam0100644 0000000 0000000 00000000164 15217274217 032424 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameSampleSequenceStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameSampleSequenceStrea0100644 0000000 0000000 00000014016 15217274217 034127 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.IOException; import java.util.Collections; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.Sequence; import opennlp.tools.ml.model.SequenceStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.featuregen.AdaptiveFeatureGenerator; /** * A {@link SequenceStream} implementation encapsulating {@link NameSample samples}. */ public class NameSampleSequenceStream implements SequenceStream { private final NameContextGenerator pcg; private final boolean useOutcomes; private final ObjectStream psi; private final SequenceCodec seqCodec; /** * Initializes a {@link NameSampleSequenceStream} with given {@code psi} samples. * * @param psi The data stream of {@link NameSample samples}. */ public NameSampleSequenceStream(ObjectStream psi) { this(psi, new DefaultNameContextGenerator((AdaptiveFeatureGenerator) null), true); } /** * Initializes a {@link NameSampleSequenceStream} with given {@code psi} samples * and an {@link AdaptiveFeatureGenerator feature generator}. * * @param psi The data stream of {@link NameSample samples}. * @param featureGen The {@link AdaptiveFeatureGenerator feature generator} to use. */ public NameSampleSequenceStream(ObjectStream psi, AdaptiveFeatureGenerator featureGen) { this(psi, new DefaultNameContextGenerator(featureGen), true); } /** * Initializes a {@link NameSampleSequenceStream} with given {@code psi} samples * and an {@link AdaptiveFeatureGenerator feature generator}. * * @param psi The data stream of {@link NameSample samples}. * @param featureGen The {@link AdaptiveFeatureGenerator feature generator} to use. * @param useOutcomes Whether to use outcomes or not. */ public NameSampleSequenceStream(ObjectStream psi, AdaptiveFeatureGenerator featureGen, boolean useOutcomes) { this(psi, new DefaultNameContextGenerator(featureGen), useOutcomes); } /** * Initializes a {@link NameSampleSequenceStream} with given {@code psi} samples * and an {@link AdaptiveFeatureGenerator feature generator}. * * @param psi The data stream of {@link NameSample samples}. * @param pcg The {@link NameContextGenerator context generator} to use. */ public NameSampleSequenceStream(ObjectStream psi, NameContextGenerator pcg) { this(psi, pcg, true); } /** * Initializes a {@link NameSampleSequenceStream} with given {@code psi} samples * and an {@link AdaptiveFeatureGenerator feature generator}. * * @param psi The data stream of {@link NameSample samples}. * @param pcg The {@link NameContextGenerator context generator} to use. * @param useOutcomes Whether to use outcomes or not. */ public NameSampleSequenceStream(ObjectStream psi, NameContextGenerator pcg, boolean useOutcomes) { this(psi, pcg, useOutcomes, new BioCodec()); } /** * Initializes a {@link NameSampleSequenceStream} with given {@code psi} samples * and an {@link AdaptiveFeatureGenerator feature generator}. * * @param psi The data stream of {@link NameSample samples}. * @param pcg The {@link NameContextGenerator context generator} to use. * @param useOutcomes Whether to use outcomes or not. * @param seqCodec The {@link SequenceCodec} to use. */ public NameSampleSequenceStream(ObjectStream psi, NameContextGenerator pcg, boolean useOutcomes, SequenceCodec seqCodec) { this.psi = psi; this.useOutcomes = useOutcomes; this.pcg = pcg; this.seqCodec = seqCodec; } @Override public Event[] updateContext(Sequence sequence, AbstractModel model) { TokenNameFinder tagger = new NameFinderME(new TokenNameFinderModel( "x-unspecified", model, Collections.emptyMap(), null)); String[] sentence = sequence.getSource().getSentence(); String[] tags = seqCodec.encode(tagger.find(sentence), sentence.length); Event[] events = new Event[sentence.length]; NameFinderEventStream.generateEvents(sentence,tags,pcg).toArray(events); return events; } @Override public Sequence read() throws IOException { NameSample sample = psi.read(); if (sample != null) { String[] sentence = sample.getSentence(); String[] tags = seqCodec.encode(sample.getNames(), sentence.length); Event[] events = new Event[sentence.length]; for (int i = 0; i < sentence.length; i++) { // it is safe to pass the tags as previous tags because // the context generator does not look for non predicted tags String[] context; if (useOutcomes) { context = pcg.getContext(i, sentence, tags, null); } else { context = pcg.getContext(i, sentence, null, null); } events[i] = new Event(tags[i], context); } return new Sequence<>(events,sample); } else { return null; } } @Override public void reset() throws IOException, UnsupportedOperationException { psi.reset(); } @Override public void close() throws IOException { psi.close(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_NameSam0100644 0000000 0000000 00000000160 15217274217 032420 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameSampleTypeFilter.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/NameSampleTypeFilter.ja0100644 0000000 0000000 00000005130 15217274217 034035 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * A {@link FilterObjectStream stream} which removes {@link NameSample name samples} * which do not have a certain type. */ public class NameSampleTypeFilter extends FilterObjectStream { private final Set types; /** * Initializes a {@link NameSampleTypeFilter}. * * @param types An array with types to use. * @param samples An {@link ObjectStream} with the samples to filter. */ public NameSampleTypeFilter(String[] types, ObjectStream samples) { super(samples); this.types = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(types))); } /** * Initializes a {@link NameSampleTypeFilter}. * * @param types A {@link Set} with types to use. * @param samples An {@link ObjectStream} with the samples to filter. */ public NameSampleTypeFilter(Set types, ObjectStream samples) { super(samples); this.types = Set.copyOf(types); } @Override public NameSample read() throws IOException { NameSample sample = samples.read(); if (sample != null) { List filteredNames = new ArrayList<>(); for (Span name : sample.getNames()) { if (types.contains(name.getType())) { filteredNames.add(name); } } return new NameSample(sample.getId(), sample.getSentence(), filteredNames.toArray(new Span[0]), null, sample.isClearAdaptiveDataSet()); } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/RegexNameFinder.java0100644 0000000 0000000 00000013423 15217274217 033341 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import opennlp.tools.util.Span; /** * A {@link TokenNameFinder} implementation based on a series of regular expressions. */ public final class RegexNameFinder implements TokenNameFinder { private Pattern[] mPatterns; private String sType; private Map regexMap; /** * Initializes a {@link RegexNameFinder} instance. * * @param regexMap A {@link Map} where the key is a type, and the value is a * {@link Pattern[]}. Must not be {@code null}. */ public RegexNameFinder(Map regexMap) { this.regexMap = Objects.requireNonNull(regexMap, "regexMap must not be null"); } /** * Initializes a {@link RegexNameFinder} instance. * * @param patterns The {@link Pattern[] patterns} to use. * Must not be {@code null} and not be empty. * @param type The type to use. * * @throws IllegalArgumentException Thrown if {@code patterns} were {@code null} or empty. */ public RegexNameFinder(Pattern[] patterns, String type) { if (patterns == null || patterns.length == 0) { throw new IllegalArgumentException("patterns must not be null or empty!"); } mPatterns = patterns; sType = type; } @Override public Span[] find(String[] tokens) { Map sentencePosTokenMap = new HashMap<>(); StringBuilder sentenceString = new StringBuilder(tokens.length * 10); for (int i = 0; i < tokens.length; i++) { int startIndex = sentenceString.length(); sentencePosTokenMap.put(startIndex, i); sentenceString.append(tokens[i]); int endIndex = sentenceString.length(); sentencePosTokenMap.put(endIndex, i + 1); if (i < tokens.length - 1) { sentenceString.append(' '); } } Collection annotations = new LinkedList<>(); if (regexMap != null) { for (Map.Entry entry : regexMap.entrySet()) { for (Pattern mPattern : entry.getValue()) { Matcher matcher = mPattern.matcher(sentenceString); while (matcher.find()) { Integer tokenStartIndex = sentencePosTokenMap.get(matcher.start()); Integer tokenEndIndex = sentencePosTokenMap.get(matcher.end()); if (tokenStartIndex != null && tokenEndIndex != null) { Span annotation = new Span(tokenStartIndex, tokenEndIndex, entry.getKey()); annotations.add(annotation); } } } } } else { for (Pattern mPattern : mPatterns) { Matcher matcher = mPattern.matcher(sentenceString); while (matcher.find()) { Integer tokenStartIndex = sentencePosTokenMap.get(matcher.start()); Integer tokenEndIndex = sentencePosTokenMap.get(matcher.end()); if (tokenStartIndex != null && tokenEndIndex != null) { Span annotation = new Span(tokenStartIndex, tokenEndIndex, sType); annotations.add(annotation); } } } } return annotations.toArray(new Span[0]); } /** * Finds {@link Span spans} with character indices, rather than word. * * @param text The text to use. * @return A {@link Span[]} representing the annotations. */ public Span[] find(String text) { return getAnnotations(text); } private Span[] getAnnotations(String text) { Collection annotations = new LinkedList<>(); if (regexMap != null) { for (Map.Entry entry : regexMap.entrySet()) { for (Pattern mPattern : entry.getValue()) { Matcher matcher = mPattern.matcher(text); while (matcher.find()) { Span annotation = new Span(matcher.start(), matcher.end(), entry.getKey()); annotations.add(annotation); } } } } else { for (Pattern mPattern : mPatterns) { Matcher matcher = mPattern.matcher(text); while (matcher.find()) { Span annotation = new Span(matcher.start(), matcher.end(), sType); annotations.add(annotation); } } } return annotations.toArray(new Span[0]); } @Override public void clearAdaptiveData() { // nothing to clear } /** * @return Retrieves the {@link Pattern matching patterns} used. */ public Pattern[] getMatchingPatterns() { return mPatterns; } /** * @param mPatterns The {@link Pattern matching patterns} to be set. */ public void setMatchingPatterns(Pattern[] mPatterns) { this.mPatterns = mPatterns; } /** * @return Retrieves the {@link Span} type used. */ public String getSpanType() { return sType; } /** * @param sType Sets a (different) {@link Span} type. */ public void setSpanType(String sType) { this.sType = sType; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_RegexNa0100644 0000000 0000000 00000000162 15217274217 032432 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/RegexNameFinderFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/RegexNameFinderFactory.0100644 0000000 0000000 00000016436 15217274217 034036 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; /** * * Returns a {@link RegexNameFinder} based on a selection of * defaults or a configuration and a selection of defaults. */ public class RegexNameFinderFactory { /** * Allows for use of selected Defaults as well as regexes from external * configuration. * * @param config A {@link Map} where the key is a type, and the value is a * {@link Pattern[]}. If a key clashes with one of the default keys, * the config map entry will be taken. * @param defaults One or more of the default {@link DEFAULT_REGEX_NAME_FINDER} enum values. * @return A {@link RegexNameFinder} instance. */ public static synchronized RegexNameFinder getDefaultRegexNameFinders( Map config, DEFAULT_REGEX_NAME_FINDER... defaults) { Objects.requireNonNull(config, "config must not be null"); Map defaultsToMap = new HashMap<>(); if (defaults != null) { defaultsToMap = defaultsToMap(defaults); } defaultsToMap.putAll(config); return new RegexNameFinder(defaultsToMap); } /** * Retrieves a {@link RegexNameFinder} that will utilize specified default regexes. * * @param defaults One or more of the default {@link DEFAULT_REGEX_NAME_FINDER} enum values. * @return A {@link RegexNameFinder} instance. */ public static synchronized RegexNameFinder getDefaultRegexNameFinders( DEFAULT_REGEX_NAME_FINDER... defaults) { Objects.requireNonNull(defaults, "defaults must not be null"); return new RegexNameFinder(defaultsToMap(defaults)); } private synchronized static Map defaultsToMap( DEFAULT_REGEX_NAME_FINDER... defaults) { Map regexMap = new HashMap<>(); for (DEFAULT_REGEX_NAME_FINDER def : defaults) { regexMap.putAll(def.getRegexMap()); } return regexMap; } public interface RegexAble { Map getRegexMap(); String getType(); } /** * Enumeration of typical regex expressions available in OpenNLP. */ public enum DEFAULT_REGEX_NAME_FINDER implements RegexAble { USA_PHONE_NUM { @Override public Map getRegexMap() { Pattern[] p = new Pattern[1]; // p[0] = Pattern.compile("([\\+(]?(\\d){2,}[)]?[- \\.]?(\\d){2,}[- \\.]?(\\d){2,}[- \\.]? // (\\d){2,}[- \\.]?(\\d){2,})|([\\+(]?(\\d){2,}[)]?[- \\.]?(\\d){2,}[- \\.]?(\\d){2,}[- // \\.]?(\\d){2,})|([\\+(]?(\\d){2,}[)]?[- \\.]?(\\d){2,}[- \\.]?(\\d){2,})", // Pattern.CASE_INSENSITIVE); p[0] = Pattern.compile("((\\(\\d{3}\\) ?)|(\\d{3}-))?\\d{3}-\\d{4}"); Map regexMap = new HashMap<>(); regexMap.put(getType(), p); return regexMap; } @Override public String getType() { return "PHONE_NUM"; } }, EMAIL { @Override public Map getRegexMap() { Pattern[] p = new Pattern[1]; // Every quantifier is bounded by a constant, which removes both the exponential // backtracking and the recursion depth that made the old pattern a ReDoS vector. // Limits follow RFC 5321: local part <= 64 chars, each domain label <= 63 chars. p[0] = Pattern.compile( "(? regexMap = new HashMap<>(); regexMap.put(getType(), p); return regexMap; } @Override public String getType() { return "EMAIL"; } }, URL { @Override public Map getRegexMap() { Pattern[] p = new Pattern[1]; // Flattened to single-level groups and every quantifier bounded by a constant. // The bounds alone remove the nested-quantifier backtracking and the recursion // depth that caused the StackOverflowError; they must stay bounded ({0,255} / // {1,63} rather than * / +) or a long path segment reintroduces the overflow. p[0] = Pattern.compile("\\b(?:(?:ht|f)tps?://|~/|/|www\\.)" + "(?:\\w{1,63}:\\w{1,63}@)?" + "(?:[-\\w]{1,63}\\.){1,20}(?:com|org|net|gov" + "|mil|biz|info|mobi|name|aero|jobs|museum" + "|travel|[a-z]{2})(?::\\d{1,5})?" + "(?:/(?:[-\\w~!$+|.,=]|%[a-f\\d]{2}){0,255}){0,50}" + "(?:\\?(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2}){0,255}" + "(?:&(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2}){0,255}){0,50})?" + "(?:#(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2}){0,255})?\\b", Pattern.CASE_INSENSITIVE); Map regexMap = new HashMap<>(); regexMap.put(getType(), p); return regexMap; } @Override public String getType() { return "URL"; } }, MGRS { @Override public Map getRegexMap() { Pattern[] p = new Pattern[1]; p[0] = Pattern.compile("\\d{1,2}[A-Za-z]\\s*[A-Za-z]{2}\\s*\\d{1,5}\\s*\\d{1,5}", Pattern.CASE_INSENSITIVE); Map regexMap = new HashMap<>(); regexMap.put(getType(), p); return regexMap; } @Override public String getType() { return "MGRS"; } }, DEGREES_MIN_SEC_LAT_LON { @Override public Map getRegexMap() { Pattern[] p = new Pattern[1]; p[0] = Pattern.compile("([-|\\+]?\\d{1,3}[d|D|\\u00B0|\\s](\\s*\\d{1,2}['|\\u2019|\\s])" + "?(\\s*\\d{1,2}[\\\"|\\u201d])?\\s*[N|n|S|s]?)(\\s*|,|,\\s*)([-|\\+]?\\d{1,3}[d|D|\\u00B0|" + "\\s](\\s*\\d{1,2}['|\\u2019|\\s])?(\\s*\\d{1,2}[\\\"|\\u201d])?\\s*[E|e|W|w]?)", Pattern.CASE_INSENSITIVE); Map regexMap = new HashMap<>(); regexMap.put(getType(), p); return regexMap; } @Override public String getType() { return "DEGREES_MIN_SEC_LAT_LON"; } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_ThreadS0100644 0000000 0000000 00000000162 15217274217 032433 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/ThreadSafeNameFinderME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/ThreadSafeNameFinderME.0100644 0000000 0000000 00000005252 15217274217 033656 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.commons.ThreadSafe; import opennlp.tools.ml.Probabilistic; import opennlp.tools.util.Span; /** * A thread-safe version of {@link NameFinderME}. Using it is completely transparent. * You can use it in a single-threaded context as well, it only incurs a minimal overhead. *

* Note:
* This implementation uses a {@link ThreadLocal}. Although the implementation is * lightweight because the model is not duplicated, if you have many long-running threads, * you may run into memory problems. *

* Be careful when using this in a Jakarta EE application, for example. *

* The user is responsible for clearing the {@link ThreadLocal} via calling {@link #close()}. * * @see NameFinderME * @see Probabilistic * @see TokenNameFinder */ @ThreadSafe public class ThreadSafeNameFinderME implements TokenNameFinder, Probabilistic, AutoCloseable { private final TokenNameFinderModel model; private final ThreadLocal threadLocal = new ThreadLocal<>(); /** * Initializes a {@link ThreadSafeNameFinderME} with the specified {@code model}. * * @param model A valid {@link TokenNameFinderModel}. */ public ThreadSafeNameFinderME(TokenNameFinderModel model) { super(); this.model = model; } // If a thread-local version exists, return it. Otherwise, create, then return. private NameFinderME getNameFinder() { NameFinderME nf = threadLocal.get(); if (nf == null) { nf = new NameFinderME(model); threadLocal.set(nf); } return nf; } @Override public Span[] find(String[] tokens) { return getNameFinder().find(tokens); } @Override public double[] probs() { return getNameFinder().probs(); } @Override public void clearAdaptiveData() { getNameFinder().clearAdaptiveData(); } @Override public void close() { threadLocal.remove(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinder.java0100644 0000000 0000000 00000003110 15217274217 033337 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.util.Span; /** * The interface for name finders which provide name tags for a sequence of tokens. */ public interface TokenNameFinder { /** * Generates name tags for the given sequence, typically a sentence, * returning {@link Span token spans} for any identified names. * * @param tokens An array of the tokens or words of the sequence, typically a sentence. * @return An array of {@link Span spans} for each of the names identified. */ Span[] find(String[] tokens); /** * Forgets all adaptive data which was collected during previous * calls to one of the find methods. *

* Note: * This method should typically be called at the end of the processing of a document. */ void clearAdaptiveData(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_TokenNa0100644 0000000 0000000 00000000171 15217274217 032440 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderCrossVal0100644 0000000 0000000 00000020703 15217274217 034103 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import opennlp.tools.commons.Sample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.FMeasure; /** * Cross validator for {@link TokenNameFinder}. */ public class TokenNameFinderCrossValidator { private record DocumentSample(NameSample[] samples) implements Sample { private static final long serialVersionUID = -4199121634493414749L; } /** * Reads {@link NameSample samples} to group them as a document based on the clear adaptive data flag. */ private static class NameToDocumentSampleStream extends FilterObjectStream { private NameSample beginSample; protected NameToDocumentSampleStream(ObjectStream samples) { super(samples); } @Override public DocumentSample read() throws IOException { List document = new ArrayList<>(); if (beginSample == null) { // Assume that the clear flag is set beginSample = samples.read(); } // Underlying stream is exhausted! if (beginSample == null) { return null; } document.add(beginSample); NameSample sample; while ((sample = samples.read()) != null) { if (sample.isClearAdaptiveDataSet()) { beginSample = sample; break; } document.add(sample); } // Underlying stream is exhausted, // next call must return null if (sample == null) { beginSample = null; } return new DocumentSample(document.toArray(new NameSample[0])); } @Override public void reset() throws IOException, UnsupportedOperationException { super.reset(); beginSample = null; } } /** * Splits {@link DocumentSample document samples} into {@link NameSample name samples}. */ private static class DocumentToNameSampleStream extends FilterObjectStream { protected DocumentToNameSampleStream(ObjectStream samples) { super(samples); } private Iterator documentSamples = Collections.emptyIterator(); @Override public NameSample read() throws IOException { // Note: Empty document samples should be skipped if (documentSamples.hasNext()) { return documentSamples.next(); } else { DocumentSample docSample = samples.read(); if (docSample != null) { documentSamples = Arrays.asList(docSample.samples()).iterator(); return read(); } else { return null; } } } } private final String languageCode; private final TrainingParameters params; private final String type; private final byte[] featureGeneratorBytes; private final Map resources; private final TokenNameFinderEvaluationMonitor[] listeners; private final FMeasure fmeasure = new FMeasure(); private TokenNameFinderFactory factory; /** * Initializes a {@link TokenNameFinderCrossValidator} with the given parameters. * * @param languageCode The ISO conform language code. * @param type {@code null} or an override type for all types in the training data. * @param featureGeneratorBytes The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param codec The {@link SequenceCodec} to use. * @param params The {@link TrainingParameters} for the context of cross validation. * @param listeners the {@link TokenNameFinderEvaluationMonitor evaluation listeners}. */ public TokenNameFinderCrossValidator(String languageCode, String type, TrainingParameters params, byte[] featureGeneratorBytes, Map resources, SequenceCodec codec, TokenNameFinderEvaluationMonitor... listeners) { this.languageCode = languageCode; this.type = type; this.featureGeneratorBytes = featureGeneratorBytes; this.resources = resources; this.params = params; this.listeners = listeners; } /** * Initializes a {@link TokenNameFinderCrossValidator} with the given parameters. * * @param languageCode The ISO conform language code. * @param type {@code null} or an override type for all types in the training data. * @param featureGeneratorBytes The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param listeners the {@link TokenNameFinderEvaluationMonitor evaluation listeners}. */ public TokenNameFinderCrossValidator(String languageCode, String type, TrainingParameters trainParams, byte[] featureGeneratorBytes, Map resources, TokenNameFinderEvaluationMonitor... listeners) { this(languageCode, type, trainParams, featureGeneratorBytes, resources, new BioCodec(), listeners); } /** * Initializes a {@link TokenNameFinderCrossValidator} with the given parameters. * * @param languageCode The ISO conform language code. * @param type {@code null} or an override type for all types in the training data. * @param params The {@link TrainingParameters} for the context of cross validation. * @param factory The {@link TokenNameFinderFactory} for creating related objects. * @param listeners the {@link TokenNameFinderEvaluationMonitor evaluation listeners}. */ public TokenNameFinderCrossValidator(String languageCode, String type, TrainingParameters params, TokenNameFinderFactory factory, TokenNameFinderEvaluationMonitor... listeners) { this(languageCode, type, params, null, null, new BioCodec(), listeners); this.factory = factory; } /** * Starts the evaluation. *

* Note: * The name samples need to be grouped on a document basis. * * @param samples The {@link ObjectStream} of {@link NameSample samples} to train and test with. * @param nFolds Number of folds. It must be greater than zero. * * @throws IOException Thrown if IO errors occurred. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>( new NameToDocumentSampleStream(samples), nFolds); while (partitioner.hasNext()) { CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner.next(); TokenNameFinderModel model; if (factory != null) { model = NameFinderME.train(languageCode, type, new DocumentToNameSampleStream(trainingSampleStream), params, factory); } else { model = NameFinderME.train(languageCode, type, new DocumentToNameSampleStream(trainingSampleStream), params, TokenNameFinderFactory.create(null, featureGeneratorBytes, resources, new BioCodec())); } // do testing TokenNameFinderEvaluator evaluator = new TokenNameFinderEvaluator( new NameFinderME(model), listeners); evaluator.evaluate(new DocumentToNameSampleStream(trainingSampleStream.getTestSampleStream())); fmeasure.mergeInto(evaluator.getFMeasure()); } } public FMeasure getFMeasure() { return fmeasure; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_TokenNa0100644 0000000 0000000 00000000174 15217274217 032443 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderEvaluati0100644 0000000 0000000 00000002046 15217274217 034121 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link TokenNameFinder name finders}. */ public interface TokenNameFinderEvaluationMonitor extends EvaluationMonitor { } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_TokenNa0100644 0000000 0000000 00000000164 15217274217 032442 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderEvaluator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderEvaluato0100644 0000000 0000000 00000006166 15217274217 034136 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import opennlp.tools.util.Span; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.FMeasure; /** * The {@link TokenNameFinderEvaluator} measures the performance * of the given {@link TokenNameFinder} with the provided * reference {@link NameSample samples}. * * @see Evaluator * @see TokenNameFinder * @see NameSample */ public class TokenNameFinderEvaluator extends Evaluator { private final FMeasure fmeasure = new FMeasure(); /** * The {@link TokenNameFinder} used to create the predicted {@link NameSample} objects. */ private final TokenNameFinder nameFinder; /** * Initializes a {@link TokenNameFinderEvaluator} for a given {@link TokenNameFinder}. * * @param nameFinder The {@link TokenNameFinder} to evaluate. * @param listeners The {@link TokenNameFinderEvaluationMonitor evaluation listeners}. */ public TokenNameFinderEvaluator(TokenNameFinder nameFinder, TokenNameFinderEvaluationMonitor ... listeners) { super(listeners); this.nameFinder = nameFinder; } /** * Evaluates the given reference {@link NameSample} object. *

* This is done by finding the names with the * {@link TokenNameFinder} in the sentence from the reference * {@link NameSample}. The found names are then used to * calculate and update the scores. * * @param reference The reference {@link NameSample}. * * @return The predicted {@link NameSample}. */ @Override protected NameSample processSample(NameSample reference) { if (reference.isClearAdaptiveDataSet()) { nameFinder.clearAdaptiveData(); } Span[] predictedNames = nameFinder.find(reference.getSentence()); Span[] references = reference.getNames(); // OPENNLP-396 When evaluating with a file in the old format // the type of the span is null, but must be set to default to match // the output of the name finder. for (int i = 0; i < references.length; i++) { if (references[i].getType() == null) { references[i] = new Span(references[i].getStart(), references[i].getEnd(), "default"); } } fmeasure.updateScores(references, predictedNames); return new NameSample(reference.getSentence(), predictedNames, reference.isClearAdaptiveDataSet()); } public FMeasure getFMeasure() { return fmeasure; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_TokenNa0100644 0000000 0000000 00000000162 15217274217 032440 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderFactory.0100644 0000000 0000000 00000027415 15217274217 034043 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Map; import opennlp.tools.namefind.TokenNameFinderModel.FeatureGeneratorCreationError; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.featuregen.AdaptiveFeatureGenerator; import opennlp.tools.util.featuregen.AggregatedFeatureGenerator; import opennlp.tools.util.featuregen.BigramNameFeatureGenerator; import opennlp.tools.util.featuregen.CachedFeatureGenerator; import opennlp.tools.util.featuregen.GeneratorFactory; import opennlp.tools.util.featuregen.OutcomePriorFeatureGenerator; import opennlp.tools.util.featuregen.PreviousMapFeatureGenerator; import opennlp.tools.util.featuregen.SentenceFeatureGenerator; import opennlp.tools.util.featuregen.TokenClassFeatureGenerator; import opennlp.tools.util.featuregen.TokenFeatureGenerator; import opennlp.tools.util.featuregen.WindowFeatureGenerator; /** * The factory that provides {@link TokenNameFinder} default implementations and * resources. That only works if that's the central class used for training/runtime. */ public class TokenNameFinderFactory extends BaseToolFactory { private byte[] featureGeneratorBytes; private Map resources; private SequenceCodec seqCodec; /** * Initializes a {@link TokenNameFinderFactory} that provides the default implementation * of the resources. {@link BioCodec} will be used as default {@link SequenceCodec}. */ public TokenNameFinderFactory() { this.seqCodec = new BioCodec(); } /** * Initializes a {@link TokenNameFinderFactory} instance via given parameters. * * @param featureGeneratorBytes The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param seqCodec The {@link SequenceCodec} to use. */ public TokenNameFinderFactory(byte[] featureGeneratorBytes, final Map resources, SequenceCodec seqCodec) { init(featureGeneratorBytes, resources, seqCodec); } /** * Initializes via given parameters. * * @param featureGeneratorBytes The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param seqCodec The {@link SequenceCodec} to use. */ void init(byte[] featureGeneratorBytes, final Map resources, SequenceCodec seqCodec) { this.featureGeneratorBytes = featureGeneratorBytes; this.resources = resources; this.seqCodec = seqCodec; } /* * Loads the default feature generator bytes via classpath resources. */ private static byte[] loadDefaultFeatureGeneratorBytes() { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); InputStream resource = TokenNameFinderFactory.class.getResourceAsStream( "/opennlp/tools/namefind/ner-default-features.xml"); if (resource == null) { throw new IllegalStateException("Classpath must contain 'ner-default-features.xml' file!"); } try (InputStream in = new BufferedInputStream(resource)) { byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { bytes.write(buf, 0, len); } } catch (IOException e) { throw new IllegalStateException("Failed reading from 'ner-default-features.xml' file on classpath!"); } return bytes.toByteArray(); } /** * @return Retrieves the {@link SequenceCodec} in use. */ protected SequenceCodec getSequenceCodec() { return seqCodec; } /** * @return Retrieves the additional {@code resources} in use. */ protected Map getResources() { return resources; } /** * @return Retrieves {@code byte[]} in use representing the feature generator descriptor. */ protected byte[] getFeatureGenerator() { return featureGeneratorBytes; } /** * Initializes a {@link TokenNameFinderFactory} instance via given parameters. * * @param subclassName The class name used for instantiation. If {@code null}, an * instance of {@link TokenNameFinderFactory} will be returned * per default. Otherwise, the {@link ExtensionLoader} mechanism * is applied to load the requested {@code subclassName}. * @param featureGeneratorBytes The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param seqCodec The {@link SequenceCodec} to use. * * @return A valid {@link TokenNameFinderFactory} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the factory associated with {@code subclassName}. */ public static TokenNameFinderFactory create(String subclassName, byte[] featureGeneratorBytes, final Map resources, SequenceCodec seqCodec) throws InvalidFormatException { TokenNameFinderFactory theFactory; if (subclassName == null) { // will create the default factory theFactory = new TokenNameFinderFactory(); } else { try { theFactory = ExtensionLoader.instantiateExtension( TokenNameFinderFactory.class, subclassName); } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } } theFactory.init(featureGeneratorBytes, resources, seqCodec); return theFactory; } @Override public void validateArtifactMap() throws InvalidFormatException { // no additional artifacts } /** * @return Initializes and returns a {@link SequenceCodec} via its class name configured in a manifest. * If that initialization fails (e.g., if no matching class could be loaded for the configured * class name at runtime), the currently loaded (default) {@link SequenceCodec} is returned. * * @see BioCodec * @see BilouCodec */ public SequenceCodec createSequenceCodec() { if (artifactProvider != null) { String sequenceCodecImplName = artifactProvider.getManifestProperty( TokenNameFinderModel.SEQUENCE_CODEC_CLASS_NAME_PARAMETER); try { return instantiateSequenceCodec(sequenceCodecImplName); } catch (InvalidFormatException e) { // Uses the (already) available SequenceCodec instance. Default: BioCodec, see no-arg constructor return seqCodec; } } else { return seqCodec; } } /** * Creates and configures a new {@link NameContextGenerator} in a default combination. * * @return A {@link NameContextGenerator} instance. * * @see DefaultNameContextGenerator * @see AdaptiveFeatureGenerator */ public NameContextGenerator createContextGenerator() { AdaptiveFeatureGenerator featureGenerator = createFeatureGenerators(); if (featureGenerator == null) { featureGenerator = new CachedFeatureGenerator( new WindowFeatureGenerator(new TokenFeatureGenerator(), 2, 2), new WindowFeatureGenerator(new TokenClassFeatureGenerator(true), 2, 2), new OutcomePriorFeatureGenerator(), new PreviousMapFeatureGenerator(), new BigramNameFeatureGenerator(), new SentenceFeatureGenerator(true, false)); } return new DefaultNameContextGenerator(featureGenerator); } /** * Creates the {@link AdaptiveFeatureGenerator}. Usually this * is a set of generators contained in {@link AggregatedFeatureGenerator}. *

* Note: * The generators are created on every call to this method. * * @return The {@link AdaptiveFeatureGenerator} or {@code null} if there * is no descriptor in the model. * * @throws FeatureGeneratorCreationError Thrown if configuration errors occurred. * @throws IllegalStateException Thrown if inconsistencies occurred during creation. */ public AdaptiveFeatureGenerator createFeatureGenerators() { if (featureGeneratorBytes == null && artifactProvider != null) { featureGeneratorBytes = artifactProvider.getArtifact( TokenNameFinderModel.GENERATOR_DESCRIPTOR_ENTRY_NAME); } if (featureGeneratorBytes == null) { featureGeneratorBytes = loadDefaultFeatureGeneratorBytes(); } try (InputStream descriptorIn = new ByteArrayInputStream(featureGeneratorBytes)) { return GeneratorFactory.create(descriptorIn, key -> { if (artifactProvider != null) { return artifactProvider.getArtifact(key); } else { return resources.get(key); } }); } catch (InvalidFormatException e) { // It is assumed that the creation of the feature generation does not // fail after it succeeded once during model loading. // But it might still be possible that such an exception is thrown, // in this case the caller should not be forced to handle the exception // and a Runtime Exception is thrown instead. // If the re-creation of the feature generation fails it is assumed // that this can only be caused by a programming mistake and therefore // throwing a Runtime Exception is reasonable throw new FeatureGeneratorCreationError(e); } catch (IOException e) { throw new IllegalStateException("Reading from mem cannot result in an I/O error", e); } } /** * Initializes a {@link SequenceCodec} instance via given parameters. * * @param sequenceCodecImplName The class name used for instantiation. If {@code null}, * an instance of {@link BioCodec} will be returned * per default. Otherwise, the {@link ExtensionLoader} * mechanism is applied to load the requested {@code subclassName}. * * @return A valid {@link SequenceCodec} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the codec associated with {@code sequenceCodecImplName}. * @see SequenceCodec * @see BioCodec * @see BilouCodec */ public static SequenceCodec instantiateSequenceCodec(String sequenceCodecImplName) throws InvalidFormatException { if (sequenceCodecImplName != null) { try { return ExtensionLoader.instantiateExtension(SequenceCodec.class, sequenceCodecImplName); } catch (Exception e) { String msg = "Could not instantiate the " + sequenceCodecImplName + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } } else { // If nothing is specified return default codec! return new BioCodec(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_namefind_TokenNa0100644 0000000 0000000 00000000160 15217274217 032436 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderModel.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/TokenNameFinderModel.ja0100644 0000000 0000000 00000034755 15217274217 034014 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.namefind; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Serial; import java.net.URL; import java.nio.file.Path; import java.util.Map; import java.util.Properties; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.SequenceCodec; import opennlp.tools.util.featuregen.BrownCluster; import opennlp.tools.util.featuregen.WordClusterDictionary; import opennlp.tools.util.featuregen.WordClusterFeatureGenerator; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.BaseModel; import opennlp.tools.util.model.ByteArraySerializer; /** * The {@link TokenNameFinderModel} is the model used by a learnable {@link TokenNameFinder}. * * @see NameFinderME */ // TODO: Fix the model validation, on loading via constructors and input streams public class TokenNameFinderModel extends BaseModel { @Serial private static final long serialVersionUID = -459655422186301499L; public static class FeatureGeneratorCreationError extends RuntimeException { @Serial private static final long serialVersionUID = -7004590770543145243L; FeatureGeneratorCreationError(Throwable t) { super(t); } } private static final String COMPONENT_NAME = "NameFinderME"; private static final String MAXENT_MODEL_ENTRY_NAME = "nameFinder.model"; static final String GENERATOR_DESCRIPTOR_ENTRY_NAME = "generator.featuregen"; static final String SEQUENCE_CODEC_CLASS_NAME_PARAMETER = "sequenceCodecImplName"; /** * Initializes a {@link TokenNameFinderModel} instance via given parameters. * * @param languageCode The ISO conform language code. * @param nameFinderModel A valid {@link MaxentModel}. * @param generatorDescriptor The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param manifestInfoEntries Additional information kept in the manifest. * @param seqCodec The {@link SequenceCodec} to use. * @param factory The {@link TokenNameFinderFactory} for creating related objects. * * @throws IllegalArgumentException Thrown if the {@code namFinderModel} incompatible * with {@code seqCodec}. */ public TokenNameFinderModel(String languageCode, SequenceClassificationModel nameFinderModel, byte[] generatorDescriptor, Map resources, Map manifestInfoEntries, SequenceCodec seqCodec, TokenNameFinderFactory factory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, factory); init(nameFinderModel, generatorDescriptor, resources, manifestInfoEntries, seqCodec); if (!seqCodec.areOutcomesCompatible(nameFinderModel.getOutcomes())) { throw new IllegalArgumentException("Model not compatible with name finder!"); } } /** * Initializes a {@link TokenNameFinderModel} instance via given parameters. * * @param languageCode The ISO conform language code. * @param nameFinderModel A valid {@link MaxentModel}. * @param beamSize The beam size. Must be greater than {@code 0}. * @param generatorDescriptor The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param manifestInfoEntries Additional information kept in the manifest. * @param seqCodec The {@link SequenceCodec} to use. * @param factory The {@link TokenNameFinderFactory} for creating related objects. * * @throws IllegalArgumentException Thrown if the {@code namFinderModel} incompatible * with {@code seqCodec}. */ public TokenNameFinderModel(String languageCode, MaxentModel nameFinderModel, int beamSize, byte[] generatorDescriptor, Map resources, Map manifestInfoEntries, SequenceCodec seqCodec, TokenNameFinderFactory factory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, factory); Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); manifest.put(BeamSearch.BEAM_SIZE_PARAMETER, Integer.toString(beamSize)); init(nameFinderModel, generatorDescriptor, resources, manifestInfoEntries, seqCodec); if (!isModelValid(nameFinderModel)) { throw new IllegalArgumentException("Model not compatible with name finder!"); } } /** * Initializes a {@link TokenNameFinderModel} instance via given parameters. * * @param languageCode The ISO conform language code. * @param nameFinderModel A valid {@link MaxentModel}. * @param generatorDescriptor The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param manifestInfoEntries Additional information kept in the manifest. * * @throws IllegalArgumentException Thrown if the {@code namFinderModel} incompatible * with {@code seqCodec}. */ public TokenNameFinderModel(String languageCode, MaxentModel nameFinderModel, byte[] generatorDescriptor, Map resources, Map manifestInfoEntries) { this(languageCode, nameFinderModel, NameFinderME.DEFAULT_BEAM_SIZE, generatorDescriptor, resources, manifestInfoEntries, new BioCodec(), new TokenNameFinderFactory()); } /** * Initializes a {@link TokenNameFinderModel} instance via given parameters. * * @param languageCode The ISO conform language code. * @param nameFinderModel A valid {@link MaxentModel}. * @param beamSize The beam size. Must be greater than {@code 0}. * @param generatorDescriptor The {@code byte[]} representing the feature generator descriptor. * @param resources Additional resources in a mapping. * @param manifestInfoEntries Additional information kept in the manifest. * * @throws IllegalArgumentException Thrown if the {@code namFinderModel} incompatible * with {@code seqCodec}. */ public TokenNameFinderModel(String languageCode, MaxentModel nameFinderModel, int beamSize, byte[] generatorDescriptor, Map resources, Map manifestInfoEntries) { this(languageCode, nameFinderModel, beamSize, generatorDescriptor, resources, manifestInfoEntries, new BioCodec(), new TokenNameFinderFactory()); } /** * Initializes a {@link TokenNameFinderModel} instance via given parameters. * * @param languageCode The ISO conform language code. * @param nameFinderModel A valid {@link MaxentModel}. * @param resources Additional resources in a mapping. * @param manifestInfoEntries Additional information kept in the manifest. * * @throws IllegalArgumentException Thrown if the {@code nameFinderModel} is incompatible * with {@code seqCodec}. */ public TokenNameFinderModel(String languageCode, MaxentModel nameFinderModel, Map resources, Map manifestInfoEntries) { this(languageCode, nameFinderModel, null, resources, manifestInfoEntries); } /** * Initializes a {@link TokenNameFinderModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenNameFinderModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link TokenNameFinderModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenNameFinderModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link TokenNameFinderModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenNameFinderModel(Path modelPath) throws IOException { super(COMPONENT_NAME, modelPath); } /** * Initializes a {@link TokenNameFinderModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenNameFinderModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } private void init(Object nameFinderModel, byte[] generatorDescriptor, Map resources, Map manifestInfoEntries, SequenceCodec seqCodec) { Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); manifest.put(SEQUENCE_CODEC_CLASS_NAME_PARAMETER, seqCodec.getClass().getName()); artifactMap.put(MAXENT_MODEL_ENTRY_NAME, nameFinderModel); if (generatorDescriptor != null && generatorDescriptor.length > 0) artifactMap.put(GENERATOR_DESCRIPTOR_ENTRY_NAME, generatorDescriptor); if (resources != null) { // The resource map must not contain key which are already taken // like the name finder maxent model name if (resources.containsKey(MAXENT_MODEL_ENTRY_NAME) || resources.containsKey(GENERATOR_DESCRIPTOR_ENTRY_NAME)) { throw new IllegalArgumentException(); } // TODO: Add checks to not put resources where no serializer exists, // make that case fail here, should be done in the BaseModel artifactMap.putAll(resources); } checkArtifactMap(); } /** * @return Retrieves a valid {@link SequenceClassificationModel} or {@code null} * if no matching one could be found. */ public SequenceClassificationModel getNameFinderSequenceModel() { Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); if (artifactMap.get(MAXENT_MODEL_ENTRY_NAME) instanceof MaxentModel) { String beamSizeString = manifest.getProperty(BeamSearch.BEAM_SIZE_PARAMETER); int beamSize = NameFinderME.DEFAULT_BEAM_SIZE; if (beamSizeString != null) { beamSize = Integer.parseInt(beamSizeString); } return new BeamSearch(beamSize, (MaxentModel) artifactMap.get(MAXENT_MODEL_ENTRY_NAME)); } else if (artifactMap.get(MAXENT_MODEL_ENTRY_NAME) instanceof SequenceClassificationModel) { return (SequenceClassificationModel) artifactMap.get(MAXENT_MODEL_ENTRY_NAME); } else { return null; } } @Override protected Class getDefaultFactory() { return TokenNameFinderFactory.class; } /** * @return Retrieves the {@link SequenceCodec} in use. */ public SequenceCodec getSequenceCodec() { return this.getFactory().getSequenceCodec(); } /** * @return Retrieves the {@link TokenNameFinderFactory} in use. */ public TokenNameFinderFactory getFactory() { return (TokenNameFinderFactory) this.toolFactory; } @Override protected void createArtifactSerializers(Map> serializers) { super.createArtifactSerializers(serializers); serializers.put("featuregen", new ByteArraySerializer()); } /** * Create the {@link ArtifactSerializer serializers}. Currently, for serializers related to * features that require external resources, such as {@code W2VClassesDictionary} * objects, the convention is to add its element tag name as key of the serializer map. *

* For example, the element tag name for the {@link WordClusterFeatureGenerator} which * uses {@code W2VClassesDictionary} objects serialized by the {@code W2VClassesDictionarySerializer} * is 'wordcluster', which is the key used to add the serializer to the map. * * @return A {@link Map} containing the added {@link ArtifactSerializer serializers}. */ public static Map> createArtifactSerializers() { // TODO: Not so nice, because code cannot really be reused by the other create serializer method // Has to be redesigned, we need static access to default serializers // and these should be able to extend during runtime ?! // // The XML feature generator factory should provide these mappings. // Usually the feature generators should know what type of resource they expect. Map> serializers = BaseModel.createArtifactSerializers(); serializers.put("featuregen", new ByteArraySerializer()); serializers.put("wordcluster", new WordClusterDictionary.WordClusterDictionarySerializer()); serializers.put("brownclustertoken", new BrownCluster.BrownClusterSerializer()); serializers.put("brownclustertokenclass", new BrownCluster.BrownClusterSerializer()); serializers.put("brownclusterbigram", new BrownCluster.BrownClusterSerializer()); return serializers; } private boolean isModelValid(MaxentModel model) { String[] outcomes = new String[model.getNumOutcomes()]; for (int i = 0; i < model.getNumOutcomes(); i++) { outcomes[i] = model.getOutcome(i); } return getFactory().createSequenceCodec().areOutcomesCompatible(outcomes); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(MAXENT_MODEL_ENTRY_NAME) instanceof MaxentModel) && !(artifactMap.get(MAXENT_MODEL_ENTRY_NAME) instanceof SequenceClassificationModel)) { throw new InvalidFormatException("Token Name Finder model is incomplete!"); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/namefind/package-info.java0100644 0000000 0000000 00000001612 15217274217 032657 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to finding proper names and numeric amounts. */ package opennlp.tools.namefind; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ngram/NGramCharModel.java0100644 0000000 0000000 00000014137 15217274217 032447 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ngram; import java.nio.CharBuffer; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import opennlp.tools.util.StringUtil; /** * The {@link NGramCharModel} can be used to create character ngrams. * * @see NGramModel */ public class NGramCharModel implements Iterable { protected static final String COUNT = "count"; private final Map mNGrams = new HashMap<>(); /** * Initializes an empty instance. */ public NGramCharModel() { } /** * Retrieves the count of the given {@link CharSequence ngram}. * * @param ngram The {@code ngram} to get the count for. * @return Count of the {@code ngram} or {@code 0} if it is not contained at all. */ public int getCount(CharSequence ngram) { Integer count; if (ngram instanceof CharBuffer) { count = mNGrams.get(ngram); } else { count = mNGrams.get(CharBuffer.wrap(ngram)); } if (count == null) { return 0; } return count; } /** * Sets the count of an existing {@link CharSequence ngram}. * * @param ngram The {@code ngram} to get the count for. * @param count The count of the {@code ngram} to set. */ public void setCount(CharSequence ngram, int count) { Integer oldCount = mNGrams.put(ngram, count); if (oldCount == null) { mNGrams.remove(ngram); throw new NoSuchElementException(); } } /** * Adds an {@code ngram}. If it already exists the count increase by one. * * @param ngram The {@link CharSequence} to be added. */ public void add(CharSequence ngram) { if (contains(ngram)) { setCount(ngram, getCount(ngram) + 1); } else { mNGrams.put(CharBuffer.wrap(ngram), 1); } } /** * Adds a {@link CharSequence} that will be ngrammed into chars. * * @param chars The {@link CharSequence} to be ngrammed. * @param minLength The minimal length for {@code 'n'} to populate ngrams with. * @param maxLength The maximum length for {@code 'n'} to populate ngrams with. */ public void add(CharSequence chars, int minLength, int maxLength) { CharBuffer cb = StringUtil.toLowerCaseCharBuffer(chars); for (int lengthIndex = minLength; lengthIndex < maxLength + 1; lengthIndex++) { for (int textIndex = 0; textIndex + lengthIndex - 1 < cb.length(); textIndex++) { CharSequence gram = cb.subSequence(textIndex, textIndex + lengthIndex); add(gram); } } } /** * Removes the specified {@code ngram} is from a {@link NGramCharModel}. * * @param ngram The {@code ngram} to remove. If {@code null}, the model keeps its state. */ public void remove(CharSequence ngram) { if (ngram instanceof CharBuffer) { mNGrams.remove(ngram); } else { if (ngram != null) { mNGrams.remove(CharBuffer.wrap(ngram)); } } } /** * Checks if the given {@code ngram} is contained in a {@link NGramCharModel}. * * @param ngram The {@code ngram} to check. If {@code null}, the model keeps its state. * * @return {@code true} if the ngram is contained, {@code false} otherwise. */ public boolean contains(CharSequence ngram) { if (ngram instanceof CharBuffer) { return mNGrams.containsKey(ngram); } else { if (ngram != null) { return mNGrams.containsKey(CharBuffer.wrap(ngram)); } return false; } } /** * Retrieves the number of {@link CharSequence entries} in a {@link NGramCharModel}. * * @return Number of different grams or {@code 0} if the model is empty. */ public int size() { return mNGrams.size(); } /** * Retrieves an {@link Iterator} over all {@link CharSequence entries}. * * @return iterator over all ngrams */ @Override public Iterator iterator() { return mNGrams.keySet().iterator(); } /** * Retrieves the total count of all Ngrams. * * @return total count of all ngrams */ public int numberOfGrams() { int counter = 0; for (CharSequence ngram : this) { counter += getCount(ngram); } return counter; } /** * Deletes all ngram which do appear less than the {@code cutoffUnder} value * and more often than the {@code cutoffOver} value. * * @param cutoffUnder The lower boundary to use for deletions. * Must be greater than {@code 0}. * @param cutoffOver The upper boundary to use for deletions. * Must be greater than {@code 0} */ public void cutoff(int cutoffUnder, int cutoffOver) { if (cutoffUnder > 0 || cutoffOver < Integer.MAX_VALUE) { for (Iterator it = iterator(); it.hasNext(); ) { CharSequence ngram = it.next(); int count = getCount(ngram); if (count < cutoffUnder || count > cutoffOver) { it.remove(); } } } } @Override public boolean equals(Object obj) { boolean result; if (obj == this) { result = true; } else if (obj instanceof NGramCharModel model) { result = mNGrams.equals(model.mNGrams); } else { result = false; } return result; } @Override public String toString() { return "Size: " + size(); } @Override public int hashCode() { return mNGrams.hashCode(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ngram/NGramGenerator.java0100644 0000000 0000000 00000005700 15217274217 032533 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ngram; import java.util.ArrayList; import java.util.List; /** * Generates an nGram, via an optional separator, and returns the grams as a list * of strings */ public class NGramGenerator { /** * Creates nGrams separated * by the separator param value i.e. {@code a,b,c,d} with {@code n = 3} and a * separator as {@code "-"} would return {@code a-b-c,b-c-d}. * * @param input the input tokens the output ngrams will be derived from * @param n the number of tokens as the sliding window * @param separator each string in each gram will be separated by this value if desired. * Pass in empty string if no separator is desired * @return The generated list of resulting nGrams. */ public static List generate(List input, int n, String separator) { List outGrams = new ArrayList<>(); for (int i = 0; i < input.size() - (n - 1); i++) { final StringBuilder sb = new StringBuilder(); for (int x = i; x < (n + i); x++) { sb.append(input.get(x)); sb.append(separator); } String gram = sb.toString(); gram = gram.substring(0, gram.lastIndexOf(separator)); outGrams.add(gram); } return outGrams; } /** * Generates nGrams based on a {@code char[]} input. * @param input the array of chars to convert to nGram * @param n The number of grams (chars) that each output gram will consist of * @param separator each char in each gram will be separated by this value if desired. * Pass in empty string if no separator is desired * @return The generated list of resulting nGrams. */ public static List generate(char[] input, int n, String separator) { List outGrams = new ArrayList<>(); for (int i = 0; i < input.length - (n - 1); i++) { final StringBuilder sb = new StringBuilder(); for (int x = i; x < (n + i); x++) { sb.append(input[x]); sb.append(separator); } String gram = sb.toString(); gram = gram.substring(0, gram.lastIndexOf(separator)); outGrams.add(gram); } return outGrams; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ngram/NGramModel.java0100644 0000000 0000000 00000022170 15217274217 031645 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ngram; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.CharBuffer; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.NoSuchElementException; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.dictionary.serializer.Attributes; import opennlp.tools.dictionary.serializer.DictionaryEntryPersistor; import opennlp.tools.dictionary.serializer.Entry; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.StringList; import opennlp.tools.util.StringUtil; /** * The {@link NGramModel} can be used to crate ngrams and character ngrams. * * @see StringList */ public class NGramModel implements Iterable { protected static final String COUNT = "count"; private final Map mNGrams = new LinkedHashMap<>(); /** * Instantiates an empty {@link NGramModel} instance. */ public NGramModel() { } /** * Instantiates a {@link NGramModel} via an {@link InputStream} reference. * * @param in the serialized model stream * @throws IOException Thrown if errors occurred reading from {@code in}. */ public NGramModel(InputStream in) throws IOException { DictionaryEntryPersistor.create(in, entry -> { int count; String countValueString = null; try { countValueString = entry.attributes().getValue(COUNT); if (countValueString == null) { throw new InvalidFormatException("The count attribute must be set!"); } count = Integer.parseInt(countValueString); } catch (NumberFormatException e) { throw new InvalidFormatException("The count attribute '" + countValueString + "' must be a number!", e); } add(entry.tokens()); setCount(entry.tokens(), count); }); } /** * Retrieves the count of the given ngram. * * @param ngram an ngram * @return count of the ngram or 0 if it is not contained * */ public int getCount(StringList ngram) { Integer count = mNGrams.get(ngram); if (count == null) { return 0; } return count; } /** * Sets the count of an existing ngram. * * @param ngram * @param count */ public void setCount(StringList ngram, int count) { Integer oldCount = mNGrams.put(ngram, count); if (oldCount == null) { mNGrams.remove(ngram); throw new NoSuchElementException(); } } /** * Adds one NGram, if it already exists the count increase by one. * * @param ngram */ public void add(StringList ngram) { if (contains(ngram)) { setCount(ngram, getCount(ngram) + 1); } else { mNGrams.put(ngram, 1); } } /** * Adds NGrams up to the specified length to the current instance. * * @param ngram the tokens to build the uni-grams, bi-grams, tri-grams, .. * from. * @param minLength - minimal length * @param maxLength - maximal length */ public void add(StringList ngram, int minLength, int maxLength) { if (minLength < 1 || maxLength < 1) throw new IllegalArgumentException("minLength and maxLength param must be at least 1. " + "minLength=" + minLength + ", maxLength= " + maxLength); if (minLength > maxLength) throw new IllegalArgumentException("minLength param must not be larger than " + "maxLength param. minLength=" + minLength + ", maxLength= " + maxLength); for (int lengthIndex = minLength; lengthIndex < maxLength + 1; lengthIndex++) { for (int textIndex = 0; textIndex + lengthIndex - 1 < ngram.size(); textIndex++) { String[] grams = new String[lengthIndex]; for (int i = textIndex; i < textIndex + lengthIndex; i++) { grams[i - textIndex] = ngram.getToken(i); } add(new StringList(grams)); } } } /** * Adds character NGrams to the current instance. * * @param chars * @param minLength * @param maxLength */ public void add(CharSequence chars, int minLength, int maxLength) { CharBuffer cb = StringUtil.toLowerCaseCharBuffer(chars); for (int lengthIndex = minLength; lengthIndex < maxLength + 1; lengthIndex++) { for (int textIndex = 0; textIndex + lengthIndex - 1 < chars.length(); textIndex++) { CharSequence gram = cb.subSequence(textIndex, textIndex + lengthIndex); add(new StringList(new String[]{gram.toString()})); } } } /** * Removes the specified tokens form the NGram model, they are just dropped. * * @param tokens */ public void remove(StringList tokens) { mNGrams.remove(tokens); } /** * Checks fit he given tokens are contained by the current instance. * * @param tokens * * @return true if the ngram is contained */ public boolean contains(StringList tokens) { return mNGrams.containsKey(tokens); } /** * Retrieves the number of {@link StringList} entries in the current instance. * * @return number of different grams */ public int size() { return mNGrams.size(); } /** * Retrieves an {@link Iterator} over all {@link StringList} entries. * * @return iterator over all grams */ @Override public Iterator iterator() { return mNGrams.keySet().iterator(); } /** * Retrieves the total count of all Ngrams. * * @return total count of all ngrams */ public int numberOfGrams() { int counter = 0; for (StringList ngram : this) { counter += getCount(ngram); } return counter; } /** * Deletes all ngram which do appear less than the cutoffUnder value * and more often than the cutoffOver value. * * @param cutoffUnder * @param cutoffOver */ public void cutoff(int cutoffUnder, int cutoffOver) { if (cutoffUnder > 0 || cutoffOver < Integer.MAX_VALUE) { for (Iterator it = iterator(); it.hasNext(); ) { StringList ngram = it.next(); int count = getCount(ngram); if (count < cutoffUnder || count > cutoffOver) { it.remove(); } } } } /** * Creates a dictionary which contain all {@link StringList} which * are in the current {@link NGramModel}. *

* Entries which are only different in the case are merged into one. *

* Calling this method is the same as calling {@link #toDictionary(boolean)} with true. * * @return a dictionary of the ngrams */ public Dictionary toDictionary() { return toDictionary(false); } /** * Creates a dictionary which contains all {@link StringList}s which * are in the current {@link NGramModel}. * * @param caseSensitive Specifies whether case distinctions should be kept * in the creation of the dictionary. * * @return a dictionary of the ngrams */ public Dictionary toDictionary(boolean caseSensitive) { Dictionary dict = new Dictionary(caseSensitive); for (StringList stringList : this) { dict.put(stringList); } return dict; } /** * Writes the ngram instance to the given {@link OutputStream}. * * @param out * * @throws IOException if an I/O Error during writing occurs */ public void serialize(OutputStream out) throws IOException { Iterator entryIterator = new Iterator<>() { private final Iterator mDictionaryIterator = NGramModel.this.iterator(); @Override public boolean hasNext() { return mDictionaryIterator.hasNext(); } @Override public Entry next() { StringList tokens = mDictionaryIterator.next(); Attributes attributes = new Attributes(); attributes.setValue(COUNT, Integer.toString(getCount(tokens))); return new Entry(tokens, attributes); } @Override public void remove() { throw new UnsupportedOperationException(); } }; DictionaryEntryPersistor.serialize(out, entryIterator, false); } @Override public boolean equals(Object obj) { boolean result; if (obj == this) { result = true; } else if (obj instanceof NGramModel model) { result = mNGrams.equals(model.mNGrams); } else { result = false; } return result; } @Override public String toString() { return "Size: " + size(); } @Override public int hashCode() { return mNGrams.hashCode(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ngram/NGramUtils.java0100644 0000000 0000000 00000023434 15217274217 031711 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.ngram; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import opennlp.tools.util.StringList; /** * Utility class for ngrams. * Some methods apply specifically to certain 'n' values, for e.g. tri/bi/uni-grams. */ public class NGramUtils { /** * calculate the probability of a ngram in a vocabulary using Laplace smoothing algorithm * * @param ngram the ngram to get the probability for * @param set the vocabulary * @param k the smoothing factor * @return the Laplace smoothing probability * @see Additive Smoothing */ public static double calculateLaplaceSmoothingProbability(StringList ngram, Iterable set, Double k) { return (count(ngram, set) + k) / (count(getNMinusOneTokenFirst(ngram), set) + k * 1); } /** * calculate the probability of a unigram in a vocabulary using maximum likelihood estimation * * @param word the only word in the unigram * @param set the vocabulary * @return the maximum likelihood probability */ public static double calculateUnigramMLProbability(String word, Collection set) { double vocSize = 0d; for (StringList s : set) { vocSize += s.size(); } return count(new StringList(word), set) / vocSize; } /** * calculate the probability of a bigram in a vocabulary using maximum likelihood estimation * * @param x0 first word in the bigram * @param x1 second word in the bigram * @param set the vocabulary * @return the maximum likelihood probability */ public static double calculateBigramMLProbability(String x0, String x1, Collection set) { return calculateNgramMLProbability(new StringList(x0, x1), set); } /** * calculate the probability of a trigram in a vocabulary using maximum likelihood estimation * * @param x0 first word in the trigram * @param x1 second word in the trigram * @param x2 third word in the trigram * @param set the vocabulary * @return the maximum likelihood probability */ public static double calculateTrigramMLProbability(String x0, String x1, String x2, Iterable set) { return calculateNgramMLProbability(new StringList(x0, x1, x2), set); } /** * calculate the probability of a ngram in a vocabulary using maximum likelihood estimation * * @param ngram a ngram * @param set the vocabulary * @return the maximum likelihood probability */ public static double calculateNgramMLProbability(StringList ngram, Iterable set) { StringList ngramMinusOne = getNMinusOneTokenFirst(ngram); return count(ngram, set) / count(ngramMinusOne, set); } /** * calculate the probability of a bigram in a vocabulary using prior Laplace smoothing algorithm * * @param x0 the first word in the bigram * @param x1 the second word in the bigram * @param set the vocabulary * @param k the smoothing factor * @return the prior Laplace smoothing probability */ public static double calculateBigramPriorSmoothingProbability(String x0, String x1, Collection set, Double k) { return (count(new StringList(x0, x1), set) + k * calculateUnigramMLProbability(x1, set)) / (count(new StringList(x0), set) + k * set.size()); } /** * calculate the probability of a trigram in a vocabulary using a linear interpolation algorithm * * @param x0 the first word in the trigram * @param x1 the second word in the trigram * @param x2 the third word in the trigram * @param set the vocabulary * @param lambda1 trigram interpolation factor * @param lambda2 bigram interpolation factor * @param lambda3 unigram interpolation factor * @return the linear interpolation probability */ public static double calculateTrigramLinearInterpolationProbability(String x0, String x1, String x2, Collection set, Double lambda1, Double lambda2, Double lambda3) { assert lambda1 + lambda2 + lambda3 == 1 : "lambdas sum should be equals to 1"; assert lambda1 > 0 && lambda2 > 0 && lambda3 > 0 : "lambdas should all be greater than 0"; return lambda1 * calculateTrigramMLProbability(x0, x1, x2, set) + lambda2 * calculateBigramMLProbability(x1, x2, set) + lambda3 * calculateUnigramMLProbability(x2, set); } /** * calculate the probability of a ngram in a vocabulary using the missing probability mass algorithm * * @param ngram the ngram * @param discount discount factor * @param set the vocabulary * @return the probability */ public static double calculateMissingNgramProbabilityMass(StringList ngram, double discount, Iterable set) { double missingMass = 0d; double countWord = count(ngram, set); for (String word : flatSet(set)) { missingMass += (count(getNPlusOneNgram(ngram, word), set) - discount) / countWord; } return 1 - missingMass; } /** * get the (n-1)th ngram of a given ngram, that is the same ngram except the last word in the ngram * * @param ngram a ngram * @return a ngram */ public static StringList getNMinusOneTokenFirst(StringList ngram) { String[] tokens = new String[ngram.size() - 1]; for (int i = 0; i < ngram.size() - 1; i++) { tokens[i] = ngram.getToken(i); } return tokens.length > 0 ? new StringList(tokens) : null; } /** * get the (n-1)th ngram of a given ngram, that is the same ngram except the first word in the ngram * * @param ngram a ngram * @return a ngram */ public static StringList getNMinusOneTokenLast(StringList ngram) { String[] tokens = new String[ngram.size() - 1]; for (int i = 1; i < ngram.size(); i++) { tokens[i - 1] = ngram.getToken(i); } return tokens.length > 0 ? new StringList(tokens) : null; } private static StringList getNPlusOneNgram(StringList ngram, String word) { String[] tokens = new String[ngram.size() + 1]; for (int i = 0; i < ngram.size(); i++) { tokens[i] = ngram.getToken(i); } tokens[tokens.length - 1] = word; return new StringList(tokens); } private static Double count(StringList ngram, Iterable sentences) { Double count = 0d; for (StringList sentence : sentences) { int idx0 = indexOf(sentence, ngram.getToken(0)); if (idx0 >= 0 && sentence.size() >= idx0 + ngram.size()) { boolean match = true; for (int i = 1; i < ngram.size(); i++) { String sentenceToken = sentence.getToken(idx0 + i); String ngramToken = ngram.getToken(i); match &= sentenceToken.equals(ngramToken); } if (match) { count++; } } } return count; } private static int indexOf(StringList sentence, String token) { for (int i = 0; i < sentence.size(); i++) { if (token.equals(sentence.getToken(i))) { return i; } } return -1; } private static Collection flatSet(Iterable set) { Collection flatSet = new HashSet<>(); for (StringList sentence : set) { for (String word : sentence) { flatSet.add(word); } } return flatSet; } /** * Get the ngrams of dimension n of a certain input sequence of tokens. * * @param sequence a sequence of tokens * @param size the size of the resulting ngrmams * @return all the possible ngrams of the given size derivable from the input sequence */ public static Collection getNGrams(StringList sequence, int size) { Collection ngrams = new LinkedList<>(); if (size == -1 || size >= sequence.size()) { ngrams.add(sequence); } else { String[] ngram = new String[size]; for (int i = 0; i < sequence.size() - size + 1; i++) { ngram[0] = sequence.getToken(i); for (int j = 1; j < size; j++) { ngram[j] = sequence.getToken(i + j); } ngrams.add(new StringList(ngram)); } } return ngrams; } /** * Get the ngrams of dimension n of a certain input sequence of tokens. * * @param sequence a sequence of tokens * @param size the size of the resulting ngrmams * @return all the possible ngrams of the given size derivable from the input sequence */ public static Collection getNGrams(String[] sequence, int size) { Collection ngrams = new LinkedList<>(); if (size == -1 || size >= sequence.length) { ngrams.add(sequence); } else { for (int i = 0; i < sequence.length - size + 1; i++) { String[] ngram = new String[size]; ngram[0] = sequence[i]; for (int j = 1; j < size; j++) { ngram[j] = sequence[i + j]; } ngrams.add(ngram); } } return ngrams; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/ngram/package-info.java0100644 0000000 0000000 00000001607 15217274217 032206 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to computing and storing n-gram frequencies. */ package opennlp.tools.ngram; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/package-info.java0100644 0000000 0000000 00000001564 15217274217 031104 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Contains packages which solve common NLP tasks. */ package opennlp.tools; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_AbstractB0100644 0000000 0000000 00000000160 15217274217 032457 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/AbstractBottomUpParser.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/AbstractBottomUpParser.ja0100644 0000000 0000000 00000050513 15217274217 034135 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.chunker.Chunker; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ngram.NGramModel; import opennlp.tools.parser.chunking.ParserEventStream; import opennlp.tools.postag.POSTagger; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Sequence; import opennlp.tools.util.Span; import opennlp.tools.util.StringList; import opennlp.tools.util.TrainingParameters; /** * Abstract class which contains code to tag and chunk parses for bottom up parsing and * leaves implementation of advancing parses and completing parses to extend class. *

* Note:
The nodes within the returned parses are shared with other parses * and therefore their parent node references will not be consistent with their child * node reference. {@link #setParents setParents} can be used to make the parents consistent * with a particular parse, but subsequent calls to setParents can invalidate * the results of earlier calls.
*/ public abstract class AbstractBottomUpParser implements Parser { private static final Logger logger = LoggerFactory.getLogger(AbstractBottomUpParser.class); /** * The maximum number of parses advanced from all preceding * parses at each derivation step. */ protected int M; /** * The maximum number of parses to advance from a single preceding parse. */ protected int K; /** * The minimum total probability mass of advanced outcomes. */ protected double Q; /** * The default beam size used if no beam size is given. */ public static final int defaultBeamSize = 20; /** * The default amount of probability mass required of advanced outcomes. */ public static final double defaultAdvancePercentage = 0.95; /* * Completed parses. */ private final SortedSet completeParses; /* * Incomplete parses which will be advanced. */ private SortedSet odh; /* * Incomplete parses which have been advanced. */ private SortedSet ndh; /** * The head rules for the parser. */ protected HeadRules headRules; /** * The set strings which are considered punctuation for the parser. * Punctuation is not attached, but floats to the top of the parse as attachment * decisions are made about its non-punctuation sister nodes. */ protected Set punctSet; /** * The label for the top node. */ public static final String TOP_NODE = "TOP"; /** * The label for the top if an incomplete node. */ public static final String INC_NODE = "INC"; /** * The label for a token node. */ public static final String TOK_NODE = "TK"; /** * Prefix for outcomes starting a constituent. */ public static final String START = "S-"; /** * Prefix for outcomes continuing a constituent. */ public static final String CONT = "C-"; /** * Outcome for token which is not contained in a basal constituent. */ public static final String OTHER = "O"; /** * Outcome used when a constituent is complete. */ public static final String COMPLETE = "c"; /** * Outcome used when a constituent is incomplete. */ public static final String INCOMPLETE = "i"; /** * The pos-tagger that the parser uses. */ protected POSTagger tagger; /** * The chunker that the parser uses to chunk non-recursive structures. */ protected Chunker chunker; /** * Specifies whether failed parses should be reported to standard error. */ protected boolean reportFailedParse; /** * Specifies whether a derivation string should be created during parsing. * This is useful for debugging. */ protected boolean createDerivationString = false; public AbstractBottomUpParser(POSTagger tagger, Chunker chunker, HeadRules headRules, int beamSize, double advancePercentage) { this.tagger = tagger; this.chunker = chunker; this.M = beamSize; this.K = beamSize; this.Q = advancePercentage; reportFailedParse = true; this.headRules = headRules; this.punctSet = headRules.getPunctuationTags(); odh = new TreeSet<>(); ndh = new TreeSet<>(); completeParses = new TreeSet<>(); } /** * Specifies whether the parser should report when it was unable to find a parse for * a particular sentence. * * @param errorReporting {@code true} if un-parsed sentences should be reported, * {@code false} otherwise. */ public void setErrorReporting(boolean errorReporting) { this.reportFailedParse = errorReporting; } /** * Assigns parent references for the specified parse so that they * are consistent with the children references. * * @param p The {@link Parse} whose parent references need to be assigned. */ public static void setParents(Parse p) { Parse[] children = p.getChildren(); for (Parse child : children) { child.setParent(p); setParents(child); } } /** * Removes the punctuation from the specified set of {@code chunks}, adds it to the * parses adjacent to the punctuation is specified, and returns a new array of parses * with the punctuation removed. * * @param chunks A set of {@link Parse parses}. * @param punctSet The set of punctuation to be removed. * @return Array of {@link Parse parses} which is a subset of chunks with punctuation removed. */ public static Parse[] collapsePunctuation(Parse[] chunks, Set punctSet) { List collapsedParses = new ArrayList<>(chunks.length); int lastNonPunct = -1; int nextNonPunct; for (int ci = 0, cn = chunks.length; ci < cn; ci++) { if (punctSet.contains(chunks[ci].getType())) { if (lastNonPunct >= 0) { chunks[lastNonPunct].addNextPunctuation(chunks[ci]); } for (nextNonPunct = ci + 1; nextNonPunct < cn; nextNonPunct++) { if (!punctSet.contains(chunks[nextNonPunct].getType())) { break; } } if (nextNonPunct < cn) { chunks[nextNonPunct].addPreviousPunctuation(chunks[ci]); } } else { collapsedParses.add(chunks[ci]); lastNonPunct = ci; } } if (collapsedParses.size() == chunks.length) { return chunks; } return collapsedParses.toArray(new Parse[0]); } /** * Advances the specified {@link Parse} and returns the an array advanced parses whose * probability accounts for more than the specified amount of probability mass. * * @param p The {@link Parse} to advance. * @param probMass The amount of probability mass that should be accounted for * by the advanced parses. */ protected abstract Parse[] advanceParses(final Parse p, double probMass); /** * Adds the {@link #TOP_NODE} to the specified parse. * * @param p The complete {@link Parse}. */ protected abstract void advanceTop(Parse p); @Override public Parse[] parse(Parse tokens, int numParses) { if (createDerivationString) tokens.setDerivation(new StringBuffer(100)); odh.clear(); ndh.clear(); completeParses.clear(); int derivationStage = 0; //derivation length int maxDerivationLength = 2 * tokens.getChildCount() + 3; odh.add(tokens); Parse guess = null; double minComplete = 2; double bestComplete = -100000; //approximating -infinity/0 in ln domain while (odh.size() > 0 && (completeParses.size() < M || (odh.first()).getProb() < minComplete) && derivationStage < maxDerivationLength) { ndh = new TreeSet<>(); int derivationRank = 0; for (Iterator pi = odh.iterator(); pi.hasNext() && derivationRank < K; derivationRank++) { // foreach derivation Parse tp = pi.next(); //TODO: Need to look at this for K-best parsing cases /* //this parse and the ones which follow will never win, stop advancing. if (tp.getProb() < bestComplete) { break; } */ if (guess == null && derivationStage == 2) { guess = tp; } if (logger.isDebugEnabled()) { logger.debug("{} {} {}", derivationStage, derivationRank, tp.getProb()); tp.show(); } Parse[] nd; if (0 == derivationStage) { nd = advanceTags(tp); } else if (1 == derivationStage) { if (ndh.size() < K) { nd = advanceChunks(tp,bestComplete); } else { nd = advanceChunks(tp,(ndh.last()).getProb()); } } else { // i > 1 nd = advanceParses(tp, Q); } if (nd != null) { for (Parse parse : nd) { if (parse.complete()) { advanceTop(parse); if (parse.getProb() > bestComplete) { bestComplete = parse.getProb(); } if (parse.getProb() < minComplete) { minComplete = parse.getProb(); } completeParses.add(parse); } else { ndh.add(parse); } } } else { advanceTop(tp); completeParses.add(tp); } } derivationStage++; odh = ndh; } if (completeParses.size() == 0) { if (guess != null) { setParents(guess); for (Parse childGuess: guess.getChildren()) { setParents(childGuess); } } return new Parse[] {guess}; } else if (numParses == 1) { Parse best = completeParses.first(); setParents(best); for (Parse childBest: best.getChildren()) { setParents(childBest); } return new Parse[] {best}; } else { List topParses = new ArrayList<>(numParses); while (!completeParses.isEmpty() && topParses.size() < numParses) { Parse tp = completeParses.first(); setParents(tp); for (Parse childTp: tp.getChildren()) { setParents(childTp); } completeParses.remove(tp); topParses.add(tp); //parses.remove(tp); } return topParses.toArray(new Parse[0]); } } @Override public Parse parse(Parse tokens) { if (tokens.getChildCount() > 0) { Parse p = parse(tokens,1)[0]; setParents(p); return p; } else { return tokens; } } /** * Returns the top chunk sequences for the specified {@link Parse}. * * @param p A pos-tag assigned {@link Parse}. * @param minChunkScore A minimum score below which chunks should not be advanced. * @return The top chunk assignments to the specified {@link Parse}. */ protected Parse[] advanceChunks(final Parse p, double minChunkScore) { // chunk Parse[] children = p.getChildren(); String[] words = new String[children.length]; String[] ptags = new String[words.length]; double[] probs = new double[words.length]; for (int i = 0, il = children.length; i < il; i++) { Parse sp = children[i]; words[i] = sp.getHead().getCoveredText(); ptags[i] = sp.getType(); } Sequence[] cs = chunker.topKSequences(words, ptags,minChunkScore - p.getProb()); Parse[] newParses = new Parse[cs.length]; for (int si = 0, sl = cs.length; si < sl; si++) { newParses[si] = (Parse) p.clone(); //copies top level if (createDerivationString) newParses[si].getDerivation().append(si).append("."); String[] tags = cs[si].getOutcomes().toArray(new String[words.length]); cs[si].getProbs(probs); int start = -1; int end = 0; String type = null; for (int j = 0; j <= tags.length; j++) { if (j != tags.length) { newParses[si].addProb(StrictMath.log(probs[j])); } // if continue just update end chunking tag don't use contTypeMap if (j != tags.length && tags[j].startsWith(CONT)) { end = j; } else { //make previous constituent if it exists if (type != null) { Parse p1 = p.getChildren()[start]; Parse p2 = p.getChildren()[end]; Parse[] cons = new Parse[end - start + 1]; cons[0] = p1; //cons[0].label="Start-"+type; if (end - start != 0) { cons[end - start] = p2; //cons[end-start].label="Cont-"+type; for (int ci = 1; ci < end - start; ci++) { cons[ci] = p.getChildren()[ci + start]; //cons[ci].label="Cont-"+type; } } Parse chunk = new Parse(p1.getText(), new Span(p1.getSpan().getStart(), p2.getSpan().getEnd()), type, 1, headRules.getHead(cons, type)); chunk.isChunk(true); newParses[si].insert(chunk); } if (j != tags.length) { //update for new constituent if (tags[j].startsWith(START)) { // don't use startTypeMap these are chunk tags type = tags[j].substring(START.length()); start = j; end = j; } else { // other type = null; } } } } } return newParses; } /** * Advances the {@link Parse} by assigning it POS tags and returns multiple tag sequences. * * @param p The {@link Parse} to be tagged. * @return Parses with different POS-tag sequence assignments. */ protected Parse[] advanceTags(final Parse p) { Parse[] children = p.getChildren(); String[] words = new String[children.length]; double[] probs = new double[words.length]; for (int i = 0,il = children.length; i < il; i++) { words[i] = children[i].getCoveredText(); } Sequence[] ts = tagger.topKSequences(words); Parse[] newParses = new Parse[ts.length]; for (int i = 0; i < ts.length; i++) { String[] tags = ts[i].getOutcomes().toArray(new String[words.length]); ts[i].getProbs(probs); newParses[i] = (Parse) p.clone(); //copies top level if (createDerivationString) newParses[i].getDerivation().append(i).append("."); for (int j = 0; j < words.length; j++) { Parse word = children[j]; double prob = probs[j]; newParses[i].insert(new Parse(word.getText(), word.getSpan(), tags[j], prob,j)); newParses[i].addProb(StrictMath.log(prob)); } } return newParses; } /** * Determines the mapping between the specified {@code index} into the specified {@link Parse parses} * without punctuation to the corresponding index into the specified {@link Parse parses}. * * @param index An index into the {@link Parse parses} without punctuation. * @param nonPunctParses The {@link Parse parses} without punctuation. * @param parses The {@link Parse parses} with punctuation. * @return An index into the specified parses which corresponds to the same node the specified index * into the parses with punctuation. */ protected int mapParseIndex(int index, Parse[] nonPunctParses, Parse[] parses) { int parseIndex = index; while (parses[parseIndex] != nonPunctParses[index]) { parseIndex++; } return parseIndex; } private static boolean lastChild(Parse child, Parse parent, Set punctSet) { if (parent == null) { return false; } Parse[] kids = collapsePunctuation(parent.getChildren(), punctSet); return (kids[kids.length - 1] == child); } /** * Creates a n-gram {@link Dictionary} from the specified data stream using the specified * head rule and specified cut-off. * * @param data The data stream of {@link Parse parses}. * @param rules The {@link HeadRules} for the parses. * @param params The {@link TrainingParameters} which can contain a {@code cutoff}, * the minimum number of entries required for the n-gram to be saved as * part of the {@link Dictionary}. * @return A {@link Dictionary} instance. */ public static Dictionary buildDictionary(ObjectStream data, HeadRules rules, TrainingParameters params) throws IOException { int cutoff = params.getIntParameter("dict", TrainingParameters.CUTOFF_PARAM, 5); NGramModel mdict = new NGramModel(); Parse p; while ((p = data.read()) != null) { p.updateHeads(rules); Parse[] pwords = p.getTagNodes(); String[] words = new String[pwords.length]; //add all uni-grams for (int wi = 0;wi < words.length; wi++) { words[wi] = pwords[wi].getCoveredText(); } mdict.add(new StringList(words), 1, 1); //add tri-grams and bi-grams for initial sequence Parse[] chunks = collapsePunctuation(ParserEventStream.getInitialChunks(p), rules.getPunctuationTags()); String[] cwords = new String[chunks.length]; for (int wi = 0; wi < cwords.length; wi++) { cwords[wi] = chunks[wi].getHead().getCoveredText(); } mdict.add(new StringList(cwords), 2, 3); //emulate reductions to produce additional n-grams int ci = 0; while (ci < chunks.length) { // System.err.println("chunks["+ci+"]="+chunks[ci].getHead().getCoveredText() // +" chunks.length="+chunks.length + " " + chunks[ci].getParent()); if (chunks[ci].getParent() == null) { chunks[ci].show(); } if (lastChild(chunks[ci], chunks[ci].getParent(),rules.getPunctuationTags())) { //perform reduce int reduceStart = ci; while (reduceStart >= 0 && chunks[reduceStart].getParent() == chunks[ci].getParent()) { reduceStart--; } reduceStart++; chunks = ParserEventStream.reduceChunks(chunks,ci,chunks[ci].getParent()); ci = reduceStart; if (chunks.length != 0) { String[] window = new String[5]; int wi = 0; if (ci - 2 >= 0) window[wi++] = chunks[ci - 2].getHead().getCoveredText(); if (ci - 1 >= 0) window[wi++] = chunks[ci - 1].getHead().getCoveredText(); window[wi++] = chunks[ci].getHead().getCoveredText(); if (ci + 1 < chunks.length) window[wi++] = chunks[ci + 1].getHead().getCoveredText(); if (ci + 2 < chunks.length) window[wi++] = chunks[ci + 2].getHead().getCoveredText(); if (wi < 5) { String[] subWindow = new String[wi]; System.arraycopy(window, 0, subWindow, 0, wi); window = subWindow; } if (window.length >= 3) { mdict.add(new StringList(window), 2, 3); } else if (window.length == 2) { mdict.add(new StringList(window), 2, 2); } } ci = reduceStart - 1; //ci will be incremented at end of loop } ci++; } } mdict.cutoff(cutoff, Integer.MAX_VALUE); return mdict.toDictionary(true); } /** * Creates a n-gram {@link Dictionary} from the specified data stream using {@link HeadRules} * and specified cut-off. * * @param data The data stream of {@link Parse parses}. * @param rules The {@link HeadRules} for the {@link Parse parses}. * @param cutoff The minimum number of entries required for the n-gram to be * saved as part of the dictionary. * @return A {@link Dictionary} instance. */ public static Dictionary buildDictionary(ObjectStream data, HeadRules rules, int cutoff) throws IOException { TrainingParameters params = new TrainingParameters(); params.put("dict", TrainingParameters.CUTOFF_PARAM, cutoff); return buildDictionary(data, rules, params); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_AbstractC0100644 0000000 0000000 00000000162 15217274217 032462 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/AbstractContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/AbstractContextGenerator.0100644 0000000 0000000 00000042166 15217274217 034174 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.Collection; import java.util.List; import java.util.Set; /** * Abstract class containing many of the methods used to generate contexts for parsing. */ public abstract class AbstractContextGenerator { protected static final String EOS = "eos"; protected boolean zeroBackOff; /** Set of punctuation to be used in generating features. */ protected Set punctSet; protected boolean useLabel; /** * Creates punctuation feature for the specified punctuation at the specified index * {@code i} based on the {@code punctuation} mark. * * @param punct The punctuation which is in context. * @param i The index of the {@code punctuation} with relative to the parse. * @return Punctuation feature for the parse and the punctuation at the specified index. */ protected String punct(Parse punct, int i) { return i + "=" + punct.getCoveredText(); } /** * Creates punctuation feature for the specified punctuation at the specified index * {@code i} based on the {@code punctuation}'s tag. * * @param punct The punctuation which is in context. * @param i The index of the {@code punctuation} relative to the parse. * @return Punctuation feature for the parse and the punctuation at the specified index. */ protected String punctbo(Parse punct, int i) { return i + "=" + punct.getType(); } protected String cons(Parse p, int i) { StringBuilder feat = new StringBuilder(20); feat.append(i).append("="); if (p != null) { if (useLabel && i < 0) { feat.append(p.getLabel()).append("|"); } feat.append(p.getType()).append("|").append(p.getHead().getCoveredText()); } else { feat.append(EOS); } return feat.toString(); } protected String consbo(Parse p, int i) { //cons back-off StringBuilder feat = new StringBuilder(20); feat.append(i).append("*="); if (p != null) { if (useLabel && i < 0) { feat.append(p.getLabel()).append("|"); } feat.append(p.getType()); } else { feat.append(EOS); } return feat.toString(); } /** * Generates a string representing the grammar rule production that the specified parse * is starting. *

* The rule is of the form {@code p.type -> c.children[0..n].type}. * * @param p The {@link Parse} which stats the production. * @param includePunctuation Whether punctuation should be included in the production. * @return A string representing the grammar rule production that the specified parse * is starting. */ protected String production(Parse p, boolean includePunctuation) { StringBuilder production = new StringBuilder(20); production.append(p.getType()).append("->"); Parse[] children = AbstractBottomUpParser.collapsePunctuation(p.getChildren(),punctSet); for (int ci = 0; ci < children.length; ci++) { production.append(children[ci].getType()); if (ci + 1 != children.length) { production.append(","); Collection nextPunct = children[ci].getNextPunctuationSet(); if (includePunctuation && nextPunct != null) { //TODO: make sure multiple punctuation comes out the same for (Parse punct : nextPunct) { production.append(punct.getType()).append(","); } } } } return production.toString(); } protected void cons2(List features, Cons c0, Cons c1, Collection punct1s, boolean bigram) { if (punct1s != null) { for (Parse p : punct1s) { String punctbo = punctbo(p, c1.index <= 0 ? c1.index - 1 : c1.index); //punctbo(1); features.add(punctbo); if (c0.index == 0) { //TODO look at removing case //cons(0)punctbo(1) if (c0.unigram) features.add(c0.cons + "," + punctbo); features.add(c0.consbo + "," + punctbo); } if (c1.index == 0) { //TODO look at removing case //punctbo(1)cons(1) if (c1.unigram) features.add(punctbo + "," + c1.cons); features.add(punctbo + "," + c1.consbo); } //cons(0)punctbo(1)cons(1) if (bigram) features.add(c0.cons + "," + punctbo + "," + c1.cons); if (c1.unigram) features.add(c0.consbo + "," + punctbo + "," + c1.cons); if (c0.unigram) features.add(c0.cons + "," + punctbo + "," + c1.consbo); features.add(c0.consbo + "," + punctbo + "," + c1.consbo); } } else { //cons(0),cons(1) if (bigram) features.add(c0.cons + "," + c1.cons); if (c1.unigram) features.add(c0.consbo + "," + c1.cons); if (c0.unigram) features.add(c0.cons + "," + c1.consbo); features.add(c0.consbo + "," + c1.consbo); } } /** * Creates cons features involving the 3 specified nodes and adds them to the specified feature list. * * @param features The list of features. * @param c0 The first {@link Cons node}. * @param c1 The second {@link Cons node}. * @param c2 The third {@link Cons node}. * @param punct1s The punctuation between {@code c0} and {@code c1}. * @param punct2s The punctuation between {@code c1} and {@code c2}. * @param trigram Specifies whether lexical tri-gram features between these nodes * should be generated. * @param bigram1 Specifies whether lexical bi-gram features between {@code c0} and {@code c1} * should be generated. * @param bigram2 Specifies whether lexical bi-gram features between {@code c1} and {@code c2} * should be generated. */ protected void cons3(List features, Cons c0, Cons c1, Cons c2, Collection punct1s, Collection punct2s, boolean trigram, boolean bigram1, boolean bigram2) { // features.add("stage=cons(0),cons(1),cons(2)"); if (punct1s != null) { if (c0.index == -2) { for (Parse p : punct1s) { // String punct = punct(p,c1.index); String punctbo = punctbo(p, c1.index <= 0 ? c1.index - 1 : c1.index); //punct(-2) //TODO consider changing //features.add(punct); //punctbo(-2) features.add(punctbo); } } } if (punct2s != null) { if (c2.index == 2) { for (Parse p : punct2s) { // String punct = punct(p,c2.index); String punctbo = punctbo(p, c2.index); //punct(2) //TODO consider changing //features.add(punct); //punctbo(2) features.add(punctbo); } } if (punct1s != null) { //cons(0),punctbo(1),cons(1),punctbo(2),cons(2) for (Parse punct2 : punct2s) { String punctbo2 = punctbo(punct2, c2.index <= 0 ? c2.index - 1 : c2.index); for (Parse punct1 : punct1s) { String punctbo1 = punctbo(punct1, c1.index <= 0 ? c1.index - 1 : c1.index); if (trigram) features.add(c0.cons + "," + punctbo1 + "," + c1.cons + "," + punctbo2 + "," + c2.cons); if (bigram2) features.add(c0.consbo + "," + punctbo1 + "," + c1.cons + "," + punctbo2 + "," + c2.cons); if (c0.unigram && c2.unigram) features.add(c0.cons + "," + punctbo1 + "," + c1.consbo + "," + punctbo2 + "," + c2.cons); if (bigram1) features.add(c0.cons + "," + punctbo1 + "," + c1.cons + "," + punctbo2 + "," + c2.consbo); if (c2.unigram) features.add(c0.consbo + "," + punctbo1 + "," + c1.consbo + "," + punctbo2 + "," + c2.cons); if (c1.unigram) features.add(c0.consbo + "," + punctbo1 + "," + c1.cons + "," + punctbo2 + "," + c2.consbo); if (c0.unigram) features.add(c0.cons + "," + punctbo1 + "," + c1.consbo + "," + punctbo2 + "," + c2.consbo); features.add(c0.consbo + "," + punctbo1 + "," + c1.consbo + "," + punctbo2 + "," + c2.consbo); if (zeroBackOff) { if (bigram1) features.add(c0.cons + "," + punctbo1 + "," + c1.cons + "," + punctbo2); if (c1.unigram) features.add(c0.consbo + "," + punctbo1 + "," + c1.cons + "," + punctbo2); if (c0.unigram) features.add(c0.cons + "," + punctbo1 + "," + c1.consbo + "," + punctbo2); features.add(c0.consbo + "," + punctbo1 + "," + c1.consbo + "," + punctbo2); } } } } else { //punct1s == null //cons(0),cons(1),punctbo(2),cons(2) for (Parse punct2 : punct2s) { String punctbo2 = punctbo(punct2, c2.index <= 0 ? c2.index - 1 : c2.index); if (trigram) features.add(c0.cons + "," + c1.cons + "," + punctbo2 + "," + c2.cons); if (bigram2) features.add(c0.consbo + "," + c1.cons + "," + punctbo2 + "," + c2.cons); if (c0.unigram && c2.unigram) features.add(c0.cons + "," + c1.consbo + "," + punctbo2 + "," + c2.cons); if (bigram1) features.add(c0.cons + "," + c1.cons + "," + punctbo2 + "," + c2.consbo); if (c2.unigram) features.add(c0.consbo + "," + c1.consbo + "," + punctbo2 + "," + c2.cons); if (c1.unigram) features.add(c0.consbo + "," + c1.cons + "," + punctbo2 + "," + c2.consbo); if (c0.unigram) features.add(c0.cons + "," + c1.consbo + "," + punctbo2 + "," + c2.consbo); features.add(c0.consbo + "," + c1.consbo + "," + punctbo2 + "," + c2.consbo); if (zeroBackOff) { if (bigram1) features.add(c0.cons + "," + c1.cons + "," + punctbo2); if (c1.unigram) features.add(c0.consbo + "," + c1.cons + "," + punctbo2); if (c0.unigram) features.add(c0.cons + "," + c1.consbo + "," + punctbo2); features.add(c0.consbo + "," + c1.consbo + "," + punctbo2); } } } } else { if (punct1s != null) { //cons(0),punctbo(1),cons(1),cons(2) for (Parse punct1 : punct1s) { String punctbo1 = punctbo(punct1, c1.index <= 0 ? c1.index - 1 : c1.index); if (trigram) features.add(c0.cons + "," + punctbo1 + "," + c1.cons + "," + c2.cons); if (bigram2) features.add(c0.consbo + "," + punctbo1 + "," + c1.cons + "," + c2.cons); if (c0.unigram && c2.unigram) features.add(c0.cons + "," + punctbo1 + "," + c1.consbo + "," + c2.cons); if (bigram1) features.add(c0.cons + "," + punctbo1 + "," + c1.cons + "," + c2.consbo); if (c2.unigram) features.add(c0.consbo + "," + punctbo1 + "," + c1.consbo + "," + c2.cons); if (c1.unigram) features.add(c0.consbo + "," + punctbo1 + "," + c1.cons + "," + c2.consbo); if (c0.unigram) features.add(c0.cons + "," + punctbo1 + "," + c1.consbo + "," + c2.consbo); features.add(c0.consbo + "," + punctbo1 + "," + c1.consbo + "," + c2.consbo); //zero backoff case covered by cons(0)cons(1) } } else { //cons(0),cons(1),cons(2) if (trigram) features.add(c0.cons + "," + c1.cons + "," + c2.cons); if (bigram2) features.add(c0.consbo + "," + c1.cons + "," + c2.cons); if (c0.unigram && c2.unigram) features.add(c0.cons + "," + c1.consbo + "," + c2.cons); if (bigram1) features.add(c0.cons + "," + c1.cons + "," + c2.consbo); if (c2.unigram) features.add(c0.consbo + "," + c1.consbo + "," + c2.cons); if (c1.unigram) features.add(c0.consbo + "," + c1.cons + "," + c2.consbo); if (c0.unigram) features.add(c0.cons + "," + c1.consbo + "," + c2.consbo); features.add(c0.consbo + "," + c1.consbo + "," + c2.consbo); } } } /** * Generates features for nodes surrounding a completed node of the specified {@code type}. * * @param node A surrounding {@link Parse node}. * @param i The index of the surrounding {@code node} with respect to the completed node. * @param type The type of the completed node. * @param punctuation The punctuation adjacent and between the specified surrounding node. * @param features A list to which features are added. */ protected void surround(Parse node, int i, String type, Collection punctuation, List features) { StringBuilder feat = new StringBuilder(20); feat.append("s").append(i).append("="); if (punctuation != null) { for (Parse punct : punctuation) { if (node != null) { feat.append(node.getHead().getCoveredText()).append("|").append(type) .append("|").append(node.getType()).append("|").append(punct.getType()); } else { feat.append(type).append("|").append(EOS).append("|").append(punct.getType()); } features.add(feat.toString()); feat.setLength(0); feat.append("s").append(i).append("*="); if (node != null) { feat.append(type).append("|").append(node.getType()).append("|").append(punct.getType()); } else { feat.append(type).append("|").append(EOS).append("|").append(punct.getType()); } features.add(feat.toString()); feat.setLength(0); feat.append("s").append(i).append("*="); feat.append(type).append("|").append(punct.getType()); features.add(feat.toString()); } } else { if (node != null) { feat.append(node.getHead().getCoveredText()).append("|").append(type) .append("|").append(node.getType()); } else { feat.append(type).append("|").append(EOS); } features.add(feat.toString()); feat.setLength(0); feat.append("s").append(i).append("*="); if (node != null) { feat.append(type).append("|").append(node.getType()); } else { feat.append(type).append("|").append(EOS); } features.add(feat.toString()); } } /** * Produces features to determine whether the specified child node is part of * a complete constituent of the specified type and adds those features to the * specified list. * * @param child The {@link Parse node} to consider. * @param i A string indicating the position of the child node. * @param type The type of constituent being built. * @param features List to add features to. */ protected void checkcons(Parse child, String i, String type, List features) { StringBuilder feat = new StringBuilder(20); feat.append("c").append(i).append("=").append(child.getType()).append("|") .append(child.getHead().getCoveredText()).append("|").append(type); features.add(feat.toString()); feat.setLength(0); feat.append("c").append(i).append("*=").append(child.getType()).append("|").append(type); features.add(feat.toString()); } protected void checkcons(Parse p1, Parse p2, String type, List features) { StringBuilder feat = new StringBuilder(20); feat.append("cil=").append(type).append(",").append(p1.getType()).append("|") .append(p1.getHead().getCoveredText()).append(",").append(p2.getType()) .append("|").append(p2.getHead().getCoveredText()); features.add(feat.toString()); feat.setLength(0); feat.append("ci*l=").append(type).append(",").append(p1.getType()).append(",") .append(p2.getType()).append("|").append(p2.getHead().getCoveredText()); features.add(feat.toString()); feat.setLength(0); feat.append("cil*=").append(type).append(",").append(p1.getType()).append("|") .append(p1.getHead().getCoveredText()).append(",").append(p2.getType()); features.add(feat.toString()); feat.setLength(0); feat.append("ci*l*=").append(type).append(",").append(p1.getType()) .append(",").append(p2.getType()); features.add(feat.toString()); } /** * Populates specified nodes array with left-most right frontier * node with a unique head. If the right frontier doesn't contain * enough nodes, then {@code nulls} are placed in the array elements. * * @param rf The current right frontier. * @param nodes The array to be populated. */ protected void getFrontierNodes(List rf, Parse[] nodes) { int leftIndex = 0; int prevHeadIndex = -1; for (Parse fn : rf) { int headIndex = fn.getHeadIndex(); if (headIndex != prevHeadIndex) { nodes[leftIndex] = fn; leftIndex++; prevHeadIndex = headIndex; if (leftIndex == nodes.length) { break; } } } for (int ni = leftIndex; ni < nodes.length; ni++) { nodes[ni] = null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_AbstractP0100644 0000000 0000000 00000000163 15217274217 032500 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/AbstractParserEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/AbstractParserEventStream0100644 0000000 0000000 00000014570 15217274217 034233 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import opennlp.tools.chunker.ChunkerContextGenerator; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.model.Event; import opennlp.tools.parser.chunking.Parser; import opennlp.tools.postag.DefaultPOSContextGenerator; import opennlp.tools.postag.POSContextGenerator; import opennlp.tools.util.ObjectStream; /** * Abstract class extended by parser event streams which perform tagging and chunking. */ public abstract class AbstractParserEventStream extends opennlp.tools.util.AbstractEventStream { private ChunkerContextGenerator chunkerContextGenerator; private POSContextGenerator tagContextGenerator; protected final HeadRules rules; protected final Set punctSet; /** * The type of events being generated by this event stream. */ protected final ParserEventTypeEnum etype; protected boolean fixPossesives; protected final Dictionary dict; public AbstractParserEventStream(ObjectStream d, HeadRules rules, ParserEventTypeEnum etype, Dictionary dict) { super(d); this.dict = dict; if (etype == ParserEventTypeEnum.CHUNK) { this.chunkerContextGenerator = new ChunkContextGenerator(); } else if (etype == ParserEventTypeEnum.TAG) { this.tagContextGenerator = new DefaultPOSContextGenerator(null); } this.rules = rules; punctSet = rules.getPunctuationTags(); this.etype = etype; init(); } @Override protected Iterator createEvents(Parse sample) { List newEvents = new ArrayList<>(); Parse.pruneParse(sample); if (fixPossesives) { Parse.fixPossesives(sample); } sample.updateHeads(rules); Parse[] chunks = getInitialChunks(sample); if (etype == ParserEventTypeEnum.TAG) { addTagEvents(newEvents, chunks); } else if (etype == ParserEventTypeEnum.CHUNK) { addChunkEvents(newEvents, chunks); } else { addParseEvents(newEvents, Parser.collapsePunctuation(chunks,punctSet)); } return newEvents.iterator(); } protected void init() { fixPossesives = false; } public AbstractParserEventStream(ObjectStream d, HeadRules rules, ParserEventTypeEnum etype) { this(d,rules,etype,null); } public static Parse[] getInitialChunks(Parse p) { List chunks = new ArrayList<>(); getInitialChunks(p, chunks); return chunks.toArray(new Parse[0]); } private static void getInitialChunks(Parse p, List ichunks) { if (p.isPosTag()) { ichunks.add(p); } else { Parse[] kids = p.getChildren(); boolean allKidsAreTags = true; for (Parse kid : kids) { if (!kid.isPosTag()) { allKidsAreTags = false; break; } } if (allKidsAreTags) { ichunks.add(p); } else { for (Parse kid : kids) { getInitialChunks(kid, ichunks); } } } } /** * Produces all events for the specified sentence {@code chunks} * and adds them to the specified {@code newEvents} list. * * @param newEvents A list of {@link Event events} to be added to. * @param chunks Pre-chunked {@link Parse constituents} of a sentence. */ protected abstract void addParseEvents(List newEvents, Parse[] chunks); private void addChunkEvents(List chunkEvents, Parse[] chunks) { List toks = new ArrayList<>(); List tags = new ArrayList<>(); List preds = new ArrayList<>(); for (Parse c : chunks) { if (c.isPosTag()) { toks.add(c.getCoveredText()); tags.add(c.getType()); preds.add(Parser.OTHER); } else { boolean start = true; String ctype = c.getType(); Parse[] kids = c.getChildren(); for (Parse tok : kids) { toks.add(tok.getCoveredText()); tags.add(tok.getType()); if (start) { preds.add(Parser.START + ctype); start = false; } else { preds.add(Parser.CONT + ctype); } } } } for (int ti = 0, tl = toks.size(); ti < tl; ti++) { chunkEvents.add(new Event(preds.get(ti), chunkerContextGenerator.getContext(ti, toks.toArray(new String[0]), tags.toArray(new String[0]), preds.toArray(new String[0])))); } } private void addTagEvents(List tagEvents, Parse[] chunks) { List toks = new ArrayList<>(); List preds = new ArrayList<>(); for (Parse c : chunks) { if (c.isPosTag()) { toks.add(c.getCoveredText()); preds.add(c.getType()); } else { Parse[] kids = c.getChildren(); for (Parse tok : kids) { toks.add(tok.getCoveredText()); preds.add(tok.getType()); } } } for (int ti = 0, tl = toks.size(); ti < tl; ti++) { tagEvents.add(new Event(preds.get(ti), tagContextGenerator.getContext(ti, toks.toArray(new String[0]), preds.toArray(new String[0]), null))); } } /** * Returns {@code true} if the {@link Parse child} is the last child of the specified * {@link Parse parent}. * * @param child The child {@link Parse}. * @param parent The parent {@link Parse}. * @return {@code true} if the specified child is the last child of the specified parent, * {@code false} otherwise. */ protected boolean lastChild(Parse child, Parse parent) { Parse[] kids = AbstractBottomUpParser.collapsePunctuation(parent.getChildren(),punctSet); return kids[kids.length - 1] == child; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_ChunkCont0100644 0000000 0000000 00000000157 15217274217 032514 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ChunkContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ChunkContextGenerator.jav0100644 0000000 0000000 00000012320 15217274217 034167 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.ArrayList; import java.util.List; import opennlp.tools.chunker.ChunkerContextGenerator; import opennlp.tools.util.Cache; import opennlp.tools.util.TokenTag; /** * Creates predictive context for the pre-chunking phases of parsing. */ public class ChunkContextGenerator implements ChunkerContextGenerator { private static final String EOS = "eos"; private Cache contextsCache; private Object wordsKey; /** * Initializes a {@link ChunkContextGenerator} instance. */ public ChunkContextGenerator() { this(0); } /** * Initializes a {@link ChunkContextGenerator} instance with a custom {@code cacheSize}. * * @param cacheSize The cache size. Must be greater than {@code 0} to have an effect. */ public ChunkContextGenerator(int cacheSize) { super(); if (cacheSize > 0) { contextsCache = new Cache<>(cacheSize); } } @Override public String[] getContext(int i, String[] words, String[] tags, String[] preds) { List features = new ArrayList<>(19); int x_2 = i - 2; int x_1 = i - 1; int x2 = i + 2; int x1 = i + 1; String w_2,w_1,w0,w1,w2; String t_2,t_1,t0,t1,t2; String p_2,p_1; // chunkandpostag(-2) if (x_2 >= 0) { t_2 = tags[x_2]; p_2 = preds[x_2]; w_2 = words[x_2]; } else { t_2 = EOS; p_2 = EOS; w_2 = EOS; } // chunkandpostag(-1) if (x_1 >= 0) { t_1 = tags[x_1]; p_1 = preds[x_1]; w_1 = words[x_1]; } else { t_1 = EOS; p_1 = EOS; w_1 = EOS; } // chunkandpostag(0) t0 = tags[i]; w0 = words[i]; // chunkandpostag(1) if (x1 < tags.length) { t1 = tags[x1]; w1 = words[x1]; } else { t1 = EOS; w1 = EOS; } // chunkandpostag(2) if (x2 < tags.length) { t2 = tags[x2]; w2 = words[x2]; } else { t2 = EOS; w2 = EOS; } String cacheKey = i + t_2 + t1 + t0 + t1 + t2 + p_2 + p_1; if (contextsCache != null) { if (wordsKey == words) { String[] contexts = contextsCache.get(cacheKey); if (contexts != null) { return contexts; } } else { contextsCache.clear(); wordsKey = words; } } String ct_2 = chunkandpostag(-2, w_2, t_2, p_2); String ctbo_2 = chunkandpostagbo(-2, t_2, p_2); String ct_1 = chunkandpostag(-1, w_1, t_1, p_1); String ctbo_1 = chunkandpostagbo(-1, t_1, p_1); String ct0 = chunkandpostag(0, w0, t0, null); String ctbo0 = chunkandpostagbo(0, t0, null); String ct1 = chunkandpostag(1, w1, t1, null); String ctbo1 = chunkandpostagbo(1, t1, null); String ct2 = chunkandpostag(2, w2, t2, null); String ctbo2 = chunkandpostagbo(2, t2, null); features.add("default"); features.add(ct_2); features.add(ctbo_2); features.add(ct_1); features.add(ctbo_1); features.add(ct0); features.add(ctbo0); features.add(ct1); features.add(ctbo1); features.add(ct2); features.add(ctbo2); //chunkandpostag(-1,0) features.add(ct_1 + "," + ct0); features.add(ctbo_1 + "," + ct0); features.add(ct_1 + "," + ctbo0); features.add(ctbo_1 + "," + ctbo0); //chunkandpostag(0,1) features.add(ct0 + "," + ct1); features.add(ctbo0 + "," + ct1); features.add(ct0 + "," + ctbo1); features.add(ctbo0 + "," + ctbo1); String[] contexts = features.toArray(new String[0]); if (contextsCache != null) { contextsCache.put(cacheKey,contexts); } return contexts; } private String chunkandpostag(int i, String tok, String tag, String chunk) { StringBuilder feat = new StringBuilder(20); feat.append(i).append("=").append(tok).append("|").append(tag); if (i < 0) { feat.append("|").append(chunk); } return feat.toString(); } private String chunkandpostagbo(int i, String tag, String chunk) { StringBuilder feat = new StringBuilder(20); feat.append(i).append("*=").append(tag); if (i < 0) { feat.append("|").append(chunk); } return feat.toString(); } @Override public String[] getContext(int index, TokenTag[] sequence, String[] priorDecisions, Object[] additionalContext) { String[] token = TokenTag.extractTokens(sequence); String[] tags = TokenTag.extractTags(sequence); return getContext(index, token, tags, priorDecisions); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ChunkSampleStream.java0100644 0000000 0000000 00000006155 15217274217 033443 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.io.IOException; import java.util.ArrayList; import java.util.List; import opennlp.tools.chunker.ChunkSample; import opennlp.tools.parser.chunking.Parser; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public class ChunkSampleStream extends FilterObjectStream { /** * Initializes a {@link ChunkSampleStream instance}. * * @param in A {@link ObjectStream stream} used as input. */ public ChunkSampleStream(ObjectStream in) { super(in); } private static void getInitialChunks(Parse p, List ichunks) { if (p.isPosTag()) { ichunks.add(p); } else { Parse[] kids = p.getChildren(); boolean allKidsAreTags = true; for (Parse kid : kids) { if (!kid.isPosTag()) { allKidsAreTags = false; break; } } if (allKidsAreTags) { ichunks.add(p); } else { for (Parse kid : kids) { getInitialChunks(kid, ichunks); } } } } public static Parse[] getInitialChunks(Parse p) { List chunks = new ArrayList<>(); getInitialChunks(p, chunks); return chunks.toArray(new Parse[0]); } @Override public ChunkSample read() throws IOException { Parse parse = samples.read(); if (parse != null) { Parse[] chunks = getInitialChunks(parse); List toks = new ArrayList<>(); List tags = new ArrayList<>(); List preds = new ArrayList<>(); for (Parse c : chunks) { if (c.isPosTag()) { toks.add(c.getCoveredText()); tags.add(c.getType()); preds.add(Parser.OTHER); } else { boolean start = true; String ctype = c.getType(); Parse[] kids = c.getChildren(); for (Parse tok : kids) { toks.add(tok.getCoveredText()); tags.add(tok.getType()); if (start) { preds.add(Parser.START + ctype); start = false; } else { preds.add(Parser.CONT + ctype); } } } } return new ChunkSample(toks.toArray(new String[0]), tags.toArray(new String[0]), preds.toArray(new String[0])); } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/Cons.java0100644 0000000 0000000 00000002274 15217274217 030755 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; /** * Holds feature information about a specific {@link Parse} node. * * @see Parse */ public class Cons { final String cons; final String consbo; final int index; final boolean unigram; public Cons(String cons, String consbo, int index, boolean unigram) { this.cons = cons; this.consbo = consbo; this.index = index; this.unigram = unigram; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/Constituent.java0100644 0000000 0000000 00000003060 15217274217 032364 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import opennlp.tools.util.Span; /** * Holds constituents when reading {@link Parse parses}. * * @see Parse */ public class Constituent { private String label; private final Span span; public Constituent(String label, Span span) { this.label = label; this.span = span; } /** * Returns the label of the constituent. * @return the label of the constituent. */ public String getLabel() { return label; } /** * Assigns the label to the constituent. * @param label The label to set. */ public void setLabel(String label) { this.label = label; } /** * Returns the span of the constituent. * @return the span of the constituent. */ public Span getSpan() { return span; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/GapLabeler.java0100644 0000000 0000000 00000002415 15217274217 032046 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.Stack; /** * Represents a labeler for nodes which contain traces so that these traces can be predicted * by a {@link Parser}. * * @see Parser */ public interface GapLabeler { /** * Labels {@link Constituent constituents} found in the {@code stack} with gap labels * if appropriate. * * @param stack The {@link Stack} of un-completed {@link Constituent constituents}. */ void labelGaps(Stack stack); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/HeadRules.java0100644 0000000 0000000 00000003067 15217274217 031730 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.Set; /** * Encoder for head rules associated with parsing. */ public interface HeadRules { /** * Retrieves the head {@link Parse constituent} for the specified constituents of given {@code type}. * * @param constituents The {@link Parse constituents} which make up a constituent of the * specified {@code type}. * @param type The type of a constituent which is made up of the {@code constituents}. * @return The {@link Parse constituent} which represents the head. */ Parse getHead(Parse[] constituents, String type); /** * @return Retrieves the set of punctuation tags. * Attachment decisions for these tags will not be modeled. */ Set getPunctuationTags(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/Parse.java0100644 0000000 0000000 00000103607 15217274217 031127 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.Stack; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.Span; /** * Data structure for holding parse constituents. */ public class Parse implements Cloneable, Comparable { private static final Logger logger = LoggerFactory.getLogger(Parse.class); public static final String BRACKET_LRB = "("; public static final String BRACKET_RRB = ")"; public static final String BRACKET_LCB = "{"; public static final String BRACKET_RCB = "}"; public static final String BRACKET_LSB = "["; public static final String BRACKET_RSB = "]"; /** * The text string on which this parse is based. * This object is shared among all parses for the same sentence. */ private final String text; /** * The character offsets into the text for this constituent. */ private Span span; /** * The syntactic type of this parse. */ private String type; /** * The sub-constituents of this parse. */ private List parts; /** * The head parse of this parse. A parse can be its own head. */ private Parse head; /** * A string used during parse construction to specify which * stage of parsing has been performed on this node. */ private String label; /** * Index in the sentence of the head of this constituent. */ private int headIndex; /** * The parent parse of this parse. */ private Parse parent; /** * The probability associated with the syntactic type * assigned to this parse. */ private double prob; /** * The string buffer used to track the derivation of this parse. */ private StringBuffer derivation; /** * Specifies whether this constituent was built during the chunking phase. */ private boolean isChunk; /** * The pattern used to find the base constituent label of a * Penn Treebank labeled constituent. */ private static final Pattern typePattern = Pattern.compile("^([^ =-]+)"); /** * The pattern used to find the function tags. */ private static final Pattern funTypePattern = Pattern.compile("^[^ =-]+-([^ =-]+)"); /** * The patter used to identify tokens in Penn Treebank labeled constituents. */ private static final Pattern tokenPattern = Pattern.compile("^[^ ()]+ ([^ ()]+)\\s*\\)"); /** * The set of punctuation parses which are between this parse and the previous parse. */ private Collection prevPunctSet; /** * The set of punctuation parses which are between this parse and * the subsequent parse. */ private Collection nextPunctSet; /** * Specifies whether constituent labels should include parts specified * after minus character. */ private static boolean useFunctionTags; /** * Initializes a {@link Parse node} for this specified {@code text} and {@code span} of the * specified {@code type} with probability {@code p} and the head {@code index}. * * @param text The text of the sentence for which this node is a part of. * @param span The {@link Span character offsets} for this node within the specified {@code text}. * @param type The constituent label of this node. * @param p The probability of this {@link Parse}. * @param index The token index of the head of this parse. */ public Parse(String text, Span span, String type, double p, int index) { this.text = text; this.span = span; this.type = type; this.prob = p; this.head = this; this.headIndex = index; this.parts = new LinkedList<>(); this.label = null; this.parent = null; } /** * Initializes a {@link Parse node} for this specified {@code text} and {@code span} of the * specified {@code type} with probability {@code p} and the head {@code index}. * * @param text The text of the sentence for which this node is a part of. * @param span The {@link Span character offsets} for this node within the specified {@code text}. * @param type The constituent label of this node. * @param p The probability of this parse. * @param h The head token of this parse. */ public Parse(String text, Span span, String type, double p, Parse h) { this(text, span, type, p, 0); if (h != null) { this.head = h; this.headIndex = h.headIndex; } } @Override public Object clone() { Parse p = new Parse(this.text, this.span, this.type, this.prob, this.head); p.parts = new LinkedList<>(); p.parts.addAll(this.parts); if (derivation != null) { p.derivation = new StringBuffer(100); p.derivation.append(this.derivation); } p.label = this.label; return (p); } /** * Clones the right frontier of {@link Parse} up to the specified {@code node}. * * @param node The last {@code node} in the right frontier of the parse tree to be cloned. * @return A clone of this parse and its right frontier up to and including the specified node. */ public Parse clone(Parse node) { if (this == node) { return (Parse) this.clone(); } else { Parse c = (Parse) this.clone(); Parse lc = c.parts.get(parts.size() - 1); c.parts.set(parts.size() - 1, lc.clone(node)); return c; } } /** * Clones the right frontier of this root {@link Parse} up to and including the specified node. * * @param node The last {@code node} in the right frontier of the parse tree to be cloned. * @param parseIndex The child index of the parse for this root {@code node}. * @return A clone of this root parse and its right frontier up to and including the specified node. */ public Parse cloneRoot(Parse node, int parseIndex) { Parse c = (Parse) this.clone(); Parse fc = c.parts.get(parseIndex); c.parts.set(parseIndex, fc.clone(node)); return c; } /** * Specifies whether function tags should be included as part of the constituent type. * * @param uft {@code true} is they should be included, {@code false} otherwise. */ public static void useFunctionTags(boolean uft) { useFunctionTags = uft; } /** * Set the type of this constituent to the specified type. * * @param type The type of this constituent. */ public void setType(String type) { this.type = type; } /** * @return Retrieves the constituent label for this node of the parse. */ public String getType() { return type; } /** * @return Retrieves the set of punctuation {@link Parse parses} that occur * immediately before this parse. */ public Collection getPreviousPunctuationSet() { return prevPunctSet; } /** * Designates that the specified punctuation should is prior to this parse. * * @param punct The {@link Parse punctuation} to be added. */ public void addPreviousPunctuation(Parse punct) { if (this.prevPunctSet == null) { this.prevPunctSet = new TreeSet<>(); } prevPunctSet.add(punct); } /** * @return Retrieves the set of punctuation {@link Parse parses} that occur * immediately after this parse. */ public Collection getNextPunctuationSet() { return nextPunctSet; } /** * Designates that the specified punctuation follows this parse. * * @param punct The {@link Parse punctuation} set. */ public void addNextPunctuation(Parse punct) { if (this.nextPunctSet == null) { this.nextPunctSet = new TreeSet<>(); } nextPunctSet.add(punct); } /** * Sets the {@link Parse punctuation tags} which follow this parse. * * @param punctSet The punctuation tags which follow this parse. */ public void setNextPunctuation(Collection punctSet) { this.nextPunctSet = punctSet; } /** * Sets the {@link Parse punctuation tags} which precede this parse. * * @param punctSet The punctuation tags which precede this parse. */ public void setPrevPunctuation(Collection punctSet) { this.prevPunctSet = punctSet; } /** * Inserts the specified constituent into this parse based on its text span. * This method assumes that the specified constituent can be inserted into this parse. * * @param constituent The {@link Parse constituent} to be inserted. */ public void insert(final Parse constituent) { Span ic = constituent.span; if (span.contains(ic)) { //double oprob=c.prob; int pi = 0; int pn = parts.size(); for (; pi < pn; pi++) { Parse subPart = parts.get(pi); if (logger.isTraceEnabled()) { logger.trace("Parse.insert:con={} sp[{}] {} {}", constituent, pi, subPart, subPart.getType()); } Span sp = subPart.span; if (sp.getStart() >= ic.getEnd()) { break; } // constituent contains subPart else if (ic.contains(sp)) { if (logger.isTraceEnabled()) { logger.trace("Parse.insert:con contains subPart"); } parts.remove(pi); pi--; constituent.parts.add(subPart); subPart.setParent(constituent); if (logger.isTraceEnabled()) { logger.trace("Parse.insert: {} -> {}", subPart.hashCode(), subPart.getParent().hashCode()); } pn = parts.size(); } else if (sp.contains(ic)) { if (logger.isTraceEnabled()) { logger.trace("Parse.insert:subPart contains con"); } subPart.insert(constituent); return; } } if (logger.isTraceEnabled()) { logger.trace("Parse.insert:adding con={} to {}", constituent, this); } parts.add(pi, constituent); constituent.setParent(this); // System.err.println("Parse.insert: "+constituent.hashCode()+" -> " // +constituent.getParent().hashCode()); } else { throw new IllegalArgumentException("Inserting constituent not contained in the sentence!"); } } /** * Fills the specified {@link StringBuffer} with a string representation of this parse. * * @param sb A {@link StringBuffer} into which the parse string can be appended. */ public void show(StringBuffer sb) { int start; start = span.getStart(); if (!type.equals(AbstractBottomUpParser.TOK_NODE)) { sb.append("("); sb.append(type).append(" "); if (logger.isTraceEnabled()) { logger.trace("{} ", label); } if (logger.isTraceEnabled()) { logger.trace("{} ", head); } if (logger.isTraceEnabled()) { logger.trace("{} ", prob); } } for (Parse c : parts) { Span s = c.span; if (start < s.getStart()) { if (logger.isTraceEnabled()) { logger.trace("pre {} {}", start, s.getStart()); } sb.append(encodeToken(text.substring(start, s.getStart()))); } c.show(sb); start = s.getEnd(); } if (start < span.getEnd()) { sb.append(encodeToken(text.substring(start, span.getEnd()))); } if (!type.equals(AbstractBottomUpParser.TOK_NODE)) { sb.append(")"); } } /** * Prints this parse using Penn Treebank-style formatting. */ public void show() { StringBuffer sb = new StringBuffer(text.length() * 4); show(sb); logger.debug(sb.toString()); } /** * @return Retrieves the probability associated with the pos-tag sequence assigned * to this parse. */ public double getTagSequenceProb() { if (logger.isTraceEnabled()) { logger.trace("Parse.getTagSequenceProb: {} {}",type, this); } if (parts.size() == 1 && (parts.get(0)).type.equals(AbstractBottomUpParser.TOK_NODE)) { if (logger.isTraceEnabled()) { logger.trace("{} {}", this, prob); } return (StrictMath.log(prob)); } else if (parts.size() == 0) { logger.warn("Parse.getTagSequenceProb: Wrong base case!"); return (0.0); } else { double sum = 0.0; for (Parse part : parts) { sum += part.getTagSequenceProb(); } return sum; } } /** * @return {@code true} if the parse contains a single top-most node (=complete), * {@code false} otherwise. */ public boolean complete() { return (parts.size() == 1); } public String getCoveredText() { return text.substring(span.getStart(), span.getEnd()); } /** * @return Retrieves a String representation using Penn Treebank-style formatting. */ public String toStringPennTreebank() { StringBuffer buffer = new StringBuffer(); show(buffer); return buffer.toString(); } /** * Represents this {@link Parse} in a human-readable way. */ @Override public String toString() { // TODO: Use the commented code in next bigger release, // change probably breaks backward compatibility in some // applications //StringBuffer buffer = new StringBuffer(); //show(buffer); //return buffer.toString(); return getCoveredText(); } /** * @return Retrieves the text of the sentence over which this parse was formed. */ public String getText() { return text; } /** * @return Retrieves the {@link Span character offsets} for this constituent. */ public Span getSpan() { return span; } /** * @return Retrieves the {@code log} of the product of the probability associated with all the * decisions which formed this constituent. */ public double getProb() { return prob; } /** * Adds the specified {@code logProb} to this current log for this parse. * * @param logProb The probability of an action performed on this parse. */ public void addProb(double logProb) { this.prob += logProb; } /** * @return Retrieves the {@link Parse child constituents} of this constituent. */ public Parse[] getChildren() { return parts.toArray(new Parse[0]); } /** * Replaces the child at the specified index with a new child with the specified label. * * @param index The index of the child to be replaced. * @param label The label to be assigned to the new child. */ public void setChild(int index, String label) { Parse newChild = (Parse) (parts.get(index)).clone(); newChild.setLabel(label); parts.set(index, newChild); } public void add(Parse daughter, HeadRules rules) { if (daughter.prevPunctSet != null) { parts.addAll(daughter.prevPunctSet); } parts.add(daughter); this.span = new Span(span.getStart(), daughter.getSpan().getEnd()); this.head = rules.getHead(getChildren(), type); this.headIndex = head.headIndex; } public void remove(int index) { parts.remove(index); if (!parts.isEmpty()) { if (index == 0 || index == parts.size()) { //size is orig last element span = new Span((parts.get(0)).span.getStart(), (parts.get(parts.size() - 1)).span.getEnd()); } } } public Parse adjoinRoot(Parse node, HeadRules rules, int parseIndex) { Parse lastChild = parts.get(parseIndex); Parse adjNode = new Parse(this.text, new Span(lastChild.getSpan().getStart(), node.getSpan().getEnd()), lastChild.getType(), 1, rules.getHead(new Parse[] {lastChild, node}, lastChild.getType())); adjNode.parts.add(lastChild); if (node.prevPunctSet != null) { adjNode.parts.addAll(node.prevPunctSet); } adjNode.parts.add(node); parts.set(parseIndex, adjNode); return adjNode; } /** * Sister adjoins this node's last child and the specified sister node and returns their * new parent node. The new parent node replace this node's last child. * * @param sister The {@link Parse node} to be adjoined. * @param rules The {@link HeadRules} for the parser. * @return The new {@link Parse parent node} of this node and the specified sister node. */ public Parse adjoin(Parse sister, HeadRules rules) { Parse lastChild = parts.get(parts.size() - 1); Parse adjNode = new Parse(this.text, new Span(lastChild.getSpan().getStart(), sister.getSpan().getEnd()), lastChild.getType(), 1, rules.getHead(new Parse[] {lastChild, sister}, lastChild.getType())); adjNode.parts.add(lastChild); if (sister.prevPunctSet != null) { adjNode.parts.addAll(sister.prevPunctSet); } adjNode.parts.add(sister); parts.set(parts.size() - 1, adjNode); this.span = new Span(span.getStart(), sister.getSpan().getEnd()); this.head = rules.getHead(getChildren(), type); this.headIndex = head.headIndex; return adjNode; } public void expandTopNode(Parse root) { boolean beforeRoot = true; if (logger.isTraceEnabled()) { logger.trace("expandTopNode: parts={}", parts); } for (int pi = 0, ai = 0; pi < parts.size(); pi++, ai++) { Parse node = parts.get(pi); if (node == root) { beforeRoot = false; } else if (beforeRoot) { root.parts.add(ai, node); parts.remove(pi); pi--; } else { root.parts.add(node); parts.remove(pi); pi--; } } root.updateSpan(); } /** * @return Retrieves the number of children for this parse node. */ public int getChildCount() { return parts.size(); } /** * @param child A child of this parse. * @return Retrieves the index of this specified child or {@code -1} * if the specified child is not a child of this parse. */ public int indexOf(Parse child) { return parts.indexOf(child); } /** * @return Retrieves the head constituent associated with this constituent. */ public Parse getHead() { return head; } /** * @return Retrieves the index within a sentence of the head token for this parse. */ public int getHeadIndex() { return headIndex; } /** * Retrieves the label assigned to this parse node during parsing * which specifies how this node will be formed into a constituent. * * @return The outcome label assigned to this node during parsing. */ public String getLabel() { return label; } /** * Assigns this parse the specified label. This is used by parsing schemes to * tag parsing nodes while building. * * @param label A label indicating something about the stage of building for this parse node. */ public void setLabel(String label) { this.label = label; } private static String getType(String rest) { if (rest.startsWith("-LCB-")) { return "-LCB-"; } else if (rest.startsWith("-RCB-")) { return "-RCB-"; } else if (rest.startsWith("-LRB-")) { return "-LRB-"; } else if (rest.startsWith("-RRB-")) { return "-RRB-"; } else if (rest.startsWith("-RSB-")) { return "-RSB-"; } else if (rest.startsWith("-LSB-")) { return "-LSB-"; } else if (rest.startsWith("-NONE-")) { return "-NONE-"; } else { Matcher typeMatcher = typePattern.matcher(rest); if (typeMatcher.find()) { String type = typeMatcher.group(1); if (useFunctionTags) { Matcher funMatcher = funTypePattern.matcher(rest); if (funMatcher.find()) { String ftag = funMatcher.group(1); type = type + "-" + ftag; } } return type; } } return null; } private static String encodeToken(String token) { if (BRACKET_LRB.equals(token)) { return "-LRB-"; } else if (BRACKET_RRB.equals(token)) { return "-RRB-"; } else if (BRACKET_LCB.equals(token)) { return "-LCB-"; } else if (BRACKET_RCB.equals(token)) { return "-RCB-"; } else if (BRACKET_LSB.equals(token)) { return "-LSB-"; } else if (BRACKET_RSB.equals(token)) { return "-RSB-"; } return token; } private static String decodeToken(String token) { if ("-LRB-".equals(token)) { return BRACKET_LRB; } else if ("-RRB-".equals(token)) { return BRACKET_RRB; } else if ("-LCB-".equals(token)) { return BRACKET_LCB; } else if ("-RCB-".equals(token)) { return BRACKET_RCB; } else if ("-LSB-".equals(token)) { return BRACKET_LSB; } else if ("-RSB-".equals(token)) { return BRACKET_RSB; } return token; } /** * @param rest The portion of the parse string remaining to be processed. * @return Retrieves the string containing the token for the specified portion of the parse * string or {@code null} if the portion of the parse string does not represent a token. */ private static String getToken(String rest) { Matcher tokenMatcher = tokenPattern.matcher(rest); if (tokenMatcher.find()) { return decodeToken(tokenMatcher.group(1)); } return null; } /** * Computes the head parses for this parse and its sub-parses and stores this information * in the parse data structure. * * @param rules The {@link HeadRules} which determine how the head of the parse is computed. */ public void updateHeads(HeadRules rules) { if (parts != null && parts.size() != 0) { for (Parse c : parts) { c.updateHeads(rules); } this.head = rules.getHead(parts.toArray(new Parse[0]), type); if (head == null) { head = this; } else { this.headIndex = head.headIndex; } } else { this.head = this; } } public void updateSpan() { span = new Span((parts.get(0)).span.getStart(), (parts.get(parts.size() - 1)).span.getEnd()); } /** * Prune the specified sentence parse of vacuous productions. * * @param parse The sentence {@link Parse}. */ public static void pruneParse(Parse parse) { List nodes = new LinkedList<>(); nodes.add(parse); while (nodes.size() != 0) { Parse node = nodes.remove(0); Parse[] children = node.getChildren(); if (children.length == 1 && node.getType().equals(children[0].getType())) { int index = node.getParent().parts.indexOf(node); children[0].setParent(node.getParent()); node.getParent().parts.set(index, children[0]); node.parent = null; node.parts = null; } nodes.addAll(Arrays.asList(children)); } } public static void fixPossesives(Parse parse) { Parse[] tags = parse.getTagNodes(); for (int ti = 0; ti < tags.length; ti++) { if (tags[ti].getType().equals("POS")) { if (ti + 1 < tags.length && tags[ti + 1].getParent() == tags[ti].getParent().getParent()) { int start = tags[ti + 1].getSpan().getStart(); int end = tags[ti + 1].getSpan().getEnd(); for (int npi = ti + 2; npi < tags.length; npi++) { if (tags[npi].getParent() == tags[npi - 1].getParent()) { end = tags[npi].getSpan().getEnd(); } else { break; } } Parse npPos = new Parse(parse.getText(), new Span(start, end), "NP", 1, tags[ti + 1]); parse.insert(npPos); } } } } /** * Creates a {@link Parse} structure from an array of * pre-tokenized strings. *

* This is a convenience factory method for cases * where the input sentence is already tokenized * (e.g., as a {@code String[]}). It joins the * tokens with whitespace, computes character offset * {@link Span spans} for each token, and builds the * initial flat parse tree expected by * {@link Parser#parse(Parse)}. * * @param tokens The tokens of the sentence. * @return A flat {@link Parse} structure with token * nodes ready for a {@link Parser}. * @throws IllegalArgumentException if {@code tokens} * is {@code null} or empty. */ public static Parse createFromTokens(final String[] tokens) { if (tokens == null) { throw new IllegalArgumentException("tokens must not be null"); } if (tokens.length == 0) { throw new IllegalArgumentException("tokens must not be empty"); } String text = String.join(" ", tokens); final Parse p = new Parse(text, new Span(0, text.length()), AbstractBottomUpParser.INC_NODE, 0, 0); int start = 0; for (int i = 0; i < tokens.length; i++) { p.insert(new Parse(text, new Span(start, start + tokens[i].length()), AbstractBottomUpParser.TOK_NODE, 0, i)); start += tokens[i].length() + 1; } return p; } /** * Parses the specified tree-bank style parse string and return a {@link Parse} structure * for that string. * * @param parse A tree-bank style {@link Parse} string. * @return A {@link Parse} structure for the specified tree-bank style parse string. */ public static Parse parseParse(String parse) { return parseParse(parse, null); } /** * Parses the specified tree-bank style {@link Parse} string and return a {@link Parse} structure * for that string. * * @param parse A tree-bank style {@link Parse} string. * @param gl The {@link GapLabeler} to be used. * @return A {@link Parse} structure for the specified tree-bank style parse string. */ public static Parse parseParse(String parse, GapLabeler gl) { StringBuilder text = new StringBuilder(); int offset = 0; Stack stack = new Stack<>(); List cons = new LinkedList<>(); for (int ci = 0, cl = parse.length(); ci < cl; ci++) { char c = parse.charAt(ci); if (c == '(') { String rest = parse.substring(ci + 1); String type = getType(rest); if (type == null) { logger.warn("null type for: {}", rest); } String token = getToken(rest); stack.push(new Constituent(type, new Span(offset, offset))); if (token != null) { if (Objects.equals(type, "-NONE-") && gl != null) { if (logger.isTraceEnabled()) { logger.trace("stack.size={}", stack.size()); } gl.labelGaps(stack); } else { cons.add(new Constituent(AbstractBottomUpParser.TOK_NODE, new Span(offset, offset + token.length()))); text.append(token).append(" "); offset += token.length() + 1; } } } else if (c == ')') { Constituent con = stack.pop(); int start = con.getSpan().getStart(); if (start < offset) { cons.add(new Constituent(con.getLabel(), new Span(start, offset - 1))); } } } String txt = text.toString(); int tokenIndex = -1; Parse p = new Parse(txt, new Span(0, txt.length()), AbstractBottomUpParser.TOP_NODE, 1, 0); for (Constituent con : cons) { String type = con.getLabel(); if (!type.equals(AbstractBottomUpParser.TOP_NODE)) { if (AbstractBottomUpParser.TOK_NODE.equals(type)) { tokenIndex++; } Parse c = new Parse(txt, con.getSpan(), type, 1, tokenIndex); if (logger.isTraceEnabled()) { logger.trace("insert[{}] {} {} {}", tokenIndex, type, c, c.hashCode()); } p.insert(c); //codeTree(p); } } return p; } /** * @return Retrieves the parent parse node of this constituent. */ public Parse getParent() { return parent; } /** * Specifies the parent parse node for this constituent. * * @param parent The parent parse node for this constituent. */ public void setParent(Parse parent) { this.parent = parent; } /** * Indicates whether this parse node is a pos-tag. * * @return {@code true} if this node is a pos-tag, {@code false} otherwise. */ public boolean isPosTag() { return (parts.size() == 1 && (parts.get(0)).getType().equals(AbstractBottomUpParser.TOK_NODE)); } /** * Indicates whether this parse node contains no sub-constituents. * * @return {@code true} if this constituent contains no sub-constituents; {@code false} otherwise. */ public boolean isFlat() { boolean flat = true; for (Parse part : parts) { flat &= part.isPosTag(); } return flat; } public void isChunk(boolean ic) { this.isChunk = ic; } public boolean isChunk() { return isChunk; } /** * @return Retrieves the parse nodes which are children of this node and which are pos tags. */ public Parse[] getTagNodes() { List tags = new LinkedList<>(); List nodes = new LinkedList<>(this.parts); while (nodes.size() != 0) { Parse p = nodes.remove(0); if (p.isPosTag()) { tags.add(p); } else { nodes.addAll(0, p.parts); } } return tags.toArray(new Parse[0]); } public Parse[] getTokenNodes() { List tokens = new LinkedList<>(); List nodes = new LinkedList<>(this.parts); while (nodes.size() != 0) { Parse p = nodes.remove(0); if (p.getType().equals(AbstractBottomUpParser.TOK_NODE)) { tokens.add(p); } else { nodes.addAll(0, p.parts); } } return tokens.toArray(new Parse[0]); } /** * Returns the deepest shared parent of this node and the specified node. * If the nodes are identical then their parent is returned. * If one node is the parent of the other than the parent node is returned. * * @param node The node from which parents are compared to this node's parents. * @return the deepest shared parent of this node and the specified node. */ public Parse getCommonParent(Parse node) { if (this == node) { return parent; } Set parents = new HashSet<>(); Parse cparent = this; while (cparent != null) { parents.add(cparent); cparent = cparent.getParent(); } while (node != null) { if (parents.contains(node)) { return node; } node = node.getParent(); } return null; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Parse p) { return Objects.equals(label, p.label) && span.equals(p.span) && text.equals(p.text) && parts.equals(p.parts); } return false; } @Override public int hashCode() { // Note: label is missing here! return Objects.hash(span, text); } public int compareTo(Parse p) { return Double.compare(p.getProb(), this.getProb()); } /** * @return Retrieves the derivation string for this parse or {@code null} * if no derivation string has been created. */ public StringBuffer getDerivation() { return derivation; } /** * Specifies the derivation string to be associated with this parse. * * @param derivation The derivation string to be associated with this parse. */ public void setDerivation(StringBuffer derivation) { this.derivation = derivation; } private void codeTree(Parse p, int[] levels) { Parse[] kids = p.getChildren(); StringBuilder levelsBuff = new StringBuilder(); levelsBuff.append("["); int[] nlevels = new int[levels.length + 1]; for (int li = 0; li < levels.length; li++) { nlevels[li] = levels[li]; levelsBuff.append(levels[li]).append("."); } for (int ki = 0; ki < kids.length; ki++) { nlevels[levels.length] = ki; logger.info(levelsBuff.toString() + ki + "] " + kids[ki].getType() + " " + kids[ki].hashCode() + " -> " + kids[ki].getParent().hashCode() + " " + kids[ki].getParent().getType() + " " + kids[ki].getCoveredText()); codeTree(kids[ki], nlevels); } } /** * Prints to standard out a representation of the specified parse which * contains hash codes so that parent/child relationships can be explicitly seen. */ public void showCodeTree() { codeTree(this, new int[0]); } /** * Utility method to insert named entities. * * @param tag A token representing a tag. * @param names An array of {@link Span names}. * @param tokens An array of {@link Parse tokens}. */ public static void addNames(String tag, Span[] names, Parse[] tokens) { for (Span nameTokenSpan : names) { Parse startToken = tokens[nameTokenSpan.getStart()]; Parse endToken = tokens[nameTokenSpan.getEnd() - 1]; Parse commonParent = startToken.getCommonParent(endToken); if (logger.isTraceEnabled()) { logger.trace("addNames: {} .. {} commonParent = {}", startToken, endToken, commonParent); } if (commonParent != null) { Span nameSpan = new Span(startToken.getSpan().getStart(), endToken.getSpan().getEnd()); if (nameSpan.equals(commonParent.getSpan())) { commonParent.insert(new Parse(commonParent.getText(), nameSpan, tag, 1.0, endToken.getHeadIndex())); } else { Parse[] kids = commonParent.getChildren(); boolean crossingKids = false; for (Parse kid : kids) { if (nameSpan.crosses(kid.getSpan())) { crossingKids = true; } } if (!crossingKids) { commonParent.insert(new Parse(commonParent.getText(), nameSpan, tag, 1.0, endToken.getHeadIndex())); } else { if (commonParent.getType().equals("NP")) { Parse[] grandKids = kids[0].getChildren(); if (grandKids.length > 1 && nameSpan.contains(grandKids[grandKids.length - 1].getSpan())) { commonParent.insert(new Parse(commonParent.getText(), commonParent.getSpan(), tag, 1.0, commonParent.getHeadIndex())); } } } } } } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParseSampleStream.java0100644 0000000 0000000 00000003061 15217274217 033436 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.io.IOException; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * @see Parse * @see FilterObjectStream */ public class ParseSampleStream extends FilterObjectStream { /** * Initializes a {@link ParseSampleStream instance}. * * @param in A plain text {@link ObjectStream stream} used as input. */ public ParseSampleStream(ObjectStream in) { super(in); } @Override public Parse read() throws IOException { String parse = samples.read(); if (parse != null) { if (!parse.trim().isEmpty()) { return Parse.parseParse(parse); } else { return read(); } } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/Parser.java0100644 0000000 0000000 00000004012 15217274217 031277 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; /** * Defines common methods for full-syntactic parsers. */ public interface Parser { /** * Returns the specified number of parses or fewer for the specified tokens. *

* * Note: The nodes within * the returned parses are shared with other parses and therefore their parent node references * will not be consistent with their child node reference. *

* * {@link Parse#setParent(Parse)} can be used to make the parents consistent with a * particular parse, but subsequent calls to setParents can invalidate the * results of earlier calls.
* * @param tokens A {@link Parse} containing the tokens with a single parent node. * @param numParses The number of parses desired. * @return the specified number of {@link Parse parses} for the specified {@code tokens}. */ Parse[] parse(Parse tokens, int numParses); /** * Returns a {@link Parse} for the specified {@link Parse} of {@code tokens}. * * @param tokens The root node of a flat parse containing only tokens. * @return A full parse of the specified tokens or the flat chunks of the tokens if a * full parse could not be found. */ Parse parse(Parse tokens); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_ParserChu0100644 0000000 0000000 00000000156 15217274217 032513 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserChunkerFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserChunkerFactory.java0100644 0000000 0000000 00000003201 15217274217 034146 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import opennlp.tools.chunker.ChunkerContextGenerator; import opennlp.tools.chunker.ChunkerFactory; import opennlp.tools.chunker.ChunkerME; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.TokenTag; public class ParserChunkerFactory extends ChunkerFactory { @Override public ChunkerContextGenerator getContextGenerator() { return new ChunkContextGenerator(ChunkerME.DEFAULT_BEAM_SIZE); } @Override public SequenceValidator getSequenceValidator() { MaxentModel model = artifactProvider.getArtifact("chunker.model"); String[] outcomes = new String[model.getNumOutcomes()]; for (int i = 0; i < outcomes.length; i++) { outcomes[i] = model.getOutcome(i); } return new ParserChunkerSequenceValidator(outcomes); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_ParserChu0100644 0000000 0000000 00000000170 15217274217 032507 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserChunkerSequenceValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserChunkerSequenceVali0100644 0000000 0000000 00000004557 15217274217 034222 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.HashMap; import java.util.Map; import opennlp.tools.parser.chunking.Parser; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.TokenTag; /** * The parser chunker {@link SequenceValidator} implementation. */ public class ParserChunkerSequenceValidator implements SequenceValidator { private final Map continueStartMap; public ParserChunkerSequenceValidator(String[] outcomes) { continueStartMap = new HashMap<>(outcomes.length); for (String outcome : outcomes) { if (outcome.startsWith(Parser.CONT)) { continueStartMap.put(outcome, Parser.START + outcome.substring( Parser.CONT.length())); } } } public boolean validSequence(int i, String[] inputSequence, String[] tagList, String outcome) { if (continueStartMap.containsKey(outcome)) { int lti = tagList.length - 1; if (lti == -1) { return false; } else { String lastTag = tagList[lti]; if (lastTag.equals(outcome)) { return true; } if (lastTag.equals(continueStartMap.get(outcome))) { return true; } if (lastTag.equals(Parser.OTHER)) { return false; } return false; } } return true; } @Override public boolean validSequence(int i, TokenTag[] inputTuples, String[] outcomesSequence, String outcome) { String[] inputSequence = TokenTag.extractTokens(inputTuples); return validSequence(i, inputSequence, outcomesSequence, outcome); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_ParserCro0100644 0000000 0000000 00000000156 15217274217 032517 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserCrossValidator.java0100644 0000000 0000000 00000007133 15217274217 034166 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.io.IOException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.FMeasure; /** * Cross validator for a {@link Parser}. */ public class ParserCrossValidator { private final String languageCode; private final TrainingParameters params; private final HeadRules rules; private final FMeasure fmeasure = new FMeasure(); private final ParserType parserType; private final ParserEvaluationMonitor[] monitors; /** * Initializes a {@link ParserCrossValidator} instance via given parameters. * * @param languageCode An ISO conform language code. * @param params The {@link TrainingParameters} for the context of cross validation. * @param rules The {@link HeadRules} for the context of cross validation. * @param parserType The {@link ParserType} for the context of cross validation. * @param monitors the {@link ParserEvaluationMonitor evaluation listeners}. */ public ParserCrossValidator(String languageCode, TrainingParameters params, HeadRules rules, ParserType parserType, ParserEvaluationMonitor... monitors) { this.languageCode = languageCode; this.params = params; this.rules = rules; this.parserType = parserType; this.monitors = monitors; } /** * Starts the evaluation. * * @param samples The {@link ObjectStream} of {@link Parse samples} to train and test with. * @param nFolds Number of folds. It must be greater than zero. * * @throws IOException Thrown if IO errors occurred. * @throws IllegalStateException Thrown if the currently active {@link ParserType} is not supported. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>(samples, nFolds); while (partitioner.hasNext()) { try (CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner.next()) { ParserModel model; if (ParserType.CHUNKING.equals(parserType)) { model = opennlp.tools.parser.chunking.Parser.train(languageCode, samples, rules, params); } else if (ParserType.TREEINSERT.equals(parserType)) { model = opennlp.tools.parser.treeinsert.Parser.train(languageCode, samples, rules, params); } else { throw new IllegalStateException("Unexpected parser type: " + parserType); } ParserEvaluator evaluator = new ParserEvaluator(ParserFactory.create(model), monitors); evaluator.evaluate(trainingSampleStream.getTestSampleStream()); fmeasure.mergeInto(evaluator.getFMeasure()); } } } public FMeasure getFMeasure() { return fmeasure; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_ParserEva0100644 0000000 0000000 00000000161 15217274217 032503 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserEvaluationMonitor.j0100644 0000000 0000000 00000002007 15217274217 034211 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link Parser parsers}. */ public interface ParserEvaluationMonitor extends EvaluationMonitor { } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserEvaluator.java0100644 0000000 0000000 00000007315 15217274217 033173 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.util.ArrayList; import java.util.List; import java.util.Stack; import opennlp.tools.cmdline.parser.ParserTool; import opennlp.tools.util.Span; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.FMeasure; /** * This implementation of {@link Evaluator} behaves like {@code EVALB} with no exceptions, * e.g, without removing punctuation tags, or equality between {@code ADVP} and {@code PRT}, as * in * COLLINS convention. *

* To follow parsing evaluation conventions (Bikel, Collins, Charniak, etc.) as in {@code EVALB}, * options are to be added to the {@code ParserEvaluatorTool}. * * @see Parser * @see Evaluator * @see Parse */ public class ParserEvaluator extends Evaluator { /* * Holds the evaluation results for the last run of {@link #processSample}. */ private final FMeasure fmeasure = new FMeasure(); /* * The parser to evaluate. */ private final Parser parser; /** * Initializes a {@link ParserEvaluator} instance with the given {@link Parser}. * * @param aParser The {@link Parser} to evaluate. * @param monitors The {@link ParserEvaluationMonitor evaluation listeners}. */ public ParserEvaluator(final Parser aParser, final ParserEvaluationMonitor... monitors) { super(monitors); this.parser = aParser; } /** * Obtains {@link Span spans} for every parse in a sentence. * * @param parse The parse from which to obtain {@link Span spans}. * * @return An array of {@link Span spans} for the parse */ private static Span[] getConstituencySpans(final Parse parse) { Stack stack = new Stack<>(); if (parse.getChildCount() > 0) { for (Parse child : parse.getChildren()) { stack.push(child); } } List consts = new ArrayList<>(); while (!stack.isEmpty()) { Parse constSpan = stack.pop(); if (!constSpan.isPosTag()) { Span span = constSpan.getSpan(); consts.add(new Span(span.getStart(), span.getEnd(), constSpan.getType())); for (Parse child : constSpan.getChildren()) { stack.push(child); } } } return consts.toArray(new Span[0]); } @Override protected final Parse processSample(final Parse reference) { List tokens = new ArrayList<>(); for (Parse token : reference.getTokenNodes()) { tokens.add(token.getSpan().getCoveredText(reference.getText()).toString()); } Parse[] predictions = ParserTool.parseLine(String.join(" ", tokens), parser, 1); Parse prediction = null; if (predictions.length > 0) { prediction = predictions[0]; fmeasure.updateScores(getConstituencySpans(reference), getConstituencySpans(prediction)); } return prediction; } public final FMeasure getFMeasure() { return fmeasure; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserEventTypeEnum.java0100644 0000000 0000000 00000002046 15217274217 033775 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; /** * Enumeration of event types for a {@link Parser}. */ public enum ParserEventTypeEnum { BUILD, CHECK, // TODO Add reason why those enum values are deprecated @Deprecated CHUNK, @Deprecated TAG, ATTACH } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserFactory.java0100644 0000000 0000000 00000005215 15217274217 032635 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; public class ParserFactory { private ParserFactory() { } /** * Instantiates a {@link Parser} via a given {@code model} and * other configuration parameters. * * @param model The {@link ParserModel} to use. * @param beamSize The number of different parses kept during parsing. * @param advancePercentage The minimal amount of probability mass which advanced outcomes * must represent. Only outcomes which contribute to the top * {@code advancePercentage} will be explored. * * @return A valid {@link Parser} instance. * @throws IllegalStateException Thrown if the {@link ParserType} is not supported. * * @see Parser * @see ParserModel */ public static Parser create(ParserModel model, int beamSize, double advancePercentage) { if (ParserType.CHUNKING.equals(model.getParserType())) { return new opennlp.tools.parser.chunking.Parser(model, beamSize, advancePercentage); } else if (ParserType.TREEINSERT.equals(model.getParserType())) { return new opennlp.tools.parser.treeinsert.Parser(model, beamSize, advancePercentage); } else { throw new IllegalStateException("Unexpected ParserType: " + model.getParserType().name()); } } /** * Instantiates a {@link Parser} via a given {@code model} and * default configuration parameters (see: {@link AbstractBottomUpParser}). * * @param model The {@link ParserModel} to use. * * @return A valid {@link Parser} instance. * @throws IllegalStateException Thrown if the {@link ParserType} is not supported. * * @see Parser * @see AbstractBottomUpParser */ public static Parser create(ParserModel model) { return create(model, AbstractBottomUpParser.defaultBeamSize, AbstractBottomUpParser.defaultAdvancePercentage); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserModel.java0100644 0000000 0000000 00000034607 15217274217 032275 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Serial; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Map; import java.util.Objects; import opennlp.tools.chunker.ChunkerModel; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.postag.POSModel; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.BaseModel; import opennlp.tools.util.model.ChunkerModelSerializer; import opennlp.tools.util.model.POSModelSerializer; /** * This is the default {@link ParserModel} implementation. */ public class ParserModel extends BaseModel { @Serial private static final long serialVersionUID = 8130378166122870498L; private static class HeadRulesSerializer implements ArtifactSerializer { public opennlp.tools.parser.lang.en.HeadRules create(InputStream in) throws IOException { return new opennlp.tools.parser.lang.en.HeadRules(new BufferedReader( new InputStreamReader(in, StandardCharsets.UTF_8))); } public void serialize(opennlp.tools.parser.lang.en.HeadRules artifact, OutputStream out) throws IOException { artifact.serialize(new OutputStreamWriter(out, StandardCharsets.UTF_8)); } } private static final String COMPONENT_NAME = "Parser"; private static final String BUILD_MODEL_ENTRY_NAME = "build.model"; private static final String CHECK_MODEL_ENTRY_NAME = "check.model"; private static final String ATTACH_MODEL_ENTRY_NAME = "attach.model"; private static final String PARSER_TAGGER_MODEL_ENTRY_NAME = "parsertager.postagger"; private static final String CHUNKER_TAGGER_MODEL_ENTRY_NAME = "parserchunker.chunker"; private static final String HEAD_RULES_MODEL_ENTRY_NAME = "head-rules.headrules"; private static final String PARSER_TYPE = "parser-type"; /** * Initializes a {@link ParserModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param buildModel A valid {@link MaxentModel} used to build. * @param checkModel A valid {@link MaxentModel} used to check. * @param attachModel A valid {@link MaxentModel} used to attach. * @param parserTagger A valid {@link POSModel} to parse. * @param chunkerTagger A valid {@link ChunkerModel} to chunk. * @param headRules The {@link HeadRules} to to use for parsing. * @param modelType The {@link ParserType} to use. * @param manifestInfoEntries Additional information kept in the manifest. */ public ParserModel(String languageCode, MaxentModel buildModel, MaxentModel checkModel, MaxentModel attachModel, POSModel parserTagger, ChunkerModel chunkerTagger, HeadRules headRules, ParserType modelType, Map manifestInfoEntries) { super(COMPONENT_NAME, languageCode, manifestInfoEntries); setManifestProperty(PARSER_TYPE, modelType.name()); artifactMap.put(BUILD_MODEL_ENTRY_NAME, buildModel); artifactMap.put(CHECK_MODEL_ENTRY_NAME, checkModel); if (ParserType.CHUNKING.equals(modelType)) { if (attachModel != null) throw new IllegalArgumentException("attachModel must be null for chunking parser!"); } else if (ParserType.TREEINSERT.equals(modelType)) { Objects.requireNonNull(attachModel, "attachModel must not be null"); artifactMap.put(ATTACH_MODEL_ENTRY_NAME, attachModel); } else { throw new IllegalStateException("Unknown ParserType '" + modelType + "'!"); } artifactMap.put(PARSER_TAGGER_MODEL_ENTRY_NAME, parserTagger); artifactMap.put(CHUNKER_TAGGER_MODEL_ENTRY_NAME, chunkerTagger); artifactMap.put(HEAD_RULES_MODEL_ENTRY_NAME, headRules); checkArtifactMap(); } /** * Initializes a {@link ParserModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param buildModel A valid {@link MaxentModel} used to build. * @param checkModel A valid {@link MaxentModel} used to check. * @param parserTagger A valid {@link POSModel} to parse. * @param chunkerTagger A valid {@link ChunkerModel} to chunk. * @param headRules The {@link HeadRules} to to use for parsing. * @param modelType The {@link ParserType} to use. */ public ParserModel(String languageCode, MaxentModel buildModel, MaxentModel checkModel, MaxentModel attachModel, POSModel parserTagger, ChunkerModel chunkerTagger, HeadRules headRules, ParserType modelType) { this (languageCode, buildModel, checkModel, attachModel, parserTagger, chunkerTagger, headRules, modelType, null); } /** * Initializes a {@link ParserModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param buildModel A valid {@link MaxentModel} used to build. * @param checkModel A valid {@link MaxentModel} used to check. * @param parserTagger A valid {@link POSModel} to parse. * @param chunkerTagger A valid {@link ChunkerModel} to chunk. * @param headRules The {@link HeadRules} to to use for parsing. * @param type The {@link ParserType} to use. * @param manifestInfoEntries Additional information kept in the manifest. */ public ParserModel(String languageCode, MaxentModel buildModel, MaxentModel checkModel, POSModel parserTagger, ChunkerModel chunkerTagger, HeadRules headRules, ParserType type, Map manifestInfoEntries) { this (languageCode, buildModel, checkModel, null, parserTagger, chunkerTagger, headRules, type, manifestInfoEntries); } /** * Initializes a {@link ParserModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ParserModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link ParserModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ParserModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link ParserModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ParserModel(Path modelPath) throws IOException { this(modelPath.toFile()); } /** * Initializes a {@link ParserModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public ParserModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } @Override protected void createArtifactSerializers(Map> serializers) { super.createArtifactSerializers(serializers); // In 1.6.x the head rules artifact is serialized with the new API // which uses the Serializable interface // This change is not backward compatible with the 1.5.x models. // In order to load 1.5.x model the English head rules serializer must be // put on the serializer map. if (getVersion().getMajor() == 1 && getVersion().getMinor() == 5) { serializers.put("headrules", new HeadRulesSerializer()); } serializers.put("postagger", new POSModelSerializer()); serializers.put("chunker", new ChunkerModelSerializer()); } /** * @return Retrieves the {@link ParserType} as configured in the manifest. */ public ParserType getParserType() { return ParserType.parse(getManifestProperty(PARSER_TYPE)); } /** * @return Retrieves the {@link MaxentModel build model} as configured in the manifest. */ public MaxentModel getBuildModel() { return (MaxentModel) artifactMap.get(BUILD_MODEL_ENTRY_NAME); } /** * @return Retrieves the {@link MaxentModel check model} as configured in the manifest. */ public MaxentModel getCheckModel() { return (MaxentModel) artifactMap.get(CHECK_MODEL_ENTRY_NAME); } /** * @return Retrieves the {@link MaxentModel attach model} as configured in the manifest. */ public MaxentModel getAttachModel() { return (MaxentModel) artifactMap.get(ATTACH_MODEL_ENTRY_NAME); } /** * @return Retrieves the {@link POSModel} as configured in the manifest. */ public POSModel getParserTaggerModel() { return (POSModel) artifactMap.get(PARSER_TAGGER_MODEL_ENTRY_NAME); } /** * @return Retrieves the {@link ChunkerModel} as configured in the manifest. */ public ChunkerModel getParserChunkerModel() { return (ChunkerModel) artifactMap.get(CHUNKER_TAGGER_MODEL_ENTRY_NAME); } /** * @return Retrieves the {@link HeadRules} as configured in the manifest. */ public HeadRules getHeadRules() { return (opennlp.tools.parser.HeadRules) artifactMap.get(HEAD_RULES_MODEL_ENTRY_NAME); } // TODO: (All!) Update model methods should make sure properties are copied correctly ... /** * Instantiates a new {@link ParserModel} instance from the existing configuration * with the specified {@code buildModel} for exchange. * * @param buildModel A valid {@link MaxentModel} used to build. * @return A valid {@link ParserModel}. */ public ParserModel updateBuildModel(MaxentModel buildModel) { return new ParserModel(getLanguage(), buildModel, getCheckModel(), getAttachModel(), getParserTaggerModel(), getParserChunkerModel(), getHeadRules(), getParserType()); } /** * Instantiates a new {@link ParserModel} instance from the existing configuration * with the specified {@code checkModel} for exchange. * * @param checkModel A valid {@link MaxentModel} used to check. * @return A valid {@link ParserModel}. */ public ParserModel updateCheckModel(MaxentModel checkModel) { return new ParserModel(getLanguage(), getBuildModel(), checkModel, getAttachModel(), getParserTaggerModel(), getParserChunkerModel(), getHeadRules(), getParserType()); } /** * Instantiates a new {@link ParserModel} instance from the existing configuration * with the specified {@code taggerModel} for exchange. * * @param taggerModel A valid {@link POSModel} used to tag. * @return A valid {@link ParserModel}. */ public ParserModel updateTaggerModel(POSModel taggerModel) { return new ParserModel(getLanguage(), getBuildModel(), getCheckModel(), getAttachModel(), taggerModel, getParserChunkerModel(), getHeadRules(), getParserType()); } /** * Instantiates a new {@link ParserModel} instance from the existing configuration * with the specified {@code chunkModel} for exchange. * * @param chunkModel A valid {@link ChunkerModel} used to tag. * @return A valid {@link ParserModel}. */ public ParserModel updateChunkerModel(ChunkerModel chunkModel) { return new ParserModel(getLanguage(), getBuildModel(), getCheckModel(), getAttachModel(), getParserTaggerModel(), chunkModel, getHeadRules(), getParserType()); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(BUILD_MODEL_ENTRY_NAME) instanceof AbstractModel)) { throw new InvalidFormatException("Missing the build model!"); } ParserType modelType = getParserType(); if (modelType != null) { if (ParserType.CHUNKING.equals(modelType)) { if (artifactMap.get(ATTACH_MODEL_ENTRY_NAME) != null) throw new InvalidFormatException("attachModel must be null for chunking parser!"); } else if (ParserType.TREEINSERT.equals(modelType)) { if (!(artifactMap.get(ATTACH_MODEL_ENTRY_NAME) instanceof AbstractModel)) throw new InvalidFormatException("attachModel must not be null!"); } else { throw new InvalidFormatException("Unknown ParserType '" + modelType + "'!"); } } else { throw new InvalidFormatException("Missing the parser type property!"); } if (!(artifactMap.get(CHECK_MODEL_ENTRY_NAME) instanceof AbstractModel)) { throw new InvalidFormatException("Missing the check model!"); } if (!(artifactMap.get(PARSER_TAGGER_MODEL_ENTRY_NAME) instanceof POSModel)) { throw new InvalidFormatException("Missing the tagger model!"); } if (!(artifactMap.get(CHUNKER_TAGGER_MODEL_ENTRY_NAME) instanceof ChunkerModel)) { throw new InvalidFormatException("Missing the chunker model!"); } if (!(artifactMap.get(HEAD_RULES_MODEL_ENTRY_NAME) instanceof HeadRules)) { throw new InvalidFormatException("Missing the head rules!"); } } @Override public int hashCode() { return Objects.hash(artifactMap.get(MANIFEST_ENTRY), artifactMap.get(PARSER_TAGGER_MODEL_ENTRY_NAME)); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof ParserModel model) { Map artifactMapToCheck = model.artifactMap; AbstractModel abstractModel = (AbstractModel) artifactMapToCheck.get(BUILD_MODEL_ENTRY_NAME); return artifactMap.get(MANIFEST_ENTRY).equals(artifactMapToCheck.get(MANIFEST_ENTRY)) && artifactMap.get(BUILD_MODEL_ENTRY_NAME).equals(abstractModel); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/ParserType.java0100644 0000000 0000000 00000002567 15217274217 032156 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; /** * Enumeration of supported {@link Parser} types. */ public enum ParserType { CHUNKING, TREEINSERT; /** * @param type The string representation of the requested {@link ParserType}. * @return The {@link ParserType} matching {@code type}, {@code null} otherwise. */ public static ParserType parse(String type) { if (ParserType.CHUNKING.name().equals(type)) { return ParserType.CHUNKING; } else if (ParserType.TREEINSERT.name().equals(type)) { return ParserType.TREEINSERT; } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/PosSampleStream.java0100644 0000000 0000000 00000003375 15217274217 033135 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser; import java.io.IOException; import opennlp.tools.postag.POSSample; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; public class PosSampleStream extends FilterObjectStream { /** * Initializes a {@link PosSampleStream instance}. * * @param in A {@link ObjectStream stream} used as input. */ public PosSampleStream(ObjectStream in) { super(in); } @Override public POSSample read() throws IOException { Parse parse = samples.read(); if (parse != null) { Parse[] nodes = parse.getTagNodes(); String[] toks = new String[nodes.length]; String[] preds = new String[nodes.length]; for (int ti = 0; ti < nodes.length; ti++) { Parse tok = nodes[ti]; toks[ti] = tok.getCoveredText(); preds[ti] = tok.getType(); } return new POSSample(toks, preds); } else { return null; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_chunking_0100644 0000000 0000000 00000000170 15217274217 032560 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/BuildContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/BuildContextGene0100644 0000000 0000000 00000023122 15217274217 034137 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.chunking; import java.util.ArrayList; import java.util.Collection; import java.util.List; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.parser.AbstractContextGenerator; import opennlp.tools.parser.Cons; import opennlp.tools.parser.Parse; import opennlp.tools.util.StringList; /** * Generates predictive contexts for deciding how constituents should be combined. * * @see AbstractContextGenerator */ public class BuildContextGenerator extends AbstractContextGenerator { private Dictionary dict; private String[] unigram; private String[] bigram; private String[] trigram; /** * Instantiates a {@link BuildContextGenerator} for making decisions about combining constituents. */ public BuildContextGenerator() { super(); zeroBackOff = false; useLabel = true; } /** * Instantiates a {@link BuildContextGenerator} for making decisions about combining constituents * using a {@link Dictionary}. * * @param dict A {@link Dictionary} to be used during context generation. */ public BuildContextGenerator(Dictionary dict) { this(); this.dict = dict; unigram = new String[1]; bigram = new String[2]; trigram = new String[3]; } public String[] getContext(Object o) { Object[] params = (Object[]) o; return getContext((Parse[]) params[0], (Integer) params[1]); } /** * Finds the predictive context used to determine how constituent at the specified {@code index} * should be combined with other constituents. * * @param constituents The {@link Parse constituents} which have yet to be combined into new constituents. * @param index The index of the constituent which is being considered. * @return The context for building constituents at the specified {@code index}. */ public String[] getContext(Parse[] constituents, int index) { List features = new ArrayList<>(100); int ps = constituents.length; // cons(-2), cons(-1), cons(0), cons(1), cons(2) // cons(-2) Collection punct2s = null; Collection punct_2s = null; Parse p_2 = null; if (index - 2 >= 0) { p_2 = constituents[index - 2]; } Parse p_1 = null; if (index - 1 >= 0) { p_1 = constituents[index - 1]; punct_2s = p_1.getPreviousPunctuationSet(); } Parse p0 = constituents[index]; Collection punct_1s = p0.getPreviousPunctuationSet(); Collection punct1s = p0.getNextPunctuationSet(); Parse p1 = null; if (index + 1 < ps) { p1 = constituents[index + 1]; punct2s = p1.getNextPunctuationSet(); } Parse p2 = null; if (index + 2 < ps) { p2 = constituents[index + 2]; } boolean u_2 = true; boolean u_1 = true; boolean u0 = true; boolean u1 = true; boolean u2 = true; boolean b_2_1 = true; boolean b_10 = true; boolean b01 = true; boolean b12 = true; boolean t_2_10 = true; boolean t_101 = true; boolean t012 = true; if (dict != null) { if (p_2 != null) { unigram[0] = p_2.getHead().getCoveredText(); u_2 = dict.contains(new StringList(unigram)); } if (p2 != null) { unigram[0] = p2.getHead().getCoveredText(); u2 = dict.contains(new StringList(unigram)); } unigram[0] = p0.getHead().getCoveredText(); u0 = dict.contains(new StringList(unigram)); if (p_2 != null && p_1 != null) { bigram[0] = p_2.getHead().getCoveredText(); bigram[1] = p_1.getHead().getCoveredText(); b_2_1 = dict.contains(new StringList(bigram)); trigram[0] = p_2.getHead().getCoveredText(); trigram[1] = p_1.getHead().getCoveredText(); trigram[2] = p0.getHead().getCoveredText(); t_2_10 = dict.contains(new StringList(trigram)); } if (p_1 != null && p1 != null) { trigram[0] = p_1.getHead().getCoveredText(); trigram[1] = p0.getHead().getCoveredText(); trigram[2] = p1.getHead().getCoveredText(); t_101 = dict.contains(new StringList(trigram)); } if (p_1 != null) { unigram[0] = p_1.getHead().getCoveredText(); u_1 = dict.contains(new StringList(unigram)); //extra check for 2==null case b_2_1 = b_2_1 && u_1 & u_2; t_2_10 = t_2_10 && u_1 & u_2 & u0; t_101 = t_101 && u_1 & u0 && u1; bigram[0] = p_1.getHead().getCoveredText(); bigram[1] = p0.getHead().getCoveredText(); b_10 = dict.contains(new StringList(bigram)) && u_1 && u0; } if (p1 != null && p2 != null) { bigram[0] = p1.getHead().getCoveredText(); bigram[1] = p2.getHead().getCoveredText(); b12 = dict.contains(new StringList(bigram)); trigram[0] = p0.getHead().getCoveredText(); trigram[1] = p1.getHead().getCoveredText(); trigram[2] = p2.getHead().getCoveredText(); t012 = dict.contains(new StringList(trigram)); } if (p1 != null) { unigram[0] = p1.getHead().getCoveredText(); u1 = dict.contains(new StringList(unigram)); //extra check for 2==null case b12 = b12 && u1 && u2; t012 = t012 && u1 && u2 && u0; t_101 = t_101 && u0 && u_1 && u1; bigram[0] = p0.getHead().getCoveredText(); bigram[1] = p1.getHead().getCoveredText(); b01 = dict.contains(new StringList(bigram)); b01 = b01 && u0 && u1; } } String consp_2 = cons(p_2, -2); String consp_1 = cons(p_1, -1); String consp0 = cons(p0, 0); String consp1 = cons(p1, 1); String consp2 = cons(p2, 2); String consbop_2 = consbo(p_2, -2); String consbop_1 = consbo(p_1, -1); String consbop0 = consbo(p0, 0); String consbop1 = consbo(p1, 1); String consbop2 = consbo(p2, 2); Cons c_2 = new Cons(consp_2,consbop_2,-2,u_2); Cons c_1 = new Cons(consp_1,consbop_1,-1,u_1); Cons c0 = new Cons(consp0,consbop0,0,u0); Cons c1 = new Cons(consp1,consbop1,1,u1); Cons c2 = new Cons(consp2,consbop2,2,u2); //default features.add("default"); //first constituent label //features.add("fl="+constituents[0].getLabel()); // features.add("stage=cons(i)"); // cons(-2), cons(-1), cons(0), cons(1), cons(2) if (u0) features.add(consp0); features.add(consbop0); if (u_2) features.add(consp_2); features.add(consbop_2); if (u_1) features.add(consp_1); features.add(consbop_1); if (u1) features.add(consp1); features.add(consbop1); if (u2) features.add(consp2); features.add(consbop2); //cons(0),cons(1) cons2(features,c0,c1,punct1s,b01); //cons(-1),cons(0) cons2(features,c_1,c0,punct_1s,b_10); //features.add("stage=cons(0),cons(1),cons(2)"); cons3(features,c0,c1,c2,punct1s,punct2s,t012,b01,b12); cons3(features,c_2,c_1,c0,punct_2s,punct_1s,t_2_10,b_2_1,b_10); cons3(features,c_1,c0,c1,punct_1s,punct1s,t_101,b_10,b01); //features.add("stage=other"); String p0Tag = p0.getType(); if (p0Tag.equals("-RRB-")) { for (int pi = index - 1; pi >= 0; pi--) { Parse p = constituents[pi]; if (p.getType().equals("-LRB-")) { features.add("bracketsmatch"); break; } if (p.getLabel().startsWith(Parser.START)) { break; } } } if (p0Tag.equals("-RCB-")) { for (int pi = index - 1; pi >= 0; pi--) { Parse p = constituents[pi]; if (p.getType().equals("-LCB-")) { features.add("bracketsmatch"); break; } if (p.getLabel().startsWith(Parser.START)) { break; } } } if (p0Tag.equals("''")) { for (int pi = index - 1; pi >= 0; pi--) { Parse p = constituents[pi]; if (p.getType().equals("``")) { features.add("quotesmatch"); break; } if (p.getLabel().startsWith(Parser.START)) { break; } } } if (p0Tag.equals("'")) { for (int pi = index - 1; pi >= 0; pi--) { Parse p = constituents[pi]; if (p.getType().equals("`")) { features.add("quotesmatch"); break; } if (p.getLabel().startsWith(Parser.START)) { break; } } } if (p0Tag.equals(",")) { for (int pi = index - 1; pi >= 0; pi--) { Parse p = constituents[pi]; if (p.getType().equals(",")) { features.add("iscomma"); break; } if (p.getLabel().startsWith(Parser.START)) { break; } } } if (p0Tag.equals(".") && index == ps - 1) { for (int pi = index - 1; pi >= 0; pi--) { Parse p = constituents[pi]; if (p.getLabel().startsWith(Parser.START)) { if (pi == 0) { features.add("endofsentence"); } break; } } } return features.toArray(new String[0]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_chunking_0100644 0000000 0000000 00000000170 15217274217 032560 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/CheckContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/CheckContextGene0100644 0000000 0000000 00000010501 15217274217 034112 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.chunking; import java.util.ArrayList; import java.util.Collection; import java.util.List; import opennlp.tools.parser.AbstractContextGenerator; import opennlp.tools.parser.Parse; /** * Generates predictive context for deciding when a constituent is complete. * * @see AbstractContextGenerator */ public class CheckContextGenerator extends AbstractContextGenerator { /** * Instantiates a {@link CheckContextGenerator} for generating predictive context for deciding * when a constituent is complete. */ public CheckContextGenerator() { super(); } public String[] getContext(Object o) { Object[] params = (Object[]) o; return getContext((Parse[]) params[0], (String) params[1], (Integer) params[2], (Integer) params[3]); } /** * Finds predictive context for deciding whether the specified constituents between the * specified {@code start} and {@code end} index can be combined to form a * new constituent of the specified {@code type}. * * @param constituents The {@link Parse constituents} which have yet to be combined into new constituents. * @param type The type of the new constituent proposed. * @param start The first constituent of the proposed constituent. * @param end The last constituent of the proposed constituent. * @return The predictive context for deciding whether a new constituent should be created. */ public String[] getContext(Parse[] constituents, String type, int start, int end) { int ps = constituents.length; List features = new ArrayList<>(100); //default features.add("default"); //first constituent label features.add("fl=" + constituents[0].getLabel()); Parse pstart = constituents[start]; Parse pend = constituents[end]; checkcons(pstart, "begin", type, features); checkcons(pend, "last", type, features); StringBuilder production = new StringBuilder(20); StringBuilder punctProduction = new StringBuilder(20); production.append("p=").append(type).append("->"); punctProduction.append("pp=").append(type).append("->"); for (int pi = start; pi < end; pi++) { Parse p = constituents[pi]; checkcons(p, pend, type, features); production.append(p.getType()).append(","); punctProduction.append(p.getType()).append(","); Collection nextPunct = p.getNextPunctuationSet(); if (nextPunct != null) { for (Parse punct : nextPunct) { punctProduction.append(punct.getType()).append(","); } } } production.append(pend.getType()); punctProduction.append(pend.getType()); features.add(production.toString()); features.add(punctProduction.toString()); Parse p_2 = null; Parse p_1 = null; Parse p1 = null; Parse p2 = null; Collection p1s = constituents[end].getNextPunctuationSet(); Collection p2s = null; Collection p_1s = constituents[start].getPreviousPunctuationSet(); Collection p_2s = null; if (start - 2 >= 0) { p_2 = constituents[start - 2]; } if (start - 1 >= 0) { p_1 = constituents[start - 1]; p_2s = p_1.getPreviousPunctuationSet(); } if (end + 1 < ps) { p1 = constituents[end + 1]; p2s = p1.getNextPunctuationSet(); } if (end + 2 < ps) { p2 = constituents[end + 2]; } surround(p_1, -1, type, p_1s, features); surround(p_2, -2, type, p_2s, features); surround(p1, 1, type, p1s, features); surround(p2, 2, type, p2s, features); return features.toArray(new String[0]); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/Parser.java0100644 0000000 0000000 00000037716 15217274217 033126 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.chunking; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.chunker.Chunker; import opennlp.tools.chunker.ChunkerME; import opennlp.tools.chunker.ChunkerModel; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.parser.AbstractBottomUpParser; import opennlp.tools.parser.ChunkSampleStream; import opennlp.tools.parser.HeadRules; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserChunkerFactory; import opennlp.tools.parser.ParserEventTypeEnum; import opennlp.tools.parser.ParserModel; import opennlp.tools.parser.ParserType; import opennlp.tools.parser.PosSampleStream; import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSTagger; import opennlp.tools.postag.POSTaggerFactory; import opennlp.tools.postag.POSTaggerME; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; import opennlp.tools.util.TrainingParameters; /** * A shift reduce style {@link opennlp.tools.parser.Parser} implementation * based on Adwait Ratnaparkhi's 1998 thesis. * * @see AbstractBottomUpParser * @see opennlp.tools.parser.Parser */ public class Parser extends AbstractBottomUpParser { private static final Logger logger = LoggerFactory.getLogger(Parser.class); private final MaxentModel buildModel; private final MaxentModel checkModel; private final BuildContextGenerator buildContextGenerator; private final CheckContextGenerator checkContextGenerator; private final double[] bprobs; private final double[] cprobs; private static final String TOP_START = START + TOP_NODE; private final int topStartIndex; private final Map startTypeMap; private final Map contTypeMap; private final int completeIndex; private final int incompleteIndex; /** * Instantiates a {@link Parser} via a given {@code model} and * other configuration parameters. Uses the default implementations of * {@link POSTaggerME} and {@link ChunkerME}. * * @param model The {@link ParserModel} to use. * @param beamSize The number of different parses kept during parsing. * @param advancePercentage The minimal amount of probability mass which advanced outcomes * must represent. Only outcomes which contribute to the top * {@code advancePercentage} will be explored. * @throws IllegalStateException Thrown if the {@link ParserType} is not supported. * @see ParserModel * @see POSTaggerME * @see ChunkerME */ public Parser(ParserModel model, int beamSize, double advancePercentage) { this(model.getBuildModel(), model.getCheckModel(), new POSTaggerME(model.getParserTaggerModel()), new ChunkerME(model.getParserChunkerModel()), model.getHeadRules(), beamSize, advancePercentage); } /** * Instantiates a {@link Parser} via a given {@code model}. * Uses the default implementations of {@link POSTaggerME} and {@link ChunkerME} * and default values for {@code beamSize} and {@code advancePercentage}. * * @param model The {@link ParserModel} to use. * @throws IllegalStateException Thrown if the {@link ParserType} is not supported. * @see ParserModel * @see POSTaggerME * @see ChunkerME */ public Parser(ParserModel model) { this(model, defaultBeamSize, defaultAdvancePercentage); } /** * Instantiates a {@link Parser} via a given {@code model} and other configuration parameters. * * @param buildModel A valid {@link MaxentModel} used to build. * @param checkModel A valid {@link MaxentModel} used to check. * @param tagger A valid {@link POSModel} used to tag. * @param chunker A valid {@link ChunkerModel} used to chunk. * @param headRules The {@link HeadRules} for head word percolation. * @param beamSize The number of different parses kept during parsing. * @param advancePercentage The minimal amount of probability mass which advanced outcomes * must represent. Only outcomes which contribute to the top * {@code advancePercentage} will be explored. * @see POSTagger * @see Chunker */ private Parser(MaxentModel buildModel, MaxentModel checkModel, POSTagger tagger, Chunker chunker, HeadRules headRules, int beamSize, double advancePercentage) { super(tagger, chunker, headRules, beamSize, advancePercentage); this.buildModel = buildModel; this.checkModel = checkModel; bprobs = new double[buildModel.getNumOutcomes()]; cprobs = new double[checkModel.getNumOutcomes()]; this.buildContextGenerator = new BuildContextGenerator(); this.checkContextGenerator = new CheckContextGenerator(); startTypeMap = new HashMap<>(); contTypeMap = new HashMap<>(); for (int boi = 0, bon = buildModel.getNumOutcomes(); boi < bon; boi++) { String outcome = buildModel.getOutcome(boi); if (outcome.startsWith(START)) { if (logger.isTraceEnabled()) { logger.trace("startMap {} -> {} ", outcome, outcome.substring(START.length())); } startTypeMap.put(outcome, outcome.substring(START.length())); } else if (outcome.startsWith(CONT)) { if (logger.isTraceEnabled()) { logger.trace("contMap {} -> {}", outcome, outcome.substring(CONT.length())); } contTypeMap.put(outcome, outcome.substring(CONT.length())); } } topStartIndex = buildModel.getIndex(TOP_START); completeIndex = checkModel.getIndex(COMPLETE); incompleteIndex = checkModel.getIndex(INCOMPLETE); } @Override protected void advanceTop(Parse p) { buildModel.eval(buildContextGenerator.getContext(p.getChildren(), 0), bprobs); p.addProb(StrictMath.log(bprobs[topStartIndex])); checkModel.eval(checkContextGenerator.getContext(p.getChildren(), TOP_NODE, 0, 0), cprobs); p.addProb(StrictMath.log(cprobs[completeIndex])); p.setType(TOP_NODE); } @Override protected Parse[] advanceParses(final Parse p, double probMass) { double q = 1 - probMass; /* The closest previous node which has been labeled as a start node. */ Parse lastStartNode = null; /* The index of the closest previous node which has been labeled as a start node. */ int lastStartIndex = -1; /* The type of the closest previous node which has been labeled as a start node. */ String lastStartType = null; /* The index of the node which will be labeled in this iteration of advancing the parse. */ int advanceNodeIndex; /* The node which will be labeled in this iteration of advancing the parse. */ Parse advanceNode = null; Parse[] originalChildren = p.getChildren(); Parse[] children = collapsePunctuation(originalChildren, punctSet); int numNodes = children.length; if (numNodes == 0) { return null; } //determines which node needs to be labeled and prior labels. for (advanceNodeIndex = 0; advanceNodeIndex < numNodes; advanceNodeIndex++) { advanceNode = children[advanceNodeIndex]; if (advanceNode.getLabel() == null) { break; } else if (startTypeMap.containsKey(advanceNode.getLabel())) { lastStartType = startTypeMap.get(advanceNode.getLabel()); lastStartNode = advanceNode; lastStartIndex = advanceNodeIndex; if (logger.isTraceEnabled()) { logger.trace("lastStart {} {} {}", lastStartIndex, lastStartNode.getLabel(), lastStartNode.getProb()); } } } int originalAdvanceIndex = mapParseIndex(advanceNodeIndex, children, originalChildren); List newParsesList = new ArrayList<>(buildModel.getNumOutcomes()); //call build buildModel.eval(buildContextGenerator.getContext(children, advanceNodeIndex), bprobs); double bprobSum = 0; while (bprobSum < probMass) { // The largest unadvanced labeling. int max = 0; for (int pi = 1; pi < bprobs.length; pi++) { //for each build outcome if (bprobs[pi] > bprobs[max]) { max = pi; } } if (bprobs[max] == 0) { break; } double bprob = bprobs[max]; bprobs[max] = 0; //zero out so new max can be found bprobSum += bprob; String tag = buildModel.getOutcome(max); if (logger.isTraceEnabled()) { logger.trace("trying {} {} list={}", tag, bprobSum, tag); } if (max == topStartIndex) { // can't have top until complete continue; } if (logger.isTraceEnabled()) { logger.trace("{} {}", tag, bprob); } if (startTypeMap.containsKey(tag)) { //update last start lastStartIndex = advanceNodeIndex; lastStartNode = advanceNode; lastStartType = startTypeMap.get(tag); } else if (contTypeMap.containsKey(tag)) { if (lastStartNode == null || !lastStartType.equals(contTypeMap.get(tag))) { continue; //Cont must match previous start or continue } } Parse newParse1 = (Parse) p.clone(); //clone parse if (createDerivationString) { newParse1.getDerivation().append(max).append("-"); } //replace constituent being labeled to create new derivation newParse1.setChild(originalAdvanceIndex, tag); newParse1.addProb(StrictMath.log(bprob)); //check checkModel.eval(checkContextGenerator.getContext( collapsePunctuation(newParse1.getChildren(), punctSet), lastStartType, lastStartIndex, advanceNodeIndex), cprobs); if (logger.isTraceEnabled()) { String[] context = checkContextGenerator.getContext(newParse1.getChildren(), lastStartType, lastStartIndex, advanceNodeIndex); logger.trace("check {} {} {} {} {}", lastStartType, cprobs[completeIndex], cprobs[incompleteIndex], tag, java.util.Arrays.asList(context)); } Parse newParse2; if (cprobs[completeIndex] > q) { //make sure a reduce is likely newParse2 = (Parse) newParse1.clone(); if (createDerivationString) { newParse2.getDerivation().append(1).append("."); } newParse2.addProb(StrictMath.log(cprobs[completeIndex])); Parse[] cons = new Parse[advanceNodeIndex - lastStartIndex + 1]; boolean flat = true; //first cons[0] = lastStartNode; flat &= cons[0].isPosTag(); //last cons[advanceNodeIndex - lastStartIndex] = advanceNode; flat &= cons[advanceNodeIndex - lastStartIndex].isPosTag(); //middle for (int ci = 1; ci < advanceNodeIndex - lastStartIndex; ci++) { cons[ci] = children[ci + lastStartIndex]; flat &= cons[ci].isPosTag(); } if (!flat) { //flat chunks are done by chunker //check for top node to include end and begining punctuation if (lastStartIndex == 0 && advanceNodeIndex == numNodes - 1) { if (logger.isTraceEnabled()) { logger.trace("ParserME.advanceParses: reducing entire span: {} {} {}", new Span(lastStartNode.getSpan().getStart(), advanceNode.getSpan().getEnd()), lastStartType, java.util.Arrays.asList(children)); } newParse2.insert(new Parse(p.getText(), p.getSpan(), lastStartType, cprobs[1], headRules.getHead(cons, lastStartType))); } else { newParse2.insert(new Parse(p.getText(), new Span(lastStartNode.getSpan().getStart(), advanceNode.getSpan().getEnd()), lastStartType, cprobs[1], headRules.getHead(cons, lastStartType))); } newParsesList.add(newParse2); } } if (cprobs[incompleteIndex] > q) { //make sure a shift is likely if (createDerivationString) { newParse1.getDerivation().append(0).append("."); } if (advanceNodeIndex != numNodes - 1) { //can't shift last element newParse1.addProb(StrictMath.log(cprobs[incompleteIndex])); newParsesList.add(newParse1); } } } Parse[] newParses = new Parse[newParsesList.size()]; newParsesList.toArray(newParses); return newParses; } public static void mergeReportIntoManifest(Map manifest, Map report, String namespace) { for (Map.Entry entry : report.entrySet()) { manifest.put(namespace + "." + entry.getKey(), entry.getValue()); } } /** * Starts a training of a {@link ParserModel}. * * @param languageCode An ISO conform language code. * @param parseSamples The {@link ObjectStream samples} as input. * @param rules The {@link HeadRules} to use. * @param mlParams The {@link TrainingParameters parameters} for training. * @return A valid {@link ParserModel}. * @throws IOException Thrown if IO errors occurred during training. */ public static ParserModel train(String languageCode, ObjectStream parseSamples, HeadRules rules, TrainingParameters mlParams) throws IOException { logger.info("Building dictionary"); Dictionary mdict = buildDictionary(parseSamples, rules, mlParams); parseSamples.reset(); Map manifestInfoEntries = new HashMap<>(); // build logger.info("Training builder"); ObjectStream bes = new ParserEventStream(parseSamples, rules, ParserEventTypeEnum.BUILD, mdict); Map buildReportMap = new HashMap<>(); EventTrainer buildTrainer = TrainerFactory.getEventTrainer(mlParams.getParameters("build"), buildReportMap); MaxentModel buildModel = buildTrainer.train(bes); mergeReportIntoManifest(manifestInfoEntries, buildReportMap, "build"); parseSamples.reset(); // tag TrainingParameters posTaggerParams = mlParams.getParameters("tagger"); if (!posTaggerParams.getObjectSettings().containsKey(BeamSearch.BEAM_SIZE_PARAMETER)) { mlParams.put("tagger", BeamSearch.BEAM_SIZE_PARAMETER, 10); } POSModel posModel = POSTaggerME.train(languageCode, new PosSampleStream(parseSamples), mlParams.getParameters("tagger"), new POSTaggerFactory()); parseSamples.reset(); // chunk ChunkerModel chunkModel = ChunkerME.train(languageCode, new ChunkSampleStream(parseSamples), mlParams.getParameters("chunker"), new ParserChunkerFactory()); parseSamples.reset(); // check logger.info("Training checker"); ObjectStream kes = new ParserEventStream(parseSamples, rules, ParserEventTypeEnum.CHECK); Map checkReportMap = new HashMap<>(); EventTrainer checkTrainer = TrainerFactory.getEventTrainer(mlParams.getParameters("check"), checkReportMap); MaxentModel checkModel = checkTrainer.train(kes); mergeReportIntoManifest(manifestInfoEntries, checkReportMap, "check"); return new ParserModel(languageCode, buildModel, checkModel, posModel, chunkModel, rules, ParserType.CHUNKING, manifestInfoEntries); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_chunking_0100644 0000000 0000000 00000000164 15217274217 032563 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/ParserEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/ParserEventStrea0100644 0000000 0000000 00000015476 15217274217 034206 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.chunking; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.model.Event; import opennlp.tools.parser.AbstractBottomUpParser; import opennlp.tools.parser.AbstractParserEventStream; import opennlp.tools.parser.HeadRules; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserEventTypeEnum; import opennlp.tools.util.ObjectStream; /** * Wrapper class for one of four {@link Parser shift-reduce parser} event streams. * The particular {@link ParserEventTypeEnum event type} is specified at construction. */ public class ParserEventStream extends AbstractParserEventStream { private static final Logger logger = LoggerFactory.getLogger(ParserEventStream.class); protected BuildContextGenerator bcg; protected CheckContextGenerator kcg; /** * Instantiates a {@link ParserEventStream} based on the specified data stream * of the {@link ParserEventTypeEnum type} using {@link HeadRules head rules}. * * @param d A 1-parse-per-line Penn Treebank Style parse. * @param rules The {@link HeadRules head rules} to use. * @param etype The {@link ParserEventTypeEnum type} of events desired. * @param dict A tri-gram {@link Dictionary} to reduce feature generation. * * @see ParserEventTypeEnum */ public ParserEventStream(ObjectStream d, HeadRules rules, ParserEventTypeEnum etype, Dictionary dict) { super(d,rules,etype,dict); } /** * Instantiates a {@link ParserEventStream} based on the specified data stream * of the {@link ParserEventTypeEnum type} using {@link HeadRules head rules}. * * @param d A 1-parse-per-line Penn Treebank Style parse. * @param rules The {@link HeadRules head rules} to use. * @param etype The {@link ParserEventTypeEnum type} of events desired. * * @see ParserEventTypeEnum */ public ParserEventStream(ObjectStream d, HeadRules rules, ParserEventTypeEnum etype) { this (d,rules,etype,null); } @Override protected void init() { if (etype == ParserEventTypeEnum.BUILD) { this.bcg = new BuildContextGenerator(dict); } else if (etype == ParserEventTypeEnum.CHECK) { this.kcg = new CheckContextGenerator(); } } /** * @param child The child {@link Parse}. * @param parent The parent {@link Parse}. * * @return {@code true} if the specified {@code child} is the first child of the * specified {@code parent}, {@code false} otherwise. */ protected boolean firstChild(Parse child, Parse parent) { return AbstractBottomUpParser.collapsePunctuation(parent.getChildren(), punctSet)[0] == child; } public static Parse[] reduceChunks(Parse[] chunks, int ci, Parse parent) { String type = parent.getType(); // perform reduce int reduceStart = ci; int reduceEnd = ci; while (reduceStart >= 0 && chunks[reduceStart].getParent() == parent) { reduceStart--; } reduceStart++; Parse[] reducedChunks; if (!type.equals(AbstractBottomUpParser.TOP_NODE)) { //total - num_removed + 1 (for new node) reducedChunks = new Parse[chunks.length - (reduceEnd - reduceStart + 1) + 1]; //insert nodes before reduction System.arraycopy(chunks, 0, reducedChunks, 0, reduceStart); //insert reduced node reducedChunks[reduceStart] = parent; //propagate punctuation sets parent.setPrevPunctuation(chunks[reduceStart].getPreviousPunctuationSet()); parent.setNextPunctuation(chunks[reduceEnd].getNextPunctuationSet()); //insert nodes after reduction int ri = reduceStart + 1; for (int rci = reduceEnd + 1; rci < chunks.length; rci++) { reducedChunks[ri] = chunks[rci]; ri++; } ci = reduceStart - 1; //ci will be incremented at end of loop } else { reducedChunks = new Parse[0]; } return reducedChunks; } /** * Adds {@link Event events} for parsing (post tagging and chunking) * to the specified list of events for the specified parse chunks. * * @param parseEvents The {@link Event events} for the specified chunks. * @param chunks The incomplete {@link Parse parses} to be parsed. */ @Override protected void addParseEvents(List parseEvents, Parse[] chunks) { int ci = 0; while (ci < chunks.length) { if (logger.isTraceEnabled()) { logger.trace("parserEventStream.addParseEvents: chunks={}", Arrays.asList(chunks)); } Parse c = chunks[ci]; Parse parent = c.getParent(); if (parent != null) { String type = parent.getType(); String outcome; if (firstChild(c, parent)) { outcome = AbstractBottomUpParser.START + type; } else { outcome = AbstractBottomUpParser.CONT + type; } if (logger.isTraceEnabled()) { logger.trace("parserEventStream.addParseEvents: chunks[{}]={} label={} bcg={}", ci, c, outcome, bcg); } c.setLabel(outcome); if (etype == ParserEventTypeEnum.BUILD) { parseEvents.add(new Event(outcome, bcg.getContext(chunks, ci))); } int start = ci - 1; while (start >= 0 && chunks[start].getParent() == parent) { start--; } if (lastChild(c, parent)) { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.COMPLETE, kcg.getContext( chunks, type, start + 1, ci))); } //perform reduce int reduceStart = ci; while (reduceStart >= 0 && chunks[reduceStart].getParent() == parent) { reduceStart--; } reduceStart++; chunks = reduceChunks(chunks,ci,parent); ci = reduceStart - 1; //ci will be incremented at end of loop } else { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.INCOMPLETE, kcg.getContext(chunks, type, start + 1, ci))); } } } ci++; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_chunking_0100644 0000000 0000000 00000000157 15217274217 032565 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/chunking/package-info.jav0100644 0000000 0000000 00000001666 15217274217 034050 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package containing code for performing full syntactic parsing using shift/reduce-style decisions. */ package opennlp.tools.parser.chunking; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/lang/en/HeadRules.java0100644 0000000 0000000 00000023553 15217274217 033255 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.lang.en; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; import opennlp.tools.parser.Constituent; import opennlp.tools.parser.GapLabeler; import opennlp.tools.parser.Parse; import opennlp.tools.parser.chunking.Parser; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.SerializableArtifact; /** * Class for storing the English {@link opennlp.tools.parser.HeadRules} associated with parsing. */ public class HeadRules implements opennlp.tools.parser.HeadRules, GapLabeler, SerializableArtifact { // POS tagsets are fixed by linguistic convention (Penn Treebank: ~45 tags). // No single head rule will ever list more than a small fraction of the tagset. // 1000 gives 20x headroom over the real-world maximum and is not configurable // because tag counts are a linguistics constraint, not a deployment parameter. private static final int MAX_TAGS_PER_RULE = 1_000; public static class HeadRulesSerializer implements ArtifactSerializer { public HeadRules create(InputStream in) throws IOException { return new HeadRules(new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))); } public void serialize(opennlp.tools.parser.lang.en.HeadRules artifact, OutputStream out) throws IOException { artifact.serialize(new OutputStreamWriter(out, StandardCharsets.UTF_8)); } } private static class HeadRule { public final boolean leftToRight; public final String[] tags; public HeadRule(boolean l2r, String[] tags) { leftToRight = l2r; for (String tag : tags) { Objects.requireNonNull(tag, "tags must not contain null values"); } this.tags = tags; } @Override public int hashCode() { return Objects.hash(leftToRight, Arrays.hashCode(tags)); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof HeadRule rule) { return rule.leftToRight == leftToRight && Arrays.equals(rule.tags, tags); } return false; } } private Map headRules; private final Set punctSet; /** * Creates a new set of head rules based on the specified reader. * * @param rulesReader A {@link Reader} for a head rules file. * * @throws IOException Thrown f the head rules reader can not be read. */ public HeadRules(Reader rulesReader) throws IOException { BufferedReader in = new BufferedReader(rulesReader); readHeadRules(in); punctSet = new HashSet<>(); punctSet.add("."); punctSet.add(","); punctSet.add("``"); punctSet.add("''"); //punctSet.add(":"); } @Override public Set getPunctuationTags() { return punctSet; } @Override public Parse getHead(Parse[] constituents, String type) { if (Parser.TOK_NODE.equals(constituents[0].getType())) { return null; } HeadRule hr; if (type.equals("NP") || type.equals("NX")) { String[] tags1 = { "NN", "NNP", "NNPS", "NNS", "NX", "JJR", "POS" }; for (int ci = constituents.length - 1; ci >= 0; ci--) { for (int ti = tags1.length - 1; ti >= 0; ti--) { if (constituents[ci].getType().equals(tags1[ti])) { return constituents[ci].getHead(); } } } for (Parse constituent : constituents) { if (constituent.getType().equals("NP")) { return constituent.getHead(); } } String[] tags2 = { "$", "ADJP", "PRN" }; for (int ci = constituents.length - 1; ci >= 0; ci--) { for (int ti = tags2.length - 1; ti >= 0; ti--) { if (constituents[ci].getType().equals(tags2[ti])) { return constituents[ci].getHead(); } } } String[] tags3 = { "JJ", "JJS", "RB", "QP" }; for (int ci = constituents.length - 1; ci >= 0; ci--) { for (int ti = tags3.length - 1; ti >= 0; ti--) { if (constituents[ci].getType().equals(tags3[ti])) { return constituents[ci].getHead(); } } } return constituents[constituents.length - 1].getHead(); } else if ((hr = headRules.get(type)) != null) { String[] tags = hr.tags; int cl = constituents.length; int tl = tags.length; if (hr.leftToRight) { for (String tag : tags) { for (Parse constituent : constituents) { if (constituent.getType().equals(tag)) { return constituent.getHead(); } } } return constituents[0].getHead(); } else { for (String tag : tags) { for (int ci = cl - 1; ci >= 0; ci--) { if (constituents[ci].getType().equals(tag)) { return constituents[ci].getHead(); } } } return constituents[cl - 1].getHead(); } } return constituents[constituents.length - 1].getHead(); } private void readHeadRules(BufferedReader str) throws IOException { String line; headRules = new HashMap<>(30); while ((line = str.readLine()) != null) { StringTokenizer st = new StringTokenizer(line); String num = st.nextToken(); String type = st.nextToken(); String dir = st.nextToken(); int rawCount; try { rawCount = Integer.parseInt(num); } catch (NumberFormatException e) { throw new IOException("Invalid tag count in head rules: " + num, e); } int numTags = rawCount - 2; if (numTags < 0 || numTags > MAX_TAGS_PER_RULE) { throw new IOException("Invalid tag count in head rules: " + num); } String[] tags = new String[numTags]; int ti = 0; while (st.hasMoreTokens()) { tags[ti] = st.nextToken(); ti++; } headRules.put(type, new HeadRule(dir.equals("1"), tags)); } } @Override public void labelGaps(Stack stack) { if (stack.size() > 4) { //Constituent con0 = (Constituent) stack.get(stack.size()-1); Constituent con1 = stack.get(stack.size() - 2); Constituent con2 = stack.get(stack.size() - 3); Constituent con3 = stack.get(stack.size() - 4); Constituent con4 = stack.get(stack.size() - 5); // System.err.println("con0="+con0.label+" con1="+con1.label+" con2=" // +con2.label+" con3="+con3.label+" con4="+con4.label); //subject extraction if (con1.getLabel().equals("NP") && con2.getLabel().equals("S") && con3.getLabel().equals("SBAR")) { con1.setLabel(con1.getLabel() + "-G"); con2.setLabel(con2.getLabel() + "-G"); con3.setLabel(con3.getLabel() + "-G"); } //object extraction else if (con1.getLabel().equals("NP") && con2.getLabel().equals("VP") && con3.getLabel().equals("S") && con4.getLabel().equals("SBAR")) { con1.setLabel(con1.getLabel() + "-G"); con2.setLabel(con2.getLabel() + "-G"); con3.setLabel(con3.getLabel() + "-G"); con4.setLabel(con4.getLabel() + "-G"); } } } /** * Serializes the head rules via a {@link Writer} in a format suitable for loading * the head rules again. The encoding must be taken into account while * working with the writer and reader. *

* Once the entries have been written, the {@code writer} is flushed. *

* Note: * The {@code writer} remains open after this method returns. * * @param writer The {@link Writer} to write the head rules to. * @throws IOException Thrown if IO errors occurred during write operation. */ public void serialize(Writer writer) throws IOException { for (Entry entry : headRules.entrySet()) { String type = entry.getKey(); HeadRule headRule = entry.getValue(); // write num of tags writer.write(Integer.toString(headRule.tags.length + 2)); writer.write(' '); // write type writer.write(type); writer.write(' '); // write l2r true == 1 if (headRule.leftToRight) writer.write("1"); else writer.write("0"); // write tags for (String tag : headRule.tags) { writer.write(' '); writer.write(tag); } writer.write('\n'); } writer.flush(); } @Override public int hashCode() { return Objects.hash(headRules, punctSet); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof HeadRules rules) { return rules.headRules.equals(headRules) && rules.punctSet.equals(punctSet); } return false; } @Override public Class getArtifactSerializerClass() { return HeadRulesSerializer.class; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_lang_es_A0100644 0000000 0000000 00000000170 15217274217 032463 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/lang/es/AncoraSpanishHeadRules.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/lang/es/AncoraSpanishHead0100644 0000000 0000000 00000024652 15217274217 034002 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.lang.es; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; import opennlp.tools.parser.Constituent; import opennlp.tools.parser.GapLabeler; import opennlp.tools.parser.HeadRules; import opennlp.tools.parser.Parse; import opennlp.tools.parser.chunking.Parser; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.SerializableArtifact; /** * Class for storing the Ancora Spanish head rules associated with parsing. In this class * headrules for noun phrases are specified. The rest of the rules are * in opennlp-tools/lang/es/parser/es-head-rules *

* NOTE: This class has been adapted from opennlp.tools.parser.lang.en.HeadRules *

* The main change is the constituents search direction in the first for loop. *

* Note also the change in the return of the getHead() method: * In the lang.en.HeadRules class: return constituents[ci].getHead(); * Now: return constituents[ci]; *

* Other changes include removal of deprecated methods. * */ public class AncoraSpanishHeadRules implements HeadRules, GapLabeler, SerializableArtifact { // POS tagsets are fixed by linguistic convention (Penn Treebank: ~45 tags). // No single head rule will ever list more than a small fraction of the tagset. // 1000 gives 20x headroom over the real-world maximum and is not configurable // because tag counts are a linguistics constraint, not a deployment parameter. private static final int MAX_TAGS_PER_RULE = 1_000; public static class HeadRulesSerializer implements ArtifactSerializer { public AncoraSpanishHeadRules create(InputStream in) throws IOException { return new AncoraSpanishHeadRules(new BufferedReader( new InputStreamReader(in, StandardCharsets.UTF_8))); } public void serialize(opennlp.tools.parser.lang.es.AncoraSpanishHeadRules artifact, OutputStream out) throws IOException { artifact.serialize(new OutputStreamWriter(out, StandardCharsets.UTF_8)); } } private static class HeadRule { public final boolean leftToRight; public final String[] tags; public HeadRule(boolean l2r, String[] tags) { leftToRight = l2r; for (String tag : tags) { Objects.requireNonNull(tag, "tags must not contain null values!"); } this.tags = tags; } @Override public int hashCode() { return Objects.hash(leftToRight, Arrays.hashCode(tags)); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof HeadRule rule) { return (rule.leftToRight == leftToRight) && Arrays.equals(rule.tags, tags); } return false; } } private Map headRules; private final Set punctSet; /** * Creates a new set of head rules based on the specified reader. * * @param rulesReader A {@link Reader} for a head rules file. * * @throws IOException Thrown f the head rules reader can not be read. */ public AncoraSpanishHeadRules(Reader rulesReader) throws IOException { BufferedReader in = new BufferedReader(rulesReader); readHeadRules(in); punctSet = new HashSet<>(); punctSet.add("."); punctSet.add(","); punctSet.add("``"); punctSet.add("''"); //punctSet.add(":"); } @Override public Set getPunctuationTags() { return punctSet; } @Override public Parse getHead(Parse[] constituents, String type) { if (Parser.TOK_NODE.equals(constituents[0].getType())) { return null; } HeadRule hr; if (type.equals("SN") || type.equals("GRUP.NOM")) { String[] tags1 = {"AQA.*","AQC.*","GRUP\\.A","S\\.A","NC.*S.*", "NP.*","NC.*P.*", "GRUP\\.NOM"}; for (Parse constituent : constituents) { for (int t = tags1.length - 1; t >= 0; t--) { if (constituent.getType().matches(tags1[t])) { return constituent; } } } for (Parse constituent : constituents) { if (constituent.getType().equals("SN") || constituent.getType().equals("GRUP.NOM")) { return constituent; } } String[] tags2 = {"\\$","GRUP\\.A","SA"}; for (int ci = constituents.length - 1; ci >= 0; ci--) { for (int ti = tags2.length - 1; ti >= 0; ti--) { if (constituents[ci].getType().matches(tags2[ti])) { return constituents[ci]; } } } String[] tags3 = {"AQ0.*", "AQ[AC].*","AO.*","GRUP\\.A","S\\.A","RG","RN","GRUP\\.NOM"}; for (int ci = constituents.length - 1; ci >= 0; ci--) { for (int ti = tags3.length - 1; ti >= 0; ti--) { if (constituents[ci].getType().matches(tags3[ti])) { return constituents[ci]; } } } return constituents[constituents.length - 1].getHead(); } else if ((hr = headRules.get(type)) != null) { String[] tags = hr.tags; int cl = constituents.length; int tl = tags.length; if (hr.leftToRight) { for (String tag : tags) { for (Parse constituent : constituents) { if (constituent.getType().matches(tag)) { return constituent; } } } return constituents[0].getHead(); } else { for (String tag : tags) { for (int ci = cl - 1; ci >= 0; ci--) { if (constituents[ci].getType().matches(tag)) { return constituents[ci]; } } } return constituents[cl - 1].getHead(); } } return constituents[constituents.length - 1].getHead(); } private void readHeadRules(BufferedReader str) throws IOException { String line; headRules = new HashMap<>(60); while ((line = str.readLine()) != null) { StringTokenizer st = new StringTokenizer(line); String num = st.nextToken(); String type = st.nextToken(); String dir = st.nextToken(); int rawCount; try { rawCount = Integer.parseInt(num); } catch (NumberFormatException e) { throw new IOException("Invalid tag count in head rules: " + num, e); } int numTags = rawCount - 2; if (numTags < 0 || numTags > MAX_TAGS_PER_RULE) { throw new IOException("Invalid tag count in head rules: " + num); } String[] tags = new String[numTags]; int ti = 0; while (st.hasMoreTokens()) { tags[ti] = st.nextToken(); ti++; } headRules.put(type, new HeadRule(dir.equals("1"), tags)); } } @Override public void labelGaps(Stack stack) { if (stack.size() > 4) { //Constituent con0 = (Constituent) stack.get(stack.size()-1); Constituent con1 = stack.get(stack.size() - 2); Constituent con2 = stack.get(stack.size() - 3); Constituent con3 = stack.get(stack.size() - 4); Constituent con4 = stack.get(stack.size() - 5); //subject extraction if (con1.getLabel().equals("SN") && con2.getLabel().equals("S") && con3.getLabel().equals("GRUP.NOM")) { con1.setLabel(con1.getLabel() + "-G"); con2.setLabel(con2.getLabel() + "-G"); con3.setLabel(con3.getLabel() + "-G"); } //object extraction else if (con1.getLabel().equals("SN") && con2.getLabel().equals("GRUP.VERB") && con3.getLabel().equals("S") && con4.getLabel().equals("GRUP.NOM")) { con1.setLabel(con1.getLabel() + "-G"); con2.setLabel(con2.getLabel() + "-G"); con3.setLabel(con3.getLabel() + "-G"); con4.setLabel(con4.getLabel() + "-G"); } } } /** * Serializes the head rules via a {@link Writer} in a format suitable for loading * the head rules again. The encoding must be taken into account while * working with the writer and reader. *

* Once the entries have been written, the {@code writer} is flushed. *

* Note: * The {@code writer} remains open after this method returns. * * @param writer The {@link Writer} to write the head rules to. * @throws IOException Thrown if IO errors occurred during write operation. */ public void serialize(Writer writer) throws IOException { for (Entry entry : headRules.entrySet()) { String type = entry.getKey(); HeadRule headRule = entry.getValue(); // write num of tags writer.write(Integer.toString(headRule.tags.length + 2)); writer.write(' '); // write type writer.write(type); writer.write(' '); // write l2r true == 1 if (headRule.leftToRight) writer.write("1"); else writer.write("0"); // write tags for (String tag : headRule.tags) { writer.write(' '); writer.write(tag); } writer.write('\n'); } writer.flush(); } @Override public int hashCode() { return Objects.hash(headRules, punctSet); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof AncoraSpanishHeadRules rules) { return rules.headRules.equals(headRules) && rules.punctSet.equals(punctSet); } return false; } @Override public Class getArtifactSerializerClass() { return HeadRulesSerializer.class; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/package-info.java0100644 0000000 0000000 00000001621 15217274217 032372 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package containing common code for performing full syntactic parsing. */ package opennlp.tools.parser; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_treeinser0100644 0000000 0000000 00000000173 15217274217 032616 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/AttachContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/AttachContextG0100644 0000000 0000000 00000013035 15217274217 034174 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.treeinsert; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import opennlp.tools.parser.AbstractContextGenerator; import opennlp.tools.parser.Cons; import opennlp.tools.parser.Parse; /** * Generates predictive contexts for deciding how constituents should be attached. * * @see AbstractContextGenerator */ public class AttachContextGenerator extends AbstractContextGenerator { /** * Instantiates an {@link AttachContextGenerator} for making decisions about attachments. */ public AttachContextGenerator(Set punctSet) { this.punctSet = punctSet; } public String[] getContext(Object o) { Object[] parts = (Object[]) o; return getContext((Parse[]) parts[0], (Integer) parts[1], (List) parts[2], (Integer) parts[3]); } private boolean containsPunct(Collection puncts, String punct) { if (puncts != null) { for (Parse p : puncts) { if (p.getType().equals(punct)) { return true; } } } return false; } /** * Finds the predictive contextual features about an attachment. * * @param constituents The {@link Parse constituents} as they have been constructed so far. * @param index The constituent index of the node being attached. * @param rightFrontier The nodes which have been not attach to so far. * @return A set of contextual features about this attachment. */ public String[] getContext(Parse[] constituents, int index, List rightFrontier, int rfi) { List features = new ArrayList<>(100); Parse fn = rightFrontier.get(rfi); Parse fp = null; if (rfi + 1 < rightFrontier.size()) { fp = rightFrontier.get(rfi + 1); } Parse p_1 = null; if (rightFrontier.size() > 0) { p_1 = rightFrontier.get(0); } Parse p0 = constituents[index]; Parse p1 = null; if (index + 1 < constituents.length) { p1 = constituents[index + 1]; } Collection punct_1fs = fn.getPreviousPunctuationSet(); Collection punct_1s = p0.getPreviousPunctuationSet(); Collection punct1s = p0.getNextPunctuationSet(); String consfp = cons(fp, -3); String consf = cons(fn, -2); String consp_1 = cons(p_1, -1); String consp0 = cons(p0, 0); String consp1 = cons(p1, 1); String consbofp = consbo(fp, -3); String consbof = consbo(fn, -2); String consbop_1 = consbo(p_1, -1); String consbop0 = consbo(p0, 0); String consbop1 = consbo(p1, 1); Cons cfp = new Cons(consfp,consbofp,-3,true); Cons cf = new Cons(consf,consbof,-2,true); Cons c_1 = new Cons(consp_1,consbop_1,-1,true); Cons c0 = new Cons(consp0,consbop0,0,true); Cons c1 = new Cons(consp1,consbop1,1,true); //default features.add("default"); //unigrams features.add(consfp); features.add(consbofp); features.add(consf); features.add(consbof); features.add(consp_1); features.add(consbop_1); features.add(consp0); features.add(consbop0); features.add(consp1); features.add(consbop1); //productions String prod = production(fn,false); //String punctProd = production(fn,true,punctSet); features.add("pn=" + prod); features.add("pd=" + prod + "," + p0.getType()); features.add("ps=" + fn.getType() + "->" + fn.getType() + "," + p0.getType()); if (punct_1s != null) { StringBuilder punctBuf = new StringBuilder(5); for (Parse punct : punct_1s) { punctBuf.append(punct.getType()).append(","); } //features.add("ppd="+punctProd+","+punctBuf.toString()+p0.getType()); //features.add("pps="+fn.getType()+"->"+fn.getType()+","+punctBuf.toString()+p0.getType()); } //bi-grams //cons(fn),cons(0) cons2(features,cfp,c0,punct_1s,true); cons2(features,cf,c0,punct_1s,true); cons2(features,c_1,c0,punct_1s,true); cons2(features,c0,c1,punct1s,true); cons3(features,cf,c_1,c0,null,punct_1s,true,true,true); cons3(features,cf,c0,c1,punct_1s,punct1s,true,true,true); cons3(features,cfp,cf,c0,null,punct_1s,true,true,true); /* for (int ri=0;ri punct_1s = p0.getPreviousPunctuationSet(); Collection punct1s = p0.getNextPunctuationSet(); Collection punct2s = null; if (p1 != null) { punct2s = p1.getNextPunctuationSet(); } List rf; if (index == 0) { rf = Collections.emptyList(); } else { //this isn't a root node so, punctSet won't be used and can be passed as empty. Set emptyPunctSet = Collections.emptySet(); rf = Parser.getRightFrontier(constituents[0], emptyPunctSet); } getFrontierNodes(rf,leftNodes); Parse p_1 = leftNodes[0]; Parse p_2 = leftNodes[1]; Collection punct_2s = null; if (p_1 != null) { punct_2s = p_1.getPreviousPunctuationSet(); } String consp_2 = cons(p_2, -2); String consp_1 = cons(p_1, -1); String consp0 = cons(p0, 0); String consp1 = cons(p1, 1); String consp2 = cons(p2, 2); String consbop_2 = consbo(p_2, -2); String consbop_1 = consbo(p_1, -1); String consbop0 = consbo(p0, 0); String consbop1 = consbo(p1, 1); String consbop2 = consbo(p2, 2); Cons c_2 = new Cons(consp_2,consbop_2,-2,true); Cons c_1 = new Cons(consp_1,consbop_1,-1,true); Cons c0 = new Cons(consp0,consbop0,0,true); Cons c1 = new Cons(consp1,consbop1,1,true); Cons c2 = new Cons(consp2,consbop2,2,true); List features = new ArrayList<>(); features.add("default"); //unigrams features.add(consp_2); features.add(consbop_2); features.add(consp_1); features.add(consbop_1); features.add(consp0); features.add(consbop0); features.add(consp1); features.add(consbop1); features.add(consp2); features.add(consbop2); //cons(0),cons(1) cons2(features,c0,c1,punct1s,true); //cons(-1),cons(0) cons2(features,c_1,c0,punct_1s,true); //features.add("stage=cons(0),cons(1),cons(2)"); cons3(features,c0,c1,c2,punct1s,punct2s,true,true,true); cons3(features,c_2,c_1,c0,punct_2s,punct_1s,true,true,true); cons3(features,c_1,c0,c1,punct_1s,punct_1s,true,true,true); if (rf.isEmpty()) { features.add(EOS + "," + consp0); features.add(EOS + "," + consbop0); } return features.toArray(new String[0]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_treeinser0100644 0000000 0000000 00000000172 15217274217 032615 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/CheckContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/CheckContextGe0100644 0000000 0000000 00000010453 15217274217 034153 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.treeinsert; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import opennlp.tools.parser.AbstractContextGenerator; import opennlp.tools.parser.Parse; /** * Generates predictive context for deciding when a constituent is complete. * * @see AbstractContextGenerator */ public class CheckContextGenerator extends AbstractContextGenerator { private final Parse[] leftNodes; /** * Instantiates a {@link CheckContextGenerator} for making decisions using a {@code punctSet}. * * @param punctSet A set of punctuation symbols to be used during context generation. */ public CheckContextGenerator(Set punctSet) { this.punctSet = punctSet; leftNodes = new Parse[2]; } public String[] getContext(Object o) { Object[] params = (Object[]) o; return getContext((Parse) params[0], (Parse[]) params[1], (Integer) params[2], (Boolean) params[3]); } /** * Finds the predictive context used to determine how constituent at the specified {@code index} * should be combined with a {@code parent} constituent. * * @param parent The {@link Parse parent} element. * @param constituents The {@link Parse constituents} which have yet to be combined into new constituents. * @param index The index of the constituent which is being considered. * @param trimFrontier Whether the frontier should be trimmed, or not. * * @return The context for deciding whether a new constituent should be created. */ public String[] getContext(Parse parent, Parse[] constituents, int index, boolean trimFrontier) { List features = new ArrayList<>(100); //default features.add("default"); Parse[] children = Parser.collapsePunctuation(parent.getChildren(),punctSet); Parse pstart = children[0]; Parse pend = children[children.length - 1]; String type = parent.getType(); checkcons(pstart, "begin", type, features); checkcons(pend, "last", type, features); String production = "p=" + production(parent,false); String punctProduction = "pp=" + production(parent,true); features.add(production); features.add(punctProduction); Parse p1 = null; Parse p2 = null; Collection p1s = constituents[index].getNextPunctuationSet(); Collection p2s = null; Collection p_1s = constituents[index].getPreviousPunctuationSet(); Collection p_2s = null; List rf; if (index == 0) { rf = Collections.emptyList(); } else { rf = Parser.getRightFrontier(constituents[0], punctSet); if (trimFrontier) { int pi = rf.indexOf(parent); if (pi == -1) { throw new RuntimeException("Parent not found in right frontier:" + parent + " rf=" + rf); } else { for (int ri = 0; ri <= pi; ri++) { rf.remove(0); } } } } getFrontierNodes(rf,leftNodes); Parse p_1 = leftNodes[0]; Parse p_2 = leftNodes[1]; int ps = constituents.length; if (p_1 != null) { p_2s = p_1.getPreviousPunctuationSet(); } if (index + 1 < ps) { p1 = constituents[index + 1]; p2s = p1.getNextPunctuationSet(); } if (index + 2 < ps) { p2 = constituents[index + 2]; } surround(p_1, -1, type, p_1s, features); surround(p_2, -2, type, p_2s, features); surround(p1, 1, type, p1s, features); surround(p2, 2, type, p2s, features); return features.toArray(new String[0]); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/Parser.java0100644 0000000 0000000 00000060436 15217274217 033477 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.treeinsert; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.chunker.Chunker; import opennlp.tools.chunker.ChunkerME; import opennlp.tools.chunker.ChunkerModel; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.parser.AbstractBottomUpParser; import opennlp.tools.parser.ChunkSampleStream; import opennlp.tools.parser.HeadRules; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserChunkerFactory; import opennlp.tools.parser.ParserEventTypeEnum; import opennlp.tools.parser.ParserModel; import opennlp.tools.parser.ParserType; import opennlp.tools.parser.PosSampleStream; import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSTagger; import opennlp.tools.postag.POSTaggerFactory; import opennlp.tools.postag.POSTaggerME; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; /** * A built-attach {@link opennlp.tools.parser.Parser} implementation. *

* Nodes are built when their left-most child is encountered. * Subsequent children are attached as daughters. * Attachment is based on node in the right-frontier * of the tree. After each attachment or building, nodes are * assessed as either complete or incomplete. Complete nodes * are no longer eligible for daughter attachment. *

* Complex modifiers which produce additional node * levels of the same type are attached with sister-adjunction. * Attachment can not take place higher in the right-frontier * than an incomplete node. * * @see AbstractBottomUpParser * @see opennlp.tools.parser.Parser */ public class Parser extends AbstractBottomUpParser { private static final Logger logger = LoggerFactory.getLogger(Parser.class); /** Outcome used when a constituent needs an no additional parent node/building. */ public static final String DONE = "d"; /** Outcome used when a node should be attached as a sister to another node. */ public static final String ATTACH_SISTER = "s"; /** Outcome used when a node should be attached as a daughter to another node. */ public static final String ATTACH_DAUGHTER = "d"; /** Outcome used when a node should not be attached to another node. */ public static final String NON_ATTACH = "n"; /** Label used to distinguish build nodes from non-built nodes. */ public static final String BUILT = "built"; private final MaxentModel buildModel; private final MaxentModel attachModel; private final MaxentModel checkModel; static boolean checkComplete = false; private final BuildContextGenerator buildContextGenerator; private final AttachContextGenerator attachContextGenerator; private final CheckContextGenerator checkContextGenerator; private final double[] bprobs; private final double[] aprobs; private double[] cprobs; private final int doneIndex; private final int sisterAttachIndex; private final int daughterAttachIndex; private final int nonAttachIndex; private final int completeIndex; private final int[] attachments; /** * Instantiates a {@link Parser} via a given {@code model} and * other configuration parameters. Uses the default implementations of * {@link POSTaggerME} and {@link ChunkerME}. * * @param model The {@link ParserModel} to use. * @param beamSize The number of different parses kept during parsing. * @param advancePercentage The minimal amount of probability mass which advanced outcomes * must represent. Only outcomes which contribute to the top * {@code advancePercentage} will be explored. * * @throws IllegalStateException Thrown if the {@link ParserType} is not supported. * * @see ParserModel * @see POSTaggerME * @see ChunkerME */ public Parser(ParserModel model, int beamSize, double advancePercentage) { this(model.getBuildModel(), model.getAttachModel(), model.getCheckModel(), new POSTaggerME(model.getParserTaggerModel()), new ChunkerME(model.getParserChunkerModel()), model.getHeadRules(), beamSize, advancePercentage); } /** * Instantiates a {@link Parser} via a given {@code model}. * Uses the default implementations of {@link POSTaggerME} and {@link ChunkerME} * and default values for {@code beamSize} and {@code advancePercentage}. * * @param model The {@link ParserModel} to use. * * @throws IllegalStateException Thrown if the {@link ParserType} is not supported. * * @see ParserModel * @see POSTaggerME * @see ChunkerME */ public Parser(ParserModel model) { this(model, defaultBeamSize, defaultAdvancePercentage); } /** * Instantiates a {@link Parser} via a given {@code model} and other configuration parameters. * * @param buildModel A valid {@link MaxentModel} used to build. * @param checkModel A valid {@link MaxentModel} used to check. * @param tagger A valid {@link POSModel} used to tag. * @param chunker A valid {@link ChunkerModel} used to chunk. * @param headRules The {@link HeadRules} for head word percolation. * @param beamSize The number of different parses kept during parsing. * @param advancePercentage The minimal amount of probability mass which advanced outcomes * must represent. Only outcomes which contribute to the top * {@code advancePercentage} will be explored. * @see POSTagger * @see Chunker */ private Parser(MaxentModel buildModel, MaxentModel attachModel, MaxentModel checkModel, POSTagger tagger, Chunker chunker, HeadRules headRules, int beamSize, double advancePercentage) { super(tagger,chunker,headRules,beamSize,advancePercentage); this.buildModel = buildModel; this.attachModel = attachModel; this.checkModel = checkModel; this.buildContextGenerator = new BuildContextGenerator(); this.attachContextGenerator = new AttachContextGenerator(punctSet); this.checkContextGenerator = new CheckContextGenerator(punctSet); this.bprobs = new double[buildModel.getNumOutcomes()]; this.aprobs = new double[attachModel.getNumOutcomes()]; this.cprobs = new double[checkModel.getNumOutcomes()]; this.doneIndex = buildModel.getIndex(DONE); this.sisterAttachIndex = attachModel.getIndex(ATTACH_SISTER); this.daughterAttachIndex = attachModel.getIndex(ATTACH_DAUGHTER); this.nonAttachIndex = attachModel.getIndex(NON_ATTACH); attachments = new int[] {daughterAttachIndex,sisterAttachIndex}; this.completeIndex = checkModel.getIndex(Parser.COMPLETE); } /** * Returns the right frontier of the specified {@link Parse tree} with nodes ordered from deepest * to shallowest. * * @param root The {@link Parse root} of the parse tree. * @param punctSet A set of punctuation symbols to be used. * @return The right frontier of the specified parse tree. */ public static List getRightFrontier(Parse root, Set punctSet) { List rf = new LinkedList<>(); Parse top; if (AbstractBottomUpParser.TOP_NODE.equals(root.getType()) || AbstractBottomUpParser.INC_NODE.equals(root.getType())) { top = collapsePunctuation(root.getChildren(),punctSet)[0]; } else { top = root; } while (!top.isPosTag()) { rf.add(0,top); Parse[] kids = top.getChildren(); top = kids[kids.length - 1]; } return new ArrayList<>(rf); } private void setBuilt(Parse p) { String l = p.getLabel(); if (l == null) { p.setLabel(Parser.BUILT); } else { if (isComplete(p)) { p.setLabel(Parser.BUILT + "." + Parser.COMPLETE); } else { p.setLabel(Parser.BUILT + "." + Parser.INCOMPLETE); } } } private void setComplete(Parse p) { String l = p.getLabel(); if (!isBuilt(p)) { p.setLabel(Parser.COMPLETE); } else { p.setLabel(Parser.BUILT + "." + Parser.COMPLETE); } } private void setIncomplete(Parse p) { if (!isBuilt(p)) { p.setLabel(Parser.INCOMPLETE); } else { p.setLabel(Parser.BUILT + "." + Parser.INCOMPLETE); } } private boolean isBuilt(Parse p) { String l = p.getLabel(); return l != null && l.startsWith(Parser.BUILT); } private boolean isComplete(Parse p) { String l = p.getLabel(); return l != null && l.endsWith(Parser.COMPLETE); } @Override protected Parse[] advanceChunks(Parse p, double minChunkScore) { Parse[] parses = super.advanceChunks(p, minChunkScore); for (Parse parse : parses) { Parse[] chunks = parse.getChildren(); for (Parse chunk : chunks) { setComplete(chunk); } } return parses; } @Override protected Parse[] advanceParses(Parse p, double probMass) { double q = 1 - probMass; /* The index of the node which will be labeled in this iteration of advancing the parse. */ int advanceNodeIndex; /* The node which will be labeled in this iteration of advancing the parse. */ Parse advanceNode = null; Parse[] originalChildren = p.getChildren(); Parse[] children = collapsePunctuation(originalChildren,punctSet); int numNodes = children.length; if (numNodes == 0) { return null; } else if (numNodes == 1) { //put sentence initial and final punct in top node if (children[0].isPosTag()) { return null; } else { p.expandTopNode(children[0]); return new Parse[] { p }; } } //determines which node needs to adanced. for (advanceNodeIndex = 0; advanceNodeIndex < numNodes; advanceNodeIndex++) { advanceNode = children[advanceNodeIndex]; if (!isBuilt(advanceNode)) { break; } } int originalZeroIndex = mapParseIndex(0,children,originalChildren); int originalAdvanceIndex = mapParseIndex(advanceNodeIndex,children,originalChildren); List newParsesList = new ArrayList<>(); //call build model buildModel.eval(buildContextGenerator.getContext(children, advanceNodeIndex), bprobs); double doneProb = bprobs[doneIndex]; if (logger.isDebugEnabled()) logger.debug("adi={} {}.{} {} choose build={} attach={}", advanceNodeIndex, advanceNode.getType(), advanceNode.getLabel(), advanceNode, (1 - doneProb), doneProb); if (1 - doneProb > q) { double bprobSum = 0; while (bprobSum < probMass) { /* The largest unadvanced labeling. */ int max = 0; for (int pi = 1; pi < bprobs.length; pi++) { //for each build outcome if (bprobs[pi] > bprobs[max]) { max = pi; } } if (bprobs[max] == 0) { break; } double bprob = bprobs[max]; bprobs[max] = 0; //zero out so new max can be found bprobSum += bprob; String tag = buildModel.getOutcome(max); if (!tag.equals(DONE)) { Parse newParse1 = (Parse) p.clone(); Parse newNode = new Parse(p.getText(),advanceNode.getSpan(),tag,bprob,advanceNode.getHead()); newParse1.insert(newNode); newParse1.addProb(StrictMath.log(bprob)); newParsesList.add(newParse1); if (checkComplete) { cprobs = checkModel.eval(checkContextGenerator.getContext(newNode, children, advanceNodeIndex,false)); if (logger.isDebugEnabled()) logger.debug("building {} {} c={}", tag, bprob, cprobs[completeIndex]); if (cprobs[completeIndex] > probMass) { //just complete advances setComplete(newNode); newParse1.addProb(StrictMath.log(cprobs[completeIndex])); if (logger.isDebugEnabled()) logger.debug("Only advancing complete node"); } else if (1 - cprobs[completeIndex] > probMass) { //just incomplete advances setIncomplete(newNode); newParse1.addProb(StrictMath.log(1 - cprobs[completeIndex])); if (logger.isDebugEnabled()) logger.debug("Only advancing incomplete node"); } else { //both complete and incomplete advance if (logger.isDebugEnabled()) logger.debug("Advancing both complete and incomplete nodes"); setComplete(newNode); newParse1.addProb(StrictMath.log(cprobs[completeIndex])); Parse newParse2 = (Parse) p.clone(); Parse newNode2 = new Parse(p.getText(),advanceNode.getSpan(),tag,bprob,advanceNode.getHead()); newParse2.insert(newNode2); newParse2.addProb(StrictMath.log(bprob)); newParsesList.add(newParse2); newParse2.addProb(StrictMath.log(1 - cprobs[completeIndex])); setIncomplete(newNode2); //set incomplete for non-clone } } else { if (logger.isDebugEnabled()) logger.debug("building {} {}", tag, bprob); } } } } //advance attaches if (doneProb > q) { Parse newParse1 = (Parse) p.clone(); //clone parse //mark nodes as built if (checkComplete) { if (isComplete(advanceNode)) { //replace constituent being labeled to create new derivation newParse1.setChild(originalAdvanceIndex,Parser.BUILT + "." + Parser.COMPLETE); } else { //replace constituent being labeled to create new derivation newParse1.setChild(originalAdvanceIndex,Parser.BUILT + "." + Parser.INCOMPLETE); } } else { //replace constituent being labeled to create new derivation newParse1.setChild(originalAdvanceIndex,Parser.BUILT); } newParse1.addProb(StrictMath.log(doneProb)); if (advanceNodeIndex == 0) { //no attach if first node. newParsesList.add(newParse1); } else { List rf = getRightFrontier(p,punctSet); for (int fi = 0,fs = rf.size(); fi < fs; fi++) { Parse fn = rf.get(fi); attachModel.eval(attachContextGenerator.getContext(children, advanceNodeIndex, rf, fi), aprobs); if (logger.isDebugEnabled()) { // List cs = java.util.Arrays.asList(attachContextGenerator.getContext(children, // advanceNodeIndex,rf,fi,punctSet)); logger.debug("Frontier node({}): {}.{} {} <- {} {} d={} s={} ", fi, fn.getType(), fn.getLabel(), fn, advanceNode.getType(), advanceNode, aprobs[daughterAttachIndex], aprobs[sisterAttachIndex]); } for (int attachment : attachments) { double prob = aprobs[attachment]; //should we try an attach if p > threshold and // if !checkComplete then prevent daughter attaching to chunk // if checkComplete then prevent daughter attacing to complete node or // sister attaching to an incomplete node if (prob > q && ( (!checkComplete && (attachment != daughterAttachIndex || !isComplete(fn))) || (checkComplete && ((attachment == daughterAttachIndex && !isComplete(fn)) || (attachment == sisterAttachIndex && isComplete(fn)))))) { Parse newParse2 = newParse1.cloneRoot(fn, originalZeroIndex); Parse[] newKids = Parser.collapsePunctuation(newParse2.getChildren(), punctSet); //remove node from top level since were going to attach it (including punct) for (int ri = originalZeroIndex + 1; ri <= originalAdvanceIndex; ri++) { if (logger.isTraceEnabled()) { logger.trace("{}-removing {} {}", ri, (originalZeroIndex + 1), newParse2.getChildren()[originalZeroIndex + 1]); } newParse2.remove(originalZeroIndex + 1); } List crf = getRightFrontier(newParse2, punctSet); Parse updatedNode; if (attachment == daughterAttachIndex) { //attach daughter updatedNode = crf.get(fi); updatedNode.add(advanceNode, headRules); } else { //attach sister Parse psite; if (fi + 1 < crf.size()) { psite = crf.get(fi + 1); updatedNode = psite.adjoin(advanceNode, headRules); } else { psite = newParse2; updatedNode = psite.adjoinRoot(advanceNode, headRules, originalZeroIndex); newKids[0] = updatedNode; } } //update spans affected by attachment for (int ni = fi + 1; ni < crf.size(); ni++) { Parse node = crf.get(ni); node.updateSpan(); } //if (debugOn) {System.out.print(ai+"-result: ");newParse2.show();System.out.println();} newParse2.addProb(StrictMath.log(prob)); newParsesList.add(newParse2); if (checkComplete) { cprobs = checkModel.eval( checkContextGenerator.getContext(updatedNode, newKids, advanceNodeIndex, true)); if (cprobs[completeIndex] > probMass) { setComplete(updatedNode); newParse2.addProb(StrictMath.log(cprobs[completeIndex])); if (logger.isDebugEnabled()) logger.debug("Only advancing complete node"); } else if (1 - cprobs[completeIndex] > probMass) { setIncomplete(updatedNode); newParse2.addProb(StrictMath.log(1 - cprobs[completeIndex])); if (logger.isDebugEnabled()) logger.debug("Only advancing incomplete node"); } else { setComplete(updatedNode); Parse newParse3 = newParse2.cloneRoot(updatedNode, originalZeroIndex); newParse3.addProb(StrictMath.log(cprobs[completeIndex])); newParsesList.add(newParse3); setIncomplete(updatedNode); newParse2.addProb(StrictMath.log(1 - cprobs[completeIndex])); if (logger.isDebugEnabled()) logger.debug("Advancing both complete and incomplete nodes; c={}", cprobs[completeIndex]); } } } else { if (logger.isDebugEnabled()) logger.debug("Skipping {}.{} {} daughter={} complete={} prob={}", fn.getType(), fn.getLabel(), fn, (attachment == daughterAttachIndex), isComplete(fn), prob); } } if (checkComplete && !isComplete(fn)) { if (logger.isDebugEnabled()) logger.debug("Stopping at incomplete node({}): {} . {} {}", fi, fn.getType(), fn.getLabel(), fn); break; } } } } Parse[] newParses = new Parse[newParsesList.size()]; newParsesList.toArray(newParses); return newParses; } @Override protected void advanceTop(Parse p) { p.setType(TOP_NODE); } /** * Starts a training of a {@link ParserModel}. * * @param languageCode An ISO conform language code. * @param parseSamples The {@link ObjectStream samples} as input. * @param rules The {@link HeadRules} to use. * @param mlParams The {@link TrainingParameters parameters} for training. * @return A valid {@link ParserModel}. * @throws IOException Thrown if IO errors occurred during training. */ public static ParserModel train(String languageCode, ObjectStream parseSamples, HeadRules rules, TrainingParameters mlParams) throws IOException { Map manifestInfoEntries = new HashMap<>(); logger.info("Building dictionary"); Dictionary mdict = buildDictionary(parseSamples, rules, mlParams); parseSamples.reset(); // tag POSModel posModel = POSTaggerME.train(languageCode, new PosSampleStream( parseSamples), mlParams.getParameters("tagger"), new POSTaggerFactory()); parseSamples.reset(); // chunk ChunkerModel chunkModel = ChunkerME.train(languageCode, new ChunkSampleStream( parseSamples), mlParams.getParameters("chunker"), new ParserChunkerFactory()); parseSamples.reset(); // build logger.info("Training builder"); ObjectStream bes = new ParserEventStream(parseSamples, rules, ParserEventTypeEnum.BUILD, mdict); Map buildReportMap = new HashMap<>(); EventTrainer buildTrainer = TrainerFactory.getEventTrainer( mlParams.getParameters("build"), buildReportMap); MaxentModel buildModel = buildTrainer.train(bes); opennlp.tools.parser.chunking.Parser.mergeReportIntoManifest( manifestInfoEntries, buildReportMap, "build"); parseSamples.reset(); // check logger.info("Training checker"); ObjectStream kes = new ParserEventStream(parseSamples, rules, ParserEventTypeEnum.CHECK); Map checkReportMap = new HashMap<>(); EventTrainer checkTrainer = TrainerFactory.getEventTrainer( mlParams.getParameters("check"), checkReportMap); MaxentModel checkModel = checkTrainer.train(kes); opennlp.tools.parser.chunking.Parser.mergeReportIntoManifest( manifestInfoEntries, checkReportMap, "check"); parseSamples.reset(); // attach logger.info("Training attacher"); ObjectStream attachEvents = new ParserEventStream(parseSamples, rules, ParserEventTypeEnum.ATTACH); Map attachReportMap = new HashMap<>(); EventTrainer attachTrainer = TrainerFactory.getEventTrainer( mlParams.getParameters("attach"), attachReportMap); MaxentModel attachModel = attachTrainer.train(attachEvents); opennlp.tools.parser.chunking.Parser.mergeReportIntoManifest( manifestInfoEntries, attachReportMap, "attach"); return new ParserModel(languageCode, buildModel, checkModel, attachModel, posModel, chunkModel, rules, ParserType.TREEINSERT, manifestInfoEntries); } /** * Starts a training of a {@link ParserModel}. * * @param languageCode An ISO conform language code. * @param parseSamples The {@link ObjectStream samples} as input. * @param rules The {@link HeadRules} to use. * @param iterations The number of iterations to be conducted. * @param cutoff The cut-off parameter to be used. * @return A valid {@link ParserModel}. * @throws IOException Thrown if IO errors occurred during training. */ public static ParserModel train(String languageCode, ObjectStream parseSamples, HeadRules rules, int iterations, int cutoff) throws IOException { TrainingParameters params = new TrainingParameters(); params.put("dict", TrainingParameters.CUTOFF_PARAM, cutoff); params.put("tagger", TrainingParameters.CUTOFF_PARAM, cutoff); params.put("tagger", TrainingParameters.ITERATIONS_PARAM, iterations); params.put("chunker", TrainingParameters.CUTOFF_PARAM, cutoff); params.put("chunker", TrainingParameters.ITERATIONS_PARAM, iterations); params.put("check", TrainingParameters.CUTOFF_PARAM, cutoff); params.put("check", TrainingParameters.ITERATIONS_PARAM, iterations); params.put("build", TrainingParameters.CUTOFF_PARAM, cutoff); params.put("build", TrainingParameters.ITERATIONS_PARAM, iterations); return train(languageCode, parseSamples, rules, params); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_treeinser0100644 0000000 0000000 00000000166 15217274217 032620 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/ParserEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/ParserEventStr0100644 0000000 0000000 00000036167 15217274217 034256 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.parser.treeinsert; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.model.Event; import opennlp.tools.parser.AbstractBottomUpParser; import opennlp.tools.parser.AbstractParserEventStream; import opennlp.tools.parser.HeadRules; import opennlp.tools.parser.Parse; import opennlp.tools.parser.ParserEventTypeEnum; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * Wrapper class for one of four {@link Parser built-attach parser} event streams. * The particular {@link ParserEventTypeEnum event type} is specified at construction. */ public class ParserEventStream extends AbstractParserEventStream { private static final Logger logger = LoggerFactory.getLogger(ParserEventStream.class); protected AttachContextGenerator attachContextGenerator; protected BuildContextGenerator buildContextGenerator; protected CheckContextGenerator checkContextGenerator; /** * Instantiates a {@link ParserEventStream} based on the specified data stream * of the {@link ParserEventTypeEnum type} using {@link HeadRules head rules}. * * @param d A 1-parse-per-line Penn Treebank Style parse. * @param rules The {@link HeadRules head rules} to use. * @param etype The {@link ParserEventTypeEnum type} of events desired. * @param dict A tri-gram {@link Dictionary} to reduce feature generation. * * @see ParserEventTypeEnum */ public ParserEventStream(ObjectStream d, HeadRules rules, ParserEventTypeEnum etype, Dictionary dict) { super(d, rules, etype, dict); } /** * Instantiates a {@link ParserEventStream} based on the specified data stream * of the {@link ParserEventTypeEnum type} using {@link HeadRules head rules}. * * @param d A 1-parse-per-line Penn Treebank Style parse. * @param rules The {@link HeadRules head rules} to use. * @param etype The {@link ParserEventTypeEnum type} of events desired. * * @see ParserEventTypeEnum */ public ParserEventStream(ObjectStream d, HeadRules rules, ParserEventTypeEnum etype) { super(d, rules, etype); } @Override public void init() { buildContextGenerator = new BuildContextGenerator(); attachContextGenerator = new AttachContextGenerator(punctSet); checkContextGenerator = new CheckContextGenerator(punctSet); } /** * Returns a map of parent nodes which consist of the immediate * parent of the specified {@link Parse node} and any of its parent which * share the same syntactic type. * * @param node The {@link Parse node} whose parents are to be returned. * @return A {@link Map} of parent {@link Parse nodes}. */ private Map getNonAdjoinedParent(Parse node) { Map parents = new HashMap<>(); Parse parent = node.getParent(); int index = indexOf(node,parent); parents.put(parent, index); while (parent.getType().equals(node.getType())) { node = parent; parent = parent.getParent(); index = indexOf(node,parent); parents.put(parent, index); } return parents; } private int indexOf(Parse child, Parse parent) { Parse[] kids = Parser.collapsePunctuation(parent.getChildren(),punctSet); for (int ki = 0; ki < kids.length; ki++) { if (child == kids[ki]) { return ki; } } return -1; } private int nonPunctChildCount(Parse node) { return Parser.collapsePunctuation(node.getChildren(),punctSet).length; } @Override protected boolean lastChild(Parse child, Parse parent) { boolean lc = super.lastChild(child, parent); while (!lc) { Parse cp = child.getParent(); if (cp != parent && cp.getType().equals(child.getType())) { lc = super.lastChild(cp,parent); child = cp; } else { break; } } return lc; } @Override protected void addParseEvents(List parseEvents, Parse[] chunks) { /* Frontier nodes built from node in a completed parse. Specifically, * they have all their children regardless of the stage of parsing.*/ List rightFrontier = new ArrayList<>(); List builtNodes = new ArrayList<>(); /* Nodes which characterize what the parse looks like to the parser as its being built. * Specifically, these nodes don't have all their children attached like the parents of * the chunk nodes do.*/ Parse[] currentChunks = new Parse[chunks.length]; for (int ci = 0; ci < chunks.length; ci++) { currentChunks[ci] = (Parse) chunks[ci].clone(); currentChunks[ci].setPrevPunctuation(chunks[ci].getPreviousPunctuationSet()); currentChunks[ci].setNextPunctuation(chunks[ci].getNextPunctuationSet()); currentChunks[ci].setLabel(Parser.COMPLETE); chunks[ci].setLabel(Parser.COMPLETE); } for (int ci = 0; ci < chunks.length; ci++) { Parse parent = chunks[ci].getParent(); Parse prevParent = chunks[ci]; int off = 0; //build un-built parents if (!chunks[ci].isPosTag()) { builtNodes.add(off++,chunks[ci]); } //perform build stages while (!parent.getType().equals(AbstractBottomUpParser.TOP_NODE) && parent.getLabel() == null) { if (!prevParent.getType().equals(parent.getType())) { //build level if (logger.isDebugEnabled()) { logger.debug("Build: {} for: {}", parent.getType(), currentChunks[ci]); } if (etype == ParserEventTypeEnum.BUILD) { parseEvents.add(new Event(parent.getType(), buildContextGenerator.getContext(currentChunks, ci))); } builtNodes.add(off++,parent); Parse newParent = new Parse(currentChunks[ci].getText(), currentChunks[ci].getSpan(),parent.getType(),1,0); newParent.add(currentChunks[ci],rules); newParent.setPrevPunctuation(currentChunks[ci].getPreviousPunctuationSet()); newParent.setNextPunctuation(currentChunks[ci].getNextPunctuationSet()); currentChunks[ci].setParent(newParent); currentChunks[ci] = newParent; newParent.setLabel(Parser.BUILT); //see if chunk is complete if (lastChild(chunks[ci], parent)) { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.COMPLETE, checkContextGenerator.getContext(currentChunks[ci],currentChunks, ci,false))); } currentChunks[ci].setLabel(Parser.COMPLETE); parent.setLabel(Parser.COMPLETE); } else { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.INCOMPLETE, checkContextGenerator.getContext(currentChunks[ci],currentChunks,ci,false))); } currentChunks[ci].setLabel(Parser.INCOMPLETE); parent.setLabel(Parser.COMPLETE); } chunks[ci] = parent; } //TODO: Consider whether we need to set this label or train parses at all. parent.setLabel(Parser.BUILT); prevParent = parent; parent = parent.getParent(); } //decide to attach if (etype == ParserEventTypeEnum.BUILD) { parseEvents.add(new Event(Parser.DONE, buildContextGenerator.getContext(currentChunks, ci))); } //attach node String attachType = null; /* Node selected for attachment. */ Parse attachNode = null; int attachNodeIndex = -1; if (ci == 0) { Parse top = new Parse(currentChunks[ci].getText(), new Span(0,currentChunks[ci].getText().length()),AbstractBottomUpParser.TOP_NODE,1,0); top.insert(currentChunks[ci]); } else { /* Right frontier consisting of partially-built nodes based on current state of the parse.*/ List currentRightFrontier = Parser.getRightFrontier(currentChunks[0],punctSet); if (currentRightFrontier.size() != rightFrontier.size()) { logger.error("Frontiers mis-aligned: {} != {} {} {}", currentRightFrontier.size(), rightFrontier.size(), currentRightFrontier, rightFrontier); System.exit(1); } Map parents = getNonAdjoinedParent(chunks[ci]); //try daughters first. for (int cfi = 0; cfi < currentRightFrontier.size(); cfi++) { Parse frontierNode = rightFrontier.get(cfi); Parse cfn = currentRightFrontier.get(cfi); if (!Parser.checkComplete || !Parser.COMPLETE.equals(cfn.getLabel())) { Integer i = parents.get(frontierNode); if (logger.isDebugEnabled()) logger.debug("Looking at attachment site ({}): {} ci={} cs={}, {} :for {} {} -> {}", cfi, cfn.getType(), i, nonPunctChildCount(cfn), cfn, currentChunks[ci].getType(), currentChunks[ci], parents ); if (attachNode == null && i != null && i == nonPunctChildCount(cfn)) { attachType = Parser.ATTACH_DAUGHTER; attachNodeIndex = cfi; attachNode = cfn; if (etype == ParserEventTypeEnum.ATTACH) { parseEvents.add(new Event(attachType, attachContextGenerator.getContext(currentChunks, ci, currentRightFrontier, attachNodeIndex))); } } } else { if (logger.isDebugEnabled()) logger.debug("Skipping ({}): {},{} {} :for {} {} -> {}", cfi, cfn.getType(), cfn.getPreviousPunctuationSet(), cfn, currentChunks[ci].getType(), currentChunks[ci], parents); } // Can't attach past first incomplete node. if (Parser.checkComplete && cfn.getLabel().equals(Parser.INCOMPLETE)) { if (logger.isDebugEnabled()) logger.debug("breaking on incomplete: {} {}", cfn.getType(), cfn); break; } } //try sisters, and generate non-attach events. for (int cfi = 0; cfi < currentRightFrontier.size(); cfi++) { Parse frontierNode = rightFrontier.get(cfi); Parse cfn = currentRightFrontier.get(cfi); if (attachNode == null && parents.containsKey(frontierNode.getParent()) && frontierNode.getType().equals(frontierNode.getParent().getType()) ) { //&& frontierNode.getParent().getLabel() == null) { attachType = Parser.ATTACH_SISTER; attachNode = cfn; attachNodeIndex = cfi; if (etype == ParserEventTypeEnum.ATTACH) { parseEvents.add(new Event(Parser.ATTACH_SISTER, attachContextGenerator.getContext(currentChunks, ci, currentRightFrontier, cfi))); } chunks[ci].getParent().setLabel(Parser.BUILT); } else if (cfi == attachNodeIndex) { //skip over previously attached daughter. } else { if (etype == ParserEventTypeEnum.ATTACH) { parseEvents.add(new Event(Parser.NON_ATTACH, attachContextGenerator.getContext(currentChunks, ci, currentRightFrontier, cfi))); } } //Can't attach past first incomplete node. if (Parser.checkComplete && cfn.getLabel().equals(Parser.INCOMPLETE)) { if (logger.isDebugEnabled()) logger.debug("breaking on incomplete: {} {}", cfn.getType(), cfn); break; } } //attach Node if (attachNode != null) { if (Parser.ATTACH_DAUGHTER.equals(attachType)) { Parse daughter = currentChunks[ci]; if (logger.isDebugEnabled()) logger.debug("daughter attach a={}:{} d={} com={}", attachNode.getType(), attachNode, daughter, lastChild(chunks[ci], rightFrontier.get(attachNodeIndex))); attachNode.add(daughter,rules); daughter.setParent(attachNode); if (lastChild(chunks[ci], rightFrontier.get(attachNodeIndex))) { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.COMPLETE, checkContextGenerator.getContext(attachNode,currentChunks,ci,true))); } attachNode.setLabel(Parser.COMPLETE); } else { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.INCOMPLETE, checkContextGenerator.getContext(attachNode,currentChunks,ci,true))); } } } else if (Parser.ATTACH_SISTER.equals(attachType)) { Parse frontierNode = rightFrontier.get(attachNodeIndex); rightFrontier.set(attachNodeIndex,frontierNode.getParent()); Parse sister = currentChunks[ci]; if (logger.isDebugEnabled()) logger.debug("sister attach a={}:{} s={} ap={} com={}", attachNode.getType(), attachNode, sister, attachNode.getParent(), lastChild(chunks[ci], rightFrontier.get(attachNodeIndex))); Parse newParent = attachNode.getParent().adjoin(sister,rules); newParent.setParent(attachNode.getParent()); attachNode.setParent(newParent); sister.setParent(newParent); if (attachNode == currentChunks[0]) { currentChunks[0] = newParent; } if (lastChild(chunks[ci], rightFrontier.get(attachNodeIndex))) { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.COMPLETE, checkContextGenerator.getContext(newParent,currentChunks,ci,true))); } newParent.setLabel(Parser.COMPLETE); } else { if (etype == ParserEventTypeEnum.CHECK) { parseEvents.add(new Event(Parser.INCOMPLETE, checkContextGenerator.getContext(newParent,currentChunks,ci,true))); } newParent.setLabel(Parser.INCOMPLETE); } } //update right frontier for (int ni = 0; ni < attachNodeIndex; ni++) { rightFrontier.remove(0); } } else { throw new RuntimeException("No Attachment: " + chunks[ci]); } } rightFrontier.addAll(0,builtNodes); builtNodes.clear(); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_parser_treeinser0100644 0000000 0000000 00000000161 15217274217 032613 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/package-info.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/parser/treeinsert/package-info.j0100644 0000000 0000000 00000001700 15217274217 034064 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package containing experimental code for performing full syntactic * parsing using attachment decisions. */ package opennlp.tools.parser.treeinsert; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_Configura0100644 0000000 0000000 00000000171 15217274217 032532 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/ConfigurablePOSContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/ConfigurablePOSContextGen0100644 0000000 0000000 00000007564 15217274217 034124 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.util.ArrayList; import java.util.List; import java.util.Objects; import opennlp.tools.util.Cache; import opennlp.tools.util.featuregen.AdaptiveFeatureGenerator; /** * A configurable {@link POSContextGenerator context generator} for a {@link POSTagger}. * This implementation makes use of {@link AdaptiveFeatureGenerator}. * * @see POSTagger * @see POSTaggerME * @see DefaultPOSContextGenerator */ public class ConfigurablePOSContextGenerator implements POSContextGenerator { private Cache contextsCache; private Object wordsKey; private final AdaptiveFeatureGenerator featureGenerator; /** * Initializes a {@link ConfigurablePOSContextGenerator} instance. * A cache size of {@code 0} will be used as default. * * @param featureGenerator The {@link AdaptiveFeatureGenerator} to be used. */ public ConfigurablePOSContextGenerator(AdaptiveFeatureGenerator featureGenerator) { this(0, featureGenerator); } /** * Initializes a {@link ConfigurablePOSContextGenerator} instance. * * @param cacheSize The size of the {@link Cache} to set. * Must be greater than {@code 0} to have an effect. * @param featureGenerator The {@link AdaptiveFeatureGenerator} to be used. */ public ConfigurablePOSContextGenerator(int cacheSize, AdaptiveFeatureGenerator featureGenerator) { this.featureGenerator = Objects.requireNonNull(featureGenerator, "featureGenerator must not be null"); if (cacheSize > 0) { contextsCache = new Cache<>(cacheSize); } } /** * Returns the context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. * * @param index The index of the token for which the context is provided. * @param tokens The tokens representing a sentence. * @param tags The tags assigned to the previous words in the sentence. * @param additionalContext The context for additional information. * * @return The context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. */ @Override public String[] getContext(int index, String[] tokens, String[] tags, Object[] additionalContext) { String tagprev = null; String tagprevprev = null; if (index - 1 >= 0) { tagprev = tags[index - 1]; if (index - 2 >= 0) { tagprevprev = tags[index - 2]; } } String cacheKey = index + tagprev + tagprevprev; if (contextsCache != null) { if (wordsKey == tokens) { String[] cachedContexts = contextsCache.get(cacheKey); if (cachedContexts != null) { return cachedContexts; } } else { contextsCache.clear(); wordsKey = tokens; } } List e = new ArrayList<>(); featureGenerator.createFeatures(e, tokens, index, tags); String[] contexts = e.toArray(new String[0]); if (contextsCache != null) { contextsCache.put(cacheKey, contexts); } return contexts; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_DefaultPO0100644 0000000 0000000 00000000164 15217274217 032442 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/DefaultPOSContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/DefaultPOSContextGenerato0100644 0000000 0000000 00000015305 15217274217 034133 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.util.Cache; import opennlp.tools.util.StringList; /** * A default {@link POSContextGenerator context generator} for a {@link POSTagger}. * * @see POSTagger * @see POSTaggerME */ public class DefaultPOSContextGenerator implements POSContextGenerator { protected final String SE = "*SE*"; protected final String SB = "*SB*"; private static final int PREFIX_LENGTH = 4; private static final int SUFFIX_LENGTH = 4; private static final Pattern hasCap = Pattern.compile("[A-Z]"); private static final Pattern hasNum = Pattern.compile("[0-9]"); private Cache contextsCache; private Object wordsKey; private final Dictionary dict; /** * Initializes a {@link DefaultPOSContextGenerator} instance. * A cache size of {@code 0} will be used as default. * * @param dict The {@link Dictionary} to be used. */ public DefaultPOSContextGenerator(Dictionary dict) { this(0,dict); } /** * Initializes a {@link DefaultPOSContextGenerator} instance. * * @param cacheSize The size of the {@link Cache} to set. * Must be greater than {@code 0} to have an effect. * @param dict The {@link Dictionary} to be used. */ public DefaultPOSContextGenerator(int cacheSize, Dictionary dict) { this.dict = dict; if (cacheSize > 0) { contextsCache = new Cache<>(cacheSize); } } protected static String[] getPrefixes(String lex) { String[] prefs = new String[PREFIX_LENGTH]; for (int li = 0; li < PREFIX_LENGTH; li++) { prefs[li] = lex.substring(0, StrictMath.min(li + 1, lex.length())); } return prefs; } protected static String[] getSuffixes(String lex) { String[] suffs = new String[SUFFIX_LENGTH]; for (int li = 0; li < SUFFIX_LENGTH; li++) { suffs[li] = lex.substring(StrictMath.max(lex.length() - li - 1, 0)); } return suffs; } /** * Returns the context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. * * @param index The index of the token for which the context is provided. * @param sequence The token sequence representing a sentence. * @param priorDecisions The tags assigned to the previous words in the sentence. * @param additionalContext The context for additional information. * * @return The context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. */ @Override public String[] getContext(int index, String[] sequence, String[] priorDecisions, Object[] additionalContext) { return getContext(index,sequence,priorDecisions); } /** * Returns the context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. * * @param index The index of the token for which the context is provided. * @param tokens The tokens representing a sentence. * @param tags The tags assigned to the previous words in the sentence. * * @return The context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. */ public String[] getContext(int index, Object[] tokens, String[] tags) { String next, nextnext = null, lex, prev, prevprev = null; String tagprev, tagprevprev; tagprev = tagprevprev = null; lex = tokens[index].toString(); if (tokens.length > index + 1) { next = tokens[index + 1].toString(); if (tokens.length > index + 2) nextnext = tokens[index + 2].toString(); else nextnext = SE; // Sentence End } else { next = SE; // Sentence End } if (index - 1 >= 0) { prev = tokens[index - 1].toString(); tagprev = tags[index - 1]; if (index - 2 >= 0) { prevprev = tokens[index - 2].toString(); tagprevprev = tags[index - 2]; } else { prevprev = SB; // Sentence Beginning } } else { prev = SB; // Sentence Beginning } String cacheKey = index + tagprev + tagprevprev; if (contextsCache != null) { if (wordsKey == tokens) { String[] cachedContexts = contextsCache.get(cacheKey); if (cachedContexts != null) { return cachedContexts; } } else { contextsCache.clear(); wordsKey = tokens; } } List e = new ArrayList<>(); e.add("default"); // add the word itself e.add("w=" + lex); if (dict == null || !dict.contains(new StringList(lex))) { // do some basic suffix analysis String[] suffs = getSuffixes(lex); for (String suff : suffs) { e.add("suf=" + suff); } String[] prefs = getPrefixes(lex); for (String pref : prefs) { e.add("pre=" + pref); } // see if the word has any special characters if (lex.indexOf('-') != -1) { e.add("h"); } if (hasCap.matcher(lex).find()) { e.add("c"); } if (hasNum.matcher(lex).find()) { e.add("d"); } } // add the words and pos's of the surrounding context if (prev != null) { e.add("p=" + prev); if (tagprev != null) { e.add("t=" + tagprev); } if (prevprev != null) { e.add("pp=" + prevprev); if (tagprevprev != null) { e.add("t2=" + tagprevprev + "," + tagprev); } } } if (next != null) { e.add("n=" + next); if (nextnext != null) { e.add("nn=" + nextnext); } } String[] contexts = e.toArray(new String[0]); if (contextsCache != null) { contextsCache.put(cacheKey,contexts); } return contexts; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_DefaultPO0100644 0000000 0000000 00000000165 15217274217 032443 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/DefaultPOSSequenceValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/DefaultPOSSequenceValidat0100644 0000000 0000000 00000003174 15217274217 034100 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.util.Arrays; import opennlp.tools.util.SequenceValidator; /** * The default POS tagger {@link SequenceValidator} implementation. */ public class DefaultPOSSequenceValidator implements SequenceValidator { private final TagDictionary tagDictionary; /** * @param tagDictionary A {@link TagDictionary} used for the new {@link SequenceValidator}. */ public DefaultPOSSequenceValidator(TagDictionary tagDictionary) { this.tagDictionary = tagDictionary; } @Override public boolean validSequence(int i, String[] inputSequence, String[] outcomesSequence, String outcome) { if (tagDictionary == null) { return true; } else { String[] tags = tagDictionary.getTags(inputSequence[i]); return tags == null || Arrays.asList(tags).contains(outcome); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_MutableTa0100644 0000000 0000000 00000000156 15217274217 032476 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/MutableTagDictionary.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/MutableTagDictionary.java0100644 0000000 0000000 00000003043 15217274217 034122 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; /** * Interface that allows {@link TagDictionary} entries to be added and removed. * This can be used to induce the dictionary from training data. */ public interface MutableTagDictionary extends TagDictionary { /** * Associates the specified tags with the specified word. If the dictionary * previously contained keys for the word, the old tags are replaced by the * specified tags. * * @param word * word with which the specified tags is to be associated * @param tags * tags to be associated with the specified word * * @return the previous tags associated with the word, or null if there was no * mapping for word. */ String[] put(String word, String... tags); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSContextGenerator.java0100644 0000000 0000000 00000003371 15217274217 033730 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import opennlp.tools.util.BeamSearchContextGenerator; /** * Interface for a {@link BeamSearchContextGenerator} used in POS tagging. */ public interface POSContextGenerator extends BeamSearchContextGenerator { /** * Returns the context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. * * @param index The index of the token for which the context is provided. * @param tokens The token sequence representing a sentence. * @param prevTags The tags assigned to the previous words in the sentence. * @param additionalContext The context for additional information. * * @return The context for making a postag decision at the specified token {@code index} * given the specified {@code tokens} and previous {@code tags}. */ String[] getContext(int index, String[] tokens, String[] prevTags, Object[] additionalContext); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSDictionary.java0100644 0000000 0000000 00000016453 15217274217 032547 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Objects; import opennlp.tools.dictionary.serializer.Attributes; import opennlp.tools.dictionary.serializer.DictionaryEntryPersistor; import opennlp.tools.dictionary.serializer.Entry; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.StringList; import opennlp.tools.util.StringUtil; import opennlp.tools.util.model.SerializableArtifact; /** * Provides a means of determining which tags are valid for a particular word * based on a {@link TagDictionary} read from a file. */ public class POSDictionary implements Iterable, MutableTagDictionary, SerializableArtifact { private Map dictionary; private boolean caseSensitive = true; /** * Initializes an empty case sensitive {@link POSDictionary}. */ public POSDictionary() { this(true); } /** * Initializes an empty {@link POSDictionary}. * * @param caseSensitive {@code true} if the {@link POSDictionary} is case sensitive, * {@code false} otherwise. */ public POSDictionary(boolean caseSensitive) { dictionary = new HashMap<>(); this.caseSensitive = caseSensitive; } /** * Returns a list of valid tags for the specified {@code word}. * * @param word The word. * * @return An array of valid tags for the specified word or * {@code null} if no information is available for that word. */ public String[] getTags(String word) { if (caseSensitive) { return dictionary.get(word); } else { return dictionary.get(StringUtil.toLowerCase(word)); } } /** * Retrieves an {@link Iterator} over all words in the dictionary. */ public Iterator iterator() { return dictionary.keySet().iterator(); } private static String tagsToString(String[] tags) { StringBuilder tagString = new StringBuilder(); for (String tag : tags) { tagString.append(tag); tagString.append(' '); } // remove last space if (tagString.length() > 0) { tagString.setLength(tagString.length() - 1); } return tagString.toString(); } /** * Writes the {@link POSDictionary} to the given {@link OutputStream}; *

* After the serialization is finished the provided * {@link OutputStream} remains open. * * @param out * the {@link OutputStream} to write the dictionary into. * * @throws IOException * Throw if writing to the {@link OutputStream} fails */ public void serialize(OutputStream out) throws IOException { Iterator entries = new Iterator<>() { final Iterator iterator = dictionary.keySet().iterator(); public boolean hasNext() { return iterator.hasNext(); } public Entry next() { String word = iterator.next(); Attributes tagAttribute = new Attributes(); tagAttribute.setValue("tags", tagsToString(getTags(word))); return new Entry(new StringList(word), tagAttribute); } public void remove() { throw new UnsupportedOperationException(); } }; DictionaryEntryPersistor.serialize(out, entries, caseSensitive); } @Override public int hashCode() { int[] keyHashes = new int[dictionary.size()]; int[] valueHashes = new int[dictionary.size()]; int i = 0; for (String word : this) { keyHashes[i] = word.hashCode(); valueHashes[i] = Arrays.hashCode(getTags(word)); i++; } Arrays.sort(keyHashes); Arrays.sort(valueHashes); return Objects.hash(Arrays.hashCode(keyHashes), Arrays.hashCode(valueHashes)); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof POSDictionary posDictionary) { if (this.dictionary.size() == posDictionary.dictionary.size()) { for (String word : this) { if (!Arrays.equals(getTags(word), posDictionary.getTags(word))) { return false; } } return true; } } return false; } @Override public String toString() { // it is time-consuming to output the dictionary entries. // will output something meaningful for debugging, like // POSDictionary{size=100, caseSensitive=true} return "POSDictionary{size=" + dictionary.size() + ", caseSensitive=" + this.caseSensitive + "}"; } /** * Creates a new {@link POSDictionary} from an {@link InputStream}. *

* After creation is finished the provided {@link InputStream} is closed. * * @param in The {@link InputStream} used for creating the {@link POSDictionary}. * The stream must be open and have bytes available to read from. * * @return A valid {@link POSDictionary} instance. * * @throws IOException Thrown if IO errors occurred during creation. * @throws InvalidFormatException Thrown if the entries don't have exactly one token. */ public static POSDictionary create(InputStream in) throws IOException { final POSDictionary newPosDict = new POSDictionary(); boolean isCaseSensitive = DictionaryEntryPersistor.create(in, entry -> { String tagString = entry.attributes().getValue("tags"); String[] tags = tagString.split(" "); StringList word = entry.tokens(); if (word.size() != 1) throw new InvalidFormatException("Each entry must have exactly one token! " + word); newPosDict.dictionary.put(word.getToken(0), tags); }); newPosDict.caseSensitive = isCaseSensitive; // TODO: The dictionary API needs to be improved to do this better! if (!isCaseSensitive) { Map lowerCasedDictionary = new HashMap<>(); for (Map.Entry entry : newPosDict.dictionary.entrySet()) { lowerCasedDictionary.put(StringUtil.toLowerCase(entry.getKey()), entry.getValue()); } newPosDict.dictionary = lowerCasedDictionary; } return newPosDict; } @Override public String[] put(String word, String... tags) { if (this.caseSensitive) { return dictionary.put(word, tags); } else { return dictionary.put(StringUtil.toLowerCase(word), tags); } } @Override public boolean isCaseSensitive() { return this.caseSensitive; } @Override public Class getArtifactSerializerClass() { return POSTaggerFactory.POSDictionarySerializer.class; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSEvaluator.java0100644 0000000 0000000 00000005676 15217274217 032411 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.Mean; /** * The {@link POSEvaluator} measures the performance of the given {@link POSTagger} * with the provided reference {@link POSSample samples}. */ public class POSEvaluator extends Evaluator { private final POSTagger tagger; private final Mean wordAccuracy = new Mean(); /** * Initializes the current instance. * * @param tagger The {@link POSTagger} to evaluate. * @param listeners the {@link POSTaggerEvaluationMonitor evaluation listeners}. */ public POSEvaluator(POSTagger tagger, POSTaggerEvaluationMonitor ... listeners) { super(listeners); this.tagger = tagger; } /** * Evaluates the given reference {@link POSSample} object. * This is done by tagging the sentence from the reference * {@link POSSample} with the {@link POSTagger}. The * tags are then used to update the word accuracy score. * * @param reference The {@link POSSample} to process. * * @return The predicted {@link POSSample}. */ @Override protected POSSample processSample(POSSample reference) { String[] predictedTags = tagger.tag(reference.getSentence(), reference.getAdditionalContext()); String[] referenceTags = reference.getTags(); for (int i = 0; i < referenceTags.length; i++) { if (referenceTags[i].equals(predictedTags[i])) { wordAccuracy.add(1); } else { wordAccuracy.add(0); } } return new POSSample(reference.getSentence(), predictedTags); } /** * Accuracy defined as: * {@code word accuracy = correctly detected tags / total words} * * @return Retrieves the mean word accuracy. */ public double getWordAccuracy() { return wordAccuracy.mean(); } /** * @return Retrieves the total number of words considered in the evaluation. */ public long getWordCount() { return wordAccuracy.count(); } /** * Represents this object as human-readable {@link String}. */ @Override public String toString() { return "Accuracy:" + wordAccuracy.mean() + " Number of Samples: " + wordAccuracy.count(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSModel.java0100644 0000000 0000000 00000021447 15217274217 031501 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Serial; import java.net.URL; import java.nio.file.Path; import java.util.Arrays; import java.util.Map; import java.util.Objects; import java.util.Properties; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.BaseModel; import opennlp.tools.util.model.ByteArraySerializer; import opennlp.tools.util.model.POSModelSerializer; import opennlp.tools.util.model.SerializableArtifact; /** * The {@link POSModel} is the model used by a learnable {@link POSTagger}. * * @see POSTaggerME */ public final class POSModel extends BaseModel implements SerializableArtifact { @Serial private static final long serialVersionUID = -3085487677101643697L; private static final String COMPONENT_NAME = "POSTaggerME"; static final String POS_MODEL_ENTRY_NAME = "pos.model"; static final String GENERATOR_DESCRIPTOR_ENTRY_NAME = "generator.featuregen"; /** * Initializes a {@link POSModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param posModel A valid {@link SequenceClassificationModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param posFactory The {@link POSTaggerFactory} for creating related objects. */ public POSModel(String languageCode, SequenceClassificationModel posModel, Map manifestInfoEntries, POSTaggerFactory posFactory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, posFactory); artifactMap.put(POS_MODEL_ENTRY_NAME, Objects.requireNonNull(posModel, "posModel must not be null")); artifactMap.put(GENERATOR_DESCRIPTOR_ENTRY_NAME, posFactory.getFeatureGenerator()); artifactMap.putAll(posFactory.getResources()); // TODO: This fails probably for the sequence model ... ?! // checkArtifactMap(); } /** * Initializes a {@link POSModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param posModel A valid {@link MaxentModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param posFactory The {@link POSTaggerFactory} for creating related objects. */ public POSModel(String languageCode, MaxentModel posModel, Map manifestInfoEntries, POSTaggerFactory posFactory) { this(languageCode, posModel, POSTaggerME.DEFAULT_BEAM_SIZE, manifestInfoEntries, posFactory); } /** * Initializes a {@link POSModel} instance via given parameters. * * @param languageCode An ISO conform language code. * @param posModel A valid {@link MaxentModel}. * @param beamSize The size of the beam that should be used when decoding sequences. * @param manifestInfoEntries Additional information kept in the manifest. * @param posFactory The {@link POSTaggerFactory} for creating related objects. */ public POSModel(String languageCode, MaxentModel posModel, int beamSize, Map manifestInfoEntries, POSTaggerFactory posFactory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, posFactory); Objects.requireNonNull(posModel, "posModel must not be null"); Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); manifest.setProperty(BeamSearch.BEAM_SIZE_PARAMETER, Integer.toString(beamSize)); artifactMap.put(POS_MODEL_ENTRY_NAME, posModel); artifactMap.put(GENERATOR_DESCRIPTOR_ENTRY_NAME, posFactory.getFeatureGenerator()); artifactMap.putAll(posFactory.getResources()); checkArtifactMap(); } /** * Initializes a {@link POSModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public POSModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link POSModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public POSModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link POSModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public POSModel(Path modelPath) throws IOException { this(modelPath.toFile()); } /** * Initializes a {@link POSModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public POSModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } @Override protected Class getDefaultFactory() { return POSTaggerFactory.class; } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(POS_MODEL_ENTRY_NAME) instanceof MaxentModel)) { throw new InvalidFormatException("POS model is incomplete!"); } } @Override protected boolean skipEntryForSerialization(Map.Entry entry) { // An old model format was detected, skipping the process for this entry, see: OPENNLP-1369 return GENERATOR_DESCRIPTOR_ENTRY_NAME.equals(entry.getKey()) && entry.getValue() == null; } /** * @return Retrieves a {@link SequenceClassificationModel}. */ public SequenceClassificationModel getPosSequenceModel() { Properties manifest = (Properties) artifactMap.get(MANIFEST_ENTRY); if (artifactMap.get(POS_MODEL_ENTRY_NAME) instanceof MaxentModel) { String beamSizeString = manifest.getProperty(BeamSearch.BEAM_SIZE_PARAMETER); int beamSize = POSTaggerME.DEFAULT_BEAM_SIZE; if (beamSizeString != null) { beamSize = Integer.parseInt(beamSizeString); } return new BeamSearch(beamSize, (MaxentModel) artifactMap.get(POS_MODEL_ENTRY_NAME)); } else if (artifactMap.get(POS_MODEL_ENTRY_NAME) instanceof SequenceClassificationModel) { return (SequenceClassificationModel) artifactMap.get(POS_MODEL_ENTRY_NAME); } else { return null; } } /** * @return Retrieves the active {@link POSTaggerFactory}. */ public POSTaggerFactory getFactory() { return (POSTaggerFactory) this.toolFactory; } @Override protected void createArtifactSerializers(Map> serializers) { super.createArtifactSerializers(serializers); serializers.put("featuregen", new ByteArraySerializer()); } @Override public Class getArtifactSerializerClass() { return POSModelSerializer.class; } @Override public int hashCode() { return Objects.hash(artifactMap.get("manifest.properties"), artifactMap.get("pos.model"), Arrays.hashCode((byte[]) artifactMap.get(GENERATOR_DESCRIPTOR_ENTRY_NAME)) ); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof POSModel model) { Map artifactMapToCheck = model.artifactMap; AbstractModel abstractModel = (AbstractModel) artifactMapToCheck.get("pos.model"); return artifactMap.get("manifest.properties").equals(artifactMapToCheck.get("manifest.properties")) && artifactMap.get("pos.model").equals(abstractModel) && Arrays.equals((byte[]) artifactMap.get(GENERATOR_DESCRIPTOR_ENTRY_NAME), (byte[]) artifactMapToCheck.get(GENERATOR_DESCRIPTOR_ENTRY_NAME)); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSSample.java0100644 0000000 0000000 00000013634 15217274217 031661 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import opennlp.tools.commons.Sample; import opennlp.tools.tokenize.WhitespaceTokenizer; import opennlp.tools.util.InvalidFormatException; /** * Represents an pos-tagged {@link Sample sentence}. */ public class POSSample implements Sample { private static final long serialVersionUID = -5782784526335651421L; private final List sentence; private final List tags; private final String[][] additionalContext; /** * Initializes a {@link POSSample} instance. * * @param sentence The sentence of tokens to be tagged. * @param tags An array of pos tags for each token provided in {@code sentence}. */ public POSSample(String[] sentence, String[] tags) { this(sentence, tags, null); } /** * Initializes a {@link POSSample} instance. * * @param sentence The sentence to be tagged. * @param tags A {@link List} of pos tags for each token provided in {@code sentence}. */ public POSSample(List sentence, List tags) { this(sentence, tags, null); } /** * Initializes a {@link POSSample} instance. * * @param sentence The sentence to be tagged. * @param tags A {@link List} of pos tags for each token provided in {@code sentence}. * @param additionalContext A 2D array which holds additional information for the context. */ public POSSample(List sentence, List tags, String[][] additionalContext) { this.sentence = Collections.unmodifiableList(sentence); this.tags = Collections.unmodifiableList(tags); checkArguments(); String[][] ac; if (additionalContext != null) { ac = new String[additionalContext.length][]; for (int i = 0; i < additionalContext.length; i++) { ac[i] = new String[additionalContext[i].length]; System.arraycopy(additionalContext[i], 0, ac[i], 0, additionalContext[i].length); } } else { ac = null; } this.additionalContext = ac; } /** * Initializes a {@link POSSample} instance. * * @param sentence The sentence to be tagged. * @param tags An array of pos tags for each token provided in {@code sentence}. * @param additionalContext A 2D array which holds additional information for the context. */ public POSSample(String[] sentence, String[] tags, String[][] additionalContext) { this(Arrays.asList(sentence), Arrays.asList(tags), additionalContext); } private void checkArguments() { if (sentence.size() != tags.size()) { throw new IllegalArgumentException( "There must be exactly one tag for each token. tokens: " + sentence.size() + ", tags: " + tags.size()); } if (sentence.contains(null)) { throw new IllegalArgumentException("null elements are not allowed in sentence tokens!"); } if (tags.contains(null)) { throw new IllegalArgumentException("null elements are not allowed in tags!"); } } /** * @return Retrieves the sentence as array. */ public String[] getSentence() { return sentence.toArray(new String[0]); } /** * @return Retrieves the tags as array. */ public String[] getTags() { return tags.toArray(new String[0]); } /** * @return Retrieves additional information for the context. */ public String[][] getAdditionalContext() { return this.additionalContext; } @Override public String toString() { StringBuilder result = new StringBuilder(); for (int i = 0; i < getSentence().length; i++) { result.append(getSentence()[i]); result.append('_'); result.append(getTags()[i]); result.append(' '); } if (result.length() > 0) { // get rid of last space result.setLength(result.length() - 1); } return result.toString(); } /** * Parses a {@code sentenceString}. * * @param sentenceString The sentence to be parsed. * @return A valid {@link POSSample} result. * * @throws InvalidFormatException Thrown if errors occurred during parsing. */ public static POSSample parse(String sentenceString) throws InvalidFormatException { String[] tokenTags = WhitespaceTokenizer.INSTANCE.tokenize(sentenceString); String[] sentence = new String[tokenTags.length]; String[] tags = new String[tokenTags.length]; for (int i = 0; i < tokenTags.length; i++) { int split = tokenTags[i].lastIndexOf("_"); if (split == -1) { throw new InvalidFormatException("Cannot find \"_\" inside token '" + tokenTags[i] + "'!"); } sentence[i] = tokenTags[i].substring(0, split); tags[i] = tokenTags[i].substring(split + 1); } return new POSSample(sentence, tags); } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(getSentence()), Arrays.hashCode(getTags())); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof POSSample a) { return Arrays.equals(getSentence(), a.getSentence()) && Arrays.equals(getTags(), a.getTags()); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_POSSample0100644 0000000 0000000 00000000156 15217274217 032423 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSSampleEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSSampleEventStream.java0100644 0000000 0000000 00000006112 15217274217 034030 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import opennlp.tools.ml.model.Event; import opennlp.tools.util.AbstractEventStream; import opennlp.tools.util.ObjectStream; /** * Reads the {@link POSSample samples} from an {@link Iterator} * and converts those samples into {@link Event events} which * can be used by the maxent library for training. */ public class POSSampleEventStream extends AbstractEventStream { /** * The {@link POSContextGenerator} used to create the training {@link Event events}. */ private final POSContextGenerator cg; /** * Initializes the current instance with the given samples and a {@link POSContextGenerator}. * * @param samples The data stream for this event stream. * @param cg A {@link POSContextGenerator} to process the event stream {@code samples}. */ public POSSampleEventStream(ObjectStream samples, POSContextGenerator cg) { super(samples); this.cg = cg; } /** * Initializes the current instance with given samples * and a {@link DefaultPOSContextGenerator}. * * @param samples The data stream for this event stream. */ public POSSampleEventStream(ObjectStream samples) { this(samples, new DefaultPOSContextGenerator(null)); } @Override protected Iterator createEvents(POSSample sample) { String[] sentence = sample.getSentence(); String[] tags = sample.getTags(); Object[] ac = sample.getAdditionalContext(); List events = generateEvents(sentence, tags, ac, cg); return events.iterator(); } public static List generateEvents(String[] sentence, String[] tags, Object[] additionalContext, POSContextGenerator cg) { List events = new ArrayList<>(sentence.length); for (int i = 0; i < sentence.length; i++) { // it is safe to pass the tags as previous tags because // the context generator does not look for non predicted tags String[] context = cg.getContext(i, sentence, tags, additionalContext); events.add(new Event(tags[i], context)); } return events; } public static List generateEvents(String[] sentence, String[] tags, POSContextGenerator cg) { return generateEvents(sentence, tags, null, cg); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_POSSample0100644 0000000 0000000 00000000161 15217274217 032417 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSSampleSequenceStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSSampleSequenceStream.j0100644 0000000 0000000 00000006534 15217274217 034037 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.IOException; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.Sequence; import opennlp.tools.ml.model.SequenceStream; import opennlp.tools.util.ObjectStream; /** * A {@link SequenceStream} implementation encapsulating {@link POSSample samples}. */ public class POSSampleSequenceStream implements SequenceStream { private final POSContextGenerator pcg; private final ObjectStream psi; /** * Creates a {@link POSSampleSequenceStream} with given {@code samples} using * a {@link DefaultPOSContextGenerator}. * * @param psi The data stream of {@link POSSample samples}. */ public POSSampleSequenceStream(ObjectStream psi) { this(psi, new DefaultPOSContextGenerator(null)); } /** * Creates a {@link POSSampleSequenceStream} with given {@code samples} using * a {@link POSContextGenerator}. * * @param psi The data stream of {@link POSSample samples}. * @param pcg A {@link POSContextGenerator} which shall be used. */ public POSSampleSequenceStream(ObjectStream psi, POSContextGenerator pcg) { this.psi = psi; this.pcg = pcg; } @Override public Event[] updateContext(Sequence pss, AbstractModel model) { POSTagger tagger = new POSTaggerME(new POSModel("x-unspecified", model, null, new POSTaggerFactory())); String[] sentence = pss.getSource().getSentence(); Object[] ac = pss.getSource().getAdditionalContext(); String[] tags = tagger.tag(pss.getSource().getSentence()); Event[] events = new Event[sentence.length]; POSSampleEventStream.generateEvents(sentence, tags, ac, pcg).toArray(events); return events; } @Override public Sequence read() throws IOException { POSSample sample = psi.read(); if (sample != null) { String[] sentence = sample.getSentence(); String[] tags = sample.getTags(); Event[] events = new Event[sentence.length]; for (int i = 0; i < sentence.length; i++) { // it is safe to pass the tags as previous tags because // the context generator does not look for non predicted tags String[] context = pcg.getContext(i, sentence, tags, null); events[i] = new Event(tags[i], context); } return new Sequence<>(events,sample); } return null; } @Override public void reset() throws IOException, UnsupportedOperationException { psi.reset(); } @Override public void close() throws IOException { psi.close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTagFormat.java0100644 0000000 0000000 00000002156 15217274217 032321 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; /** * Defines the format for part-of-speech tagging, i.e. * PENN * or UD format. */ public enum POSTagFormat { UD, PENN, CUSTOM, UNKNOWN } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTagFormatMapper.java0100644 0000000 0000000 00000022274 15217274217 033471 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A mapping implementation for converting between different POS tag formats. * This class supports conversion between Penn Treebank (PENN) and Universal Dependencies (UD) formats. * The conversion is based on the Universal Dependencies conversion table. * Please note that when converting from UD to Penn format, there may be ambiguity in some cases. */ public class POSTagFormatMapper { private static final Logger logger = LoggerFactory.getLogger(POSTagFormatMapper.class); private static final Map CONVERSION_TABLE_PENN_TO_UD = new HashMap<>(); private static final Map CONVERSION_TABLE_UD_TO_PENN = new HashMap<>(); static { /* * This is a conversion table to convert PENN to UD format as described in * https://universaldependencies.org/tagset-conversion/en-penn-uposf.html */ CONVERSION_TABLE_PENN_TO_UD.put("#", "SYM"); CONVERSION_TABLE_PENN_TO_UD.put("$", "SYM"); CONVERSION_TABLE_PENN_TO_UD.put("''", "PUNCT"); CONVERSION_TABLE_PENN_TO_UD.put(",", "PUNCT"); CONVERSION_TABLE_PENN_TO_UD.put("-LRB-", "PUNCT"); CONVERSION_TABLE_PENN_TO_UD.put("-RRB-", "PUNCT"); CONVERSION_TABLE_PENN_TO_UD.put(".", "PUNCT"); CONVERSION_TABLE_PENN_TO_UD.put(":", "PUNCT"); CONVERSION_TABLE_PENN_TO_UD.put("AFX", "ADJ"); CONVERSION_TABLE_PENN_TO_UD.put("CC", "CCONJ"); CONVERSION_TABLE_PENN_TO_UD.put("CD", "NUM"); CONVERSION_TABLE_PENN_TO_UD.put("DT", "DET"); CONVERSION_TABLE_PENN_TO_UD.put("EX", "PRON"); CONVERSION_TABLE_PENN_TO_UD.put("FW", "X"); CONVERSION_TABLE_PENN_TO_UD.put("HYPH", "PUNCT"); CONVERSION_TABLE_PENN_TO_UD.put("IN", "ADP"); CONVERSION_TABLE_PENN_TO_UD.put("JJ", "ADJ"); CONVERSION_TABLE_PENN_TO_UD.put("JJR", "ADJ"); CONVERSION_TABLE_PENN_TO_UD.put("JJS", "ADJ"); CONVERSION_TABLE_PENN_TO_UD.put("LS", "X"); CONVERSION_TABLE_PENN_TO_UD.put("MD", "VERB"); CONVERSION_TABLE_PENN_TO_UD.put("NIL", "X"); CONVERSION_TABLE_PENN_TO_UD.put("NN", "NOUN"); CONVERSION_TABLE_PENN_TO_UD.put("NNP", "PROPN"); CONVERSION_TABLE_PENN_TO_UD.put("NNPS", "PROPN"); CONVERSION_TABLE_PENN_TO_UD.put("NNS", "NOUN"); CONVERSION_TABLE_PENN_TO_UD.put("PDT", "DET"); CONVERSION_TABLE_PENN_TO_UD.put("POS", "PART"); CONVERSION_TABLE_PENN_TO_UD.put("PRP", "PRON"); CONVERSION_TABLE_PENN_TO_UD.put("PRP$", "DET"); CONVERSION_TABLE_PENN_TO_UD.put("RB", "ADV"); CONVERSION_TABLE_PENN_TO_UD.put("RBR", "ADV"); CONVERSION_TABLE_PENN_TO_UD.put("RBS", "ADV"); CONVERSION_TABLE_PENN_TO_UD.put("RP", "ADP"); CONVERSION_TABLE_PENN_TO_UD.put("SYM", "SYM"); CONVERSION_TABLE_PENN_TO_UD.put("TO", "PART"); CONVERSION_TABLE_PENN_TO_UD.put("UH", "INTJ"); CONVERSION_TABLE_PENN_TO_UD.put("VB", "VERB"); CONVERSION_TABLE_PENN_TO_UD.put("VBD", "VERB"); CONVERSION_TABLE_PENN_TO_UD.put("VBG", "VERB"); CONVERSION_TABLE_PENN_TO_UD.put("VBN", "VERB"); CONVERSION_TABLE_PENN_TO_UD.put("VBP", "VERB"); CONVERSION_TABLE_PENN_TO_UD.put("VBZ", "VERB"); CONVERSION_TABLE_PENN_TO_UD.put("WDT", "DET"); CONVERSION_TABLE_PENN_TO_UD.put("WP", "PRON"); CONVERSION_TABLE_PENN_TO_UD.put("WP$", "DET"); CONVERSION_TABLE_PENN_TO_UD.put("WRB", "ADV"); /* * Note: The back conversion might lose information. */ CONVERSION_TABLE_UD_TO_PENN.put("ADJ", "JJ"); CONVERSION_TABLE_UD_TO_PENN.put("ADP", "IN"); CONVERSION_TABLE_UD_TO_PENN.put("ADV", "RB"); CONVERSION_TABLE_UD_TO_PENN.put("AUX", "MD"); CONVERSION_TABLE_UD_TO_PENN.put("CCONJ", "CC"); CONVERSION_TABLE_UD_TO_PENN.put("DET", "DT"); CONVERSION_TABLE_UD_TO_PENN.put("INTJ", "UH"); CONVERSION_TABLE_UD_TO_PENN.put("NOUN", "NN"); CONVERSION_TABLE_UD_TO_PENN.put("NUM", "CD"); CONVERSION_TABLE_UD_TO_PENN.put("PART", "RP"); CONVERSION_TABLE_UD_TO_PENN.put("PRON", "PRP"); CONVERSION_TABLE_UD_TO_PENN.put("PROPN", "NNP"); CONVERSION_TABLE_UD_TO_PENN.put("PUNCT", "."); CONVERSION_TABLE_UD_TO_PENN.put("SCONJ", "IN"); CONVERSION_TABLE_UD_TO_PENN.put("SYM", "SYM"); CONVERSION_TABLE_UD_TO_PENN.put("VERB", "VB"); CONVERSION_TABLE_UD_TO_PENN.put("X", "FW"); } private final POSTagFormat modelFormat; protected POSTagFormatMapper(final String[] possibleOutcomes) { this.modelFormat = guessModelTagFormat(possibleOutcomes); } /** * Converts a list of tags to the specified format. * * @param tags a list of tags to be converted. * @return an array containing the converted tags with the same order and size as the given input list. * Note: A given tag might be {@code ?} if no mapping for the given {@code tag} could be found. */ public String[] convertTags(List tags) { Objects.requireNonNull(tags, "Supplied tags must not be NULL."); return tags.stream() .map(this::convertTag) .toArray(String[]::new); } /** * Converts a given tag to the specified format. * * @param tag no restrictions on this parameter. * @return the converted tag form or {@code ?} if no mapping for {@code tag} could be found. */ public String convertTag(String tag) { switch (modelFormat) { case UD -> { return CONVERSION_TABLE_UD_TO_PENN.getOrDefault(tag, "?"); } case PENN -> { if ("NOUN".equals(tag)) { logger.warn("Ambiguity detected: NN can be 'NN' or 'NNS' depending on the number. " + "Returning 'NN'."); } if ("PART".equals(tag)) { logger.warn("Ambiguity detected: PART can be 'RP' or 'TO'. Returning 'RP'."); } if ("PROPN".equals(tag)) { logger.warn("Ambiguity detected: Can be 'NNP' or 'NNPS. Returning 'NNP'"); } if ("PUNCT".equals(tag)) { logger.warn("Ambiguity detected: PUNCT needs specific punctuation mapping. Returning '.'"); } if ("VERB".equals(tag)) { logger.warn("Ambiguity detected: VERB can be 'VB', 'VBD', 'VBG', 'VBN', 'VBP', 'VBZ'. " + "Returning 'VERB'."); } return CONVERSION_TABLE_PENN_TO_UD.getOrDefault(tag, "?"); } default -> { return tag; } } } /** * * @return The guessed {@link POSTagFormat}. Guaranteed to be not {@code null}. */ public POSTagFormat getGuessedFormat() { return this.modelFormat; } /** * Guesses the {@link POSTagFormat} by using majority quorum. * @param outcomes must not be {@code null}. * @return the guessed {@link POSTagFormat}. * If the given input was empty, {@link POSTagFormat#UNKNOWN} is returned. */ private POSTagFormat guessModelTagFormat(final String[] outcomes) { Objects.requireNonNull(outcomes, "Outcomes must not be NULL."); int udMatches = 0; int pennMatches = 0; for (String outcome : outcomes) { if (CONVERSION_TABLE_UD_TO_PENN.containsKey(outcome)) { udMatches++; } if (CONVERSION_TABLE_PENN_TO_UD.containsKey(outcome)) { pennMatches++; } } if (udMatches > pennMatches) { return POSTagFormat.UD; } else if (pennMatches > udMatches) { return POSTagFormat.PENN; } else { logger.warn("Detected an unknown POS format."); return POSTagFormat.UNKNOWN; } } /** * Guesses the {@link POSTagFormat} of a given {@link POSModel} * @param posModel must not be {@code null}. * @return the guessed {@link POSTagFormat}. */ public static POSTagFormat guessFormat(POSModel posModel) { Objects.requireNonNull(posModel, "POSModel must not be NULL."); Objects.requireNonNull(posModel.getPosSequenceModel(), "POSSequenceModel must not be NULL."); final POSTagFormatMapper mapper = new POSTagFormatMapper(posModel.getPosSequenceModel().getOutcomes()); return mapper.getGuessedFormat(); } public static class NoOp extends POSTagFormatMapper { protected NoOp() { super(new String[0]); } @Override public String[] convertTags(List tags) { Objects.requireNonNull(tags, "tags must not be NULL."); return tags.toArray(new String[0]); } @Override public String convertTag(String tag) { return tag; } @Override public POSTagFormat getGuessedFormat() { return POSTagFormat.CUSTOM; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTagger.java0100644 0000000 0000000 00000004265 15217274217 031651 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import opennlp.tools.util.Sequence; /** * The interface for part of speech taggers. */ public interface POSTagger { /** * Assigns the sentence of tokens pos tags. * * @param sentence The sentence of tokens to be tagged. * @return An array of pos tags for each token provided in {@code sentence}. */ String[] tag(String[] sentence); /** * Assigns the sentence of tokens pos tags. * * @param sentence The sentence of tokens to be tagged. * @param additionalContext The context to provide additional information with. * * @return An array of pos tags for each token provided in {@code sentence}. */ String[] tag(String[] sentence, Object[] additionalContext); /** * Assigns the sentence the top-k {@link Sequence sequences}. * * @param sentence The sentence of tokens to be tagged. * * @return An array of {@link Sequence sequences} for each token provided in {@code sentence}. */ Sequence[] topKSequences(String[] sentence); /** * Assigns the sentence the top-k {@link Sequence sequences}. * * @param sentence The sentence of tokens to be tagged. * @param additionalContext The context to provide additional information with. * * @return An array of {@link Sequence sequences} for each token provided in {@code sentence}. */ Sequence[] topKSequences(String[] sentence, Object[] additionalContext); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_POSTagger0100644 0000000 0000000 00000000161 15217274217 032407 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTaggerCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTaggerCrossValidator.j0100644 0000000 0000000 00000020603 15217274217 034033 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.File; import java.io.IOException; import java.util.Map; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.Mean; public class POSTaggerCrossValidator { private final String languageCode; private final TrainingParameters params; private final POSTagFormat posTagFormat; private byte[] featureGeneratorBytes; private Map resources; private final Mean wordAccuracy = new Mean(); private final POSTaggerEvaluationMonitor[] listeners; /* this will be used to load the factory after the ngram dictionary was created */ private String factoryClassName; /* user can also send a ready to use factory */ private POSTaggerFactory factory; private final Integer tagdicCutoff; private File tagDictionaryFile; /** * Initializes a {@link POSTaggerCrossValidator} that builds a ngram dictionary * dynamically. It instantiates a subclass of {@link POSTaggerFactory} using * the tag and the ngram dictionaries. * * @param languageCode An ISO conform language code. * @param trainParam The {@link TrainingParameters} for the context of cross validation. * @param tagDictionary The {@link File} that references the a {@link TagDictionary}. * @param featureGeneratorBytes The bytes for feature generation. * @param resources Additional resources as key-value map. * @param factoryClass The class name used for factory instantiation. * @param format A valid {@link POSTagFormat}. * @param listeners The {@link POSTaggerEvaluationMonitor evaluation listeners}. */ public POSTaggerCrossValidator(String languageCode, TrainingParameters trainParam, File tagDictionary, byte[] featureGeneratorBytes, Map resources, Integer tagdicCutoff, String factoryClass, POSTagFormat format, POSTaggerEvaluationMonitor... listeners) { this.languageCode = languageCode; this.params = trainParam; this.featureGeneratorBytes = featureGeneratorBytes; this.resources = resources; this.listeners = listeners; this.factoryClassName = factoryClass; this.tagdicCutoff = tagdicCutoff; this.tagDictionaryFile = tagDictionary; this.posTagFormat = format; } /** * Initializes a {@link POSTaggerCrossValidator} that builds a ngram dictionary * dynamically. It instantiates a subclass of {@link POSTaggerFactory} using * the tag and the ngram dictionaries. * * @param languageCode An ISO conform language code. * @param trainParam The {@link TrainingParameters} for the context of cross validation. * @param tagDictionary The {@link File} that references the a {@link TagDictionary}. * @param featureGeneratorBytes The bytes for feature generation. * @param resources Additional resources as key-value map. * @param factoryClass The class name used for factory instantiation. * @param listeners The {@link POSTaggerEvaluationMonitor evaluation listeners}. */ public POSTaggerCrossValidator(String languageCode, TrainingParameters trainParam, File tagDictionary, byte[] featureGeneratorBytes, Map resources, Integer tagdicCutoff, String factoryClass, POSTaggerEvaluationMonitor... listeners) { this(languageCode, trainParam, tagDictionary, featureGeneratorBytes, resources, tagdicCutoff, factoryClass, POSTagFormat.UD, listeners); } /** * Creates a {@link POSTaggerCrossValidator} using the given {@link POSTaggerFactory}. * * @param languageCode An ISO conform language code. * @param trainParam The {@link TrainingParameters} for the context of cross validation. * @param factory The {@link POSTaggerFactory} to be used. * @param listeners The {@link POSTaggerEvaluationMonitor evaluation listeners}. */ public POSTaggerCrossValidator(String languageCode, TrainingParameters trainParam, POSTaggerFactory factory, POSTaggerEvaluationMonitor... listeners) { this(languageCode, trainParam, factory, POSTagFormat.UD, listeners); } /** * Creates a {@link POSTaggerCrossValidator} using the given {@link POSTaggerFactory}. * * @param languageCode An ISO conform language code. * @param trainParam The {@link TrainingParameters} for the context of cross validation. * @param factory The {@link POSTaggerFactory} to be used. * @param format A valid {@link POSTagFormat}. * @param listeners The {@link POSTaggerEvaluationMonitor evaluation listeners}. */ public POSTaggerCrossValidator(String languageCode, TrainingParameters trainParam, POSTaggerFactory factory, POSTagFormat format, POSTaggerEvaluationMonitor... listeners) { this.languageCode = languageCode; this.params = trainParam; this.listeners = listeners; this.factory = factory; this.posTagFormat = format; this.tagdicCutoff = null; } /** * Starts the evaluation. * * @param samples The {@link ObjectStream} of {@link POSSample samples} to train and test with. * @param nFolds Number of folds. It must be greater than zero. * * @throws IOException Thrown if IO errors occurred. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>( samples, nFolds); while (partitioner.hasNext()) { CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner .next(); if (this.tagDictionaryFile != null && this.factory.getTagDictionary() == null) { this.factory.setTagDictionary(this.factory .createTagDictionary(tagDictionaryFile)); } TagDictionary dict = null; if (this.tagdicCutoff != null) { dict = this.factory.getTagDictionary(); if (dict == null) { dict = this.factory.createEmptyTagDictionary(); } if (dict instanceof MutableTagDictionary) { POSTaggerME.populatePOSDictionary(trainingSampleStream, (MutableTagDictionary)dict, this.tagdicCutoff); } else { throw new IllegalArgumentException( "Can't extend a TagDictionary that does not implement MutableTagDictionary."); } trainingSampleStream.reset(); } if (this.factory == null) { this.factory = POSTaggerFactory.create(this.factoryClassName, null, null); } factory.init(featureGeneratorBytes, resources, dict); POSModel model = POSTaggerME.train(languageCode, trainingSampleStream, params, this.factory); POSEvaluator evaluator = new POSEvaluator(new POSTaggerME(model, posTagFormat), listeners); evaluator.evaluate(trainingSampleStream.getTestSampleStream()); wordAccuracy.add(evaluator.getWordAccuracy(), evaluator.getWordCount()); if (this.tagdicCutoff != null) { this.factory.setTagDictionary(null); } } } /** * @return Retrieves the accuracy for all iterations. */ public double getWordAccuracy() { return wordAccuracy.mean(); } /** * @return Retrieves the number of words which where validated * over all iterations. The result is the amount of folds * multiplied by the total number of words. */ public long getWordCount() { return wordAccuracy.count(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_POSTagger0100644 0000000 0000000 00000000164 15217274217 032412 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTaggerEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTaggerEvaluationMonito0100644 0000000 0000000 00000002026 15217274217 034140 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link POSTagger pos taggers}. */ public interface POSTaggerEvaluationMonitor extends EvaluationMonitor { } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTaggerFactory.java0100644 0000000 0000000 00000037677 15217274217 033216 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.Version; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.featuregen.AdaptiveFeatureGenerator; import opennlp.tools.util.featuregen.AggregatedFeatureGenerator; import opennlp.tools.util.featuregen.GeneratorFactory; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.UncloseableInputStream; /** * The factory that provides {@link POSTagger} default implementations and resources. */ public class POSTaggerFactory extends BaseToolFactory { private static final String TAG_DICTIONARY_ENTRY_NAME = "tags.tagdict"; private static final String NGRAM_DICTIONARY_ENTRY_NAME = "ngram.dictionary"; protected Dictionary ngramDictionary; private byte[] featureGeneratorBytes; private Map resources; protected TagDictionary posDictionary; /** * Initializes a {@link POSTaggerFactory} that provides the default implementation * of the resources. */ public POSTaggerFactory() { } /** * Initializes a {@link POSTaggerFactory} from a given set of the resources. * * @param featureGeneratorBytes The bytes for feature generation. * @param resources Additional resources as key-value map. * @param posDictionary A {@link TagDictionary} used for the new instance. */ public POSTaggerFactory(byte[] featureGeneratorBytes, final Map resources, TagDictionary posDictionary) { this.featureGeneratorBytes = featureGeneratorBytes; if (this.featureGeneratorBytes == null) { this.featureGeneratorBytes = loadDefaultFeatureGeneratorBytes(); } this.resources = resources; this.posDictionary = posDictionary; } // reduced visibility to ensure deprecation is respected in future versions @Deprecated(forRemoval = true) POSTaggerFactory(Dictionary ngramDictionary, TagDictionary posDictionary) { this.init(ngramDictionary, posDictionary); // TODO: This could be made functional by creating some default feature generation // which uses the dictionary ... } // reduced visibility to ensure deprecation is respected in future versions // will be removed when only 8 series models are supported @Deprecated(forRemoval = true) void init(Dictionary ngramDictionary, TagDictionary posDictionary) { this.ngramDictionary = ngramDictionary; this.posDictionary = posDictionary; } protected void init(byte[] featureGeneratorBytes, final Map resources, TagDictionary posDictionary) { this.featureGeneratorBytes = featureGeneratorBytes; this.resources = resources; this.posDictionary = posDictionary; } /* * Loads the default feature generator bytes via classpath resources. */ private static byte[] loadDefaultFeatureGeneratorBytes() { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); InputStream resource = POSTaggerFactory.class.getResourceAsStream( "/opennlp/tools/postag/pos-default-features.xml"); if (resource == null) { throw new IllegalStateException("Classpath must contain 'pos-default-features.xml' file!"); } try (InputStream in = new BufferedInputStream(resource)) { byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { bytes.write(buf, 0, len); } } catch (IOException e) { throw new IllegalStateException("Failed reading from 'pos-default-features.xml' file on classpath!"); } return bytes.toByteArray(); } /** * Creates the {@link AdaptiveFeatureGenerator}. Usually this * is a set of generators contained in the {@link AggregatedFeatureGenerator}. *

* Note: * The generators are created on every call to this method. * * @return the feature generator or {@code null} if there is no descriptor in the model * @throws IllegalStateException Thrown if inconsistencies occurred during creation. */ public AdaptiveFeatureGenerator createFeatureGenerators() { if (featureGeneratorBytes == null && artifactProvider != null) { featureGeneratorBytes = artifactProvider.getArtifact( POSModel.GENERATOR_DESCRIPTOR_ENTRY_NAME); } if (featureGeneratorBytes == null) { featureGeneratorBytes = loadDefaultFeatureGeneratorBytes(); } AdaptiveFeatureGenerator generator; try (InputStream descriptorIn = new ByteArrayInputStream(featureGeneratorBytes)) { generator = GeneratorFactory.create(descriptorIn, key -> { if (artifactProvider != null) { return artifactProvider.getArtifact(key); } else { return resources.get(key); } }); } catch (InvalidFormatException e) { // It is assumed that the creation of the feature generation does not // fail after it succeeded once during model loading. // But it might still be possible that such an exception is thrown, // in this case the caller should not be forced to handle the exception // and a Runtime Exception is thrown instead. // If the re-creation of the feature generation fails it is assumed // that this can only be caused by a programming mistake and therefore // throwing a Runtime Exception is reasonable throw new IllegalStateException(e); // FeatureGeneratorCreationError(e); } catch (IOException e) { throw new IllegalStateException("Reading from mem cannot result in an I/O error", e); } return generator; } @Override public Map> createArtifactSerializersMap() { Map> serializers = super.createArtifactSerializersMap(); // NOTE: This is only needed for old models and this if can be removed if support is dropped POSDictionarySerializer.register(serializers); return serializers; } @Override public Map createArtifactMap() { Map artifactMap = super.createArtifactMap(); if (posDictionary != null) { artifactMap.put(TAG_DICTIONARY_ENTRY_NAME, posDictionary); } if (ngramDictionary != null) { artifactMap.put(NGRAM_DICTIONARY_ENTRY_NAME, ngramDictionary); } return artifactMap; } /** * Initializes a {@link TagDictionary} from a {@link File dictionary file}. * * @param dictionary The {@link File} used for creating the dictionary. * @return A valid {@link TagDictionary} ready for use. * @throws IOException Thrown if IO errors occurred during creation. */ public TagDictionary createTagDictionary(File dictionary) throws IOException { return createTagDictionary(new BufferedInputStream(new FileInputStream(dictionary))); } /** * Initializes a {@link TagDictionary} from a {@link InputStream dictionary stream}. * * @param in The {@link InputStream} used for creating the dictionary. * @return A valid {@link TagDictionary} ready for use. * @throws IOException Thrown if IO errors occurred during creation. */ public TagDictionary createTagDictionary(InputStream in) throws IOException { return POSDictionary.create(in); } public void setTagDictionary(TagDictionary dictionary) { if (artifactProvider != null) { throw new IllegalStateException( "Can not set tag dictionary while using artifact provider."); } this.posDictionary = dictionary; } /** * @return The key-value based resources map, or an empty map. */ protected Map getResources() { if (resources != null) { return resources; } return Collections.emptyMap(); } /** * @return The feature generator bytes used. */ protected byte[] getFeatureGenerator() { return featureGeneratorBytes; } /** * @return The {@link TagDictionary} used. */ public TagDictionary getTagDictionary() { if (this.posDictionary == null && artifactProvider != null) { this.posDictionary = artifactProvider.getArtifact(TAG_DICTIONARY_ENTRY_NAME); } return this.posDictionary; } @Deprecated(forRemoval = true) // will be removed when only 8 series models are supported private Dictionary getDictionary() { if (this.ngramDictionary == null && artifactProvider != null) { this.ngramDictionary = artifactProvider.getArtifact(NGRAM_DICTIONARY_ENTRY_NAME); } return this.ngramDictionary; } /** * @return The {@link POSContextGenerator} with a default cache size of {@code 0}. */ public POSContextGenerator getPOSContextGenerator() { return getPOSContextGenerator(0); } /** * @param cacheSize Must be greater than or equal to {@code 0}. * @return The {@link POSContextGenerator} configured with the given {@code cacheSize}. */ public POSContextGenerator getPOSContextGenerator(int cacheSize) { if (artifactProvider != null) { Properties manifest = artifactProvider.getArtifact("manifest.properties"); String version = manifest.getProperty("OpenNLP-Version"); Version v = Version.parse(version); if (v.getMajor() == 1 && v.getMinor() < 8) { return new DefaultPOSContextGenerator(cacheSize, getDictionary()); } } return new ConfigurablePOSContextGenerator(cacheSize, createFeatureGenerators()); } /** * @return The {@link SequenceValidator} used. */ public SequenceValidator getSequenceValidator() { return new DefaultPOSSequenceValidator(getTagDictionary()); } // TODO: This should not be done anymore for 8 models, they can just // use the SerializableArtifact interface public static class POSDictionarySerializer implements ArtifactSerializer { @Override public POSDictionary create(InputStream in) throws IOException { return POSDictionary.create(new UncloseableInputStream(in)); } @Override public void serialize(POSDictionary artifact, OutputStream out) throws IOException { artifact.serialize(out); } static void register(Map> factories) { factories.put("tagdict", new POSDictionarySerializer()); } } protected void validatePOSDictionary(POSDictionary posDict, AbstractModel posModel) throws InvalidFormatException { Set dictTags = new HashSet<>(); for (String word : posDict) { Collections.addAll(dictTags, posDict.getTags(word)); } Set modelTags = new HashSet<>(); for (int i = 0; i < posModel.getNumOutcomes(); i++) { modelTags.add(posModel.getOutcome(i)); } if (!modelTags.containsAll(dictTags)) { StringBuilder unknownTag = new StringBuilder(); for (String d : dictTags) { if (!modelTags.contains(d)) { unknownTag.append(d).append(" "); } } throw new InvalidFormatException("Tag dictionary contains tags " + "which are unknown by the model! The unknown tags are: " + unknownTag); } } @Override public void validateArtifactMap() throws InvalidFormatException { // Ensure that the tag dictionary is compatible with the model Object tagdictEntry = this.artifactProvider .getArtifact(TAG_DICTIONARY_ENTRY_NAME); if (tagdictEntry != null) { if (tagdictEntry instanceof POSDictionary) { if (!this.artifactProvider.isLoadedFromSerialized()) { AbstractModel posModel = this.artifactProvider .getArtifact(POSModel.POS_MODEL_ENTRY_NAME); POSDictionary posDict = (POSDictionary) tagdictEntry; validatePOSDictionary(posDict, posModel); } } else { throw new InvalidFormatException( "POSTag dictionary has wrong type!"); } } Object ngramDictEntry = this.artifactProvider .getArtifact(NGRAM_DICTIONARY_ENTRY_NAME); if (ngramDictEntry != null && !(ngramDictEntry instanceof Dictionary)) { throw new InvalidFormatException("NGram dictionary has wrong type!"); } } // reduced visibility to ensure deprecation is respected in future versions @Deprecated static POSTaggerFactory create(String subclassName, Dictionary ngramDictionary, TagDictionary posDictionary) throws InvalidFormatException { if (subclassName == null) { // will create the default factory return new POSTaggerFactory(ngramDictionary, posDictionary); } try { POSTaggerFactory theFactory = ExtensionLoader.instantiateExtension( POSTaggerFactory.class, subclassName); theFactory.init(ngramDictionary, posDictionary); return theFactory; } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization throw an exception."; throw new InvalidFormatException(msg, e); } } /** * Instantiates a {@link POSTaggerFactory} via a given {@code subclassName}. * * @param subclassName The class name used for instantiation. If {@code null}, an * instance of {@link POSTaggerFactory} will be returned * per default. Otherwise, the {@link ExtensionLoader} mechanism * is applied to load the requested {@code subclassName}. * @param featureGeneratorBytes The bytes for feature generation. * @param resources Additional resources as key-value map. * @param posDictionary A {@link TagDictionary} used for the new instance. * @return @return A valid {@link POSTaggerFactory} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * load the factory via the {@code subclassName}. */ public static POSTaggerFactory create(String subclassName, byte[] featureGeneratorBytes, Map resources, TagDictionary posDictionary) throws InvalidFormatException { POSTaggerFactory theFactory; if (subclassName == null) { // will create the default factory theFactory = new POSTaggerFactory(); theFactory.init(featureGeneratorBytes, resources, posDictionary); } else { try { theFactory = ExtensionLoader.instantiateExtension(POSTaggerFactory.class, subclassName); } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization throw an exception."; throw new InvalidFormatException(msg, e); } } theFactory.init(featureGeneratorBytes, resources, posDictionary); return theFactory; } /** * @return An empty, case-sensitive {@link TagDictionary}. */ public TagDictionary createEmptyTagDictionary() { this.posDictionary = new POSDictionary(true); return this.posDictionary; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/POSTaggerME.java0100644 0000000 0000000 00000036072 15217274217 032074 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.BeamSearch; import opennlp.tools.ml.EventModelSequenceTrainer; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.Probabilistic; import opennlp.tools.ml.SequenceTrainer; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.TrainerFactory.TrainerType; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.ml.model.SequenceClassificationModel; import opennlp.tools.models.ModelType; import opennlp.tools.ngram.NGramModel; import opennlp.tools.util.DownloadUtil; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Sequence; import opennlp.tools.util.SequenceValidator; import opennlp.tools.util.StringList; import opennlp.tools.util.StringUtil; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.featuregen.StringPattern; /** * A {@link POSTagger part-of-speech tagger} implementation that uses maximum entropy. *

* Tries to predict whether words are nouns, verbs, or any other {@link POSTagFormat POS tags} * depending on their surrounding context. * * @see POSModel * @see POSTagFormat * @see POSTagger * @see Probabilistic */ public class POSTaggerME implements POSTagger, Probabilistic { private static final Logger logger = LoggerFactory.getLogger(POSTaggerME.class); /** * The default beam size value is 3. */ public static final int DEFAULT_BEAM_SIZE = 3; private final POSModel modelPackage; /** * The {@link POSContextGenerator feature context generator}. */ protected final POSContextGenerator cg; /** * {@link TagDictionary} used for restricting words to a fixed set of tags. */ protected final TagDictionary tagDictionary; /** * The size of the beam to be used in determining the best sequence of pos tags. */ protected final int size; private Sequence bestSequence; private final SequenceClassificationModel model; private final SequenceValidator sequenceValidator; private final POSTagFormat posTagFormat; protected final POSTagFormatMapper posTagFormatMapper; /** * Initializes a {@link POSTaggerME} by downloading a default model for a given * {@code language}. * * @param language An ISO conform language code. * @throws IOException Thrown if the model could not be downloaded or saved. */ public POSTaggerME(String language) throws IOException { this(language, POSTagFormat.UD); } /** * Initializes a {@link POSTaggerME} by downloading a default model for a given * {@code language}. * * @param language An ISO conform language code. * @param format A valid {@link POSTagFormat}. * @throws IOException Thrown if the model could not be downloaded or saved. */ public POSTaggerME(String language, POSTagFormat format) throws IOException { this(DownloadUtil.downloadModel(language, ModelType.POS, POSModel.class), format); } /** * Initializes a {@link POSTaggerME} with the provided {@link POSModel model}. * * @param model A valid {@link POSModel}. */ public POSTaggerME(POSModel model) { this(model, POSTagFormat.UD); } /** * Initializes a {@link POSTaggerME} with the provided {@link POSModel model}. * * @param model A valid {@link POSModel}. * @param format A valid {@link POSTagFormat}. */ public POSTaggerME(POSModel model, POSTagFormat format) { this.posTagFormat = format; POSTaggerFactory factory = model.getFactory(); int beamSize = POSTaggerME.DEFAULT_BEAM_SIZE; String beamSizeString = model.getManifestProperty(BeamSearch.BEAM_SIZE_PARAMETER); if (beamSizeString != null) { beamSize = Integer.parseInt(beamSizeString); } modelPackage = model; cg = factory.getPOSContextGenerator(beamSize); tagDictionary = factory.getTagDictionary(); size = beamSize; sequenceValidator = factory.getSequenceValidator(); if (model.getPosSequenceModel() != null) { this.model = model.getPosSequenceModel(); } else { this.model = new BeamSearch(beamSize, model.getArtifact(POSModel.POS_MODEL_ENTRY_NAME), 0); } this.posTagFormatMapper = (format == POSTagFormat.CUSTOM) ? new POSTagFormatMapper.NoOp() : new POSTagFormatMapper(getAllPosTags()); } /** * @return Retrieves an array of all possible part-of-speech tags from the tagger. */ public String[] getAllPosTags() { return model.getOutcomes(); } /** * {@inheritDoc} */ @Override public String[] tag(String[] sentence) { return this.tag(sentence, null); } /** * {@inheritDoc} */ @Override public String[] tag(String[] sentence, Object[] additionalContext) { bestSequence = model.bestSequence(sentence, additionalContext, cg, sequenceValidator); final List t = bestSequence.getOutcomes(); return convertTags(t); } /** * Returns at most the specified {@code numTaggings} for the specified {@code sentence}. * * @param numTaggings The number of tagging to be returned. * @param sentence An array of tokens which make up a sentence. * @return At most the specified number of taggings for the specified {@code sentence}. */ public String[][] tag(int numTaggings, String[] sentence) { Sequence[] bestSequences = model.bestSequences(numTaggings, sentence, null, cg, sequenceValidator); String[][] tags = new String[bestSequences.length][]; for (int si = 0; si < tags.length; si++) { List t = bestSequences[si].getOutcomes(); tags[si] = convertTags(t); } return tags; } private String[] convertTags(List t) { if (posTagFormat == POSTagFormat.CUSTOM || posTagFormatMapper.getGuessedFormat() == posTagFormat) { return t.toArray(new String[0]); } else { return posTagFormatMapper.convertTags(t); } } /** * {@inheritDoc} */ @Override public Sequence[] topKSequences(String[] sentence) { return this.topKSequences(sentence, null); } /** * {@inheritDoc} */ @Override public Sequence[] topKSequences(String[] sentence, Object[] additionalContext) { return model.bestSequences(size, sentence, additionalContext, cg, sequenceValidator); } /** * Populates the specified {@code probs} array with the probabilities * for each tag of the last tagged sentence. * * @param probs An array to put the probabilities into. */ public void probs(double[] probs) { bestSequence.getProbs(probs); } /** * {@inheritDoc} * * The sequence was determined based on the previous call to {@link #tag(String[])}. * * @return An array with the same number of probabilities as tokens were sent * to {@link #tag(String[])} when it was last called. */ @Override public double[] probs() { return bestSequence.getProbs(); } public String[] getOrderedTags(List words, List tags, int index) { return getOrderedTags(words, tags, index, null); } public String[] getOrderedTags(List words, List tags, int index, double[] tprobs) { MaxentModel posModel = modelPackage.getArtifact(POSModel.POS_MODEL_ENTRY_NAME); if (posModel != null) { double[] probs = posModel.eval(cg.getContext(index, words.toArray(new String[0]), tags.toArray(new String[0]), null)); String[] orderedTags = new String[probs.length]; for (int i = 0; i < probs.length; i++) { int max = 0; for (int ti = 1; ti < probs.length; ti++) { if (probs[ti] > probs[max]) { max = ti; } } orderedTags[i] = posModel.getOutcome(max); if (tprobs != null) { tprobs[i] = probs[max]; } probs[max] = 0; } return convertTags(Arrays.stream(orderedTags).toList()); } else { throw new UnsupportedOperationException("This method can only be called if the " + "classification model is an event model!"); } } /** * Starts a training of a {@link POSModel} with the given parameters. * * @param languageCode The ISO language code to train the model. Must not be {@code null}. * @param samples The {@link ObjectStream} of {@link POSSample} used as input for training. * @param mlParams The {@link TrainingParameters} for the context of the training process. * @param posFactory The {@link POSTaggerFactory} for creating related objects as defined * via {@code mlParams}. * * @return A valid, trained {@link POSModel} instance. * @throws IOException Thrown if IO errors occurred. */ public static POSModel train(String languageCode, ObjectStream samples, TrainingParameters mlParams, POSTaggerFactory posFactory) throws IOException { final int beamSize = mlParams.getIntParameter( BeamSearch.BEAM_SIZE_PARAMETER, POSTaggerME.DEFAULT_BEAM_SIZE); final POSContextGenerator contextGenerator = posFactory.getPOSContextGenerator(); final TrainerType trainerType = TrainerFactory.getTrainerType(mlParams); final Map manifestInfoEntries = new HashMap<>(); MaxentModel posModel = null; SequenceClassificationModel seqPosModel = null; if (TrainerType.EVENT_MODEL_TRAINER.equals(trainerType)) { ObjectStream es = new POSSampleEventStream(samples, contextGenerator); EventTrainer trainer = TrainerFactory.getEventTrainer(mlParams, manifestInfoEntries); posModel = trainer.train(es); } else if (TrainerType.EVENT_MODEL_SEQUENCE_TRAINER.equals(trainerType)) { POSSampleSequenceStream ss = new POSSampleSequenceStream(samples, contextGenerator); EventModelSequenceTrainer trainer = TrainerFactory.getEventModelSequenceTrainer(mlParams, manifestInfoEntries); posModel = trainer.train(ss); } else if (TrainerType.SEQUENCE_TRAINER.equals(trainerType)) { SequenceTrainer trainer = TrainerFactory.getSequenceModelTrainer( mlParams, manifestInfoEntries); // TODO: This will probably cause issue, since the feature generator uses the outcomes array POSSampleSequenceStream ss = new POSSampleSequenceStream(samples, contextGenerator); seqPosModel = trainer.train(ss); } else { throw new IllegalArgumentException("Trainer type is not supported: " + trainerType); } if (posModel != null) { return new POSModel(languageCode, posModel, beamSize, manifestInfoEntries, posFactory); } else { return new POSModel(languageCode, seqPosModel, manifestInfoEntries, posFactory); } } /** * Constructs a {@link Dictionary nGram dictionary} from an {@link ObjectStream} of samples. * * @param samples The {@link ObjectStream} to process. * @param cutoff A non-negative cut-off value. * @return A valid {@link Dictionary} instance holding nGrams. * @throws IOException Thrown if IO errors occurred during dictionary construction. */ public static Dictionary buildNGramDictionary(ObjectStream samples, int cutoff) throws IOException { NGramModel ngramModel = new NGramModel(); POSSample sample; while ((sample = samples.read()) != null) { String[] words = sample.getSentence(); if (words.length > 0) { ngramModel.add(new StringList(words), 1, 1); } } ngramModel.cutoff(cutoff, Integer.MAX_VALUE); return ngramModel.toDictionary(true); } /** * Populates a {@link POSDictionary} from an {@link ObjectStream} of samples. * * @param samples The {@link ObjectStream} to process. * @param dict The {@link MutableTagDictionary} to use during population. * @param cutoff A non-negative cut-off value. * @throws IOException Thrown if IO errors occurred during dictionary construction. */ public static void populatePOSDictionary(ObjectStream samples, MutableTagDictionary dict, int cutoff) throws IOException { logger.info("Expanding POS Dictionary ..."); long start = System.nanoTime(); // the data structure will store the word, the tag, and the number of // occurrences Map> newEntries = new HashMap<>(); POSSample sample; while ((sample = samples.read()) != null) { String[] words = sample.getSentence(); String[] tags = sample.getTags(); for (int i = 0; i < words.length; i++) { // only store words if (!StringPattern.recognize(words[i]).containsDigit()) { String word; if (dict.isCaseSensitive()) { word = words[i]; } else { word = StringUtil.toLowerCase(words[i]); } if (!newEntries.containsKey(word)) { newEntries.put(word, new HashMap<>()); } String[] dictTags = dict.getTags(word); if (dictTags != null) { for (String tag : dictTags) { // for this tags we start with the cutoff Map value = newEntries.get(word); if (!value.containsKey(tag)) { value.put(tag, new AtomicInteger(cutoff)); } } } if (!newEntries.get(word).containsKey(tags[i])) { newEntries.get(word).put(tags[i], new AtomicInteger(1)); } else { newEntries.get(word).get(tags[i]).incrementAndGet(); } } } } // now we check if the word + tag pairs have enough occurrences, if yes we // add it to the dictionary for (Entry> wordEntry : newEntries .entrySet()) { List tagsForWord = new ArrayList<>(); for (Entry entry : wordEntry.getValue().entrySet()) { if (entry.getValue().get() >= cutoff) { tagsForWord.add(entry.getKey()); } } if (!tagsForWord.isEmpty()) { dict.put(wordEntry.getKey(), tagsForWord.toArray(new String[0])); } } logger.info("... finished expanding POS Dictionary. [ {} ms]", (System.nanoTime() - start) / 1000000); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/TagDictionary.java0100644 0000000 0000000 00000002650 15217274217 032613 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; /** * Interface to determine which tags are valid for a particular word * based on a tag dictionary. */ public interface TagDictionary { /** * Retrieves a list of valid tags for the specified {@code word}. * * @param word The word. * @return An array of valid tags for the specified {@code word} or {@code null} if * no information is available for that word. */ String[] getTags(String word); /** * Whether the dictionary is case-sensitive or not. * * @return {@code true} if the dictionary is case-sensitive, else {@code false}. */ boolean isCaseSensitive(); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_postag_ThreadSaf0100644 0000000 0000000 00000000157 15217274217 032462 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/ThreadSafePOSTaggerME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/ThreadSafePOSTaggerME.jav0100644 0000000 0000000 00000010344 15217274217 033654 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.IOException; import opennlp.tools.commons.ThreadSafe; import opennlp.tools.ml.Probabilistic; import opennlp.tools.models.ModelType; import opennlp.tools.util.DownloadUtil; import opennlp.tools.util.Sequence; /** * A thread-safe version of the {@link POSTaggerME}. Using it is completely transparent. * You can use it in a single-threaded context as well, it only incurs a minimal overhead. *

* Note:
* This implementation uses a {@link ThreadLocal}. Although the implementation is * lightweight because the model is not duplicated, if you have many long-running threads, * you may run into memory problems. *

* Be careful when using this in a Jakarta EE application, for example. *

* The user is responsible for clearing the {@link ThreadLocal} * via calling {@link #close()}. * * @see POSTagger * @see POSTaggerME * @see Probabilistic */ @ThreadSafe public class ThreadSafePOSTaggerME implements POSTagger, Probabilistic, AutoCloseable { private final POSModel model; private final POSTagFormat posTagFormat; private final ThreadLocal threadLocal = new ThreadLocal<>(); /** * Initializes a {@link ThreadSafePOSTaggerME} by downloading a default model for a given * {@code language}. * * @param language An ISO conform language code. * @throws IOException Thrown if the model could not be downloaded or saved. */ public ThreadSafePOSTaggerME(String language) throws IOException { this(language, POSTagFormat.UD); } /** * Initializes a {@link ThreadSafePOSTaggerME} by downloading a default model * for a given {@code language}. * * @param language An ISO conform language code. * @param format A valid {@link POSTagFormat}. * @throws IOException Thrown if the model could not be downloaded or saved. */ public ThreadSafePOSTaggerME(String language, POSTagFormat format) throws IOException { this(DownloadUtil.downloadModel(language, ModelType.POS, POSModel.class), format); } /** * Initializes a {@link ThreadSafePOSTaggerME} with the specified {@code model}. * * @param model A valid {@link POSModel}. */ public ThreadSafePOSTaggerME(POSModel model) { this(model, POSTagFormat.UD); } /** * Initializes a {@link ThreadSafePOSTaggerME} with the specified {@link POSModel model}. * * @param model A valid {@link POSModel}. * @param format A valid {@link POSTagFormat}. */ public ThreadSafePOSTaggerME(POSModel model, POSTagFormat format) { super(); this.model = model; this.posTagFormat = format; } private POSTaggerME getTagger() { POSTaggerME tagger = threadLocal.get(); if (tagger == null) { tagger = new POSTaggerME(model, posTagFormat); threadLocal.set(tagger); } return tagger; } @Override public String[] tag(String[] sentence) { return getTagger().tag(sentence); } @Override public String[] tag(String[] sentence, Object[] additionaContext) { return getTagger().tag(sentence, additionaContext); } @Override public Sequence[] topKSequences(String[] sentence) { return getTagger().topKSequences(sentence); } @Override public Sequence[] topKSequences(String[] sentence, Object[] additionaContext) { return getTagger().topKSequences(sentence, additionaContext); } @Override public double[] probs() { return getTagger().probs(); } @Override public void close() { threadLocal.remove(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/WordTagSampleStream.java0100644 0000000 0000000 00000005071 15217274217 033737 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.postag; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ObjectStream; /** * A {@link FilterObjectStream stream filter} which reads a sentence per line that contains * words and tags in {@code word_tag} format and outputs a {@link POSSample} objects. */ public class WordTagSampleStream extends FilterObjectStream { private static final Logger logger = LoggerFactory.getLogger(WordTagSampleStream.class); /** * Initializes a {@link POSSample} instance. * * @param sentences The {@link ObjectStream sentences} to wrap. */ public WordTagSampleStream(ObjectStream sentences) { super(sentences); } /** * Reads the next tokens and parses it into the next {@link POSSample} object. *

* If an error occurs an empty {@link POSSample} object is returned * and a warning message is logged. Usually it does not matter if one * or many sentences are ignored. * * @return A valid {@link POSSample} or {@code null} if the * {@link ObjectStream stream} is exhausted. * * @throws IOException Thrown if IO errors occurred during read. */ @Override public POSSample read() throws IOException { String sentence = samples.read(); if (sentence != null) { POSSample sample; try { sample = POSSample.parse(sentence); } catch (InvalidFormatException e) { logger.warn("Error during parsing, ignoring sentence: {}", sentence, e); sample = new POSSample(new String[]{}, new String[]{}); } return sample; } else { return null; // sentences stream is exhausted } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/postag/package-info.java0100644 0000000 0000000 00000001566 15217274217 032403 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to part-of-speech tagging. */ package opennlp.tools.postag; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Defau0100644 0000000 0000000 00000000171 15217274217 032506 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/DefaultEndOfSentenceScanner.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/DefaultEndOfSentenceS0100644 0000000 0000000 00000004373 15217274217 034113 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Default implementation of the {@link EndOfSentenceScanner}. * It uses a character array with possible end of sentence chars * to identify potential sentence endings. */ public class DefaultEndOfSentenceScanner implements EndOfSentenceScanner { private final Set eosCharacters; /** * Initializes the current instance. * * @param eosCharacters The characters to be used to detect sentence endings. */ public DefaultEndOfSentenceScanner(char[] eosCharacters) { this.eosCharacters = new HashSet<>(); for (char eosChar: eosCharacters) { this.eosCharacters.add(eosChar); } } @Override public List getPositions(CharSequence s) { List l = new ArrayList<>(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (eosCharacters.contains(c)) { l.add(i); } } return l; } @Override public List getPositions(StringBuffer buf) { return getPositions(buf.toString().toCharArray()); } @Override public List getPositions(char[] cbuf) { List l = new ArrayList<>(); for (int i = 0; i < cbuf.length; i++) { if (eosCharacters.contains(cbuf[i])) { l.add(i); } } return l; } @Override public Set getEOSCharacters() { return eosCharacters; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Defau0100644 0000000 0000000 00000000167 15217274217 032513 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/DefaultSDContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/DefaultSDContextGener0100644 0000000 0000000 00000020201 15217274217 034130 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import opennlp.tools.util.StringUtil; /** * Generate event contexts for maxent decisions for sentence detection. * */ public class DefaultSDContextGenerator implements SDContextGenerator { /** * String buffer for generating features. */ protected final StringBuffer buf; /** * List for holding features as they are generated. */ protected final List collectFeats; private final Set inducedAbbreviations; private final Set eosCharacters; /** * Creates a new instance with no induced abbreviations. * * @param eosCharacters The characters to be used to detect sentence endings. */ public DefaultSDContextGenerator(char[] eosCharacters) { this(Collections.emptySet(), eosCharacters); } /** * Creates a new SDContextGenerator instance which uses * the set of induced abbreviations. * * @param inducedAbbreviations a Set of Strings * representing induced abbreviations in the training data. * Example: "Mr." * * @param eosCharacters The characters to be used to detect sentence endings. */ public DefaultSDContextGenerator(Set inducedAbbreviations, char[] eosCharacters) { this.inducedAbbreviations = inducedAbbreviations; this.eosCharacters = new HashSet<>(); for (char eosChar: eosCharacters) { this.eosCharacters.add(eosChar); } buf = new StringBuffer(); collectFeats = new ArrayList<>(); } private static String escapeChar(Character c) { if (c == '\n') { return ""; } if (c == '\r') { return ""; } return String.valueOf(c); } @Override public String[] getContext(CharSequence sb, int position) { /* * String preceding the eos character in the eos token. */ String prefix; /* * Space delimited token preceding token containing eos character. */ String previous; /* * String following the eos character in the eos token. */ String suffix; /* * Space delimited token following token containing eos character. */ String next; int lastIndex = sb.length() - 1; { // compute space previous and space next features. if (position > 0 && StringUtil.isWhitespace(sb.charAt(position - 1))) collectFeats.add("sp"); if (position < lastIndex && StringUtil.isWhitespace(sb.charAt(position + 1))) collectFeats.add("sn"); collectFeats.add("eos=" + escapeChar(sb.charAt(position))); } int prefixStart = previousSpaceIndex(sb, position); int c = position; { ///assign prefix, stop if you run into a period though otherwise stop at space while (--c > prefixStart) { if (eosCharacters.contains(sb.charAt(c))) { prefixStart = c; c++; // this gets us out of while loop. } } prefix = String.valueOf(sb.subSequence(prefixStart, position)).trim(); } int prevStart = previousSpaceIndex(sb, prefixStart); previous = String.valueOf(sb.subSequence(prevStart, prefixStart)).trim(); int suffixEnd = nextSpaceIndex(sb, position, lastIndex); { c = position; while (++c < suffixEnd) { if (eosCharacters.contains(sb.charAt(c))) { suffixEnd = c; c--; // this gets us out of while loop. } } } int nextEnd = nextSpaceIndex(sb, suffixEnd + 1, lastIndex + 1); if (position == lastIndex) { suffix = ""; next = ""; } else { suffix = String.valueOf(sb.subSequence(position + 1, suffixEnd)).trim(); next = String.valueOf(sb.subSequence(suffixEnd + 1, nextEnd)).trim(); } collectFeatures(prefix,suffix,previous,next, sb.charAt(position)); String[] context = new String[collectFeats.size()]; context = collectFeats.toArray(context); collectFeats.clear(); return context; } /** * Determines some features for the sentence detector and adds them to list features. * * @param prefix String preceding the {@code eosChar} in the eos token. * @param suffix String following the {@code eosChar} in the eos token. * @param previous Space delimited token preceding token containing {@code eosChar}. * @param next Space delimited token following token containing {@code eosChar}. * @param eosChar the EOS character been analyzed. */ protected void collectFeatures(String prefix, String suffix, String previous, String next, Character eosChar) { buf.append("x="); buf.append(prefix); collectFeats.add(buf.toString()); buf.setLength(0); if (!prefix.isEmpty()) { collectFeats.add(Integer.toString(prefix.length())); if (isFirstUpper(prefix)) { collectFeats.add("xcap"); } if (eosChar != null && inducedAbbreviations.contains(prefix + eosChar)) { collectFeats.add("xabbrev"); } } buf.append("v="); buf.append(previous); collectFeats.add(buf.toString()); buf.setLength(0); if (!previous.isEmpty()) { if (isFirstUpper(previous)) { collectFeats.add("vcap"); } if (inducedAbbreviations.contains(previous)) { collectFeats.add("vabbrev"); } } buf.append("s="); buf.append(suffix); collectFeats.add(buf.toString()); buf.setLength(0); if (!suffix.isEmpty()) { if (isFirstUpper(suffix)) { collectFeats.add("scap"); } if (inducedAbbreviations.contains(suffix)) { collectFeats.add("sabbrev"); } } buf.append("n="); buf.append(next); collectFeats.add(buf.toString()); buf.setLength(0); if (!next.isEmpty()) { if (isFirstUpper(next)) { collectFeats.add("ncap"); } if (inducedAbbreviations.contains(next)) { collectFeats.add("nabbrev"); } } } private static boolean isFirstUpper(String s) { return Character.isUpperCase(s.charAt(0)); } /** * Finds the index of the nearest space before a specified index which is not itself preceded by a space. * * @param sb The {@link CharSequence} which contains the text being examined. * @param seek The index to begin searching from. * @return The index which contains the nearest space. */ private static int previousSpaceIndex(CharSequence sb, int seek) { do { seek--; } while (seek > 0 && !StringUtil.isWhitespace(sb.charAt(seek))); if (seek > 0 && StringUtil.isWhitespace(sb.charAt(seek))) { while (seek > 0 && StringUtil.isWhitespace(sb.charAt(seek - 1))) seek--; return seek; } return 0; } /** * Finds the index of the nearest space after a specified index. * * @param sb The {@link CharSequence} which contains the text being examined. * @param seek The index to begin searching from. * @param lastIndex The highest index of the StringBuffer sb. * @return The index which contains the nearest space. */ private static int nextSpaceIndex(CharSequence sb, int seek, int lastIndex) { seek++; char c; while (seek < lastIndex) { c = sb.charAt(seek); if (StringUtil.isWhitespace(c)) { while (sb.length() > seek + 1 && StringUtil.isWhitespace(sb.charAt(seek + 1))) seek++; return seek; } seek++; } return lastIndex; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Empty0100644 0000000 0000000 00000000171 15217274217 032560 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/EmptyLinePreprocessorStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/EmptyLinePreprocessor0100644 0000000 0000000 00000004314 15217274217 034313 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.io.IOException; import opennlp.tools.commons.Internal; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * {@link ObjectStream} to clean up empty lines for empty line separated document streams.
* * - Skips empty line at training data start
* - Transforms multiple empty lines in a row into one
* - Replaces white space lines with empty lines
* - TODO: Terminates last document with empty line if it is missing
*
* This stream should be used by the components that mark empty lines to mark document boundaries. *

* Note: This class is not thread safe. *

* Note: Do not use this class, internal use only! */ @Internal public class EmptyLinePreprocessorStream extends FilterObjectStream { private boolean lastLineWasEmpty = true; public EmptyLinePreprocessorStream(ObjectStream in) { super(in); } private static boolean isLineEmpty(String line) { return line.trim().length() == 0; } @Override public String read() throws IOException { String line = samples.read(); if (lastLineWasEmpty) { lastLineWasEmpty = false; while (line != null && isLineEmpty(line)) { line = samples.read(); } } if (line != null && isLineEmpty(line)) { lastLineWasEmpty = true; line = ""; } return line; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_EndOf0100644 0000000 0000000 00000000162 15217274217 032455 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/EndOfSentenceScanner.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/EndOfSentenceScanner.0100644 0000000 0000000 00000004160 15217274217 034045 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.util.List; import java.util.Set; /** * Scans {@link CharSequence}, {@link StringBuffer}, and {@code char[]} for the offsets of * sentence ending characters. * *

Implementations of this interface can use regular expressions, * hand-coded DFAs, and other scanning techniques to locate end of * sentence offsets.

*/ public interface EndOfSentenceScanner { /** * @return a set of {@link Character characters} which can indicate the end of a sentence. */ Set getEOSCharacters(); /** * The receiver scans the specified string for sentence ending characters and * returns their offsets. * * @param s A {@link CharSequence} to be scanned. * @return A {@link List} of Integer objects. */ List getPositions(CharSequence s); /** * The receiver scans {@code buf} for sentence ending characters and * returns their offsets. * * @param buf A {@link StringBuffer} to be scanned. * @return A {@link List} of Integer objects. */ List getPositions(StringBuffer buf); /** * The receiver scans {@code cbuf} for sentence ending characters and * returns their offsets. * * @param cbuf A {@code char[]} to be scanned. * @return A {@link List} of Integer objects. */ List getPositions(char[] cbuf); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Newli0100644 0000000 0000000 00000000165 15217274217 032543 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/NewlineSentenceDetector.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/NewlineSentenceDetect0100644 0000000 0000000 00000003563 15217274217 034222 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.util.ArrayList; import java.util.List; import opennlp.tools.util.Span; /** * The Newline {@link SentenceDetector} assumes that sentences are line delimited and * recognizes one sentence per non-empty line. */ public class NewlineSentenceDetector implements SentenceDetector { @Override public String[] sentDetect(CharSequence s) { return Span.spansToStrings(sentPosDetect(s), s); } @Override public Span[] sentPosDetect(CharSequence s) { List sentences = new ArrayList<>(); int start = 0; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '\n' || c == '\r') { if (i - start > 0) { Span span = new Span(start, i).trim(s); if (span.length() > 0) { sentences.add(span); } start = i + 1; } } } if (s.length() - start > 0) { Span span = new Span(start, s.length()).trim(s); if (span.length() > 0) { sentences.add(span); } } return sentences.toArray(new Span[0]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_SDCon0100644 0000000 0000000 00000000160 15217274217 032426 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SDContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SDContextGenerator.ja0100644 0000000 0000000 00000002740 15217274217 034112 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; /** * Interface for {@link SentenceDetectorME} context generators. */ public interface SDContextGenerator { /** * Returns an array of contextual features for the potential sentence boundary at the * specified position within the specified string buffer. * * @param s The {@link String} for which sentences are being determined. * @param position An index into the specified string buffer when a sentence boundary may occur. * * @return an array of contextual features for the potential sentence boundary at the * specified {@code position} within the specified string buffer. */ String[] getContext(CharSequence s, int position); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_SDCro0100644 0000000 0000000 00000000156 15217274217 032437 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SDCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SDCrossValidator.java0100644 0000000 0000000 00000005362 15217274217 034110 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.io.IOException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.FMeasure; /** * A cross validator for {@link SentenceDetector sentence detectors}. */ public class SDCrossValidator { private final String languageCode; private final TrainingParameters params; private final FMeasure fmeasure = new FMeasure(); private final SentenceDetectorEvaluationMonitor[] listeners; private final SentenceDetectorFactory sdFactory; public SDCrossValidator(String languageCode, TrainingParameters params, SentenceDetectorFactory sdFactory, SentenceDetectorEvaluationMonitor... listeners) { this.languageCode = languageCode; this.params = params; this.listeners = listeners; this.sdFactory = sdFactory; } /** * Starts the evaluation. * * @param samples * the data to train and test * @param nFolds * number of folds * * @throws IOException Thrown if IO errors occurred during processing. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>(samples, nFolds); while (partitioner.hasNext()) { CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner.next(); SentenceModel model; model = SentenceDetectorME.train(languageCode, trainingSampleStream, sdFactory, params); // do testing SentenceDetectorEvaluator evaluator = new SentenceDetectorEvaluator( new SentenceDetectorME(model), listeners); evaluator.evaluate(trainingSampleStream.getTestSampleStream()); fmeasure.mergeInto(evaluator.getFMeasure()); } } public FMeasure getFMeasure() { return fmeasure; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SDEventStream.java0100644 0000000 0000000 00000004607 15217274217 033407 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import opennlp.tools.ml.model.Event; import opennlp.tools.util.AbstractEventStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; public class SDEventStream extends AbstractEventStream { private final SDContextGenerator cg; private final EndOfSentenceScanner scanner; /** * Initializes the current instance. * * @param samples An {@link ObjectStream stream} of {@link SentenceSample samples}. * @param cg The {@link SDContextGenerator} to be used. * @param scanner The {@link EndOfSentenceScanner scanner} to be used. */ public SDEventStream(ObjectStream samples, SDContextGenerator cg, EndOfSentenceScanner scanner) { super(samples); this.cg = cg; this.scanner = scanner; } @Override protected Iterator createEvents(SentenceSample sample) { Collection events = new ArrayList<>(); for (Span sentenceSpan : sample.getSentences()) { String sentenceString = sentenceSpan.getCoveredText(sample.getDocument()).toString(); for (Iterator it = scanner.getPositions( sentenceString).iterator(); it.hasNext();) { int candidate = it.next(); String type = SentenceDetectorME.NO_SPLIT; if (!it.hasNext()) { type = SentenceDetectorME.SPLIT; } events.add(new Event(type, cg.getContext(sample.getDocument(), sentenceSpan.getStart() + candidate))); } } return events.iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Sente0100644 0000000 0000000 00000000156 15217274217 032543 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetector.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetector.java0100644 0000000 0000000 00000003115 15217274217 034152 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import opennlp.tools.util.Span; /** * The interface for sentence detectors, which find the sentence boundaries in * a text. */ public interface SentenceDetector { /** * Detects sentences in a character sequence. * * @param s The {@link CharSequence} for which sentences shall to be detected. * @return The String[] with the individual sentences as the array * elements. */ String[] sentDetect(CharSequence s); /** * Detects sentences in a character sequence. * * @param s The {@link CharSequence} for which sentences shall be detected. * * @return The array of {@link Span spans} (offsets into {@code s}) for each * detected sentence as the individuals array elements. */ Span[] sentPosDetect(CharSequence s); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Sente0100644 0000000 0000000 00000000177 15217274217 032546 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorEvalu0100644 0000000 0000000 00000001736 15217274217 034236 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import opennlp.tools.util.eval.EvaluationMonitor; public interface SentenceDetectorEvaluationMonitor extends EvaluationMonitor { } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Sente0100644 0000000 0000000 00000000167 15217274217 032545 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorEvaluator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorEvalu0100644 0000000 0000000 00000005102 15217274217 034225 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import opennlp.tools.util.Span; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.FMeasure; /** * The {@link SentenceDetectorEvaluator} measures the performance of * the given {@link SentenceDetector} with the provided reference * {@link SentenceSample}s. * * @see Evaluator * @see SentenceDetector * @see SentenceSample */ public class SentenceDetectorEvaluator extends Evaluator { private final FMeasure fmeasure = new FMeasure(); /** * The {@link SentenceDetector} used to predict sentences. */ private final SentenceDetector sentenceDetector; /** * Initializes the current instance. * * @param sentenceDetector The {@link SentenceDetector} to be used for predicting sentences. * @param listeners The {@link SentenceDetectorEvaluationMonitor evaluation sample listeners}. */ public SentenceDetectorEvaluator(SentenceDetector sentenceDetector, SentenceDetectorEvaluationMonitor... listeners) { super(listeners); this.sentenceDetector = sentenceDetector; } private Span[] trimSpans(String document, Span[] spans) { Span[] trimedSpans = new Span[spans.length]; for (int i = 0; i < spans.length; i++) { trimedSpans[i] = spans[i].trim(document); } return trimedSpans; } @Override protected SentenceSample processSample(SentenceSample sample) { Span[] predictions = trimSpans(sample.getDocument(), sentenceDetector.sentPosDetect(sample.getDocument())); Span[] references = trimSpans(sample.getDocument(), sample.getSentences()); fmeasure.updateScores(references, predictions); return new SentenceSample(sample.getDocument(), predictions); } public FMeasure getFMeasure() { return fmeasure; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Sente0100644 0000000 0000000 00000000165 15217274217 032543 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorFacto0100644 0000000 0000000 00000021301 15217274217 034204 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.util.Collections; import java.util.Map; import java.util.Set; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.sentdetect.lang.Factory; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ext.ExtensionLoader; /** * The factory that provides {@link SentenceDetector} default implementations and * resources */ public class SentenceDetectorFactory extends BaseToolFactory { private String languageCode; private char[] eosCharacters; private Dictionary abbreviationDictionary; private Boolean useTokenEnd = null; private static final String ABBREVIATIONS_ENTRY_NAME = "abbreviations.dictionary"; private static final String EOS_CHARACTERS_PROPERTY = "eosCharacters"; private static final String TOKEN_END_PROPERTY = "useTokenEnd"; /** * Creates a {@link SentenceDetectorFactory} that provides the default * implementation of the resources. */ public SentenceDetectorFactory() { } /** * Creates a {@link SentenceDetectorFactory}. Use this constructor to * programmatically create a factory. * * @param languageCode The ISO language code to be used for this factory. * @param useTokenEnd {@code true} if {@link #TOKEN_END_PROPERTY} shall be used, {@code false} otherwise. * @param abbreviationDictionary The {@link Dictionary} which holds abbreviations. * @param eosCharacters The characters to be used to detect sentence endings. */ public SentenceDetectorFactory(String languageCode, boolean useTokenEnd, Dictionary abbreviationDictionary, char[] eosCharacters) { this.init(languageCode, useTokenEnd, abbreviationDictionary, eosCharacters); } protected void init(String languageCode, boolean useTokenEnd, Dictionary abbreviationDictionary, char[] eosCharacters) { this.languageCode = languageCode; this.useTokenEnd = useTokenEnd; this.eosCharacters = eosCharacters; this.abbreviationDictionary = abbreviationDictionary; } @Override public void validateArtifactMap() throws InvalidFormatException { if (this.artifactProvider.getManifestProperty(TOKEN_END_PROPERTY) == null) throw new InvalidFormatException(TOKEN_END_PROPERTY + " is a mandatory property!"); Object abbreviationsEntry = this.artifactProvider.getArtifact(ABBREVIATIONS_ENTRY_NAME); if (abbreviationsEntry != null && !(abbreviationsEntry instanceof Dictionary)) { throw new InvalidFormatException( "Abbreviations dictionary '" + abbreviationsEntry + "' has wrong type, needs to be of type Dictionary!"); } } @Override public Map createArtifactMap() { Map artifactMap = super.createArtifactMap(); // Abbreviations are optional if (abbreviationDictionary != null) artifactMap.put(ABBREVIATIONS_ENTRY_NAME, abbreviationDictionary); return artifactMap; } @Override public Map createManifestEntries() { Map manifestEntries = super.createManifestEntries(); manifestEntries.put(TOKEN_END_PROPERTY, Boolean.toString(isUseTokenEnd())); // EOS characters are optional if (getEOSCharacters() != null) manifestEntries.put(EOS_CHARACTERS_PROPERTY, eosCharArrayToString(getEOSCharacters())); return manifestEntries; } /** * Instantiates a {@link SentenceDetectorFactory} via a given {@code subclassName}. * * @param subclassName The class name used for instantiation. If {@code null}, an * instance of {@link SentenceDetectorFactory} will be returned * per default. Otherwise, the {@link ExtensionLoader} mechanism * is applied to load the requested {@code subclassName}. * @param languageCode The ISO language code to be used. Must not be {@code null}. * @param useTokenEnd {@code true} if {@link #TOKEN_END_PROPERTY} shall be set, * {@code false} otherwise. * @param abbrDictionary The {@link Dictionary} of abbreviations if available; * may be {@code null}. * @param eosChars An array of characters representing end of sentence * symbols / characters. * * @return A valid {@link SentenceDetectorFactory} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the factory associated with {@code subclassName}. */ public static SentenceDetectorFactory create(String subclassName, String languageCode, boolean useTokenEnd, Dictionary abbrDictionary, char[] eosChars) throws InvalidFormatException { if (subclassName == null) { // will create the default factory return new SentenceDetectorFactory(languageCode, useTokenEnd, abbrDictionary, eosChars); } try { SentenceDetectorFactory theFactory = ExtensionLoader.instantiateExtension( SentenceDetectorFactory.class, subclassName); theFactory.init(languageCode, useTokenEnd, abbrDictionary, eosChars); return theFactory; } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization throw an exception."; throw new InvalidFormatException(msg, e); } } public char[] getEOSCharacters() { if (this.eosCharacters == null) { if (artifactProvider != null) { String prop = this.artifactProvider .getManifestProperty(EOS_CHARACTERS_PROPERTY); if (prop != null) { this.eosCharacters = eosStringToCharArray(prop); } } else { // get from language dependent factory Factory f = new Factory(); this.eosCharacters = f.getEOSCharacters(languageCode); } } return this.eosCharacters; } public boolean isUseTokenEnd() { if (this.useTokenEnd == null && artifactProvider != null) { this.useTokenEnd = Boolean.valueOf(artifactProvider .getManifestProperty(TOKEN_END_PROPERTY)); } return this.useTokenEnd; } /** * @return An abbreviation {@link Dictionary} or {@code null} if unset. */ public Dictionary getAbbreviationDictionary() { if (this.abbreviationDictionary == null && artifactProvider != null) { this.abbreviationDictionary = artifactProvider .getArtifact(ABBREVIATIONS_ENTRY_NAME); } return this.abbreviationDictionary; } public String getLanguageCode() { if (this.languageCode == null && artifactProvider != null) { this.languageCode = this.artifactProvider.getLanguage(); } return this.languageCode; } /** * @return An {@link EndOfSentenceScanner} instance, guaranteed to be not {@code null}. */ public EndOfSentenceScanner getEndOfSentenceScanner() { Factory f = new Factory(); char[] eosChars = getEOSCharacters(); if (eosChars != null && eosChars.length > 0) { return f.createEndOfSentenceScanner(eosChars); } else { return f.createEndOfSentenceScanner(this.languageCode); } } /** * @return A {@link SDContextGenerator} instance, guaranteed to be not {@code null}. */ public SDContextGenerator getSDContextGenerator() { Factory f = new Factory(); char[] eosChars = getEOSCharacters(); Set abbs; Dictionary abbDict = getAbbreviationDictionary(); if (abbDict != null) { abbs = abbDict.asStringSet(); } else { abbs = Collections.emptySet(); } if (eosChars != null && eosChars.length > 0) { return f.createSentenceContextGenerator(abbs, eosChars); } else { return f.createSentenceContextGenerator(this.languageCode, abbs); } } private String eosCharArrayToString(char[] eosCharacters) { return String.valueOf(eosCharacters); } private char[] eosStringToCharArray(String eosCharacters) { return eosCharacters.toCharArray(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Sente0100644 0000000 0000000 00000000160 15217274217 032536 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceDetectorME.ja0100644 0000000 0000000 00000051755 15217274217 034062 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.Probabilistic; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.models.ModelType; import opennlp.tools.sentdetect.lang.Factory; import opennlp.tools.util.DownloadUtil; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; import opennlp.tools.util.StringList; import opennlp.tools.util.StringUtil; import opennlp.tools.util.TrainingParameters; /** * A sentence detector for splitting up raw text into sentences. *

* A maximum entropy model is used to evaluate end-of-sentence characters in a * string to determine if they signify the end of a sentence. */ public class SentenceDetectorME implements SentenceDetector, Probabilistic { /** * Constant indicates a sentence split. */ public static final String SPLIT = "s"; /** * Constant indicates no sentence split. */ public static final String NO_SPLIT = "n"; /** * The maximum entropy model to use to evaluate contexts. */ private final MaxentModel model; /** * The feature context generator. */ private final SDContextGenerator cgen; /** * The {@link EndOfSentenceScanner} to use when scanning for end of sentence offsets. */ private final EndOfSentenceScanner scanner; /** * The list of probabilities associated with each decision. */ private final List sentProbs = new ArrayList<>(); /** * The abbreviation dictionary index that backs {@link #isAcceptableBreak(CharSequence, int, int)}. * It is {@code null} if no abbreviation dictionary is available for the underlying model. */ private final AbbreviationIndex abbIndex; protected final boolean useTokenEnd; /** * Initializes the sentence detector by downloading a default model. * @param language The language of the sentence detector. * @throws IOException Thrown if the model cannot be downloaded or saved. */ public SentenceDetectorME(String language) throws IOException { this(DownloadUtil.downloadModel(language, ModelType.SENTENCE_DETECTOR, SentenceModel.class)); } /** * Initializes the current instance. * * @param model the {@link SentenceModel} */ public SentenceDetectorME(SentenceModel model) { this(model, model.getAbbreviations()); } /** * Instantiates a {@link SentenceDetectorME} with an existing {@link SentenceModel}. * * @param model The {@link SentenceModel} to be used. * @param abbDict The {@link Dictionary} to be used. It must fit the language of the {@code model}. * Its entries are read once, here; later changes to the {@code abbDict} instance do not * affect this detector. */ public SentenceDetectorME(SentenceModel model, Dictionary abbDict) { this.model = model.getMaxentModel(); this.abbIndex = AbbreviationIndex.of(abbDict); SentenceDetectorFactory sdFactory = model.getFactory(); cgen = sdFactory.getSDContextGenerator(); scanner = sdFactory.getEndOfSentenceScanner(); useTokenEnd = sdFactory.isUseTokenEnd(); } /** * @deprecated Use a {@link SentenceDetectorFactory} to extend * SentenceDetector functionality. */ @Deprecated public SentenceDetectorME(SentenceModel model, Factory factory) { this.model = model.getMaxentModel(); // if the model has custom EOS characters set, use this to get the context // generator and the EOS scanner; otherwise use language-specific defaults char[] customEOSCharacters = model.getEosCharacters(); if (customEOSCharacters == null) { cgen = factory.createSentenceContextGenerator(model.getLanguage(), getAbbreviations(model.getAbbreviations())); scanner = factory.createEndOfSentenceScanner(model.getLanguage()); } else { cgen = factory.createSentenceContextGenerator( getAbbreviations(model.getAbbreviations()), customEOSCharacters); scanner = factory.createEndOfSentenceScanner(customEOSCharacters); } abbIndex = AbbreviationIndex.of(model.getAbbreviations()); useTokenEnd = model.useTokenEnd(); } private static Set getAbbreviations(Dictionary abbreviations) { if (abbreviations == null) { return Collections.emptySet(); } return abbreviations.asStringSet(); } /** * Detects sentences in given input {@link CharSequence}.. * * @param s The {@link CharSequence}. to be processed. * * @return A string array containing individual sentences as elements. */ @Override public String[] sentDetect(CharSequence s) { Span[] spans = sentPosDetect(s); String[] sentences; if (spans.length != 0) { sentences = new String[spans.length]; for (int si = 0; si < spans.length; si++) { sentences[si] = spans[si].getCoveredText(s).toString(); } } else { sentences = new String[] {}; } return sentences; } private int getFirstWS(CharSequence s, int pos) { while (pos < s.length() && !StringUtil.isWhitespace(s.charAt(pos))) pos++; return pos; } private int getFirstNonWS(CharSequence s, int pos) { while (pos < s.length() && StringUtil.isWhitespace(s.charAt(pos))) pos++; return pos; } /** * Detects the position of the first words of sentences in a {@link CharSequence}. * * @param s The {@link CharSequence} to be processed. * @return An {@link Span span array} containing the positions of the end index of * every sentence. * */ @Override public Span[] sentPosDetect(CharSequence s) { sentProbs.clear(); List enders = scanner.getPositions(s); List positions = new ArrayList<>(enders.size()); for (int i = 0, end = enders.size(), index = 0; i < end; i++) { int cint = enders.get(i); // skip over the leading parts of non-token final delimiters int fws = getFirstWS(s,cint + 1); if (i + 1 < end && enders.get(i + 1) < fws) { // Do not skip if the character right after the delimiter is uppercase, // as this likely indicates the start of a new sentence (e.g., "Gedanken.Bek.") // rather than a multi-period abbreviation (e.g., "z.B."). int nextCharIdx = cint + 1; if (nextCharIdx >= s.length() || !Character.isUpperCase(s.charAt(nextCharIdx))) { continue; } } if (positions.size() > 0 && cint < positions.get(positions.size() - 1)) continue; double[] probs = model.eval(cgen.getContext(s, cint)); String bestOutcome = model.getBestOutcome(probs); if (bestOutcome.equals(SPLIT) && isAcceptableBreak(s, index, cint)) { if (index != cint) { if (useTokenEnd) { positions.add(getFirstNonWS(s, getFirstWS(s,cint + 1))); } else { positions.add(getFirstNonWS(s, cint + 1)); } sentProbs.add(probs[model.getIndex(bestOutcome)]); } index = cint + 1; } } int[] starts = ArrayMath.toIntArray(positions); // string does not contain sentence end positions if (starts.length == 0) { // remove leading and trailing whitespace int start = 0; int end = s.length(); while (start < s.length() && StringUtil.isWhitespace(s.charAt(start))) start++; while (end > 0 && StringUtil.isWhitespace(s.charAt(end - 1))) end--; if (end - start > 0) { sentProbs.add(1d); return new Span[] {new Span(start, end)}; } else return new Span[0]; } // Convert the sentence end indexes to spans boolean leftover = starts[starts.length - 1] != s.length(); Span[] spans = new Span[leftover ? starts.length + 1 : starts.length]; for (int si = 0; si < starts.length; si++) { int start; if (si == 0) { start = 0; } else { start = starts[si - 1]; } // A span might contain only white spaces, in this case the length of // the span will be zero after trimming and should be ignored. Span span = new Span(start, starts[si]).trim(s); if (span.length() > 0) { spans[si] = span; } else { sentProbs.remove(si); } } if (leftover) { Span span = new Span(starts[starts.length - 1], s.length()).trim(s); if (span.length() > 0) { spans[spans.length - 1] = span; sentProbs.add(1d); } } /* * set the prob for each span */ for (int i = 0; i < spans.length; i++) { double prob = sentProbs.get(i); spans[i] = new Span(spans[i], prob); } return spans; } /** * {@inheritDoc} * * The sequence was determined based on the previous call to * {@link #sentDetect(CharSequence)}. * * @return An array with the same number of probabilities as tokens were sent to * {@link #sentDetect(CharSequence)} when it was last called. * If not applicable, an empty array is returned. */ @Override public double[] probs() { return ArrayMath.toDoubleArray(sentProbs); } /** * * @return The probability for each sentence returned for the most recent * call to {@link #sentDetect(CharSequence)}. * If not applicable, an empty array is returned. * * @deprecated Use {@link #probs()} instead. */ @Deprecated(forRemoval = true, since = "2.5.5") public double[] getSentenceProbabilities() { return probs(); } /** * Allows subclasses to check an overzealous (read: poorly * trained) model from flagging obvious non-breaks as breaks based * on some boolean determination of a break's acceptability. * *

Note: The implementation always returns {@code true} if no * abbreviation dictionary is available for the underlying model.

* *

Only a bounded region of {@code s} is consulted. An abbreviation occurrence starting at * {@code p} with length {@code L} can veto the break only when it starts at or before the * candidate and reaches it, that is when * {@code candidateIndex - L <= p <= candidateIndex}. Positions outside that window are * irrelevant by construction, so the decision costs time proportional to the longest * dictionary entry rather than to the length of {@code s}.

* *

A {@code candidateIndex} past the end of {@code s} cannot carry an abbreviation, so it * is accepted rather than raising an {@link IndexOutOfBoundsException}. At * {@code candidateIndex == s.length()}, the decision matches the previous implementation when * the match is not at {@code fromIndex}; only the match-at-{@code fromIndex} case is an * accept-instead-of-throw relaxation.

* * @param s the {@link CharSequence} in which the break occurred. * @param fromIndex the start of the segment currently being evaluated. * @param candidateIndex the index of the candidate sentence ending. Must be greater than or * equal to {@code fromIndex} and a valid index into {@code s}. * @return {@code true} if the break is acceptable, {@code false} otherwise. */ protected boolean isAcceptableBreak(CharSequence s, int fromIndex, int candidateIndex) { return abbIndex == null || abbIndex.allowsBreak(s, fromIndex, candidateIndex); } /** * An immutable, length-bucketed index over an abbreviation {@link Dictionary}. It answers * {@link #isAcceptableBreak(CharSequence, int, int)} by enumerating the few text positions * that can carry a relevant abbreviation and asking a hash set what is there, instead of * searching the whole text once per dictionary entry. */ private static final class AbbreviationIndex { /** * The dictionary entries, folded to lower case unless the dictionary is case-sensitive. * Only the first token of a multi-token entry participates, as before. */ private final Set entries; /** * The distinct entry lengths, ascending. These are the only window sizes worth probing. */ private final int[] entryLengths; /** * The longest entry length, that is how far past a candidate a relevant match can reach. */ private final int maxEntryLength; /** * Whether the dictionary matches case-sensitively. */ private final boolean caseSensitive; /** * @param abbDict The {@link Dictionary} to index, may be {@code null}. * @return An index over {@code abbDict}, or {@code null} if {@code abbDict} is {@code null}. */ static AbbreviationIndex of(Dictionary abbDict) { return abbDict == null ? null : new AbbreviationIndex(abbDict); } /** * Reads {@code abbDict} once, so this instance is immutable and safe to share. * * @param abbDict The {@link Dictionary} to index. Must not be {@code null}. */ private AbbreviationIndex(Dictionary abbDict) { caseSensitive = abbDict.isCaseSensitive(); final Set tokens = new HashSet<>(); final SortedSet lengths = new TreeSet<>(); for (StringList abb : abbDict) { final String token = caseSensitive ? abb.getToken(0) : StringUtil.toLowerCase(abb.getToken(0)); tokens.add(token); lengths.add(token.length()); } entries = tokens; entryLengths = lengths.stream().mapToInt(Integer::intValue).toArray(); maxEntryLength = entryLengths.length == 0 ? 0 : entryLengths[entryLengths.length - 1]; } /** * @param s The text in which the break occurred. * @param fromIndex The start of the segment currently being evaluated. * @param candidateIndex The index of the candidate sentence ending. * @return {@code true} if a break at {@code candidateIndex} is allowed. */ boolean allowsBreak(CharSequence s, int fromIndex, int candidateIndex) { final int textLength = s.length(); if (entryLengths.length == 0 || candidateIndex < fromIndex || candidateIndex < 0 || candidateIndex > textLength) { return true; } // Occurrences before the segment start do not participate. final int scanStart = StrictMath.max(0, fromIndex); // The window holds every position a relevant occurrence can start at, plus the longest // entry so that the text of an occurrence starting at the candidate is covered too. final int windowStart = codePointStart(s, StrictMath.max(scanStart, candidateIndex - maxEntryLength)); final int windowEnd = codePointEnd(s, StrictMath.min(textLength, candidateIndex + maxEntryLength)); // Case folding is applied to the window only. It is per code point, so it preserves // indices and yields exactly the characters a folding of the whole text would. final String window = caseSensitive ? s.subSequence(windowStart, windowEnd).toString() : toLowerCase(s, windowStart, windowEnd); for (final int tokenLength : entryLengths) { for (int pos = StrictMath.max(scanStart, candidateIndex - tokenLength); pos <= candidateIndex; pos++) { final int endPos = pos + tokenLength; if (endPos > textLength) { break; // the entry no longer fits, and it fits even less further right } if (!entries.contains(window.substring(pos - windowStart, endPos - windowStart))) { continue; } if (pos == fromIndex && endPos == candidateIndex + 1) { return false; // full abbreviation match at segment start -> no acceptable break } final char prevChar = s.charAt(pos == fromIndex ? pos : pos - 1); /* * Note: * Skip abbreviation candidate if regular characters exist directly before it, * That is, any letter or digit except: a whitespace, an apostrophe, or an opening round bracket. * This prevents mismatches from overlaps close to an actual sentence end. */ if (Character.isWhitespace(prevChar) || isApostrophe(prevChar) || prevChar == '(') { return false; // in case of a valid abbreviation: the (sentence) break is not accepted } } } return true; // no abbreviation(s) at given positions: valid sentence boundary } /** * Lower-cases {@code [from, to)} exactly as {@link StringUtil#toLowerCase(CharSequence)} * lower-cases a whole text: per code point via {@link Character#toLowerCase(int)}. * *

Folding only the window is correct only because that mapping is 1:1 in {@code char} * count, so {@code pos - windowStart} taken from the unfolded text still indexes the folded * window. {@link String#toLowerCase()} must not be used here: full case mapping can expand * a code point (for example {@code İ} / U+0130) and would corrupt every offset in the window.

* * @param s The text to read from. * @param from The first index to fold, at a code point boundary. * @param to The index to stop at, at a code point boundary. * @return The folded characters of {@code [from, to)}. */ private static String toLowerCase(CharSequence s, int from, int to) { final StringBuilder folded = new StringBuilder(to - from); int i = from; while (i < to) { final int cp = Character.codePointAt(s, i); folded.appendCodePoint(Character.toLowerCase(cp)); i += Character.charCount(cp); } return folded.toString(); } /** * @param s The text {@code index} refers to. * @param index The index to align. * @return {@code index}, moved one character left if it points at the trailing half of a * surrogate pair, which is the only index a code point walk cannot start at. */ private static int codePointStart(CharSequence s, int index) { if (index > 0 && index < s.length() && Character.isLowSurrogate(s.charAt(index)) && Character.isHighSurrogate(s.charAt(index - 1))) { return index - 1; } return index; } /** * @param s The text {@code index} refers to. * @param index The index to align. * @return {@code index}, moved one character right if it splits a surrogate pair, which is * the only index a code point walk cannot stop at. */ private static int codePointEnd(CharSequence s, int index) { if (index > 0 && index < s.length() && Character.isHighSurrogate(s.charAt(index - 1)) && Character.isLowSurrogate(s.charAt(index))) { return index + 1; } return index; } } /** * @param c The character to check. * @return {@code true} if the character represents an apostrophe, {@code false} otherwise. */ private static boolean isApostrophe(char c) { return c == '\'' || c == '`' || c == '´'; } /** * Starts a training of a {@link SentenceModel} with the given parameters. * * @param languageCode The ISO language code to train the model. Must not be {@code null}. * @param samples The {@link ObjectStream} of {@link SentenceSample} used as input for training. * @param sdFactory The {@link SentenceDetectorFactory} for creating related objects as defined * via {@code mlParams}. * @param mlParams The {@link TrainingParameters} for the context of the training process. * * @return A valid, trained {@link SentenceModel} instance. * @throws IOException Thrown if IO errors occurred. */ public static SentenceModel train(String languageCode, ObjectStream samples, SentenceDetectorFactory sdFactory, TrainingParameters mlParams) throws IOException { Map manifestInfoEntries = new HashMap<>(); // TODO: Fix the EventStream to throw exceptions when training goes wrong ObjectStream eventStream = new SDEventStream(samples, sdFactory.getSDContextGenerator(), sdFactory.getEndOfSentenceScanner()); EventTrainer trainer = TrainerFactory.getEventTrainer(mlParams, manifestInfoEntries); MaxentModel sentModel = trainer.train(eventStream); return new SentenceModel(languageCode, sentModel, manifestInfoEntries, sdFactory); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceModel.java0100644 0000000 0000000 00000011642 15217274217 033445 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Path; import java.util.Map; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.BaseModel; import opennlp.tools.util.model.ModelUtil; /** * The {@link SentenceModel} is the model used by a learnable * {@link SentenceDetector}. * * @see SentenceDetectorME */ public class SentenceModel extends BaseModel { private static final long serialVersionUID = -8374532795287293730L; private static final String COMPONENT_NAME = "SentenceDetectorME"; private static final String MAXENT_MODEL_ENTRY_NAME = "sent.model"; /** * Initializes a {@link SentenceModel} instance via given parameters. * * @param languageCode The ISO language code for this model. Must not be {@code null}. * @param sentModel A valid {@link MaxentModel}. * @param manifestInfoEntries Additional information kept in the manifest. * @param sdFactory The {@link SentenceDetectorFactory} for creating related objects. */ public SentenceModel(String languageCode, MaxentModel sentModel, Map manifestInfoEntries, SentenceDetectorFactory sdFactory) { super(COMPONENT_NAME, languageCode, manifestInfoEntries, sdFactory); artifactMap.put(MAXENT_MODEL_ENTRY_NAME, sentModel); checkArtifactMap(); } /** * Initializes a {@link SentenceModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public SentenceModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link SentenceModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public SentenceModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link SentenceModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public SentenceModel(Path modelPath) throws IOException { this(modelPath.toFile()); } /** * Initializes a {@link SentenceModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public SentenceModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(MAXENT_MODEL_ENTRY_NAME) instanceof MaxentModel)) { throw new InvalidFormatException("Unable to find " + MAXENT_MODEL_ENTRY_NAME + " maxent model!"); } if (!ModelUtil.validateOutcomes(getMaxentModel(), SentenceDetectorME.SPLIT, SentenceDetectorME.NO_SPLIT)) { throw new InvalidFormatException("The maxent model is not compatible " + "with the sentence detector!"); } } public SentenceDetectorFactory getFactory() { return (SentenceDetectorFactory) this.toolFactory; } @Override protected Class getDefaultFactory() { return SentenceDetectorFactory.class; } public MaxentModel getMaxentModel() { return (MaxentModel) artifactMap.get(MAXENT_MODEL_ENTRY_NAME); } public Dictionary getAbbreviations() { if (getFactory() != null) { return getFactory().getAbbreviationDictionary(); } return null; } public boolean useTokenEnd() { return getFactory() == null || getFactory().isUseTokenEnd(); } public char[] getEosCharacters() { if (getFactory() != null) { return getFactory().getEOSCharacters(); } return null; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceSample.java0100644 0000000 0000000 00000007346 15217274217 033634 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import opennlp.tools.commons.Sample; import opennlp.tools.tokenize.Detokenizer; import opennlp.tools.util.Span; /** * A {@link SentenceSample} contains a document with * begin indexes of the individual sentences. */ public class SentenceSample implements Sample { private static final long serialVersionUID = 1771522768104567531L; private final String document; private final List sentences; /** * Initializes the current instance. * * @param document The document represented as plain {@link CharSequence}. * @param sentences One or more {@link Span spans} that represent a sentence each. */ public SentenceSample(CharSequence document, Span... sentences) { this.document = document.toString(); this.sentences = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(sentences))); // validate that all spans are inside the document text for (Span sentence : sentences) { if (sentence.getEnd() > document.length()) { throw new IllegalArgumentException( String.format("Sentence span is outside of document text [len %d] and span %s", document.length(), sentence)); } } } public SentenceSample(Detokenizer detokenizer, String[][] sentences) { List spans = new ArrayList<>(sentences.length); StringBuilder documentBuilder = new StringBuilder(); for (String[] sentenceTokens : sentences) { String sampleSentence = detokenizer.detokenize(sentenceTokens, null); int beginIndex = documentBuilder.length(); documentBuilder.append(sampleSentence); spans.add(new Span(beginIndex, documentBuilder.length())); } document = documentBuilder.toString(); this.sentences = Collections.unmodifiableList(spans); } /** * @return the document as a plain string. */ public String getDocument() { return document; } /** * @return the {@link Span spans} of the sentences in a document. */ public Span[] getSentences() { return sentences.toArray(new Span[0]); } // TODO: This one must output the tags! @Override public String toString() { StringBuilder documentBuilder = new StringBuilder(); for (Span sentSpan : sentences) { documentBuilder.append(sentSpan.getCoveredText(document).toString() .replace("\r", "").replace("\n", "")); documentBuilder.append("\n"); } return documentBuilder.toString(); } @Override public int hashCode() { return Objects.hash(getDocument(), Arrays.hashCode(getSentences())); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof SentenceSample a) { return getDocument().equals(a.getDocument()) && Arrays.equals(getSentences(), a.getSentences()); } return false; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Sente0100644 0000000 0000000 00000000162 15217274217 032540 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/SentenceSampleStream.0100644 0000000 0000000 00000004433 15217274217 034140 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.io.IOException; import java.util.LinkedList; import java.util.List; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * This class is a stream filter which reads a sentence by line samples from * an {@link ObjectStream} and converts them into {@link SentenceSample} objects. * An empty line indicates the beginning of a new document. */ public class SentenceSampleStream extends FilterObjectStream { public SentenceSampleStream(ObjectStream sentences) { super(new EmptyLinePreprocessorStream(sentences)); } public static String replaceNewLineEscapeTags(String s) { return s.replace("", "\n").replace("", "\r"); } @Override public SentenceSample read() throws IOException { StringBuilder sentencesString = new StringBuilder(); List sentenceSpans = new LinkedList<>(); String sentence; while ((sentence = samples.read()) != null && !sentence.isEmpty()) { int begin = sentencesString.length(); sentence = sentence.trim(); sentence = replaceNewLineEscapeTags(sentence); sentencesString.append(sentence); int end = sentencesString.length(); sentenceSpans.add(new Span(begin, end)); sentencesString.append(' '); } if (!sentenceSpans.isEmpty()) { return new SentenceSample(sentencesString.toString(), sentenceSpans.toArray(new Span[0])); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_Threa0100644 0000000 0000000 00000000172 15217274217 032526 xustar000000000 0000000 122 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/ThreadSafeSentenceDetectorME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/ThreadSafeSentenceDet0100644 0000000 0000000 00000007601 15217274217 034130 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect; import java.io.IOException; import opennlp.tools.commons.ThreadSafe; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.Probabilistic; import opennlp.tools.models.ModelType; import opennlp.tools.util.DownloadUtil; import opennlp.tools.util.Span; /** * A thread-safe version of {@link SentenceDetectorME}. Using it is completely transparent. * You can use it in a single-threaded context as well, it only incurs a minimal overhead. *

* Note:
* This implementation uses a {@link ThreadLocal}. Although the implementation is * lightweight because the model is not duplicated, if you have many long-running threads, * you may run into memory problems. *

* Be careful when using this in a Jakarta EE application, for example. *

* The user is responsible for clearing the {@link ThreadLocal} * via calling {@link #close()}. * * @see Probabilistic * @see SentenceDetector * @see SentenceDetectorME */ @ThreadSafe public class ThreadSafeSentenceDetectorME implements SentenceDetector, Probabilistic, AutoCloseable { private final SentenceModel model; private final Dictionary abbDict; private final ThreadLocal threadLocal = new ThreadLocal<>(); /** * Initializes a {@link ThreadSafeSentenceDetectorME} by downloading a default model * for a given {@code language}. * * @param language An ISO conform language code. * @throws IOException Thrown if the model could not be downloaded or saved. */ public ThreadSafeSentenceDetectorME(String language) throws IOException { this(DownloadUtil.downloadModel(language, ModelType.SENTENCE_DETECTOR, SentenceModel.class)); } /** * Initializes a {@link ThreadSafeSentenceDetectorME} with the specified {@code model}. * * @param model A valid {@link SentenceModel}. */ public ThreadSafeSentenceDetectorME(SentenceModel model) { this(model, model.getAbbreviations()); } /** * Instantiates a {@link ThreadSafeSentenceDetectorME} with an existing {@link SentenceModel}. * * @param model The {@link SentenceModel} to be used. * @param abbDict The {@link Dictionary} to be used. It must fit the language of the {@code model}. */ public ThreadSafeSentenceDetectorME(SentenceModel model, Dictionary abbDict) { this.model = model; this.abbDict = abbDict; } // If a thread-local version exists, return it. Otherwise, create, then return. private SentenceDetectorME getSD() { SentenceDetectorME sd = threadLocal.get(); if (sd == null) { sd = new SentenceDetectorME(model, abbDict); threadLocal.set(sd); } return sd; } @Override public String[] sentDetect(CharSequence s) { return getSD().sentDetect(s); } @Override public Span[] sentPosDetect(CharSequence s) { return getSD().sentPosDetect(s); } /** * @deprecated Use {@link #probs()} instead. */ @Deprecated public double[] getSentenceProbabilities() { return probs(); } @Override public double[] probs() { return getSD().probs(); } @Override public void close() { threadLocal.remove(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/lang/Factory.java0100644 0000000 0000000 00000006060 15217274217 033246 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect.lang; import java.util.Collections; import java.util.Set; import opennlp.tools.sentdetect.DefaultEndOfSentenceScanner; import opennlp.tools.sentdetect.DefaultSDContextGenerator; import opennlp.tools.sentdetect.EndOfSentenceScanner; import opennlp.tools.sentdetect.SDContextGenerator; import opennlp.tools.sentdetect.lang.th.SentenceContextGenerator; public class Factory { public static final char[] ptEosCharacters = new char[] { '.', '?', '!', ';', ':', '(', ')', '«', '»', '\'', '"' }; public static final char[] defaultEosCharacters = new char[] { '.', '!', '?' }; public static final char[] thEosCharacters = new char[] { ' ','\n' }; public static final char[] jpnEosCharacters = new char[] {'。', '�', '?'}; public EndOfSentenceScanner createEndOfSentenceScanner(String languageCode) { return new DefaultEndOfSentenceScanner(getEOSCharacters(languageCode)); } public EndOfSentenceScanner createEndOfSentenceScanner( char[] customEOSCharacters) { return new DefaultEndOfSentenceScanner(customEOSCharacters); } public SDContextGenerator createSentenceContextGenerator(String languageCode, Set abbreviations) { if ("th".equals(languageCode) || "tha".equals(languageCode)) { return new SentenceContextGenerator(); } else if ("pt".equals(languageCode) || "por".equals(languageCode)) { return new DefaultSDContextGenerator(abbreviations, ptEosCharacters); } return new DefaultSDContextGenerator(abbreviations, defaultEosCharacters); } public SDContextGenerator createSentenceContextGenerator( Set abbreviations, char[] customEOSCharacters) { return new DefaultSDContextGenerator(abbreviations, customEOSCharacters); } public SDContextGenerator createSentenceContextGenerator(String languageCode) { return createSentenceContextGenerator(languageCode, Collections.emptySet()); } public char[] getEOSCharacters(String languageCode) { if ("th".equals(languageCode) || "tha".equals(languageCode)) { return thEosCharacters; } else if ("pt".equals(languageCode) || "por".equals(languageCode)) { return ptEosCharacters; } else if ("jpn".equals(languageCode)) { return jpnEosCharacters; } return defaultEosCharacters; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_sentdetect_lang_0100644 0000000 0000000 00000000176 15217274217 032547 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/lang/th/SentenceContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/lang/th/SentenceConte0100644 0000000 0000000 00000005334 15217274217 034072 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.sentdetect.lang.th; import opennlp.tools.sentdetect.DefaultSDContextGenerator; /** * Creates contexts/features for end-of-sentence detection in Thai text. */ public class SentenceContextGenerator extends DefaultSDContextGenerator { public static final char[] eosCharacters = {' ','\n'}; public SentenceContextGenerator() { super(eosCharacters); } @Override protected void collectFeatures(String prefix, String suffix, String previous, String next, Character eosChar) { buf.append("p="); buf.append(prefix); collectFeats.add(buf.toString()); buf.setLength(0); buf.append("s="); buf.append(suffix); collectFeats.add(buf.toString()); buf.setLength(0); collectFeats.add("p1=" + prefix.substring(StrictMath.max(prefix.length() - 1,0))); collectFeats.add("p2=" + prefix.substring(StrictMath.max(prefix.length() - 2,0))); collectFeats.add("p3=" + prefix.substring(StrictMath.max(prefix.length() - 3,0))); collectFeats.add("p4=" + prefix.substring(StrictMath.max(prefix.length() - 4,0))); collectFeats.add("p5=" + prefix.substring(StrictMath.max(prefix.length() - 5,0))); collectFeats.add("p6=" + prefix.substring(StrictMath.max(prefix.length() - 6,0))); collectFeats.add("p7=" + prefix.substring(StrictMath.max(prefix.length() - 7,0))); collectFeats.add("n1=" + suffix.substring(0,StrictMath.min(1, suffix.length()))); collectFeats.add("n2=" + suffix.substring(0,StrictMath.min(2, suffix.length()))); collectFeats.add("n3=" + suffix.substring(0,StrictMath.min(3, suffix.length()))); collectFeats.add("n4=" + suffix.substring(0,StrictMath.min(4, suffix.length()))); collectFeats.add("n5=" + suffix.substring(0,StrictMath.min(5, suffix.length()))); collectFeats.add("n6=" + suffix.substring(0,StrictMath.min(6, suffix.length()))); collectFeats.add("n7=" + suffix.substring(0,StrictMath.min(7, suffix.length()))); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/lang/th/package.html0100644 0000000 0000000 00000001666 15217274217 033677 0ustar00rootroot0000000 0000000 Package related to the processing of Thai data. apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/sentdetect/package-info.java0100644 0000000 0000000 00000001603 15217274217 033240 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package related to identifying sentence boundaries. */ package opennlp.tools.sentdetect; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/PorterStemmer.java0100644 0000000 0000000 00000034767 15217274217 033057 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Porter stemmer in Java. The original paper is in Porter, 1980, An algorithm for suffix stripping, Program, Vol. 14, no. 3, pp 130-137, See also http://www.tartarus.org/~martin/PorterStemmer/index.html Bug 1 (reported by Gonzalo Parra 16/10/99) fixed as marked below. Tthe words 'aed', 'eed', 'oed' leave k at 'a' for step 3, and b[k-1] is then out outside the bounds of b. Similarly, Bug 2 (reported by Steve Dyrdahl 22/2/00) fixed as marked below. 'ion' by itself leaves j = -1 in the test for 'ion' in step 5, and b[j] is then outside the bounds of b. Release 3. [ This version is derived from Release 3, modified by Brian Goetz to optimize for fewer object creations. ] */ package opennlp.tools.stemmer; /** * A {@link Stemmer}, implementing the * Porter Stemming Algorithm *

* The Stemmer implementation transforms a word into its root form. The input * word can be provided a character at time (by calling {@link #add(char)}), * or at once by calling one of the various {@code stem(..)} methods. */ // CHECKSTYLE:OFF public class PorterStemmer implements Stemmer { private static final int INC = 50; private char[] b; private int i, /* offset into b */ j, k, k0; private boolean dirty = false; public PorterStemmer() { b = new char[INC]; i = 0; } /** * reset() resets the stemmer so it can stem another word. If you invoke * the stemmer by calling add(char) and then stem(), you must call reset() * before starting another word. */ public void reset() { i = 0; dirty = false; } /** * Add a character to the word being stemmed. When you are finished * adding characters, you can call stem(void) to process the word. */ public void add(char ch) { if (b.length == i) { char[] new_b = new char[i + INC]; System.arraycopy(b, 0, new_b, 0, i); { b = new_b; } } b[i++] = ch; } /** * After a word has been stemmed, it can be retrieved by toString(), * or a reference to the internal buffer can be retrieved by getResultBuffer * and getResultLength (which is generally more efficient.) */ @Override public String toString() { return new String(b, 0, i); } /** * Returns the length of the word resulting from the stemming process. */ public int getResultLength() { return i; } /** * Returns a reference to a character buffer containing the results of * the stemming process. You also need to consult getResultLength() * to determine the length of the result. */ public char[] getResultBuffer() { return b; } /* cons(i) is true <=> b[i] is a consonant. */ private boolean cons(int i) { return switch (b[i]) { case 'a', 'e', 'i', 'o', 'u' -> false; case 'y' -> (i == k0) || !cons(i - 1); default -> true; }; } /* m() measures the number of consonant sequences between k0 and j. if c is a consonant sequence and v a vowel sequence, and <..> indicates arbitrary presence, gives 0 vc gives 1 vcvc gives 2 vcvcvc gives 3 .... */ private int m() { int n = 0; int i = k0; while (true) { if (i > j) { return n; } if (!cons(i)) { break; } i++; } i++; while (true) { while (true) { if (i > j) { return n; } if (cons(i)) { break; } i++; } i++; n++; while (true) { if (i > j) { return n; } if (!cons(i)) { break; } i++; } i++; } } /* vowelinstem() is true <=> k0,...j contains a vowel */ private boolean vowelinstem() { int i; for (i = k0; i <= j; i++) { if (!cons(i)) { return true; } } return false; } /* doublec(j) is true <=> j,(j-1) contain a double consonant. */ private boolean doublec(int j) { return j >= k0 + 1 && b[j] == b[j - 1] && cons(j); } /* cvc(i) is true <=> i-2,i-1,i has the form consonant - vowel - consonant and also if the second c is not w,x or y. this is used when trying to restore an e at the end of a short word. e.g. cav(e), lov(e), hop(e), crim(e), but snow, box, tray. */ private boolean cvc(int i) { if (i < k0 + 2 || !cons(i) || cons(i - 1) || !cons(i - 2)) { return false; } else { int ch = b[i]; if (ch == 'w' || ch == 'x' || ch == 'y') { return false; } } return true; } private boolean ends(String s) { int l = s.length(); int o = k - l + 1; if (o < k0) { return false; } for (int i = 0; i < l; i++) { if (b[o + i] != s.charAt(i)) { return false; } } j = k - l; return true; } /* setto(s) sets (j+1),...k to the characters in the string s, readjusting k. */ void setto(String s) { int l = s.length(); int o = j + 1; for (int i = 0; i < l; i++) { b[o + i] = s.charAt(i); } k = j + l; dirty = true; } /* r(s) is used further down. */ void r(String s) { if (m() > 0) { setto(s); } } /* step1() gets rid of plurals and -ed or -ing. e.g. caresses -> caress ponies -> poni ties -> ti caress -> caress cats -> cat feed -> feed agreed -> agree disabled -> disable matting -> mat mating -> mate meeting -> meet milling -> mill messing -> mess meetings -> meet */ private void step1() { if (b[k] == 's') { if (ends("sses")) { k -= 2; } else if (ends("ies")) { setto("i"); } else if (b[k - 1] != 's') { k--; } } if (ends("eed")) { if (m() > 0) { k--; } } else if ((ends("ed") || ends("ing")) && vowelinstem()) { k = j; if (ends("at")) { setto("ate"); } else if (ends("bl")) { setto("ble"); } else if (ends("iz")) { setto("ize"); } else if (doublec(k)) { int ch = b[k--]; if (ch == 'l' || ch == 's' || ch == 'z') { k++; } } else if (m() == 1 && cvc(k)) { setto("e"); } } } /* step2() turns terminal y to i when there is another vowel in the stem. */ private void step2() { if (ends("y") && vowelinstem()) { b[k] = 'i'; dirty = true; } } /* step3() maps double suffices to single ones. so -ization ( = -ize plus -ation) maps to -ize etc. note that the string before the suffix must give m() > 0. */ private void step3() { if (k == k0) { return; /* For Bug 1 */ } switch (b[k - 1]) { case 'a': if (ends("ational")) { r("ate"); break; } if (ends("tional")) { r("tion"); break; } break; case 'c': if (ends("enci")) { r("ence"); break; } if (ends("anci")) { r("ance"); break; } break; case 'e': if (ends("izer")) { r("ize"); break; } break; case 'l': if (ends("bli")) { r("ble"); break; } if (ends("alli")) { r("al"); break; } if (ends("entli")) { r("ent"); break; } if (ends("eli")) { r("e"); break; } if (ends("ousli")) { r("ous"); break; } break; case 'o': if (ends("ization")) { r("ize"); break; } if (ends("ation")) { r("ate"); break; } if (ends("ator")) { r("ate"); break; } break; case 's': if (ends("alism")) { r("al"); break; } if (ends("iveness")) { r("ive"); break; } if (ends("fulness")) { r("ful"); break; } if (ends("ousness")) { r("ous"); break; } break; case 't': if (ends("aliti")) { r("al"); break; } if (ends("iviti")) { r("ive"); break; } if (ends("biliti")) { r("ble"); break; } break; case 'g': if (ends("logi")) { r("log"); break; } } } /* step4() deals with -ic-, -full, -ness etc. similar strategy to step3. */ private void step4() { switch (b[k]) { case 'e': if (ends("icate")) { r("ic"); break; } if (ends("ative")) { r(""); break; } if (ends("alize")) { r("al"); break; } break; case 'i': if (ends("iciti")) { r("ic"); break; } break; case 'l': if (ends("ical")) { r("ic"); break; } if (ends("ful")) { r(""); break; } break; case 's': if (ends("ness")) { r(""); break; } break; } } /* step5() takes off -ant, -ence etc., in context vcvc. */ private void step5() { if (k == k0) { return; /* for Bug 1 */ } switch (b[k - 1]) { case 'a': if (ends("al")) { break; } return; case 'c': if (ends("ance")) { break; } if (ends("ence")) { break; } return; case 'e': if (ends("er")) { break; } return; case 'i': if (ends("ic")) { break; } return; case 'l': if (ends("able")) { break; } if (ends("ible")) { break; } return; case 'n': if (ends("ant")) { break; } if (ends("ement")) { break; } if (ends("ment")) { break; } /* element etc. not stripped before the m */ if (ends("ent")) { break; } return; case 'o': if (ends("ion") && j >= 0 && (b[j] == 's' || b[j] == 't')) { break; } /* j >= 0 fixes Bug 2 */ if (ends("ou")) { break; } return; /* takes care of -ous */ case 's': if (ends("ism")) { break; } return; case 't': if (ends("ate")) { break; } if (ends("iti")) { break; } return; case 'u': if (ends("ous")) { break; } return; case 'v': if (ends("ive")) { break; } return; case 'z': if (ends("ize")) { break; } return; default: return; } if (m() > 1) { k = j; } } /* step6() removes a final -e if m() > 1. */ private void step6() { j = k; if (b[k] == 'e') { int a = m(); if (a > 1 || a == 1 && !cvc(k - 1)) { k--; } } if (b[k] == 'l' && doublec(k) && m() > 1) { k--; } } /** * Stem a word provided as a String. Returns the result as a String. */ public String stem(String s) { if (stem(s.toCharArray(), s.length())) { return toString(); } else { return s; } } /** * Stem a word provided as a CharSequence. * Returns the result as a CharSequence. */ public CharSequence stem(CharSequence word) { return stem(word.toString()); } /** * Stem a word contained in a char[]. Returns true if the stemming process * resulted in a word different from the input. You can retrieve the * result with getResultLength()/getResultBuffer() or toString(). */ public boolean stem(char[] word) { return stem(word, word.length); } /** * Stem a word contained in a portion of a char[] array. Returns * true if the stemming process resulted in a word different from * the input. You can retrieve the result with * getResultLength()/getResultBuffer() or toString(). */ public boolean stem(char[] wordBuffer, int offset, int wordLen) { reset(); if (b.length < wordLen) { b = new char[wordLen - offset]; } System.arraycopy(wordBuffer, offset, b, 0, wordLen); i = wordLen; return stem(0); } /** * Stem a word contained in a leading portion of a char[] array. * Returns true if the stemming process resulted in a word different * from the input. You can retrieve the result with * getResultLength()/getResultBuffer() or toString(). */ public boolean stem(char[] word, int wordLen) { return stem(word, 0, wordLen); } /** * Stem the word placed into the Stemmer buffer through calls to add(). * Returns true if the stemming process resulted in a word different * from the input. You can retrieve the result with * getResultLength()/getResultBuffer() or toString(). */ public boolean stem() { return stem(0); } public boolean stem(int i0) { k = i - 1; k0 = i0; if (k > k0 + 1) { step1(); step2(); step3(); step4(); step5(); step6(); } // Also, a word is considered dirty if we lopped off letters // Thanks to Ifigenia Vairelles for pointing this out. if (i != k + 1) { dirty = true; } i = k + 1; return dirty; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/Stemmer.java0100644 0000000 0000000 00000001677 15217274217 031655 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.stemmer; /** * The stemmer is reducing a word to its stem. */ public interface Stemmer { CharSequence stem(CharSequence word); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000173 15217274217 032617 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/AbstractSnowballStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/AbstractSnowbal0100644 0000000 0000000 00000003520 15217274217 034220 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package opennlp.tools.stemmer.snowball; /** * Parent class of all snowball stemmers, which must implement stem */ abstract class AbstractSnowballStemmer extends SnowballProgram { public abstract boolean stem(); static final long serialVersionUID = 2016072500L; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/Among.java0100644 0000000 0000000 00000006344 15217274217 033117 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.Locale; /** * Internal class used by Snowball stemmers */ public class Among { public Among(String s, int substring_i, int result) { this.s = s.toCharArray(); this.substring_i = substring_i; this.result = result; this.method = null; } public Among(String s, int substring_i, int result, String methodname, MethodHandles.Lookup methodobject) { this.s = s.toCharArray(); this.substring_i = substring_i; this.result = result; final Class clazz = methodobject.lookupClass().asSubclass(SnowballProgram.class); if (methodname.length() > 0) { try { this.method = methodobject.findVirtual(clazz, methodname, MethodType.methodType(boolean.class)) .asType(MethodType.methodType(boolean.class, SnowballProgram.class)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new RuntimeException(String.format(Locale.ENGLISH, "Snowball program '%s' is broken, cannot access method: boolean %s()", clazz.getSimpleName(), methodname ), e); } } else { this.method = null; } } final char[] s; /* search string */ final int substring_i; /* index to longest matching substring */ final int result; /* result of the lookup */ // Make sure this is not accessible outside package for Java security reasons! final MethodHandle method; /* method to use if substring matches */ };./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000163 15217274217 032616 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/SnowballProgram.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/SnowballProgram0100644 0000000 0000000 00000027765 15217274217 034261 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package opennlp.tools.stemmer.snowball; import java.io.Serializable; import java.lang.reflect.UndeclaredThrowableException; import java.util.Arrays; /** * Base class for a snowball stemmer */ public class SnowballProgram implements Serializable { protected SnowballProgram() { setCurrent(""); } static final long serialVersionUID = 2016072500L; /** * Set the current string. */ public void setCurrent(String value) { setCurrent(value.toCharArray(), value.length()); } /** * Get the current string. */ public String getCurrent() { return new String(current, 0, length); } /** * Set the current string. * * @param text character array containing input * @param length valid length of text. */ public void setCurrent(char[] text, int length) { current = text; cursor = 0; this.length = limit = length; limit_backward = 0; bra = cursor; ket = limit; } /** * Get the current buffer containing the stem. *

* NOTE: this may be a reference to a different character array than the * one originally provided with setCurrent, in the exceptional case that * stemming produced a longer intermediate or result string. *

*

* It is necessary to use {@link #getCurrentBufferLength()} to determine * the valid length of the returned buffer. For example, many words are * stemmed simply by subtracting from the length to remove suffixes. *

* * @see #getCurrentBufferLength() */ public char[] getCurrentBuffer() { return current; } /** * Get the valid length of the character array in * {@link #getCurrentBuffer()}. * * @return valid length of the array. */ public int getCurrentBufferLength() { return length; } // current string private char[] current; protected int cursor; protected int length; protected int limit; protected int limit_backward; protected int bra; protected int ket; public SnowballProgram(SnowballProgram other) { current = other.current; cursor = other.cursor; length = other.length; limit = other.limit; limit_backward = other.limit_backward; bra = other.bra; ket = other.ket; } protected void copy_from(SnowballProgram other) { current = other.current; cursor = other.cursor; length = other.length; limit = other.limit; limit_backward = other.limit_backward; bra = other.bra; ket = other.ket; } protected boolean in_grouping(char[] s, int min, int max) { if (cursor >= limit) { return false; } char ch = current[cursor]; if (ch > max || ch < min) { return false; } ch -= min; if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) { return false; } cursor++; return true; } protected boolean in_grouping_b(char[] s, int min, int max) { if (cursor <= limit_backward) { return false; } char ch = current[cursor - 1]; if (ch > max || ch < min) { return false; } ch -= min; if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) { return false; } cursor--; return true; } protected boolean out_grouping(char[] s, int min, int max) { if (cursor >= limit) { return false; } char ch = current[cursor]; if (ch > max || ch < min) { cursor++; return true; } ch -= min; if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) { cursor++; return true; } return false; } protected boolean out_grouping_b(char[] s, int min, int max) { if (cursor <= limit_backward) { return false; } char ch = current[cursor - 1]; if (ch > max || ch < min) { cursor--; return true; } ch -= min; if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) { cursor--; return true; } return false; } protected boolean eq_s(CharSequence s) { if (limit - cursor < s.length()) { return false; } int i; for (i = 0; i != s.length(); i++) { if (current[cursor + i] != s.charAt(i)) { return false; } } cursor += s.length(); return true; } protected boolean eq_s_b(CharSequence s) { if (cursor - limit_backward < s.length()) { return false; } int i; for (i = 0; i != s.length(); i++) { if (current[cursor - s.length() + i] != s.charAt(i)) { return false; } } cursor -= s.length(); return true; } protected int find_among(Among[] v) { int i = 0; int j = v.length; int c = cursor; int l = limit; int common_i = 0; int common_j = 0; boolean first_key_inspected = false; while (true) { int k = i + ((j - i) >> 1); int diff = 0; int common = common_i < common_j ? common_i : common_j; // smaller Among w = v[k]; int i2; for (i2 = common; i2 < w.s.length; i2++) { if (c + common == l) { diff = -1; break; } diff = current[c + common] - w.s[i2]; if (diff != 0) { break; } common++; } if (diff < 0) { j = k; common_j = common; } else { i = k; common_i = common; } if (j - i <= 1) { if (i > 0) { break; // v->s has been inspected } if (j == i) { break; // only one item in v } // - but now we need to go round once more to get // v->s inspected. This looks messy, but is actually // the optimal approach. if (first_key_inspected) { break; } first_key_inspected = true; } } while (true) { Among w = v[i]; if (common_i >= w.s.length) { cursor = c + w.s.length; if (w.method == null) { return w.result; } boolean res = false; try { res = (boolean) w.method.invokeExact(this); } catch (Error | RuntimeException e) { throw e; } catch (Throwable e) { throw new UndeclaredThrowableException(e); } cursor = c + w.s.length; if (res) { return w.result; } } i = w.substring_i; if (i < 0) { return 0; } } } // find_among_b is for backwards processing. Same comments apply protected int find_among_b(Among[] v) { int i = 0; int j = v.length; int c = cursor; int lb = limit_backward; int common_i = 0; int common_j = 0; boolean first_key_inspected = false; while (true) { int k = i + ((j - i) >> 1); int diff = 0; int common = common_i < common_j ? common_i : common_j; Among w = v[k]; int i2; for (i2 = w.s.length - 1 - common; i2 >= 0; i2--) { if (c - common == lb) { diff = -1; break; } diff = current[c - 1 - common] - w.s[i2]; if (diff != 0) { break; } common++; } if (diff < 0) { j = k; common_j = common; } else { i = k; common_i = common; } if (j - i <= 1) { if (i > 0) { break; } if (j == i) { break; } if (first_key_inspected) { break; } first_key_inspected = true; } } while (true) { Among w = v[i]; if (common_i >= w.s.length) { cursor = c - w.s.length; if (w.method == null) { return w.result; } boolean res = false; try { res = (boolean) w.method.invokeExact(this); } catch (Error | RuntimeException e) { throw e; } catch (Throwable e) { throw new UndeclaredThrowableException(e); } cursor = c - w.s.length; if (res) { return w.result; } } i = w.substring_i; if (i < 0) { return 0; } } } /* to replace chars between c_bra and c_ket in current by the * chars in s. */ protected int replace_s(int c_bra, int c_ket, CharSequence s) { final int adjustment = s.length() - (c_ket - c_bra); final int newLength = length + adjustment; //resize if necessary if (newLength > current.length) { current = Arrays.copyOf(current, newLength); } // if the substring being replaced is longer or shorter than the // replacement, need to shift things around if (adjustment != 0 && c_ket < length) { System.arraycopy(current, c_ket, current, c_bra + s.length(), length - c_ket); } // insert the replacement text // Note, faster is s.getChars(0, s.length(), current, c_bra); // but would have to duplicate this method for both String and StringBuilder for (int i = 0; i < s.length(); i++) { current[c_bra + i] = s.charAt(i); } length += adjustment; limit += adjustment; if (cursor >= c_ket) { cursor += adjustment; } else if (cursor > c_bra) { cursor = c_bra; } return adjustment; } protected void slice_check() { assert bra >= 0 : "bra=" + bra; assert bra <= ket : "bra=" + bra + ",ket=" + ket; assert limit <= length : "limit=" + limit + ",length=" + length; assert ket <= limit : "ket=" + ket + ",limit=" + limit; } protected void slice_from(CharSequence s) { slice_check(); replace_s(bra, ket, s); } protected void slice_del() { slice_from(""); } protected void insert(int c_bra, int c_ket, CharSequence s) { int adjustment = replace_s(c_bra, c_ket, s); if (c_bra <= bra) { bra += adjustment; } if (c_bra <= ket) { ket += adjustment; } } /* Copy the slice into the supplied StringBuilder */ protected void slice_to(StringBuilder s) { slice_check(); int len = ket - bra; s.setLength(0); s.append(current, bra, len); } protected void assign_to(StringBuilder s) { s.setLength(0); s.append(current, 0, limit); } /* extern void debug(struct SN_env * z, int number, int line_count) { int i; int limit = SIZE(z->p); //if (number >= 0) printf("%3d (line %4d): '", number, line_count); if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit); for (i = 0; i <= limit; i++) { if (z->lb == i) printf("{"); if (z->bra == i) printf("["); if (z->c == i) printf("|"); if (z->ket == i) printf("]"); if (z->l == i) printf("}"); if (i < limit) { int ch = z->p[i]; if (ch == 0) ch = '#'; printf("%c", ch); } } printf("'\n"); } */ };./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000163 15217274217 032616 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/SnowballStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/SnowballStemmer0100644 0000000 0000000 00000007176 15217274217 034260 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.stemmer.snowball; import opennlp.tools.stemmer.Stemmer; public class SnowballStemmer implements Stemmer { private final AbstractSnowballStemmer stemmer; private final int repeat; public SnowballStemmer(ALGORITHM algorithm, int repeat) { this.repeat = repeat; if (ALGORITHM.ARABIC.equals(algorithm)) { stemmer = new arabicStemmer(); } else if (ALGORITHM.DANISH.equals(algorithm)) { stemmer = new danishStemmer(); } else if (ALGORITHM.DUTCH.equals(algorithm)) { stemmer = new dutchStemmer(); } else if (ALGORITHM.CATALAN.equals(algorithm)) { stemmer = new catalanStemmer(); } else if (ALGORITHM.ENGLISH.equals(algorithm)) { stemmer = new englishStemmer(); } else if (ALGORITHM.FINNISH.equals(algorithm)) { stemmer = new finnishStemmer(); } else if (ALGORITHM.FRENCH.equals(algorithm)) { stemmer = new frenchStemmer(); } else if (ALGORITHM.GERMAN.equals(algorithm)) { stemmer = new germanStemmer(); } else if (ALGORITHM.GREEK.equals(algorithm)) { stemmer = new greekStemmer(); } else if (ALGORITHM.HUNGARIAN.equals(algorithm)) { stemmer = new hungarianStemmer(); } else if (ALGORITHM.INDONESIAN.equals(algorithm)) { stemmer = new indonesianStemmer(); } else if (ALGORITHM.IRISH.equals(algorithm)) { stemmer = new irishStemmer(); } else if (ALGORITHM.ITALIAN.equals(algorithm)) { stemmer = new italianStemmer(); } else if (ALGORITHM.NORWEGIAN.equals(algorithm)) { stemmer = new norwegianStemmer(); } else if (ALGORITHM.PORTER.equals(algorithm)) { stemmer = new porterStemmer(); } else if (ALGORITHM.PORTUGUESE.equals(algorithm)) { stemmer = new portugueseStemmer(); } else if (ALGORITHM.ROMANIAN.equals(algorithm)) { stemmer = new romanianStemmer(); } else if (ALGORITHM.RUSSIAN.equals(algorithm)) { stemmer = new russianStemmer(); } else if (ALGORITHM.SPANISH.equals(algorithm)) { stemmer = new spanishStemmer(); } else if (ALGORITHM.SWEDISH.equals(algorithm)) { stemmer = new swedishStemmer(); } else if (ALGORITHM.TURKISH.equals(algorithm)) { stemmer = new turkishStemmer(); } else { throw new IllegalStateException("Unexpected stemmer algorithm: " + algorithm); } } public SnowballStemmer(ALGORITHM algorithm) { this(algorithm, 1); } public CharSequence stem(CharSequence word) { stemmer.setCurrent(word.toString()); for (int i = 0; i < repeat; i++) { stemmer.stem(); } return stemmer.getCurrent(); } public enum ALGORITHM { ARABIC, DANISH, DUTCH, CATALAN, ENGLISH, FINNISH, FRENCH, GERMAN, GREEK, HUNGARIAN, INDONESIAN, IRISH, ITALIAN, NORWEGIAN, PORTER, PORTUGUESE, ROMANIAN, RUSSIAN, SPANISH, SWEDISH, TURKISH } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000161 15217274217 032614 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/arabicStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/arabicStemmer.j0100644 0000000 0000000 00000100163 15217274217 034136 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class arabicStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("\u0640", -1, 1), new Among("\u064B", -1, 1), new Among("\u064C", -1, 1), new Among("\u064D", -1, 1), new Among("\u064E", -1, 1), new Among("\u064F", -1, 1), new Among("\u0650", -1, 1), new Among("\u0651", -1, 1), new Among("\u0652", -1, 1), new Among("\u0660", -1, 2), new Among("\u0661", -1, 3), new Among("\u0662", -1, 4), new Among("\u0663", -1, 5), new Among("\u0664", -1, 6), new Among("\u0665", -1, 7), new Among("\u0666", -1, 8), new Among("\u0667", -1, 9), new Among("\u0668", -1, 10), new Among("\u0669", -1, 11), new Among("\uFE80", -1, 12), new Among("\uFE81", -1, 16), new Among("\uFE82", -1, 16), new Among("\uFE83", -1, 13), new Among("\uFE84", -1, 13), new Among("\uFE85", -1, 17), new Among("\uFE86", -1, 17), new Among("\uFE87", -1, 14), new Among("\uFE88", -1, 14), new Among("\uFE89", -1, 15), new Among("\uFE8A", -1, 15), new Among("\uFE8B", -1, 15), new Among("\uFE8C", -1, 15), new Among("\uFE8D", -1, 18), new Among("\uFE8E", -1, 18), new Among("\uFE8F", -1, 19), new Among("\uFE90", -1, 19), new Among("\uFE91", -1, 19), new Among("\uFE92", -1, 19), new Among("\uFE93", -1, 20), new Among("\uFE94", -1, 20), new Among("\uFE95", -1, 21), new Among("\uFE96", -1, 21), new Among("\uFE97", -1, 21), new Among("\uFE98", -1, 21), new Among("\uFE99", -1, 22), new Among("\uFE9A", -1, 22), new Among("\uFE9B", -1, 22), new Among("\uFE9C", -1, 22), new Among("\uFE9D", -1, 23), new Among("\uFE9E", -1, 23), new Among("\uFE9F", -1, 23), new Among("\uFEA0", -1, 23), new Among("\uFEA1", -1, 24), new Among("\uFEA2", -1, 24), new Among("\uFEA3", -1, 24), new Among("\uFEA4", -1, 24), new Among("\uFEA5", -1, 25), new Among("\uFEA6", -1, 25), new Among("\uFEA7", -1, 25), new Among("\uFEA8", -1, 25), new Among("\uFEA9", -1, 26), new Among("\uFEAA", -1, 26), new Among("\uFEAB", -1, 27), new Among("\uFEAC", -1, 27), new Among("\uFEAD", -1, 28), new Among("\uFEAE", -1, 28), new Among("\uFEAF", -1, 29), new Among("\uFEB0", -1, 29), new Among("\uFEB1", -1, 30), new Among("\uFEB2", -1, 30), new Among("\uFEB3", -1, 30), new Among("\uFEB4", -1, 30), new Among("\uFEB5", -1, 31), new Among("\uFEB6", -1, 31), new Among("\uFEB7", -1, 31), new Among("\uFEB8", -1, 31), new Among("\uFEB9", -1, 32), new Among("\uFEBA", -1, 32), new Among("\uFEBB", -1, 32), new Among("\uFEBC", -1, 32), new Among("\uFEBD", -1, 33), new Among("\uFEBE", -1, 33), new Among("\uFEBF", -1, 33), new Among("\uFEC0", -1, 33), new Among("\uFEC1", -1, 34), new Among("\uFEC2", -1, 34), new Among("\uFEC3", -1, 34), new Among("\uFEC4", -1, 34), new Among("\uFEC5", -1, 35), new Among("\uFEC6", -1, 35), new Among("\uFEC7", -1, 35), new Among("\uFEC8", -1, 35), new Among("\uFEC9", -1, 36), new Among("\uFECA", -1, 36), new Among("\uFECB", -1, 36), new Among("\uFECC", -1, 36), new Among("\uFECD", -1, 37), new Among("\uFECE", -1, 37), new Among("\uFECF", -1, 37), new Among("\uFED0", -1, 37), new Among("\uFED1", -1, 38), new Among("\uFED2", -1, 38), new Among("\uFED3", -1, 38), new Among("\uFED4", -1, 38), new Among("\uFED5", -1, 39), new Among("\uFED6", -1, 39), new Among("\uFED7", -1, 39), new Among("\uFED8", -1, 39), new Among("\uFED9", -1, 40), new Among("\uFEDA", -1, 40), new Among("\uFEDB", -1, 40), new Among("\uFEDC", -1, 40), new Among("\uFEDD", -1, 41), new Among("\uFEDE", -1, 41), new Among("\uFEDF", -1, 41), new Among("\uFEE0", -1, 41), new Among("\uFEE1", -1, 42), new Among("\uFEE2", -1, 42), new Among("\uFEE3", -1, 42), new Among("\uFEE4", -1, 42), new Among("\uFEE5", -1, 43), new Among("\uFEE6", -1, 43), new Among("\uFEE7", -1, 43), new Among("\uFEE8", -1, 43), new Among("\uFEE9", -1, 44), new Among("\uFEEA", -1, 44), new Among("\uFEEB", -1, 44), new Among("\uFEEC", -1, 44), new Among("\uFEED", -1, 45), new Among("\uFEEE", -1, 45), new Among("\uFEEF", -1, 46), new Among("\uFEF0", -1, 46), new Among("\uFEF1", -1, 47), new Among("\uFEF2", -1, 47), new Among("\uFEF3", -1, 47), new Among("\uFEF4", -1, 47), new Among("\uFEF5", -1, 51), new Among("\uFEF6", -1, 51), new Among("\uFEF7", -1, 49), new Among("\uFEF8", -1, 49), new Among("\uFEF9", -1, 50), new Among("\uFEFA", -1, 50), new Among("\uFEFB", -1, 48), new Among("\uFEFC", -1, 48) }; private final static Among[] a_1 = { new Among("\u0622", -1, 1), new Among("\u0623", -1, 1), new Among("\u0624", -1, 1), new Among("\u0625", -1, 1), new Among("\u0626", -1, 1) }; private final static Among[] a_2 = { new Among("\u0622", -1, 1), new Among("\u0623", -1, 1), new Among("\u0624", -1, 2), new Among("\u0625", -1, 1), new Among("\u0626", -1, 3) }; private final static Among[] a_3 = { new Among("\u0627\u0644", -1, 2), new Among("\u0628\u0627\u0644", -1, 1), new Among("\u0643\u0627\u0644", -1, 1), new Among("\u0644\u0644", -1, 2) }; private final static Among[] a_4 = { new Among("\u0623\u0622", -1, 2), new Among("\u0623\u0623", -1, 1), new Among("\u0623\u0624", -1, 1), new Among("\u0623\u0625", -1, 4), new Among("\u0623\u0627", -1, 3) }; private final static Among[] a_5 = { new Among("\u0641", -1, 1), new Among("\u0648", -1, 1) }; private final static Among[] a_6 = { new Among("\u0627\u0644", -1, 2), new Among("\u0628\u0627\u0644", -1, 1), new Among("\u0643\u0627\u0644", -1, 1), new Among("\u0644\u0644", -1, 2) }; private final static Among[] a_7 = { new Among("\u0628", -1, 1), new Among("\u0628\u0627", 0, -1), new Among("\u0628\u0628", 0, 2), new Among("\u0643\u0643", -1, 3) }; private final static Among[] a_8 = { new Among("\u0633\u0623", -1, 4), new Among("\u0633\u062A", -1, 2), new Among("\u0633\u0646", -1, 3), new Among("\u0633\u064A", -1, 1) }; private final static Among[] a_9 = { new Among("\u062A\u0633\u062A", -1, 1), new Among("\u0646\u0633\u062A", -1, 1), new Among("\u064A\u0633\u062A", -1, 1) }; private final static Among[] a_10 = { new Among("\u0643\u0645\u0627", -1, 3), new Among("\u0647\u0645\u0627", -1, 3), new Among("\u0646\u0627", -1, 2), new Among("\u0647\u0627", -1, 2), new Among("\u0643", -1, 1), new Among("\u0643\u0645", -1, 2), new Among("\u0647\u0645", -1, 2), new Among("\u0647\u0646", -1, 2), new Among("\u0647", -1, 1), new Among("\u064A", -1, 1) }; private final static Among[] a_11 = { new Among("\u0646", -1, 1) }; private final static Among[] a_12 = { new Among("\u0627", -1, 1), new Among("\u0648", -1, 1), new Among("\u064A", -1, 1) }; private final static Among[] a_13 = { new Among("\u0627\u062A", -1, 1) }; private final static Among[] a_14 = { new Among("\u062A", -1, 1) }; private final static Among[] a_15 = { new Among("\u0629", -1, 1) }; private final static Among[] a_16 = { new Among("\u064A", -1, 1) }; private final static Among[] a_17 = { new Among("\u0643\u0645\u0627", -1, 3), new Among("\u0647\u0645\u0627", -1, 3), new Among("\u0646\u0627", -1, 2), new Among("\u0647\u0627", -1, 2), new Among("\u0643", -1, 1), new Among("\u0643\u0645", -1, 2), new Among("\u0647\u0645", -1, 2), new Among("\u0643\u0646", -1, 2), new Among("\u0647\u0646", -1, 2), new Among("\u0647", -1, 1), new Among("\u0643\u0645\u0648", -1, 3), new Among("\u0646\u064A", -1, 2) }; private final static Among[] a_18 = { new Among("\u0627", -1, 1), new Among("\u062A\u0627", 0, 2), new Among("\u062A\u0645\u0627", 0, 4), new Among("\u0646\u0627", 0, 2), new Among("\u062A", -1, 1), new Among("\u0646", -1, 1), new Among("\u0627\u0646", 5, 3), new Among("\u062A\u0646", 5, 2), new Among("\u0648\u0646", 5, 3), new Among("\u064A\u0646", 5, 3), new Among("\u064A", -1, 1) }; private final static Among[] a_19 = { new Among("\u0648\u0627", -1, 1), new Among("\u062A\u0645", -1, 1) }; private final static Among[] a_20 = { new Among("\u0648", -1, 1), new Among("\u062A\u0645\u0648", 0, 2) }; private final static Among[] a_21 = { new Among("\u0649", -1, 1) }; private boolean B_is_defined; private boolean B_is_verb; private boolean B_is_noun; private boolean r_Normalize_pre() { int among_var; int v_1 = cursor; lab0: { while (true) { int v_2 = cursor; lab1: { lab2: { int v_3 = cursor; lab3: { bra = cursor; among_var = find_among(a_0); if (among_var == 0) { break lab3; } ket = cursor; switch (among_var) { case 1: slice_del(); break; case 2: slice_from("0"); break; case 3: slice_from("1"); break; case 4: slice_from("2"); break; case 5: slice_from("3"); break; case 6: slice_from("4"); break; case 7: slice_from("5"); break; case 8: slice_from("6"); break; case 9: slice_from("7"); break; case 10: slice_from("8"); break; case 11: slice_from("9"); break; case 12: slice_from("\u0621"); break; case 13: slice_from("\u0623"); break; case 14: slice_from("\u0625"); break; case 15: slice_from("\u0626"); break; case 16: slice_from("\u0622"); break; case 17: slice_from("\u0624"); break; case 18: slice_from("\u0627"); break; case 19: slice_from("\u0628"); break; case 20: slice_from("\u0629"); break; case 21: slice_from("\u062A"); break; case 22: slice_from("\u062B"); break; case 23: slice_from("\u062C"); break; case 24: slice_from("\u062D"); break; case 25: slice_from("\u062E"); break; case 26: slice_from("\u062F"); break; case 27: slice_from("\u0630"); break; case 28: slice_from("\u0631"); break; case 29: slice_from("\u0632"); break; case 30: slice_from("\u0633"); break; case 31: slice_from("\u0634"); break; case 32: slice_from("\u0635"); break; case 33: slice_from("\u0636"); break; case 34: slice_from("\u0637"); break; case 35: slice_from("\u0638"); break; case 36: slice_from("\u0639"); break; case 37: slice_from("\u063A"); break; case 38: slice_from("\u0641"); break; case 39: slice_from("\u0642"); break; case 40: slice_from("\u0643"); break; case 41: slice_from("\u0644"); break; case 42: slice_from("\u0645"); break; case 43: slice_from("\u0646"); break; case 44: slice_from("\u0647"); break; case 45: slice_from("\u0648"); break; case 46: slice_from("\u0649"); break; case 47: slice_from("\u064A"); break; case 48: slice_from("\u0644\u0627"); break; case 49: slice_from("\u0644\u0623"); break; case 50: slice_from("\u0644\u0625"); break; case 51: slice_from("\u0644\u0622"); break; } break lab2; } cursor = v_3; if (cursor >= limit) { break lab1; } cursor++; } continue; } cursor = v_2; break; } } cursor = v_1; return true; } private boolean r_Normalize_post() { int among_var; int v_1 = cursor; lab0: { limit_backward = cursor; cursor = limit; ket = cursor; if (find_among_b(a_1) == 0) { break lab0; } bra = cursor; slice_from("\u0621"); cursor = limit_backward; } cursor = v_1; int v_2 = cursor; lab1: { while (true) { int v_3 = cursor; lab2: { lab3: { int v_4 = cursor; lab4: { bra = cursor; among_var = find_among(a_2); if (among_var == 0) { break lab4; } ket = cursor; switch (among_var) { case 1: slice_from("\u0627"); break; case 2: slice_from("\u0648"); break; case 3: slice_from("\u064A"); break; } break lab3; } cursor = v_4; if (cursor >= limit) { break lab2; } cursor++; } continue; } cursor = v_3; break; } } cursor = v_2; return true; } private boolean r_Checks1() { int among_var; bra = cursor; among_var = find_among(a_3); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: if (length <= 4) { return false; } B_is_noun = true; B_is_verb = false; B_is_defined = true; break; case 2: if (length <= 3) { return false; } B_is_noun = true; B_is_verb = false; B_is_defined = true; break; } return true; } private boolean r_Prefix_Step1() { int among_var; bra = cursor; among_var = find_among(a_4); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: if (length <= 3) { return false; } slice_from("\u0623"); break; case 2: if (length <= 3) { return false; } slice_from("\u0622"); break; case 3: if (length <= 3) { return false; } slice_from("\u0627"); break; case 4: if (length <= 3) { return false; } slice_from("\u0625"); break; } return true; } private boolean r_Prefix_Step2() { bra = cursor; if (find_among(a_5) == 0) { return false; } ket = cursor; if (length <= 3) { return false; } { int v_1 = cursor; lab0: { if (!(eq_s("\u0627"))) { break lab0; } return false; } cursor = v_1; } slice_del(); return true; } private boolean r_Prefix_Step3a_Noun() { int among_var; bra = cursor; among_var = find_among(a_6); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: if (length <= 5) { return false; } slice_del(); break; case 2: if (length <= 4) { return false; } slice_del(); break; } return true; } private boolean r_Prefix_Step3b_Noun() { int among_var; bra = cursor; among_var = find_among(a_7); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: if (length <= 3) { return false; } slice_del(); break; case 2: if (length <= 3) { return false; } slice_from("\u0628"); break; case 3: if (length <= 3) { return false; } slice_from("\u0643"); break; } return true; } private boolean r_Prefix_Step3_Verb() { int among_var; bra = cursor; among_var = find_among(a_8); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: if (length <= 4) { return false; } slice_from("\u064A"); break; case 2: if (length <= 4) { return false; } slice_from("\u062A"); break; case 3: if (length <= 4) { return false; } slice_from("\u0646"); break; case 4: if (length <= 4) { return false; } slice_from("\u0623"); break; } return true; } private boolean r_Prefix_Step4_Verb() { bra = cursor; if (find_among(a_9) == 0) { return false; } ket = cursor; if (length <= 4) { return false; } B_is_verb = true; B_is_noun = false; slice_from("\u0627\u0633\u062A"); return true; } private boolean r_Suffix_Noun_Step1a() { int among_var; ket = cursor; among_var = find_among_b(a_10); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (length < 4) { return false; } slice_del(); break; case 2: if (length < 5) { return false; } slice_del(); break; case 3: if (length < 6) { return false; } slice_del(); break; } return true; } private boolean r_Suffix_Noun_Step1b() { ket = cursor; if (find_among_b(a_11) == 0) { return false; } bra = cursor; if (length <= 5) { return false; } slice_del(); return true; } private boolean r_Suffix_Noun_Step2a() { ket = cursor; if (find_among_b(a_12) == 0) { return false; } bra = cursor; if (length <= 4) { return false; } slice_del(); return true; } private boolean r_Suffix_Noun_Step2b() { ket = cursor; if (find_among_b(a_13) == 0) { return false; } bra = cursor; if (length < 5) { return false; } slice_del(); return true; } private boolean r_Suffix_Noun_Step2c1() { ket = cursor; if (find_among_b(a_14) == 0) { return false; } bra = cursor; if (length < 4) { return false; } slice_del(); return true; } private boolean r_Suffix_Noun_Step2c2() { ket = cursor; if (find_among_b(a_15) == 0) { return false; } bra = cursor; if (length < 4) { return false; } slice_del(); return true; } private boolean r_Suffix_Noun_Step3() { ket = cursor; if (find_among_b(a_16) == 0) { return false; } bra = cursor; if (length < 3) { return false; } slice_del(); return true; } private boolean r_Suffix_Verb_Step1() { int among_var; ket = cursor; among_var = find_among_b(a_17); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (length < 4) { return false; } slice_del(); break; case 2: if (length < 5) { return false; } slice_del(); break; case 3: if (length < 6) { return false; } slice_del(); break; } return true; } private boolean r_Suffix_Verb_Step2a() { int among_var; ket = cursor; among_var = find_among_b(a_18); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (length < 4) { return false; } slice_del(); break; case 2: if (length < 5) { return false; } slice_del(); break; case 3: if (length <= 5) { return false; } slice_del(); break; case 4: if (length < 6) { return false; } slice_del(); break; } return true; } private boolean r_Suffix_Verb_Step2b() { ket = cursor; if (find_among_b(a_19) == 0) { return false; } bra = cursor; if (length < 5) { return false; } slice_del(); return true; } private boolean r_Suffix_Verb_Step2c() { int among_var; ket = cursor; among_var = find_among_b(a_20); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (length < 4) { return false; } slice_del(); break; case 2: if (length < 6) { return false; } slice_del(); break; } return true; } private boolean r_Suffix_All_alef_maqsura() { ket = cursor; if (find_among_b(a_21) == 0) { return false; } bra = cursor; slice_from("\u064A"); return true; } @Override public boolean stem() { B_is_noun = true; B_is_verb = true; B_is_defined = false; int v_1 = cursor; r_Checks1(); cursor = v_1; r_Normalize_pre(); limit_backward = cursor; cursor = limit; int v_3 = limit - cursor; lab0: { lab1: { int v_4 = limit - cursor; lab2: { if (!(B_is_verb)) { break lab2; } lab3: { int v_5 = limit - cursor; lab4: { { int v_6 = 1; while (true) { int v_7 = limit - cursor; lab5: { if (!r_Suffix_Verb_Step1()) { break lab5; } v_6--; continue; } cursor = limit - v_7; break; } if (v_6 > 0) { break lab4; } } lab6: { int v_8 = limit - cursor; lab7: { if (!r_Suffix_Verb_Step2a()) { break lab7; } break lab6; } cursor = limit - v_8; lab8: { if (!r_Suffix_Verb_Step2c()) { break lab8; } break lab6; } cursor = limit - v_8; if (cursor <= limit_backward) { break lab4; } cursor--; } break lab3; } cursor = limit - v_5; lab9: { if (!r_Suffix_Verb_Step2b()) { break lab9; } break lab3; } cursor = limit - v_5; if (!r_Suffix_Verb_Step2a()) { break lab2; } } break lab1; } cursor = limit - v_4; lab10: { if (!(B_is_noun)) { break lab10; } int v_9 = limit - cursor; lab11: { lab12: { int v_10 = limit - cursor; lab13: { if (!r_Suffix_Noun_Step2c2()) { break lab13; } break lab12; } cursor = limit - v_10; lab14: { lab15: { if (!(B_is_defined)) { break lab15; } break lab14; } if (!r_Suffix_Noun_Step1a()) { break lab14; } lab16: { int v_12 = limit - cursor; lab17: { if (!r_Suffix_Noun_Step2a()) { break lab17; } break lab16; } cursor = limit - v_12; lab18: { if (!r_Suffix_Noun_Step2b()) { break lab18; } break lab16; } cursor = limit - v_12; lab19: { if (!r_Suffix_Noun_Step2c1()) { break lab19; } break lab16; } cursor = limit - v_12; if (cursor <= limit_backward) { break lab14; } cursor--; } break lab12; } cursor = limit - v_10; lab20: { if (!r_Suffix_Noun_Step1b()) { break lab20; } lab21: { int v_13 = limit - cursor; lab22: { if (!r_Suffix_Noun_Step2a()) { break lab22; } break lab21; } cursor = limit - v_13; lab23: { if (!r_Suffix_Noun_Step2b()) { break lab23; } break lab21; } cursor = limit - v_13; if (!r_Suffix_Noun_Step2c1()) { break lab20; } } break lab12; } cursor = limit - v_10; lab24: { lab25: { if (!(B_is_defined)) { break lab25; } break lab24; } if (!r_Suffix_Noun_Step2a()) { break lab24; } break lab12; } cursor = limit - v_10; if (!r_Suffix_Noun_Step2b()) { cursor = limit - v_9; break lab11; } } } if (!r_Suffix_Noun_Step3()) { break lab10; } break lab1; } cursor = limit - v_4; if (!r_Suffix_All_alef_maqsura()) { break lab0; } } } cursor = limit - v_3; cursor = limit_backward; int v_15 = cursor; lab26: { int v_16 = cursor; lab27: { if (!r_Prefix_Step1()) { cursor = v_16; break lab27; } } int v_17 = cursor; lab28: { if (!r_Prefix_Step2()) { cursor = v_17; break lab28; } } lab29: { int v_18 = cursor; lab30: { if (!r_Prefix_Step3a_Noun()) { break lab30; } break lab29; } cursor = v_18; lab31: { if (!(B_is_noun)) { break lab31; } if (!r_Prefix_Step3b_Noun()) { break lab31; } break lab29; } cursor = v_18; if (!(B_is_verb)) { break lab26; } int v_19 = cursor; lab32: { if (!r_Prefix_Step3_Verb()) { cursor = v_19; break lab32; } } if (!r_Prefix_Step4_Verb()) { break lab26; } } } cursor = v_15; r_Normalize_post(); return true; } @Override public boolean equals(Object o) { return o instanceof arabicStemmer; } @Override public int hashCode() { return arabicStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/catalanStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/catalanStemmer.0100644 0000000 0000000 00000063346 15217274217 034161 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2010, Israel Olalla Copyright (c) 2010, ISOCO All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class catalanStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("", -1, 7), new Among("\u00B7", 0, 6), new Among("\u00E0", 0, 1), new Among("\u00E1", 0, 1), new Among("\u00E8", 0, 2), new Among("\u00E9", 0, 2), new Among("\u00EC", 0, 3), new Among("\u00ED", 0, 3), new Among("\u00EF", 0, 3), new Among("\u00F2", 0, 4), new Among("\u00F3", 0, 4), new Among("\u00FA", 0, 5), new Among("\u00FC", 0, 5) }; private final static Among[] a_1 = { new Among("la", -1, 1), new Among("-la", 0, 1), new Among("sela", 0, 1), new Among("le", -1, 1), new Among("me", -1, 1), new Among("-me", 4, 1), new Among("se", -1, 1), new Among("-te", -1, 1), new Among("hi", -1, 1), new Among("'hi", 8, 1), new Among("li", -1, 1), new Among("-li", 10, 1), new Among("'l", -1, 1), new Among("'m", -1, 1), new Among("-m", -1, 1), new Among("'n", -1, 1), new Among("-n", -1, 1), new Among("ho", -1, 1), new Among("'ho", 17, 1), new Among("lo", -1, 1), new Among("selo", 19, 1), new Among("'s", -1, 1), new Among("las", -1, 1), new Among("selas", 22, 1), new Among("les", -1, 1), new Among("-les", 24, 1), new Among("'ls", -1, 1), new Among("-ls", -1, 1), new Among("'ns", -1, 1), new Among("-ns", -1, 1), new Among("ens", -1, 1), new Among("los", -1, 1), new Among("selos", 31, 1), new Among("nos", -1, 1), new Among("-nos", 33, 1), new Among("vos", -1, 1), new Among("us", -1, 1), new Among("-us", 36, 1), new Among("'t", -1, 1) }; private final static Among[] a_2 = { new Among("ica", -1, 4), new Among("l\u00F3gica", 0, 3), new Among("enca", -1, 1), new Among("ada", -1, 2), new Among("ancia", -1, 1), new Among("encia", -1, 1), new Among("\u00E8ncia", -1, 1), new Among("\u00EDcia", -1, 1), new Among("logia", -1, 3), new Among("inia", -1, 1), new Among("\u00EDinia", 9, 1), new Among("eria", -1, 1), new Among("\u00E0ria", -1, 1), new Among("at\u00F2ria", -1, 1), new Among("alla", -1, 1), new Among("ella", -1, 1), new Among("\u00EDvola", -1, 1), new Among("ima", -1, 1), new Among("\u00EDssima", 17, 1), new Among("qu\u00EDssima", 18, 5), new Among("ana", -1, 1), new Among("ina", -1, 1), new Among("era", -1, 1), new Among("sfera", 22, 1), new Among("ora", -1, 1), new Among("dora", 24, 1), new Among("adora", 25, 1), new Among("adura", -1, 1), new Among("esa", -1, 1), new Among("osa", -1, 1), new Among("assa", -1, 1), new Among("essa", -1, 1), new Among("issa", -1, 1), new Among("eta", -1, 1), new Among("ita", -1, 1), new Among("ota", -1, 1), new Among("ista", -1, 1), new Among("ialista", 36, 1), new Among("ionista", 36, 1), new Among("iva", -1, 1), new Among("ativa", 39, 1), new Among("n\u00E7a", -1, 1), new Among("log\u00EDa", -1, 3), new Among("ic", -1, 4), new Among("\u00EDstic", 43, 1), new Among("enc", -1, 1), new Among("esc", -1, 1), new Among("ud", -1, 1), new Among("atge", -1, 1), new Among("ble", -1, 1), new Among("able", 49, 1), new Among("ible", 49, 1), new Among("isme", -1, 1), new Among("ialisme", 52, 1), new Among("ionisme", 52, 1), new Among("ivisme", 52, 1), new Among("aire", -1, 1), new Among("icte", -1, 1), new Among("iste", -1, 1), new Among("ici", -1, 1), new Among("\u00EDci", -1, 1), new Among("logi", -1, 3), new Among("ari", -1, 1), new Among("tori", -1, 1), new Among("al", -1, 1), new Among("il", -1, 1), new Among("all", -1, 1), new Among("ell", -1, 1), new Among("\u00EDvol", -1, 1), new Among("isam", -1, 1), new Among("issem", -1, 1), new Among("\u00ECssem", -1, 1), new Among("\u00EDssem", -1, 1), new Among("\u00EDssim", -1, 1), new Among("qu\u00EDssim", 73, 5), new Among("amen", -1, 1), new Among("\u00ECssin", -1, 1), new Among("ar", -1, 1), new Among("ificar", 77, 1), new Among("egar", 77, 1), new Among("ejar", 77, 1), new Among("itar", 77, 1), new Among("itzar", 77, 1), new Among("fer", -1, 1), new Among("or", -1, 1), new Among("dor", 84, 1), new Among("dur", -1, 1), new Among("doras", -1, 1), new Among("ics", -1, 4), new Among("l\u00F3gics", 88, 3), new Among("uds", -1, 1), new Among("nces", -1, 1), new Among("ades", -1, 2), new Among("ancies", -1, 1), new Among("encies", -1, 1), new Among("\u00E8ncies", -1, 1), new Among("\u00EDcies", -1, 1), new Among("logies", -1, 3), new Among("inies", -1, 1), new Among("\u00EDnies", -1, 1), new Among("eries", -1, 1), new Among("\u00E0ries", -1, 1), new Among("at\u00F2ries", -1, 1), new Among("bles", -1, 1), new Among("ables", 103, 1), new Among("ibles", 103, 1), new Among("imes", -1, 1), new Among("\u00EDssimes", 106, 1), new Among("qu\u00EDssimes", 107, 5), new Among("formes", -1, 1), new Among("ismes", -1, 1), new Among("ialismes", 110, 1), new Among("ines", -1, 1), new Among("eres", -1, 1), new Among("ores", -1, 1), new Among("dores", 114, 1), new Among("idores", 115, 1), new Among("dures", -1, 1), new Among("eses", -1, 1), new Among("oses", -1, 1), new Among("asses", -1, 1), new Among("ictes", -1, 1), new Among("ites", -1, 1), new Among("otes", -1, 1), new Among("istes", -1, 1), new Among("ialistes", 124, 1), new Among("ionistes", 124, 1), new Among("iques", -1, 4), new Among("l\u00F3giques", 127, 3), new Among("ives", -1, 1), new Among("atives", 129, 1), new Among("log\u00EDes", -1, 3), new Among("alleng\u00FCes", -1, 1), new Among("icis", -1, 1), new Among("\u00EDcis", -1, 1), new Among("logis", -1, 3), new Among("aris", -1, 1), new Among("toris", -1, 1), new Among("ls", -1, 1), new Among("als", 138, 1), new Among("ells", 138, 1), new Among("ims", -1, 1), new Among("\u00EDssims", 141, 1), new Among("qu\u00EDssims", 142, 5), new Among("ions", -1, 1), new Among("cions", 144, 1), new Among("acions", 145, 2), new Among("esos", -1, 1), new Among("osos", -1, 1), new Among("assos", -1, 1), new Among("issos", -1, 1), new Among("ers", -1, 1), new Among("ors", -1, 1), new Among("dors", 152, 1), new Among("adors", 153, 1), new Among("idors", 153, 1), new Among("ats", -1, 1), new Among("itats", 156, 1), new Among("bilitats", 157, 1), new Among("ivitats", 157, 1), new Among("ativitats", 159, 1), new Among("\u00EFtats", 156, 1), new Among("ets", -1, 1), new Among("ants", -1, 1), new Among("ents", -1, 1), new Among("ments", 164, 1), new Among("aments", 165, 1), new Among("ots", -1, 1), new Among("uts", -1, 1), new Among("ius", -1, 1), new Among("trius", 169, 1), new Among("atius", 169, 1), new Among("\u00E8s", -1, 1), new Among("\u00E9s", -1, 1), new Among("\u00EDs", -1, 1), new Among("d\u00EDs", 174, 1), new Among("\u00F3s", -1, 1), new Among("itat", -1, 1), new Among("bilitat", 177, 1), new Among("ivitat", 177, 1), new Among("ativitat", 179, 1), new Among("\u00EFtat", -1, 1), new Among("et", -1, 1), new Among("ant", -1, 1), new Among("ent", -1, 1), new Among("ient", 184, 1), new Among("ment", 184, 1), new Among("ament", 186, 1), new Among("isament", 187, 1), new Among("ot", -1, 1), new Among("isseu", -1, 1), new Among("\u00ECsseu", -1, 1), new Among("\u00EDsseu", -1, 1), new Among("triu", -1, 1), new Among("\u00EDssiu", -1, 1), new Among("atiu", -1, 1), new Among("\u00F3", -1, 1), new Among("i\u00F3", 196, 1), new Among("ci\u00F3", 197, 1), new Among("aci\u00F3", 198, 1) }; private final static Among[] a_3 = { new Among("aba", -1, 1), new Among("esca", -1, 1), new Among("isca", -1, 1), new Among("\u00EFsca", -1, 1), new Among("ada", -1, 1), new Among("ida", -1, 1), new Among("uda", -1, 1), new Among("\u00EFda", -1, 1), new Among("ia", -1, 1), new Among("aria", 8, 1), new Among("iria", 8, 1), new Among("ara", -1, 1), new Among("iera", -1, 1), new Among("ira", -1, 1), new Among("adora", -1, 1), new Among("\u00EFra", -1, 1), new Among("ava", -1, 1), new Among("ixa", -1, 1), new Among("itza", -1, 1), new Among("\u00EDa", -1, 1), new Among("ar\u00EDa", 19, 1), new Among("er\u00EDa", 19, 1), new Among("ir\u00EDa", 19, 1), new Among("\u00EFa", -1, 1), new Among("isc", -1, 1), new Among("\u00EFsc", -1, 1), new Among("ad", -1, 1), new Among("ed", -1, 1), new Among("id", -1, 1), new Among("ie", -1, 1), new Among("re", -1, 1), new Among("dre", 30, 1), new Among("ase", -1, 1), new Among("iese", -1, 1), new Among("aste", -1, 1), new Among("iste", -1, 1), new Among("ii", -1, 1), new Among("ini", -1, 1), new Among("esqui", -1, 1), new Among("eixi", -1, 1), new Among("itzi", -1, 1), new Among("am", -1, 1), new Among("em", -1, 1), new Among("arem", 42, 1), new Among("irem", 42, 1), new Among("\u00E0rem", 42, 1), new Among("\u00EDrem", 42, 1), new Among("\u00E0ssem", 42, 1), new Among("\u00E9ssem", 42, 1), new Among("iguem", 42, 1), new Among("\u00EFguem", 42, 1), new Among("avem", 42, 1), new Among("\u00E0vem", 42, 1), new Among("\u00E1vem", 42, 1), new Among("ir\u00ECem", 42, 1), new Among("\u00EDem", 42, 1), new Among("ar\u00EDem", 55, 1), new Among("ir\u00EDem", 55, 1), new Among("assim", -1, 1), new Among("essim", -1, 1), new Among("issim", -1, 1), new Among("\u00E0ssim", -1, 1), new Among("\u00E8ssim", -1, 1), new Among("\u00E9ssim", -1, 1), new Among("\u00EDssim", -1, 1), new Among("\u00EFm", -1, 1), new Among("an", -1, 1), new Among("aban", 66, 1), new Among("arian", 66, 1), new Among("aran", 66, 1), new Among("ieran", 66, 1), new Among("iran", 66, 1), new Among("\u00EDan", 66, 1), new Among("ar\u00EDan", 72, 1), new Among("er\u00EDan", 72, 1), new Among("ir\u00EDan", 72, 1), new Among("en", -1, 1), new Among("ien", 76, 1), new Among("arien", 77, 1), new Among("irien", 77, 1), new Among("aren", 76, 1), new Among("eren", 76, 1), new Among("iren", 76, 1), new Among("\u00E0ren", 76, 1), new Among("\u00EFren", 76, 1), new Among("asen", 76, 1), new Among("iesen", 76, 1), new Among("assen", 76, 1), new Among("essen", 76, 1), new Among("issen", 76, 1), new Among("\u00E9ssen", 76, 1), new Among("\u00EFssen", 76, 1), new Among("esquen", 76, 1), new Among("isquen", 76, 1), new Among("\u00EFsquen", 76, 1), new Among("aven", 76, 1), new Among("ixen", 76, 1), new Among("eixen", 96, 1), new Among("\u00EFxen", 76, 1), new Among("\u00EFen", 76, 1), new Among("in", -1, 1), new Among("inin", 100, 1), new Among("sin", 100, 1), new Among("isin", 102, 1), new Among("assin", 102, 1), new Among("essin", 102, 1), new Among("issin", 102, 1), new Among("\u00EFssin", 102, 1), new Among("esquin", 100, 1), new Among("eixin", 100, 1), new Among("aron", -1, 1), new Among("ieron", -1, 1), new Among("ar\u00E1n", -1, 1), new Among("er\u00E1n", -1, 1), new Among("ir\u00E1n", -1, 1), new Among("i\u00EFn", -1, 1), new Among("ado", -1, 1), new Among("ido", -1, 1), new Among("ando", -1, 2), new Among("iendo", -1, 1), new Among("io", -1, 1), new Among("ixo", -1, 1), new Among("eixo", 121, 1), new Among("\u00EFxo", -1, 1), new Among("itzo", -1, 1), new Among("ar", -1, 1), new Among("tzar", 125, 1), new Among("er", -1, 1), new Among("eixer", 127, 1), new Among("ir", -1, 1), new Among("ador", -1, 1), new Among("as", -1, 1), new Among("abas", 131, 1), new Among("adas", 131, 1), new Among("idas", 131, 1), new Among("aras", 131, 1), new Among("ieras", 131, 1), new Among("\u00EDas", 131, 1), new Among("ar\u00EDas", 137, 1), new Among("er\u00EDas", 137, 1), new Among("ir\u00EDas", 137, 1), new Among("ids", -1, 1), new Among("es", -1, 1), new Among("ades", 142, 1), new Among("ides", 142, 1), new Among("udes", 142, 1), new Among("\u00EFdes", 142, 1), new Among("atges", 142, 1), new Among("ies", 142, 1), new Among("aries", 148, 1), new Among("iries", 148, 1), new Among("ares", 142, 1), new Among("ires", 142, 1), new Among("adores", 142, 1), new Among("\u00EFres", 142, 1), new Among("ases", 142, 1), new Among("ieses", 142, 1), new Among("asses", 142, 1), new Among("esses", 142, 1), new Among("isses", 142, 1), new Among("\u00EFsses", 142, 1), new Among("ques", 142, 1), new Among("esques", 161, 1), new Among("\u00EFsques", 161, 1), new Among("aves", 142, 1), new Among("ixes", 142, 1), new Among("eixes", 165, 1), new Among("\u00EFxes", 142, 1), new Among("\u00EFes", 142, 1), new Among("abais", -1, 1), new Among("arais", -1, 1), new Among("ierais", -1, 1), new Among("\u00EDais", -1, 1), new Among("ar\u00EDais", 172, 1), new Among("er\u00EDais", 172, 1), new Among("ir\u00EDais", 172, 1), new Among("aseis", -1, 1), new Among("ieseis", -1, 1), new Among("asteis", -1, 1), new Among("isteis", -1, 1), new Among("inis", -1, 1), new Among("sis", -1, 1), new Among("isis", 181, 1), new Among("assis", 181, 1), new Among("essis", 181, 1), new Among("issis", 181, 1), new Among("\u00EFssis", 181, 1), new Among("esquis", -1, 1), new Among("eixis", -1, 1), new Among("itzis", -1, 1), new Among("\u00E1is", -1, 1), new Among("ar\u00E9is", -1, 1), new Among("er\u00E9is", -1, 1), new Among("ir\u00E9is", -1, 1), new Among("ams", -1, 1), new Among("ados", -1, 1), new Among("idos", -1, 1), new Among("amos", -1, 1), new Among("\u00E1bamos", 197, 1), new Among("\u00E1ramos", 197, 1), new Among("i\u00E9ramos", 197, 1), new Among("\u00EDamos", 197, 1), new Among("ar\u00EDamos", 201, 1), new Among("er\u00EDamos", 201, 1), new Among("ir\u00EDamos", 201, 1), new Among("aremos", -1, 1), new Among("eremos", -1, 1), new Among("iremos", -1, 1), new Among("\u00E1semos", -1, 1), new Among("i\u00E9semos", -1, 1), new Among("imos", -1, 1), new Among("adors", -1, 1), new Among("ass", -1, 1), new Among("erass", 212, 1), new Among("ess", -1, 1), new Among("ats", -1, 1), new Among("its", -1, 1), new Among("ents", -1, 1), new Among("\u00E0s", -1, 1), new Among("ar\u00E0s", 218, 1), new Among("ir\u00E0s", 218, 1), new Among("ar\u00E1s", -1, 1), new Among("er\u00E1s", -1, 1), new Among("ir\u00E1s", -1, 1), new Among("\u00E9s", -1, 1), new Among("ar\u00E9s", 224, 1), new Among("\u00EDs", -1, 1), new Among("i\u00EFs", -1, 1), new Among("at", -1, 1), new Among("it", -1, 1), new Among("ant", -1, 1), new Among("ent", -1, 1), new Among("int", -1, 1), new Among("ut", -1, 1), new Among("\u00EFt", -1, 1), new Among("au", -1, 1), new Among("erau", 235, 1), new Among("ieu", -1, 1), new Among("ineu", -1, 1), new Among("areu", -1, 1), new Among("ireu", -1, 1), new Among("\u00E0reu", -1, 1), new Among("\u00EDreu", -1, 1), new Among("asseu", -1, 1), new Among("esseu", -1, 1), new Among("eresseu", 244, 1), new Among("\u00E0sseu", -1, 1), new Among("\u00E9sseu", -1, 1), new Among("igueu", -1, 1), new Among("\u00EFgueu", -1, 1), new Among("\u00E0veu", -1, 1), new Among("\u00E1veu", -1, 1), new Among("itzeu", -1, 1), new Among("\u00ECeu", -1, 1), new Among("ir\u00ECeu", 253, 1), new Among("\u00EDeu", -1, 1), new Among("ar\u00EDeu", 255, 1), new Among("ir\u00EDeu", 255, 1), new Among("assiu", -1, 1), new Among("issiu", -1, 1), new Among("\u00E0ssiu", -1, 1), new Among("\u00E8ssiu", -1, 1), new Among("\u00E9ssiu", -1, 1), new Among("\u00EDssiu", -1, 1), new Among("\u00EFu", -1, 1), new Among("ix", -1, 1), new Among("eix", 265, 1), new Among("\u00EFx", -1, 1), new Among("itz", -1, 1), new Among("i\u00E0", -1, 1), new Among("ar\u00E0", -1, 1), new Among("ir\u00E0", -1, 1), new Among("itz\u00E0", -1, 1), new Among("ar\u00E1", -1, 1), new Among("er\u00E1", -1, 1), new Among("ir\u00E1", -1, 1), new Among("ir\u00E8", -1, 1), new Among("ar\u00E9", -1, 1), new Among("er\u00E9", -1, 1), new Among("ir\u00E9", -1, 1), new Among("\u00ED", -1, 1), new Among("i\u00EF", -1, 1), new Among("i\u00F3", -1, 1) }; private final static Among[] a_4 = { new Among("a", -1, 1), new Among("e", -1, 1), new Among("i", -1, 1), new Among("\u00EFn", -1, 1), new Among("o", -1, 1), new Among("ir", -1, 1), new Among("s", -1, 1), new Among("is", 6, 1), new Among("os", 6, 1), new Among("\u00EFs", 6, 1), new Among("it", -1, 1), new Among("eu", -1, 1), new Among("iu", -1, 1), new Among("iqu", -1, 2), new Among("itz", -1, 1), new Among("\u00E0", -1, 1), new Among("\u00E1", -1, 1), new Among("\u00E9", -1, 1), new Among("\u00EC", -1, 1), new Among("\u00ED", -1, 1), new Among("\u00EF", -1, 1), new Among("\u00F3", -1, 1) }; private static final char[] g_v = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 129, 81, 6, 10}; private int I_p2; private int I_p1; private boolean r_mark_regions() { I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { golab1: while (true) { lab2: { if (!(in_grouping(g_v, 97, 252))) { break lab2; } break golab1; } if (cursor >= limit) { break lab0; } cursor++; } golab3: while (true) { lab4: { if (!(out_grouping(g_v, 97, 252))) { break lab4; } break golab3; } if (cursor >= limit) { break lab0; } cursor++; } I_p1 = cursor; golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 252))) { break lab6; } break golab5; } if (cursor >= limit) { break lab0; } cursor++; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 252))) { break lab8; } break golab7; } if (cursor >= limit) { break lab0; } cursor++; } I_p2 = cursor; } cursor = v_1; return true; } private boolean r_cleaning() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_0); ket = cursor; switch (among_var) { case 1: slice_from("a"); break; case 2: slice_from("e"); break; case 3: slice_from("i"); break; case 4: slice_from("o"); break; case 5: slice_from("u"); break; case 6: slice_from("."); break; case 7: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_attached_pronoun() { ket = cursor; if (find_among_b(a_1) == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } slice_del(); return true; } private boolean r_standard_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R1()) { return false; } slice_del(); break; case 2: if (!r_R2()) { return false; } slice_del(); break; case 3: if (!r_R2()) { return false; } slice_from("log"); break; case 4: if (!r_R2()) { return false; } slice_from("ic"); break; case 5: if (!r_R1()) { return false; } slice_from("c"); break; } return true; } private boolean r_verb_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R1()) { return false; } slice_del(); break; case 2: if (!r_R2()) { return false; } slice_del(); break; } return true; } private boolean r_residual_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R1()) { return false; } slice_del(); break; case 2: if (!r_R1()) { return false; } slice_from("ic"); break; } return true; } @Override public boolean stem() { r_mark_regions(); limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_attached_pronoun(); cursor = limit - v_2; int v_3 = limit - cursor; lab0: { lab1: { int v_4 = limit - cursor; lab2: { if (!r_standard_suffix()) { break lab2; } break lab1; } cursor = limit - v_4; if (!r_verb_suffix()) { break lab0; } } } cursor = limit - v_3; int v_5 = limit - cursor; r_residual_suffix(); cursor = limit - v_5; cursor = limit_backward; int v_6 = cursor; r_cleaning(); cursor = v_6; return true; } @Override public boolean equals(Object o) { return o instanceof catalanStemmer; } @Override public int hashCode() { return catalanStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000161 15217274217 032614 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/danishStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/danishStemmer.j0100644 0000000 0000000 00000017260 15217274217 034170 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class danishStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("hed", -1, 1), new Among("ethed", 0, 1), new Among("ered", -1, 1), new Among("e", -1, 1), new Among("erede", 3, 1), new Among("ende", 3, 1), new Among("erende", 5, 1), new Among("ene", 3, 1), new Among("erne", 3, 1), new Among("ere", 3, 1), new Among("en", -1, 1), new Among("heden", 10, 1), new Among("eren", 10, 1), new Among("er", -1, 1), new Among("heder", 13, 1), new Among("erer", 13, 1), new Among("s", -1, 2), new Among("heds", 16, 1), new Among("es", 16, 1), new Among("endes", 18, 1), new Among("erendes", 19, 1), new Among("enes", 18, 1), new Among("ernes", 18, 1), new Among("eres", 18, 1), new Among("ens", 16, 1), new Among("hedens", 24, 1), new Among("erens", 24, 1), new Among("ers", 16, 1), new Among("ets", 16, 1), new Among("erets", 28, 1), new Among("et", -1, 1), new Among("eret", 30, 1) }; private final static Among[] a_1 = { new Among("gd", -1, -1), new Among("dt", -1, -1), new Among("gt", -1, -1), new Among("kt", -1, -1) }; private final static Among[] a_2 = { new Among("ig", -1, 1), new Among("lig", 0, 1), new Among("elig", 1, 1), new Among("els", -1, 1), new Among("l\u00F8st", -1, 2) }; private static final char[] g_c = {119, 223, 119, 1}; private static final char[] g_v = {17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 128}; private static final char[] g_s_ending = {239, 254, 42, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}; private int I_x; private int I_p1; private java.lang.StringBuilder S_ch = new java.lang.StringBuilder(); private boolean r_mark_regions() { I_p1 = limit; int v_1 = cursor; { int c = cursor + 3; if (c > limit) { return false; } cursor = c; } I_x = cursor; cursor = v_1; golab0: while (true) { int v_2 = cursor; lab1: { if (!(in_grouping(g_v, 97, 248))) { break lab1; } cursor = v_2; break golab0; } cursor = v_2; if (cursor >= limit) { return false; } cursor++; } golab2: while (true) { lab3: { if (!(out_grouping(g_v, 97, 248))) { break lab3; } break golab2; } if (cursor >= limit) { return false; } cursor++; } I_p1 = cursor; lab4: { if (I_p1 >= I_x) { break lab4; } I_p1 = I_x; } return true; } private boolean r_main_suffix() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_0); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: slice_del(); break; case 2: if (!(in_grouping_b(g_s_ending, 97, 229))) { return false; } slice_del(); break; } return true; } private boolean r_consonant_pair() { int v_1 = limit - cursor; if (cursor < I_p1) { return false; } int v_3 = limit_backward; limit_backward = I_p1; ket = cursor; if (find_among_b(a_1) == 0) { limit_backward = v_3; return false; } bra = cursor; limit_backward = v_3; cursor = limit - v_1; if (cursor <= limit_backward) { return false; } cursor--; bra = cursor; slice_del(); return true; } private boolean r_other_suffix() { int among_var; int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("st"))) { break lab0; } bra = cursor; if (!(eq_s_b("ig"))) { break lab0; } slice_del(); } cursor = limit - v_1; if (cursor < I_p1) { return false; } int v_3 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { limit_backward = v_3; return false; } bra = cursor; limit_backward = v_3; switch (among_var) { case 1: slice_del(); int v_4 = limit - cursor; r_consonant_pair(); cursor = limit - v_4; break; case 2: slice_from("l\u00F8s"); break; } return true; } private boolean r_undouble() { if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; if (!(in_grouping_b(g_c, 98, 122))) { limit_backward = v_2; return false; } bra = cursor; slice_to(S_ch); limit_backward = v_2; if (!(eq_s_b(S_ch))) { return false; } slice_del(); return true; } @Override public boolean stem() { int v_1 = cursor; r_mark_regions(); cursor = v_1; limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_main_suffix(); cursor = limit - v_2; int v_3 = limit - cursor; r_consonant_pair(); cursor = limit - v_3; int v_4 = limit - cursor; r_other_suffix(); cursor = limit - v_4; int v_5 = limit - cursor; r_undouble(); cursor = limit - v_5; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof danishStemmer; } @Override public int hashCode() { return danishStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000160 15217274217 032613 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/dutchStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/dutchStemmer.ja0100644 0000000 0000000 00000032100 15217274217 034160 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class dutchStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("", -1, 6), new Among("\u00E1", 0, 1), new Among("\u00E4", 0, 1), new Among("\u00E9", 0, 2), new Among("\u00EB", 0, 2), new Among("\u00ED", 0, 3), new Among("\u00EF", 0, 3), new Among("\u00F3", 0, 4), new Among("\u00F6", 0, 4), new Among("\u00FA", 0, 5), new Among("\u00FC", 0, 5) }; private final static Among[] a_1 = { new Among("", -1, 3), new Among("I", 0, 2), new Among("Y", 0, 1) }; private final static Among[] a_2 = { new Among("dd", -1, -1), new Among("kk", -1, -1), new Among("tt", -1, -1) }; private final static Among[] a_3 = { new Among("ene", -1, 2), new Among("se", -1, 3), new Among("en", -1, 2), new Among("heden", 2, 1), new Among("s", -1, 3) }; private final static Among[] a_4 = { new Among("end", -1, 1), new Among("ig", -1, 2), new Among("ing", -1, 1), new Among("lijk", -1, 3), new Among("baar", -1, 4), new Among("bar", -1, 5) }; private final static Among[] a_5 = { new Among("aa", -1, -1), new Among("ee", -1, -1), new Among("oo", -1, -1), new Among("uu", -1, -1) }; private static final char[] g_v = {17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128}; private static final char[] g_v_I = {1, 0, 0, 17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128}; private static final char[] g_v_j = {17, 67, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128}; private int I_p2; private int I_p1; private boolean B_e_found; private boolean r_prelude() { int among_var; int v_1 = cursor; while (true) { int v_2 = cursor; lab0: { bra = cursor; among_var = find_among(a_0); ket = cursor; switch (among_var) { case 1: slice_from("a"); break; case 2: slice_from("e"); break; case 3: slice_from("i"); break; case 4: slice_from("o"); break; case 5: slice_from("u"); break; case 6: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_2; break; } cursor = v_1; int v_3 = cursor; lab1: { bra = cursor; if (!(eq_s("y"))) { cursor = v_3; break lab1; } ket = cursor; slice_from("Y"); } while (true) { int v_4 = cursor; lab2: { golab3: while (true) { int v_5 = cursor; lab4: { if (!(in_grouping(g_v, 97, 232))) { break lab4; } bra = cursor; lab5: { int v_6 = cursor; lab6: { if (!(eq_s("i"))) { break lab6; } ket = cursor; if (!(in_grouping(g_v, 97, 232))) { break lab6; } slice_from("I"); break lab5; } cursor = v_6; if (!(eq_s("y"))) { break lab4; } ket = cursor; slice_from("Y"); } cursor = v_5; break golab3; } cursor = v_5; if (cursor >= limit) { break lab2; } cursor++; } continue; } cursor = v_4; break; } return true; } private boolean r_mark_regions() { I_p1 = limit; I_p2 = limit; golab0: while (true) { lab1: { if (!(in_grouping(g_v, 97, 232))) { break lab1; } break golab0; } if (cursor >= limit) { return false; } cursor++; } golab2: while (true) { lab3: { if (!(out_grouping(g_v, 97, 232))) { break lab3; } break golab2; } if (cursor >= limit) { return false; } cursor++; } I_p1 = cursor; lab4: { if (I_p1 >= 3) { break lab4; } I_p1 = 3; } golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 232))) { break lab6; } break golab5; } if (cursor >= limit) { return false; } cursor++; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 232))) { break lab8; } break golab7; } if (cursor >= limit) { return false; } cursor++; } I_p2 = cursor; return true; } private boolean r_postlude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_1); ket = cursor; switch (among_var) { case 1: slice_from("y"); break; case 2: slice_from("i"); break; case 3: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_undouble() { int v_1 = limit - cursor; if (find_among_b(a_2) == 0) { return false; } cursor = limit - v_1; ket = cursor; if (cursor <= limit_backward) { return false; } cursor--; bra = cursor; slice_del(); return true; } private boolean r_e_ending() { B_e_found = false; ket = cursor; if (!(eq_s_b("e"))) { return false; } bra = cursor; if (!r_R1()) { return false; } int v_1 = limit - cursor; if (!(out_grouping_b(g_v, 97, 232))) { return false; } cursor = limit - v_1; slice_del(); B_e_found = true; if (!r_undouble()) { return false; } return true; } private boolean r_en_ending() { if (!r_R1()) { return false; } int v_1 = limit - cursor; if (!(out_grouping_b(g_v, 97, 232))) { return false; } cursor = limit - v_1; { int v_2 = limit - cursor; lab0: { if (!(eq_s_b("gem"))) { break lab0; } return false; } cursor = limit - v_2; } slice_del(); if (!r_undouble()) { return false; } return true; } private boolean r_standard_suffix() { int among_var; int v_1 = limit - cursor; lab0: { ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { break lab0; } bra = cursor; switch (among_var) { case 1: if (!r_R1()) { break lab0; } slice_from("heid"); break; case 2: if (!r_en_ending()) { break lab0; } break; case 3: if (!r_R1()) { break lab0; } if (!(out_grouping_b(g_v_j, 97, 232))) { break lab0; } slice_del(); break; } } cursor = limit - v_1; int v_2 = limit - cursor; r_e_ending(); cursor = limit - v_2; int v_3 = limit - cursor; lab1: { ket = cursor; if (!(eq_s_b("heid"))) { break lab1; } bra = cursor; if (!r_R2()) { break lab1; } { int v_4 = limit - cursor; lab2: { if (!(eq_s_b("c"))) { break lab2; } break lab1; } cursor = limit - v_4; } slice_del(); ket = cursor; if (!(eq_s_b("en"))) { break lab1; } bra = cursor; if (!r_en_ending()) { break lab1; } } cursor = limit - v_3; int v_5 = limit - cursor; lab3: { ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { break lab3; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { break lab3; } slice_del(); lab4: { int v_6 = limit - cursor; lab5: { ket = cursor; if (!(eq_s_b("ig"))) { break lab5; } bra = cursor; if (!r_R2()) { break lab5; } { int v_7 = limit - cursor; lab6: { if (!(eq_s_b("e"))) { break lab6; } break lab5; } cursor = limit - v_7; } slice_del(); break lab4; } cursor = limit - v_6; if (!r_undouble()) { break lab3; } } break; case 2: if (!r_R2()) { break lab3; } { int v_8 = limit - cursor; lab7: { if (!(eq_s_b("e"))) { break lab7; } break lab3; } cursor = limit - v_8; } slice_del(); break; case 3: if (!r_R2()) { break lab3; } slice_del(); if (!r_e_ending()) { break lab3; } break; case 4: if (!r_R2()) { break lab3; } slice_del(); break; case 5: if (!r_R2()) { break lab3; } if (!(B_e_found)) { break lab3; } slice_del(); break; } } cursor = limit - v_5; int v_9 = limit - cursor; lab8: { if (!(out_grouping_b(g_v_I, 73, 232))) { break lab8; } int v_10 = limit - cursor; if (find_among_b(a_5) == 0) { break lab8; } if (!(out_grouping_b(g_v, 97, 232))) { break lab8; } cursor = limit - v_10; ket = cursor; if (cursor <= limit_backward) { break lab8; } cursor--; bra = cursor; slice_del(); } cursor = limit - v_9; return true; } @Override public boolean stem() { int v_1 = cursor; r_prelude(); cursor = v_1; int v_2 = cursor; r_mark_regions(); cursor = v_2; limit_backward = cursor; cursor = limit; r_standard_suffix(); cursor = limit_backward; int v_4 = cursor; r_postlude(); cursor = v_4; return true; } @Override public boolean equals(Object o) { return o instanceof dutchStemmer; } @Override public int hashCode() { return dutchStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/englishStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/englishStemmer.0100644 0000000 0000000 00000050523 15217274217 034200 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class englishStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("arsen", -1, -1), new Among("commun", -1, -1), new Among("gener", -1, -1) }; private final static Among[] a_1 = { new Among("'", -1, 1), new Among("'s'", 0, 1), new Among("'s", -1, 1) }; private final static Among[] a_2 = { new Among("ied", -1, 2), new Among("s", -1, 3), new Among("ies", 1, 2), new Among("sses", 1, 1), new Among("ss", 1, -1), new Among("us", 1, -1) }; private final static Among[] a_3 = { new Among("", -1, 3), new Among("bb", 0, 2), new Among("dd", 0, 2), new Among("ff", 0, 2), new Among("gg", 0, 2), new Among("bl", 0, 1), new Among("mm", 0, 2), new Among("nn", 0, 2), new Among("pp", 0, 2), new Among("rr", 0, 2), new Among("at", 0, 1), new Among("tt", 0, 2), new Among("iz", 0, 1) }; private final static Among[] a_4 = { new Among("ed", -1, 2), new Among("eed", 0, 1), new Among("ing", -1, 2), new Among("edly", -1, 2), new Among("eedly", 3, 1), new Among("ingly", -1, 2) }; private final static Among[] a_5 = { new Among("anci", -1, 3), new Among("enci", -1, 2), new Among("ogi", -1, 13), new Among("li", -1, 15), new Among("bli", 3, 12), new Among("abli", 4, 4), new Among("alli", 3, 8), new Among("fulli", 3, 9), new Among("lessli", 3, 14), new Among("ousli", 3, 10), new Among("entli", 3, 5), new Among("aliti", -1, 8), new Among("biliti", -1, 12), new Among("iviti", -1, 11), new Among("tional", -1, 1), new Among("ational", 14, 7), new Among("alism", -1, 8), new Among("ation", -1, 7), new Among("ization", 17, 6), new Among("izer", -1, 6), new Among("ator", -1, 7), new Among("iveness", -1, 11), new Among("fulness", -1, 9), new Among("ousness", -1, 10) }; private final static Among[] a_6 = { new Among("icate", -1, 4), new Among("ative", -1, 6), new Among("alize", -1, 3), new Among("iciti", -1, 4), new Among("ical", -1, 4), new Among("tional", -1, 1), new Among("ational", 5, 2), new Among("ful", -1, 5), new Among("ness", -1, 5) }; private final static Among[] a_7 = { new Among("ic", -1, 1), new Among("ance", -1, 1), new Among("ence", -1, 1), new Among("able", -1, 1), new Among("ible", -1, 1), new Among("ate", -1, 1), new Among("ive", -1, 1), new Among("ize", -1, 1), new Among("iti", -1, 1), new Among("al", -1, 1), new Among("ism", -1, 1), new Among("ion", -1, 2), new Among("er", -1, 1), new Among("ous", -1, 1), new Among("ant", -1, 1), new Among("ent", -1, 1), new Among("ment", 15, 1), new Among("ement", 16, 1) }; private final static Among[] a_8 = { new Among("e", -1, 1), new Among("l", -1, 2) }; private final static Among[] a_9 = { new Among("succeed", -1, -1), new Among("proceed", -1, -1), new Among("exceed", -1, -1), new Among("canning", -1, -1), new Among("inning", -1, -1), new Among("earring", -1, -1), new Among("herring", -1, -1), new Among("outing", -1, -1) }; private final static Among[] a_10 = { new Among("andes", -1, -1), new Among("atlas", -1, -1), new Among("bias", -1, -1), new Among("cosmos", -1, -1), new Among("dying", -1, 3), new Among("early", -1, 9), new Among("gently", -1, 7), new Among("howe", -1, -1), new Among("idly", -1, 6), new Among("lying", -1, 4), new Among("news", -1, -1), new Among("only", -1, 10), new Among("singly", -1, 11), new Among("skies", -1, 2), new Among("skis", -1, 1), new Among("sky", -1, -1), new Among("tying", -1, 5), new Among("ugly", -1, 8) }; private static final char[] g_aeo = {17, 64}; private static final char[] g_v = {17, 65, 16, 1}; private static final char[] g_v_WXY = {1, 17, 65, 208, 1}; private static final char[] g_valid_LI = {55, 141, 2}; private boolean B_Y_found; private int I_p2; private int I_p1; private boolean r_prelude() { B_Y_found = false; int v_1 = cursor; lab0: { bra = cursor; if (!(eq_s("'"))) { break lab0; } ket = cursor; slice_del(); } cursor = v_1; int v_2 = cursor; lab1: { bra = cursor; if (!(eq_s("y"))) { break lab1; } ket = cursor; slice_from("Y"); B_Y_found = true; } cursor = v_2; int v_3 = cursor; lab2: { while (true) { int v_4 = cursor; lab3: { golab4: while (true) { int v_5 = cursor; lab5: { if (!(in_grouping(g_v, 97, 121))) { break lab5; } bra = cursor; if (!(eq_s("y"))) { break lab5; } ket = cursor; cursor = v_5; break golab4; } cursor = v_5; if (cursor >= limit) { break lab3; } cursor++; } slice_from("Y"); B_Y_found = true; continue; } cursor = v_4; break; } } cursor = v_3; return true; } private boolean r_mark_regions() { I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { lab1: { int v_2 = cursor; lab2: { if (find_among(a_0) == 0) { break lab2; } break lab1; } cursor = v_2; golab3: while (true) { lab4: { if (!(in_grouping(g_v, 97, 121))) { break lab4; } break golab3; } if (cursor >= limit) { break lab0; } cursor++; } golab5: while (true) { lab6: { if (!(out_grouping(g_v, 97, 121))) { break lab6; } break golab5; } if (cursor >= limit) { break lab0; } cursor++; } } I_p1 = cursor; golab7: while (true) { lab8: { if (!(in_grouping(g_v, 97, 121))) { break lab8; } break golab7; } if (cursor >= limit) { break lab0; } cursor++; } golab9: while (true) { lab10: { if (!(out_grouping(g_v, 97, 121))) { break lab10; } break golab9; } if (cursor >= limit) { break lab0; } cursor++; } I_p2 = cursor; } cursor = v_1; return true; } private boolean r_shortv() { lab0: { int v_1 = limit - cursor; lab1: { if (!(out_grouping_b(g_v_WXY, 89, 121))) { break lab1; } if (!(in_grouping_b(g_v, 97, 121))) { break lab1; } if (!(out_grouping_b(g_v, 97, 121))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(out_grouping_b(g_v, 97, 121))) { return false; } if (!(in_grouping_b(g_v, 97, 121))) { return false; } if (cursor > limit_backward) { return false; } } return true; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_Step_1a() { int among_var; int v_1 = limit - cursor; lab0: { ket = cursor; if (find_among_b(a_1) == 0) { cursor = limit - v_1; break lab0; } bra = cursor; slice_del(); } ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: slice_from("ss"); break; case 2: lab1: { int v_2 = limit - cursor; lab2: { { int c = cursor - 2; if (c < limit_backward) { break lab2; } cursor = c; } slice_from("i"); break lab1; } cursor = limit - v_2; slice_from("ie"); } break; case 3: if (cursor <= limit_backward) { return false; } cursor--; golab3: while (true) { lab4: { if (!(in_grouping_b(g_v, 97, 121))) { break lab4; } break golab3; } if (cursor <= limit_backward) { return false; } cursor--; } slice_del(); break; } return true; } private boolean r_Step_1b() { int among_var; ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R1()) { return false; } slice_from("ee"); break; case 2: int v_1 = limit - cursor; golab0: while (true) { lab1: { if (!(in_grouping_b(g_v, 97, 121))) { break lab1; } break golab0; } if (cursor <= limit_backward) { return false; } cursor--; } cursor = limit - v_1; slice_del(); ket = cursor; bra = cursor; int v_3 = limit - cursor; among_var = find_among_b(a_3); switch (among_var) { case 1: slice_from("e"); return false; case 2: { int v_4 = limit - cursor; lab2: { if (!(in_grouping_b(g_aeo, 97, 111))) { break lab2; } if (cursor > limit_backward) { break lab2; } return false; } cursor = limit - v_4; } break; case 3: if (cursor != I_p1) { return false; } int v_5 = limit - cursor; if (!r_shortv()) { return false; } cursor = limit - v_5; slice_from("e"); return false; } cursor = limit - v_3; ket = cursor; if (cursor <= limit_backward) { return false; } cursor--; bra = cursor; slice_del(); break; } return true; } private boolean r_Step_1c() { ket = cursor; lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("y"))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(eq_s_b("Y"))) { return false; } } bra = cursor; if (!(out_grouping_b(g_v, 97, 121))) { return false; } lab2: { if (cursor > limit_backward) { break lab2; } return false; } slice_from("i"); return true; } private boolean r_Step_2() { int among_var; ket = cursor; among_var = find_among_b(a_5); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("tion"); break; case 2: slice_from("ence"); break; case 3: slice_from("ance"); break; case 4: slice_from("able"); break; case 5: slice_from("ent"); break; case 6: slice_from("ize"); break; case 7: slice_from("ate"); break; case 8: slice_from("al"); break; case 9: slice_from("ful"); break; case 10: slice_from("ous"); break; case 11: slice_from("ive"); break; case 12: slice_from("ble"); break; case 13: if (!(eq_s_b("l"))) { return false; } slice_from("og"); break; case 14: slice_from("less"); break; case 15: if (!(in_grouping_b(g_valid_LI, 99, 116))) { return false; } slice_del(); break; } return true; } private boolean r_Step_3() { int among_var; ket = cursor; among_var = find_among_b(a_6); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("tion"); break; case 2: slice_from("ate"); break; case 3: slice_from("al"); break; case 4: slice_from("ic"); break; case 5: slice_del(); break; case 6: if (!r_R2()) { return false; } slice_del(); break; } return true; } private boolean r_Step_4() { int among_var; ket = cursor; among_var = find_among_b(a_7); if (among_var == 0) { return false; } bra = cursor; if (!r_R2()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("s"))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(eq_s_b("t"))) { return false; } } slice_del(); break; } return true; } private boolean r_Step_5() { int among_var; ket = cursor; among_var = find_among_b(a_8); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: lab0: { lab1: { if (!r_R2()) { break lab1; } break lab0; } if (!r_R1()) { return false; } { int v_2 = limit - cursor; lab2: { if (!r_shortv()) { break lab2; } return false; } cursor = limit - v_2; } } slice_del(); break; case 2: if (!r_R2()) { return false; } if (!(eq_s_b("l"))) { return false; } slice_del(); break; } return true; } private boolean r_exception2() { ket = cursor; if (find_among_b(a_9) == 0) { return false; } bra = cursor; if (cursor > limit_backward) { return false; } return true; } private boolean r_exception1() { int among_var; bra = cursor; among_var = find_among(a_10); if (among_var == 0) { return false; } ket = cursor; if (cursor < limit) { return false; } switch (among_var) { case 1: slice_from("ski"); break; case 2: slice_from("sky"); break; case 3: slice_from("die"); break; case 4: slice_from("lie"); break; case 5: slice_from("tie"); break; case 6: slice_from("idl"); break; case 7: slice_from("gentl"); break; case 8: slice_from("ugli"); break; case 9: slice_from("earli"); break; case 10: slice_from("onli"); break; case 11: slice_from("singl"); break; } return true; } private boolean r_postlude() { if (!(B_Y_found)) { return false; } while (true) { int v_1 = cursor; lab0: { golab1: while (true) { int v_2 = cursor; lab2: { bra = cursor; if (!(eq_s("Y"))) { break lab2; } ket = cursor; cursor = v_2; break golab1; } cursor = v_2; if (cursor >= limit) { break lab0; } cursor++; } slice_from("y"); continue; } cursor = v_1; break; } return true; } @Override public boolean stem() { lab0: { int v_1 = cursor; lab1: { if (!r_exception1()) { break lab1; } break lab0; } cursor = v_1; lab2: { { int v_2 = cursor; lab3: { { int c = cursor + 3; if (c > limit) { break lab3; } cursor = c; } break lab2; } cursor = v_2; } break lab0; } cursor = v_1; r_prelude(); r_mark_regions(); limit_backward = cursor; cursor = limit; int v_5 = limit - cursor; r_Step_1a(); cursor = limit - v_5; lab4: { int v_6 = limit - cursor; lab5: { if (!r_exception2()) { break lab5; } break lab4; } cursor = limit - v_6; int v_7 = limit - cursor; r_Step_1b(); cursor = limit - v_7; int v_8 = limit - cursor; r_Step_1c(); cursor = limit - v_8; int v_9 = limit - cursor; r_Step_2(); cursor = limit - v_9; int v_10 = limit - cursor; r_Step_3(); cursor = limit - v_10; int v_11 = limit - cursor; r_Step_4(); cursor = limit - v_11; int v_12 = limit - cursor; r_Step_5(); cursor = limit - v_12; } cursor = limit_backward; int v_13 = cursor; r_postlude(); cursor = v_13; } return true; } @Override public boolean equals(Object o) { return o instanceof englishStemmer; } @Override public int hashCode() { return englishStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/finnishStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/finnishStemmer.0100644 0000000 0000000 00000040616 15217274217 034207 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class finnishStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private static final java.lang.invoke.MethodHandles.Lookup methodObject = java.lang.invoke.MethodHandles.lookup(); private final static Among[] a_0 = { new Among("pa", -1, 1), new Among("sti", -1, 2), new Among("kaan", -1, 1), new Among("han", -1, 1), new Among("kin", -1, 1), new Among("h\u00E4n", -1, 1), new Among("k\u00E4\u00E4n", -1, 1), new Among("ko", -1, 1), new Among("p\u00E4", -1, 1), new Among("k\u00F6", -1, 1) }; private final static Among[] a_1 = { new Among("lla", -1, -1), new Among("na", -1, -1), new Among("ssa", -1, -1), new Among("ta", -1, -1), new Among("lta", 3, -1), new Among("sta", 3, -1) }; private final static Among[] a_2 = { new Among("ll\u00E4", -1, -1), new Among("n\u00E4", -1, -1), new Among("ss\u00E4", -1, -1), new Among("t\u00E4", -1, -1), new Among("lt\u00E4", 3, -1), new Among("st\u00E4", 3, -1) }; private final static Among[] a_3 = { new Among("lle", -1, -1), new Among("ine", -1, -1) }; private final static Among[] a_4 = { new Among("nsa", -1, 3), new Among("mme", -1, 3), new Among("nne", -1, 3), new Among("ni", -1, 2), new Among("si", -1, 1), new Among("an", -1, 4), new Among("en", -1, 6), new Among("\u00E4n", -1, 5), new Among("ns\u00E4", -1, 3) }; private final static Among[] a_5 = { new Among("aa", -1, -1), new Among("ee", -1, -1), new Among("ii", -1, -1), new Among("oo", -1, -1), new Among("uu", -1, -1), new Among("\u00E4\u00E4", -1, -1), new Among("\u00F6\u00F6", -1, -1) }; private final static Among[] a_6 = { new Among("a", -1, 8), new Among("lla", 0, -1), new Among("na", 0, -1), new Among("ssa", 0, -1), new Among("ta", 0, -1), new Among("lta", 4, -1), new Among("sta", 4, -1), new Among("tta", 4, 2), new Among("lle", -1, -1), new Among("ine", -1, -1), new Among("ksi", -1, -1), new Among("n", -1, 7), new Among("han", 11, 1), new Among("den", 11, -1, "r_VI", methodObject), new Among("seen", 11, -1, "r_LONG", methodObject), new Among("hen", 11, 2), new Among("tten", 11, -1, "r_VI", methodObject), new Among("hin", 11, 3), new Among("siin", 11, -1, "r_VI", methodObject), new Among("hon", 11, 4), new Among("h\u00E4n", 11, 5), new Among("h\u00F6n", 11, 6), new Among("\u00E4", -1, 8), new Among("ll\u00E4", 22, -1), new Among("n\u00E4", 22, -1), new Among("ss\u00E4", 22, -1), new Among("t\u00E4", 22, -1), new Among("lt\u00E4", 26, -1), new Among("st\u00E4", 26, -1), new Among("tt\u00E4", 26, 2) }; private final static Among[] a_7 = { new Among("eja", -1, -1), new Among("mma", -1, 1), new Among("imma", 1, -1), new Among("mpa", -1, 1), new Among("impa", 3, -1), new Among("mmi", -1, 1), new Among("immi", 5, -1), new Among("mpi", -1, 1), new Among("impi", 7, -1), new Among("ej\u00E4", -1, -1), new Among("mm\u00E4", -1, 1), new Among("imm\u00E4", 10, -1), new Among("mp\u00E4", -1, 1), new Among("imp\u00E4", 12, -1) }; private final static Among[] a_8 = { new Among("i", -1, -1), new Among("j", -1, -1) }; private final static Among[] a_9 = { new Among("mma", -1, 1), new Among("imma", 0, -1) }; private static final char[] g_AEI = {17, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8}; private static final char[] g_C = {119, 223, 119, 1}; private static final char[] g_V1 = {17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 32}; private static final char[] g_V2 = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 32}; private static final char[] g_particle_end = {17, 97, 24, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 32}; private boolean B_ending_removed; private java.lang.StringBuilder S_x = new java.lang.StringBuilder(); private int I_p2; private int I_p1; private boolean r_mark_regions() { I_p1 = limit; I_p2 = limit; golab0: while (true) { int v_1 = cursor; lab1: { if (!(in_grouping(g_V1, 97, 246))) { break lab1; } cursor = v_1; break golab0; } cursor = v_1; if (cursor >= limit) { return false; } cursor++; } golab2: while (true) { lab3: { if (!(out_grouping(g_V1, 97, 246))) { break lab3; } break golab2; } if (cursor >= limit) { return false; } cursor++; } I_p1 = cursor; golab4: while (true) { int v_3 = cursor; lab5: { if (!(in_grouping(g_V1, 97, 246))) { break lab5; } cursor = v_3; break golab4; } cursor = v_3; if (cursor >= limit) { return false; } cursor++; } golab6: while (true) { lab7: { if (!(out_grouping(g_V1, 97, 246))) { break lab7; } break golab6; } if (cursor >= limit) { return false; } cursor++; } I_p2 = cursor; return true; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_particle_etc() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_0); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: if (!(in_grouping_b(g_particle_end, 97, 246))) { return false; } break; case 2: if (!r_R2()) { return false; } break; } slice_del(); return true; } private boolean r_possessive() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: { int v_3 = limit - cursor; lab0: { if (!(eq_s_b("k"))) { break lab0; } return false; } cursor = limit - v_3; } slice_del(); break; case 2: slice_del(); ket = cursor; if (!(eq_s_b("kse"))) { return false; } bra = cursor; slice_from("ksi"); break; case 3: slice_del(); break; case 4: if (find_among_b(a_1) == 0) { return false; } slice_del(); break; case 5: if (find_among_b(a_2) == 0) { return false; } slice_del(); break; case 6: if (find_among_b(a_3) == 0) { return false; } slice_del(); break; } return true; } private boolean r_LONG() { if (find_among_b(a_5) == 0) { return false; } return true; } private boolean r_VI() { if (!(eq_s_b("i"))) { return false; } if (!(in_grouping_b(g_V2, 97, 246))) { return false; } return true; } private boolean r_case_ending() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_6); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: if (!(eq_s_b("a"))) { return false; } break; case 2: if (!(eq_s_b("e"))) { return false; } break; case 3: if (!(eq_s_b("i"))) { return false; } break; case 4: if (!(eq_s_b("o"))) { return false; } break; case 5: if (!(eq_s_b("\u00E4"))) { return false; } break; case 6: if (!(eq_s_b("\u00F6"))) { return false; } break; case 7: int v_3 = limit - cursor; lab0: { int v_4 = limit - cursor; lab1: { int v_5 = limit - cursor; lab2: { if (!r_LONG()) { break lab2; } break lab1; } cursor = limit - v_5; if (!(eq_s_b("ie"))) { cursor = limit - v_3; break lab0; } } cursor = limit - v_4; if (cursor <= limit_backward) { cursor = limit - v_3; break lab0; } cursor--; bra = cursor; } break; case 8: if (!(in_grouping_b(g_V1, 97, 246))) { return false; } if (!(in_grouping_b(g_C, 98, 122))) { return false; } break; } slice_del(); B_ending_removed = true; return true; } private boolean r_other_endings() { int among_var; if (cursor < I_p2) { return false; } int v_2 = limit_backward; limit_backward = I_p2; ket = cursor; among_var = find_among_b(a_7); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: { int v_3 = limit - cursor; lab0: { if (!(eq_s_b("po"))) { break lab0; } return false; } cursor = limit - v_3; } break; } slice_del(); return true; } private boolean r_i_plural() { if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; if (find_among_b(a_8) == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; slice_del(); return true; } private boolean r_t_plural() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; if (!(eq_s_b("t"))) { limit_backward = v_2; return false; } bra = cursor; int v_3 = limit - cursor; if (!(in_grouping_b(g_V1, 97, 246))) { limit_backward = v_2; return false; } cursor = limit - v_3; slice_del(); limit_backward = v_2; if (cursor < I_p2) { return false; } int v_5 = limit_backward; limit_backward = I_p2; ket = cursor; among_var = find_among_b(a_9); if (among_var == 0) { limit_backward = v_5; return false; } bra = cursor; limit_backward = v_5; switch (among_var) { case 1: { int v_6 = limit - cursor; lab0: { if (!(eq_s_b("po"))) { break lab0; } return false; } cursor = limit - v_6; } break; } slice_del(); return true; } private boolean r_tidy() { if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; int v_3 = limit - cursor; lab0: { int v_4 = limit - cursor; if (!r_LONG()) { break lab0; } cursor = limit - v_4; ket = cursor; if (cursor <= limit_backward) { break lab0; } cursor--; bra = cursor; slice_del(); } cursor = limit - v_3; int v_5 = limit - cursor; lab1: { ket = cursor; if (!(in_grouping_b(g_AEI, 97, 228))) { break lab1; } bra = cursor; if (!(in_grouping_b(g_C, 98, 122))) { break lab1; } slice_del(); } cursor = limit - v_5; int v_6 = limit - cursor; lab2: { ket = cursor; if (!(eq_s_b("j"))) { break lab2; } bra = cursor; lab3: { int v_7 = limit - cursor; lab4: { if (!(eq_s_b("o"))) { break lab4; } break lab3; } cursor = limit - v_7; if (!(eq_s_b("u"))) { break lab2; } } slice_del(); } cursor = limit - v_6; int v_8 = limit - cursor; lab5: { ket = cursor; if (!(eq_s_b("o"))) { break lab5; } bra = cursor; if (!(eq_s_b("j"))) { break lab5; } slice_del(); } cursor = limit - v_8; limit_backward = v_2; golab6: while (true) { int v_9 = limit - cursor; lab7: { if (!(out_grouping_b(g_V1, 97, 246))) { break lab7; } cursor = limit - v_9; break golab6; } cursor = limit - v_9; if (cursor <= limit_backward) { return false; } cursor--; } ket = cursor; if (!(in_grouping_b(g_C, 98, 122))) { return false; } bra = cursor; slice_to(S_x); if (!(eq_s_b(S_x))) { return false; } slice_del(); return true; } @Override public boolean stem() { int v_1 = cursor; r_mark_regions(); cursor = v_1; B_ending_removed = false; limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_particle_etc(); cursor = limit - v_2; int v_3 = limit - cursor; r_possessive(); cursor = limit - v_3; int v_4 = limit - cursor; r_case_ending(); cursor = limit - v_4; int v_5 = limit - cursor; r_other_endings(); cursor = limit - v_5; lab0: { lab1: { if (!(B_ending_removed)) { break lab1; } int v_7 = limit - cursor; r_i_plural(); cursor = limit - v_7; break lab0; } int v_8 = limit - cursor; r_t_plural(); cursor = limit - v_8; } int v_9 = limit - cursor; r_tidy(); cursor = limit - v_9; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof finnishStemmer; } @Override public int hashCode() { return finnishStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000161 15217274217 032614 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/frenchStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/frenchStemmer.j0100644 0000000 0000000 00000064340 15217274217 034170 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class frenchStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("col", -1, -1), new Among("par", -1, -1), new Among("tap", -1, -1) }; private final static Among[] a_1 = { new Among("", -1, 7), new Among("H", 0, 6), new Among("He", 1, 4), new Among("Hi", 1, 5), new Among("I", 0, 1), new Among("U", 0, 2), new Among("Y", 0, 3) }; private final static Among[] a_2 = { new Among("iqU", -1, 3), new Among("abl", -1, 3), new Among("I\u00E8r", -1, 4), new Among("i\u00E8r", -1, 4), new Among("eus", -1, 2), new Among("iv", -1, 1) }; private final static Among[] a_3 = { new Among("ic", -1, 2), new Among("abil", -1, 1), new Among("iv", -1, 3) }; private final static Among[] a_4 = { new Among("iqUe", -1, 1), new Among("atrice", -1, 2), new Among("ance", -1, 1), new Among("ence", -1, 5), new Among("logie", -1, 3), new Among("able", -1, 1), new Among("isme", -1, 1), new Among("euse", -1, 11), new Among("iste", -1, 1), new Among("ive", -1, 8), new Among("if", -1, 8), new Among("usion", -1, 4), new Among("ation", -1, 2), new Among("ution", -1, 4), new Among("ateur", -1, 2), new Among("iqUes", -1, 1), new Among("atrices", -1, 2), new Among("ances", -1, 1), new Among("ences", -1, 5), new Among("logies", -1, 3), new Among("ables", -1, 1), new Among("ismes", -1, 1), new Among("euses", -1, 11), new Among("istes", -1, 1), new Among("ives", -1, 8), new Among("ifs", -1, 8), new Among("usions", -1, 4), new Among("ations", -1, 2), new Among("utions", -1, 4), new Among("ateurs", -1, 2), new Among("ments", -1, 15), new Among("ements", 30, 6), new Among("issements", 31, 12), new Among("it\u00E9s", -1, 7), new Among("ment", -1, 15), new Among("ement", 34, 6), new Among("issement", 35, 12), new Among("amment", 34, 13), new Among("emment", 34, 14), new Among("aux", -1, 10), new Among("eaux", 39, 9), new Among("eux", -1, 1), new Among("it\u00E9", -1, 7) }; private final static Among[] a_5 = { new Among("ira", -1, 1), new Among("ie", -1, 1), new Among("isse", -1, 1), new Among("issante", -1, 1), new Among("i", -1, 1), new Among("irai", 4, 1), new Among("ir", -1, 1), new Among("iras", -1, 1), new Among("ies", -1, 1), new Among("\u00EEmes", -1, 1), new Among("isses", -1, 1), new Among("issantes", -1, 1), new Among("\u00EEtes", -1, 1), new Among("is", -1, 1), new Among("irais", 13, 1), new Among("issais", 13, 1), new Among("irions", -1, 1), new Among("issions", -1, 1), new Among("irons", -1, 1), new Among("issons", -1, 1), new Among("issants", -1, 1), new Among("it", -1, 1), new Among("irait", 21, 1), new Among("issait", 21, 1), new Among("issant", -1, 1), new Among("iraIent", -1, 1), new Among("issaIent", -1, 1), new Among("irent", -1, 1), new Among("issent", -1, 1), new Among("iront", -1, 1), new Among("\u00EEt", -1, 1), new Among("iriez", -1, 1), new Among("issiez", -1, 1), new Among("irez", -1, 1), new Among("issez", -1, 1) }; private final static Among[] a_6 = { new Among("a", -1, 3), new Among("era", 0, 2), new Among("asse", -1, 3), new Among("ante", -1, 3), new Among("\u00E9e", -1, 2), new Among("ai", -1, 3), new Among("erai", 5, 2), new Among("er", -1, 2), new Among("as", -1, 3), new Among("eras", 8, 2), new Among("\u00E2mes", -1, 3), new Among("asses", -1, 3), new Among("antes", -1, 3), new Among("\u00E2tes", -1, 3), new Among("\u00E9es", -1, 2), new Among("ais", -1, 3), new Among("erais", 15, 2), new Among("ions", -1, 1), new Among("erions", 17, 2), new Among("assions", 17, 3), new Among("erons", -1, 2), new Among("ants", -1, 3), new Among("\u00E9s", -1, 2), new Among("ait", -1, 3), new Among("erait", 23, 2), new Among("ant", -1, 3), new Among("aIent", -1, 3), new Among("eraIent", 26, 2), new Among("\u00E8rent", -1, 2), new Among("assent", -1, 3), new Among("eront", -1, 2), new Among("\u00E2t", -1, 3), new Among("ez", -1, 2), new Among("iez", 32, 2), new Among("eriez", 33, 2), new Among("assiez", 33, 3), new Among("erez", 32, 2), new Among("\u00E9", -1, 2) }; private final static Among[] a_7 = { new Among("e", -1, 3), new Among("I\u00E8re", 0, 2), new Among("i\u00E8re", 0, 2), new Among("ion", -1, 1), new Among("Ier", -1, 2), new Among("ier", -1, 2) }; private final static Among[] a_8 = { new Among("ell", -1, -1), new Among("eill", -1, -1), new Among("enn", -1, -1), new Among("onn", -1, -1), new Among("ett", -1, -1) }; private static final char[] g_v = {17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 130, 103, 8, 5}; private static final char[] g_keep_with_s = {1, 65, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128}; private int I_p2; private int I_p1; private int I_pV; private boolean r_prelude() { while (true) { int v_1 = cursor; lab0: { golab1: while (true) { int v_2 = cursor; lab2: { lab3: { int v_3 = cursor; lab4: { if (!(in_grouping(g_v, 97, 251))) { break lab4; } bra = cursor; lab5: { int v_4 = cursor; lab6: { if (!(eq_s("u"))) { break lab6; } ket = cursor; if (!(in_grouping(g_v, 97, 251))) { break lab6; } slice_from("U"); break lab5; } cursor = v_4; lab7: { if (!(eq_s("i"))) { break lab7; } ket = cursor; if (!(in_grouping(g_v, 97, 251))) { break lab7; } slice_from("I"); break lab5; } cursor = v_4; if (!(eq_s("y"))) { break lab4; } ket = cursor; slice_from("Y"); } break lab3; } cursor = v_3; lab8: { bra = cursor; if (!(eq_s("\u00EB"))) { break lab8; } ket = cursor; slice_from("He"); break lab3; } cursor = v_3; lab9: { bra = cursor; if (!(eq_s("\u00EF"))) { break lab9; } ket = cursor; slice_from("Hi"); break lab3; } cursor = v_3; lab10: { bra = cursor; if (!(eq_s("y"))) { break lab10; } ket = cursor; if (!(in_grouping(g_v, 97, 251))) { break lab10; } slice_from("Y"); break lab3; } cursor = v_3; if (!(eq_s("q"))) { break lab2; } bra = cursor; if (!(eq_s("u"))) { break lab2; } ket = cursor; slice_from("U"); } cursor = v_2; break golab1; } cursor = v_2; if (cursor >= limit) { break lab0; } cursor++; } continue; } cursor = v_1; break; } return true; } private boolean r_mark_regions() { I_pV = limit; I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { lab1: { int v_2 = cursor; lab2: { if (!(in_grouping(g_v, 97, 251))) { break lab2; } if (!(in_grouping(g_v, 97, 251))) { break lab2; } if (cursor >= limit) { break lab2; } cursor++; break lab1; } cursor = v_2; lab3: { if (find_among(a_0) == 0) { break lab3; } break lab1; } cursor = v_2; if (cursor >= limit) { break lab0; } cursor++; golab4: while (true) { lab5: { if (!(in_grouping(g_v, 97, 251))) { break lab5; } break golab4; } if (cursor >= limit) { break lab0; } cursor++; } } I_pV = cursor; } cursor = v_1; int v_4 = cursor; lab6: { golab7: while (true) { lab8: { if (!(in_grouping(g_v, 97, 251))) { break lab8; } break golab7; } if (cursor >= limit) { break lab6; } cursor++; } golab9: while (true) { lab10: { if (!(out_grouping(g_v, 97, 251))) { break lab10; } break golab9; } if (cursor >= limit) { break lab6; } cursor++; } I_p1 = cursor; golab11: while (true) { lab12: { if (!(in_grouping(g_v, 97, 251))) { break lab12; } break golab11; } if (cursor >= limit) { break lab6; } cursor++; } golab13: while (true) { lab14: { if (!(out_grouping(g_v, 97, 251))) { break lab14; } break golab13; } if (cursor >= limit) { break lab6; } cursor++; } I_p2 = cursor; } cursor = v_4; return true; } private boolean r_postlude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_1); ket = cursor; switch (among_var) { case 1: slice_from("i"); break; case 2: slice_from("u"); break; case 3: slice_from("y"); break; case 4: slice_from("\u00EB"); break; case 5: slice_from("\u00EF"); break; case 6: slice_del(); break; case 7: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_RV() { return I_pV <= cursor; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_standard_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { return false; } slice_del(); break; case 2: if (!r_R2()) { return false; } slice_del(); int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("ic"))) { cursor = limit - v_1; break lab0; } bra = cursor; lab1: { int v_2 = limit - cursor; lab2: { if (!r_R2()) { break lab2; } slice_del(); break lab1; } cursor = limit - v_2; slice_from("iqU"); } } break; case 3: if (!r_R2()) { return false; } slice_from("log"); break; case 4: if (!r_R2()) { return false; } slice_from("u"); break; case 5: if (!r_R2()) { return false; } slice_from("ent"); break; case 6: if (!r_RV()) { return false; } slice_del(); int v_3 = limit - cursor; lab3: { ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { cursor = limit - v_3; break lab3; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { cursor = limit - v_3; break lab3; } slice_del(); ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_3; break lab3; } bra = cursor; if (!r_R2()) { cursor = limit - v_3; break lab3; } slice_del(); break; case 2: lab4: { int v_4 = limit - cursor; lab5: { if (!r_R2()) { break lab5; } slice_del(); break lab4; } cursor = limit - v_4; if (!r_R1()) { cursor = limit - v_3; break lab3; } slice_from("eux"); } break; case 3: if (!r_R2()) { cursor = limit - v_3; break lab3; } slice_del(); break; case 4: if (!r_RV()) { cursor = limit - v_3; break lab3; } slice_from("i"); break; } } break; case 7: if (!r_R2()) { return false; } slice_del(); int v_5 = limit - cursor; lab6: { ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { cursor = limit - v_5; break lab6; } bra = cursor; switch (among_var) { case 1: lab7: { int v_6 = limit - cursor; lab8: { if (!r_R2()) { break lab8; } slice_del(); break lab7; } cursor = limit - v_6; slice_from("abl"); } break; case 2: lab9: { int v_7 = limit - cursor; lab10: { if (!r_R2()) { break lab10; } slice_del(); break lab9; } cursor = limit - v_7; slice_from("iqU"); } break; case 3: if (!r_R2()) { cursor = limit - v_5; break lab6; } slice_del(); break; } } break; case 8: if (!r_R2()) { return false; } slice_del(); int v_8 = limit - cursor; lab11: { ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_8; break lab11; } bra = cursor; if (!r_R2()) { cursor = limit - v_8; break lab11; } slice_del(); ket = cursor; if (!(eq_s_b("ic"))) { cursor = limit - v_8; break lab11; } bra = cursor; lab12: { int v_9 = limit - cursor; lab13: { if (!r_R2()) { break lab13; } slice_del(); break lab12; } cursor = limit - v_9; slice_from("iqU"); } } break; case 9: slice_from("eau"); break; case 10: if (!r_R1()) { return false; } slice_from("al"); break; case 11: lab14: { int v_10 = limit - cursor; lab15: { if (!r_R2()) { break lab15; } slice_del(); break lab14; } cursor = limit - v_10; if (!r_R1()) { return false; } slice_from("eux"); } break; case 12: if (!r_R1()) { return false; } if (!(out_grouping_b(g_v, 97, 251))) { return false; } slice_del(); break; case 13: if (!r_RV()) { return false; } slice_from("ant"); return false; case 14: if (!r_RV()) { return false; } slice_from("ent"); return false; case 15: int v_11 = limit - cursor; if (!(in_grouping_b(g_v, 97, 251))) { return false; } if (!r_RV()) { return false; } cursor = limit - v_11; slice_del(); return false; } return true; } private boolean r_i_verb_suffix() { if (cursor < I_pV) { return false; } int v_2 = limit_backward; limit_backward = I_pV; ket = cursor; if (find_among_b(a_5) == 0) { limit_backward = v_2; return false; } bra = cursor; { int v_3 = limit - cursor; lab0: { if (!(eq_s_b("H"))) { break lab0; } limit_backward = v_2; return false; } cursor = limit - v_3; } if (!(out_grouping_b(g_v, 97, 251))) { limit_backward = v_2; return false; } slice_del(); limit_backward = v_2; return true; } private boolean r_verb_suffix() { int among_var; if (cursor < I_pV) { return false; } int v_2 = limit_backward; limit_backward = I_pV; ket = cursor; among_var = find_among_b(a_6); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { limit_backward = v_2; return false; } slice_del(); break; case 2: slice_del(); break; case 3: slice_del(); int v_3 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("e"))) { cursor = limit - v_3; break lab0; } bra = cursor; slice_del(); } break; } limit_backward = v_2; return true; } private boolean r_residual_suffix() { int among_var; int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("s"))) { cursor = limit - v_1; break lab0; } bra = cursor; int v_2 = limit - cursor; lab1: { int v_3 = limit - cursor; lab2: { if (!(eq_s_b("Hi"))) { break lab2; } break lab1; } cursor = limit - v_3; if (!(out_grouping_b(g_keep_with_s, 97, 232))) { cursor = limit - v_1; break lab0; } } cursor = limit - v_2; slice_del(); } if (cursor < I_pV) { return false; } int v_5 = limit_backward; limit_backward = I_pV; ket = cursor; among_var = find_among_b(a_7); if (among_var == 0) { limit_backward = v_5; return false; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { limit_backward = v_5; return false; } lab3: { int v_6 = limit - cursor; lab4: { if (!(eq_s_b("s"))) { break lab4; } break lab3; } cursor = limit - v_6; if (!(eq_s_b("t"))) { limit_backward = v_5; return false; } } slice_del(); break; case 2: slice_from("i"); break; case 3: slice_del(); break; } limit_backward = v_5; return true; } private boolean r_un_double() { int v_1 = limit - cursor; if (find_among_b(a_8) == 0) { return false; } cursor = limit - v_1; ket = cursor; if (cursor <= limit_backward) { return false; } cursor--; bra = cursor; slice_del(); return true; } private boolean r_un_accent() { { int v_1 = 1; while (true) { lab0: { if (!(out_grouping_b(g_v, 97, 251))) { break lab0; } v_1--; continue; } break; } if (v_1 > 0) { return false; } } ket = cursor; lab1: { int v_3 = limit - cursor; lab2: { if (!(eq_s_b("\u00E9"))) { break lab2; } break lab1; } cursor = limit - v_3; if (!(eq_s_b("\u00E8"))) { return false; } } bra = cursor; slice_from("e"); return true; } @Override public boolean stem() { int v_1 = cursor; r_prelude(); cursor = v_1; r_mark_regions(); limit_backward = cursor; cursor = limit; int v_3 = limit - cursor; lab0: { lab1: { int v_4 = limit - cursor; lab2: { int v_5 = limit - cursor; lab3: { int v_6 = limit - cursor; lab4: { if (!r_standard_suffix()) { break lab4; } break lab3; } cursor = limit - v_6; lab5: { if (!r_i_verb_suffix()) { break lab5; } break lab3; } cursor = limit - v_6; if (!r_verb_suffix()) { break lab2; } } cursor = limit - v_5; int v_7 = limit - cursor; lab6: { ket = cursor; lab7: { int v_8 = limit - cursor; lab8: { if (!(eq_s_b("Y"))) { break lab8; } bra = cursor; slice_from("i"); break lab7; } cursor = limit - v_8; if (!(eq_s_b("\u00E7"))) { cursor = limit - v_7; break lab6; } bra = cursor; slice_from("c"); } } break lab1; } cursor = limit - v_4; if (!r_residual_suffix()) { break lab0; } } } cursor = limit - v_3; int v_9 = limit - cursor; r_un_double(); cursor = limit - v_9; int v_10 = limit - cursor; r_un_accent(); cursor = limit - v_10; cursor = limit_backward; int v_11 = cursor; r_postlude(); cursor = v_11; return true; } @Override public boolean equals(Object o) { return o instanceof frenchStemmer; } @Override public int hashCode() { return frenchStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000161 15217274217 032614 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/germanStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/germanStemmer.j0100644 0000000 0000000 00000031167 15217274217 034175 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class germanStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("", -1, 5), new Among("ae", 0, 2), new Among("oe", 0, 3), new Among("qu", 0, -1), new Among("ue", 0, 4), new Among("\u00DF", 0, 1) }; private final static Among[] a_1 = { new Among("", -1, 5), new Among("U", 0, 2), new Among("Y", 0, 1), new Among("\u00E4", 0, 3), new Among("\u00F6", 0, 4), new Among("\u00FC", 0, 2) }; private final static Among[] a_2 = { new Among("e", -1, 3), new Among("em", -1, 1), new Among("en", -1, 3), new Among("erinnen", 2, 2), new Among("erin", -1, 2), new Among("ln", -1, 5), new Among("ern", -1, 2), new Among("er", -1, 2), new Among("s", -1, 4), new Among("es", 8, 3), new Among("lns", 8, 5) }; private final static Among[] a_3 = { new Among("en", -1, 1), new Among("er", -1, 1), new Among("st", -1, 2), new Among("est", 2, 1) }; private final static Among[] a_4 = { new Among("ig", -1, 1), new Among("lich", -1, 1) }; private final static Among[] a_5 = { new Among("end", -1, 1), new Among("ig", -1, 2), new Among("ung", -1, 1), new Among("lich", -1, 3), new Among("isch", -1, 2), new Among("ik", -1, 2), new Among("heit", -1, 3), new Among("keit", -1, 4) }; private static final char[] g_v = {17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 32, 8}; private static final char[] g_s_ending = {117, 30, 5}; private static final char[] g_st_ending = {117, 30, 4}; private int I_x; private int I_p2; private int I_p1; private boolean r_prelude() { int among_var; int v_1 = cursor; while (true) { int v_2 = cursor; lab0: { golab1: while (true) { int v_3 = cursor; lab2: { if (!(in_grouping(g_v, 97, 252))) { break lab2; } bra = cursor; lab3: { int v_4 = cursor; lab4: { if (!(eq_s("u"))) { break lab4; } ket = cursor; if (!(in_grouping(g_v, 97, 252))) { break lab4; } slice_from("U"); break lab3; } cursor = v_4; if (!(eq_s("y"))) { break lab2; } ket = cursor; if (!(in_grouping(g_v, 97, 252))) { break lab2; } slice_from("Y"); } cursor = v_3; break golab1; } cursor = v_3; if (cursor >= limit) { break lab0; } cursor++; } continue; } cursor = v_2; break; } cursor = v_1; while (true) { int v_5 = cursor; lab5: { bra = cursor; among_var = find_among(a_0); ket = cursor; switch (among_var) { case 1: slice_from("ss"); break; case 2: slice_from("\u00E4"); break; case 3: slice_from("\u00F6"); break; case 4: slice_from("\u00FC"); break; case 5: if (cursor >= limit) { break lab5; } cursor++; break; } continue; } cursor = v_5; break; } return true; } private boolean r_mark_regions() { I_p1 = limit; I_p2 = limit; int v_1 = cursor; { int c = cursor + 3; if (c > limit) { return false; } cursor = c; } I_x = cursor; cursor = v_1; golab0: while (true) { lab1: { if (!(in_grouping(g_v, 97, 252))) { break lab1; } break golab0; } if (cursor >= limit) { return false; } cursor++; } golab2: while (true) { lab3: { if (!(out_grouping(g_v, 97, 252))) { break lab3; } break golab2; } if (cursor >= limit) { return false; } cursor++; } I_p1 = cursor; lab4: { if (I_p1 >= I_x) { break lab4; } I_p1 = I_x; } golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 252))) { break lab6; } break golab5; } if (cursor >= limit) { return false; } cursor++; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 252))) { break lab8; } break golab7; } if (cursor >= limit) { return false; } cursor++; } I_p2 = cursor; return true; } private boolean r_postlude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_1); ket = cursor; switch (among_var) { case 1: slice_from("y"); break; case 2: slice_from("u"); break; case 3: slice_from("a"); break; case 4: slice_from("o"); break; case 5: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_standard_suffix() { int among_var; int v_1 = limit - cursor; lab0: { ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { break lab0; } bra = cursor; if (!r_R1()) { break lab0; } switch (among_var) { case 1: { int v_2 = limit - cursor; lab1: { if (!(eq_s_b("syst"))) { break lab1; } break lab0; } cursor = limit - v_2; } slice_del(); break; case 2: slice_del(); break; case 3: slice_del(); int v_3 = limit - cursor; lab2: { ket = cursor; if (!(eq_s_b("s"))) { cursor = limit - v_3; break lab2; } bra = cursor; if (!(eq_s_b("nis"))) { cursor = limit - v_3; break lab2; } slice_del(); } break; case 4: if (!(in_grouping_b(g_s_ending, 98, 116))) { break lab0; } slice_del(); break; case 5: slice_from("l"); break; } } cursor = limit - v_1; int v_4 = limit - cursor; lab3: { ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { break lab3; } bra = cursor; if (!r_R1()) { break lab3; } switch (among_var) { case 1: slice_del(); break; case 2: if (!(in_grouping_b(g_st_ending, 98, 116))) { break lab3; } { int c = cursor - 3; if (c < limit_backward) { break lab3; } cursor = c; } slice_del(); break; } } cursor = limit - v_4; int v_5 = limit - cursor; lab4: { ket = cursor; among_var = find_among_b(a_5); if (among_var == 0) { break lab4; } bra = cursor; if (!r_R2()) { break lab4; } switch (among_var) { case 1: slice_del(); int v_6 = limit - cursor; lab5: { ket = cursor; if (!(eq_s_b("ig"))) { cursor = limit - v_6; break lab5; } bra = cursor; { int v_7 = limit - cursor; lab6: { if (!(eq_s_b("e"))) { break lab6; } cursor = limit - v_6; break lab5; } cursor = limit - v_7; } if (!r_R2()) { cursor = limit - v_6; break lab5; } slice_del(); } break; case 2: { int v_8 = limit - cursor; lab7: { if (!(eq_s_b("e"))) { break lab7; } break lab4; } cursor = limit - v_8; } slice_del(); break; case 3: slice_del(); int v_9 = limit - cursor; lab8: { ket = cursor; lab9: { int v_10 = limit - cursor; lab10: { if (!(eq_s_b("er"))) { break lab10; } break lab9; } cursor = limit - v_10; if (!(eq_s_b("en"))) { cursor = limit - v_9; break lab8; } } bra = cursor; if (!r_R1()) { cursor = limit - v_9; break lab8; } slice_del(); } break; case 4: slice_del(); int v_11 = limit - cursor; lab11: { ket = cursor; if (find_among_b(a_4) == 0) { cursor = limit - v_11; break lab11; } bra = cursor; if (!r_R2()) { cursor = limit - v_11; break lab11; } slice_del(); } break; } } cursor = limit - v_5; return true; } @Override public boolean stem() { int v_1 = cursor; r_prelude(); cursor = v_1; int v_2 = cursor; r_mark_regions(); cursor = v_2; limit_backward = cursor; cursor = limit; r_standard_suffix(); cursor = limit_backward; int v_4 = cursor; r_postlude(); cursor = v_4; return true; } @Override public boolean equals(Object o) { return o instanceof germanStemmer; } @Override public int hashCode() { return germanStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000160 15217274217 032613 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/greekStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/greekStemmer.ja0100644 0000000 0000000 00000230610 15217274217 034154 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class greekStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("", -1, 25), new Among("\u0386", 0, 1), new Among("\u0388", 0, 5), new Among("\u0389", 0, 7), new Among("\u038A", 0, 9), new Among("\u038C", 0, 15), new Among("\u038E", 0, 20), new Among("\u038F", 0, 24), new Among("\u0390", 0, 7), new Among("\u0391", 0, 1), new Among("\u0392", 0, 2), new Among("\u0393", 0, 3), new Among("\u0394", 0, 4), new Among("\u0395", 0, 5), new Among("\u0396", 0, 6), new Among("\u0397", 0, 7), new Among("\u0398", 0, 8), new Among("\u0399", 0, 9), new Among("\u039A", 0, 10), new Among("\u039B", 0, 11), new Among("\u039C", 0, 12), new Among("\u039D", 0, 13), new Among("\u039E", 0, 14), new Among("\u039F", 0, 15), new Among("\u03A0", 0, 16), new Among("\u03A1", 0, 17), new Among("\u03A3", 0, 18), new Among("\u03A4", 0, 19), new Among("\u03A5", 0, 20), new Among("\u03A6", 0, 21), new Among("\u03A7", 0, 22), new Among("\u03A8", 0, 23), new Among("\u03A9", 0, 24), new Among("\u03AA", 0, 9), new Among("\u03AB", 0, 20), new Among("\u03AC", 0, 1), new Among("\u03AD", 0, 5), new Among("\u03AE", 0, 7), new Among("\u03AF", 0, 9), new Among("\u03B0", 0, 20), new Among("\u03C2", 0, 18), new Among("\u03CA", 0, 7), new Among("\u03CB", 0, 20), new Among("\u03CC", 0, 15), new Among("\u03CD", 0, 20), new Among("\u03CE", 0, 24) }; private final static Among[] a_1 = { new Among("\u03C3\u03BA\u03B1\u03B3\u03B9\u03B1", -1, 2), new Among("\u03C6\u03B1\u03B3\u03B9\u03B1", -1, 1), new Among("\u03BF\u03BB\u03BF\u03B3\u03B9\u03B1", -1, 3), new Among("\u03C3\u03BF\u03B3\u03B9\u03B1", -1, 4), new Among("\u03C4\u03B1\u03C4\u03BF\u03B3\u03B9\u03B1", -1, 5), new Among("\u03BA\u03C1\u03B5\u03B1\u03C4\u03B1", -1, 6), new Among("\u03C0\u03B5\u03C1\u03B1\u03C4\u03B1", -1, 7), new Among("\u03C4\u03B5\u03C1\u03B1\u03C4\u03B1", -1, 8), new Among("\u03B3\u03B5\u03B3\u03BF\u03BD\u03BF\u03C4\u03B1", -1, 11), new Among("\u03BA\u03B1\u03B8\u03B5\u03C3\u03C4\u03C9\u03C4\u03B1", -1, 10), new Among("\u03C6\u03C9\u03C4\u03B1", -1, 9), new Among("\u03C0\u03B5\u03C1\u03B1\u03C4\u03B7", -1, 7), new Among("\u03C3\u03BA\u03B1\u03B3\u03B9\u03C9\u03BD", -1, 2), new Among("\u03C6\u03B1\u03B3\u03B9\u03C9\u03BD", -1, 1), new Among("\u03BF\u03BB\u03BF\u03B3\u03B9\u03C9\u03BD", -1, 3), new Among("\u03C3\u03BF\u03B3\u03B9\u03C9\u03BD", -1, 4), new Among("\u03C4\u03B1\u03C4\u03BF\u03B3\u03B9\u03C9\u03BD", -1, 5), new Among("\u03BA\u03C1\u03B5\u03B1\u03C4\u03C9\u03BD", -1, 6), new Among("\u03C0\u03B5\u03C1\u03B1\u03C4\u03C9\u03BD", -1, 7), new Among("\u03C4\u03B5\u03C1\u03B1\u03C4\u03C9\u03BD", -1, 8), new Among("\u03B3\u03B5\u03B3\u03BF\u03BD\u03BF\u03C4\u03C9\u03BD", -1, 11), new Among("\u03BA\u03B1\u03B8\u03B5\u03C3\u03C4\u03C9\u03C4\u03C9\u03BD", -1, 10), new Among("\u03C6\u03C9\u03C4\u03C9\u03BD", -1, 9), new Among("\u03BA\u03C1\u03B5\u03B1\u03C3", -1, 6), new Among("\u03C0\u03B5\u03C1\u03B1\u03C3", -1, 7), new Among("\u03C4\u03B5\u03C1\u03B1\u03C3", -1, 8), new Among("\u03B3\u03B5\u03B3\u03BF\u03BD\u03BF\u03C3", -1, 11), new Among("\u03BA\u03C1\u03B5\u03B1\u03C4\u03BF\u03C3", -1, 6), new Among("\u03C0\u03B5\u03C1\u03B1\u03C4\u03BF\u03C3", -1, 7), new Among("\u03C4\u03B5\u03C1\u03B1\u03C4\u03BF\u03C3", -1, 8), new Among("\u03B3\u03B5\u03B3\u03BF\u03BD\u03BF\u03C4\u03BF\u03C3", -1, 11), new Among("\u03BA\u03B1\u03B8\u03B5\u03C3\u03C4\u03C9\u03C4\u03BF\u03C3", -1, 10), new Among("\u03C6\u03C9\u03C4\u03BF\u03C3", -1, 9), new Among("\u03BA\u03B1\u03B8\u03B5\u03C3\u03C4\u03C9\u03C3", -1, 10), new Among("\u03C6\u03C9\u03C3", -1, 9), new Among("\u03C3\u03BA\u03B1\u03B3\u03B9\u03BF\u03C5", -1, 2), new Among("\u03C6\u03B1\u03B3\u03B9\u03BF\u03C5", -1, 1), new Among("\u03BF\u03BB\u03BF\u03B3\u03B9\u03BF\u03C5", -1, 3), new Among("\u03C3\u03BF\u03B3\u03B9\u03BF\u03C5", -1, 4), new Among("\u03C4\u03B1\u03C4\u03BF\u03B3\u03B9\u03BF\u03C5", -1, 5) }; private final static Among[] a_2 = { new Among("\u03C0\u03B1", -1, 1), new Among("\u03BE\u03B1\u03BD\u03B1\u03C0\u03B1", 0, 1), new Among("\u03B5\u03C0\u03B1", 0, 1), new Among("\u03C0\u03B5\u03C1\u03B9\u03C0\u03B1", 0, 1), new Among("\u03B1\u03BD\u03B1\u03BC\u03C0\u03B1", 0, 1), new Among("\u03B5\u03BC\u03C0\u03B1", 0, 1), new Among("\u03B2", -1, 2), new Among("\u03B4\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B2\u03B1\u03B8\u03C5\u03C1\u03B9", -1, 2), new Among("\u03B2\u03B1\u03C1\u03BA", -1, 2), new Among("\u03BC\u03B1\u03C1\u03BA", -1, 2), new Among("\u03BB", -1, 2), new Among("\u03BC", -1, 2), new Among("\u03BA\u03BF\u03C1\u03BD", -1, 2), new Among("\u03B1\u03B8\u03C1\u03BF", -1, 1), new Among("\u03C3\u03C5\u03BD\u03B1\u03B8\u03C1\u03BF", 14, 1), new Among("\u03C0", -1, 2), new Among("\u03B9\u03BC\u03C0", 16, 2), new Among("\u03C1", -1, 2), new Among("\u03BC\u03B1\u03C1", 18, 2), new Among("\u03B1\u03BC\u03C0\u03B1\u03C1", 18, 2), new Among("\u03B3\u03BA\u03C1", 18, 2), new Among("\u03B2\u03BF\u03BB\u03B2\u03BF\u03C1", 18, 2), new Among("\u03B3\u03BB\u03C5\u03BA\u03BF\u03C1", 18, 2), new Among("\u03C0\u03B9\u03C0\u03B5\u03C1\u03BF\u03C1", 18, 2), new Among("\u03C0\u03C1", 18, 2), new Among("\u03BC\u03C0\u03C1", 25, 2), new Among("\u03B1\u03C1\u03C1", 18, 2), new Among("\u03B3\u03BB\u03C5\u03BA\u03C5\u03C1", 18, 2), new Among("\u03C0\u03BF\u03BB\u03C5\u03C1", 18, 2), new Among("\u03BB\u03BF\u03C5", -1, 2) }; private final static Among[] a_3 = { new Among("\u03B9\u03B6\u03B1", -1, 1), new Among("\u03B9\u03B6\u03B5", -1, 1), new Among("\u03B9\u03B6\u03B1\u03BC\u03B5", -1, 1), new Among("\u03B9\u03B6\u03BF\u03C5\u03BC\u03B5", -1, 1), new Among("\u03B9\u03B6\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B9\u03B6\u03BF\u03C5\u03BD\u03B5", -1, 1), new Among("\u03B9\u03B6\u03B1\u03C4\u03B5", -1, 1), new Among("\u03B9\u03B6\u03B5\u03C4\u03B5", -1, 1), new Among("\u03B9\u03B6\u03B5\u03B9", -1, 1), new Among("\u03B9\u03B6\u03B1\u03BD", -1, 1), new Among("\u03B9\u03B6\u03BF\u03C5\u03BD", -1, 1), new Among("\u03B9\u03B6\u03B5\u03C3", -1, 1), new Among("\u03B9\u03B6\u03B5\u03B9\u03C3", -1, 1), new Among("\u03B9\u03B6\u03C9", -1, 1) }; private final static Among[] a_4 = { new Among("\u03B2\u03B9", -1, 1), new Among("\u03BB\u03B9", -1, 1), new Among("\u03B1\u03BB", -1, 1), new Among("\u03B5\u03BD", -1, 1), new Among("\u03C3", -1, 1), new Among("\u03C7", -1, 1), new Among("\u03C5\u03C8", -1, 1), new Among("\u03B6\u03C9", -1, 1) }; private final static Among[] a_5 = { new Among("\u03C9\u03B8\u03B7\u03BA\u03B1", -1, 1), new Among("\u03C9\u03B8\u03B7\u03BA\u03B5", -1, 1), new Among("\u03C9\u03B8\u03B7\u03BA\u03B1\u03BC\u03B5", -1, 1), new Among("\u03C9\u03B8\u03B7\u03BA\u03B1\u03BD\u03B5", -1, 1), new Among("\u03C9\u03B8\u03B7\u03BA\u03B1\u03C4\u03B5", -1, 1), new Among("\u03C9\u03B8\u03B7\u03BA\u03B1\u03BD", -1, 1), new Among("\u03C9\u03B8\u03B7\u03BA\u03B5\u03C3", -1, 1) }; private final static Among[] a_6 = { new Among("\u03BE\u03B1\u03BD\u03B1\u03C0\u03B1", -1, 1), new Among("\u03B5\u03C0\u03B1", -1, 1), new Among("\u03C0\u03B5\u03C1\u03B9\u03C0\u03B1", -1, 1), new Among("\u03B1\u03BD\u03B1\u03BC\u03C0\u03B1", -1, 1), new Among("\u03B5\u03BC\u03C0\u03B1", -1, 1), new Among("\u03C7\u03B1\u03C1\u03C4\u03BF\u03C0\u03B1", -1, 1), new Among("\u03B5\u03BE\u03B1\u03C1\u03C7\u03B1", -1, 1), new Among("\u03B3\u03B5", -1, 2), new Among("\u03B3\u03BA\u03B5", -1, 2), new Among("\u03BA\u03BB\u03B5", -1, 1), new Among("\u03B5\u03BA\u03BB\u03B5", 9, 1), new Among("\u03B1\u03C0\u03B5\u03BA\u03BB\u03B5", 10, 1), new Among("\u03B1\u03C0\u03BF\u03BA\u03BB\u03B5", 9, 1), new Among("\u03B5\u03C3\u03C9\u03BA\u03BB\u03B5", 9, 1), new Among("\u03B4\u03B1\u03BD\u03B5", -1, 1), new Among("\u03C0\u03B5", -1, 1), new Among("\u03B5\u03C0\u03B5", 15, 1), new Among("\u03BC\u03B5\u03C4\u03B5\u03C0\u03B5", 16, 1), new Among("\u03B5\u03C3\u03B5", -1, 1), new Among("\u03B3\u03BA", -1, 2), new Among("\u03BC", -1, 2), new Among("\u03C0\u03BF\u03C5\u03BA\u03B1\u03BC", 20, 2), new Among("\u03BA\u03BF\u03BC", 20, 2), new Among("\u03B1\u03BD", -1, 2), new Among("\u03BF\u03BB\u03BF", -1, 2), new Among("\u03B1\u03B8\u03C1\u03BF", -1, 1), new Among("\u03C3\u03C5\u03BD\u03B1\u03B8\u03C1\u03BF", 25, 1), new Among("\u03C0", -1, 2), new Among("\u03BB\u03B1\u03C1", -1, 2), new Among("\u03B4\u03B7\u03BC\u03BF\u03BA\u03C1\u03B1\u03C4", -1, 2), new Among("\u03B1\u03C6", -1, 2), new Among("\u03B3\u03B9\u03B3\u03B1\u03BD\u03C4\u03BF\u03B1\u03C6", 30, 2) }; private final static Among[] a_7 = { new Among("\u03B9\u03C3\u03B1", -1, 1), new Among("\u03B9\u03C3\u03B1\u03BC\u03B5", -1, 1), new Among("\u03B9\u03C3\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B9\u03C3\u03B5", -1, 1), new Among("\u03B9\u03C3\u03B1\u03C4\u03B5", -1, 1), new Among("\u03B9\u03C3\u03B1\u03BD", -1, 1), new Among("\u03B9\u03C3\u03B5\u03C3", -1, 1) }; private final static Among[] a_8 = { new Among("\u03BE\u03B1\u03BD\u03B1\u03C0\u03B1", -1, 1), new Among("\u03B5\u03C0\u03B1", -1, 1), new Among("\u03C0\u03B5\u03C1\u03B9\u03C0\u03B1", -1, 1), new Among("\u03B1\u03BD\u03B1\u03BC\u03C0\u03B1", -1, 1), new Among("\u03B5\u03BC\u03C0\u03B1", -1, 1), new Among("\u03C7\u03B1\u03C1\u03C4\u03BF\u03C0\u03B1", -1, 1), new Among("\u03B5\u03BE\u03B1\u03C1\u03C7\u03B1", -1, 1), new Among("\u03BA\u03BB\u03B5", -1, 1), new Among("\u03B5\u03BA\u03BB\u03B5", 7, 1), new Among("\u03B1\u03C0\u03B5\u03BA\u03BB\u03B5", 8, 1), new Among("\u03B1\u03C0\u03BF\u03BA\u03BB\u03B5", 7, 1), new Among("\u03B5\u03C3\u03C9\u03BA\u03BB\u03B5", 7, 1), new Among("\u03B4\u03B1\u03BD\u03B5", -1, 1), new Among("\u03C0\u03B5", -1, 1), new Among("\u03B5\u03C0\u03B5", 13, 1), new Among("\u03BC\u03B5\u03C4\u03B5\u03C0\u03B5", 14, 1), new Among("\u03B5\u03C3\u03B5", -1, 1), new Among("\u03B1\u03B8\u03C1\u03BF", -1, 1), new Among("\u03C3\u03C5\u03BD\u03B1\u03B8\u03C1\u03BF", 17, 1) }; private final static Among[] a_9 = { new Among("\u03B9\u03C3\u03BF\u03C5\u03BC\u03B5", -1, 1), new Among("\u03B9\u03C3\u03BF\u03C5\u03BD\u03B5", -1, 1), new Among("\u03B9\u03C3\u03B5\u03C4\u03B5", -1, 1), new Among("\u03B9\u03C3\u03B5\u03B9", -1, 1), new Among("\u03B9\u03C3\u03BF\u03C5\u03BD", -1, 1), new Among("\u03B9\u03C3\u03B5\u03B9\u03C3", -1, 1), new Among("\u03B9\u03C3\u03C9", -1, 1) }; private final static Among[] a_10 = { new Among("\u03B1\u03C4\u03B1", -1, 2), new Among("\u03C6\u03B1", -1, 2), new Among("\u03B7\u03C6\u03B1", 1, 2), new Among("\u03BC\u03B5\u03B3", -1, 2), new Among("\u03BB\u03C5\u03B3", -1, 2), new Among("\u03B7\u03B4", -1, 2), new Among("\u03BA\u03BB\u03B5", -1, 1), new Among("\u03B5\u03C3\u03C9\u03BA\u03BB\u03B5", 6, 1), new Among("\u03C0\u03BB\u03B5", -1, 1), new Among("\u03B4\u03B1\u03BD\u03B5", -1, 1), new Among("\u03C3\u03B5", -1, 1), new Among("\u03B1\u03C3\u03B5", 10, 1), new Among("\u03BA\u03B1\u03B8", -1, 2), new Among("\u03B5\u03C7\u03B8", -1, 2), new Among("\u03BA\u03B1\u03BA", -1, 2), new Among("\u03BC\u03B1\u03BA", -1, 2), new Among("\u03C3\u03BA", -1, 2), new Among("\u03C6\u03B9\u03BB", -1, 2), new Among("\u03BA\u03C5\u03BB", -1, 2), new Among("\u03BC", -1, 2), new Among("\u03B3\u03B5\u03BC", 19, 2), new Among("\u03B1\u03C7\u03BD", -1, 2), new Among("\u03C3\u03C5\u03BD\u03B1\u03B8\u03C1\u03BF", -1, 1), new Among("\u03C0", -1, 2), new Among("\u03B1\u03C0", 23, 2), new Among("\u03B5\u03BC\u03C0", 23, 2), new Among("\u03B5\u03C5\u03C0", 23, 2), new Among("\u03B1\u03C1", -1, 2), new Among("\u03B1\u03BF\u03C1", -1, 2), new Among("\u03B3\u03C5\u03C1", -1, 2), new Among("\u03C7\u03C1", -1, 2), new Among("\u03C7\u03C9\u03C1", -1, 2), new Among("\u03BA\u03C4", -1, 2), new Among("\u03B1\u03BA\u03C4", 32, 2), new Among("\u03C7\u03C4", -1, 2), new Among("\u03B1\u03C7\u03C4", 34, 2), new Among("\u03C4\u03B1\u03C7", -1, 2), new Among("\u03C3\u03C7", -1, 2), new Among("\u03B1\u03C3\u03C7", 37, 2), new Among("\u03C5\u03C8", -1, 2) }; private final static Among[] a_11 = { new Among("\u03B9\u03C3\u03C4\u03B1", -1, 1), new Among("\u03B9\u03C3\u03C4\u03B5", -1, 1), new Among("\u03B9\u03C3\u03C4\u03B7", -1, 1), new Among("\u03B9\u03C3\u03C4\u03BF\u03B9", -1, 1), new Among("\u03B9\u03C3\u03C4\u03C9\u03BD", -1, 1), new Among("\u03B9\u03C3\u03C4\u03BF", -1, 1), new Among("\u03B9\u03C3\u03C4\u03B5\u03C3", -1, 1), new Among("\u03B9\u03C3\u03C4\u03B7\u03C3", -1, 1), new Among("\u03B9\u03C3\u03C4\u03BF\u03C3", -1, 1), new Among("\u03B9\u03C3\u03C4\u03BF\u03C5\u03C3", -1, 1), new Among("\u03B9\u03C3\u03C4\u03BF\u03C5", -1, 1) }; private final static Among[] a_12 = { new Among("\u03B5\u03B3\u03BA\u03BB\u03B5", -1, 1), new Among("\u03B1\u03C0\u03BF\u03BA\u03BB\u03B5", -1, 1), new Among("\u03B4\u03B1\u03BD\u03B5", -1, 2), new Among("\u03B1\u03BD\u03C4\u03B9\u03B4\u03B1\u03BD\u03B5", 2, 2), new Among("\u03C3\u03B5", -1, 1), new Among("\u03BC\u03B5\u03C4\u03B1\u03C3\u03B5", 4, 1), new Among("\u03BC\u03B9\u03BA\u03C1\u03BF\u03C3\u03B5", 4, 1) }; private final static Among[] a_13 = { new Among("\u03B1\u03C4\u03BF\u03BC\u03B9\u03BA", -1, 2), new Among("\u03B5\u03B8\u03BD\u03B9\u03BA", -1, 4), new Among("\u03C4\u03BF\u03C0\u03B9\u03BA", -1, 7), new Among("\u03B5\u03BA\u03BB\u03B5\u03BA\u03C4\u03B9\u03BA", -1, 5), new Among("\u03C3\u03BA\u03B5\u03C0\u03C4\u03B9\u03BA", -1, 6), new Among("\u03B3\u03BD\u03C9\u03C3\u03C4\u03B9\u03BA", -1, 3), new Among("\u03B1\u03B3\u03BD\u03C9\u03C3\u03C4\u03B9\u03BA", 5, 1), new Among("\u03B1\u03BB\u03B5\u03BE\u03B1\u03BD\u03B4\u03C1\u03B9\u03BD", -1, 8), new Among("\u03B8\u03B5\u03B1\u03C4\u03C1\u03B9\u03BD", -1, 10), new Among("\u03B2\u03C5\u03B6\u03B1\u03BD\u03C4\u03B9\u03BD", -1, 9) }; private final static Among[] a_14 = { new Among("\u03B9\u03C3\u03BC\u03BF\u03B9", -1, 1), new Among("\u03B9\u03C3\u03BC\u03C9\u03BD", -1, 1), new Among("\u03B9\u03C3\u03BC\u03BF", -1, 1), new Among("\u03B9\u03C3\u03BC\u03BF\u03C3", -1, 1), new Among("\u03B9\u03C3\u03BC\u03BF\u03C5\u03C3", -1, 1), new Among("\u03B9\u03C3\u03BC\u03BF\u03C5", -1, 1) }; private final static Among[] a_15 = { new Among("\u03C3", -1, 1), new Among("\u03C7", -1, 1) }; private final static Among[] a_16 = { new Among("\u03BF\u03C5\u03B4\u03B1\u03BA\u03B9\u03B1", -1, 1), new Among("\u03B1\u03C1\u03B1\u03BA\u03B9\u03B1", -1, 1), new Among("\u03BF\u03C5\u03B4\u03B1\u03BA\u03B9", -1, 1), new Among("\u03B1\u03C1\u03B1\u03BA\u03B9", -1, 1) }; private final static Among[] a_17 = { new Among("\u03B2", -1, 2), new Among("\u03B2\u03B1\u03BC\u03B2", 0, 1), new Among("\u03C3\u03BB\u03BF\u03B2", 0, 1), new Among("\u03C4\u03C3\u03B5\u03C7\u03BF\u03C3\u03BB\u03BF\u03B2", 2, 1), new Among("\u03BA\u03B1\u03C1\u03B4", -1, 2), new Among("\u03B6", -1, 2), new Among("\u03C4\u03B6", 5, 1), new Among("\u03BA", -1, 1), new Among("\u03BA\u03B1\u03C0\u03B1\u03BA", 7, 1), new Among("\u03C3\u03BF\u03BA", 7, 1), new Among("\u03C3\u03BA", 7, 1), new Among("\u03B2\u03B1\u03BB", -1, 2), new Among("\u03BC\u03B1\u03BB", -1, 1), new Among("\u03B3\u03BB", -1, 2), new Among("\u03C4\u03C1\u03B9\u03C0\u03BF\u03BB", -1, 2), new Among("\u03C0\u03BB", -1, 1), new Among("\u03BB\u03BF\u03C5\u03BB", -1, 1), new Among("\u03C6\u03C5\u03BB", -1, 1), new Among("\u03BA\u03B1\u03B9\u03BC", -1, 1), new Among("\u03BA\u03BB\u03B9\u03BC", -1, 1), new Among("\u03C6\u03B1\u03C1\u03BC", -1, 1), new Among("\u03B3\u03B9\u03B1\u03BD", -1, 2), new Among("\u03C3\u03C0\u03B1\u03BD", -1, 1), new Among("\u03B7\u03B3\u03BF\u03C5\u03BC\u03B5\u03BD", -1, 2), new Among("\u03BA\u03BF\u03BD", -1, 1), new Among("\u03BC\u03B1\u03BA\u03C1\u03C5\u03BD", -1, 2), new Among("\u03C0", -1, 2), new Among("\u03BA\u03B1\u03C4\u03C1\u03B1\u03C0", 26, 1), new Among("\u03C1", -1, 1), new Among("\u03B2\u03C1", 28, 1), new Among("\u03BB\u03B1\u03B2\u03C1", 29, 1), new Among("\u03B1\u03BC\u03B2\u03C1", 29, 1), new Among("\u03BC\u03B5\u03C1", 28, 1), new Among("\u03C0\u03B1\u03C4\u03B5\u03C1", 28, 2), new Among("\u03B1\u03BD\u03B8\u03C1", 28, 1), new Among("\u03BA\u03BF\u03C1", 28, 1), new Among("\u03C3", -1, 1), new Among("\u03BD\u03B1\u03B3\u03BA\u03B1\u03C3", 36, 1), new Among("\u03C4\u03BF\u03C3", 36, 2), new Among("\u03BC\u03BF\u03C5\u03C3\u03C4", -1, 1), new Among("\u03C1\u03C5", -1, 1), new Among("\u03C6", -1, 1), new Among("\u03C3\u03C6", 41, 1), new Among("\u03B1\u03BB\u03B9\u03C3\u03C6", 42, 1), new Among("\u03BD\u03C5\u03C6", 41, 2), new Among("\u03C7", -1, 1) }; private final static Among[] a_18 = { new Among("\u03B1\u03BA\u03B9\u03B1", -1, 1), new Among("\u03B1\u03C1\u03B1\u03BA\u03B9\u03B1", 0, 1), new Among("\u03B9\u03C4\u03C3\u03B1", -1, 1), new Among("\u03B1\u03BA\u03B9", -1, 1), new Among("\u03B1\u03C1\u03B1\u03BA\u03B9", 3, 1), new Among("\u03B9\u03C4\u03C3\u03C9\u03BD", -1, 1), new Among("\u03B9\u03C4\u03C3\u03B1\u03C3", -1, 1), new Among("\u03B9\u03C4\u03C3\u03B5\u03C3", -1, 1) }; private final static Among[] a_19 = { new Among("\u03C8\u03B1\u03BB", -1, 1), new Among("\u03B1\u03B9\u03C6\u03BD", -1, 1), new Among("\u03BF\u03BB\u03BF", -1, 1), new Among("\u03B9\u03C1", -1, 1) }; private final static Among[] a_20 = { new Among("\u03B5", -1, 1), new Among("\u03C0\u03B1\u03B9\u03C7\u03BD", -1, 1) }; private final static Among[] a_21 = { new Among("\u03B9\u03B4\u03B9\u03B1", -1, 1), new Among("\u03B9\u03B4\u03B9\u03C9\u03BD", -1, 1), new Among("\u03B9\u03B4\u03B9\u03BF", -1, 1) }; private final static Among[] a_22 = { new Among("\u03B9\u03B2", -1, 1), new Among("\u03B4", -1, 1), new Among("\u03C6\u03C1\u03B1\u03B3\u03BA", -1, 1), new Among("\u03BB\u03C5\u03BA", -1, 1), new Among("\u03BF\u03B2\u03B5\u03BB", -1, 1), new Among("\u03BC\u03B7\u03BD", -1, 1), new Among("\u03C1", -1, 1) }; private final static Among[] a_23 = { new Among("\u03B9\u03C3\u03BA\u03B5", -1, 1), new Among("\u03B9\u03C3\u03BA\u03BF", -1, 1), new Among("\u03B9\u03C3\u03BA\u03BF\u03C3", -1, 1), new Among("\u03B9\u03C3\u03BA\u03BF\u03C5", -1, 1) }; private final static Among[] a_24 = { new Among("\u03B1\u03B4\u03C9\u03BD", -1, 1), new Among("\u03B1\u03B4\u03B5\u03C3", -1, 1) }; private final static Among[] a_25 = { new Among("\u03B3\u03B9\u03B1\u03B3\u03B9", -1, -1), new Among("\u03B8\u03B5\u03B9", -1, -1), new Among("\u03BF\u03BA", -1, -1), new Among("\u03BC\u03B1\u03BC", -1, -1), new Among("\u03BC\u03B1\u03BD", -1, -1), new Among("\u03BC\u03C0\u03B1\u03BC\u03C0", -1, -1), new Among("\u03C0\u03B5\u03B8\u03B5\u03C1", -1, -1), new Among("\u03C0\u03B1\u03C4\u03B5\u03C1", -1, -1), new Among("\u03BA\u03C5\u03C1", -1, -1), new Among("\u03BD\u03C4\u03B1\u03BD\u03C4", -1, -1) }; private final static Among[] a_26 = { new Among("\u03B5\u03B4\u03C9\u03BD", -1, 1), new Among("\u03B5\u03B4\u03B5\u03C3", -1, 1) }; private final static Among[] a_27 = { new Among("\u03BC\u03B9\u03BB", -1, 1), new Among("\u03B4\u03B1\u03C0", -1, 1), new Among("\u03B3\u03B7\u03C0", -1, 1), new Among("\u03B9\u03C0", -1, 1), new Among("\u03B5\u03BC\u03C0", -1, 1), new Among("\u03BF\u03C0", -1, 1), new Among("\u03BA\u03C1\u03B1\u03C3\u03C0", -1, 1), new Among("\u03C5\u03C0", -1, 1) }; private final static Among[] a_28 = { new Among("\u03BF\u03C5\u03B4\u03C9\u03BD", -1, 1), new Among("\u03BF\u03C5\u03B4\u03B5\u03C3", -1, 1) }; private final static Among[] a_29 = { new Among("\u03C4\u03C1\u03B1\u03B3", -1, 1), new Among("\u03C6\u03B5", -1, 1), new Among("\u03BA\u03B1\u03BB\u03B9\u03B1\u03BA", -1, 1), new Among("\u03B1\u03C1\u03BA", -1, 1), new Among("\u03C3\u03BA", -1, 1), new Among("\u03C0\u03B5\u03C4\u03B1\u03BB", -1, 1), new Among("\u03B2\u03B5\u03BB", -1, 1), new Among("\u03BB\u03BF\u03C5\u03BB", -1, 1), new Among("\u03C6\u03BB", -1, 1), new Among("\u03C7\u03BD", -1, 1), new Among("\u03C0\u03BB\u03B5\u03BE", -1, 1), new Among("\u03C3\u03C0", -1, 1), new Among("\u03C6\u03C1", -1, 1), new Among("\u03C3", -1, 1), new Among("\u03BB\u03B9\u03C7", -1, 1) }; private final static Among[] a_30 = { new Among("\u03B5\u03C9\u03BD", -1, 1), new Among("\u03B5\u03C9\u03C3", -1, 1) }; private final static Among[] a_31 = { new Among("\u03B4", -1, 1), new Among("\u03B9\u03B4", 0, 1), new Among("\u03B8", -1, 1), new Among("\u03B3\u03B1\u03BB", -1, 1), new Among("\u03B5\u03BB", -1, 1), new Among("\u03BD", -1, 1), new Among("\u03C0", -1, 1), new Among("\u03C0\u03B1\u03C1", -1, 1) }; private final static Among[] a_32 = { new Among("\u03B9\u03B1", -1, 1), new Among("\u03B9\u03C9\u03BD", -1, 1), new Among("\u03B9\u03BF\u03C5", -1, 1) }; private final static Among[] a_33 = { new Among("\u03B9\u03BA\u03B1", -1, 1), new Among("\u03B9\u03BA\u03C9\u03BD", -1, 1), new Among("\u03B9\u03BA\u03BF", -1, 1), new Among("\u03B9\u03BA\u03BF\u03C5", -1, 1) }; private final static Among[] a_34 = { new Among("\u03B1\u03B4", -1, 1), new Among("\u03C3\u03C5\u03BD\u03B1\u03B4", 0, 1), new Among("\u03BA\u03B1\u03C4\u03B1\u03B4", 0, 1), new Among("\u03B1\u03BD\u03C4\u03B9\u03B4", -1, 1), new Among("\u03B5\u03BD\u03B4", -1, 1), new Among("\u03C6\u03C5\u03BB\u03BF\u03B4", -1, 1), new Among("\u03C5\u03C0\u03BF\u03B4", -1, 1), new Among("\u03C0\u03C1\u03C9\u03C4\u03BF\u03B4", -1, 1), new Among("\u03B5\u03BE\u03C9\u03B4", -1, 1), new Among("\u03B7\u03B8", -1, 1), new Among("\u03B1\u03BD\u03B7\u03B8", 9, 1), new Among("\u03BE\u03B9\u03BA", -1, 1), new Among("\u03B1\u03BB", -1, 1), new Among("\u03B1\u03BC\u03BC\u03BF\u03C7\u03B1\u03BB", 12, 1), new Among("\u03C3\u03C5\u03BD\u03BF\u03BC\u03B7\u03BB", -1, 1), new Among("\u03BC\u03C0\u03BF\u03BB", -1, 1), new Among("\u03BC\u03BF\u03C5\u03BB", -1, 1), new Among("\u03C4\u03C3\u03B1\u03BC", -1, 1), new Among("\u03B2\u03C1\u03C9\u03BC", -1, 1), new Among("\u03B1\u03BC\u03B1\u03BD", -1, 1), new Among("\u03BC\u03C0\u03B1\u03BD", -1, 1), new Among("\u03BA\u03B1\u03BB\u03BB\u03B9\u03BD", -1, 1), new Among("\u03C0\u03BF\u03C3\u03C4\u03B5\u03BB\u03BD", -1, 1), new Among("\u03C6\u03B9\u03BB\u03BF\u03BD", -1, 1), new Among("\u03BA\u03B1\u03BB\u03C0", -1, 1), new Among("\u03B3\u03B5\u03C1", -1, 1), new Among("\u03C7\u03B1\u03C3", -1, 1), new Among("\u03BC\u03C0\u03BF\u03C3", -1, 1), new Among("\u03C0\u03BB\u03B9\u03B1\u03C4\u03C3", -1, 1), new Among("\u03C0\u03B5\u03C4\u03C3", -1, 1), new Among("\u03C0\u03B9\u03C4\u03C3", -1, 1), new Among("\u03C6\u03C5\u03C3", -1, 1), new Among("\u03BC\u03C0\u03B1\u03B3\u03B9\u03B1\u03C4", -1, 1), new Among("\u03BD\u03B9\u03C4", -1, 1), new Among("\u03C0\u03B9\u03BA\u03B1\u03BD\u03C4", -1, 1), new Among("\u03C3\u03B5\u03C1\u03C4", -1, 1) }; private final static Among[] a_35 = { new Among("\u03B1\u03B3\u03B1\u03BC\u03B5", -1, 1), new Among("\u03B7\u03BA\u03B1\u03BC\u03B5", -1, 1), new Among("\u03B7\u03B8\u03B7\u03BA\u03B1\u03BC\u03B5", 1, 1), new Among("\u03B7\u03C3\u03B1\u03BC\u03B5", -1, 1), new Among("\u03BF\u03C5\u03C3\u03B1\u03BC\u03B5", -1, 1) }; private final static Among[] a_36 = { new Among("\u03B2\u03BF\u03C5\u03B2", -1, 1), new Among("\u03BE\u03B5\u03B8", -1, 1), new Among("\u03C0\u03B5\u03B8", -1, 1), new Among("\u03B1\u03C0\u03BF\u03B8", -1, 1), new Among("\u03B1\u03C0\u03BF\u03BA", -1, 1), new Among("\u03BF\u03C5\u03BB", -1, 1), new Among("\u03B1\u03BD\u03B1\u03C0", -1, 1), new Among("\u03C0\u03B9\u03BA\u03C1", -1, 1), new Among("\u03C0\u03BF\u03C4", -1, 1), new Among("\u03B1\u03C0\u03BF\u03C3\u03C4", -1, 1), new Among("\u03C7", -1, 1), new Among("\u03C3\u03B9\u03C7", 10, 1) }; private final static Among[] a_37 = { new Among("\u03C4\u03C1", -1, 1), new Among("\u03C4\u03C3", -1, 1) }; private final static Among[] a_38 = { new Among("\u03B1\u03B3\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B7\u03BA\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B7\u03B8\u03B7\u03BA\u03B1\u03BD\u03B5", 1, 1), new Among("\u03B7\u03C3\u03B1\u03BD\u03B5", -1, 1), new Among("\u03BF\u03C5\u03C3\u03B1\u03BD\u03B5", -1, 1), new Among("\u03BF\u03BD\u03C4\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B9\u03BF\u03BD\u03C4\u03B1\u03BD\u03B5", 5, 1), new Among("\u03BF\u03C5\u03BD\u03C4\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B9\u03BF\u03C5\u03BD\u03C4\u03B1\u03BD\u03B5", 7, 1), new Among("\u03BF\u03C4\u03B1\u03BD\u03B5", -1, 1), new Among("\u03B9\u03BF\u03C4\u03B1\u03BD\u03B5", 9, 1) }; private final static Among[] a_39 = { new Among("\u03C4\u03B1\u03B2", -1, 1), new Among("\u03BD\u03C4\u03B1\u03B2", 0, 1), new Among("\u03C8\u03B7\u03BB\u03BF\u03C4\u03B1\u03B2", 0, 1), new Among("\u03BB\u03B9\u03B2", -1, 1), new Among("\u03BA\u03BB\u03B9\u03B2", 3, 1), new Among("\u03BE\u03B7\u03C1\u03BF\u03BA\u03BB\u03B9\u03B2", 4, 1), new Among("\u03B3", -1, 1), new Among("\u03B1\u03B3", 6, 1), new Among("\u03C4\u03C1\u03B1\u03B3", 7, 1), new Among("\u03C4\u03C3\u03B1\u03B3", 7, 1), new Among("\u03B1\u03B8\u03B9\u03B3\u03B3", 6, 1), new Among("\u03C4\u03C3\u03B9\u03B3\u03B3", 6, 1), new Among("\u03B1\u03C4\u03C3\u03B9\u03B3\u03B3", 11, 1), new Among("\u03C3\u03C4\u03B5\u03B3", 6, 1), new Among("\u03B1\u03C0\u03B7\u03B3", 6, 1), new Among("\u03C3\u03B9\u03B3", 6, 1), new Among("\u03B1\u03BD\u03BF\u03C1\u03B3", 6, 1), new Among("\u03B5\u03BD\u03BF\u03C1\u03B3", 6, 1), new Among("\u03BA\u03B1\u03BB\u03C0\u03BF\u03C5\u03B6", -1, 1), new Among("\u03B8", -1, 1), new Among("\u03BC\u03C9\u03B1\u03BC\u03B5\u03B8", 19, 1), new Among("\u03C0\u03B9\u03B8", 19, 1), new Among("\u03B1\u03C0\u03B9\u03B8", 21, 1), new Among("\u03B4\u03B5\u03BA", -1, 1), new Among("\u03C0\u03B5\u03BB\u03B5\u03BA", -1, 1), new Among("\u03B9\u03BA", -1, 1), new Among("\u03B1\u03BD\u03B9\u03BA", 25, 1), new Among("\u03B2\u03BF\u03C5\u03BB\u03BA", -1, 1), new Among("\u03B2\u03B1\u03C3\u03BA", -1, 1), new Among("\u03B2\u03C1\u03B1\u03C7\u03C5\u03BA", -1, 1), new Among("\u03B3\u03B1\u03BB", -1, 1), new Among("\u03BA\u03B1\u03C4\u03B1\u03B3\u03B1\u03BB", 30, 1), new Among("\u03BF\u03BB\u03BF\u03B3\u03B1\u03BB", 30, 1), new Among("\u03B2\u03B1\u03B8\u03C5\u03B3\u03B1\u03BB", 30, 1), new Among("\u03BC\u03B5\u03BB", -1, 1), new Among("\u03BA\u03B1\u03C3\u03C4\u03B5\u03BB", -1, 1), new Among("\u03C0\u03BF\u03C1\u03C4\u03BF\u03BB", -1, 1), new Among("\u03C0\u03BB", -1, 1), new Among("\u03B4\u03B9\u03C0\u03BB", 37, 1), new Among("\u03BB\u03B1\u03BF\u03C0\u03BB", 37, 1), new Among("\u03C8\u03C5\u03C7\u03BF\u03C0\u03BB", 37, 1), new Among("\u03BF\u03C5\u03BB", -1, 1), new Among("\u03BC", -1, 1), new Among("\u03BF\u03BB\u03B9\u03B3\u03BF\u03B4\u03B1\u03BC", 42, 1), new Among("\u03BC\u03BF\u03C5\u03C3\u03BF\u03C5\u03BB\u03BC", 42, 1), new Among("\u03B4\u03C1\u03B1\u03B4\u03BF\u03C5\u03BC", 42, 1), new Among("\u03B2\u03C1\u03B1\u03C7\u03BC", 42, 1), new Among("\u03BD", -1, 1), new Among("\u03B1\u03BC\u03B5\u03C1\u03B9\u03BA\u03B1\u03BD", 47, 1), new Among("\u03C0", -1, 1), new Among("\u03B1\u03B4\u03B1\u03C0", 49, 1), new Among("\u03C7\u03B1\u03BC\u03B7\u03BB\u03BF\u03B4\u03B1\u03C0", 49, 1), new Among("\u03C0\u03BF\u03BB\u03C5\u03B4\u03B1\u03C0", 49, 1), new Among("\u03BA\u03BF\u03C0", 49, 1), new Among("\u03C5\u03C0\u03BF\u03BA\u03BF\u03C0", 53, 1), new Among("\u03C4\u03C3\u03BF\u03C0", 49, 1), new Among("\u03C3\u03C0", 49, 1), new Among("\u03B5\u03C1", -1, 1), new Among("\u03B3\u03B5\u03C1", 57, 1), new Among("\u03B2\u03B5\u03C4\u03B5\u03C1", 57, 1), new Among("\u03BB\u03BF\u03C5\u03B8\u03B7\u03C1", -1, 1), new Among("\u03BA\u03BF\u03C1\u03BC\u03BF\u03C1", -1, 1), new Among("\u03C0\u03B5\u03C1\u03B9\u03C4\u03C1", -1, 1), new Among("\u03BF\u03C5\u03C1", -1, 1), new Among("\u03C3", -1, 1), new Among("\u03B2\u03B1\u03C3", 64, 1), new Among("\u03C0\u03BF\u03BB\u03B9\u03C3", 64, 1), new Among("\u03C3\u03B1\u03C1\u03B1\u03BA\u03B1\u03C4\u03C3", 64, 1), new Among("\u03B8\u03C5\u03C3", 64, 1), new Among("\u03B4\u03B9\u03B1\u03C4", -1, 1), new Among("\u03C0\u03BB\u03B1\u03C4", -1, 1), new Among("\u03C4\u03C3\u03B1\u03C1\u03BB\u03B1\u03C4", -1, 1), new Among("\u03C4\u03B5\u03C4", -1, 1), new Among("\u03C0\u03BF\u03C5\u03C1\u03B9\u03C4", -1, 1), new Among("\u03C3\u03BF\u03C5\u03BB\u03C4", -1, 1), new Among("\u03BC\u03B1\u03B9\u03BD\u03C4", -1, 1), new Among("\u03B6\u03C9\u03BD\u03C4", -1, 1), new Among("\u03BA\u03B1\u03C3\u03C4", -1, 1), new Among("\u03C6", -1, 1), new Among("\u03B4\u03B9\u03B1\u03C6", 78, 1), new Among("\u03C3\u03C4\u03B5\u03C6", 78, 1), new Among("\u03C6\u03C9\u03C4\u03BF\u03C3\u03C4\u03B5\u03C6", 80, 1), new Among("\u03C0\u03B5\u03C1\u03B7\u03C6", 78, 1), new Among("\u03C5\u03C0\u03B5\u03C1\u03B7\u03C6", 82, 1), new Among("\u03BA\u03BF\u03B9\u03BB\u03B1\u03C1\u03C6", 78, 1), new Among("\u03C0\u03B5\u03BD\u03C4\u03B1\u03C1\u03C6", 78, 1), new Among("\u03BF\u03C1\u03C6", 78, 1), new Among("\u03C7", -1, 1), new Among("\u03B1\u03BC\u03B7\u03C7", 87, 1), new Among("\u03B2\u03B9\u03BF\u03BC\u03B7\u03C7", 87, 1), new Among("\u03BC\u03B5\u03B3\u03BB\u03BF\u03B2\u03B9\u03BF\u03BC\u03B7\u03C7", 89, 1), new Among("\u03BA\u03B1\u03C0\u03BD\u03BF\u03B2\u03B9\u03BF\u03BC\u03B7\u03C7", 89, 1), new Among("\u03BC\u03B9\u03BA\u03C1\u03BF\u03B2\u03B9\u03BF\u03BC\u03B7\u03C7", 89, 1), new Among("\u03C0\u03BF\u03BB\u03C5\u03BC\u03B7\u03C7", 87, 1), new Among("\u03BB\u03B9\u03C7", 87, 1) }; private final static Among[] a_40 = { new Among("\u03B7\u03C3\u03B5\u03C4\u03B5", -1, 1) }; private final static Among[] a_41 = { new Among("\u03B5\u03BD\u03B4", -1, 1), new Among("\u03C3\u03C5\u03BD\u03B4", -1, 1), new Among("\u03BF\u03B4", -1, 1), new Among("\u03B4\u03B9\u03B1\u03B8", -1, 1), new Among("\u03BA\u03B1\u03B8", -1, 1), new Among("\u03C1\u03B1\u03B8", -1, 1), new Among("\u03C4\u03B1\u03B8", -1, 1), new Among("\u03C4\u03B9\u03B8", -1, 1), new Among("\u03B5\u03BA\u03B8", -1, 1), new Among("\u03B5\u03BD\u03B8", -1, 1), new Among("\u03C3\u03C5\u03BD\u03B8", -1, 1), new Among("\u03C1\u03BF\u03B8", -1, 1), new Among("\u03C5\u03C0\u03B5\u03C1\u03B8", -1, 1), new Among("\u03C3\u03B8", -1, 1), new Among("\u03B5\u03C5\u03B8", -1, 1), new Among("\u03B1\u03C1\u03BA", -1, 1), new Among("\u03C9\u03C6\u03B5\u03BB", -1, 1), new Among("\u03B2\u03BF\u03BB", -1, 1), new Among("\u03B1\u03B9\u03BD", -1, 1), new Among("\u03C0\u03BF\u03BD", -1, 1), new Among("\u03C1\u03BF\u03BD", -1, 1), new Among("\u03C3\u03C5\u03BD", -1, 1), new Among("\u03B2\u03B1\u03C1", -1, 1), new Among("\u03B2\u03C1", -1, 1), new Among("\u03B1\u03B9\u03C1", -1, 1), new Among("\u03C6\u03BF\u03C1", -1, 1), new Among("\u03B5\u03C5\u03C1", -1, 1), new Among("\u03C0\u03C5\u03C1", -1, 1), new Among("\u03C7\u03C9\u03C1", -1, 1), new Among("\u03BD\u03B5\u03C4", -1, 1), new Among("\u03C3\u03C7", -1, 1) }; private final static Among[] a_42 = { new Among("\u03C0\u03B1\u03B3", -1, 1), new Among("\u03B4", -1, 1), new Among("\u03B1\u03B4", 1, 1), new Among("\u03B8", -1, 1), new Among("\u03B1\u03B8", 3, 1), new Among("\u03C4\u03BF\u03BA", -1, 1), new Among("\u03C3\u03BA", -1, 1), new Among("\u03C0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB", -1, 1), new Among("\u03C3\u03BA\u03B5\u03BB", -1, 1), new Among("\u03B1\u03C0\u03BB", -1, 1), new Among("\u03B5\u03BC", -1, 1), new Among("\u03B1\u03BD", -1, 1), new Among("\u03B2\u03B5\u03BD", -1, 1), new Among("\u03B2\u03B1\u03C1\u03BF\u03BD", -1, 1), new Among("\u03BA\u03BF\u03C0", -1, 1), new Among("\u03C3\u03B5\u03C1\u03C0", -1, 1), new Among("\u03B1\u03B2\u03B1\u03C1", -1, 1), new Among("\u03B5\u03BD\u03B1\u03C1", -1, 1), new Among("\u03B1\u03B2\u03C1", -1, 1), new Among("\u03BC\u03C0\u03BF\u03C1", -1, 1), new Among("\u03B8\u03B1\u03C1\u03C1", -1, 1), new Among("\u03BD\u03C4\u03C1", -1, 1), new Among("\u03C5", -1, 1), new Among("\u03BD\u03B9\u03C6", -1, 1), new Among("\u03C3\u03C5\u03C1\u03C6", -1, 1) }; private final static Among[] a_43 = { new Among("\u03BF\u03BD\u03C4\u03B1\u03C3", -1, 1), new Among("\u03C9\u03BD\u03C4\u03B1\u03C3", -1, 1) }; private final static Among[] a_44 = { new Among("\u03BF\u03BC\u03B1\u03C3\u03C4\u03B5", -1, 1), new Among("\u03B9\u03BF\u03BC\u03B1\u03C3\u03C4\u03B5", 0, 1) }; private final static Among[] a_45 = { new Among("\u03C0", -1, 1), new Among("\u03B1\u03C0", 0, 1), new Among("\u03B1\u03BA\u03B1\u03C4\u03B1\u03C0", 1, 1), new Among("\u03C3\u03C5\u03BC\u03C0", 0, 1), new Among("\u03B1\u03C3\u03C5\u03BC\u03C0", 3, 1), new Among("\u03B1\u03BC\u03B5\u03C4\u03B1\u03BC\u03C6", -1, 1) }; private final static Among[] a_46 = { new Among("\u03B6", -1, 1), new Among("\u03B1\u03BB", -1, 1), new Among("\u03C0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB", 1, 1), new Among("\u03B5\u03BA\u03C4\u03B5\u03BB", -1, 1), new Among("\u03BC", -1, 1), new Among("\u03BE", -1, 1), new Among("\u03C0\u03C1\u03BF", -1, 1), new Among("\u03B1\u03C1", -1, 1), new Among("\u03BD\u03B9\u03C3", -1, 1) }; private final static Among[] a_47 = { new Among("\u03B7\u03B8\u03B7\u03BA\u03B1", -1, 1), new Among("\u03B7\u03B8\u03B7\u03BA\u03B5", -1, 1), new Among("\u03B7\u03B8\u03B7\u03BA\u03B5\u03C3", -1, 1) }; private final static Among[] a_48 = { new Among("\u03C0\u03B9\u03B8", -1, 1), new Among("\u03BF\u03B8", -1, 1), new Among("\u03BD\u03B1\u03C1\u03B8", -1, 1), new Among("\u03C3\u03BA\u03BF\u03C5\u03BB", -1, 1), new Among("\u03C3\u03BA\u03C9\u03BB", -1, 1), new Among("\u03C3\u03C6", -1, 1) }; private final static Among[] a_49 = { new Among("\u03B8", -1, 1), new Among("\u03B4\u03B9\u03B1\u03B8", 0, 1), new Among("\u03C0\u03B1\u03C1\u03B1\u03BA\u03B1\u03C4\u03B1\u03B8", 0, 1), new Among("\u03C3\u03C5\u03BD\u03B8", 0, 1), new Among("\u03C0\u03C1\u03BF\u03C3\u03B8", 0, 1) }; private final static Among[] a_50 = { new Among("\u03B7\u03BA\u03B1", -1, 1), new Among("\u03B7\u03BA\u03B5", -1, 1), new Among("\u03B7\u03BA\u03B5\u03C3", -1, 1) }; private final static Among[] a_51 = { new Among("\u03C6\u03B1\u03B3", -1, 1), new Among("\u03BB\u03B7\u03B3", -1, 1), new Among("\u03C6\u03C1\u03C5\u03B4", -1, 1), new Among("\u03BC\u03B1\u03BD\u03C4\u03B9\u03BB", -1, 1), new Among("\u03BC\u03B1\u03BB\u03BB", -1, 1), new Among("\u03BF\u03BC", -1, 1), new Among("\u03B2\u03BB\u03B5\u03C0", -1, 1), new Among("\u03C0\u03BF\u03B4\u03B1\u03C1", -1, 1), new Among("\u03BA\u03C5\u03BC\u03B1\u03C4", -1, 1), new Among("\u03C0\u03C1\u03C9\u03C4", -1, 1), new Among("\u03BB\u03B1\u03C7", -1, 1), new Among("\u03C0\u03B1\u03BD\u03C4\u03B1\u03C7", -1, 1) }; private final static Among[] a_52 = { new Among("\u03C4\u03C3\u03B1", -1, 1), new Among("\u03C7\u03B1\u03B4", -1, 1), new Among("\u03BC\u03B5\u03B4", -1, 1), new Among("\u03BB\u03B1\u03BC\u03C0\u03B9\u03B4", -1, 1), new Among("\u03B4\u03B5", -1, 1), new Among("\u03C0\u03BB\u03B5", -1, 1), new Among("\u03BC\u03B5\u03C3\u03B1\u03B6", -1, 1), new Among("\u03B4\u03B5\u03C3\u03C0\u03BF\u03B6", -1, 1), new Among("\u03B1\u03B9\u03B8", -1, 1), new Among("\u03C6\u03B1\u03C1\u03BC\u03B1\u03BA", -1, 1), new Among("\u03B1\u03B3\u03BA", -1, 1), new Among("\u03B1\u03BD\u03B7\u03BA", -1, 1), new Among("\u03BB", -1, 1), new Among("\u03BC", -1, 1), new Among("\u03B1\u03BC", 13, 1), new Among("\u03B2\u03C1\u03BF\u03BC", 13, 1), new Among("\u03C5\u03C0\u03BF\u03C4\u03B5\u03B9\u03BD", -1, 1), new Among("\u03B5\u03BA\u03BB\u03B9\u03C0", -1, 1), new Among("\u03C1", -1, 1), new Among("\u03B5\u03BD\u03B4\u03B9\u03B1\u03C6\u03B5\u03C1", 18, 1), new Among("\u03B1\u03BD\u03B1\u03C1\u03C1", 18, 1), new Among("\u03C0\u03B1\u03C4", -1, 1), new Among("\u03BA\u03B1\u03B8\u03B1\u03C1\u03B5\u03C5", -1, 1), new Among("\u03B4\u03B5\u03C5\u03C4\u03B5\u03C1\u03B5\u03C5", -1, 1), new Among("\u03BB\u03B5\u03C7", -1, 1) }; private final static Among[] a_53 = { new Among("\u03BF\u03C5\u03C3\u03B1", -1, 1), new Among("\u03BF\u03C5\u03C3\u03B5", -1, 1), new Among("\u03BF\u03C5\u03C3\u03B5\u03C3", -1, 1) }; private final static Among[] a_54 = { new Among("\u03C0\u03B5\u03BB", -1, 1), new Among("\u03BB\u03BB", -1, 1), new Among("\u03C3\u03BC\u03B7\u03BD", -1, 1), new Among("\u03C1\u03C0", -1, 1), new Among("\u03C0\u03C1", -1, 1), new Among("\u03C6\u03C1", -1, 1), new Among("\u03C7\u03BF\u03C1\u03C4", -1, 1), new Among("\u03BF\u03C6", -1, 1), new Among("\u03C8\u03BF\u03C6", 7, -1), new Among("\u03C3\u03C6", -1, 1), new Among("\u03BB\u03BF\u03C7", -1, 1), new Among("\u03BD\u03B1\u03C5\u03BB\u03BF\u03C7", 10, -1) }; private final static Among[] a_55 = { new Among("\u03B1\u03BC\u03B1\u03BB\u03BB\u03B9", -1, 1), new Among("\u03BB", -1, 1), new Among("\u03B1\u03BC\u03B1\u03BB", 1, 1), new Among("\u03BC", -1, 1), new Among("\u03BF\u03C5\u03BB\u03B1\u03BC", 3, 1), new Among("\u03B5\u03BD", -1, 1), new Among("\u03B4\u03B5\u03C1\u03B2\u03B5\u03BD", 5, 1), new Among("\u03C0", -1, 1), new Among("\u03B1\u03B5\u03B9\u03C0", 7, 1), new Among("\u03B1\u03C1\u03C4\u03B9\u03C0", 7, 1), new Among("\u03C3\u03C5\u03BC\u03C0", 7, 1), new Among("\u03BD\u03B5\u03BF\u03C0", 7, 1), new Among("\u03BA\u03C1\u03BF\u03BA\u03B1\u03BB\u03BF\u03C0", 7, 1), new Among("\u03BF\u03BB\u03BF\u03C0", 7, 1), new Among("\u03C0\u03C1\u03BF\u03C3\u03C9\u03C0\u03BF\u03C0", 7, 1), new Among("\u03C3\u03B9\u03B4\u03B7\u03C1\u03BF\u03C0", 7, 1), new Among("\u03B4\u03C1\u03BF\u03C3\u03BF\u03C0", 7, 1), new Among("\u03B1\u03C3\u03C0", 7, 1), new Among("\u03B1\u03BD\u03C5\u03C0", 7, 1), new Among("\u03C1", -1, 1), new Among("\u03B1\u03C3\u03C0\u03B1\u03C1", 19, 1), new Among("\u03C7\u03B1\u03C1", 19, 1), new Among("\u03B1\u03C7\u03B1\u03C1", 21, 1), new Among("\u03B1\u03C0\u03B5\u03C1", 19, 1), new Among("\u03C4\u03C1", 19, 1), new Among("\u03BF\u03C5\u03C1", 19, 1), new Among("\u03C4", -1, 1), new Among("\u03B4\u03B9\u03B1\u03C4", 26, 1), new Among("\u03B5\u03C0\u03B9\u03C4", 26, 1), new Among("\u03C3\u03C5\u03BD\u03C4", 26, 1), new Among("\u03BF\u03BC\u03BF\u03C4", 26, 1), new Among("\u03BD\u03BF\u03BC\u03BF\u03C4", 30, 1), new Among("\u03B1\u03C0\u03BF\u03C4", 26, 1), new Among("\u03C5\u03C0\u03BF\u03C4", 26, 1), new Among("\u03B1\u03B2\u03B1\u03C3\u03C4", 26, 1), new Among("\u03B1\u03B9\u03BC\u03BF\u03C3\u03C4", 26, 1), new Among("\u03C0\u03C1\u03BF\u03C3\u03C4", 26, 1), new Among("\u03B1\u03BD\u03C5\u03C3\u03C4", 26, 1), new Among("\u03BD\u03B1\u03C5", -1, 1), new Among("\u03B1\u03C6", -1, 1), new Among("\u03BE\u03B5\u03C6", -1, 1), new Among("\u03B1\u03B4\u03B7\u03C6", -1, 1), new Among("\u03C0\u03B1\u03BC\u03C6", -1, 1), new Among("\u03C0\u03BF\u03BB\u03C5\u03C6", -1, 1) }; private final static Among[] a_56 = { new Among("\u03B1\u03B3\u03B1", -1, 1), new Among("\u03B1\u03B3\u03B5", -1, 1), new Among("\u03B1\u03B3\u03B5\u03C3", -1, 1) }; private final static Among[] a_57 = { new Among("\u03B7\u03C3\u03B1", -1, 1), new Among("\u03B7\u03C3\u03B5", -1, 1), new Among("\u03B7\u03C3\u03BF\u03C5", -1, 1) }; private final static Among[] a_58 = { new Among("\u03BD", -1, 1), new Among("\u03B4\u03C9\u03B4\u03B5\u03BA\u03B1\u03BD", 0, 1), new Among("\u03B5\u03C0\u03C4\u03B1\u03BD", 0, 1), new Among("\u03BC\u03B5\u03B3\u03B1\u03BB\u03BF\u03BD", 0, 1), new Among("\u03B5\u03C1\u03B7\u03BC\u03BF\u03BD", 0, 1), new Among("\u03C7\u03B5\u03C1\u03C3\u03BF\u03BD", 0, 1) }; private final static Among[] a_59 = { new Among("\u03B7\u03C3\u03C4\u03B5", -1, 1) }; private final static Among[] a_60 = { new Among("\u03C3\u03B2", -1, 1), new Among("\u03B1\u03C3\u03B2", 0, 1), new Among("\u03B1\u03C0\u03BB", -1, 1), new Among("\u03B1\u03B5\u03B9\u03BC\u03BD", -1, 1), new Among("\u03C7\u03C1", -1, 1), new Among("\u03B1\u03C7\u03C1", 4, 1), new Among("\u03BA\u03BF\u03B9\u03BD\u03BF\u03C7\u03C1", 4, 1), new Among("\u03B4\u03C5\u03C3\u03C7\u03C1", 4, 1), new Among("\u03B5\u03C5\u03C7\u03C1", 4, 1), new Among("\u03C0\u03B1\u03BB\u03B9\u03BC\u03C8", -1, 1) }; private final static Among[] a_61 = { new Among("\u03BF\u03C5\u03BD\u03B5", -1, 1), new Among("\u03B7\u03B8\u03BF\u03C5\u03BD\u03B5", 0, 1), new Among("\u03B7\u03C3\u03BF\u03C5\u03BD\u03B5", 0, 1) }; private final static Among[] a_62 = { new Among("\u03C3\u03C0\u03B9", -1, 1), new Among("\u03BD", -1, 1), new Among("\u03B5\u03BE\u03C9\u03BD", 1, 1), new Among("\u03C1", -1, 1), new Among("\u03C3\u03C4\u03C1\u03B1\u03B2\u03BF\u03BC\u03BF\u03C5\u03C4\u03C3", -1, 1), new Among("\u03BA\u03B1\u03BA\u03BF\u03BC\u03BF\u03C5\u03C4\u03C3", -1, 1) }; private final static Among[] a_63 = { new Among("\u03BF\u03C5\u03BC\u03B5", -1, 1), new Among("\u03B7\u03B8\u03BF\u03C5\u03BC\u03B5", 0, 1), new Among("\u03B7\u03C3\u03BF\u03C5\u03BC\u03B5", 0, 1) }; private final static Among[] a_64 = { new Among("\u03B1\u03B6", -1, 1), new Among("\u03C9\u03C1\u03B9\u03BF\u03C0\u03BB", -1, 1), new Among("\u03B1\u03C3\u03BF\u03C5\u03C3", -1, 1), new Among("\u03C0\u03B1\u03C1\u03B1\u03C3\u03BF\u03C5\u03C3", 2, 1), new Among("\u03B1\u03BB\u03BB\u03BF\u03C3\u03BF\u03C5\u03C3", -1, 1), new Among("\u03C6", -1, 1), new Among("\u03C7", -1, 1) }; private final static Among[] a_65 = { new Among("\u03BC\u03B1\u03C4\u03B1", -1, 1), new Among("\u03BC\u03B1\u03C4\u03C9\u03BD", -1, 1), new Among("\u03BC\u03B1\u03C4\u03BF\u03C3", -1, 1) }; private final static Among[] a_66 = { new Among("\u03B1", -1, 1), new Among("\u03B9\u03BF\u03C5\u03BC\u03B1", 0, 1), new Among("\u03BF\u03BC\u03BF\u03C5\u03BD\u03B1", 0, 1), new Among("\u03B9\u03BF\u03BC\u03BF\u03C5\u03BD\u03B1", 2, 1), new Among("\u03BF\u03C3\u03BF\u03C5\u03BD\u03B1", 0, 1), new Among("\u03B9\u03BF\u03C3\u03BF\u03C5\u03BD\u03B1", 4, 1), new Among("\u03B5", -1, 1), new Among("\u03B1\u03B3\u03B1\u03C4\u03B5", 6, 1), new Among("\u03B7\u03BA\u03B1\u03C4\u03B5", 6, 1), new Among("\u03B7\u03B8\u03B7\u03BA\u03B1\u03C4\u03B5", 8, 1), new Among("\u03B7\u03C3\u03B1\u03C4\u03B5", 6, 1), new Among("\u03BF\u03C5\u03C3\u03B1\u03C4\u03B5", 6, 1), new Among("\u03B5\u03B9\u03C4\u03B5", 6, 1), new Among("\u03B7\u03B8\u03B5\u03B9\u03C4\u03B5", 12, 1), new Among("\u03B9\u03B5\u03BC\u03B1\u03C3\u03C4\u03B5", 6, 1), new Among("\u03BF\u03C5\u03BC\u03B1\u03C3\u03C4\u03B5", 6, 1), new Among("\u03B9\u03BF\u03C5\u03BC\u03B1\u03C3\u03C4\u03B5", 15, 1), new Among("\u03B9\u03B5\u03C3\u03B1\u03C3\u03C4\u03B5", 6, 1), new Among("\u03BF\u03C3\u03B1\u03C3\u03C4\u03B5", 6, 1), new Among("\u03B9\u03BF\u03C3\u03B1\u03C3\u03C4\u03B5", 18, 1), new Among("\u03B7", -1, 1), new Among("\u03B9", -1, 1), new Among("\u03B1\u03BC\u03B1\u03B9", 21, 1), new Among("\u03B9\u03B5\u03BC\u03B1\u03B9", 21, 1), new Among("\u03BF\u03BC\u03B1\u03B9", 21, 1), new Among("\u03BF\u03C5\u03BC\u03B1\u03B9", 21, 1), new Among("\u03B1\u03C3\u03B1\u03B9", 21, 1), new Among("\u03B5\u03C3\u03B1\u03B9", 21, 1), new Among("\u03B9\u03B5\u03C3\u03B1\u03B9", 27, 1), new Among("\u03B1\u03C4\u03B1\u03B9", 21, 1), new Among("\u03B5\u03C4\u03B1\u03B9", 21, 1), new Among("\u03B9\u03B5\u03C4\u03B1\u03B9", 30, 1), new Among("\u03BF\u03BD\u03C4\u03B1\u03B9", 21, 1), new Among("\u03BF\u03C5\u03BD\u03C4\u03B1\u03B9", 21, 1), new Among("\u03B9\u03BF\u03C5\u03BD\u03C4\u03B1\u03B9", 33, 1), new Among("\u03B5\u03B9", 21, 1), new Among("\u03B1\u03B5\u03B9", 35, 1), new Among("\u03B7\u03B8\u03B5\u03B9", 35, 1), new Among("\u03B7\u03C3\u03B5\u03B9", 35, 1), new Among("\u03BF\u03B9", 21, 1), new Among("\u03B1\u03BD", -1, 1), new Among("\u03B1\u03B3\u03B1\u03BD", 40, 1), new Among("\u03B7\u03BA\u03B1\u03BD", 40, 1), new Among("\u03B7\u03B8\u03B7\u03BA\u03B1\u03BD", 42, 1), new Among("\u03B7\u03C3\u03B1\u03BD", 40, 1), new Among("\u03BF\u03C5\u03C3\u03B1\u03BD", 40, 1), new Among("\u03BF\u03BD\u03C4\u03BF\u03C5\u03C3\u03B1\u03BD", 45, 1), new Among("\u03B9\u03BF\u03BD\u03C4\u03BF\u03C5\u03C3\u03B1\u03BD", 46, 1), new Among("\u03BF\u03BD\u03C4\u03B1\u03BD", 40, 1), new Among("\u03B9\u03BF\u03BD\u03C4\u03B1\u03BD", 48, 1), new Among("\u03BF\u03C5\u03BD\u03C4\u03B1\u03BD", 40, 1), new Among("\u03B9\u03BF\u03C5\u03BD\u03C4\u03B1\u03BD", 50, 1), new Among("\u03BF\u03C4\u03B1\u03BD", 40, 1), new Among("\u03B9\u03BF\u03C4\u03B1\u03BD", 52, 1), new Among("\u03BF\u03BC\u03B1\u03C3\u03C4\u03B1\u03BD", 40, 1), new Among("\u03B9\u03BF\u03BC\u03B1\u03C3\u03C4\u03B1\u03BD", 54, 1), new Among("\u03BF\u03C3\u03B1\u03C3\u03C4\u03B1\u03BD", 40, 1), new Among("\u03B9\u03BF\u03C3\u03B1\u03C3\u03C4\u03B1\u03BD", 56, 1), new Among("\u03BF\u03C5\u03BD", -1, 1), new Among("\u03B7\u03B8\u03BF\u03C5\u03BD", 58, 1), new Among("\u03BF\u03BC\u03BF\u03C5\u03BD", 58, 1), new Among("\u03B9\u03BF\u03BC\u03BF\u03C5\u03BD", 60, 1), new Among("\u03B7\u03C3\u03BF\u03C5\u03BD", 58, 1), new Among("\u03BF\u03C3\u03BF\u03C5\u03BD", 58, 1), new Among("\u03B9\u03BF\u03C3\u03BF\u03C5\u03BD", 63, 1), new Among("\u03C9\u03BD", -1, 1), new Among("\u03B7\u03B4\u03C9\u03BD", 65, 1), new Among("\u03BF", -1, 1), new Among("\u03B1\u03C3", -1, 1), new Among("\u03B5\u03C3", -1, 1), new Among("\u03B7\u03B4\u03B5\u03C3", 69, 1), new Among("\u03B7\u03C3\u03B5\u03C3", 69, 1), new Among("\u03B7\u03C3", -1, 1), new Among("\u03B5\u03B9\u03C3", -1, 1), new Among("\u03B7\u03B8\u03B5\u03B9\u03C3", 73, 1), new Among("\u03BF\u03C3", -1, 1), new Among("\u03C5\u03C3", -1, 1), new Among("\u03BF\u03C5\u03C3", 76, 1), new Among("\u03C5", -1, 1), new Among("\u03BF\u03C5", 78, 1), new Among("\u03C9", -1, 1), new Among("\u03B1\u03C9", 80, 1), new Among("\u03B7\u03B8\u03C9", 80, 1), new Among("\u03B7\u03C3\u03C9", 80, 1) }; private final static Among[] a_67 = { new Among("\u03BF\u03C4\u03B5\u03C1", -1, 1), new Among("\u03B5\u03C3\u03C4\u03B5\u03C1", -1, 1), new Among("\u03C5\u03C4\u03B5\u03C1", -1, 1), new Among("\u03C9\u03C4\u03B5\u03C1", -1, 1), new Among("\u03BF\u03C4\u03B1\u03C4", -1, 1), new Among("\u03B5\u03C3\u03C4\u03B1\u03C4", -1, 1), new Among("\u03C5\u03C4\u03B1\u03C4", -1, 1), new Among("\u03C9\u03C4\u03B1\u03C4", -1, 1) }; private static final char[] g_v = {81, 65, 16, 1}; private static final char[] g_v2 = {81, 65, 0, 1}; private boolean B_test1; private boolean r_has_min_length() { return length >= 3; } private boolean r_tolower() { int among_var; while (true) { int v_1 = limit - cursor; lab0: { ket = cursor; among_var = find_among_b(a_0); bra = cursor; switch (among_var) { case 1: slice_from("\u03B1"); break; case 2: slice_from("\u03B2"); break; case 3: slice_from("\u03B3"); break; case 4: slice_from("\u03B4"); break; case 5: slice_from("\u03B5"); break; case 6: slice_from("\u03B6"); break; case 7: slice_from("\u03B7"); break; case 8: slice_from("\u03B8"); break; case 9: slice_from("\u03B9"); break; case 10: slice_from("\u03BA"); break; case 11: slice_from("\u03BB"); break; case 12: slice_from("\u03BC"); break; case 13: slice_from("\u03BD"); break; case 14: slice_from("\u03BE"); break; case 15: slice_from("\u03BF"); break; case 16: slice_from("\u03C0"); break; case 17: slice_from("\u03C1"); break; case 18: slice_from("\u03C3"); break; case 19: slice_from("\u03C4"); break; case 20: slice_from("\u03C5"); break; case 21: slice_from("\u03C6"); break; case 22: slice_from("\u03C7"); break; case 23: slice_from("\u03C8"); break; case 24: slice_from("\u03C9"); break; case 25: if (cursor <= limit_backward) { break lab0; } cursor--; break; } continue; } cursor = limit - v_1; break; } return true; } private boolean r_step_1() { int among_var; ket = cursor; among_var = find_among_b(a_1); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: slice_from("\u03C6\u03B1"); break; case 2: slice_from("\u03C3\u03BA\u03B1"); break; case 3: slice_from("\u03BF\u03BB\u03BF"); break; case 4: slice_from("\u03C3\u03BF"); break; case 5: slice_from("\u03C4\u03B1\u03C4\u03BF"); break; case 6: slice_from("\u03BA\u03C1\u03B5"); break; case 7: slice_from("\u03C0\u03B5\u03C1"); break; case 8: slice_from("\u03C4\u03B5\u03C1"); break; case 9: slice_from("\u03C6\u03C9"); break; case 10: slice_from("\u03BA\u03B1\u03B8\u03B5\u03C3\u03C4"); break; case 11: slice_from("\u03B3\u03B5\u03B3\u03BF\u03BD"); break; } B_test1 = false; return true; } private boolean r_step_s1() { int among_var; ket = cursor; if (find_among_b(a_3) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; among_var = find_among_b(a_2); if (among_var == 0) { return false; } if (cursor > limit_backward) { return false; } switch (among_var) { case 1: slice_from("\u03B9"); break; case 2: slice_from("\u03B9\u03B6"); break; } return true; } private boolean r_step_s2() { ket = cursor; if (find_among_b(a_5) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_4) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03C9\u03BD"); return true; } private boolean r_step_s3() { int among_var; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; if (!(eq_s_b("\u03B9\u03C3\u03B1"))) { break lab1; } bra = cursor; if (cursor > limit_backward) { break lab1; } slice_from("\u03B9\u03C3"); break lab0; } cursor = limit - v_1; ket = cursor; } if (find_among_b(a_7) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; among_var = find_among_b(a_6); if (among_var == 0) { return false; } if (cursor > limit_backward) { return false; } switch (among_var) { case 1: slice_from("\u03B9"); break; case 2: slice_from("\u03B9\u03C3"); break; } return true; } private boolean r_step_s4() { ket = cursor; if (find_among_b(a_9) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_8) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B9"); return true; } private boolean r_step_s5() { int among_var; ket = cursor; if (find_among_b(a_11) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; among_var = find_among_b(a_10); if (among_var == 0) { return false; } if (cursor > limit_backward) { return false; } switch (among_var) { case 1: slice_from("\u03B9"); break; case 2: slice_from("\u03B9\u03C3\u03C4"); break; } return true; } private boolean r_step_s6() { int among_var; ket = cursor; if (find_among_b(a_14) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; bra = cursor; among_var = find_among_b(a_12); if (among_var == 0) { break lab1; } if (cursor > limit_backward) { break lab1; } switch (among_var) { case 1: slice_from("\u03B9\u03C3\u03BC"); break; case 2: slice_from("\u03B9"); break; } break lab0; } cursor = limit - v_1; ket = cursor; among_var = find_among_b(a_13); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: slice_from("\u03B1\u03B3\u03BD\u03C9\u03C3\u03C4"); break; case 2: slice_from("\u03B1\u03C4\u03BF\u03BC"); break; case 3: slice_from("\u03B3\u03BD\u03C9\u03C3\u03C4"); break; case 4: slice_from("\u03B5\u03B8\u03BD"); break; case 5: slice_from("\u03B5\u03BA\u03BB\u03B5\u03BA\u03C4"); break; case 6: slice_from("\u03C3\u03BA\u03B5\u03C0\u03C4"); break; case 7: slice_from("\u03C4\u03BF\u03C0"); break; case 8: slice_from("\u03B1\u03BB\u03B5\u03BE\u03B1\u03BD\u03B4\u03C1"); break; case 9: slice_from("\u03B2\u03C5\u03B6\u03B1\u03BD\u03C4"); break; case 10: slice_from("\u03B8\u03B5\u03B1\u03C4\u03C1"); break; } } return true; } private boolean r_step_s7() { ket = cursor; if (find_among_b(a_16) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_15) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B1\u03C1\u03B1\u03BA"); return true; } private boolean r_step_s8() { int among_var; ket = cursor; if (find_among_b(a_18) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; bra = cursor; among_var = find_among_b(a_17); if (among_var == 0) { break lab1; } if (cursor > limit_backward) { break lab1; } switch (among_var) { case 1: slice_from("\u03B1\u03BA"); break; case 2: slice_from("\u03B9\u03C4\u03C3"); break; } break lab0; } cursor = limit - v_1; ket = cursor; bra = cursor; if (!(eq_s_b("\u03BA\u03BF\u03C1"))) { return false; } slice_from("\u03B9\u03C4\u03C3"); } return true; } private boolean r_step_s9() { ket = cursor; if (find_among_b(a_21) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; bra = cursor; if (find_among_b(a_19) == 0) { break lab1; } if (cursor > limit_backward) { break lab1; } slice_from("\u03B9\u03B4"); break lab0; } cursor = limit - v_1; ket = cursor; bra = cursor; if (find_among_b(a_20) == 0) { return false; } slice_from("\u03B9\u03B4"); } return true; } private boolean r_step_s10() { ket = cursor; if (find_among_b(a_23) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_22) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B9\u03C3\u03BA"); return true; } private boolean r_step_2a() { ket = cursor; if (find_among_b(a_24) == 0) { return false; } bra = cursor; slice_del(); { int v_1 = limit - cursor; lab0: { if (find_among_b(a_25) == 0) { break lab0; } return false; } cursor = limit - v_1; } { int c = cursor; insert(cursor, cursor, "\u03B1\u03B4"); cursor = c; } return true; } private boolean r_step_2b() { ket = cursor; if (find_among_b(a_26) == 0) { return false; } bra = cursor; slice_del(); ket = cursor; bra = cursor; if (find_among_b(a_27) == 0) { return false; } slice_from("\u03B5\u03B4"); return true; } private boolean r_step_2c() { ket = cursor; if (find_among_b(a_28) == 0) { return false; } bra = cursor; slice_del(); ket = cursor; bra = cursor; if (find_among_b(a_29) == 0) { return false; } slice_from("\u03BF\u03C5\u03B4"); return true; } private boolean r_step_2d() { ket = cursor; if (find_among_b(a_30) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_31) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B5"); return true; } private boolean r_step_3() { ket = cursor; if (find_among_b(a_32) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (!(in_grouping_b(g_v, 945, 969))) { return false; } slice_from("\u03B9"); return true; } private boolean r_step_4() { ket = cursor; if (find_among_b(a_33) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; bra = cursor; if (!(in_grouping_b(g_v, 945, 969))) { break lab1; } slice_from("\u03B9\u03BA"); break lab0; } cursor = limit - v_1; ket = cursor; } bra = cursor; if (find_among_b(a_34) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B9\u03BA"); return true; } private boolean r_step_5a() { int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("\u03B1\u03B3\u03B1\u03BC\u03B5"))) { break lab0; } bra = cursor; if (cursor > limit_backward) { break lab0; } slice_from("\u03B1\u03B3\u03B1\u03BC"); } cursor = limit - v_1; int v_2 = limit - cursor; lab1: { ket = cursor; if (find_among_b(a_35) == 0) { break lab1; } bra = cursor; slice_del(); B_test1 = false; } cursor = limit - v_2; ket = cursor; if (!(eq_s_b("\u03B1\u03BC\u03B5"))) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_36) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B1\u03BC"); return true; } private boolean r_step_5b() { int v_1 = limit - cursor; lab0: { ket = cursor; if (find_among_b(a_38) == 0) { break lab0; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_37) == 0) { break lab0; } if (cursor > limit_backward) { break lab0; } slice_from("\u03B1\u03B3\u03B1\u03BD"); } cursor = limit - v_1; ket = cursor; if (!(eq_s_b("\u03B1\u03BD\u03B5"))) { return false; } bra = cursor; slice_del(); B_test1 = false; lab1: { int v_2 = limit - cursor; lab2: { ket = cursor; bra = cursor; if (!(in_grouping_b(g_v2, 945, 969))) { break lab2; } slice_from("\u03B1\u03BD"); break lab1; } cursor = limit - v_2; ket = cursor; } bra = cursor; if (find_among_b(a_39) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B1\u03BD"); return true; } private boolean r_step_5c() { int v_1 = limit - cursor; lab0: { ket = cursor; if (find_among_b(a_40) == 0) { break lab0; } bra = cursor; slice_del(); B_test1 = false; } cursor = limit - v_1; ket = cursor; if (!(eq_s_b("\u03B5\u03C4\u03B5"))) { return false; } bra = cursor; slice_del(); B_test1 = false; lab1: { int v_2 = limit - cursor; lab2: { ket = cursor; bra = cursor; if (!(in_grouping_b(g_v2, 945, 969))) { break lab2; } slice_from("\u03B5\u03C4"); break lab1; } cursor = limit - v_2; lab3: { ket = cursor; bra = cursor; if (find_among_b(a_41) == 0) { break lab3; } slice_from("\u03B5\u03C4"); break lab1; } cursor = limit - v_2; ket = cursor; } bra = cursor; if (find_among_b(a_42) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B5\u03C4"); return true; } private boolean r_step_5d() { ket = cursor; if (find_among_b(a_43) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; bra = cursor; if (!(eq_s_b("\u03B1\u03C1\u03C7"))) { break lab1; } if (cursor > limit_backward) { break lab1; } slice_from("\u03BF\u03BD\u03C4"); break lab0; } cursor = limit - v_1; ket = cursor; bra = cursor; if (!(eq_s_b("\u03BA\u03C1\u03B5"))) { return false; } slice_from("\u03C9\u03BD\u03C4"); } return true; } private boolean r_step_5e() { ket = cursor; if (find_among_b(a_44) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (!(eq_s_b("\u03BF\u03BD"))) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03BF\u03BC\u03B1\u03C3\u03C4"); return true; } private boolean r_step_5f() { int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("\u03B9\u03B5\u03C3\u03C4\u03B5"))) { break lab0; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_45) == 0) { break lab0; } if (cursor > limit_backward) { break lab0; } slice_from("\u03B9\u03B5\u03C3\u03C4"); } cursor = limit - v_1; ket = cursor; if (!(eq_s_b("\u03B5\u03C3\u03C4\u03B5"))) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_46) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B9\u03B5\u03C3\u03C4"); return true; } private boolean r_step_5g() { int v_1 = limit - cursor; lab0: { ket = cursor; if (find_among_b(a_47) == 0) { break lab0; } bra = cursor; slice_del(); B_test1 = false; } cursor = limit - v_1; ket = cursor; if (find_among_b(a_50) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab1: { int v_2 = limit - cursor; lab2: { ket = cursor; bra = cursor; if (find_among_b(a_48) == 0) { break lab2; } slice_from("\u03B7\u03BA"); break lab1; } cursor = limit - v_2; ket = cursor; bra = cursor; if (find_among_b(a_49) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B7\u03BA"); } return true; } private boolean r_step_5h() { ket = cursor; if (find_among_b(a_53) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; bra = cursor; if (find_among_b(a_51) == 0) { break lab1; } slice_from("\u03BF\u03C5\u03C3"); break lab0; } cursor = limit - v_1; ket = cursor; bra = cursor; if (find_among_b(a_52) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03BF\u03C5\u03C3"); } return true; } private boolean r_step_5i() { int among_var; ket = cursor; if (find_among_b(a_56) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; bra = cursor; if (!(eq_s_b("\u03BA\u03BF\u03BB\u03BB"))) { break lab1; } slice_from("\u03B1\u03B3"); break lab0; } cursor = limit - v_1; lab2: { int v_2 = limit - cursor; lab3: { ket = cursor; bra = cursor; among_var = find_among_b(a_54); if (among_var == 0) { break lab3; } switch (among_var) { case 1: slice_from("\u03B1\u03B3"); break; } break lab2; } cursor = limit - v_2; ket = cursor; bra = cursor; if (find_among_b(a_55) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B1\u03B3"); } } return true; } private boolean r_step_5j() { ket = cursor; if (find_among_b(a_57) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_58) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B7\u03C3"); return true; } private boolean r_step_5k() { ket = cursor; if (find_among_b(a_59) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_60) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03B7\u03C3\u03C4"); return true; } private boolean r_step_5l() { ket = cursor; if (find_among_b(a_61) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_62) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03BF\u03C5\u03BD"); return true; } private boolean r_step_5m() { ket = cursor; if (find_among_b(a_63) == 0) { return false; } bra = cursor; slice_del(); B_test1 = false; ket = cursor; bra = cursor; if (find_among_b(a_64) == 0) { return false; } if (cursor > limit_backward) { return false; } slice_from("\u03BF\u03C5\u03BC"); return true; } private boolean r_step_6() { int v_1 = limit - cursor; lab0: { ket = cursor; if (find_among_b(a_65) == 0) { break lab0; } bra = cursor; slice_from("\u03BC\u03B1"); } cursor = limit - v_1; if (!(B_test1)) { return false; } ket = cursor; if (find_among_b(a_66) == 0) { return false; } bra = cursor; slice_del(); return true; } private boolean r_step_7() { ket = cursor; if (find_among_b(a_67) == 0) { return false; } bra = cursor; slice_del(); return true; } @Override public boolean stem() { limit_backward = cursor; cursor = limit; int v_1 = limit - cursor; r_tolower(); cursor = limit - v_1; if (!r_has_min_length()) { return false; } B_test1 = true; int v_2 = limit - cursor; r_step_1(); cursor = limit - v_2; int v_3 = limit - cursor; r_step_s1(); cursor = limit - v_3; int v_4 = limit - cursor; r_step_s2(); cursor = limit - v_4; int v_5 = limit - cursor; r_step_s3(); cursor = limit - v_5; int v_6 = limit - cursor; r_step_s4(); cursor = limit - v_6; int v_7 = limit - cursor; r_step_s5(); cursor = limit - v_7; int v_8 = limit - cursor; r_step_s6(); cursor = limit - v_8; int v_9 = limit - cursor; r_step_s7(); cursor = limit - v_9; int v_10 = limit - cursor; r_step_s8(); cursor = limit - v_10; int v_11 = limit - cursor; r_step_s9(); cursor = limit - v_11; int v_12 = limit - cursor; r_step_s10(); cursor = limit - v_12; int v_13 = limit - cursor; r_step_2a(); cursor = limit - v_13; int v_14 = limit - cursor; r_step_2b(); cursor = limit - v_14; int v_15 = limit - cursor; r_step_2c(); cursor = limit - v_15; int v_16 = limit - cursor; r_step_2d(); cursor = limit - v_16; int v_17 = limit - cursor; r_step_3(); cursor = limit - v_17; int v_18 = limit - cursor; r_step_4(); cursor = limit - v_18; int v_19 = limit - cursor; r_step_5a(); cursor = limit - v_19; int v_20 = limit - cursor; r_step_5b(); cursor = limit - v_20; int v_21 = limit - cursor; r_step_5c(); cursor = limit - v_21; int v_22 = limit - cursor; r_step_5d(); cursor = limit - v_22; int v_23 = limit - cursor; r_step_5e(); cursor = limit - v_23; int v_24 = limit - cursor; r_step_5f(); cursor = limit - v_24; int v_25 = limit - cursor; r_step_5g(); cursor = limit - v_25; int v_26 = limit - cursor; r_step_5h(); cursor = limit - v_26; int v_27 = limit - cursor; r_step_5j(); cursor = limit - v_27; int v_28 = limit - cursor; r_step_5i(); cursor = limit - v_28; int v_29 = limit - cursor; r_step_5k(); cursor = limit - v_29; int v_30 = limit - cursor; r_step_5l(); cursor = limit - v_30; int v_31 = limit - cursor; r_step_5m(); cursor = limit - v_31; int v_32 = limit - cursor; r_step_6(); cursor = limit - v_32; int v_33 = limit - cursor; r_step_7(); cursor = limit - v_33; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof greekStemmer; } @Override public int hashCode() { return greekStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000164 15217274217 032617 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/hungarianStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/hungarianStemme0100644 0000000 0000000 00000036376 15217274217 034275 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class hungarianStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("cs", -1, -1), new Among("dzs", -1, -1), new Among("gy", -1, -1), new Among("ly", -1, -1), new Among("ny", -1, -1), new Among("sz", -1, -1), new Among("ty", -1, -1), new Among("zs", -1, -1) }; private final static Among[] a_1 = { new Among("\u00E1", -1, 1), new Among("\u00E9", -1, 2) }; private final static Among[] a_2 = { new Among("bb", -1, -1), new Among("cc", -1, -1), new Among("dd", -1, -1), new Among("ff", -1, -1), new Among("gg", -1, -1), new Among("jj", -1, -1), new Among("kk", -1, -1), new Among("ll", -1, -1), new Among("mm", -1, -1), new Among("nn", -1, -1), new Among("pp", -1, -1), new Among("rr", -1, -1), new Among("ccs", -1, -1), new Among("ss", -1, -1), new Among("zzs", -1, -1), new Among("tt", -1, -1), new Among("vv", -1, -1), new Among("ggy", -1, -1), new Among("lly", -1, -1), new Among("nny", -1, -1), new Among("tty", -1, -1), new Among("ssz", -1, -1), new Among("zz", -1, -1) }; private final static Among[] a_3 = { new Among("al", -1, 1), new Among("el", -1, 1) }; private final static Among[] a_4 = { new Among("ba", -1, -1), new Among("ra", -1, -1), new Among("be", -1, -1), new Among("re", -1, -1), new Among("ig", -1, -1), new Among("nak", -1, -1), new Among("nek", -1, -1), new Among("val", -1, -1), new Among("vel", -1, -1), new Among("ul", -1, -1), new Among("n\u00E1l", -1, -1), new Among("n\u00E9l", -1, -1), new Among("b\u00F3l", -1, -1), new Among("r\u00F3l", -1, -1), new Among("t\u00F3l", -1, -1), new Among("\u00FCl", -1, -1), new Among("b\u0151l", -1, -1), new Among("r\u0151l", -1, -1), new Among("t\u0151l", -1, -1), new Among("n", -1, -1), new Among("an", 19, -1), new Among("ban", 20, -1), new Among("en", 19, -1), new Among("ben", 22, -1), new Among("k\u00E9ppen", 22, -1), new Among("on", 19, -1), new Among("\u00F6n", 19, -1), new Among("k\u00E9pp", -1, -1), new Among("kor", -1, -1), new Among("t", -1, -1), new Among("at", 29, -1), new Among("et", 29, -1), new Among("k\u00E9nt", 29, -1), new Among("ank\u00E9nt", 32, -1), new Among("enk\u00E9nt", 32, -1), new Among("onk\u00E9nt", 32, -1), new Among("ot", 29, -1), new Among("\u00E9rt", 29, -1), new Among("\u00F6t", 29, -1), new Among("hez", -1, -1), new Among("hoz", -1, -1), new Among("h\u00F6z", -1, -1), new Among("v\u00E1", -1, -1), new Among("v\u00E9", -1, -1) }; private final static Among[] a_5 = { new Among("\u00E1n", -1, 2), new Among("\u00E9n", -1, 1), new Among("\u00E1nk\u00E9nt", -1, 2) }; private final static Among[] a_6 = { new Among("stul", -1, 1), new Among("astul", 0, 1), new Among("\u00E1stul", 0, 2), new Among("st\u00FCl", -1, 1), new Among("est\u00FCl", 3, 1), new Among("\u00E9st\u00FCl", 3, 3) }; private final static Among[] a_7 = { new Among("\u00E1", -1, 1), new Among("\u00E9", -1, 1) }; private final static Among[] a_8 = { new Among("k", -1, 3), new Among("ak", 0, 3), new Among("ek", 0, 3), new Among("ok", 0, 3), new Among("\u00E1k", 0, 1), new Among("\u00E9k", 0, 2), new Among("\u00F6k", 0, 3) }; private final static Among[] a_9 = { new Among("\u00E9i", -1, 1), new Among("\u00E1\u00E9i", 0, 3), new Among("\u00E9\u00E9i", 0, 2), new Among("\u00E9", -1, 1), new Among("k\u00E9", 3, 1), new Among("ak\u00E9", 4, 1), new Among("ek\u00E9", 4, 1), new Among("ok\u00E9", 4, 1), new Among("\u00E1k\u00E9", 4, 3), new Among("\u00E9k\u00E9", 4, 2), new Among("\u00F6k\u00E9", 4, 1), new Among("\u00E9\u00E9", 3, 2) }; private final static Among[] a_10 = { new Among("a", -1, 1), new Among("ja", 0, 1), new Among("d", -1, 1), new Among("ad", 2, 1), new Among("ed", 2, 1), new Among("od", 2, 1), new Among("\u00E1d", 2, 2), new Among("\u00E9d", 2, 3), new Among("\u00F6d", 2, 1), new Among("e", -1, 1), new Among("je", 9, 1), new Among("nk", -1, 1), new Among("unk", 11, 1), new Among("\u00E1nk", 11, 2), new Among("\u00E9nk", 11, 3), new Among("\u00FCnk", 11, 1), new Among("uk", -1, 1), new Among("juk", 16, 1), new Among("\u00E1juk", 17, 2), new Among("\u00FCk", -1, 1), new Among("j\u00FCk", 19, 1), new Among("\u00E9j\u00FCk", 20, 3), new Among("m", -1, 1), new Among("am", 22, 1), new Among("em", 22, 1), new Among("om", 22, 1), new Among("\u00E1m", 22, 2), new Among("\u00E9m", 22, 3), new Among("o", -1, 1), new Among("\u00E1", -1, 2), new Among("\u00E9", -1, 3) }; private final static Among[] a_11 = { new Among("id", -1, 1), new Among("aid", 0, 1), new Among("jaid", 1, 1), new Among("eid", 0, 1), new Among("jeid", 3, 1), new Among("\u00E1id", 0, 2), new Among("\u00E9id", 0, 3), new Among("i", -1, 1), new Among("ai", 7, 1), new Among("jai", 8, 1), new Among("ei", 7, 1), new Among("jei", 10, 1), new Among("\u00E1i", 7, 2), new Among("\u00E9i", 7, 3), new Among("itek", -1, 1), new Among("eitek", 14, 1), new Among("jeitek", 15, 1), new Among("\u00E9itek", 14, 3), new Among("ik", -1, 1), new Among("aik", 18, 1), new Among("jaik", 19, 1), new Among("eik", 18, 1), new Among("jeik", 21, 1), new Among("\u00E1ik", 18, 2), new Among("\u00E9ik", 18, 3), new Among("ink", -1, 1), new Among("aink", 25, 1), new Among("jaink", 26, 1), new Among("eink", 25, 1), new Among("jeink", 28, 1), new Among("\u00E1ink", 25, 2), new Among("\u00E9ink", 25, 3), new Among("aitok", -1, 1), new Among("jaitok", 32, 1), new Among("\u00E1itok", -1, 2), new Among("im", -1, 1), new Among("aim", 35, 1), new Among("jaim", 36, 1), new Among("eim", 35, 1), new Among("jeim", 38, 1), new Among("\u00E1im", 35, 2), new Among("\u00E9im", 35, 3) }; private static final char[] g_v = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17, 36, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1}; private int I_p1; private boolean r_mark_regions() { I_p1 = limit; lab0: { int v_1 = cursor; lab1: { if (!(in_grouping(g_v, 97, 369))) { break lab1; } golab2: while (true) { int v_2 = cursor; lab3: { if (!(out_grouping(g_v, 97, 369))) { break lab3; } cursor = v_2; break golab2; } cursor = v_2; if (cursor >= limit) { break lab1; } cursor++; } lab4: { int v_3 = cursor; lab5: { if (find_among(a_0) == 0) { break lab5; } break lab4; } cursor = v_3; if (cursor >= limit) { break lab1; } cursor++; } I_p1 = cursor; break lab0; } cursor = v_1; if (!(out_grouping(g_v, 97, 369))) { return false; } golab6: while (true) { lab7: { if (!(in_grouping(g_v, 97, 369))) { break lab7; } break golab6; } if (cursor >= limit) { return false; } cursor++; } I_p1 = cursor; } return true; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_v_ending() { int among_var; ket = cursor; among_var = find_among_b(a_1); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("a"); break; case 2: slice_from("e"); break; } return true; } private boolean r_double() { int v_1 = limit - cursor; if (find_among_b(a_2) == 0) { return false; } cursor = limit - v_1; return true; } private boolean r_undouble() { if (cursor <= limit_backward) { return false; } cursor--; ket = cursor; { int c = cursor - 1; if (c < limit_backward) { return false; } cursor = c; } bra = cursor; slice_del(); return true; } private boolean r_instrum() { ket = cursor; if (find_among_b(a_3) == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } if (!r_double()) { return false; } slice_del(); if (!r_undouble()) { return false; } return true; } private boolean r_case() { ket = cursor; if (find_among_b(a_4) == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } slice_del(); if (!r_v_ending()) { return false; } return true; } private boolean r_case_special() { int among_var; ket = cursor; among_var = find_among_b(a_5); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("e"); break; case 2: slice_from("a"); break; } return true; } private boolean r_case_other() { int among_var; ket = cursor; among_var = find_among_b(a_6); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: slice_from("a"); break; case 3: slice_from("e"); break; } return true; } private boolean r_factive() { ket = cursor; if (find_among_b(a_7) == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } if (!r_double()) { return false; } slice_del(); if (!r_undouble()) { return false; } return true; } private boolean r_plural() { int among_var; ket = cursor; among_var = find_among_b(a_8); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("a"); break; case 2: slice_from("e"); break; case 3: slice_del(); break; } return true; } private boolean r_owned() { int among_var; ket = cursor; among_var = find_among_b(a_9); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: slice_from("e"); break; case 3: slice_from("a"); break; } return true; } private boolean r_sing_owner() { int among_var; ket = cursor; among_var = find_among_b(a_10); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: slice_from("a"); break; case 3: slice_from("e"); break; } return true; } private boolean r_plur_owner() { int among_var; ket = cursor; among_var = find_among_b(a_11); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: slice_from("a"); break; case 3: slice_from("e"); break; } return true; } @Override public boolean stem() { int v_1 = cursor; r_mark_regions(); cursor = v_1; limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_instrum(); cursor = limit - v_2; int v_3 = limit - cursor; r_case(); cursor = limit - v_3; int v_4 = limit - cursor; r_case_special(); cursor = limit - v_4; int v_5 = limit - cursor; r_case_other(); cursor = limit - v_5; int v_6 = limit - cursor; r_factive(); cursor = limit - v_6; int v_7 = limit - cursor; r_owned(); cursor = limit - v_7; int v_8 = limit - cursor; r_sing_owner(); cursor = limit - v_8; int v_9 = limit - cursor; r_plur_owner(); cursor = limit - v_9; int v_10 = limit - cursor; r_plural(); cursor = limit - v_10; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof hungarianStemmer; } @Override public int hashCode() { return hungarianStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000165 15217274217 032620 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/indonesianStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/indonesianStemm0100644 0000000 0000000 00000022417 15217274217 034272 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class indonesianStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private static final java.lang.invoke.MethodHandles.Lookup methodObject = java.lang.invoke.MethodHandles.lookup(); private final static Among[] a_0 = { new Among("kah", -1, 1), new Among("lah", -1, 1), new Among("pun", -1, 1) }; private final static Among[] a_1 = { new Among("nya", -1, 1), new Among("ku", -1, 1), new Among("mu", -1, 1) }; private final static Among[] a_2 = { new Among("i", -1, 1, "r_SUFFIX_I_OK", methodObject), new Among("an", -1, 1, "r_SUFFIX_AN_OK", methodObject), new Among("kan", 1, 1, "r_SUFFIX_KAN_OK", methodObject) }; private final static Among[] a_3 = { new Among("di", -1, 1), new Among("ke", -1, 2), new Among("me", -1, 1), new Among("mem", 2, 5), new Among("men", 2, 1), new Among("meng", 4, 1), new Among("meny", 4, 3, "r_VOWEL", methodObject), new Among("pem", -1, 6), new Among("pen", -1, 2), new Among("peng", 8, 2), new Among("peny", 8, 4, "r_VOWEL", methodObject), new Among("ter", -1, 1) }; private final static Among[] a_4 = { new Among("be", -1, 3, "r_KER", methodObject), new Among("belajar", 0, 4), new Among("ber", 0, 3), new Among("pe", -1, 1), new Among("pelajar", 3, 2), new Among("per", 3, 1) }; private static final char[] g_vowel = {17, 65, 16}; private int I_prefix; private int I_measure; private boolean r_remove_particle() { ket = cursor; if (find_among_b(a_0) == 0) { return false; } bra = cursor; slice_del(); I_measure -= 1; return true; } private boolean r_remove_possessive_pronoun() { ket = cursor; if (find_among_b(a_1) == 0) { return false; } bra = cursor; slice_del(); I_measure -= 1; return true; } private boolean r_SUFFIX_KAN_OK() { if (I_prefix == 3) { return false; } if (I_prefix == 2) { return false; } return true; } private boolean r_SUFFIX_AN_OK() { return I_prefix != 1; } private boolean r_SUFFIX_I_OK() { if (I_prefix > 2) { return false; } { int v_1 = limit - cursor; lab0: { if (!(eq_s_b("s"))) { break lab0; } return false; } cursor = limit - v_1; } return true; } private boolean r_remove_suffix() { ket = cursor; if (find_among_b(a_2) == 0) { return false; } bra = cursor; slice_del(); I_measure -= 1; return true; } private boolean r_VOWEL() { if (!(in_grouping(g_vowel, 97, 117))) { return false; } return true; } private boolean r_KER() { if (!(out_grouping(g_vowel, 97, 117))) { return false; } if (!(eq_s("er"))) { return false; } return true; } private boolean r_remove_first_order_prefix() { int among_var; bra = cursor; among_var = find_among(a_3); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: slice_del(); I_prefix = 1; I_measure -= 1; break; case 2: slice_del(); I_prefix = 3; I_measure -= 1; break; case 3: I_prefix = 1; slice_from("s"); I_measure -= 1; break; case 4: I_prefix = 3; slice_from("s"); I_measure -= 1; break; case 5: I_prefix = 1; I_measure -= 1; lab0: { int v_1 = cursor; lab1: { int v_2 = cursor; if (!(in_grouping(g_vowel, 97, 117))) { break lab1; } cursor = v_2; slice_from("p"); break lab0; } cursor = v_1; slice_del(); } break; case 6: I_prefix = 3; I_measure -= 1; lab2: { int v_3 = cursor; lab3: { int v_4 = cursor; if (!(in_grouping(g_vowel, 97, 117))) { break lab3; } cursor = v_4; slice_from("p"); break lab2; } cursor = v_3; slice_del(); } break; } return true; } private boolean r_remove_second_order_prefix() { int among_var; bra = cursor; among_var = find_among(a_4); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: slice_del(); I_prefix = 2; I_measure -= 1; break; case 2: slice_from("ajar"); I_measure -= 1; break; case 3: slice_del(); I_prefix = 4; I_measure -= 1; break; case 4: slice_from("ajar"); I_prefix = 4; I_measure -= 1; break; } return true; } @Override public boolean stem() { I_measure = 0; int v_1 = cursor; lab0: { while (true) { int v_2 = cursor; lab1: { golab2: while (true) { lab3: { if (!(in_grouping(g_vowel, 97, 117))) { break lab3; } break golab2; } if (cursor >= limit) { break lab1; } cursor++; } I_measure += 1; continue; } cursor = v_2; break; } } cursor = v_1; if (I_measure <= 2) { return false; } I_prefix = 0; limit_backward = cursor; cursor = limit; int v_4 = limit - cursor; r_remove_particle(); cursor = limit - v_4; if (I_measure <= 2) { return false; } int v_5 = limit - cursor; r_remove_possessive_pronoun(); cursor = limit - v_5; cursor = limit_backward; if (I_measure <= 2) { return false; } lab4: { int v_6 = cursor; lab5: { int v_7 = cursor; if (!r_remove_first_order_prefix()) { break lab5; } int v_8 = cursor; lab6: { int v_9 = cursor; if (I_measure <= 2) { break lab6; } limit_backward = cursor; cursor = limit; if (!r_remove_suffix()) { break lab6; } cursor = limit_backward; cursor = v_9; if (I_measure <= 2) { break lab6; } if (!r_remove_second_order_prefix()) { break lab6; } } cursor = v_8; cursor = v_7; break lab4; } cursor = v_6; int v_10 = cursor; r_remove_second_order_prefix(); cursor = v_10; int v_11 = cursor; lab7: { if (I_measure <= 2) { break lab7; } limit_backward = cursor; cursor = limit; if (!r_remove_suffix()) { break lab7; } cursor = limit_backward; } cursor = v_11; } return true; } @Override public boolean equals(Object o) { return o instanceof indonesianStemmer; } @Override public int hashCode() { return indonesianStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000160 15217274217 032613 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/irishStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/irishStemmer.ja0100644 0000000 0000000 00000022317 15217274217 034200 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class irishStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("b'", -1, 1), new Among("bh", -1, 4), new Among("bhf", 1, 2), new Among("bp", -1, 8), new Among("ch", -1, 5), new Among("d'", -1, 1), new Among("d'fh", 5, 2), new Among("dh", -1, 6), new Among("dt", -1, 9), new Among("fh", -1, 2), new Among("gc", -1, 5), new Among("gh", -1, 7), new Among("h-", -1, 1), new Among("m'", -1, 1), new Among("mb", -1, 4), new Among("mh", -1, 10), new Among("n-", -1, 1), new Among("nd", -1, 6), new Among("ng", -1, 7), new Among("ph", -1, 8), new Among("sh", -1, 3), new Among("t-", -1, 1), new Among("th", -1, 9), new Among("ts", -1, 3) }; private final static Among[] a_1 = { new Among("\u00EDochta", -1, 1), new Among("a\u00EDochta", 0, 1), new Among("ire", -1, 2), new Among("aire", 2, 2), new Among("abh", -1, 1), new Among("eabh", 4, 1), new Among("ibh", -1, 1), new Among("aibh", 6, 1), new Among("amh", -1, 1), new Among("eamh", 8, 1), new Among("imh", -1, 1), new Among("aimh", 10, 1), new Among("\u00EDocht", -1, 1), new Among("a\u00EDocht", 12, 1), new Among("ir\u00ED", -1, 2), new Among("air\u00ED", 14, 2) }; private final static Among[] a_2 = { new Among("\u00F3ideacha", -1, 6), new Among("patacha", -1, 5), new Among("achta", -1, 1), new Among("arcachta", 2, 2), new Among("eachta", 2, 1), new Among("grafa\u00EDochta", -1, 4), new Among("paite", -1, 5), new Among("ach", -1, 1), new Among("each", 7, 1), new Among("\u00F3ideach", 8, 6), new Among("gineach", 8, 3), new Among("patach", 7, 5), new Among("grafa\u00EDoch", -1, 4), new Among("pataigh", -1, 5), new Among("\u00F3idigh", -1, 6), new Among("acht\u00FAil", -1, 1), new Among("eacht\u00FAil", 15, 1), new Among("gineas", -1, 3), new Among("ginis", -1, 3), new Among("acht", -1, 1), new Among("arcacht", 19, 2), new Among("eacht", 19, 1), new Among("grafa\u00EDocht", -1, 4), new Among("arcachta\u00ED", -1, 2), new Among("grafa\u00EDochta\u00ED", -1, 4) }; private final static Among[] a_3 = { new Among("imid", -1, 1), new Among("aimid", 0, 1), new Among("\u00EDmid", -1, 1), new Among("a\u00EDmid", 2, 1), new Among("adh", -1, 2), new Among("eadh", 4, 2), new Among("faidh", -1, 1), new Among("fidh", -1, 1), new Among("\u00E1il", -1, 2), new Among("ain", -1, 2), new Among("tear", -1, 2), new Among("tar", -1, 2) }; private static final char[] g_v = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17, 4, 2}; private int I_p2; private int I_p1; private int I_pV; private boolean r_mark_regions() { I_pV = limit; I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { golab1: while (true) { lab2: { if (!(in_grouping(g_v, 97, 250))) { break lab2; } break golab1; } if (cursor >= limit) { break lab0; } cursor++; } I_pV = cursor; golab3: while (true) { lab4: { if (!(out_grouping(g_v, 97, 250))) { break lab4; } break golab3; } if (cursor >= limit) { break lab0; } cursor++; } I_p1 = cursor; golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 250))) { break lab6; } break golab5; } if (cursor >= limit) { break lab0; } cursor++; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 250))) { break lab8; } break golab7; } if (cursor >= limit) { break lab0; } cursor++; } I_p2 = cursor; } cursor = v_1; return true; } private boolean r_initial_morph() { int among_var; bra = cursor; among_var = find_among(a_0); if (among_var == 0) { return false; } ket = cursor; switch (among_var) { case 1: slice_del(); break; case 2: slice_from("f"); break; case 3: slice_from("s"); break; case 4: slice_from("b"); break; case 5: slice_from("c"); break; case 6: slice_from("d"); break; case 7: slice_from("g"); break; case 8: slice_from("p"); break; case 9: slice_from("t"); break; case 10: slice_from("m"); break; } return true; } private boolean r_RV() { return I_pV <= cursor; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_noun_sfx() { int among_var; ket = cursor; among_var = find_among_b(a_1); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R1()) { return false; } slice_del(); break; case 2: if (!r_R2()) { return false; } slice_del(); break; } return true; } private boolean r_deriv() { int among_var; ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { return false; } slice_del(); break; case 2: slice_from("arc"); break; case 3: slice_from("gin"); break; case 4: slice_from("graf"); break; case 5: slice_from("paite"); break; case 6: slice_from("\u00F3id"); break; } return true; } private boolean r_verb_sfx() { int among_var; ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_RV()) { return false; } slice_del(); break; case 2: if (!r_R1()) { return false; } slice_del(); break; } return true; } @Override public boolean stem() { int v_1 = cursor; r_initial_morph(); cursor = v_1; r_mark_regions(); limit_backward = cursor; cursor = limit; int v_3 = limit - cursor; r_noun_sfx(); cursor = limit - v_3; int v_4 = limit - cursor; r_deriv(); cursor = limit - v_4; int v_5 = limit - cursor; r_verb_sfx(); cursor = limit - v_5; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof irishStemmer; } @Override public int hashCode() { return irishStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/italianStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/italianStemmer.0100644 0000000 0000000 00000053021 15217274217 034164 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class italianStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("", -1, 7), new Among("qu", 0, 6), new Among("\u00E1", 0, 1), new Among("\u00E9", 0, 2), new Among("\u00ED", 0, 3), new Among("\u00F3", 0, 4), new Among("\u00FA", 0, 5) }; private final static Among[] a_1 = { new Among("", -1, 3), new Among("I", 0, 1), new Among("U", 0, 2) }; private final static Among[] a_2 = { new Among("la", -1, -1), new Among("cela", 0, -1), new Among("gliela", 0, -1), new Among("mela", 0, -1), new Among("tela", 0, -1), new Among("vela", 0, -1), new Among("le", -1, -1), new Among("cele", 6, -1), new Among("gliele", 6, -1), new Among("mele", 6, -1), new Among("tele", 6, -1), new Among("vele", 6, -1), new Among("ne", -1, -1), new Among("cene", 12, -1), new Among("gliene", 12, -1), new Among("mene", 12, -1), new Among("sene", 12, -1), new Among("tene", 12, -1), new Among("vene", 12, -1), new Among("ci", -1, -1), new Among("li", -1, -1), new Among("celi", 20, -1), new Among("glieli", 20, -1), new Among("meli", 20, -1), new Among("teli", 20, -1), new Among("veli", 20, -1), new Among("gli", 20, -1), new Among("mi", -1, -1), new Among("si", -1, -1), new Among("ti", -1, -1), new Among("vi", -1, -1), new Among("lo", -1, -1), new Among("celo", 31, -1), new Among("glielo", 31, -1), new Among("melo", 31, -1), new Among("telo", 31, -1), new Among("velo", 31, -1) }; private final static Among[] a_3 = { new Among("ando", -1, 1), new Among("endo", -1, 1), new Among("ar", -1, 2), new Among("er", -1, 2), new Among("ir", -1, 2) }; private final static Among[] a_4 = { new Among("ic", -1, -1), new Among("abil", -1, -1), new Among("os", -1, -1), new Among("iv", -1, 1) }; private final static Among[] a_5 = { new Among("ic", -1, 1), new Among("abil", -1, 1), new Among("iv", -1, 1) }; private final static Among[] a_6 = { new Among("ica", -1, 1), new Among("logia", -1, 3), new Among("osa", -1, 1), new Among("ista", -1, 1), new Among("iva", -1, 9), new Among("anza", -1, 1), new Among("enza", -1, 5), new Among("ice", -1, 1), new Among("atrice", 7, 1), new Among("iche", -1, 1), new Among("logie", -1, 3), new Among("abile", -1, 1), new Among("ibile", -1, 1), new Among("usione", -1, 4), new Among("azione", -1, 2), new Among("uzione", -1, 4), new Among("atore", -1, 2), new Among("ose", -1, 1), new Among("ante", -1, 1), new Among("mente", -1, 1), new Among("amente", 19, 7), new Among("iste", -1, 1), new Among("ive", -1, 9), new Among("anze", -1, 1), new Among("enze", -1, 5), new Among("ici", -1, 1), new Among("atrici", 25, 1), new Among("ichi", -1, 1), new Among("abili", -1, 1), new Among("ibili", -1, 1), new Among("ismi", -1, 1), new Among("usioni", -1, 4), new Among("azioni", -1, 2), new Among("uzioni", -1, 4), new Among("atori", -1, 2), new Among("osi", -1, 1), new Among("anti", -1, 1), new Among("amenti", -1, 6), new Among("imenti", -1, 6), new Among("isti", -1, 1), new Among("ivi", -1, 9), new Among("ico", -1, 1), new Among("ismo", -1, 1), new Among("oso", -1, 1), new Among("amento", -1, 6), new Among("imento", -1, 6), new Among("ivo", -1, 9), new Among("it\u00E0", -1, 8), new Among("ist\u00E0", -1, 1), new Among("ist\u00E8", -1, 1), new Among("ist\u00EC", -1, 1) }; private final static Among[] a_7 = { new Among("isca", -1, 1), new Among("enda", -1, 1), new Among("ata", -1, 1), new Among("ita", -1, 1), new Among("uta", -1, 1), new Among("ava", -1, 1), new Among("eva", -1, 1), new Among("iva", -1, 1), new Among("erebbe", -1, 1), new Among("irebbe", -1, 1), new Among("isce", -1, 1), new Among("ende", -1, 1), new Among("are", -1, 1), new Among("ere", -1, 1), new Among("ire", -1, 1), new Among("asse", -1, 1), new Among("ate", -1, 1), new Among("avate", 16, 1), new Among("evate", 16, 1), new Among("ivate", 16, 1), new Among("ete", -1, 1), new Among("erete", 20, 1), new Among("irete", 20, 1), new Among("ite", -1, 1), new Among("ereste", -1, 1), new Among("ireste", -1, 1), new Among("ute", -1, 1), new Among("erai", -1, 1), new Among("irai", -1, 1), new Among("isci", -1, 1), new Among("endi", -1, 1), new Among("erei", -1, 1), new Among("irei", -1, 1), new Among("assi", -1, 1), new Among("ati", -1, 1), new Among("iti", -1, 1), new Among("eresti", -1, 1), new Among("iresti", -1, 1), new Among("uti", -1, 1), new Among("avi", -1, 1), new Among("evi", -1, 1), new Among("ivi", -1, 1), new Among("isco", -1, 1), new Among("ando", -1, 1), new Among("endo", -1, 1), new Among("Yamo", -1, 1), new Among("iamo", -1, 1), new Among("avamo", -1, 1), new Among("evamo", -1, 1), new Among("ivamo", -1, 1), new Among("eremo", -1, 1), new Among("iremo", -1, 1), new Among("assimo", -1, 1), new Among("ammo", -1, 1), new Among("emmo", -1, 1), new Among("eremmo", 54, 1), new Among("iremmo", 54, 1), new Among("immo", -1, 1), new Among("ano", -1, 1), new Among("iscano", 58, 1), new Among("avano", 58, 1), new Among("evano", 58, 1), new Among("ivano", 58, 1), new Among("eranno", -1, 1), new Among("iranno", -1, 1), new Among("ono", -1, 1), new Among("iscono", 65, 1), new Among("arono", 65, 1), new Among("erono", 65, 1), new Among("irono", 65, 1), new Among("erebbero", -1, 1), new Among("irebbero", -1, 1), new Among("assero", -1, 1), new Among("essero", -1, 1), new Among("issero", -1, 1), new Among("ato", -1, 1), new Among("ito", -1, 1), new Among("uto", -1, 1), new Among("avo", -1, 1), new Among("evo", -1, 1), new Among("ivo", -1, 1), new Among("ar", -1, 1), new Among("ir", -1, 1), new Among("er\u00E0", -1, 1), new Among("ir\u00E0", -1, 1), new Among("er\u00F2", -1, 1), new Among("ir\u00F2", -1, 1) }; private static final char[] g_v = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 8, 2, 1}; private static final char[] g_AEIO = {17, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 8, 2}; private static final char[] g_CG = {17}; private int I_p2; private int I_p1; private int I_pV; private boolean r_prelude() { int among_var; int v_1 = cursor; while (true) { int v_2 = cursor; lab0: { bra = cursor; among_var = find_among(a_0); ket = cursor; switch (among_var) { case 1: slice_from("\u00E0"); break; case 2: slice_from("\u00E8"); break; case 3: slice_from("\u00EC"); break; case 4: slice_from("\u00F2"); break; case 5: slice_from("\u00F9"); break; case 6: slice_from("qU"); break; case 7: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_2; break; } cursor = v_1; while (true) { int v_3 = cursor; lab1: { golab2: while (true) { int v_4 = cursor; lab3: { if (!(in_grouping(g_v, 97, 249))) { break lab3; } bra = cursor; lab4: { int v_5 = cursor; lab5: { if (!(eq_s("u"))) { break lab5; } ket = cursor; if (!(in_grouping(g_v, 97, 249))) { break lab5; } slice_from("U"); break lab4; } cursor = v_5; if (!(eq_s("i"))) { break lab3; } ket = cursor; if (!(in_grouping(g_v, 97, 249))) { break lab3; } slice_from("I"); } cursor = v_4; break golab2; } cursor = v_4; if (cursor >= limit) { break lab1; } cursor++; } continue; } cursor = v_3; break; } return true; } private boolean r_mark_regions() { I_pV = limit; I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { lab1: { int v_2 = cursor; lab2: { if (!(in_grouping(g_v, 97, 249))) { break lab2; } lab3: { int v_3 = cursor; lab4: { if (!(out_grouping(g_v, 97, 249))) { break lab4; } golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 249))) { break lab6; } break golab5; } if (cursor >= limit) { break lab4; } cursor++; } break lab3; } cursor = v_3; if (!(in_grouping(g_v, 97, 249))) { break lab2; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 249))) { break lab8; } break golab7; } if (cursor >= limit) { break lab2; } cursor++; } } break lab1; } cursor = v_2; if (!(out_grouping(g_v, 97, 249))) { break lab0; } lab9: { int v_6 = cursor; lab10: { if (!(out_grouping(g_v, 97, 249))) { break lab10; } golab11: while (true) { lab12: { if (!(in_grouping(g_v, 97, 249))) { break lab12; } break golab11; } if (cursor >= limit) { break lab10; } cursor++; } break lab9; } cursor = v_6; if (!(in_grouping(g_v, 97, 249))) { break lab0; } if (cursor >= limit) { break lab0; } cursor++; } } I_pV = cursor; } cursor = v_1; int v_8 = cursor; lab13: { golab14: while (true) { lab15: { if (!(in_grouping(g_v, 97, 249))) { break lab15; } break golab14; } if (cursor >= limit) { break lab13; } cursor++; } golab16: while (true) { lab17: { if (!(out_grouping(g_v, 97, 249))) { break lab17; } break golab16; } if (cursor >= limit) { break lab13; } cursor++; } I_p1 = cursor; golab18: while (true) { lab19: { if (!(in_grouping(g_v, 97, 249))) { break lab19; } break golab18; } if (cursor >= limit) { break lab13; } cursor++; } golab20: while (true) { lab21: { if (!(out_grouping(g_v, 97, 249))) { break lab21; } break golab20; } if (cursor >= limit) { break lab13; } cursor++; } I_p2 = cursor; } cursor = v_8; return true; } private boolean r_postlude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_1); ket = cursor; switch (among_var) { case 1: slice_from("i"); break; case 2: slice_from("u"); break; case 3: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_RV() { return I_pV <= cursor; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_attached_pronoun() { int among_var; ket = cursor; if (find_among_b(a_2) == 0) { return false; } bra = cursor; among_var = find_among_b(a_3); if (among_var == 0) { return false; } if (!r_RV()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: slice_from("e"); break; } return true; } private boolean r_standard_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_6); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { return false; } slice_del(); break; case 2: if (!r_R2()) { return false; } slice_del(); int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("ic"))) { cursor = limit - v_1; break lab0; } bra = cursor; if (!r_R2()) { cursor = limit - v_1; break lab0; } slice_del(); } break; case 3: if (!r_R2()) { return false; } slice_from("log"); break; case 4: if (!r_R2()) { return false; } slice_from("u"); break; case 5: if (!r_R2()) { return false; } slice_from("ente"); break; case 6: if (!r_RV()) { return false; } slice_del(); break; case 7: if (!r_R1()) { return false; } slice_del(); int v_2 = limit - cursor; lab1: { ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { cursor = limit - v_2; break lab1; } bra = cursor; if (!r_R2()) { cursor = limit - v_2; break lab1; } slice_del(); switch (among_var) { case 1: ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_2; break lab1; } bra = cursor; if (!r_R2()) { cursor = limit - v_2; break lab1; } slice_del(); break; } } break; case 8: if (!r_R2()) { return false; } slice_del(); int v_3 = limit - cursor; lab2: { ket = cursor; if (find_among_b(a_5) == 0) { cursor = limit - v_3; break lab2; } bra = cursor; if (!r_R2()) { cursor = limit - v_3; break lab2; } slice_del(); } break; case 9: if (!r_R2()) { return false; } slice_del(); int v_4 = limit - cursor; lab3: { ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_4; break lab3; } bra = cursor; if (!r_R2()) { cursor = limit - v_4; break lab3; } slice_del(); ket = cursor; if (!(eq_s_b("ic"))) { cursor = limit - v_4; break lab3; } bra = cursor; if (!r_R2()) { cursor = limit - v_4; break lab3; } slice_del(); } break; } return true; } private boolean r_verb_suffix() { if (cursor < I_pV) { return false; } int v_2 = limit_backward; limit_backward = I_pV; ket = cursor; if (find_among_b(a_7) == 0) { limit_backward = v_2; return false; } bra = cursor; slice_del(); limit_backward = v_2; return true; } private boolean r_vowel_suffix() { int v_1 = limit - cursor; lab0: { ket = cursor; if (!(in_grouping_b(g_AEIO, 97, 242))) { cursor = limit - v_1; break lab0; } bra = cursor; if (!r_RV()) { cursor = limit - v_1; break lab0; } slice_del(); ket = cursor; if (!(eq_s_b("i"))) { cursor = limit - v_1; break lab0; } bra = cursor; if (!r_RV()) { cursor = limit - v_1; break lab0; } slice_del(); } int v_2 = limit - cursor; lab1: { ket = cursor; if (!(eq_s_b("h"))) { cursor = limit - v_2; break lab1; } bra = cursor; if (!(in_grouping_b(g_CG, 99, 103))) { cursor = limit - v_2; break lab1; } if (!r_RV()) { cursor = limit - v_2; break lab1; } slice_del(); } return true; } private boolean r_exceptions() { bra = cursor; if (!(eq_s("divano"))) { return false; } if (cursor < limit) { return false; } ket = cursor; slice_from("divan"); return true; } @Override public boolean stem() { lab0: { int v_1 = cursor; lab1: { if (!r_exceptions()) { break lab1; } break lab0; } cursor = v_1; int v_2 = cursor; r_prelude(); cursor = v_2; r_mark_regions(); limit_backward = cursor; cursor = limit; int v_4 = limit - cursor; r_attached_pronoun(); cursor = limit - v_4; int v_5 = limit - cursor; lab2: { lab3: { int v_6 = limit - cursor; lab4: { if (!r_standard_suffix()) { break lab4; } break lab3; } cursor = limit - v_6; if (!r_verb_suffix()) { break lab2; } } } cursor = limit - v_5; int v_7 = limit - cursor; r_vowel_suffix(); cursor = limit - v_7; cursor = limit_backward; int v_8 = cursor; r_postlude(); cursor = v_8; } return true; } @Override public boolean equals(Object o) { return o instanceof italianStemmer; } @Override public int hashCode() { return italianStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000164 15217274217 032617 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/norwegianStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/norwegianStemme0100644 0000000 0000000 00000015666 15217274217 034311 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class norwegianStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("a", -1, 1), new Among("e", -1, 1), new Among("ede", 1, 1), new Among("ande", 1, 1), new Among("ende", 1, 1), new Among("ane", 1, 1), new Among("ene", 1, 1), new Among("hetene", 6, 1), new Among("erte", 1, 3), new Among("en", -1, 1), new Among("heten", 9, 1), new Among("ar", -1, 1), new Among("er", -1, 1), new Among("heter", 12, 1), new Among("s", -1, 2), new Among("as", 14, 1), new Among("es", 14, 1), new Among("edes", 16, 1), new Among("endes", 16, 1), new Among("enes", 16, 1), new Among("hetenes", 19, 1), new Among("ens", 14, 1), new Among("hetens", 21, 1), new Among("ers", 14, 1), new Among("ets", 14, 1), new Among("et", -1, 1), new Among("het", 25, 1), new Among("ert", -1, 3), new Among("ast", -1, 1) }; private final static Among[] a_1 = { new Among("dt", -1, -1), new Among("vt", -1, -1) }; private final static Among[] a_2 = { new Among("leg", -1, 1), new Among("eleg", 0, 1), new Among("ig", -1, 1), new Among("eig", 2, 1), new Among("lig", 2, 1), new Among("elig", 4, 1), new Among("els", -1, 1), new Among("lov", -1, 1), new Among("elov", 7, 1), new Among("slov", 7, 1), new Among("hetslov", 9, 1) }; private static final char[] g_v = {17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 128}; private static final char[] g_s_ending = {119, 125, 149, 1}; private int I_x; private int I_p1; private boolean r_mark_regions() { I_p1 = limit; int v_1 = cursor; { int c = cursor + 3; if (c > limit) { return false; } cursor = c; } I_x = cursor; cursor = v_1; golab0: while (true) { int v_2 = cursor; lab1: { if (!(in_grouping(g_v, 97, 248))) { break lab1; } cursor = v_2; break golab0; } cursor = v_2; if (cursor >= limit) { return false; } cursor++; } golab2: while (true) { lab3: { if (!(out_grouping(g_v, 97, 248))) { break lab3; } break golab2; } if (cursor >= limit) { return false; } cursor++; } I_p1 = cursor; lab4: { if (I_p1 >= I_x) { break lab4; } I_p1 = I_x; } return true; } private boolean r_main_suffix() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_0); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: slice_del(); break; case 2: lab0: { int v_3 = limit - cursor; lab1: { if (!(in_grouping_b(g_s_ending, 98, 122))) { break lab1; } break lab0; } cursor = limit - v_3; if (!(eq_s_b("k"))) { return false; } if (!(out_grouping_b(g_v, 97, 248))) { return false; } } slice_del(); break; case 3: slice_from("er"); break; } return true; } private boolean r_consonant_pair() { int v_1 = limit - cursor; if (cursor < I_p1) { return false; } int v_3 = limit_backward; limit_backward = I_p1; ket = cursor; if (find_among_b(a_1) == 0) { limit_backward = v_3; return false; } bra = cursor; limit_backward = v_3; cursor = limit - v_1; if (cursor <= limit_backward) { return false; } cursor--; bra = cursor; slice_del(); return true; } private boolean r_other_suffix() { if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; if (find_among_b(a_2) == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; slice_del(); return true; } @Override public boolean stem() { int v_1 = cursor; r_mark_regions(); cursor = v_1; limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_main_suffix(); cursor = limit - v_2; int v_3 = limit - cursor; r_consonant_pair(); cursor = limit - v_3; int v_4 = limit - cursor; r_other_suffix(); cursor = limit - v_4; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof norwegianStemmer; } @Override public int hashCode() { return norwegianStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000161 15217274217 032614 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/porterStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/porterStemmer.j0100644 0000000 0000000 00000034230 15217274217 034231 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class porterStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("s", -1, 3), new Among("ies", 0, 2), new Among("sses", 0, 1), new Among("ss", 0, -1) }; private final static Among[] a_1 = { new Among("", -1, 3), new Among("bb", 0, 2), new Among("dd", 0, 2), new Among("ff", 0, 2), new Among("gg", 0, 2), new Among("bl", 0, 1), new Among("mm", 0, 2), new Among("nn", 0, 2), new Among("pp", 0, 2), new Among("rr", 0, 2), new Among("at", 0, 1), new Among("tt", 0, 2), new Among("iz", 0, 1) }; private final static Among[] a_2 = { new Among("ed", -1, 2), new Among("eed", 0, 1), new Among("ing", -1, 2) }; private final static Among[] a_3 = { new Among("anci", -1, 3), new Among("enci", -1, 2), new Among("abli", -1, 4), new Among("eli", -1, 6), new Among("alli", -1, 9), new Among("ousli", -1, 11), new Among("entli", -1, 5), new Among("aliti", -1, 9), new Among("biliti", -1, 13), new Among("iviti", -1, 12), new Among("tional", -1, 1), new Among("ational", 10, 8), new Among("alism", -1, 9), new Among("ation", -1, 8), new Among("ization", 13, 7), new Among("izer", -1, 7), new Among("ator", -1, 8), new Among("iveness", -1, 12), new Among("fulness", -1, 10), new Among("ousness", -1, 11) }; private final static Among[] a_4 = { new Among("icate", -1, 2), new Among("ative", -1, 3), new Among("alize", -1, 1), new Among("iciti", -1, 2), new Among("ical", -1, 2), new Among("ful", -1, 3), new Among("ness", -1, 3) }; private final static Among[] a_5 = { new Among("ic", -1, 1), new Among("ance", -1, 1), new Among("ence", -1, 1), new Among("able", -1, 1), new Among("ible", -1, 1), new Among("ate", -1, 1), new Among("ive", -1, 1), new Among("ize", -1, 1), new Among("iti", -1, 1), new Among("al", -1, 1), new Among("ism", -1, 1), new Among("ion", -1, 2), new Among("er", -1, 1), new Among("ous", -1, 1), new Among("ant", -1, 1), new Among("ent", -1, 1), new Among("ment", 15, 1), new Among("ement", 16, 1), new Among("ou", -1, 1) }; private static final char[] g_v = {17, 65, 16, 1}; private static final char[] g_v_WXY = {1, 17, 65, 208, 1}; private boolean B_Y_found; private int I_p2; private int I_p1; private boolean r_shortv() { if (!(out_grouping_b(g_v_WXY, 89, 121))) { return false; } if (!(in_grouping_b(g_v, 97, 121))) { return false; } if (!(out_grouping_b(g_v, 97, 121))) { return false; } return true; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_Step_1a() { int among_var; ket = cursor; among_var = find_among_b(a_0); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: slice_from("ss"); break; case 2: slice_from("i"); break; case 3: slice_del(); break; } return true; } private boolean r_Step_1b() { int among_var; ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R1()) { return false; } slice_from("ee"); break; case 2: int v_1 = limit - cursor; golab0: while (true) { lab1: { if (!(in_grouping_b(g_v, 97, 121))) { break lab1; } break golab0; } if (cursor <= limit_backward) { return false; } cursor--; } cursor = limit - v_1; slice_del(); int v_3 = limit - cursor; among_var = find_among_b(a_1); cursor = limit - v_3; switch (among_var) { case 1: { int c = cursor; insert(cursor, cursor, "e"); cursor = c; } break; case 2: ket = cursor; if (cursor <= limit_backward) { return false; } cursor--; bra = cursor; slice_del(); break; case 3: if (cursor != I_p1) { return false; } int v_4 = limit - cursor; if (!r_shortv()) { return false; } cursor = limit - v_4; { int c = cursor; insert(cursor, cursor, "e"); cursor = c; } break; } break; } return true; } private boolean r_Step_1c() { ket = cursor; lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("y"))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(eq_s_b("Y"))) { return false; } } bra = cursor; golab2: while (true) { lab3: { if (!(in_grouping_b(g_v, 97, 121))) { break lab3; } break golab2; } if (cursor <= limit_backward) { return false; } cursor--; } slice_from("i"); return true; } private boolean r_Step_2() { int among_var; ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("tion"); break; case 2: slice_from("ence"); break; case 3: slice_from("ance"); break; case 4: slice_from("able"); break; case 5: slice_from("ent"); break; case 6: slice_from("e"); break; case 7: slice_from("ize"); break; case 8: slice_from("ate"); break; case 9: slice_from("al"); break; case 10: slice_from("ful"); break; case 11: slice_from("ous"); break; case 12: slice_from("ive"); break; case 13: slice_from("ble"); break; } return true; } private boolean r_Step_3() { int among_var; ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("al"); break; case 2: slice_from("ic"); break; case 3: slice_del(); break; } return true; } private boolean r_Step_4() { int among_var; ket = cursor; among_var = find_among_b(a_5); if (among_var == 0) { return false; } bra = cursor; if (!r_R2()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("s"))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(eq_s_b("t"))) { return false; } } slice_del(); break; } return true; } private boolean r_Step_5a() { ket = cursor; if (!(eq_s_b("e"))) { return false; } bra = cursor; lab0: { lab1: { if (!r_R2()) { break lab1; } break lab0; } if (!r_R1()) { return false; } { int v_2 = limit - cursor; lab2: { if (!r_shortv()) { break lab2; } return false; } cursor = limit - v_2; } } slice_del(); return true; } private boolean r_Step_5b() { ket = cursor; if (!(eq_s_b("l"))) { return false; } bra = cursor; if (!r_R2()) { return false; } if (!(eq_s_b("l"))) { return false; } slice_del(); return true; } @Override public boolean stem() { B_Y_found = false; int v_1 = cursor; lab0: { bra = cursor; if (!(eq_s("y"))) { break lab0; } ket = cursor; slice_from("Y"); B_Y_found = true; } cursor = v_1; int v_2 = cursor; lab1: { while (true) { int v_3 = cursor; lab2: { golab3: while (true) { int v_4 = cursor; lab4: { if (!(in_grouping(g_v, 97, 121))) { break lab4; } bra = cursor; if (!(eq_s("y"))) { break lab4; } ket = cursor; cursor = v_4; break golab3; } cursor = v_4; if (cursor >= limit) { break lab2; } cursor++; } slice_from("Y"); B_Y_found = true; continue; } cursor = v_3; break; } } cursor = v_2; I_p1 = limit; I_p2 = limit; int v_5 = cursor; lab5: { golab6: while (true) { lab7: { if (!(in_grouping(g_v, 97, 121))) { break lab7; } break golab6; } if (cursor >= limit) { break lab5; } cursor++; } golab8: while (true) { lab9: { if (!(out_grouping(g_v, 97, 121))) { break lab9; } break golab8; } if (cursor >= limit) { break lab5; } cursor++; } I_p1 = cursor; golab10: while (true) { lab11: { if (!(in_grouping(g_v, 97, 121))) { break lab11; } break golab10; } if (cursor >= limit) { break lab5; } cursor++; } golab12: while (true) { lab13: { if (!(out_grouping(g_v, 97, 121))) { break lab13; } break golab12; } if (cursor >= limit) { break lab5; } cursor++; } I_p2 = cursor; } cursor = v_5; limit_backward = cursor; cursor = limit; int v_10 = limit - cursor; r_Step_1a(); cursor = limit - v_10; int v_11 = limit - cursor; r_Step_1b(); cursor = limit - v_11; int v_12 = limit - cursor; r_Step_1c(); cursor = limit - v_12; int v_13 = limit - cursor; r_Step_2(); cursor = limit - v_13; int v_14 = limit - cursor; r_Step_3(); cursor = limit - v_14; int v_15 = limit - cursor; r_Step_4(); cursor = limit - v_15; int v_16 = limit - cursor; r_Step_5a(); cursor = limit - v_16; int v_17 = limit - cursor; r_Step_5b(); cursor = limit - v_17; cursor = limit_backward; int v_18 = cursor; lab14: { if (!(B_Y_found)) { break lab14; } while (true) { int v_19 = cursor; lab15: { golab16: while (true) { int v_20 = cursor; lab17: { bra = cursor; if (!(eq_s("Y"))) { break lab17; } ket = cursor; cursor = v_20; break golab16; } cursor = v_20; if (cursor >= limit) { break lab15; } cursor++; } slice_from("y"); continue; } cursor = v_19; break; } } cursor = v_18; return true; } @Override public boolean equals(Object o) { return o instanceof porterStemmer; } @Override public int hashCode() { return porterStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000165 15217274217 032620 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/portugueseStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/portugueseStemm0100644 0000000 0000000 00000047751 15217274217 034355 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class portugueseStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("", -1, 3), new Among("\u00E3", 0, 1), new Among("\u00F5", 0, 2) }; private final static Among[] a_1 = { new Among("", -1, 3), new Among("a~", 0, 1), new Among("o~", 0, 2) }; private final static Among[] a_2 = { new Among("ic", -1, -1), new Among("ad", -1, -1), new Among("os", -1, -1), new Among("iv", -1, 1) }; private final static Among[] a_3 = { new Among("ante", -1, 1), new Among("avel", -1, 1), new Among("\u00EDvel", -1, 1) }; private final static Among[] a_4 = { new Among("ic", -1, 1), new Among("abil", -1, 1), new Among("iv", -1, 1) }; private final static Among[] a_5 = { new Among("ica", -1, 1), new Among("\u00E2ncia", -1, 1), new Among("\u00EAncia", -1, 4), new Among("logia", -1, 2), new Among("ira", -1, 9), new Among("adora", -1, 1), new Among("osa", -1, 1), new Among("ista", -1, 1), new Among("iva", -1, 8), new Among("eza", -1, 1), new Among("idade", -1, 7), new Among("ante", -1, 1), new Among("mente", -1, 6), new Among("amente", 12, 5), new Among("\u00E1vel", -1, 1), new Among("\u00EDvel", -1, 1), new Among("ico", -1, 1), new Among("ismo", -1, 1), new Among("oso", -1, 1), new Among("amento", -1, 1), new Among("imento", -1, 1), new Among("ivo", -1, 8), new Among("a\u00E7a~o", -1, 1), new Among("u\u00E7a~o", -1, 3), new Among("ador", -1, 1), new Among("icas", -1, 1), new Among("\u00EAncias", -1, 4), new Among("logias", -1, 2), new Among("iras", -1, 9), new Among("adoras", -1, 1), new Among("osas", -1, 1), new Among("istas", -1, 1), new Among("ivas", -1, 8), new Among("ezas", -1, 1), new Among("idades", -1, 7), new Among("adores", -1, 1), new Among("antes", -1, 1), new Among("a\u00E7o~es", -1, 1), new Among("u\u00E7o~es", -1, 3), new Among("icos", -1, 1), new Among("ismos", -1, 1), new Among("osos", -1, 1), new Among("amentos", -1, 1), new Among("imentos", -1, 1), new Among("ivos", -1, 8) }; private final static Among[] a_6 = { new Among("ada", -1, 1), new Among("ida", -1, 1), new Among("ia", -1, 1), new Among("aria", 2, 1), new Among("eria", 2, 1), new Among("iria", 2, 1), new Among("ara", -1, 1), new Among("era", -1, 1), new Among("ira", -1, 1), new Among("ava", -1, 1), new Among("asse", -1, 1), new Among("esse", -1, 1), new Among("isse", -1, 1), new Among("aste", -1, 1), new Among("este", -1, 1), new Among("iste", -1, 1), new Among("ei", -1, 1), new Among("arei", 16, 1), new Among("erei", 16, 1), new Among("irei", 16, 1), new Among("am", -1, 1), new Among("iam", 20, 1), new Among("ariam", 21, 1), new Among("eriam", 21, 1), new Among("iriam", 21, 1), new Among("aram", 20, 1), new Among("eram", 20, 1), new Among("iram", 20, 1), new Among("avam", 20, 1), new Among("em", -1, 1), new Among("arem", 29, 1), new Among("erem", 29, 1), new Among("irem", 29, 1), new Among("assem", 29, 1), new Among("essem", 29, 1), new Among("issem", 29, 1), new Among("ado", -1, 1), new Among("ido", -1, 1), new Among("ando", -1, 1), new Among("endo", -1, 1), new Among("indo", -1, 1), new Among("ara~o", -1, 1), new Among("era~o", -1, 1), new Among("ira~o", -1, 1), new Among("ar", -1, 1), new Among("er", -1, 1), new Among("ir", -1, 1), new Among("as", -1, 1), new Among("adas", 47, 1), new Among("idas", 47, 1), new Among("ias", 47, 1), new Among("arias", 50, 1), new Among("erias", 50, 1), new Among("irias", 50, 1), new Among("aras", 47, 1), new Among("eras", 47, 1), new Among("iras", 47, 1), new Among("avas", 47, 1), new Among("es", -1, 1), new Among("ardes", 58, 1), new Among("erdes", 58, 1), new Among("irdes", 58, 1), new Among("ares", 58, 1), new Among("eres", 58, 1), new Among("ires", 58, 1), new Among("asses", 58, 1), new Among("esses", 58, 1), new Among("isses", 58, 1), new Among("astes", 58, 1), new Among("estes", 58, 1), new Among("istes", 58, 1), new Among("is", -1, 1), new Among("ais", 71, 1), new Among("eis", 71, 1), new Among("areis", 73, 1), new Among("ereis", 73, 1), new Among("ireis", 73, 1), new Among("\u00E1reis", 73, 1), new Among("\u00E9reis", 73, 1), new Among("\u00EDreis", 73, 1), new Among("\u00E1sseis", 73, 1), new Among("\u00E9sseis", 73, 1), new Among("\u00EDsseis", 73, 1), new Among("\u00E1veis", 73, 1), new Among("\u00EDeis", 73, 1), new Among("ar\u00EDeis", 84, 1), new Among("er\u00EDeis", 84, 1), new Among("ir\u00EDeis", 84, 1), new Among("ados", -1, 1), new Among("idos", -1, 1), new Among("amos", -1, 1), new Among("\u00E1ramos", 90, 1), new Among("\u00E9ramos", 90, 1), new Among("\u00EDramos", 90, 1), new Among("\u00E1vamos", 90, 1), new Among("\u00EDamos", 90, 1), new Among("ar\u00EDamos", 95, 1), new Among("er\u00EDamos", 95, 1), new Among("ir\u00EDamos", 95, 1), new Among("emos", -1, 1), new Among("aremos", 99, 1), new Among("eremos", 99, 1), new Among("iremos", 99, 1), new Among("\u00E1ssemos", 99, 1), new Among("\u00EAssemos", 99, 1), new Among("\u00EDssemos", 99, 1), new Among("imos", -1, 1), new Among("armos", -1, 1), new Among("ermos", -1, 1), new Among("irmos", -1, 1), new Among("\u00E1mos", -1, 1), new Among("ar\u00E1s", -1, 1), new Among("er\u00E1s", -1, 1), new Among("ir\u00E1s", -1, 1), new Among("eu", -1, 1), new Among("iu", -1, 1), new Among("ou", -1, 1), new Among("ar\u00E1", -1, 1), new Among("er\u00E1", -1, 1), new Among("ir\u00E1", -1, 1) }; private final static Among[] a_7 = { new Among("a", -1, 1), new Among("i", -1, 1), new Among("o", -1, 1), new Among("os", -1, 1), new Among("\u00E1", -1, 1), new Among("\u00ED", -1, 1), new Among("\u00F3", -1, 1) }; private final static Among[] a_8 = { new Among("e", -1, 1), new Among("\u00E7", -1, 2), new Among("\u00E9", -1, 1), new Among("\u00EA", -1, 1) }; private static final char[] g_v = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 19, 12, 2}; private int I_p2; private int I_p1; private int I_pV; private boolean r_prelude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_0); ket = cursor; switch (among_var) { case 1: slice_from("a~"); break; case 2: slice_from("o~"); break; case 3: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_mark_regions() { I_pV = limit; I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { lab1: { int v_2 = cursor; lab2: { if (!(in_grouping(g_v, 97, 250))) { break lab2; } lab3: { int v_3 = cursor; lab4: { if (!(out_grouping(g_v, 97, 250))) { break lab4; } golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 250))) { break lab6; } break golab5; } if (cursor >= limit) { break lab4; } cursor++; } break lab3; } cursor = v_3; if (!(in_grouping(g_v, 97, 250))) { break lab2; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 250))) { break lab8; } break golab7; } if (cursor >= limit) { break lab2; } cursor++; } } break lab1; } cursor = v_2; if (!(out_grouping(g_v, 97, 250))) { break lab0; } lab9: { int v_6 = cursor; lab10: { if (!(out_grouping(g_v, 97, 250))) { break lab10; } golab11: while (true) { lab12: { if (!(in_grouping(g_v, 97, 250))) { break lab12; } break golab11; } if (cursor >= limit) { break lab10; } cursor++; } break lab9; } cursor = v_6; if (!(in_grouping(g_v, 97, 250))) { break lab0; } if (cursor >= limit) { break lab0; } cursor++; } } I_pV = cursor; } cursor = v_1; int v_8 = cursor; lab13: { golab14: while (true) { lab15: { if (!(in_grouping(g_v, 97, 250))) { break lab15; } break golab14; } if (cursor >= limit) { break lab13; } cursor++; } golab16: while (true) { lab17: { if (!(out_grouping(g_v, 97, 250))) { break lab17; } break golab16; } if (cursor >= limit) { break lab13; } cursor++; } I_p1 = cursor; golab18: while (true) { lab19: { if (!(in_grouping(g_v, 97, 250))) { break lab19; } break golab18; } if (cursor >= limit) { break lab13; } cursor++; } golab20: while (true) { lab21: { if (!(out_grouping(g_v, 97, 250))) { break lab21; } break golab20; } if (cursor >= limit) { break lab13; } cursor++; } I_p2 = cursor; } cursor = v_8; return true; } private boolean r_postlude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_1); ket = cursor; switch (among_var) { case 1: slice_from("\u00E3"); break; case 2: slice_from("\u00F5"); break; case 3: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_RV() { return I_pV <= cursor; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_standard_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_5); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { return false; } slice_del(); break; case 2: if (!r_R2()) { return false; } slice_from("log"); break; case 3: if (!r_R2()) { return false; } slice_from("u"); break; case 4: if (!r_R2()) { return false; } slice_from("ente"); break; case 5: if (!r_R1()) { return false; } slice_del(); int v_1 = limit - cursor; lab0: { ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { cursor = limit - v_1; break lab0; } bra = cursor; if (!r_R2()) { cursor = limit - v_1; break lab0; } slice_del(); switch (among_var) { case 1: ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_1; break lab0; } bra = cursor; if (!r_R2()) { cursor = limit - v_1; break lab0; } slice_del(); break; } } break; case 6: if (!r_R2()) { return false; } slice_del(); int v_2 = limit - cursor; lab1: { ket = cursor; if (find_among_b(a_3) == 0) { cursor = limit - v_2; break lab1; } bra = cursor; if (!r_R2()) { cursor = limit - v_2; break lab1; } slice_del(); } break; case 7: if (!r_R2()) { return false; } slice_del(); int v_3 = limit - cursor; lab2: { ket = cursor; if (find_among_b(a_4) == 0) { cursor = limit - v_3; break lab2; } bra = cursor; if (!r_R2()) { cursor = limit - v_3; break lab2; } slice_del(); } break; case 8: if (!r_R2()) { return false; } slice_del(); int v_4 = limit - cursor; lab3: { ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_4; break lab3; } bra = cursor; if (!r_R2()) { cursor = limit - v_4; break lab3; } slice_del(); } break; case 9: if (!r_RV()) { return false; } if (!(eq_s_b("e"))) { return false; } slice_from("ir"); break; } return true; } private boolean r_verb_suffix() { if (cursor < I_pV) { return false; } int v_2 = limit_backward; limit_backward = I_pV; ket = cursor; if (find_among_b(a_6) == 0) { limit_backward = v_2; return false; } bra = cursor; slice_del(); limit_backward = v_2; return true; } private boolean r_residual_suffix() { ket = cursor; if (find_among_b(a_7) == 0) { return false; } bra = cursor; if (!r_RV()) { return false; } slice_del(); return true; } private boolean r_residual_form() { int among_var; ket = cursor; among_var = find_among_b(a_8); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_RV()) { return false; } slice_del(); ket = cursor; lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("u"))) { break lab1; } bra = cursor; int v_2 = limit - cursor; if (!(eq_s_b("g"))) { break lab1; } cursor = limit - v_2; break lab0; } cursor = limit - v_1; if (!(eq_s_b("i"))) { return false; } bra = cursor; int v_3 = limit - cursor; if (!(eq_s_b("c"))) { return false; } cursor = limit - v_3; } if (!r_RV()) { return false; } slice_del(); break; case 2: slice_from("c"); break; } return true; } @Override public boolean stem() { int v_1 = cursor; r_prelude(); cursor = v_1; r_mark_regions(); limit_backward = cursor; cursor = limit; int v_3 = limit - cursor; lab0: { lab1: { int v_4 = limit - cursor; lab2: { int v_5 = limit - cursor; lab3: { int v_6 = limit - cursor; lab4: { if (!r_standard_suffix()) { break lab4; } break lab3; } cursor = limit - v_6; if (!r_verb_suffix()) { break lab2; } } cursor = limit - v_5; int v_7 = limit - cursor; lab5: { ket = cursor; if (!(eq_s_b("i"))) { break lab5; } bra = cursor; int v_8 = limit - cursor; if (!(eq_s_b("c"))) { break lab5; } cursor = limit - v_8; if (!r_RV()) { break lab5; } slice_del(); } cursor = limit - v_7; break lab1; } cursor = limit - v_4; if (!r_residual_suffix()) { break lab0; } } } cursor = limit - v_3; int v_9 = limit - cursor; r_residual_form(); cursor = limit - v_9; cursor = limit_backward; int v_10 = cursor; r_postlude(); cursor = v_10; return true; } @Override public boolean equals(Object o) { return o instanceof portugueseStemmer; } @Override public int hashCode() { return portugueseStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000163 15217274217 032616 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/romanianStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/romanianStemmer0100644 0000000 0000000 00000052131 15217274217 034272 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class romanianStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("\u015F", -1, 1), new Among("\u0163", -1, 2) }; private final static Among[] a_1 = { new Among("", -1, 3), new Among("I", 0, 1), new Among("U", 0, 2) }; private final static Among[] a_2 = { new Among("ea", -1, 3), new Among("a\u021Bia", -1, 7), new Among("aua", -1, 2), new Among("iua", -1, 4), new Among("a\u021Bie", -1, 7), new Among("ele", -1, 3), new Among("ile", -1, 5), new Among("iile", 6, 4), new Among("iei", -1, 4), new Among("atei", -1, 6), new Among("ii", -1, 4), new Among("ului", -1, 1), new Among("ul", -1, 1), new Among("elor", -1, 3), new Among("ilor", -1, 4), new Among("iilor", 14, 4) }; private final static Among[] a_3 = { new Among("icala", -1, 4), new Among("iciva", -1, 4), new Among("ativa", -1, 5), new Among("itiva", -1, 6), new Among("icale", -1, 4), new Among("a\u021Biune", -1, 5), new Among("i\u021Biune", -1, 6), new Among("atoare", -1, 5), new Among("itoare", -1, 6), new Among("\u0103toare", -1, 5), new Among("icitate", -1, 4), new Among("abilitate", -1, 1), new Among("ibilitate", -1, 2), new Among("ivitate", -1, 3), new Among("icive", -1, 4), new Among("ative", -1, 5), new Among("itive", -1, 6), new Among("icali", -1, 4), new Among("atori", -1, 5), new Among("icatori", 18, 4), new Among("itori", -1, 6), new Among("\u0103tori", -1, 5), new Among("icitati", -1, 4), new Among("abilitati", -1, 1), new Among("ivitati", -1, 3), new Among("icivi", -1, 4), new Among("ativi", -1, 5), new Among("itivi", -1, 6), new Among("icit\u0103i", -1, 4), new Among("abilit\u0103i", -1, 1), new Among("ivit\u0103i", -1, 3), new Among("icit\u0103\u021Bi", -1, 4), new Among("abilit\u0103\u021Bi", -1, 1), new Among("ivit\u0103\u021Bi", -1, 3), new Among("ical", -1, 4), new Among("ator", -1, 5), new Among("icator", 35, 4), new Among("itor", -1, 6), new Among("\u0103tor", -1, 5), new Among("iciv", -1, 4), new Among("ativ", -1, 5), new Among("itiv", -1, 6), new Among("ical\u0103", -1, 4), new Among("iciv\u0103", -1, 4), new Among("ativ\u0103", -1, 5), new Among("itiv\u0103", -1, 6) }; private final static Among[] a_4 = { new Among("ica", -1, 1), new Among("abila", -1, 1), new Among("ibila", -1, 1), new Among("oasa", -1, 1), new Among("ata", -1, 1), new Among("ita", -1, 1), new Among("anta", -1, 1), new Among("ista", -1, 3), new Among("uta", -1, 1), new Among("iva", -1, 1), new Among("ic", -1, 1), new Among("ice", -1, 1), new Among("abile", -1, 1), new Among("ibile", -1, 1), new Among("isme", -1, 3), new Among("iune", -1, 2), new Among("oase", -1, 1), new Among("ate", -1, 1), new Among("itate", 17, 1), new Among("ite", -1, 1), new Among("ante", -1, 1), new Among("iste", -1, 3), new Among("ute", -1, 1), new Among("ive", -1, 1), new Among("ici", -1, 1), new Among("abili", -1, 1), new Among("ibili", -1, 1), new Among("iuni", -1, 2), new Among("atori", -1, 1), new Among("osi", -1, 1), new Among("ati", -1, 1), new Among("itati", 30, 1), new Among("iti", -1, 1), new Among("anti", -1, 1), new Among("isti", -1, 3), new Among("uti", -1, 1), new Among("i\u0219ti", -1, 3), new Among("ivi", -1, 1), new Among("it\u0103i", -1, 1), new Among("o\u0219i", -1, 1), new Among("it\u0103\u021Bi", -1, 1), new Among("abil", -1, 1), new Among("ibil", -1, 1), new Among("ism", -1, 3), new Among("ator", -1, 1), new Among("os", -1, 1), new Among("at", -1, 1), new Among("it", -1, 1), new Among("ant", -1, 1), new Among("ist", -1, 3), new Among("ut", -1, 1), new Among("iv", -1, 1), new Among("ic\u0103", -1, 1), new Among("abil\u0103", -1, 1), new Among("ibil\u0103", -1, 1), new Among("oas\u0103", -1, 1), new Among("at\u0103", -1, 1), new Among("it\u0103", -1, 1), new Among("ant\u0103", -1, 1), new Among("ist\u0103", -1, 3), new Among("ut\u0103", -1, 1), new Among("iv\u0103", -1, 1) }; private final static Among[] a_5 = { new Among("ea", -1, 1), new Among("ia", -1, 1), new Among("esc", -1, 1), new Among("\u0103sc", -1, 1), new Among("ind", -1, 1), new Among("\u00E2nd", -1, 1), new Among("are", -1, 1), new Among("ere", -1, 1), new Among("ire", -1, 1), new Among("\u00E2re", -1, 1), new Among("se", -1, 2), new Among("ase", 10, 1), new Among("sese", 10, 2), new Among("ise", 10, 1), new Among("use", 10, 1), new Among("\u00E2se", 10, 1), new Among("e\u0219te", -1, 1), new Among("\u0103\u0219te", -1, 1), new Among("eze", -1, 1), new Among("ai", -1, 1), new Among("eai", 19, 1), new Among("iai", 19, 1), new Among("sei", -1, 2), new Among("e\u0219ti", -1, 1), new Among("\u0103\u0219ti", -1, 1), new Among("ui", -1, 1), new Among("ezi", -1, 1), new Among("\u00E2i", -1, 1), new Among("a\u0219i", -1, 1), new Among("se\u0219i", -1, 2), new Among("ase\u0219i", 29, 1), new Among("sese\u0219i", 29, 2), new Among("ise\u0219i", 29, 1), new Among("use\u0219i", 29, 1), new Among("\u00E2se\u0219i", 29, 1), new Among("i\u0219i", -1, 1), new Among("u\u0219i", -1, 1), new Among("\u00E2\u0219i", -1, 1), new Among("a\u021Bi", -1, 2), new Among("ea\u021Bi", 38, 1), new Among("ia\u021Bi", 38, 1), new Among("e\u021Bi", -1, 2), new Among("i\u021Bi", -1, 2), new Among("\u00E2\u021Bi", -1, 2), new Among("ar\u0103\u021Bi", -1, 1), new Among("ser\u0103\u021Bi", -1, 2), new Among("aser\u0103\u021Bi", 45, 1), new Among("seser\u0103\u021Bi", 45, 2), new Among("iser\u0103\u021Bi", 45, 1), new Among("user\u0103\u021Bi", 45, 1), new Among("\u00E2ser\u0103\u021Bi", 45, 1), new Among("ir\u0103\u021Bi", -1, 1), new Among("ur\u0103\u021Bi", -1, 1), new Among("\u00E2r\u0103\u021Bi", -1, 1), new Among("am", -1, 1), new Among("eam", 54, 1), new Among("iam", 54, 1), new Among("em", -1, 2), new Among("asem", 57, 1), new Among("sesem", 57, 2), new Among("isem", 57, 1), new Among("usem", 57, 1), new Among("\u00E2sem", 57, 1), new Among("im", -1, 2), new Among("\u00E2m", -1, 2), new Among("\u0103m", -1, 2), new Among("ar\u0103m", 65, 1), new Among("ser\u0103m", 65, 2), new Among("aser\u0103m", 67, 1), new Among("seser\u0103m", 67, 2), new Among("iser\u0103m", 67, 1), new Among("user\u0103m", 67, 1), new Among("\u00E2ser\u0103m", 67, 1), new Among("ir\u0103m", 65, 1), new Among("ur\u0103m", 65, 1), new Among("\u00E2r\u0103m", 65, 1), new Among("au", -1, 1), new Among("eau", 76, 1), new Among("iau", 76, 1), new Among("indu", -1, 1), new Among("\u00E2ndu", -1, 1), new Among("ez", -1, 1), new Among("easc\u0103", -1, 1), new Among("ar\u0103", -1, 1), new Among("ser\u0103", -1, 2), new Among("aser\u0103", 84, 1), new Among("seser\u0103", 84, 2), new Among("iser\u0103", 84, 1), new Among("user\u0103", 84, 1), new Among("\u00E2ser\u0103", 84, 1), new Among("ir\u0103", -1, 1), new Among("ur\u0103", -1, 1), new Among("\u00E2r\u0103", -1, 1), new Among("eaz\u0103", -1, 1) }; private final static Among[] a_6 = { new Among("a", -1, 1), new Among("e", -1, 1), new Among("ie", 1, 1), new Among("i", -1, 1), new Among("\u0103", -1, 1) }; private static final char[] g_v = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 4}; private boolean B_standard_suffix_removed; private int I_p2; private int I_p1; private int I_pV; private boolean r_norm() { int among_var; int v_1 = cursor; lab0: { while (true) { int v_2 = cursor; lab1: { golab2: while (true) { int v_3 = cursor; lab3: { bra = cursor; among_var = find_among(a_0); if (among_var == 0) { break lab3; } ket = cursor; switch (among_var) { case 1: slice_from("\u0219"); break; case 2: slice_from("\u021B"); break; } cursor = v_3; break golab2; } cursor = v_3; if (cursor >= limit) { break lab1; } cursor++; } continue; } cursor = v_2; break; } } cursor = v_1; return true; } private boolean r_prelude() { while (true) { int v_1 = cursor; lab0: { golab1: while (true) { int v_2 = cursor; lab2: { if (!(in_grouping(g_v, 97, 259))) { break lab2; } bra = cursor; lab3: { int v_3 = cursor; lab4: { if (!(eq_s("u"))) { break lab4; } ket = cursor; if (!(in_grouping(g_v, 97, 259))) { break lab4; } slice_from("U"); break lab3; } cursor = v_3; if (!(eq_s("i"))) { break lab2; } ket = cursor; if (!(in_grouping(g_v, 97, 259))) { break lab2; } slice_from("I"); } cursor = v_2; break golab1; } cursor = v_2; if (cursor >= limit) { break lab0; } cursor++; } continue; } cursor = v_1; break; } return true; } private boolean r_mark_regions() { I_pV = limit; I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { lab1: { int v_2 = cursor; lab2: { if (!(in_grouping(g_v, 97, 259))) { break lab2; } lab3: { int v_3 = cursor; lab4: { if (!(out_grouping(g_v, 97, 259))) { break lab4; } golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 259))) { break lab6; } break golab5; } if (cursor >= limit) { break lab4; } cursor++; } break lab3; } cursor = v_3; if (!(in_grouping(g_v, 97, 259))) { break lab2; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 259))) { break lab8; } break golab7; } if (cursor >= limit) { break lab2; } cursor++; } } break lab1; } cursor = v_2; if (!(out_grouping(g_v, 97, 259))) { break lab0; } lab9: { int v_6 = cursor; lab10: { if (!(out_grouping(g_v, 97, 259))) { break lab10; } golab11: while (true) { lab12: { if (!(in_grouping(g_v, 97, 259))) { break lab12; } break golab11; } if (cursor >= limit) { break lab10; } cursor++; } break lab9; } cursor = v_6; if (!(in_grouping(g_v, 97, 259))) { break lab0; } if (cursor >= limit) { break lab0; } cursor++; } } I_pV = cursor; } cursor = v_1; int v_8 = cursor; lab13: { golab14: while (true) { lab15: { if (!(in_grouping(g_v, 97, 259))) { break lab15; } break golab14; } if (cursor >= limit) { break lab13; } cursor++; } golab16: while (true) { lab17: { if (!(out_grouping(g_v, 97, 259))) { break lab17; } break golab16; } if (cursor >= limit) { break lab13; } cursor++; } I_p1 = cursor; golab18: while (true) { lab19: { if (!(in_grouping(g_v, 97, 259))) { break lab19; } break golab18; } if (cursor >= limit) { break lab13; } cursor++; } golab20: while (true) { lab21: { if (!(out_grouping(g_v, 97, 259))) { break lab21; } break golab20; } if (cursor >= limit) { break lab13; } cursor++; } I_p2 = cursor; } cursor = v_8; return true; } private boolean r_postlude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_1); ket = cursor; switch (among_var) { case 1: slice_from("i"); break; case 2: slice_from("u"); break; case 3: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_RV() { return I_pV <= cursor; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_step_0() { int among_var; ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: slice_from("a"); break; case 3: slice_from("e"); break; case 4: slice_from("i"); break; case 5: { int v_1 = limit - cursor; lab0: { if (!(eq_s_b("ab"))) { break lab0; } return false; } cursor = limit - v_1; } slice_from("i"); break; case 6: slice_from("at"); break; case 7: slice_from("a\u021Bi"); break; } return true; } private boolean r_combo_suffix() { int among_var; int v_1 = limit - cursor; ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { return false; } bra = cursor; if (!r_R1()) { return false; } switch (among_var) { case 1: slice_from("abil"); break; case 2: slice_from("ibil"); break; case 3: slice_from("iv"); break; case 4: slice_from("ic"); break; case 5: slice_from("at"); break; case 6: slice_from("it"); break; } B_standard_suffix_removed = true; cursor = limit - v_1; return true; } private boolean r_standard_suffix() { int among_var; B_standard_suffix_removed = false; while (true) { int v_1 = limit - cursor; lab0: { if (!r_combo_suffix()) { break lab0; } continue; } cursor = limit - v_1; break; } ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { return false; } bra = cursor; if (!r_R2()) { return false; } switch (among_var) { case 1: slice_del(); break; case 2: if (!(eq_s_b("\u021B"))) { return false; } bra = cursor; slice_from("t"); break; case 3: slice_from("ist"); break; } B_standard_suffix_removed = true; return true; } private boolean r_verb_suffix() { int among_var; if (cursor < I_pV) { return false; } int v_2 = limit_backward; limit_backward = I_pV; ket = cursor; among_var = find_among_b(a_5); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; switch (among_var) { case 1: lab0: { int v_3 = limit - cursor; lab1: { if (!(out_grouping_b(g_v, 97, 259))) { break lab1; } break lab0; } cursor = limit - v_3; if (!(eq_s_b("u"))) { limit_backward = v_2; return false; } } slice_del(); break; case 2: slice_del(); break; } limit_backward = v_2; return true; } private boolean r_vowel_suffix() { ket = cursor; if (find_among_b(a_6) == 0) { return false; } bra = cursor; if (!r_RV()) { return false; } slice_del(); return true; } @Override public boolean stem() { r_norm(); int v_2 = cursor; r_prelude(); cursor = v_2; r_mark_regions(); limit_backward = cursor; cursor = limit; int v_4 = limit - cursor; r_step_0(); cursor = limit - v_4; int v_5 = limit - cursor; r_standard_suffix(); cursor = limit - v_5; int v_6 = limit - cursor; lab0: { lab1: { int v_7 = limit - cursor; lab2: { if (!(B_standard_suffix_removed)) { break lab2; } break lab1; } cursor = limit - v_7; if (!r_verb_suffix()) { break lab0; } } } cursor = limit - v_6; int v_8 = limit - cursor; r_vowel_suffix(); cursor = limit - v_8; cursor = limit_backward; int v_9 = cursor; r_postlude(); cursor = v_9; return true; } @Override public boolean equals(Object o) { return o instanceof romanianStemmer; } @Override public int hashCode() { return romanianStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/russianStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/russianStemmer.0100644 0000000 0000000 00000036211 15217274217 034231 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class russianStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("\u0432", -1, 1), new Among("\u0438\u0432", 0, 2), new Among("\u044B\u0432", 0, 2), new Among("\u0432\u0448\u0438", -1, 1), new Among("\u0438\u0432\u0448\u0438", 3, 2), new Among("\u044B\u0432\u0448\u0438", 3, 2), new Among("\u0432\u0448\u0438\u0441\u044C", -1, 1), new Among("\u0438\u0432\u0448\u0438\u0441\u044C", 6, 2), new Among("\u044B\u0432\u0448\u0438\u0441\u044C", 6, 2) }; private final static Among[] a_1 = { new Among("\u0435\u0435", -1, 1), new Among("\u0438\u0435", -1, 1), new Among("\u043E\u0435", -1, 1), new Among("\u044B\u0435", -1, 1), new Among("\u0438\u043C\u0438", -1, 1), new Among("\u044B\u043C\u0438", -1, 1), new Among("\u0435\u0439", -1, 1), new Among("\u0438\u0439", -1, 1), new Among("\u043E\u0439", -1, 1), new Among("\u044B\u0439", -1, 1), new Among("\u0435\u043C", -1, 1), new Among("\u0438\u043C", -1, 1), new Among("\u043E\u043C", -1, 1), new Among("\u044B\u043C", -1, 1), new Among("\u0435\u0433\u043E", -1, 1), new Among("\u043E\u0433\u043E", -1, 1), new Among("\u0435\u043C\u0443", -1, 1), new Among("\u043E\u043C\u0443", -1, 1), new Among("\u0438\u0445", -1, 1), new Among("\u044B\u0445", -1, 1), new Among("\u0435\u044E", -1, 1), new Among("\u043E\u044E", -1, 1), new Among("\u0443\u044E", -1, 1), new Among("\u044E\u044E", -1, 1), new Among("\u0430\u044F", -1, 1), new Among("\u044F\u044F", -1, 1) }; private final static Among[] a_2 = { new Among("\u0435\u043C", -1, 1), new Among("\u043D\u043D", -1, 1), new Among("\u0432\u0448", -1, 1), new Among("\u0438\u0432\u0448", 2, 2), new Among("\u044B\u0432\u0448", 2, 2), new Among("\u0449", -1, 1), new Among("\u044E\u0449", 5, 1), new Among("\u0443\u044E\u0449", 6, 2) }; private final static Among[] a_3 = { new Among("\u0441\u044C", -1, 1), new Among("\u0441\u044F", -1, 1) }; private final static Among[] a_4 = { new Among("\u043B\u0430", -1, 1), new Among("\u0438\u043B\u0430", 0, 2), new Among("\u044B\u043B\u0430", 0, 2), new Among("\u043D\u0430", -1, 1), new Among("\u0435\u043D\u0430", 3, 2), new Among("\u0435\u0442\u0435", -1, 1), new Among("\u0438\u0442\u0435", -1, 2), new Among("\u0439\u0442\u0435", -1, 1), new Among("\u0435\u0439\u0442\u0435", 7, 2), new Among("\u0443\u0439\u0442\u0435", 7, 2), new Among("\u043B\u0438", -1, 1), new Among("\u0438\u043B\u0438", 10, 2), new Among("\u044B\u043B\u0438", 10, 2), new Among("\u0439", -1, 1), new Among("\u0435\u0439", 13, 2), new Among("\u0443\u0439", 13, 2), new Among("\u043B", -1, 1), new Among("\u0438\u043B", 16, 2), new Among("\u044B\u043B", 16, 2), new Among("\u0435\u043C", -1, 1), new Among("\u0438\u043C", -1, 2), new Among("\u044B\u043C", -1, 2), new Among("\u043D", -1, 1), new Among("\u0435\u043D", 22, 2), new Among("\u043B\u043E", -1, 1), new Among("\u0438\u043B\u043E", 24, 2), new Among("\u044B\u043B\u043E", 24, 2), new Among("\u043D\u043E", -1, 1), new Among("\u0435\u043D\u043E", 27, 2), new Among("\u043D\u043D\u043E", 27, 1), new Among("\u0435\u0442", -1, 1), new Among("\u0443\u0435\u0442", 30, 2), new Among("\u0438\u0442", -1, 2), new Among("\u044B\u0442", -1, 2), new Among("\u044E\u0442", -1, 1), new Among("\u0443\u044E\u0442", 34, 2), new Among("\u044F\u0442", -1, 2), new Among("\u043D\u044B", -1, 1), new Among("\u0435\u043D\u044B", 37, 2), new Among("\u0442\u044C", -1, 1), new Among("\u0438\u0442\u044C", 39, 2), new Among("\u044B\u0442\u044C", 39, 2), new Among("\u0435\u0448\u044C", -1, 1), new Among("\u0438\u0448\u044C", -1, 2), new Among("\u044E", -1, 2), new Among("\u0443\u044E", 44, 2) }; private final static Among[] a_5 = { new Among("\u0430", -1, 1), new Among("\u0435\u0432", -1, 1), new Among("\u043E\u0432", -1, 1), new Among("\u0435", -1, 1), new Among("\u0438\u0435", 3, 1), new Among("\u044C\u0435", 3, 1), new Among("\u0438", -1, 1), new Among("\u0435\u0438", 6, 1), new Among("\u0438\u0438", 6, 1), new Among("\u0430\u043C\u0438", 6, 1), new Among("\u044F\u043C\u0438", 6, 1), new Among("\u0438\u044F\u043C\u0438", 10, 1), new Among("\u0439", -1, 1), new Among("\u0435\u0439", 12, 1), new Among("\u0438\u0435\u0439", 13, 1), new Among("\u0438\u0439", 12, 1), new Among("\u043E\u0439", 12, 1), new Among("\u0430\u043C", -1, 1), new Among("\u0435\u043C", -1, 1), new Among("\u0438\u0435\u043C", 18, 1), new Among("\u043E\u043C", -1, 1), new Among("\u044F\u043C", -1, 1), new Among("\u0438\u044F\u043C", 21, 1), new Among("\u043E", -1, 1), new Among("\u0443", -1, 1), new Among("\u0430\u0445", -1, 1), new Among("\u044F\u0445", -1, 1), new Among("\u0438\u044F\u0445", 26, 1), new Among("\u044B", -1, 1), new Among("\u044C", -1, 1), new Among("\u044E", -1, 1), new Among("\u0438\u044E", 30, 1), new Among("\u044C\u044E", 30, 1), new Among("\u044F", -1, 1), new Among("\u0438\u044F", 33, 1), new Among("\u044C\u044F", 33, 1) }; private final static Among[] a_6 = { new Among("\u043E\u0441\u0442", -1, 1), new Among("\u043E\u0441\u0442\u044C", -1, 1) }; private final static Among[] a_7 = { new Among("\u0435\u0439\u0448\u0435", -1, 1), new Among("\u043D", -1, 2), new Among("\u0435\u0439\u0448", -1, 1), new Among("\u044C", -1, 3) }; private static final char[] g_v = {33, 65, 8, 232}; private int I_p2; private int I_pV; private boolean r_mark_regions() { I_pV = limit; I_p2 = limit; int v_1 = cursor; lab0: { golab1: while (true) { lab2: { if (!(in_grouping(g_v, 1072, 1103))) { break lab2; } break golab1; } if (cursor >= limit) { break lab0; } cursor++; } I_pV = cursor; golab3: while (true) { lab4: { if (!(out_grouping(g_v, 1072, 1103))) { break lab4; } break golab3; } if (cursor >= limit) { break lab0; } cursor++; } golab5: while (true) { lab6: { if (!(in_grouping(g_v, 1072, 1103))) { break lab6; } break golab5; } if (cursor >= limit) { break lab0; } cursor++; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 1072, 1103))) { break lab8; } break golab7; } if (cursor >= limit) { break lab0; } cursor++; } I_p2 = cursor; } cursor = v_1; return true; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_perfective_gerund() { int among_var; ket = cursor; among_var = find_among_b(a_0); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("\u0430"))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(eq_s_b("\u044F"))) { return false; } } slice_del(); break; case 2: slice_del(); break; } return true; } private boolean r_adjective() { ket = cursor; if (find_among_b(a_1) == 0) { return false; } bra = cursor; slice_del(); return true; } private boolean r_adjectival() { int among_var; if (!r_adjective()) { return false; } int v_1 = limit - cursor; lab0: { ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { cursor = limit - v_1; break lab0; } bra = cursor; switch (among_var) { case 1: lab1: { int v_2 = limit - cursor; lab2: { if (!(eq_s_b("\u0430"))) { break lab2; } break lab1; } cursor = limit - v_2; if (!(eq_s_b("\u044F"))) { cursor = limit - v_1; break lab0; } } slice_del(); break; case 2: slice_del(); break; } } return true; } private boolean r_reflexive() { ket = cursor; if (find_among_b(a_3) == 0) { return false; } bra = cursor; slice_del(); return true; } private boolean r_verb() { int among_var; ket = cursor; among_var = find_among_b(a_4); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("\u0430"))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(eq_s_b("\u044F"))) { return false; } } slice_del(); break; case 2: slice_del(); break; } return true; } private boolean r_noun() { ket = cursor; if (find_among_b(a_5) == 0) { return false; } bra = cursor; slice_del(); return true; } private boolean r_derivational() { ket = cursor; if (find_among_b(a_6) == 0) { return false; } bra = cursor; if (!r_R2()) { return false; } slice_del(); return true; } private boolean r_tidy_up() { int among_var; ket = cursor; among_var = find_among_b(a_7); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: slice_del(); ket = cursor; if (!(eq_s_b("\u043D"))) { return false; } bra = cursor; if (!(eq_s_b("\u043D"))) { return false; } slice_del(); break; case 2: if (!(eq_s_b("\u043D"))) { return false; } slice_del(); break; case 3: slice_del(); break; } return true; } @Override public boolean stem() { int v_1 = cursor; lab0: { while (true) { int v_2 = cursor; lab1: { golab2: while (true) { int v_3 = cursor; lab3: { bra = cursor; if (!(eq_s("\u0451"))) { break lab3; } ket = cursor; cursor = v_3; break golab2; } cursor = v_3; if (cursor >= limit) { break lab1; } cursor++; } slice_from("\u0435"); continue; } cursor = v_2; break; } } cursor = v_1; r_mark_regions(); limit_backward = cursor; cursor = limit; if (cursor < I_pV) { return false; } int v_6 = limit_backward; limit_backward = I_pV; int v_7 = limit - cursor; lab4: { lab5: { int v_8 = limit - cursor; lab6: { if (!r_perfective_gerund()) { break lab6; } break lab5; } cursor = limit - v_8; int v_9 = limit - cursor; lab7: { if (!r_reflexive()) { cursor = limit - v_9; break lab7; } } lab8: { int v_10 = limit - cursor; lab9: { if (!r_adjectival()) { break lab9; } break lab8; } cursor = limit - v_10; lab10: { if (!r_verb()) { break lab10; } break lab8; } cursor = limit - v_10; if (!r_noun()) { break lab4; } } } } cursor = limit - v_7; int v_11 = limit - cursor; lab11: { ket = cursor; if (!(eq_s_b("\u0438"))) { cursor = limit - v_11; break lab11; } bra = cursor; slice_del(); } int v_12 = limit - cursor; r_derivational(); cursor = limit - v_12; int v_13 = limit - cursor; r_tidy_up(); cursor = limit - v_13; limit_backward = v_6; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof russianStemmer; } @Override public int hashCode() { return russianStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/spanishStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/spanishStemmer.0100644 0000000 0000000 00000052004 15217274217 034210 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class spanishStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("", -1, 6), new Among("\u00E1", 0, 1), new Among("\u00E9", 0, 2), new Among("\u00ED", 0, 3), new Among("\u00F3", 0, 4), new Among("\u00FA", 0, 5) }; private final static Among[] a_1 = { new Among("la", -1, -1), new Among("sela", 0, -1), new Among("le", -1, -1), new Among("me", -1, -1), new Among("se", -1, -1), new Among("lo", -1, -1), new Among("selo", 5, -1), new Among("las", -1, -1), new Among("selas", 7, -1), new Among("les", -1, -1), new Among("los", -1, -1), new Among("selos", 10, -1), new Among("nos", -1, -1) }; private final static Among[] a_2 = { new Among("ando", -1, 6), new Among("iendo", -1, 6), new Among("yendo", -1, 7), new Among("\u00E1ndo", -1, 2), new Among("i\u00E9ndo", -1, 1), new Among("ar", -1, 6), new Among("er", -1, 6), new Among("ir", -1, 6), new Among("\u00E1r", -1, 3), new Among("\u00E9r", -1, 4), new Among("\u00EDr", -1, 5) }; private final static Among[] a_3 = { new Among("ic", -1, -1), new Among("ad", -1, -1), new Among("os", -1, -1), new Among("iv", -1, 1) }; private final static Among[] a_4 = { new Among("able", -1, 1), new Among("ible", -1, 1), new Among("ante", -1, 1) }; private final static Among[] a_5 = { new Among("ic", -1, 1), new Among("abil", -1, 1), new Among("iv", -1, 1) }; private final static Among[] a_6 = { new Among("ica", -1, 1), new Among("ancia", -1, 2), new Among("encia", -1, 5), new Among("adora", -1, 2), new Among("osa", -1, 1), new Among("ista", -1, 1), new Among("iva", -1, 9), new Among("anza", -1, 1), new Among("log\u00EDa", -1, 3), new Among("idad", -1, 8), new Among("able", -1, 1), new Among("ible", -1, 1), new Among("ante", -1, 2), new Among("mente", -1, 7), new Among("amente", 13, 6), new Among("aci\u00F3n", -1, 2), new Among("uci\u00F3n", -1, 4), new Among("ico", -1, 1), new Among("ismo", -1, 1), new Among("oso", -1, 1), new Among("amiento", -1, 1), new Among("imiento", -1, 1), new Among("ivo", -1, 9), new Among("ador", -1, 2), new Among("icas", -1, 1), new Among("ancias", -1, 2), new Among("encias", -1, 5), new Among("adoras", -1, 2), new Among("osas", -1, 1), new Among("istas", -1, 1), new Among("ivas", -1, 9), new Among("anzas", -1, 1), new Among("log\u00EDas", -1, 3), new Among("idades", -1, 8), new Among("ables", -1, 1), new Among("ibles", -1, 1), new Among("aciones", -1, 2), new Among("uciones", -1, 4), new Among("adores", -1, 2), new Among("antes", -1, 2), new Among("icos", -1, 1), new Among("ismos", -1, 1), new Among("osos", -1, 1), new Among("amientos", -1, 1), new Among("imientos", -1, 1), new Among("ivos", -1, 9) }; private final static Among[] a_7 = { new Among("ya", -1, 1), new Among("ye", -1, 1), new Among("yan", -1, 1), new Among("yen", -1, 1), new Among("yeron", -1, 1), new Among("yendo", -1, 1), new Among("yo", -1, 1), new Among("yas", -1, 1), new Among("yes", -1, 1), new Among("yais", -1, 1), new Among("yamos", -1, 1), new Among("y\u00F3", -1, 1) }; private final static Among[] a_8 = { new Among("aba", -1, 2), new Among("ada", -1, 2), new Among("ida", -1, 2), new Among("ara", -1, 2), new Among("iera", -1, 2), new Among("\u00EDa", -1, 2), new Among("ar\u00EDa", 5, 2), new Among("er\u00EDa", 5, 2), new Among("ir\u00EDa", 5, 2), new Among("ad", -1, 2), new Among("ed", -1, 2), new Among("id", -1, 2), new Among("ase", -1, 2), new Among("iese", -1, 2), new Among("aste", -1, 2), new Among("iste", -1, 2), new Among("an", -1, 2), new Among("aban", 16, 2), new Among("aran", 16, 2), new Among("ieran", 16, 2), new Among("\u00EDan", 16, 2), new Among("ar\u00EDan", 20, 2), new Among("er\u00EDan", 20, 2), new Among("ir\u00EDan", 20, 2), new Among("en", -1, 1), new Among("asen", 24, 2), new Among("iesen", 24, 2), new Among("aron", -1, 2), new Among("ieron", -1, 2), new Among("ar\u00E1n", -1, 2), new Among("er\u00E1n", -1, 2), new Among("ir\u00E1n", -1, 2), new Among("ado", -1, 2), new Among("ido", -1, 2), new Among("ando", -1, 2), new Among("iendo", -1, 2), new Among("ar", -1, 2), new Among("er", -1, 2), new Among("ir", -1, 2), new Among("as", -1, 2), new Among("abas", 39, 2), new Among("adas", 39, 2), new Among("idas", 39, 2), new Among("aras", 39, 2), new Among("ieras", 39, 2), new Among("\u00EDas", 39, 2), new Among("ar\u00EDas", 45, 2), new Among("er\u00EDas", 45, 2), new Among("ir\u00EDas", 45, 2), new Among("es", -1, 1), new Among("ases", 49, 2), new Among("ieses", 49, 2), new Among("abais", -1, 2), new Among("arais", -1, 2), new Among("ierais", -1, 2), new Among("\u00EDais", -1, 2), new Among("ar\u00EDais", 55, 2), new Among("er\u00EDais", 55, 2), new Among("ir\u00EDais", 55, 2), new Among("aseis", -1, 2), new Among("ieseis", -1, 2), new Among("asteis", -1, 2), new Among("isteis", -1, 2), new Among("\u00E1is", -1, 2), new Among("\u00E9is", -1, 1), new Among("ar\u00E9is", 64, 2), new Among("er\u00E9is", 64, 2), new Among("ir\u00E9is", 64, 2), new Among("ados", -1, 2), new Among("idos", -1, 2), new Among("amos", -1, 2), new Among("\u00E1bamos", 70, 2), new Among("\u00E1ramos", 70, 2), new Among("i\u00E9ramos", 70, 2), new Among("\u00EDamos", 70, 2), new Among("ar\u00EDamos", 74, 2), new Among("er\u00EDamos", 74, 2), new Among("ir\u00EDamos", 74, 2), new Among("emos", -1, 1), new Among("aremos", 78, 2), new Among("eremos", 78, 2), new Among("iremos", 78, 2), new Among("\u00E1semos", 78, 2), new Among("i\u00E9semos", 78, 2), new Among("imos", -1, 2), new Among("ar\u00E1s", -1, 2), new Among("er\u00E1s", -1, 2), new Among("ir\u00E1s", -1, 2), new Among("\u00EDs", -1, 2), new Among("ar\u00E1", -1, 2), new Among("er\u00E1", -1, 2), new Among("ir\u00E1", -1, 2), new Among("ar\u00E9", -1, 2), new Among("er\u00E9", -1, 2), new Among("ir\u00E9", -1, 2), new Among("i\u00F3", -1, 2) }; private final static Among[] a_9 = { new Among("a", -1, 1), new Among("e", -1, 2), new Among("o", -1, 1), new Among("os", -1, 1), new Among("\u00E1", -1, 1), new Among("\u00E9", -1, 2), new Among("\u00ED", -1, 1), new Among("\u00F3", -1, 1) }; private static final char[] g_v = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17, 4, 10}; private int I_p2; private int I_p1; private int I_pV; private boolean r_mark_regions() { I_pV = limit; I_p1 = limit; I_p2 = limit; int v_1 = cursor; lab0: { lab1: { int v_2 = cursor; lab2: { if (!(in_grouping(g_v, 97, 252))) { break lab2; } lab3: { int v_3 = cursor; lab4: { if (!(out_grouping(g_v, 97, 252))) { break lab4; } golab5: while (true) { lab6: { if (!(in_grouping(g_v, 97, 252))) { break lab6; } break golab5; } if (cursor >= limit) { break lab4; } cursor++; } break lab3; } cursor = v_3; if (!(in_grouping(g_v, 97, 252))) { break lab2; } golab7: while (true) { lab8: { if (!(out_grouping(g_v, 97, 252))) { break lab8; } break golab7; } if (cursor >= limit) { break lab2; } cursor++; } } break lab1; } cursor = v_2; if (!(out_grouping(g_v, 97, 252))) { break lab0; } lab9: { int v_6 = cursor; lab10: { if (!(out_grouping(g_v, 97, 252))) { break lab10; } golab11: while (true) { lab12: { if (!(in_grouping(g_v, 97, 252))) { break lab12; } break golab11; } if (cursor >= limit) { break lab10; } cursor++; } break lab9; } cursor = v_6; if (!(in_grouping(g_v, 97, 252))) { break lab0; } if (cursor >= limit) { break lab0; } cursor++; } } I_pV = cursor; } cursor = v_1; int v_8 = cursor; lab13: { golab14: while (true) { lab15: { if (!(in_grouping(g_v, 97, 252))) { break lab15; } break golab14; } if (cursor >= limit) { break lab13; } cursor++; } golab16: while (true) { lab17: { if (!(out_grouping(g_v, 97, 252))) { break lab17; } break golab16; } if (cursor >= limit) { break lab13; } cursor++; } I_p1 = cursor; golab18: while (true) { lab19: { if (!(in_grouping(g_v, 97, 252))) { break lab19; } break golab18; } if (cursor >= limit) { break lab13; } cursor++; } golab20: while (true) { lab21: { if (!(out_grouping(g_v, 97, 252))) { break lab21; } break golab20; } if (cursor >= limit) { break lab13; } cursor++; } I_p2 = cursor; } cursor = v_8; return true; } private boolean r_postlude() { int among_var; while (true) { int v_1 = cursor; lab0: { bra = cursor; among_var = find_among(a_0); ket = cursor; switch (among_var) { case 1: slice_from("a"); break; case 2: slice_from("e"); break; case 3: slice_from("i"); break; case 4: slice_from("o"); break; case 5: slice_from("u"); break; case 6: if (cursor >= limit) { break lab0; } cursor++; break; } continue; } cursor = v_1; break; } return true; } private boolean r_RV() { return I_pV <= cursor; } private boolean r_R1() { return I_p1 <= cursor; } private boolean r_R2() { return I_p2 <= cursor; } private boolean r_attached_pronoun() { int among_var; ket = cursor; if (find_among_b(a_1) == 0) { return false; } bra = cursor; among_var = find_among_b(a_2); if (among_var == 0) { return false; } if (!r_RV()) { return false; } switch (among_var) { case 1: bra = cursor; slice_from("iendo"); break; case 2: bra = cursor; slice_from("ando"); break; case 3: bra = cursor; slice_from("ar"); break; case 4: bra = cursor; slice_from("er"); break; case 5: bra = cursor; slice_from("ir"); break; case 6: slice_del(); break; case 7: if (!(eq_s_b("u"))) { return false; } slice_del(); break; } return true; } private boolean r_standard_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_6); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_R2()) { return false; } slice_del(); break; case 2: if (!r_R2()) { return false; } slice_del(); int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("ic"))) { cursor = limit - v_1; break lab0; } bra = cursor; if (!r_R2()) { cursor = limit - v_1; break lab0; } slice_del(); } break; case 3: if (!r_R2()) { return false; } slice_from("log"); break; case 4: if (!r_R2()) { return false; } slice_from("u"); break; case 5: if (!r_R2()) { return false; } slice_from("ente"); break; case 6: if (!r_R1()) { return false; } slice_del(); int v_2 = limit - cursor; lab1: { ket = cursor; among_var = find_among_b(a_3); if (among_var == 0) { cursor = limit - v_2; break lab1; } bra = cursor; if (!r_R2()) { cursor = limit - v_2; break lab1; } slice_del(); switch (among_var) { case 1: ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_2; break lab1; } bra = cursor; if (!r_R2()) { cursor = limit - v_2; break lab1; } slice_del(); break; } } break; case 7: if (!r_R2()) { return false; } slice_del(); int v_3 = limit - cursor; lab2: { ket = cursor; if (find_among_b(a_4) == 0) { cursor = limit - v_3; break lab2; } bra = cursor; if (!r_R2()) { cursor = limit - v_3; break lab2; } slice_del(); } break; case 8: if (!r_R2()) { return false; } slice_del(); int v_4 = limit - cursor; lab3: { ket = cursor; if (find_among_b(a_5) == 0) { cursor = limit - v_4; break lab3; } bra = cursor; if (!r_R2()) { cursor = limit - v_4; break lab3; } slice_del(); } break; case 9: if (!r_R2()) { return false; } slice_del(); int v_5 = limit - cursor; lab4: { ket = cursor; if (!(eq_s_b("at"))) { cursor = limit - v_5; break lab4; } bra = cursor; if (!r_R2()) { cursor = limit - v_5; break lab4; } slice_del(); } break; } return true; } private boolean r_y_verb_suffix() { if (cursor < I_pV) { return false; } int v_2 = limit_backward; limit_backward = I_pV; ket = cursor; if (find_among_b(a_7) == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; if (!(eq_s_b("u"))) { return false; } slice_del(); return true; } private boolean r_verb_suffix() { int among_var; if (cursor < I_pV) { return false; } int v_2 = limit_backward; limit_backward = I_pV; ket = cursor; among_var = find_among_b(a_8); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: int v_3 = limit - cursor; lab0: { if (!(eq_s_b("u"))) { cursor = limit - v_3; break lab0; } int v_4 = limit - cursor; if (!(eq_s_b("g"))) { cursor = limit - v_3; break lab0; } cursor = limit - v_4; } bra = cursor; slice_del(); break; case 2: slice_del(); break; } return true; } private boolean r_residual_suffix() { int among_var; ket = cursor; among_var = find_among_b(a_9); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: if (!r_RV()) { return false; } slice_del(); break; case 2: if (!r_RV()) { return false; } slice_del(); int v_1 = limit - cursor; lab0: { ket = cursor; if (!(eq_s_b("u"))) { cursor = limit - v_1; break lab0; } bra = cursor; int v_2 = limit - cursor; if (!(eq_s_b("g"))) { cursor = limit - v_1; break lab0; } cursor = limit - v_2; if (!r_RV()) { cursor = limit - v_1; break lab0; } slice_del(); } break; } return true; } @Override public boolean stem() { r_mark_regions(); limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_attached_pronoun(); cursor = limit - v_2; int v_3 = limit - cursor; lab0: { lab1: { int v_4 = limit - cursor; lab2: { if (!r_standard_suffix()) { break lab2; } break lab1; } cursor = limit - v_4; lab3: { if (!r_y_verb_suffix()) { break lab3; } break lab1; } cursor = limit - v_4; if (!r_verb_suffix()) { break lab0; } } } cursor = limit - v_3; int v_5 = limit - cursor; r_residual_suffix(); cursor = limit - v_5; cursor = limit_backward; int v_6 = cursor; r_postlude(); cursor = v_6; return true; } @Override public boolean equals(Object o) { return o instanceof spanishStemmer; } @Override public int hashCode() { return spanishStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/swedishStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/swedishStemmer.0100644 0000000 0000000 00000016220 15217274217 034211 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class swedishStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("a", -1, 1), new Among("arna", 0, 1), new Among("erna", 0, 1), new Among("heterna", 2, 1), new Among("orna", 0, 1), new Among("ad", -1, 1), new Among("e", -1, 1), new Among("ade", 6, 1), new Among("ande", 6, 1), new Among("arne", 6, 1), new Among("are", 6, 1), new Among("aste", 6, 1), new Among("en", -1, 1), new Among("anden", 12, 1), new Among("aren", 12, 1), new Among("heten", 12, 1), new Among("ern", -1, 1), new Among("ar", -1, 1), new Among("er", -1, 1), new Among("heter", 18, 1), new Among("or", -1, 1), new Among("s", -1, 2), new Among("as", 21, 1), new Among("arnas", 22, 1), new Among("ernas", 22, 1), new Among("ornas", 22, 1), new Among("es", 21, 1), new Among("ades", 26, 1), new Among("andes", 26, 1), new Among("ens", 21, 1), new Among("arens", 29, 1), new Among("hetens", 29, 1), new Among("erns", 21, 1), new Among("at", -1, 1), new Among("andet", -1, 1), new Among("het", -1, 1), new Among("ast", -1, 1) }; private final static Among[] a_1 = { new Among("dd", -1, -1), new Among("gd", -1, -1), new Among("nn", -1, -1), new Among("dt", -1, -1), new Among("gt", -1, -1), new Among("kt", -1, -1), new Among("tt", -1, -1) }; private final static Among[] a_2 = { new Among("ig", -1, 1), new Among("lig", 0, 1), new Among("els", -1, 1), new Among("fullt", -1, 3), new Among("\u00F6st", -1, 2) }; private static final char[] g_v = {17, 65, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 32}; private static final char[] g_s_ending = {119, 127, 149}; private static final char[] g_ost_ending = {173, 58}; private int I_x; private int I_p1; private boolean r_mark_regions() { I_p1 = limit; int v_1 = cursor; { int c = cursor + 3; if (c > limit) { return false; } cursor = c; } I_x = cursor; cursor = v_1; golab0: while (true) { int v_2 = cursor; lab1: { if (!(in_grouping(g_v, 97, 246))) { break lab1; } cursor = v_2; break golab0; } cursor = v_2; if (cursor >= limit) { return false; } cursor++; } golab2: while (true) { lab3: { if (!(out_grouping(g_v, 97, 246))) { break lab3; } break golab2; } if (cursor >= limit) { return false; } cursor++; } I_p1 = cursor; lab4: { if (I_p1 >= I_x) { break lab4; } I_p1 = I_x; } return true; } private boolean r_main_suffix() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_0); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: slice_del(); break; case 2: if (!(in_grouping_b(g_s_ending, 98, 121))) { return false; } slice_del(); break; } return true; } private boolean r_consonant_pair() { if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; int v_3 = limit - cursor; if (find_among_b(a_1) == 0) { limit_backward = v_2; return false; } cursor = limit - v_3; ket = cursor; if (cursor <= limit_backward) { limit_backward = v_2; return false; } cursor--; bra = cursor; slice_del(); limit_backward = v_2; return true; } private boolean r_other_suffix() { int among_var; if (cursor < I_p1) { return false; } int v_2 = limit_backward; limit_backward = I_p1; ket = cursor; among_var = find_among_b(a_2); if (among_var == 0) { limit_backward = v_2; return false; } bra = cursor; limit_backward = v_2; switch (among_var) { case 1: slice_del(); break; case 2: if (!(in_grouping_b(g_ost_ending, 105, 118))) { return false; } slice_from("\u00F6s"); break; case 3: slice_from("full"); break; } return true; } @Override public boolean stem() { int v_1 = cursor; r_mark_regions(); cursor = v_1; limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_main_suffix(); cursor = limit - v_2; int v_3 = limit - cursor; r_consonant_pair(); cursor = limit - v_3; int v_4 = limit - cursor; r_other_suffix(); cursor = limit - v_4; cursor = limit_backward; return true; } @Override public boolean equals(Object o) { return o instanceof swedishStemmer; } @Override public int hashCode() { return swedishStemmer.class.getName().hashCode(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_stemmer_snowball0100644 0000000 0000000 00000000162 15217274217 032615 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/turkishStemmer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/stemmer/snowball/turkishStemmer.0100644 0000000 0000000 00000140037 15217274217 034240 0ustar00rootroot0000000 0000000 // CHECKSTYLE:OFF /* Copyright (c) 2001, Dr Martin Porter Copyright (c) 2002, Richard Boulton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) package opennlp.tools.stemmer.snowball; /** * This class implements the stemming algorithm defined by a snowball script. *

* Generated by Snowball (build from 9a22f0d3f44cda36677829328fe2642750114d57) - https://github.com/snowballstem/snowball *

*/ @SuppressWarnings("unused") public class turkishStemmer extends AbstractSnowballStemmer { private static final long serialVersionUID = 1L; private final static Among[] a_0 = { new Among("m", -1, -1), new Among("n", -1, -1), new Among("miz", -1, -1), new Among("niz", -1, -1), new Among("muz", -1, -1), new Among("nuz", -1, -1), new Among("m\u00FCz", -1, -1), new Among("n\u00FCz", -1, -1), new Among("m\u0131z", -1, -1), new Among("n\u0131z", -1, -1) }; private final static Among[] a_1 = { new Among("leri", -1, -1), new Among("lar\u0131", -1, -1) }; private final static Among[] a_2 = { new Among("ni", -1, -1), new Among("nu", -1, -1), new Among("n\u00FC", -1, -1), new Among("n\u0131", -1, -1) }; private final static Among[] a_3 = { new Among("in", -1, -1), new Among("un", -1, -1), new Among("\u00FCn", -1, -1), new Among("\u0131n", -1, -1) }; private final static Among[] a_4 = { new Among("a", -1, -1), new Among("e", -1, -1) }; private final static Among[] a_5 = { new Among("na", -1, -1), new Among("ne", -1, -1) }; private final static Among[] a_6 = { new Among("da", -1, -1), new Among("ta", -1, -1), new Among("de", -1, -1), new Among("te", -1, -1) }; private final static Among[] a_7 = { new Among("nda", -1, -1), new Among("nde", -1, -1) }; private final static Among[] a_8 = { new Among("dan", -1, -1), new Among("tan", -1, -1), new Among("den", -1, -1), new Among("ten", -1, -1) }; private final static Among[] a_9 = { new Among("ndan", -1, -1), new Among("nden", -1, -1) }; private final static Among[] a_10 = { new Among("la", -1, -1), new Among("le", -1, -1) }; private final static Among[] a_11 = { new Among("ca", -1, -1), new Among("ce", -1, -1) }; private final static Among[] a_12 = { new Among("im", -1, -1), new Among("um", -1, -1), new Among("\u00FCm", -1, -1), new Among("\u0131m", -1, -1) }; private final static Among[] a_13 = { new Among("sin", -1, -1), new Among("sun", -1, -1), new Among("s\u00FCn", -1, -1), new Among("s\u0131n", -1, -1) }; private final static Among[] a_14 = { new Among("iz", -1, -1), new Among("uz", -1, -1), new Among("\u00FCz", -1, -1), new Among("\u0131z", -1, -1) }; private final static Among[] a_15 = { new Among("siniz", -1, -1), new Among("sunuz", -1, -1), new Among("s\u00FCn\u00FCz", -1, -1), new Among("s\u0131n\u0131z", -1, -1) }; private final static Among[] a_16 = { new Among("lar", -1, -1), new Among("ler", -1, -1) }; private final static Among[] a_17 = { new Among("niz", -1, -1), new Among("nuz", -1, -1), new Among("n\u00FCz", -1, -1), new Among("n\u0131z", -1, -1) }; private final static Among[] a_18 = { new Among("dir", -1, -1), new Among("tir", -1, -1), new Among("dur", -1, -1), new Among("tur", -1, -1), new Among("d\u00FCr", -1, -1), new Among("t\u00FCr", -1, -1), new Among("d\u0131r", -1, -1), new Among("t\u0131r", -1, -1) }; private final static Among[] a_19 = { new Among("cas\u0131na", -1, -1), new Among("cesine", -1, -1) }; private final static Among[] a_20 = { new Among("di", -1, -1), new Among("ti", -1, -1), new Among("dik", -1, -1), new Among("tik", -1, -1), new Among("duk", -1, -1), new Among("tuk", -1, -1), new Among("d\u00FCk", -1, -1), new Among("t\u00FCk", -1, -1), new Among("d\u0131k", -1, -1), new Among("t\u0131k", -1, -1), new Among("dim", -1, -1), new Among("tim", -1, -1), new Among("dum", -1, -1), new Among("tum", -1, -1), new Among("d\u00FCm", -1, -1), new Among("t\u00FCm", -1, -1), new Among("d\u0131m", -1, -1), new Among("t\u0131m", -1, -1), new Among("din", -1, -1), new Among("tin", -1, -1), new Among("dun", -1, -1), new Among("tun", -1, -1), new Among("d\u00FCn", -1, -1), new Among("t\u00FCn", -1, -1), new Among("d\u0131n", -1, -1), new Among("t\u0131n", -1, -1), new Among("du", -1, -1), new Among("tu", -1, -1), new Among("d\u00FC", -1, -1), new Among("t\u00FC", -1, -1), new Among("d\u0131", -1, -1), new Among("t\u0131", -1, -1) }; private final static Among[] a_21 = { new Among("sa", -1, -1), new Among("se", -1, -1), new Among("sak", -1, -1), new Among("sek", -1, -1), new Among("sam", -1, -1), new Among("sem", -1, -1), new Among("san", -1, -1), new Among("sen", -1, -1) }; private final static Among[] a_22 = { new Among("mi\u015F", -1, -1), new Among("mu\u015F", -1, -1), new Among("m\u00FC\u015F", -1, -1), new Among("m\u0131\u015F", -1, -1) }; private final static Among[] a_23 = { new Among("b", -1, 1), new Among("c", -1, 2), new Among("d", -1, 3), new Among("\u011F", -1, 4) }; private static final char[] g_vowel = {17, 65, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 8, 0, 0, 0, 0, 0, 0, 1}; private static final char[] g_U = {1, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1}; private static final char[] g_vowel1 = {1, 64, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; private static final char[] g_vowel2 = {17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130}; private static final char[] g_vowel3 = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; private static final char[] g_vowel4 = {17}; private static final char[] g_vowel5 = {65}; private static final char[] g_vowel6 = {65}; private boolean B_continue_stemming_noun_suffixes; private boolean r_check_vowel_harmony() { int v_1 = limit - cursor; golab0: while (true) { int v_2 = limit - cursor; lab1: { if (!(in_grouping_b(g_vowel, 97, 305))) { break lab1; } cursor = limit - v_2; break golab0; } cursor = limit - v_2; if (cursor <= limit_backward) { return false; } cursor--; } lab2: { int v_3 = limit - cursor; lab3: { if (!(eq_s_b("a"))) { break lab3; } golab4: while (true) { int v_4 = limit - cursor; lab5: { if (!(in_grouping_b(g_vowel1, 97, 305))) { break lab5; } cursor = limit - v_4; break golab4; } cursor = limit - v_4; if (cursor <= limit_backward) { break lab3; } cursor--; } break lab2; } cursor = limit - v_3; lab6: { if (!(eq_s_b("e"))) { break lab6; } golab7: while (true) { int v_5 = limit - cursor; lab8: { if (!(in_grouping_b(g_vowel2, 101, 252))) { break lab8; } cursor = limit - v_5; break golab7; } cursor = limit - v_5; if (cursor <= limit_backward) { break lab6; } cursor--; } break lab2; } cursor = limit - v_3; lab9: { if (!(eq_s_b("\u0131"))) { break lab9; } golab10: while (true) { int v_6 = limit - cursor; lab11: { if (!(in_grouping_b(g_vowel3, 97, 305))) { break lab11; } cursor = limit - v_6; break golab10; } cursor = limit - v_6; if (cursor <= limit_backward) { break lab9; } cursor--; } break lab2; } cursor = limit - v_3; lab12: { if (!(eq_s_b("i"))) { break lab12; } golab13: while (true) { int v_7 = limit - cursor; lab14: { if (!(in_grouping_b(g_vowel4, 101, 105))) { break lab14; } cursor = limit - v_7; break golab13; } cursor = limit - v_7; if (cursor <= limit_backward) { break lab12; } cursor--; } break lab2; } cursor = limit - v_3; lab15: { if (!(eq_s_b("o"))) { break lab15; } golab16: while (true) { int v_8 = limit - cursor; lab17: { if (!(in_grouping_b(g_vowel5, 111, 117))) { break lab17; } cursor = limit - v_8; break golab16; } cursor = limit - v_8; if (cursor <= limit_backward) { break lab15; } cursor--; } break lab2; } cursor = limit - v_3; lab18: { if (!(eq_s_b("\u00F6"))) { break lab18; } golab19: while (true) { int v_9 = limit - cursor; lab20: { if (!(in_grouping_b(g_vowel6, 246, 252))) { break lab20; } cursor = limit - v_9; break golab19; } cursor = limit - v_9; if (cursor <= limit_backward) { break lab18; } cursor--; } break lab2; } cursor = limit - v_3; lab21: { if (!(eq_s_b("u"))) { break lab21; } golab22: while (true) { int v_10 = limit - cursor; lab23: { if (!(in_grouping_b(g_vowel5, 111, 117))) { break lab23; } cursor = limit - v_10; break golab22; } cursor = limit - v_10; if (cursor <= limit_backward) { break lab21; } cursor--; } break lab2; } cursor = limit - v_3; if (!(eq_s_b("\u00FC"))) { return false; } golab24: while (true) { int v_11 = limit - cursor; lab25: { if (!(in_grouping_b(g_vowel6, 246, 252))) { break lab25; } cursor = limit - v_11; break golab24; } cursor = limit - v_11; if (cursor <= limit_backward) { return false; } cursor--; } } cursor = limit - v_1; return true; } private boolean r_mark_suffix_with_optional_n_consonant() { lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("n"))) { break lab1; } int v_2 = limit - cursor; if (!(in_grouping_b(g_vowel, 97, 305))) { break lab1; } cursor = limit - v_2; break lab0; } cursor = limit - v_1; { int v_3 = limit - cursor; lab2: { int v_4 = limit - cursor; if (!(eq_s_b("n"))) { break lab2; } cursor = limit - v_4; return false; } cursor = limit - v_3; } int v_5 = limit - cursor; if (cursor <= limit_backward) { return false; } cursor--; if (!(in_grouping_b(g_vowel, 97, 305))) { return false; } cursor = limit - v_5; } return true; } private boolean r_mark_suffix_with_optional_s_consonant() { lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("s"))) { break lab1; } int v_2 = limit - cursor; if (!(in_grouping_b(g_vowel, 97, 305))) { break lab1; } cursor = limit - v_2; break lab0; } cursor = limit - v_1; { int v_3 = limit - cursor; lab2: { int v_4 = limit - cursor; if (!(eq_s_b("s"))) { break lab2; } cursor = limit - v_4; return false; } cursor = limit - v_3; } int v_5 = limit - cursor; if (cursor <= limit_backward) { return false; } cursor--; if (!(in_grouping_b(g_vowel, 97, 305))) { return false; } cursor = limit - v_5; } return true; } private boolean r_mark_suffix_with_optional_y_consonant() { lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("y"))) { break lab1; } int v_2 = limit - cursor; if (!(in_grouping_b(g_vowel, 97, 305))) { break lab1; } cursor = limit - v_2; break lab0; } cursor = limit - v_1; { int v_3 = limit - cursor; lab2: { int v_4 = limit - cursor; if (!(eq_s_b("y"))) { break lab2; } cursor = limit - v_4; return false; } cursor = limit - v_3; } int v_5 = limit - cursor; if (cursor <= limit_backward) { return false; } cursor--; if (!(in_grouping_b(g_vowel, 97, 305))) { return false; } cursor = limit - v_5; } return true; } private boolean r_mark_suffix_with_optional_U_vowel() { lab0: { int v_1 = limit - cursor; lab1: { if (!(in_grouping_b(g_U, 105, 305))) { break lab1; } int v_2 = limit - cursor; if (!(out_grouping_b(g_vowel, 97, 305))) { break lab1; } cursor = limit - v_2; break lab0; } cursor = limit - v_1; { int v_3 = limit - cursor; lab2: { int v_4 = limit - cursor; if (!(in_grouping_b(g_U, 105, 305))) { break lab2; } cursor = limit - v_4; return false; } cursor = limit - v_3; } int v_5 = limit - cursor; if (cursor <= limit_backward) { return false; } cursor--; if (!(out_grouping_b(g_vowel, 97, 305))) { return false; } cursor = limit - v_5; } return true; } private boolean r_mark_possessives() { if (find_among_b(a_0) == 0) { return false; } if (!r_mark_suffix_with_optional_U_vowel()) { return false; } return true; } private boolean r_mark_sU() { if (!r_check_vowel_harmony()) { return false; } if (!(in_grouping_b(g_U, 105, 305))) { return false; } if (!r_mark_suffix_with_optional_s_consonant()) { return false; } return true; } private boolean r_mark_lArI() { if (find_among_b(a_1) == 0) { return false; } return true; } private boolean r_mark_yU() { if (!r_check_vowel_harmony()) { return false; } if (!(in_grouping_b(g_U, 105, 305))) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_nU() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_2) == 0) { return false; } return true; } private boolean r_mark_nUn() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_3) == 0) { return false; } if (!r_mark_suffix_with_optional_n_consonant()) { return false; } return true; } private boolean r_mark_yA() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_4) == 0) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_nA() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_5) == 0) { return false; } return true; } private boolean r_mark_DA() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_6) == 0) { return false; } return true; } private boolean r_mark_ndA() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_7) == 0) { return false; } return true; } private boolean r_mark_DAn() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_8) == 0) { return false; } return true; } private boolean r_mark_ndAn() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_9) == 0) { return false; } return true; } private boolean r_mark_ylA() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_10) == 0) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_ki() { if (!(eq_s_b("ki"))) { return false; } return true; } private boolean r_mark_ncA() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_11) == 0) { return false; } if (!r_mark_suffix_with_optional_n_consonant()) { return false; } return true; } private boolean r_mark_yUm() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_12) == 0) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_sUn() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_13) == 0) { return false; } return true; } private boolean r_mark_yUz() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_14) == 0) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_sUnUz() { if (find_among_b(a_15) == 0) { return false; } return true; } private boolean r_mark_lAr() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_16) == 0) { return false; } return true; } private boolean r_mark_nUz() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_17) == 0) { return false; } return true; } private boolean r_mark_DUr() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_18) == 0) { return false; } return true; } private boolean r_mark_cAsInA() { if (find_among_b(a_19) == 0) { return false; } return true; } private boolean r_mark_yDU() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_20) == 0) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_ysA() { if (find_among_b(a_21) == 0) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_ymUs_() { if (!r_check_vowel_harmony()) { return false; } if (find_among_b(a_22) == 0) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_mark_yken() { if (!(eq_s_b("ken"))) { return false; } if (!r_mark_suffix_with_optional_y_consonant()) { return false; } return true; } private boolean r_stem_nominal_verb_suffixes() { ket = cursor; B_continue_stemming_noun_suffixes = true; lab0: { int v_1 = limit - cursor; lab1: { lab2: { int v_2 = limit - cursor; lab3: { if (!r_mark_ymUs_()) { break lab3; } break lab2; } cursor = limit - v_2; lab4: { if (!r_mark_yDU()) { break lab4; } break lab2; } cursor = limit - v_2; lab5: { if (!r_mark_ysA()) { break lab5; } break lab2; } cursor = limit - v_2; if (!r_mark_yken()) { break lab1; } } break lab0; } cursor = limit - v_1; lab6: { if (!r_mark_cAsInA()) { break lab6; } lab7: { int v_3 = limit - cursor; lab8: { if (!r_mark_sUnUz()) { break lab8; } break lab7; } cursor = limit - v_3; lab9: { if (!r_mark_lAr()) { break lab9; } break lab7; } cursor = limit - v_3; lab10: { if (!r_mark_yUm()) { break lab10; } break lab7; } cursor = limit - v_3; lab11: { if (!r_mark_sUn()) { break lab11; } break lab7; } cursor = limit - v_3; lab12: { if (!r_mark_yUz()) { break lab12; } break lab7; } cursor = limit - v_3; } if (!r_mark_ymUs_()) { break lab6; } break lab0; } cursor = limit - v_1; lab13: { if (!r_mark_lAr()) { break lab13; } bra = cursor; slice_del(); int v_4 = limit - cursor; lab14: { ket = cursor; lab15: { int v_5 = limit - cursor; lab16: { if (!r_mark_DUr()) { break lab16; } break lab15; } cursor = limit - v_5; lab17: { if (!r_mark_yDU()) { break lab17; } break lab15; } cursor = limit - v_5; lab18: { if (!r_mark_ysA()) { break lab18; } break lab15; } cursor = limit - v_5; if (!r_mark_ymUs_()) { cursor = limit - v_4; break lab14; } } } B_continue_stemming_noun_suffixes = false; break lab0; } cursor = limit - v_1; lab19: { if (!r_mark_nUz()) { break lab19; } lab20: { int v_6 = limit - cursor; lab21: { if (!r_mark_yDU()) { break lab21; } break lab20; } cursor = limit - v_6; if (!r_mark_ysA()) { break lab19; } } break lab0; } cursor = limit - v_1; lab22: { lab23: { int v_7 = limit - cursor; lab24: { if (!r_mark_sUnUz()) { break lab24; } break lab23; } cursor = limit - v_7; lab25: { if (!r_mark_yUz()) { break lab25; } break lab23; } cursor = limit - v_7; lab26: { if (!r_mark_sUn()) { break lab26; } break lab23; } cursor = limit - v_7; if (!r_mark_yUm()) { break lab22; } } bra = cursor; slice_del(); int v_8 = limit - cursor; lab27: { ket = cursor; if (!r_mark_ymUs_()) { cursor = limit - v_8; break lab27; } } break lab0; } cursor = limit - v_1; if (!r_mark_DUr()) { return false; } bra = cursor; slice_del(); int v_9 = limit - cursor; lab28: { ket = cursor; lab29: { int v_10 = limit - cursor; lab30: { if (!r_mark_sUnUz()) { break lab30; } break lab29; } cursor = limit - v_10; lab31: { if (!r_mark_lAr()) { break lab31; } break lab29; } cursor = limit - v_10; lab32: { if (!r_mark_yUm()) { break lab32; } break lab29; } cursor = limit - v_10; lab33: { if (!r_mark_sUn()) { break lab33; } break lab29; } cursor = limit - v_10; lab34: { if (!r_mark_yUz()) { break lab34; } break lab29; } cursor = limit - v_10; } if (!r_mark_ymUs_()) { cursor = limit - v_9; break lab28; } } } bra = cursor; slice_del(); return true; } private boolean r_stem_suffix_chain_before_ki() { ket = cursor; if (!r_mark_ki()) { return false; } lab0: { int v_1 = limit - cursor; lab1: { if (!r_mark_DA()) { break lab1; } bra = cursor; slice_del(); int v_2 = limit - cursor; lab2: { ket = cursor; lab3: { int v_3 = limit - cursor; lab4: { if (!r_mark_lAr()) { break lab4; } bra = cursor; slice_del(); int v_4 = limit - cursor; lab5: { if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_4; break lab5; } } break lab3; } cursor = limit - v_3; if (!r_mark_possessives()) { cursor = limit - v_2; break lab2; } bra = cursor; slice_del(); int v_5 = limit - cursor; lab6: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_5; break lab6; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_5; break lab6; } } } } break lab0; } cursor = limit - v_1; lab7: { if (!r_mark_nUn()) { break lab7; } bra = cursor; slice_del(); int v_6 = limit - cursor; lab8: { ket = cursor; lab9: { int v_7 = limit - cursor; lab10: { if (!r_mark_lArI()) { break lab10; } bra = cursor; slice_del(); break lab9; } cursor = limit - v_7; lab11: { ket = cursor; lab12: { int v_8 = limit - cursor; lab13: { if (!r_mark_possessives()) { break lab13; } break lab12; } cursor = limit - v_8; if (!r_mark_sU()) { break lab11; } } bra = cursor; slice_del(); int v_9 = limit - cursor; lab14: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_9; break lab14; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_9; break lab14; } } break lab9; } cursor = limit - v_7; if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_6; break lab8; } } } break lab0; } cursor = limit - v_1; if (!r_mark_ndA()) { return false; } lab15: { int v_10 = limit - cursor; lab16: { if (!r_mark_lArI()) { break lab16; } bra = cursor; slice_del(); break lab15; } cursor = limit - v_10; lab17: { if (!r_mark_sU()) { break lab17; } bra = cursor; slice_del(); int v_11 = limit - cursor; lab18: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_11; break lab18; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_11; break lab18; } } break lab15; } cursor = limit - v_10; if (!r_stem_suffix_chain_before_ki()) { return false; } } } return true; } private boolean r_stem_noun_suffixes() { lab0: { int v_1 = limit - cursor; lab1: { ket = cursor; if (!r_mark_lAr()) { break lab1; } bra = cursor; slice_del(); int v_2 = limit - cursor; lab2: { if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_2; break lab2; } } break lab0; } cursor = limit - v_1; lab3: { ket = cursor; if (!r_mark_ncA()) { break lab3; } bra = cursor; slice_del(); int v_3 = limit - cursor; lab4: { lab5: { int v_4 = limit - cursor; lab6: { ket = cursor; if (!r_mark_lArI()) { break lab6; } bra = cursor; slice_del(); break lab5; } cursor = limit - v_4; lab7: { ket = cursor; lab8: { int v_5 = limit - cursor; lab9: { if (!r_mark_possessives()) { break lab9; } break lab8; } cursor = limit - v_5; if (!r_mark_sU()) { break lab7; } } bra = cursor; slice_del(); int v_6 = limit - cursor; lab10: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_6; break lab10; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_6; break lab10; } } break lab5; } cursor = limit - v_4; ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_3; break lab4; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_3; break lab4; } } } break lab0; } cursor = limit - v_1; lab11: { ket = cursor; lab12: { int v_7 = limit - cursor; lab13: { if (!r_mark_ndA()) { break lab13; } break lab12; } cursor = limit - v_7; if (!r_mark_nA()) { break lab11; } } lab14: { int v_8 = limit - cursor; lab15: { if (!r_mark_lArI()) { break lab15; } bra = cursor; slice_del(); break lab14; } cursor = limit - v_8; lab16: { if (!r_mark_sU()) { break lab16; } bra = cursor; slice_del(); int v_9 = limit - cursor; lab17: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_9; break lab17; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_9; break lab17; } } break lab14; } cursor = limit - v_8; if (!r_stem_suffix_chain_before_ki()) { break lab11; } } break lab0; } cursor = limit - v_1; lab18: { ket = cursor; lab19: { int v_10 = limit - cursor; lab20: { if (!r_mark_ndAn()) { break lab20; } break lab19; } cursor = limit - v_10; if (!r_mark_nU()) { break lab18; } } lab21: { int v_11 = limit - cursor; lab22: { if (!r_mark_sU()) { break lab22; } bra = cursor; slice_del(); int v_12 = limit - cursor; lab23: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_12; break lab23; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_12; break lab23; } } break lab21; } cursor = limit - v_11; if (!r_mark_lArI()) { break lab18; } } break lab0; } cursor = limit - v_1; lab24: { ket = cursor; if (!r_mark_DAn()) { break lab24; } bra = cursor; slice_del(); int v_13 = limit - cursor; lab25: { ket = cursor; lab26: { int v_14 = limit - cursor; lab27: { if (!r_mark_possessives()) { break lab27; } bra = cursor; slice_del(); int v_15 = limit - cursor; lab28: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_15; break lab28; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_15; break lab28; } } break lab26; } cursor = limit - v_14; lab29: { if (!r_mark_lAr()) { break lab29; } bra = cursor; slice_del(); int v_16 = limit - cursor; lab30: { if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_16; break lab30; } } break lab26; } cursor = limit - v_14; if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_13; break lab25; } } } break lab0; } cursor = limit - v_1; lab31: { ket = cursor; lab32: { int v_17 = limit - cursor; lab33: { if (!r_mark_nUn()) { break lab33; } break lab32; } cursor = limit - v_17; if (!r_mark_ylA()) { break lab31; } } bra = cursor; slice_del(); int v_18 = limit - cursor; lab34: { lab35: { int v_19 = limit - cursor; lab36: { ket = cursor; if (!r_mark_lAr()) { break lab36; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { break lab36; } break lab35; } cursor = limit - v_19; lab37: { ket = cursor; lab38: { int v_20 = limit - cursor; lab39: { if (!r_mark_possessives()) { break lab39; } break lab38; } cursor = limit - v_20; if (!r_mark_sU()) { break lab37; } } bra = cursor; slice_del(); int v_21 = limit - cursor; lab40: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_21; break lab40; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_21; break lab40; } } break lab35; } cursor = limit - v_19; if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_18; break lab34; } } } break lab0; } cursor = limit - v_1; lab41: { ket = cursor; if (!r_mark_lArI()) { break lab41; } bra = cursor; slice_del(); break lab0; } cursor = limit - v_1; lab42: { if (!r_stem_suffix_chain_before_ki()) { break lab42; } break lab0; } cursor = limit - v_1; lab43: { ket = cursor; lab44: { int v_22 = limit - cursor; lab45: { if (!r_mark_DA()) { break lab45; } break lab44; } cursor = limit - v_22; lab46: { if (!r_mark_yU()) { break lab46; } break lab44; } cursor = limit - v_22; if (!r_mark_yA()) { break lab43; } } bra = cursor; slice_del(); int v_23 = limit - cursor; lab47: { ket = cursor; lab48: { int v_24 = limit - cursor; lab49: { if (!r_mark_possessives()) { break lab49; } bra = cursor; slice_del(); int v_25 = limit - cursor; lab50: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_25; break lab50; } } break lab48; } cursor = limit - v_24; if (!r_mark_lAr()) { cursor = limit - v_23; break lab47; } } bra = cursor; slice_del(); ket = cursor; if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_23; break lab47; } } break lab0; } cursor = limit - v_1; ket = cursor; lab51: { int v_26 = limit - cursor; lab52: { if (!r_mark_possessives()) { break lab52; } break lab51; } cursor = limit - v_26; if (!r_mark_sU()) { return false; } } bra = cursor; slice_del(); int v_27 = limit - cursor; lab53: { ket = cursor; if (!r_mark_lAr()) { cursor = limit - v_27; break lab53; } bra = cursor; slice_del(); if (!r_stem_suffix_chain_before_ki()) { cursor = limit - v_27; break lab53; } } } return true; } private boolean r_post_process_last_consonants() { int among_var; ket = cursor; among_var = find_among_b(a_23); if (among_var == 0) { return false; } bra = cursor; switch (among_var) { case 1: slice_from("p"); break; case 2: slice_from("\u00E7"); break; case 3: slice_from("t"); break; case 4: slice_from("k"); break; } return true; } private boolean r_append_U_to_stems_ending_with_d_or_g() { ket = cursor; bra = cursor; lab0: { int v_1 = limit - cursor; lab1: { if (!(eq_s_b("d"))) { break lab1; } break lab0; } cursor = limit - v_1; if (!(eq_s_b("g"))) { return false; } } golab2: while (true) { int v_2 = limit - cursor; lab3: { if (!(in_grouping_b(g_vowel, 97, 305))) { break lab3; } cursor = limit - v_2; break golab2; } cursor = limit - v_2; if (cursor <= limit_backward) { return false; } cursor--; } lab4: { int v_3 = limit - cursor; lab5: { lab6: { int v_4 = limit - cursor; lab7: { if (!(eq_s_b("a"))) { break lab7; } break lab6; } cursor = limit - v_4; if (!(eq_s_b("\u0131"))) { break lab5; } } slice_from("\u0131"); break lab4; } cursor = limit - v_3; lab8: { lab9: { int v_5 = limit - cursor; lab10: { if (!(eq_s_b("e"))) { break lab10; } break lab9; } cursor = limit - v_5; if (!(eq_s_b("i"))) { break lab8; } } slice_from("i"); break lab4; } cursor = limit - v_3; lab11: { lab12: { int v_6 = limit - cursor; lab13: { if (!(eq_s_b("o"))) { break lab13; } break lab12; } cursor = limit - v_6; if (!(eq_s_b("u"))) { break lab11; } } slice_from("u"); break lab4; } cursor = limit - v_3; lab14: { int v_7 = limit - cursor; lab15: { if (!(eq_s_b("\u00F6"))) { break lab15; } break lab14; } cursor = limit - v_7; if (!(eq_s_b("\u00FC"))) { return false; } } slice_from("\u00FC"); } return true; } private boolean r_is_reserved_word() { if (!(eq_s_b("ad"))) { return false; } int v_1 = limit - cursor; lab0: { if (!(eq_s_b("soy"))) { cursor = limit - v_1; break lab0; } } if (cursor > limit_backward) { return false; } return true; } private boolean r_remove_proper_noun_suffix() { int v_1 = cursor; lab0: { golab1: while (true) { int v_2 = cursor; lab2: { if (!(eq_s("'"))) { break lab2; } cursor = v_2; break golab1; } cursor = v_2; if (cursor >= limit) { break lab0; } cursor++; } bra = cursor; cursor = limit; ket = cursor; slice_del(); } cursor = v_1; return true; } private boolean r_more_than_one_syllable_word() { int v_1 = cursor; for (int v_2 = 2; v_2 > 0; v_2--) { golab0: while (true) { lab1: { if (!(in_grouping(g_vowel, 97, 305))) { break lab1; } break golab0; } if (cursor >= limit) { return false; } cursor++; } } cursor = v_1; return true; } private boolean r_postlude() { limit_backward = cursor; cursor = limit; { int v_1 = limit - cursor; lab0: { if (!r_is_reserved_word()) { break lab0; } return false; } cursor = limit - v_1; } int v_2 = limit - cursor; r_append_U_to_stems_ending_with_d_or_g(); cursor = limit - v_2; int v_3 = limit - cursor; r_post_process_last_consonants(); cursor = limit - v_3; cursor = limit_backward; return true; } @Override public boolean stem() { r_remove_proper_noun_suffix(); if (!r_more_than_one_syllable_word()) { return false; } limit_backward = cursor; cursor = limit; int v_2 = limit - cursor; r_stem_nominal_verb_suffixes(); cursor = limit - v_2; if (!(B_continue_stemming_noun_suffixes)) { return false; } int v_3 = limit - cursor; r_stem_noun_suffixes(); cursor = limit - v_3; cursor = limit_backward; if (!r_postlude()) { return false; } return true; } @Override public boolean equals(Object o) { return o instanceof turkishStemmer; } @Override public int hashCode() { return turkishStemmer.class.getName().hashCode(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/AbstractTokenizer.java0100644 0000000 0000000 00000002455 15217274217 034046 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import opennlp.tools.util.Span; abstract class AbstractTokenizer implements Tokenizer { protected boolean keepNewLines = false; @Override public String[] tokenize(String s) { return Span.spansToStrings(tokenizePos(s), s); } /** * Switches whether to keep new lines or not. * * @param keepNewLines {@code True} if new lines are kept, {@code false} otherwise. */ public void setKeepNewLines(boolean keepNewLines) { this.keepNewLines = keepNewLines; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Default0100644 0000000 0000000 00000000170 15217274217 032533 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DefaultTokenContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DefaultTokenContextGene0100644 0000000 0000000 00000011627 15217274217 034222 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import opennlp.tools.util.StringUtil; /** * A default {@link TokenContextGenerator} which produces events for maxent decisions * for tokenization. */ public class DefaultTokenContextGenerator implements TokenContextGenerator { protected final Set inducedAbbreviations; /** * Initializes a plain {@link DefaultTokenContextGenerator} instance. */ public DefaultTokenContextGenerator() { this(Collections.emptySet()); } /** * Initializes a customized {@link DefaultTokenContextGenerator} instance via * a set of {@code inducedAbbreviations}. * * @param inducedAbbreviations The induced abbreviations to be used for this instance. */ public DefaultTokenContextGenerator(Set inducedAbbreviations) { this.inducedAbbreviations = inducedAbbreviations; } @Override public String[] getContext(String sentence, int index) { List preds = createContext(sentence, index); String[] context = new String[preds.size()]; preds.toArray(context); return context; } /** * Computes a {@link List} of features for the specified {@code sentence} * at the specified {@code index}. Extensions of {@link DefaultTokenContextGenerator} * can override this method to create a customized behaviour. * * @param sentence * The sentence to create features for. * @param index * The positional index. Must be a non-negative number or {@code 0}. * @return A {@link List} of features for the specified {@code sentence} string * at the specified index. */ protected List createContext(String sentence, int index) { List preds = new ArrayList<>(); String prefix = sentence.substring(0, index); String suffix = sentence.substring(index); preds.add("p=" + prefix); preds.add("s=" + suffix); if (index > 0) { addCharPreds("p1", sentence.charAt(index - 1), preds); if (index > 1) { addCharPreds("p2", sentence.charAt(index - 2), preds); preds.add("p21=" + sentence.charAt(index - 2) + sentence.charAt(index - 1)); } else { preds.add("p2=bok"); } preds.add("p1f1=" + sentence.charAt(index - 1) + sentence.charAt(index)); } else { preds.add("p1=bok"); } addCharPreds("f1", sentence.charAt(index), preds); if (index + 1 < sentence.length()) { addCharPreds("f2", sentence.charAt(index + 1), preds); preds.add("f12=" + sentence.charAt(index) + sentence.charAt(index + 1)); } else { preds.add("f2=bok"); } if (sentence.charAt(0) == '&' && sentence.charAt(sentence.length() - 1) == ';') { preds.add("cc");//character code } if (index == sentence.length() - 1 && inducedAbbreviations.contains(sentence)) { preds.add("pabb"); } return preds; } /** * Helper function for {@link #createContext} that appends to a given {@code key} * a fixed text sequence depending on {@code c}. The resulting combination is added * to the given list {@code preds}. * * @param key The input string to process. * @param c A character used to discriminate which fixed text shall be appended. * @param preds The list into which the resulting combinations will be added. */ protected void addCharPreds(String key, char c, List preds) { preds.add(key + "=" + c); if (Character.isLetter(c)) { preds.add(key + "_alpha"); if (Character.isUpperCase(c)) { preds.add(key + "_caps"); } } else if (Character.isDigit(c)) { preds.add(key + "_num"); } else if (StringUtil.isWhitespace(c)) { preds.add(key + "_ws"); } else { if (c == '.' || c == '?' || c == '!') { preds.add(key + "_eos"); } else if (c == '`' || c == '"' || c == '\'') { preds.add(key + "_quote"); } else if (c == '[' || c == '{' || c == '(') { preds.add(key + "_lp"); } else if (c == ']' || c == '}' || c == ')') { preds.add(key + "_rp"); } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Detoken0100644 0000000 0000000 00000000164 15217274217 032543 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DetokenizationDictionary.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DetokenizationDictionar0100644 0000000 0000000 00000015616 15217274217 034317 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import opennlp.tools.dictionary.serializer.Attributes; import opennlp.tools.dictionary.serializer.DictionaryEntryPersistor; import opennlp.tools.dictionary.serializer.Entry; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.StringList; public class DetokenizationDictionary { public enum Operation { /** * Attaches the token to the token on the right side. */ MOVE_RIGHT, /** * Attaches the token to the token on the left side. */ MOVE_LEFT, /** * Attaches the token to the token on the left and right sides. */ MOVE_BOTH, /** * Attaches the token to the right token on first occurrence, and * to the token on the left side on the second occurrence. */ RIGHT_LEFT_MATCHING; /** * @param operation The string representation for which an {@link Operation} * instance is to be found. * @return The {@link Operation enum} instance that matches the given {@code operation}, * or {@code null} if the input has no equivalent. */ public static Operation parse(String operation) { if (operation == null) { return null; } else { if (MOVE_RIGHT.toString().equals(operation)) { return MOVE_RIGHT; } else if (MOVE_LEFT.toString().equals(operation)) { return MOVE_LEFT; } else if (MOVE_BOTH.toString().equals(operation)) { return MOVE_BOTH; } else if (RIGHT_LEFT_MATCHING.toString().equals(operation)) { return RIGHT_LEFT_MATCHING; } else { return null; } } } } private final Map operationTable = new HashMap<>(); /** * Initializes a {@link DetokenizationDictionary} instance. * * @param tokens An array of tokens that should be de-tokenized according to {@code operations}. * @param operations An array of operations which specifies which operation * should be used for the provided {@code tokens}. */ public DetokenizationDictionary(String[] tokens, DetokenizationDictionary.Operation[] operations) { if (tokens.length != operations.length) throw new IllegalArgumentException("tokens and ops must have the same length: tokens=" + tokens.length + ", operations=" + operations.length + "!"); for (int i = 0; i < tokens.length; i++) { String token = tokens[i]; DetokenizationDictionary.Operation operation = operations[i]; if (token == null) throw new IllegalArgumentException("token at index " + i + " must not be null!"); if (operation == null) throw new IllegalArgumentException("operation at index " + i + " must not be null!"); operationTable.put(token, operation); } } /** * Initializes a {@link DetokenizationDictionary} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the dictionary. * * @throws IOException Thrown if IO errors occurred during initialization. */ public DetokenizationDictionary(InputStream in) throws IOException { init(in); } /** * Initializes a {@link DetokenizationDictionary} instance via a valid {@link File}. * * @param file The {@link File} used for loading the dictionary. * * @throws IOException Thrown if IO errors occurred during initialization. */ public DetokenizationDictionary(File file) throws IOException { try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { init(in); } } /** * Initializes a {@link DetokenizationDictionary} instance via a valid {@link Path}. * * @param path The {@link Path} used for loading the dictionary. * * @throws IOException Thrown if IO errors occurred during initialization. */ public DetokenizationDictionary(Path path) throws IOException { this(path.toFile()); } /* * Builds up the dictionary from an InputStream. */ private void init(InputStream in) throws IOException { DictionaryEntryPersistor.create(in, entry -> { String operationString = entry.attributes().getValue("operation"); StringList word = entry.tokens(); if (word.size() != 1) throw new InvalidFormatException("Each entry must have exactly one token! " + word); // parse operation Operation operation = Operation.parse(operationString); if (operation == null) throw new InvalidFormatException("Unknown operation type: " + operationString); operationTable.put(word.getToken(0), operation); }); } /** * @param token The input string for which a valid {@link Operation} is to be found. * @return The {@link Operation} that fits the given {@code token}. */ DetokenizationDictionary.Operation getOperation(String token) { return operationTable.get(token); } /** * Serializes the current state of a {@link DetokenizationDictionary} via an * {@link OutputStream output stream}. * * @param out A valid, open {@link OutputStream} ready to be used for serialization. * @throws IOException Thrown if IO errors occurred during serialization. */ public void serialize(OutputStream out) throws IOException { Iterator entries = new Iterator<>() { final Iterator iterator = operationTable.keySet().iterator(); public boolean hasNext() { return iterator.hasNext(); } public Entry next() { String token = iterator.next(); Attributes attributes = new Attributes(); attributes.setValue("operation", getOperation(token).toString()); return new Entry(new StringList(token), attributes); } public void remove() { throw new UnsupportedOperationException(); } }; DictionaryEntryPersistor.serialize(out, entries, false); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/Detokenizer.java0100644 0000000 0000000 00000004614 15217274217 032672 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; /** * A {@link Detokenizer} merges tokens back to their detokenized representation. */ public interface Detokenizer { /** * This enum contains an operation for every token to merge the * tokens together to their detokenized form. */ enum DetokenizationOperation { /** * The current token should be attached to the start token on the right side. */ MERGE_TO_RIGHT, /** * The current token should be attached to the string on the left side. */ MERGE_TO_LEFT, /** * The current token should be attached to the string on the left side, as * well as to the start token on the right side. */ MERGE_BOTH, /** * Do not perform a merge operation for this token, but is possible that another * token can be attached to the left or right side of this one. */ NO_OPERATION } /** * Detokenizes the collection of tokens. * * @param tokens The elements which should be detokenized. * @return The {@link DetokenizationOperation merge operations} to handle * given {@code tokens}. */ DetokenizationOperation[] detokenize(String[] tokens); /** * Detokenizes the input {@code tokens} into a String. Tokens which * are connected without a {@code whitespace} character in * between can be separated by a given {@code splitMarker}. * * @param tokens The elements which should be concatenated. * @param splitMarker The split marker or {@code null}. * * @return The concatenated tokens as a single string. */ String detokenize(String[] tokens, String splitMarker); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Detoken0100644 0000000 0000000 00000000160 15217274217 032537 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DetokenizerEvaluator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DetokenizerEvaluator.ja0100644 0000000 0000000 00000005134 15217274217 034224 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.ArrayList; import opennlp.tools.cmdline.tokenizer.DetokenEvaluationErrorListener; import opennlp.tools.util.Span; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.FMeasure; /** * The {@link DetokenizerEvaluator} measures the performance of * the given {@link Detokenizer} with the provided reference * {@link TokenSample samples}. * * @see Detokenizer * @see TokenSample */ public class DetokenizerEvaluator extends Evaluator { private final FMeasure fmeasure = new FMeasure(); /** * The {@link Detokenizer} used to create the predicted tokens. */ private final Detokenizer detokenizer; /** * Initializes the current instance with the * given {@link Detokenizer}. * * @param detokenizer The {@link Detokenizer} to evaluate. * @param listeners The {@link DetokenEvaluationErrorListener evaluation sample listeners}. */ public DetokenizerEvaluator(Detokenizer detokenizer, DetokenEvaluationErrorListener... listeners) { super(listeners); this.detokenizer = detokenizer; } @Override protected TokenSample processSample(TokenSample reference) { String[] tokens = Span.spansToStrings(reference.getTokenSpans(), reference.getText()); String tokensstring = detokenizer.detokenize(tokens, null); ArrayList predictionsArray = new ArrayList<>(); ArrayList referencesArray = new ArrayList<>(); predictionsArray.add(tokensstring); referencesArray.add(reference.getText()); Object[] references = referencesArray.toArray(); Object[] predictions = predictionsArray.toArray(); fmeasure.updateScores(references, predictions); return new TokenSample(tokensstring, reference.getTokenSpans()); } public FMeasure getFMeasure() { return fmeasure; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Diction0100644 0000000 0000000 00000000161 15217274217 032540 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DictionaryDetokenizer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/DictionaryDetokenizer.j0100644 0000000 0000000 00000011475 15217274217 034233 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.HashSet; import java.util.Set; /** * A rule based detokenizer. Simple rules which indicate in which direction a token should be * moved are looked up in a {@link DetokenizationDictionary dictionary}. * * @see Detokenizer * @see DetokenizationDictionary */ public class DictionaryDetokenizer implements Detokenizer { private final DetokenizationDictionary dict; /** * Initializes a {@link DictionaryDetokenizer} instance. * * @param dict The {@link DetokenizationDictionary} to be used. */ public DictionaryDetokenizer(DetokenizationDictionary dict) { this.dict = dict; } @Override public DetokenizationOperation[] detokenize(String[] tokens) { DetokenizationOperation[] operations = new DetokenizationOperation[tokens.length]; Set matchingTokens = new HashSet<>(); for (int i = 0; i < tokens.length; i++) { DetokenizationDictionary.Operation dictOperation = dict.getOperation(tokens[i]); if (dictOperation == null) { operations[i] = Detokenizer.DetokenizationOperation.NO_OPERATION; } else if (DetokenizationDictionary.Operation.MOVE_LEFT.equals(dictOperation)) { operations[i] = Detokenizer.DetokenizationOperation.MERGE_TO_LEFT; } else if (DetokenizationDictionary.Operation.MOVE_RIGHT.equals(dictOperation)) { operations[i] = Detokenizer.DetokenizationOperation.MERGE_TO_RIGHT; } else if (DetokenizationDictionary.Operation.MOVE_BOTH.equals(dictOperation)) { operations[i] = Detokenizer.DetokenizationOperation.MERGE_BOTH; } else if (DetokenizationDictionary.Operation.RIGHT_LEFT_MATCHING.equals(dictOperation)) { if (matchingTokens.contains(tokens[i])) { // The token already occurred once, move it to the left // and clear the occurrence flag operations[i] = Detokenizer.DetokenizationOperation.MERGE_TO_LEFT; matchingTokens.remove(tokens[i]); } else { // First time this token is seen, move it to the right // and remember it operations[i] = Detokenizer.DetokenizationOperation.MERGE_TO_RIGHT; matchingTokens.add(tokens[i]); } } else { throw new IllegalStateException("Unknown operation: " + dictOperation); } } return operations; } @Override public String detokenize(String[] tokens, String splitMarker) { DetokenizationOperation[] operations = detokenize(tokens); if (tokens.length != operations.length) throw new IllegalArgumentException("tokens and operations array must have same length: tokens=" + tokens.length + ", operations=" + operations.length + "!"); StringBuilder untokenizedString = new StringBuilder(); for (int i = 0; i < tokens.length; i++) { // attach token to string buffer untokenizedString.append(tokens[i]); boolean isAppendSpace; boolean isAppendSplitMarker; // if this token is the last token do not attach a space if (i + 1 == operations.length) { isAppendSpace = false; isAppendSplitMarker = false; } // if next token move left, no space after this token, // its safe to access next token else if (operations[i + 1].equals(DetokenizationOperation.MERGE_TO_LEFT) || operations[i + 1].equals(DetokenizationOperation.MERGE_BOTH)) { isAppendSpace = false; isAppendSplitMarker = true; } // if this token is move right, no space else if (operations[i].equals(DetokenizationOperation.MERGE_TO_RIGHT) || operations[i].equals(DetokenizationOperation.MERGE_BOTH)) { isAppendSpace = false; isAppendSplitMarker = true; } else { isAppendSpace = true; isAppendSplitMarker = false; } if (isAppendSpace) { untokenizedString.append(' '); } if (isAppendSplitMarker && splitMarker != null) { untokenizedString.append(splitMarker); } } return untokenizedString.toString(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/SimpleTokenizer.java0100644 0000000 0000000 00000006452 15217274217 033535 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.ArrayList; import java.util.List; import opennlp.tools.util.Span; import opennlp.tools.util.StringUtil; /** * A basic {@link Tokenizer} implementation which performs tokenization * using character classes. *

* To obtain an instance of this tokenizer use the static final * {@link #INSTANCE} field. */ public class SimpleTokenizer extends AbstractTokenizer { static class CharacterEnum { static final CharacterEnum WHITESPACE = new CharacterEnum("whitespace"); static final CharacterEnum ALPHABETIC = new CharacterEnum("alphabetic"); static final CharacterEnum NUMERIC = new CharacterEnum("numeric"); static final CharacterEnum OTHER = new CharacterEnum("other"); private final String name; private CharacterEnum(String name) { this.name = name; } @Override public String toString() { return name; } } /** * Use this static reference to retrieve an instance of the * {@link SimpleTokenizer}. */ public static final SimpleTokenizer INSTANCE = new SimpleTokenizer(); private SimpleTokenizer() { } @Override public Span[] tokenizePos(String s) { CharacterEnum charType = CharacterEnum.WHITESPACE; CharacterEnum state = charType; List tokens = new ArrayList<>(); int sl = s.length(); int start = -1; char pc = 0; for (int ci = 0; ci < sl; ci++) { char c = s.charAt(ci); if (StringUtil.isWhitespace(c)) { charType = CharacterEnum.WHITESPACE; } else if (Character.isAlphabetic(c)) { charType = CharacterEnum.ALPHABETIC; } else if (Character.isDigit(c)) { charType = CharacterEnum.NUMERIC; } else { charType = CharacterEnum.OTHER; } if (state == CharacterEnum.WHITESPACE) { if (charType != CharacterEnum.WHITESPACE) { start = ci; } } else { if (charType != state || charType == CharacterEnum.OTHER && c != pc) { tokens.add(new Span(start, ci)); start = ci; } } if (keepNewLines && isLineSeparator(c)) { tokens.add(new Span(start, start + 1)); start = start + 1; } state = charType; pc = c; } if (charType != CharacterEnum.WHITESPACE) { tokens.add(new Span(start, sl)); } return tokens.toArray(new Span[0]); } private boolean isLineSeparator(char character) { return character == Character.LINE_SEPARATOR || character == Character.LETTER_NUMBER; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_ThreadS0100644 0000000 0000000 00000000161 15217274217 032501 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/ThreadSafeTokenizerME.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/ThreadSafeTokenizerME.j0100644 0000000 0000000 00000007413 15217274217 034042 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.IOException; import opennlp.tools.commons.ThreadSafe; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.Probabilistic; import opennlp.tools.models.ModelType; import opennlp.tools.util.DownloadUtil; import opennlp.tools.util.Span; /** * A thread-safe version of {@link TokenizerME}. Using it is completely transparent. * You can use it in a single-threaded context as well, it only incurs a minimal overhead. *

* Note:
* This implementation uses a {@link ThreadLocal}. Although the implementation is * lightweight because the model is not duplicated, if you have many long-running threads, * you may run into memory problems. *

* Be careful when using this in a Jakarta EE application, for example. *

* The user is responsible for clearing the {@link ThreadLocal} * via calling {@link #close()}. * * @see Probabilistic * @see Tokenizer * @see TokenizerME */ @ThreadSafe public class ThreadSafeTokenizerME implements Tokenizer, Probabilistic, AutoCloseable { private final TokenizerModel model; private final Dictionary abbDict; private final ThreadLocal threadLocal = new ThreadLocal<>(); /** * Initializes a {@link ThreadSafeTokenizerME} by downloading a default model * for a given {@code language}. * * @param language An ISO conform language code. * @throws IOException Thrown if the model could not be downloaded or saved. */ public ThreadSafeTokenizerME(String language) throws IOException { this(DownloadUtil.downloadModel(language, ModelType.TOKENIZER, TokenizerModel.class)); } /** * Initializes a {@link ThreadSafeTokenizerME} with the specified {@code model}. * * @param model A valid {@link TokenizerModel}. */ public ThreadSafeTokenizerME(TokenizerModel model) { this(model, model.getAbbreviations()); } /** * Instantiates a {@link ThreadSafeTokenizerME} with an existing {@link TokenizerModel}. * * @param model The {@link TokenizerModel} to be used. * @param abbDict The {@link Dictionary} to be used. It must fit the language of the {@code model}. */ public ThreadSafeTokenizerME(TokenizerModel model, Dictionary abbDict) { this.model = model; this.abbDict = abbDict; } private TokenizerME getTokenizer() { TokenizerME tokenizer = threadLocal.get(); if (tokenizer == null) { tokenizer = new TokenizerME(model, abbDict); threadLocal.set(tokenizer); } return tokenizer; } @Override public String[] tokenize(String s) { return getTokenizer().tokenize(s); } @Override public Span[] tokenizePos(String s) { return getTokenizer().tokenizePos(s); } @Override public double[] probs() { return getTokenizer().probs(); } /** * @deprecated Use {@link #probs()} instead. */ @Deprecated(forRemoval = true, since = "2.5.5") public double[] getProbabilities() { return probs(); } @Override public void close() { threadLocal.remove(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_TokSpan0100644 0000000 0000000 00000000156 15217274217 032532 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokSpanEventStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokSpanEventStream.java0100644 0000000 0000000 00000014650 15217274217 034145 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.tokenize.lang.Factory; import opennlp.tools.util.AbstractEventStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * This class reads the {@link TokenSample samples} via an {@link Iterator} * and converts the samples into {@link Event events} which * can be used by the maxent library for training. */ public class TokSpanEventStream extends AbstractEventStream { private static final Logger logger = LoggerFactory.getLogger(TokSpanEventStream.class); private final TokenContextGenerator cg; private final boolean skipAlphaNumerics; private final Pattern alphaNumeric; /** * Initializes a new event stream based on the data stream using a {@link TokenContextGenerator}. * * @param tokenSamples The {@link ObjectStream data stream} for this event stream. * @param skipAlphaNumerics Whether alphanumerics are skipped, or not. * @param alphaNumeric A custom alphanumeric {@link Pattern} or {@code null}. * Default is: {@code "^[A-Za-z0-9]+$"}, provided by * {@link Factory#DEFAULT_ALPHANUMERIC}. * @param cg A {@link TokenContextGenerator} which should be used for the event stream {@code d}. */ public TokSpanEventStream(ObjectStream tokenSamples, boolean skipAlphaNumerics, Pattern alphaNumeric, TokenContextGenerator cg) { super(tokenSamples); this.alphaNumeric = alphaNumeric; this.skipAlphaNumerics = skipAlphaNumerics; this.cg = cg; } /** * Initializes a new event stream based on the data stream using a {@link TokenContextGenerator}. * * @param tokenSamples The {@link ObjectStream data stream} for this event stream. * @param skipAlphaNumerics Whether alphanumerics are skipped, or not. * @param cg A {@link TokenContextGenerator} which should be used for the event stream {@code d}. */ public TokSpanEventStream(ObjectStream tokenSamples, boolean skipAlphaNumerics, TokenContextGenerator cg) { this(tokenSamples, skipAlphaNumerics, new Factory().getAlphanumeric(null), cg ); } /** * Initializes a new event stream based on the data stream using a {@link TokenContextGenerator} * that relies on a {@link DefaultTokenContextGenerator}. * * @param tokenSamples The {@link ObjectStream data stream} for this event stream. * @param skipAlphaNumerics Whether alphanumerics are skipped, or not. */ public TokSpanEventStream(ObjectStream tokenSamples, boolean skipAlphaNumerics) { this(tokenSamples, skipAlphaNumerics, new DefaultTokenContextGenerator()); } /** * Adds training events to the event stream for each of the specified {@link TokenSample sample}. * * @param tokenSample character offsets into the specified text. * @return An {@link Iterator} for text {@link Event events} representing the {@code tokenSample}. */ @Override protected Iterator createEvents(TokenSample tokenSample) { List events = new ArrayList<>(50); Span[] tokens = tokenSample.getTokenSpans(); String text = tokenSample.getText(); if (tokens.length > 0) { int start = tokens[0].getStart(); int end = tokens[tokens.length - 1].getEnd(); String sent = text.substring(start, end); Span[] candTokens = WhitespaceTokenizer.INSTANCE.tokenizePos(sent); int firstTrainingToken = -1; int lastTrainingToken = -1; for (Span candToken : candTokens) { Span cSpan = candToken; String ctok = sent.substring(cSpan.getStart(), cSpan.getEnd()); //adjust cSpan to text offsets cSpan = new Span(cSpan.getStart() + start, cSpan.getEnd() + start); //should we skip this token if (ctok.length() > 1 && (!skipAlphaNumerics || !alphaNumeric.matcher(ctok).matches())) { //find offsets of annotated tokens inside of candidate tokens boolean foundTrainingTokens = false; for (int ti = lastTrainingToken + 1; ti < tokens.length; ti++) { if (cSpan.contains(tokens[ti])) { if (!foundTrainingTokens) { firstTrainingToken = ti; foundTrainingTokens = true; } lastTrainingToken = ti; } else if (cSpan.getEnd() < tokens[ti].getEnd()) { break; } else if (tokens[ti].getEnd() < cSpan.getStart()) { //keep looking } else { logger.warn("Bad training token: {} cand: {} token={}", tokens[ti], cSpan, text.substring(tokens[ti].getStart(), tokens[ti].getEnd())); } } // create training data if (foundTrainingTokens) { for (int ti = firstTrainingToken; ti <= lastTrainingToken; ti++) { Span tSpan = tokens[ti]; int cStart = cSpan.getStart(); for (int i = tSpan.getStart() + 1; i < tSpan.getEnd(); i++) { String[] context = cg.getContext(ctok, i - cStart); events.add(new Event(TokenizerME.NO_SPLIT, context)); } if (tSpan.getEnd() != cSpan.getEnd()) { String[] context = cg.getContext(ctok, tSpan.getEnd() - cStart); events.add(new Event(TokenizerME.SPLIT, context)); } } } } } } return events.iterator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_TokenCo0100644 0000000 0000000 00000000161 15217274217 032511 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenContextGenerator.j0100644 0000000 0000000 00000002320 15217274217 034203 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; /** * Interface for context generators required for {@link TokenizerME}. */ public interface TokenContextGenerator { /** * @param sentence The string that represents a sentence. * @param index The index to consider splitting tokens. * * @return An array of features for a {@code sentence} at the specified {@code index}. */ String[] getContext(String sentence, int index); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenSample.java0100644 0000000 0000000 00000016716 15217274217 032637 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import opennlp.tools.commons.Sample; import opennlp.tools.tokenize.Detokenizer.DetokenizationOperation; import opennlp.tools.util.Span; /** * A {@link TokenSample} is text with token spans. */ public class TokenSample implements Sample { private static final long serialVersionUID = 8520715903833887047L; public static final String DEFAULT_SEPARATOR_CHARS = ""; private static final String separatorChars = DEFAULT_SEPARATOR_CHARS; private final String text; private final List tokenSpans; /** * Initializes a {@link TokenSample instance}. * * @param text The text which contains the tokens. * Must not be {@code null}. * @param tokenSpans The spans which mark the start and end of the tokens. * Must not be {@code null}. */ public TokenSample(String text, Span[] tokenSpans) { Objects.requireNonNull(tokenSpans, "tokenSpans must not be null"); this.text = Objects.requireNonNull(text, "text must not be null"); this.tokenSpans = List.of(tokenSpans); for (Span tokenSpan : tokenSpans) { if (tokenSpan.getStart() < 0 || tokenSpan.getStart() > text.length() || tokenSpan.getEnd() > text.length() || tokenSpan.getEnd() < 0) { throw new IllegalArgumentException("Span " + tokenSpan + " is out of bounds, text length: " + text.length() + "!"); } } } /** * Initializes a {@link TokenSample instance} via a {@link Detokenizer}. * * @param detokenizer The text which contains the tokens. Must not be {@code null}. * @param tokens The tokens to be processed. Must not be {@code null}. */ public TokenSample(Detokenizer detokenizer, String[] tokens) { Objects.requireNonNull(detokenizer, "detokenizer must not be null"); Objects.requireNonNull(tokens, "tokens must not be null"); DetokenizationOperation[] operations = detokenizer.detokenize(tokens); List mergedTokenSpans = new ArrayList<>(); StringBuilder sentence = new StringBuilder(); for (int i = 0; i < operations.length; i++) { boolean isSeparateFromPreviousToken = i > 0 && !isMergeToRight(operations[i - 1]) && !isMergeToLeft(operations[i]); if (isSeparateFromPreviousToken) { sentence.append(' '); } int beginIndex = sentence.length(); sentence.append(tokens[i]); mergedTokenSpans.add(new Span(beginIndex, sentence.length())); } text = sentence.toString(); tokenSpans = Collections.unmodifiableList(mergedTokenSpans); } private boolean isMergeToRight(DetokenizationOperation operation) { return DetokenizationOperation.MERGE_TO_RIGHT.equals(operation) || DetokenizationOperation.MERGE_BOTH.equals(operation); } private boolean isMergeToLeft(DetokenizationOperation operation) { return DetokenizationOperation.MERGE_TO_LEFT.equals(operation) || DetokenizationOperation.MERGE_BOTH.equals(operation); } /** * @return Retrieves the text. */ public String getText() { return text; } /** * @return Retrieves the token {@link Span spans}. */ public Span[] getTokenSpans() { return tokenSpans.toArray(new Span[0]); } @Override public String toString() { StringBuilder sentence = new StringBuilder(); int lastEndIndex = -1; for (Span token : tokenSpans) { if (lastEndIndex != -1) { // If there are no chars between last token // and this token insert the separator chars // otherwise insert a space String separator; if (lastEndIndex == token.getStart()) separator = separatorChars; else separator = " "; sentence.append(separator); } sentence.append(token.getCoveredText(text)); lastEndIndex = token.getEnd(); } return sentence.toString(); } private static void addToken(StringBuilder sample, List tokenSpans, String token, boolean isNextMerged) { int tokenSpanStart = sample.length(); sample.append(token); int tokenSpanEnd = sample.length(); tokenSpans.add(new Span(tokenSpanStart, tokenSpanEnd)); if (!isNextMerged) sample.append(" "); } /** * Parses a string sample. * * @param sampleString The sample to be parsed. Must not be {@code null}. * @param separatorChars The characters to be considered separators. * See {@link #DEFAULT_SEPARATOR_CHARS}. Must not be {@code null}. * @return A valid {@link TokenSample} instance. */ public static TokenSample parse(String sampleString, String separatorChars) { Objects.requireNonNull(sampleString, "sampleString must not be null"); Objects.requireNonNull(separatorChars, "separatorChars must not be null"); Span[] whitespaceTokenSpans = WhitespaceTokenizer.INSTANCE.tokenizePos(sampleString); // Pre-allocate 20% for newly created tokens List realTokenSpans = new ArrayList<>((int) (whitespaceTokenSpans.length * 1.2d)); StringBuilder untaggedSampleString = new StringBuilder(); for (Span whiteSpaceTokenSpan : whitespaceTokenSpans) { String whitespaceToken = whiteSpaceTokenSpan.getCoveredText(sampleString).toString(); boolean wasTokenReplaced = false; int tokStart = 0; int tokEnd; while ((tokEnd = whitespaceToken.indexOf(separatorChars, tokStart)) > -1) { String token = whitespaceToken.substring(tokStart, tokEnd); addToken(untaggedSampleString, realTokenSpans, token, true); tokStart = tokEnd + separatorChars.length(); wasTokenReplaced = true; } if (wasTokenReplaced) { // If the token contains the split chars at least once // a span for the last token must still be added String token = whitespaceToken.substring(tokStart); addToken(untaggedSampleString, realTokenSpans, token, false); } else { // If it does not contain the split chars at lest once // just copy the original token span addToken(untaggedSampleString, realTokenSpans, whitespaceToken, false); } } return new TokenSample(untaggedSampleString.toString(), realTokenSpans.toArray( new Span[0])); } @Override public int hashCode() { return Objects.hash(getText(), Arrays.hashCode(getTokenSpans())); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof TokenSample a) { return getText().equals(a.getText()) && Arrays.equals(getTokenSpans(), a.getTokenSpans()); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenSampleStream.java0100644 0000000 0000000 00000005571 15217274217 034010 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.IOException; import java.util.Objects; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; /** * This class is a {@link FilterObjectStream stream filter} which reads in string encoded * samples and creates {@link TokenSample samples} out of them. * The input string sample is tokenized if a whitespace or the special separator chars occur. *

* Sample:
* "token1 token2 token3<SPLIT>token4"
* The tokens {@code token1} and {@code token2} are separated by a whitespace, * {@code token3} and {@code token4} are separated by the special character sequence. * In this case, the default split sequence applies. *

* Note: The sequence must be unique in the input string and is not escaped. */ public class TokenSampleStream extends FilterObjectStream { private final String separatorChars; /** * Initializes a {@link TokenSampleStream instance}. * * @param samples A plain text {@link ObjectStream line stream}. * Must not be {@code null}. * @param separatorChars The characters to be considered separators. * See {@link TokenSample#DEFAULT_SEPARATOR_CHARS}. * Must not be {@code null}. */ public TokenSampleStream(ObjectStream samples, String separatorChars) { super(Objects.requireNonNull(samples, "sampleStrings must not be null")); this.separatorChars = Objects.requireNonNull(separatorChars,"separatorChars must not be null"); } /** * Initializes a {@link TokenSampleStream instance}. * * @param sentences A plain text {@link ObjectStream line stream}. * Must not be {@code null}. */ public TokenSampleStream(ObjectStream sentences) { this(sentences, TokenSample.DEFAULT_SEPARATOR_CHARS); } @Override public TokenSample read() throws IOException { String sampleString = samples.read(); if (sampleString != null) { return TokenSample.parse(sampleString, separatorChars); } else { return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/Tokenizer.java0100644 0000000 0000000 00000005117 15217274217 032360 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import opennlp.tools.util.Span; /** * The interface for tokenizers, which segment a string into its tokens. *

* Tokenization is a necessary step before more complex NLP tasks can be applied. * These usually process text on a token level. The quality of tokenization is * important because it influences the performance of high-level task applied to it. *

* In segmented languages like English most words are segmented by whitespaces * expect for punctuations, etc. which is directly attached to the word without a white space * in between, it is not possible to just split at all punctuations because in abbreviations dots * are a part of the token itself. A {@link Tokenizer} is now responsible to split those tokens * correctly. *

* In non-segmented languages like Chinese, tokenization is more difficult since words * are not segmented by a whitespace. *

* Tokenizers can also be used to segment already identified tokens further into more * atomic parts to get a deeper understanding. This approach helps more complex task * to gain insight into tokens which do not represent words like numbers, units or tokens * which are part of a special notation. *

* For most subsequent NLP tasks, it is desirable to over-tokenize rather than to under-tokenize. */ public interface Tokenizer { /** * Splits a string into its atomic parts. * * @param s The string to be tokenized. * @return The String[] with the individual tokens as the array elements. */ String[] tokenize(String s); /** * Finds the boundaries of atomic parts in a string. * * @param s The string to be tokenized. * @return The {@link Span spans (offsets into {@code s})} for each token as the individuals array elements. */ Span[] tokenizePos(String s); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Tokeniz0100644 0000000 0000000 00000000163 15217274217 032574 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerCrossValidator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerCrossValidator0100644 0000000 0000000 00000005717 15217274217 034326 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.IOException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.TrainingParameters; import opennlp.tools.util.eval.CrossValidationPartitioner; import opennlp.tools.util.eval.FMeasure; /** * A cross validator for {@link Tokenizer tokenizers}. */ public class TokenizerCrossValidator { private final TrainingParameters params; private final FMeasure fmeasure = new FMeasure(); private final TokenizerEvaluationMonitor[] listeners; private final TokenizerFactory factory; /** * Creates a {@link TokenizerCrossValidator} using the given {@link TokenizerFactory}. * * @param params The {@link TrainingParameters} for the context of cross validation. * @param factory The {@link TokenizerFactory} to be used. * @param listeners The {@link TokenizerEvaluationMonitor evaluation listeners}. */ public TokenizerCrossValidator(TrainingParameters params, TokenizerFactory factory, TokenizerEvaluationMonitor... listeners) { this.params = params; this.listeners = listeners; this.factory = factory; } /** * Starts the evaluation. * * @param samples The {@link ObjectStream} of {@link TokenSample samples} to train and test with. * @param nFolds Number of folds. It must be greater than zero. * * @throws IOException Thrown if IO errors occurred during evaluation. */ public void evaluate(ObjectStream samples, int nFolds) throws IOException { CrossValidationPartitioner partitioner = new CrossValidationPartitioner<>(samples, nFolds); while (partitioner.hasNext()) { CrossValidationPartitioner.TrainingSampleStream trainingSampleStream = partitioner.next(); // Maybe throws IOException if temporary file handling fails ... TokenizerModel model = TokenizerME.train(trainingSampleStream, this.factory, params); TokenizerEvaluator evaluator = new TokenizerEvaluator(new TokenizerME(model), listeners); evaluator.evaluate(trainingSampleStream.getTestSampleStream()); fmeasure.mergeInto(evaluator.getFMeasure()); } } public FMeasure getFMeasure() { return fmeasure; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Tokeniz0100644 0000000 0000000 00000000166 15217274217 032577 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerEvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerEvaluationMoni0100644 0000000 0000000 00000002031 15217274217 034303 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import opennlp.tools.util.eval.EvaluationMonitor; /** * A marker interface for evaluating {@link Tokenizer tokenizers}. */ public interface TokenizerEvaluationMonitor extends EvaluationMonitor { } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Tokeniz0100644 0000000 0000000 00000000156 15217274217 032576 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerEvaluator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerEvaluator.java0100644 0000000 0000000 00000004104 15217274217 034236 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import opennlp.tools.util.Span; import opennlp.tools.util.eval.Evaluator; import opennlp.tools.util.eval.FMeasure; /** * The {@link TokenizerEvaluator} measures the performance of * the given {@link Tokenizer} with the provided reference * {@link TokenSample samples}. * * @see Evaluator * @see Tokenizer * @see TokenSample */ public class TokenizerEvaluator extends Evaluator { private final FMeasure fmeasure = new FMeasure(); /** * The {@link Tokenizer} used to create the predicted tokens. */ private final Tokenizer tokenizer; /** * Initializes an instance to evaluate a {@link Tokenizer}. * * @param tokenizer The {@link Tokenizer} to evaluate. * @param listeners The {@link TokenizerEvaluationMonitor evaluation listeners}. */ public TokenizerEvaluator(Tokenizer tokenizer, TokenizerEvaluationMonitor ... listeners) { super(listeners); this.tokenizer = tokenizer; } @Override protected TokenSample processSample(TokenSample reference) { Span[] predictions = tokenizer.tokenizePos(reference.getText()); fmeasure.updateScores(reference.getTokenSpans(), predictions); return new TokenSample(reference.getText(), predictions); } public FMeasure getFMeasure() { return fmeasure; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerFactory.java0100644 0000000 0000000 00000022107 15217274217 033706 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.tokenize.lang.Factory; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.ext.ExtensionLoader; /** * The factory that provides {@link Tokenizer} default implementation and * resources. Users can extend this class if their application requires * overriding the {@link TokenContextGenerator}, {@link Dictionary} etc. */ public class TokenizerFactory extends BaseToolFactory { private String languageCode; private Dictionary abbreviationDictionary; private Boolean useAlphaNumericOptimization = false; private Pattern alphaNumericPattern; private static final String ABBREVIATIONS_ENTRY_NAME = "abbreviations.dictionary"; private static final String USE_ALPHA_NUMERIC_OPTIMIZATION = "useAlphaNumericOptimization"; private static final String ALPHA_NUMERIC_PATTERN = "alphaNumericPattern"; /** * Instantiates a {@link TokenizerFactory} that provides the default implementation * of the resources. */ public TokenizerFactory() { } /** * Instantiates a {@link TokenizerFactory}. Use this constructor to * programmatically create a factory. * * @param languageCode The ISO language code to be used for this factory. * @param abbreviationDictionary The {@link Dictionary} which holds abbreviations. * @param useAlphaNumericOptimization Whether alphanumerics are skipped, or not. * @param alphaNumericPattern {@code null} or a custom alphanumeric {@link Pattern} * (default is: {@code "^[A-Za-z0-9]+$"}, provided by * {@link Factory#DEFAULT_ALPHANUMERIC}. */ public TokenizerFactory(String languageCode, Dictionary abbreviationDictionary, boolean useAlphaNumericOptimization, Pattern alphaNumericPattern) { this.init(languageCode, abbreviationDictionary, useAlphaNumericOptimization, alphaNumericPattern); } /** * @param languageCode The ISO language code to be used for this factory. * @param abbreviationDictionary The {@link Dictionary} which holds abbreviations. * @param useAlphaNumericOptimization Whether alphanumerics are skipped, or not. * @param alphaNumericPattern {@code null} or a custom alphanumeric {@link Pattern} * (default is: {@code "^[A-Za-z0-9]+$"}, provided by * {@link Factory#DEFAULT_ALPHANUMERIC}. */ protected void init(String languageCode, Dictionary abbreviationDictionary, boolean useAlphaNumericOptimization, Pattern alphaNumericPattern) { this.languageCode = languageCode; this.useAlphaNumericOptimization = useAlphaNumericOptimization; this.alphaNumericPattern = alphaNumericPattern; this.abbreviationDictionary = abbreviationDictionary; } @Override public void validateArtifactMap() throws InvalidFormatException { if (this.artifactProvider.getManifestProperty(USE_ALPHA_NUMERIC_OPTIMIZATION) == null) throw new InvalidFormatException(USE_ALPHA_NUMERIC_OPTIMIZATION + " is a mandatory property!"); Object abbreviationsEntry = this.artifactProvider.getArtifact(ABBREVIATIONS_ENTRY_NAME); if (abbreviationsEntry != null && !(abbreviationsEntry instanceof Dictionary)) { throw new InvalidFormatException("Abbreviations dictionary '" + abbreviationsEntry + "' has wrong type, needs to be of type Dictionary!"); } } @Override public Map createArtifactMap() { Map artifactMap = super.createArtifactMap(); // Abbreviations are optional if (abbreviationDictionary != null) { artifactMap.put(ABBREVIATIONS_ENTRY_NAME, abbreviationDictionary); } return artifactMap; } @Override public Map createManifestEntries() { Map manifestEntries = super.createManifestEntries(); manifestEntries.put(USE_ALPHA_NUMERIC_OPTIMIZATION, Boolean.toString(isUseAlphaNumericOptimization())); // alphanumeric pattern is optional if (getAlphaNumericPattern() != null) { manifestEntries.put(ALPHA_NUMERIC_PATTERN, getAlphaNumericPattern().pattern()); } return manifestEntries; } /** * Factory method the framework uses instantiate a new {@link TokenizerFactory}. * * @param subclassName The name of the class implementing the {@link TokenizerFactory}. * @param languageCode The ISO language code the {@link Tokenizer} should use. * @param abbreviationDictionary An optional {@link Dictionary} containing abbreviations, * or {@code null} if not present. * @param useAlphaNumericOptimization Whether the alphanumeric optimization is be enabled or not. * @param alphaNumericPattern The {@link Pattern} the alphanumeric optimization should use, * if enabled. * * @return A valid {@link TokenizerFactory} instance. * * @throws InvalidFormatException Thrown if one of the input parameters doesn't comply the expected format. */ public static TokenizerFactory create(String subclassName, String languageCode, Dictionary abbreviationDictionary, boolean useAlphaNumericOptimization, Pattern alphaNumericPattern) throws InvalidFormatException { if (subclassName == null) { // will create the default factory return new TokenizerFactory(languageCode, abbreviationDictionary, useAlphaNumericOptimization, alphaNumericPattern); } try { TokenizerFactory theFactory = ExtensionLoader.instantiateExtension( TokenizerFactory.class, subclassName); theFactory.init(languageCode, abbreviationDictionary, useAlphaNumericOptimization, alphaNumericPattern); return theFactory; } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization throw an exception."; throw new InvalidFormatException(msg, e); } } /** * @return Retrieves the (user-)specified alphanumeric {@link Pattern} or a default. */ public Pattern getAlphaNumericPattern() { if (this.alphaNumericPattern == null) { if (this.artifactProvider != null) { String prop = this.artifactProvider.getManifestProperty(ALPHA_NUMERIC_PATTERN); if (prop != null) { this.alphaNumericPattern = Pattern.compile(prop); } } // could not load from manifest, will get from language dependent factory if (this.alphaNumericPattern == null) { Factory f = new Factory(); this.alphaNumericPattern = f.getAlphanumeric(languageCode); } } return this.alphaNumericPattern; } /** * @return {@code true} if the alphanumeric optimization is enabled, otherwise {@code false}. */ public boolean isUseAlphaNumericOptimization() { if (artifactProvider != null) { this.useAlphaNumericOptimization = Boolean.valueOf(this.artifactProvider .getManifestProperty(USE_ALPHA_NUMERIC_OPTIMIZATION)); } return this.useAlphaNumericOptimization; } /** * @return The abbreviation {@link Dictionary} or {@code null} if none is active. */ public Dictionary getAbbreviationDictionary() { if (this.abbreviationDictionary == null && artifactProvider != null) { this.abbreviationDictionary = this.artifactProvider.getArtifact(ABBREVIATIONS_ENTRY_NAME); } return this.abbreviationDictionary; } /** * @return Retrieves the ISO language code in use. */ public String getLanguageCode() { if (this.languageCode == null && this.artifactProvider != null) { this.languageCode = this.artifactProvider.getLanguage(); } return this.languageCode; } /** * @return Retrieves a {@link TokenContextGenerator} instance. */ public TokenContextGenerator getContextGenerator() { Factory f = new Factory(); Set abbs; Dictionary abbDict = getAbbreviationDictionary(); if (abbDict != null) { abbs = abbDict.asStringSet(); } else { abbs = Collections.emptySet(); } return f.createTokenContextGenerator(getLanguageCode(), abbs); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerME.java0100644 0000000 0000000 00000023303 15217274217 032577 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.ArrayMath; import opennlp.tools.ml.EventTrainer; import opennlp.tools.ml.Probabilistic; import opennlp.tools.ml.TrainerFactory; import opennlp.tools.ml.model.Event; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.models.ModelType; import opennlp.tools.util.DownloadUtil; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; import opennlp.tools.util.StringList; import opennlp.tools.util.TrainingParameters; /** * A {@link Tokenizer} for converting raw text into separated tokens. It uses * Maximum Entropy to make its decisions. The features are loosely * based off of Jeff Reynar's UPenn thesis "Topic Segmentation: * Algorithms and Applications.", which is available from his * homepage: http://www.cis.upenn.edu/~jcreynar. *

* This implementation needs a statistical model to tokenize a text which reproduces * the tokenization observed in the training data used to create the model. * The {@link TokenizerModel} class encapsulates that model and provides * methods to create it from the binary representation. *

* A tokenizer instance is not thread-safe. For each thread, one tokenizer * must be instantiated which can share one {@link TokenizerModel} instance * to safe memory. *

* To train a new model, the {@link #train(ObjectStream, TokenizerFactory, TrainingParameters)} method * can be used. *

* Sample usage: *

* * InputStream modelIn;
*
* ...
*
* TokenizerModel model = TokenizerModel(modelIn);
*
* Tokenizer tokenizer = new TokenizerME(model);
*
* String tokens[] = tokenizer.tokenize("A sentence to be tokenized."); *
* * @see Tokenizer * @see TokenizerModel * @see TokenSample * @see Probabilistic */ public class TokenizerME extends AbstractTokenizer implements Probabilistic { /** * Constant indicates a token split. */ public static final String SPLIT = "T"; /** * Constant indicates no token split. */ public static final String NO_SPLIT = "F"; private final Pattern alphanumeric; /* * The maximum entropy model to use to evaluate contexts. */ private final MaxentModel model; /* * The context generator. */ private final TokenContextGenerator cg; /* * Optimization flag to skip alphanumeric tokens for further tokenization */ private final boolean useAlphaNumericOptimization; /* * List of probabilities for each token returned from a call to * tokenize or tokenizePos. */ private final List tokProbs; private final List newTokens; /* * The {@link Dictionary abbreviation dictionary} if available (may be {@code null}). */ private final Dictionary abbDict; /** * Initializes a {@link TokenizerME} by downloading a default model. * @param language The language of the tokenizer. * @throws IOException Thrown if the model cannot be downloaded or saved. */ public TokenizerME(String language) throws IOException { this(DownloadUtil.downloadModel(language, ModelType.TOKENIZER, TokenizerModel.class)); } /** * Instantiates a {@link TokenizerME} with an existing {@link TokenizerModel}. * * @param model The {@link TokenizerModel} to be used. */ public TokenizerME(TokenizerModel model) { this(model, model.getAbbreviations()); } /** * Instantiates a {@link TokenizerME} with an existing {@link TokenizerModel}. * * @param model The {@link TokenizerModel} to be used. * @param abbDict The {@link Dictionary} to be used. It must fit the language of the {@code model}. */ public TokenizerME(TokenizerModel model, Dictionary abbDict) { this.model = model.getMaxentModel(); this.abbDict = abbDict; TokenizerFactory factory = model.getFactory(); this.cg = factory.getContextGenerator(); this.alphanumeric = factory.getAlphaNumericPattern(); this.useAlphaNumericOptimization = factory.isUseAlphaNumericOptimization(); newTokens = new ArrayList<>(); tokProbs = new ArrayList<>(50); } /** * {@inheritDoc} * * The sequence was determined based on the previous call to {@link #tokenizePos(String)}. * * @return An array with the same number of probabilities as tokens were sent to * the computational method when {@link #tokenizePos(String)} was last called. * If not applicable an empty array is returned. */ @Override public double[] probs() { return ArrayMath.toDoubleArray(tokProbs); } /** * @return the probabilities associated with the most recent calls to * {@link #tokenizePos(String)}. * If not applicable an empty array is returned. * * @deprecated Use {@link #probs()} instead. */ @Deprecated(forRemoval = true, since = "2.5.5") public double[] getTokenProbabilities() { return probs(); } /** * Tokenizes the string. * * @param d The string to be tokenized. * * @return A {@link Span} array containing individual tokens as elements. */ @Override public Span[] tokenizePos(String d) { WhitespaceTokenizer whitespaceTokenizer = WhitespaceTokenizer.INSTANCE; whitespaceTokenizer.setKeepNewLines(keepNewLines); Span[] tokens = whitespaceTokenizer.tokenizePos(d); newTokens.clear(); tokProbs.clear(); for (Span s : tokens) { String tok = d.substring(s.getStart(), s.getEnd()); // Can't tokenize single characters if (tok.length() < 2) { newTokens.add(s); tokProbs.add(1d); } else if (useAlphaNumericOptimization() && alphanumeric.matcher(tok).matches()) { newTokens.add(s); tokProbs.add(1d); } else { int start = s.getStart(); int end = s.getEnd(); final int origStart = s.getStart(); double tokenProb = 1.0; for (int j = origStart + 1; j < end; j++) { double[] probs = model.eval(cg.getContext(tok, j - origStart)); String best = model.getBestOutcome(probs); tokenProb *= probs[model.getIndex(best)]; if (best.equals(TokenizerME.SPLIT)) { if (isAcceptableAbbreviation(tok)) { newTokens.add(new Span(start, end)); tokProbs.add(tokenProb); long numberOfDots = tok.codePoints().filter(ch -> ch == '.').count(); j = j + (int) numberOfDots; // To compensate for abbreviation dot(s) start = j + 1; } else { newTokens.add(new Span(start, j)); tokProbs.add(tokenProb); start = j; } tokenProb = 1.0; } } if (start < end) { newTokens.add(new Span(start, end)); tokProbs.add(tokenProb); } } } Span[] spans = new Span[newTokens.size()]; newTokens.toArray(spans); return spans; } /** * Trains a model for the {@link TokenizerME}. * * @param samples The samples used for the training. * @param factory A {@link TokenizerFactory} to get resources from. * @param mlParams The machine learning {@link TrainingParameters train parameters}. * @return A trained {@link TokenizerModel}. * @throws IOException Thrown during IO operations on a temp file which is created * during training. Or if reading from the {@link ObjectStream} fails. */ public static TokenizerModel train(ObjectStream samples, TokenizerFactory factory, TrainingParameters mlParams) throws IOException { Map manifestInfoEntries = new HashMap<>(); ObjectStream eventStream = new TokSpanEventStream(samples, factory.isUseAlphaNumericOptimization(), factory.getAlphaNumericPattern(), factory.getContextGenerator()); EventTrainer trainer = TrainerFactory.getEventTrainer( mlParams, manifestInfoEntries); MaxentModel maxentModel = trainer.train(eventStream); return new TokenizerModel(maxentModel, manifestInfoEntries, factory); } /** * @return {@code true} if the tokenizer uses alphanumeric optimization, {@code false} otherwise. */ public boolean useAlphaNumericOptimization() { return useAlphaNumericOptimization; } /** * Allows checking a token abbreviation candidate for acceptability. * *

Note: The implementation always returns {@code false} if no * abbreviation dictionary is available for the underlying model.

* * @param s the {@link CharSequence token} to check for. * @return {@code true} if the candidate is acceptable, {@code false} otherwise. */ protected boolean isAcceptableAbbreviation(CharSequence s) { if (abbDict == null) return false; return abbDict.contains(new StringList(s.toString())); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerModel.java0100644 0000000 0000000 00000014033 15217274217 033336 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Path; import java.util.Map; import java.util.Objects; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.ml.model.MaxentModel; import opennlp.tools.util.BaseToolFactory; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.BaseModel; import opennlp.tools.util.model.ModelUtil; /** * The {@link TokenizerModel} is the model used * by a learnable {@link Tokenizer}. * * @see TokenizerME * @see TokenizerFactory */ public final class TokenizerModel extends BaseModel { private static final long serialVersionUID = 42334333400920419L; private static final String COMPONENT_NAME = "TokenizerME"; private static final String TOKENIZER_MODEL_ENTRY = "token.model"; /** * Initializes a {@link TokenizerModel} instance via a {@link MaxentModel} and related resources. * * @param tokenizerModel The {@link MaxentModel model} to be used. * @param manifestInfoEntries Additional information kept in the manifest. * @param tokenizerFactory The {@link TokenizerFactory} to be used internally. */ public TokenizerModel(MaxentModel tokenizerModel, Map manifestInfoEntries, TokenizerFactory tokenizerFactory) { super(COMPONENT_NAME, tokenizerFactory.getLanguageCode(), manifestInfoEntries, tokenizerFactory); artifactMap.put(TOKENIZER_MODEL_ENTRY, tokenizerModel); checkArtifactMap(); } /** * Initializes a {@link TokenizerModel} instance via a valid {@link InputStream}. * * @param in The {@link InputStream} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenizerModel(InputStream in) throws IOException { super(COMPONENT_NAME, in); } /** * Initializes a {@link TokenizerModel} instance via a valid {@link File}. * * @param modelFile The {@link File} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenizerModel(File modelFile) throws IOException { super(COMPONENT_NAME, modelFile); } /** * Initializes a {@link TokenizerModel} instance via a valid {@link Path}. * * @param modelPath The {@link Path} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenizerModel(Path modelPath) throws IOException { this(modelPath.toFile()); } /** * Initializes a {@link TokenizerModel} instance via a valid {@link URL}. * * @param modelURL The {@link URL} used for loading the model. * * @throws IOException Thrown if IO errors occurred during initialization. */ public TokenizerModel(URL modelURL) throws IOException { super(COMPONENT_NAME, modelURL); } /** * Checks if the {@link TokenizerModel} has the right outcomes. * * @param model The {@link MaxentModel} to be checked. * @return {@code true} if the model could be validated, {@code false} otherwise. */ private static boolean isModelCompatible(MaxentModel model) { return ModelUtil.validateOutcomes(model, TokenizerME.SPLIT, TokenizerME.NO_SPLIT); } @Override protected void validateArtifactMap() throws InvalidFormatException { super.validateArtifactMap(); if (!(artifactMap.get(TOKENIZER_MODEL_ENTRY) instanceof AbstractModel)) { throw new InvalidFormatException("Token model is incomplete!"); } if (!isModelCompatible(getMaxentModel())) { throw new InvalidFormatException("The maxent model is not compatible with the tokenizer!"); } } /** * @return Retrieves the active {@link TokenizerFactory}. */ public TokenizerFactory getFactory() { return (TokenizerFactory) this.toolFactory; } @Override protected Class getDefaultFactory() { return TokenizerFactory.class; } /** * @return Retrieves the model as {@link MaxentModel} instance. */ public MaxentModel getMaxentModel() { return (MaxentModel) artifactMap.get(TOKENIZER_MODEL_ENTRY); } /** * @return Retrieves the active abbreviation {@link Dictionary}. */ public Dictionary getAbbreviations() { if (getFactory() != null) { return getFactory().getAbbreviationDictionary(); } return null; } /** * @return {@code true} if alphanumeric optimization is active, {@code false} otherwise. */ public boolean useAlphaNumericOptimization() { return getFactory() != null && getFactory().isUseAlphaNumericOptimization(); } @Override public int hashCode() { return Objects.hash(artifactMap.get(MANIFEST_ENTRY), artifactMap.get(TOKENIZER_MODEL_ENTRY)); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof TokenizerModel model) { Map artifactMapToCheck = model.artifactMap; AbstractModel abstractModel = (AbstractModel) artifactMapToCheck.get(TOKENIZER_MODEL_ENTRY); return artifactMap.get(MANIFEST_ENTRY).equals(artifactMapToCheck.get(MANIFEST_ENTRY)) && artifactMap.get(TOKENIZER_MODEL_ENTRY).equals(abstractModel); } return false; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/TokenizerStream.java0100644 0000000 0000000 00000003750 15217274217 033535 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.IOException; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * The {@link TokenizerStream} uses a {@link Tokenizer} to tokenize the * input string and output {@link TokenSample samples}. */ public class TokenizerStream implements ObjectStream { private final Tokenizer tokenizer; private final ObjectStream input; /** * Initializes a {@link TokenizerStream instance}. * * @param tokenizer A working {@link Tokenizer} instance. * @param input A plain text {@link ObjectStream line stream}. */ public TokenizerStream(Tokenizer tokenizer, ObjectStream input) { this.tokenizer = tokenizer; this.input = input; } @Override public TokenSample read() throws IOException { String inputString = input.read(); if (inputString != null) { Span[] tokens = tokenizer.tokenizePos(inputString); return new TokenSample(inputString, tokens); } return null; } @Override public void close() throws IOException { input.close(); } @Override public void reset() throws IOException, UnsupportedOperationException { input.reset(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Whitesp0100644 0000000 0000000 00000000161 15217274217 032572 xustar000000000 0000000 113 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/WhitespaceTokenStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/WhitespaceTokenStream.j0100644 0000000 0000000 00000004203 15217274217 034162 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.io.IOException; import opennlp.tools.util.FilterObjectStream; import opennlp.tools.util.ObjectStream; import opennlp.tools.util.Span; /** * This stream formats {@link ObjectStream} of {@link TokenSample samples} into whitespace * separated token strings. */ public class WhitespaceTokenStream extends FilterObjectStream { /** * Initializes a {@link WhitespaceTokenStream}. * * @param tokens The {@link ObjectStream stream} of tokens to be separated. */ public WhitespaceTokenStream(ObjectStream tokens) { super(tokens); } @Override public String read() throws IOException { TokenSample tokenSample = samples.read(); if (tokenSample != null) { StringBuilder whitespaceSeparatedTokenString = new StringBuilder(); for (Span token : tokenSample.getTokenSpans()) { whitespaceSeparatedTokenString.append( token.getCoveredText(tokenSample.getText())); whitespaceSeparatedTokenString.append(' '); } // Shorten string by one to get rid of last space if (whitespaceSeparatedTokenString.length() > 0) { whitespaceSeparatedTokenString.setLength( whitespaceSeparatedTokenString.length() - 1 ); } return whitespaceSeparatedTokenString.toString(); } return null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Whitesp0100644 0000000 0000000 00000000157 15217274217 032577 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/WhitespaceTokenizer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/WhitespaceTokenizer.jav0100644 0000000 0000000 00000004707 15217274217 034240 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.ArrayList; import java.util.List; import opennlp.tools.util.Span; import opennlp.tools.util.StringUtil; /** * A basic {@link Tokenizer} implementation which performs tokenization * using white spaces. *

* To obtain an instance of this tokenizer use the static final * {@link #INSTANCE} field. */ public class WhitespaceTokenizer extends AbstractTokenizer { /** * Use this static reference to retrieve an instance of the * {@link WhitespaceTokenizer}. */ public static final WhitespaceTokenizer INSTANCE = new WhitespaceTokenizer(); /* * Use the {@link WhitespaceTokenizer#INSTANCE} field to retrieve an instance. */ private WhitespaceTokenizer() { } @Override public Span[] tokenizePos(String d) { int tokStart = -1; List tokens = new ArrayList<>(); boolean inTok = false; // gather potential tokens int end = d.length(); for (int i = 0; i < end; i++) { if (StringUtil.isWhitespace(d.charAt(i))) { if (inTok) { tokens.add(new Span(tokStart, i)); inTok = false; tokStart = -1; } if (keepNewLines && isLineSeparator(d.charAt(i))) { tokStart = i; tokens.add(new Span(tokStart, tokStart + 1)); tokStart = -1; } } else { if (!inTok) { tokStart = i; inTok = true; } } } if (inTok) { tokens.add(new Span(tokStart, end)); } return tokens.toArray(new Span[0]); } private boolean isLineSeparator(char character) { return character == Character.LINE_SEPARATOR || character == Character.LETTER_NUMBER; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_Wordpie0100644 0000000 0000000 00000000156 15217274217 032564 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/WordpieceTokenizer.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/WordpieceTokenizer.java0100644 0000000 0000000 00000015475 15217274217 034232 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import opennlp.tools.util.Span; /** * A {@link Tokenizer} implementation which performs tokenization * using word pieces. *

* Adapted under MIT license from * https://github.com/robrua/easy-bert. *

* For reference see: *

*/ public class WordpieceTokenizer implements Tokenizer { /** BERT classification token: {@code [CLS]}. */ public static final String BERT_CLS_TOKEN = "[CLS]"; /** BERT separator token: {@code [SEP]}. */ public static final String BERT_SEP_TOKEN = "[SEP]"; /** BERT unknown token: {@code [UNK]}. */ public static final String BERT_UNK_TOKEN = "[UNK]"; /** RoBERTa classification token: {@code }. */ public static final String ROBERTA_CLS_TOKEN = ""; /** RoBERTa separator token. */ public static final String ROBERTA_SEP_TOKEN = ""; /** RoBERTa unknown token. */ public static final String ROBERTA_UNK_TOKEN = ""; private static final Pattern PUNCTUATION_PATTERN = Pattern.compile("\\p{Punct}+"); private final Set vocabulary; private final String classificationToken; private final String separatorToken; private final String unknownToken; private int maxTokenLength = 50; /** * Initializes a {@link WordpieceTokenizer} with a {@code vocabulary} and a default * {@code maxTokenLength} of {@code 50}. * * @param vocabulary A set of tokens considered the vocabulary. */ public WordpieceTokenizer(Set vocabulary) { this(vocabulary, BERT_CLS_TOKEN, BERT_SEP_TOKEN, BERT_UNK_TOKEN); } /** * Initializes a {@link WordpieceTokenizer} with a {@code vocabulary} and a custom * {@code maxTokenLength}. * * @param vocabulary A set of tokens considered the vocabulary. * @param maxTokenLength A non-negative number that is used as maximum token length. */ public WordpieceTokenizer(Set vocabulary, int maxTokenLength) { this(vocabulary); this.maxTokenLength = maxTokenLength; } /** * Initializes a {@link WordpieceTokenizer} with a * {@code vocabulary} and custom special tokens. * This allows support for models like RoBERTa that * use different special tokens instead of the BERT * defaults. * * @param vocabulary The vocabulary. * @param classificationToken The CLS token. * @param separatorToken The SEP token. * @param unknownToken The UNK token. */ public WordpieceTokenizer( final Set vocabulary, final String classificationToken, final String separatorToken, final String unknownToken) { this.vocabulary = vocabulary; this.classificationToken = classificationToken; this.separatorToken = separatorToken; this.unknownToken = unknownToken; } @Override public Span[] tokenizePos(final String text) { // TODO: Implement this. return null; } @Override public String[] tokenize(final String text) { final List tokens = new LinkedList<>(); tokens.add(classificationToken); // Put spaces around punctuation. final String spacedPunctuation = PUNCTUATION_PATTERN.matcher(text).replaceAll(" $0 "); // Split based on whitespace. final String[] split = WhitespaceTokenizer.INSTANCE.tokenize(spacedPunctuation); // For each resulting word, if the word is found in the WordPiece vocabulary, keep it as-is. // If not, starting from the beginning, pull off the biggest piece that is in the vocabulary, // and prefix "##" to the remaining piece. Repeat until the entire word is represented by // pieces from the vocabulary, if possible. for (final String token : split) { final char[] characters = token.toCharArray(); if (characters.length <= maxTokenLength) { // To start, the substring is the whole token. int start = 0; int end; // Look at the token from the start. while (start < characters.length) { end = characters.length; boolean found = false; // Look at the token from the end until the end is equal to the start. while (start < end) { // The substring is the part of the token we are looking at now. String substring = String.valueOf(characters, start, end - start); // This is a substring so prefix it with ##. if (start > 0) { substring = "##" + substring; } // See if the substring is in the vocabulary. if (vocabulary.contains(substring)) { // It is in the vocabulary so add it to the list of tokens. tokens.add(substring); // Next time we can pick up where we left off. start = end; found = true; break; } // Subtract 1 from the end to find the next longest piece in the vocabulary. end--; } // If the word can't be represented by vocabulary pieces replace // it with a specified "unknown" token. if (!found) { tokens.add(unknownToken); break; } // Start the next characters where we just left off. start = end; } } else { // If the token's length is greater than the max length just add unknown token instead. tokens.add(unknownToken); } } tokens.add(separatorToken); return tokens.toArray(new String[0]); } /** * @return The maximum token length. */ public int getMaxTokenLength() { return maxTokenLength; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/lang/Factory.java0100644 0000000 0000000 00000010523 15217274217 032733 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize.lang; import java.util.Set; import java.util.regex.Pattern; import opennlp.tools.tokenize.DefaultTokenContextGenerator; import opennlp.tools.tokenize.TokenContextGenerator; public class Factory { public static final Pattern DEFAULT_ALPHANUMERIC = Pattern.compile("^[A-Za-z0-9]+$"); private static final Pattern PORTUGUESE = Pattern.compile("^[0-9a-záãâàéêíóõôúüçA-Z�ÃÂÀÉÊ�ÓÕÔÚÜÇ]+$"); private static final Pattern FRENCH = Pattern.compile("^[a-zA-Z0-9àâäèéêëîïôœùûüÿçÀÂÄÈÉÊËÎ�ÔŒÙÛÜŸÇ]+$"); // From: https://www.sttmedia.com/characterfrequency-dutch private static final Pattern DUTCH = Pattern.compile("^[A-Za-z0-9äöüëèéïijÄÖÜËÉÈ�IJ]+$"); // Note: The extra é and É are included to cover German "Lehnwörter" such as "Café" private static final Pattern GERMAN = Pattern.compile("^[A-Za-z0-9äéöüÄÉÖÜß]+$"); // From: https://en.wikipedia.org/wiki/Polish_alphabet // https://pl.wikipedia.org/wiki/Alfabet_polski private static final Pattern POLISH = Pattern.compile("^[A-Za-z0-9żźćńółęąśŻŹĆĄŚĘ�ÓŃ]+$"); // From: https://it.wikipedia.org/wiki/Alfabeto_italiano private static final Pattern ITALIAN = Pattern.compile("^[0-9a-zàèéìîíòóùüA-ZÀÈÉÌÎ�ÒÓÙÜ]+$"); // From: https://en.wikiversity.org/wiki/Alphabet/Spanish_alphabet & // https://en.wikipedia.org/wiki/Spanish_orthography#Alphabet_in_Spanish & // https://www.fundeu.es/consulta/tilde-en-la-y-y-griega-o-ye-24786/ private static final Pattern SPANISH = Pattern.compile("^[0-9a-záéíóúüýñA-Z�É�ÓÚ�Ñ]+$"); // From: https://en.wikipedia.org/wiki/Catalan_orthography#Spelling_patterns private static final Pattern CATALAN = Pattern.compile("^[0-9a-zàèéíïòóúüçA-ZÀÈÉ��ÒÓÚÜÇ]+$"); /** * Gets the alphanumeric pattern for a language. * * @param languageCode The ISO_639-1 code. If {@code null}, or unknown, the * {@link #DEFAULT_ALPHANUMERIC} pattern will be returned. * @return The alphanumeric {@link Pattern} for the language, or the default pattern. */ public Pattern getAlphanumeric(String languageCode) { // For reference: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes if ("es".equals(languageCode) || "spa".equals(languageCode)) { return SPANISH; } if ("it".equals(languageCode) || "ita".equals(languageCode)) { return ITALIAN; } if ("pt".equals(languageCode) || "por".equals(languageCode)) { return PORTUGUESE; } if ("ca".equals(languageCode) || "cat".equals(languageCode)) { return CATALAN; } if ("pl".equals(languageCode) || "pol".equals(languageCode)) { return POLISH; } if ("de".equals(languageCode) || "deu".equals(languageCode) || "ger".equals(languageCode)) { return GERMAN; } if ("fr".equals(languageCode) || "fre".equals(languageCode) || "fra".equals(languageCode)) { return FRENCH; } if ("nl".equals(languageCode) || "nld".equals(languageCode) || "dut".equals(languageCode)) { return DUTCH; } return DEFAULT_ALPHANUMERIC; } /** * Initializes a customized {@link TokenContextGenerator} via a set of {@code abbreviations}. * * @param languageCode The ISO_639-1 code to be used. * @param abbreviations The abbreviations to be used for new instance. */ public TokenContextGenerator createTokenContextGenerator(String languageCode, Set abbreviations) { return new DefaultTokenContextGenerator(abbreviations); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_tokenize_lang_en0100644 0000000 0000000 00000000165 15217274217 032556 xustar000000000 0000000 117 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/lang/en/TokenSampleStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/lang/en/TokenSampleStre0100644 0000000 0000000 00000007667 15217274217 034105 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.tokenize.lang.en; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.tokenize.TokenSample; import opennlp.tools.util.Span; /** * Class which produces an Iterator<TokenSample> from a file of space delimited token. * This class uses a number of English-specific heuristics to un-separate tokens which * are typically found together in text. */ public class TokenSampleStream implements Iterator { private static final Logger logger = LoggerFactory.getLogger(TokenSampleStream.class); private final BufferedReader in; private String line; private final Pattern alphaNumeric = Pattern.compile("[A-Za-z0-9]"); private boolean evenq = true; public TokenSampleStream(InputStream is) throws IOException { this.in = new BufferedReader(new InputStreamReader(is)); line = in.readLine(); } public boolean hasNext() { return line != null; } public TokenSample next() { String[] tokens = line.split("\\s+"); if (tokens.length == 0) { evenq = true; } StringBuilder sb = new StringBuilder(line.length()); List spans = new ArrayList<>(); int length = 0; for (int ti = 0; ti < tokens.length; ti++) { String token = tokens[ti]; String lastToken = ti - 1 >= 0 ? tokens[ti - 1] : ""; token = switch (token) { case "-LRB-" -> "("; case "-LCB-" -> "{"; case "-RRB-" -> ")"; case "-RCB-" -> "}"; default -> token; }; if (sb.length() != 0) { if (!alphaNumeric.matcher(token).find() || token.startsWith("'") || token.equalsIgnoreCase("n't")) { if ((token.equals("``") || token.equals("--") || token.equals("$") || token.equals("(") || token.equals("&") || token.equals("#") || (token.equals("\"") && (evenq && ti != tokens.length - 1))) && (!lastToken.equals("(") || !lastToken.equals("{"))) { length++; } } else { if (!lastToken.equals("``") && (!lastToken.equals("\"") || evenq) && !lastToken.equals("(") && !lastToken.equals("{") && !lastToken.equals("$") && !lastToken.equals("#")) { length++; } } } if (token.equals("\"")) { evenq = ti == tokens.length - 1 || !evenq; } if (sb.length() < length) { sb.append(" "); } sb.append(token); spans.add(new Span(length, length + token.length())); length += token.length(); } try { line = in.readLine(); } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); line = null; } return new TokenSample(sb.toString(),spans.toArray(new Span[0])); } public void remove() { throw new UnsupportedOperationException(); } private static void usage() { logger.info("TokenSampleStream [-spans] < in"); logger.info("Where in is a space delimited list of tokens."); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/tokenize/package-info.java0100644 0000000 0000000 00000002144 15217274217 032727 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Contains classes related to finding token or words in a string. All * tokenizer implement the Tokenizer interface. Currently, there is the * learnable {@code TokenizerME}, the {@code WhitespaceTokenizer} and * the {@code SimpleTokenizer} which is a character class tokenizer. */ package opennlp.tools.tokenize; apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/AbstractEventStream.java0100644 0000000 0000000 00000004603 15217274217 033453 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import opennlp.tools.ml.model.Event; /** * A base {@link ObjectStream} implementation for events. * * @param The generic type representing samples. */ public abstract class AbstractEventStream implements ObjectStream { private final ObjectStream samples; private Iterator events = Collections.emptyIterator(); /** * Initializes an {@link AbstractEventStream} with a sample {@link Iterator}. * * @param samples The {@link Iterator} that provides the {@link T} samples. */ public AbstractEventStream(ObjectStream samples) { this.samples = samples; } /** * Creates events for the provided {@code sample}. * * @param sample The {@link T sample} for which training {@link Event events} are created. * * @return An {@link Iterator} of training events or an empty {@link Iterator}. */ protected abstract Iterator createEvents(T sample); @Override public final Event read() throws IOException { if (events.hasNext()) { return events.next(); } else { T sample; while (!events.hasNext() && (sample = samples.read()) != null) { events = createEvents(sample); } if (events.hasNext()) { return read(); } } return null; } @Override public void reset() throws IOException, UnsupportedOperationException { events = Collections.emptyIterator(); samples.reset(); } @Override public void close() throws IOException { samples.close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/AbstractObjectStream.java0100644 0000000 0000000 00000003131 15217274217 033573 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; /** * A base {@link ObjectStream} implementation. * * @param The generic type representing samples in the stream of samples. */ public abstract class AbstractObjectStream implements ObjectStream { private final ObjectStream stream; /** * Initializes an {@link AbstractObjectStream}. * * @param stream The {@link ObjectStream} that provides the {@link T} samples. */ protected AbstractObjectStream(ObjectStream stream) { this.stream = stream; } @Override public T read() throws IOException { return stream.read(); } @Override public void reset() throws IOException, UnsupportedOperationException { stream.reset(); } @Override public void close() throws IOException { stream.close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/BaseToolFactory.java0100644 0000000 0000000 00000012650 15217274217 032573 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.HashMap; import java.util.Map; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.model.ArtifactProvider; import opennlp.tools.util.model.ArtifactSerializer; /** * Base class for all tool {@code factories}. *

* Extensions of this class should: *

    *
  • implement an empty constructor,
  • *
  • implement a constructor that takes the {@link ArtifactProvider}},
  • *
  • override {@link #createArtifactMap()} and * {@link #createArtifactSerializersMap()} methods if necessary.
  • *
*/ public abstract class BaseToolFactory { protected ArtifactProvider artifactProvider; /** * All subclasses should have an empty constructor */ public BaseToolFactory() { } /** * Initializes the ToolFactory with an artifact provider. */ protected void init(ArtifactProvider artifactProvider) { this.artifactProvider = artifactProvider; } /** * Creates a {@link Map} with pairs of keys and {@link ArtifactSerializer}. * The models implementation should call this method from * {@code BaseModel#createArtifactSerializersMap}. *

* The base implementation will return a {@link HashMap} that should be * populated by subclasses. */ public Map> createArtifactSerializersMap() { return new HashMap<>(); } /** * A model's implementation should call this constructor that creates a model * programmatically. *

* The base implementation will return a {@link HashMap} that should be * populated by subclasses. * * @return Retrieves a {@link Map} with pairs of keys and objects. */ public Map createArtifactMap() { return new HashMap<>(); } /** * @return Retrieves the manifest entries to be added to the model manifest. */ public Map createManifestEntries() { return new HashMap<>(); } /** * Validates the parsed artifacts. *

* Note: * Subclasses should generally invoke {@code super.validateArtifactMap} at the beginning * of this method. * * @throws InvalidFormatException Thrown if validation found invalid states. */ public abstract void validateArtifactMap() throws InvalidFormatException; /** * Instantiates a {@link BaseToolFactory} via a given {@code subclassName}. * * @param subclassName The class name used for instantiation. The {@link ExtensionLoader} * mechanism is applied to load the requested {@code subclassName}. * @param artifactProvider The {@link ArtifactProvider} to be used. * * @return A valid {@link BaseToolFactory} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the factory associated with {@code subclassName}. */ public static BaseToolFactory create(String subclassName, ArtifactProvider artifactProvider) throws InvalidFormatException { BaseToolFactory theFactory; try { // Init the ToolFactory using the ExtensionLoader theFactory = ExtensionLoader.instantiateExtension(BaseToolFactory.class, subclassName); if (theFactory != null) { theFactory.init(artifactProvider); } } catch (Exception e) { String msg = "Could not instantiate the " + subclassName + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } return theFactory; } /** * Instantiates a {@link BaseToolFactory} via a given {@code subclassName}. * * @param factoryClass The class used for instantiation. The no-arg constructor * of that class will be used to create and init the resulting object. * @param artifactProvider The {@link ArtifactProvider} to be used. * * @return A valid {@link BaseToolFactory} instance. * @throws InvalidFormatException Thrown if the {@link ExtensionLoader} mechanism failed to * create the factory associated with {@code subclassName}. */ public static BaseToolFactory create(Class factoryClass, ArtifactProvider artifactProvider) throws InvalidFormatException { BaseToolFactory theFactory = null; if (factoryClass != null) { try { theFactory = factoryClass.getDeclaredConstructor().newInstance(); theFactory.init(artifactProvider); } catch (Exception e) { String msg = "Could not instantiate the " + factoryClass.getCanonicalName() + ". The initialization threw an exception."; throw new InvalidFormatException(msg, e); } } return theFactory; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_BeamSearchC0100644 0000000 0000000 00000000162 15217274217 032372 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/BeamSearchContextGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/BeamSearchContextGenerator.0100644 0000000 0000000 00000003200 15217274217 034066 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; /** * Interface for context generators used with a sequence beam search. */ public interface BeamSearchContextGenerator { /** * Returns the context for the specified position in the specified {@code sequence} (list). * * @param index The index of the {@code sequence}. * @param sequence The sequence of {@link T items} over which the beam search is performed. * @param priorDecisions The sequence of decisions made prior to the context for * which this decision is being made. * @param additionalContext Any additional context specific to a class implementing this interface. * * @return The context for the specified {@code index} in the specified {@code sequence}. */ String[] getContext(int index, T[] sequence, String[] priorDecisions, Object[] additionalContext); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/Cache.java0100644 0000000 0000000 00000002452 15217274217 030535 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.LinkedHashMap; import java.util.Map; /** * Provides fixed size, pre-allocated, least recently used replacement cache. */ public class Cache extends LinkedHashMap { private static final long serialVersionUID = 3037039043085908062L; private final int capacity; public Cache(final int capacity) { this.capacity = capacity; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return this.size() > this.capacity; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_CollectionO0100644 0000000 0000000 00000000156 15217274217 032512 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/CollectionObjectStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/CollectionObjectStream.java0100644 0000000 0000000 00000003003 15217274217 034121 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.Collection; import java.util.Iterator; /** * An {@link ObjectStream} implementation that works on a * {@link Collection} of {@link E} as source for elements. * * @param The generic type of the elements. */ public class CollectionObjectStream implements ObjectStream { private final Collection collection; private Iterator iterator; public CollectionObjectStream(Collection collection) { this.collection = collection; reset(); } @Override public E read() { return iterator.hasNext() ? iterator.next() : null; } @Override public void reset() { this.iterator = collection.iterator(); } @Override public void close() { } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/DownloadUtil.java0100644 0000000 0000000 00000034463 15217274217 032146 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.Formatter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import opennlp.tools.commons.Internal; import opennlp.tools.models.ModelType; import opennlp.tools.util.model.BaseModel; /** * This class facilitates the downloading of pretrained OpenNLP models. */ public class DownloadUtil { private static final Logger logger = LoggerFactory.getLogger(DownloadUtil.class); private static final String BASE_URL = System.getProperty("OPENNLP_DOWNLOAD_BASE_URL", "https://dlcdn.apache.org/opennlp/"); private static final String MODEL_URI_PATH = System.getProperty("OPENNLP_DOWNLOAD_MODEL_PATH", "models/ud-models-1.3/"); private static final String OPENNLP_DOWNLOAD_HOME = "OPENNLP_DOWNLOAD_HOME"; private static Map> availableModels; /** * Checks if a model of the specified {@code modelType} has been downloaded already * for a particular {@code language}. * * @param language The ISO language code of the requested model. * @param modelType The {@link ModelType type} of model. * @return {@code true} if a model exists locally, {@code false} otherwise. * @throws IOException Thrown if IO errors occurred or the computed hash sum * of an associated, local model file was incorrect. */ static boolean existsModel(String language, ModelType modelType) throws IOException { Map modelsByLanguage = getAvailableModels().get(language); if (modelsByLanguage == null) { return false; } else { final String url = modelsByLanguage.get(modelType); if (url != null) { final Path homeDirectory = getDownloadHome(); final String filename = url.substring(url.lastIndexOf("/") + 1); final Path localFile = homeDirectory.resolve(filename); boolean exists; if (Files.exists(localFile)) { // if this does not throw the requested model is valid! validateModel(new URL(url + ".sha512"), localFile); exists = true; } else { exists = false; } return exists; } else { return false; } } } /** * Triggers a download for the specified {@link ModelType}. * * @param language The ISO language code of the requested model. * @param modelType The {@link ModelType type} of model. * @param type The class of the resulting model. * @param The generic type which is a subclass of {@link BaseModel}. * @return A model instance of type {@link T}. * @throws IOException Thrown if IO errors occurred or the model is invalid. */ public static T downloadModel(String language, ModelType modelType, Class type) throws IOException { if (getAvailableModels().containsKey(language)) { final String url = getAvailableModels().get(language).get(modelType); if (url != null) { return downloadModel(new URL(url), type); } } throw new IOException("There is no model available: " + language + " " + modelType.getName()); } /** * Downloads a model from a {@link URL}. *

* The model is saved to an {@code .opennlp/} directory * located in the user's home directory. This directory will be created * if it does not already exist. If a model to be downloaded already * exists in that directory, the model will not be re-downloaded. * * @param url The model's {@link URL}. * @param type The class of the resulting model {@link T}. * @param The generic type which is a subclass of {@link BaseModel}. * @return A model instance of type {@link T}. * @throws IOException Thrown if the model cannot be downloaded. */ public static T downloadModel(URL url, Class type) throws IOException { final Path homeDirectory = getDownloadHome(); if (!Files.isDirectory(homeDirectory)) { try { Files.createDirectories(homeDirectory); } catch (IOException e) { throw new RuntimeException(e); } } final String filename = url.toString().substring(url.toString().lastIndexOf("/") + 1); final Path localFile = homeDirectory.resolve(filename); if (!Files.exists(localFile)) { logger.debug("Downloading model to {}.", localFile); try (final InputStream in = url.openStream()) { Files.copy(in, localFile, StandardCopyOption.REPLACE_EXISTING); } validateModel(new URL(url + ".sha512"), localFile); logger.debug("Download complete."); } else { logger.debug("Model file '{}' already exists. Skipping download.", filename); } try { return type.getConstructor(Path.class).newInstance(localFile); } catch (Exception e) { throw new IOException("Could not initialize Model of type " + type.getTypeName(), e); } } public static Map> getAvailableModels() { if (availableModels == null) { try { availableModels = new DownloadParser(new URL(BASE_URL + MODEL_URI_PATH)).getAvailableModels(); } catch (MalformedURLException e) { throw new RuntimeException(e); } } return Collections.unmodifiableMap(availableModels); } /** * Validates a downloaded model via the specified {@link Path downloadedModel path}. * * @param sha512 the url to get the sha512 hash * @param downloadedModel the model file to check * @throws IOException thrown if the checksum could not be computed */ private static void validateModel(URL sha512, Path downloadedModel) throws IOException { // Download SHA512 checksum file String expectedChecksum; try (BufferedReader reader = new BufferedReader(new InputStreamReader(sha512.openStream()))) { expectedChecksum = reader.readLine(); if (expectedChecksum != null) { expectedChecksum = expectedChecksum.split("\\s")[0].trim(); } } // Validate SHA512 checksum final String actualChecksum = calculateSHA512(downloadedModel); if (!actualChecksum.equalsIgnoreCase(expectedChecksum)) { throw new IOException("SHA512 checksum validation failed for " + downloadedModel.getFileName() + ". Expected: " + expectedChecksum + ", but got: " + actualChecksum); } } private static String calculateSHA512(Path file) throws IOException { try { MessageDigest digest = MessageDigest.getInstance("SHA-512"); try (InputStream fis = Files.newInputStream(file); DigestInputStream dis = new DigestInputStream(fis, digest)) { byte[] buffer = new byte[4096]; //noinspection StatementWithEmptyBody while (dis.read(buffer) != -1) { // Reading the file to update the digest } } return byteArrayToHexString(digest.digest()); } catch (NoSuchAlgorithmException e) { throw new IOException("SHA-512 algorithm not found", e); } } private static String byteArrayToHexString(byte[] bytes) { try (Formatter formatter = new Formatter()) { for (byte b : bytes) { formatter.format("%02x", b); } return formatter.toString(); } } private static Path getDownloadHome() { return Paths.get(System.getProperty(OPENNLP_DOWNLOAD_HOME, System.getProperty("user.home"))).resolve(".opennlp"); } @Internal static class DownloadParser { private static final Pattern LINK_PATTERN = Pattern.compile("(.*?)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); private final URL indexUrl; DownloadParser(URL indexUrl) { Objects.requireNonNull(indexUrl); this.indexUrl = indexUrl; } Map> getAvailableModels() { final Matcher matcher = LINK_PATTERN.matcher(fetchPageIndex()); final List links = new ArrayList<>(); while (matcher.find()) { links.add(matcher.group(1)); } return toMap(links); } private Map> toMap(List links) { final Map> result = new HashMap<>(); for (String link : links) { if (link.endsWith(".bin")) { if (link.contains("de-ud")) { // German addModel("de", link, result); } else if (link.contains("en-ud")) { // English addModel("en", link, result); } else if (link.contains("it-ud")) { // Italian addModel("it", link, result); } else if (link.contains("nl-ud")) { // Dutch addModel("nl", link, result); } else if (link.contains("fr-ud")) { // French addModel("fr", link, result); } else if (link.contains("af-ud")) { // Afrikaans addModel("af", link, result); } else if (link.contains("bg-ud")) { // Bulgarian addModel("bg", link, result); } else if (link.contains("ca-ud")) { // Catalan addModel("ca", link, result); } else if (link.contains("cs-ud")) { // Czech addModel("cs", link, result); } else if (link.contains("hr-ud")) { // Croatian addModel("hr", link, result); } else if (link.contains("da-ud")) { // Danish addModel("da", link, result); } else if (link.contains("el-ud")) { // Greek addModel("el", link, result); } else if (link.contains("es-ud")) { // Spanish addModel("es", link, result); } else if (link.contains("et-ud")) { // Estonian addModel("et", link, result); } else if (link.contains("eu-ud")) { // Basque addModel("eu", link, result); } else if (link.contains("fa-ud")) { // Persian addModel("fa", link, result); } else if (link.contains("fi-ud")) { // Finnish addModel("fi", link, result); } else if (link.contains("ga-ud")) { // Irish addModel("ga", link, result); } else if (link.contains("hy-ud")) { // Armenian addModel("hy", link, result); } else if (link.contains("is-ud")) { // Icelandic addModel("is", link, result); } else if (link.contains("id-ud")) { // Indonesian addModel("id", link, result); } else if (link.contains("ka-ud")) { // Georgian addModel("ka", link, result); } else if (link.contains("kk-ud")) { // Kazakh addModel("kk", link, result); } else if (link.contains("ko-ud")) { // Korean addModel("ko", link, result); } else if (link.contains("lv-ud")) { // Latvian addModel("lv", link, result); } else if (link.contains("no-ud")) { // Norwegian addModel("no", link, result); } else if (link.contains("pl-ud")) { // Polish addModel("pl", link, result); } else if (link.contains("pt-ud")) { // Portuguese addModel("pt", link, result); } else if (link.contains("ro-ud")) { // Romanian addModel("ro", link, result); } else if (link.contains("ru-ud")) { // Russian addModel("ru", link, result); } else if (link.contains("sr-ud")) { // Serbian addModel("sr", link, result); } else if (link.contains("sk-ud")) { // Slovak addModel("sk", link, result); } else if (link.contains("sl-ud")) { // Slovenian addModel("sl", link, result); } else if (link.contains("sv-ud")) { // Swedish addModel("sv", link, result); } else if (link.contains("tr-ud")) { // Turkish addModel("tr", link, result); } else if (link.contains("uk-ud")) { // Ukrainian addModel("uk", link, result); } } } return result; } private void addModel(String locale, String link, Map> result) { final Map models = result.getOrDefault(locale, new HashMap<>()); final String url = (indexUrl.toString().endsWith("/") ? indexUrl : indexUrl + "/") + link; if (link.contains("sentence")) { models.put(ModelType.SENTENCE_DETECTOR, url); } else if (link.contains("tokens")) { models.put(ModelType.TOKENIZER, url); } else if (link.contains("lemma")) { models.put(ModelType.LEMMATIZER, url); } else if (link.contains("pos")) { models.put(ModelType.POS, url); } result.putIfAbsent(locale, models); } private String fetchPageIndex() { final StringBuilder html = new StringBuilder(); try (BufferedReader br = new BufferedReader( new InputStreamReader(indexUrl.openStream(), StandardCharsets.UTF_8))) { String line; while ((line = br.readLine()) != null) { html.append(line); } } catch (IOException e) { logger.error("Could not read page index from {}", indexUrl, e); } return html.toString(); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/EventTraceStream.java0100644 0000000 0000000 00000003026 15217274217 032744 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.io.Writer; import opennlp.tools.ml.model.Event; public class EventTraceStream extends FilterObjectStream { private final Writer writer; /** * Initializes an {@link EventTraceStream}. * * @param stream The {@link ObjectStream stream} of events. * @param writer A {@link Writer} used write {@code events} to. */ public EventTraceStream(ObjectStream stream, Writer writer) { super(stream); this.writer = writer; } @Override public Event read() throws IOException { Event event = samples.read(); if (event != null) { writer.write(event.toString()); writer.write("\n"); } return event; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/FilterObjectStream.java0100644 0000000 0000000 00000003426 15217274217 033264 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.util.Objects; /** * Abstract base class for filtering {@link ObjectStream streams}. *

* Filtering streams take an existing stream and convert * its output to something else. * * @param The sample type of the source or input stream. * @param The sample type of this stream */ public abstract class FilterObjectStream implements ObjectStream { protected final ObjectStream samples; /** * Initializes an {@link FilterObjectStream}. * * @param samples The {@link ObjectStream stream} of samples to filter. * Must not be {@code null}. */ protected FilterObjectStream(ObjectStream samples) { this.samples = Objects.requireNonNull(samples, "samples must not be null!"); } @Override public void reset() throws IOException, UnsupportedOperationException { samples.reset(); } @Override public void close() throws IOException { samples.close(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/InputStreamFactory.java0100644 0000000 0000000 00000002247 15217274217 033337 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.io.InputStream; /** * Allows repeated reads through a stream for certain model building types. */ public interface InputStreamFactory { /** * @return A valid, open {@link InputStream} instance. * @throws IOException Thrown if IO errors occurred. */ InputStream createInputStream() throws IOException; } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_Insufficien0100644 0000000 0000000 00000000171 15217274217 032537 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/InsufficientTrainingDataException.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/InsufficientTrainingDataExc0100644 0000000 0000000 00000002532 15217274217 034165 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; /** * This exception indicates that the provided training data is * insufficient to train a desired model. */ @SuppressWarnings("serial") public class InsufficientTrainingDataException extends IOException { public InsufficientTrainingDataException(String message) { super(message); } public InsufficientTrainingDataException(Throwable t) { super(); initCause(t); } public InsufficientTrainingDataException(String message, Throwable t) { super(message); initCause(t); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_InvalidForm0100644 0000000 0000000 00000000156 15217274217 032512 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/InvalidFormatException.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/InvalidFormatException.java0100644 0000000 0000000 00000002424 15217274217 034147 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; /** * This exception indicates that a resource violates the expected data format. */ @SuppressWarnings("serial") public class InvalidFormatException extends IOException { public InvalidFormatException(String message) { super(message); } public InvalidFormatException(Throwable t) { super(); initCause(t); } public InvalidFormatException(String message, Throwable t) { super(message); initCause(t); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_MarkableFil0100644 0000000 0000000 00000000157 15217274217 032452 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/MarkableFileInputStream.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/MarkableFileInputStream.jav0100644 0000000 0000000 00000004676 15217274217 034115 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /** * Implements a markable {@link FileInputStream}. */ class MarkableFileInputStream extends InputStream { private final FileInputStream in; private long markedPosition = -1; private IOException markException; /** * Initializes a {@link MarkableFileInputStream}. * * @param file The {@link File} used as input source. * * @throws FileNotFoundException Thrown if {@code file} could not be found. */ MarkableFileInputStream(File file) throws FileNotFoundException { in = new FileInputStream(file); } @Override public synchronized void mark(int readlimit) { try { markedPosition = in.getChannel().position(); } catch (IOException e) { markedPosition = -1; } } @Override public boolean markSupported() { return true; } private void throwMarkExceptionIfOccurred() throws IOException { if (markException != null) { throw markException; } } @Override public synchronized void reset() throws IOException { throwMarkExceptionIfOccurred(); if (markedPosition >= 0) { in.getChannel().position(markedPosition); } else { throw new IOException("Stream has to be marked before it can be reset!"); } } @Override public int read() throws IOException { return in.read(); } @Override public int read(byte[] b) throws IOException { return in.read(b); } @Override public int read(byte[] b, int off, int len) throws IOException { return in.read(b, off, len); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_MarkableFil0100644 0000000 0000000 00000000166 15217274217 032452 xustar000000000 0000000 118 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/MarkableFileInputStreamFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/MarkableFileInputStreamFact0100644 0000000 0000000 00000003242 15217274217 034120 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /** * A factory that creates {@link MarkableFileInputStream} from a {@link File} */ public class MarkableFileInputStreamFactory implements InputStreamFactory { private final File file; /** * Initializes a {@link MarkableFileInputStreamFactory}. * * @param file The {@link File} used as input source. * * @throws FileNotFoundException Thrown if {@code file} could not be found. */ public MarkableFileInputStreamFactory(File file) throws FileNotFoundException { if (!file.exists()) { throw new FileNotFoundException("File '" + file + "' cannot be found"); } this.file = file; } @Override public InputStream createInputStream() throws IOException { return new MarkableFileInputStream(file); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/MutableInt.java0100644 0000000 0000000 00000002365 15217274217 031601 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; /** * This is a non-thread safe mutable int. */ public class MutableInt { private int i; /** * @param i The initial {@code int} value to encapsulate. */ public MutableInt(int i) { this.i = i; } /** * Adds {@code 1} to the curren value. */ public void increment() { i++; } /** * @return Retrieves the current value of the {@link MutableInt}. */ public int getValue() { return i; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ObjectStream.java0100644 0000000 0000000 00000006402 15217274217 032113 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.io.ObjectStreamException; import java.util.Iterator; /** * Reads {@link T objects} from a stream. *

* Design Decision:
* This interface provides a means for iterating over the * objects in a stream, it does not implement {@link Iterator} or * {@link Iterable} because: *

    *
  • {@link Iterator#next()} and {@link Iterator#hasNext()} are declared as * throwing no checked exceptions. Thus the {@link IOException}s thrown by * {@link #read()} would have to be wrapped in {@link RuntimeException}s, * and the compiler would be unable to force users of this code to catch * such exceptions.
  • * *
  • Implementing {@link Iterable} would mean either silently calling * {@link #reset()} to guarantee that all items were always seen on each * iteration, or documenting that the Iterable only iterates over the remaining * elements of the ObjectStream. In either case, users not reading the * documentation carefully might run into unexpected behavior.
  • *
* * @see ObjectStreamException */ public interface ObjectStream extends AutoCloseable { /** * Returns the next {@link T} object. Calling this method repeatedly until it returns * {@code null} will return each object from the underlying source exactly once. * * @return The next object or {@code null} to signal that the stream is exhausted. * * @throws IOException Thrown if there is an error during reading. */ T read() throws IOException; /** * Repositions the stream at the beginning and the previously seen object sequence * will be repeated exactly. This method can be used to re-read * the stream if multiple passes over the objects are required. *

* The implementation of this method is optional. * * @throws IOException Thrown if there is an error during resetting the stream. * @throws UnsupportedOperationException Thrown if the {@code reset()} is not supported. * By default, this is the case. */ default void reset() throws IOException { throw new UnsupportedOperationException("reset is not supported on this stream"); } /** * Closes the {@link ObjectStream} and releases all allocated * resources. After close was called, it's not allowed to call * {@link #read()} or {@link #reset()}. * * @throws IOException Thrown if there is an error during closing the stream. */ default void close() throws IOException {} } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ObjectStreamUtils.java0100644 0000000 0000000 00000013213 15217274217 033132 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.util.Collection; import java.util.Iterator; public class ObjectStreamUtils { /** * Creates an {@link ObjectStream} form an array of {@link T}. * * @param array The elements to feed into the new {@link ObjectStream}. * @param The generic type of the elements in the {@code array}. * * @return The {@link ObjectStream} over the array elements. */ @SafeVarargs public static ObjectStream createObjectStream(final T... array) { return new ObjectStream<>() { private int index = 0; @Override public T read() { if (index < array.length) return array[index++]; else return null; } @Override public void reset() { index = 0; } @Override public void close() { } }; } /** * Creates an {@link ObjectStream} form a {@link Collection}. * * @param collection The elements to feed into the new {@link ObjectStream}. * @param The generic type of the elements in the {@code collection}. * * @return The {@link ObjectStream} over the collection elements */ public static ObjectStream createObjectStream(final Collection collection) { return new ObjectStream<>() { private Iterator iterator = collection.iterator(); @Override public T read() { if (iterator.hasNext()) return iterator.next(); else return null; } @Override public void reset() { iterator = collection.iterator(); } @Override public void close() { } }; } /** * Creates a single concatenated {@link ObjectStream} from multiple individual * {@link ObjectStream streams} with the same type {@link T}. * * @param streams The collection of streams to feed into the concatenated {@link ObjectStream}. * Every element of the collection must not be {@code null}. * @param The generic type of the elements in the {@code collection}. * * @return The concatenated {@link ObjectStream} aggregating all elements in {@code streams}. */ public static ObjectStream concatenateObjectStream(final Collection> streams) { // We may want to skip null streams instead of throwing a for (ObjectStream stream : streams) { if (stream == null) { throw new NullPointerException("stream cannot be null"); } } return new ObjectStream<>() { private Iterator> iterator = streams.iterator(); private ObjectStream currentStream = iterator.next(); @Override public T read() throws IOException { T object = null; while (currentStream != null && object == null) { object = currentStream.read(); if (object == null) { currentStream = (iterator.hasNext()) ? iterator.next() : null; } } return object; } @Override public void reset() throws IOException, UnsupportedOperationException { for (ObjectStream stream : streams) { stream.reset(); } iterator = streams.iterator(); } @Override public void close() throws IOException { for (ObjectStream stream : streams) { stream.close(); } } }; } /** * Creates a single concatenated {@link ObjectStream} from multiple individual * {@link ObjectStream streams} with the same type. * * @param streams One or more stream to feed into the concatenated {@link ObjectStream}. * Every element of the collection must not be {@code null}. * @param The generic type of the elements in the {@code streams}. * * @return The concatenated {@link ObjectStream} aggregating all elements in {@code streams}. */ @SafeVarargs public static ObjectStream concatenateObjectStream(final ObjectStream... streams) { for (ObjectStream stream : streams) { if (stream == null) { throw new NullPointerException("stream cannot be null"); } } return new ObjectStream<>() { private int streamIndex = 0; @Override public T read() throws IOException { T object = null; while (streamIndex < streams.length && object == null) { object = streams[streamIndex].read(); if (object == null) streamIndex++; } return object; } @Override public void reset() throws IOException, UnsupportedOperationException { streamIndex = 0; for (ObjectStream stream : streams) { stream.reset(); } } @Override public void close() throws IOException { for (ObjectStream stream : streams) { stream.close(); } } }; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ParagraphStream.java0100644 0000000 0000000 00000003663 15217274217 032620 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; /** * A {@link FilterObjectStream} which merges text lines into paragraphs. *

* The boundary of paragraph is defined by an empty text line. * If the last paragraph in the stream is not terminated by an empty line * the left over is assumed to be a paragraph. */ public class ParagraphStream extends FilterObjectStream { /** * Initializes an {@link FilterObjectStream}. * * @param lineStream The {@link ObjectStream stream} of samples. */ public ParagraphStream(ObjectStream lineStream) { super(lineStream); } @Override public String read() throws IOException { StringBuilder paragraph = new StringBuilder(); while (true) { String line = samples.read(); // The last paragraph in the input might not // be terminated well with a new line at the end. if (line == null || line.isEmpty()) { if (paragraph.length() > 0) { return paragraph.toString(); } } else { paragraph.append(line).append('\n'); } if (line == null) return null; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/PlainTextByLineStream.java0100644 0000000 0000000 00000005257 15217274217 033727 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Objects; /** * Reads a plain text file and returns each line as a {@link String} object. */ public class PlainTextByLineStream implements ObjectStream { private final Charset encoding; private final InputStreamFactory inputStreamFactory; private BufferedReader in; /** * Initializes a {@link PlainTextByLineStream}. * * @param inputStreamFactory The {@link InputStreamFactory} to use. Must not be {@code null}. * @param charsetName The name of the {@link Charset} that is used for interpreting characters. * * @throws IOException Thrown if IO errors occurred. */ public PlainTextByLineStream(InputStreamFactory inputStreamFactory, String charsetName) throws IOException { this(inputStreamFactory, Charset.forName(charsetName)); } /** * Initializes a {@link PlainTextByLineStream}. * * @param inputStreamFactory The {@link InputStreamFactory} to use. Must not be {@code null}. * @param charset The {@link Charset} that is used for interpreting characters. * * @throws IOException Thrown if IO errors occurred. */ public PlainTextByLineStream(InputStreamFactory inputStreamFactory, Charset charset) throws IOException { this.inputStreamFactory = Objects.requireNonNull( inputStreamFactory, "inputStreamFactory must not be null!"); this.encoding = charset; reset(); } @Override public String read() throws IOException { return in.readLine(); } @Override public void reset() throws IOException { in = new BufferedReader( new InputStreamReader(inputStreamFactory.createInputStream(), encoding)); } @Override public void close() throws IOException { if (in != null) { in.close(); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ResetableIterator.java0100644 0000000 0000000 00000002175 15217274217 033154 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.Iterator; /** * This interface makes an {@link Iterator} resettable. */ public interface ResetableIterator extends Iterator { /** * Sets the {@link Iterator} back to the first retrieved element. * The already processed sequence of elements must be repeated. */ void reset(); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ReverseListIterator.java0100644 0000000 0000000 00000002626 15217274217 033516 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.Iterator; import java.util.List; /** * An iterator for a list which returns values in the opposite order as the typical list iterator. */ public class ReverseListIterator implements Iterator { private int index; private final List list; public ReverseListIterator(List list) { index = list.size() - 1; this.list = list; } @Override public T next() { return list.get(index--); } @Override public boolean hasNext() { return index >= 0; } @Override public void remove() { throw new UnsupportedOperationException(); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/Sequence.java0100644 0000000 0000000 00000012331 15217274217 031277 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; /** * Represents a weighted sequence of outcomes. */ public class Sequence implements Comparable { private double score; private final List outcomes; private final List probs; private static final Double ONE = 1.0d; /** * Initializes a new {@link Sequence} of outcomes. */ public Sequence() { outcomes = new ArrayList<>(1); probs = new ArrayList<>(1); score = 0d; } /** * Initializes a new {@link Sequence} of outcomes from an existing {@link Sequence}. * * @param s An existing {@link Sequence} used as input. */ public Sequence(Sequence s) { outcomes = new ArrayList<>(s.outcomes.size() + 1); outcomes.addAll(s.outcomes); probs = new ArrayList<>(s.probs.size() + 1); probs.addAll(s.probs); score = s.score; } /** * Initializes a new {@link Sequence} of outcomes from an existing {@link Sequence}. * * @param s An existing {@link Sequence} used as input. * @param outcome An extra outcome to add to {@code s}. * @param p A extra probability of the {@code outcome}. */ public Sequence(Sequence s, String outcome, double p) { outcomes = new ArrayList<>(s.outcomes.size() + 1); outcomes.addAll(s.outcomes); outcomes.add(outcome); probs = new ArrayList<>(s.probs.size() + 1); probs.addAll(s.probs); probs.add(p); score = s.score + StrictMath.log(p); } /** * Initializes a new {@link Sequence} of outcomes from a list of * {@code outcomes}. The probabilities for each outcome will be * equally initialized to {@link #ONE}. * * @param outcomes Several existing outcomes used as input. */ public Sequence(List outcomes) { this.outcomes = outcomes; this.probs = Collections.nCopies(outcomes.size(),ONE); } @Override public int compareTo(Sequence s) { return Double.compare(s.score, score); } @Override public int hashCode() { return Objects.hash(outcomes, probs, score); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj instanceof Sequence other) { double epsilon = 0.0000001; return Objects.equals(outcomes, other.outcomes) && Objects.equals(probs, other.probs) && StrictMath.abs(score - other.score) < epsilon; } return false; } /** Adds an outcome and probability to this sequence. * @param outcome the outcome to be added. * @param p the probability associated with this outcome. */ public void add(String outcome, double p) { outcomes.add(outcome); probs.add(p); score += StrictMath.log(p); } /** * @return Retrieves a list of outcomes for this {@link Sequence}. */ public List getOutcomes() { return List.copyOf(outcomes); } /** * @return Retrieves the size of the outcomes for this {@link Sequence}. */ public int getSize() { return outcomes.size(); } /** * @param index must be greater than or equal to zero and must be less than {@link Sequence#getSize()}. * @return the outcome at the specified index. * @throws IndexOutOfBoundsException thrown if the given index is out of range. */ public String getOutcome(int index) { return outcomes.get(index); } /** * @param index must be greater than or equal to zero and must be less than {@link Sequence#getSize()}. * @return the probability at the specified index. * @throws IndexOutOfBoundsException thrown if the given index is out of range. */ public double getProb(int index) { return probs.get(index); } /** * @return Retrieves an array of probabilities associated with the {@link Sequence} outcomes. */ public double[] getProbs() { double[] ps = new double[probs.size()]; getProbs(ps); return ps; } /** * @return Retrieves the score of this {@link Sequence}. */ public double getScore() { return score; } /** * Populates an array with the probabilities associated with the {@link Sequence} outcomes. * * @param ps A pre-allocated array to hold the values of the * probabilities of the outcomes for this {@link Sequence}. */ public void getProbs(double[] ps) { for (int pi = 0, pl = probs.size(); pi < pl; pi++) { ps[pi] = probs.get(pi); } } @Override public String toString() { return score + " " + outcomes; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/SequenceCodec.java0100644 0000000 0000000 00000004065 15217274217 032242 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.List; /** * A codec for sequences of type {@link T}. * Defines methods to en- or decode, and validate. * * @param The generic type for the elements to handle. */ public interface SequenceCodec { String DEFAULT_PREFIX = "default-"; /** * Decodes a sequence of {@link T objects} into {@link Span} objects. * * @param c A list of {@link T} to decode. * * @return A {@link Span} array encapsulating the decoded elements in {@code c}. */ Span[] decode(List c); /** * Encodes {@link Span} objects into a sequence of {@link T objects}. * * @param names A list of {@link Span elements} to encode. * @param length The length to respect. * * @return An array of {@link T} to encode. */ T[] encode(Span[] names, int length); /** * @return A {@link SequenceValidator} which can validate a sequence of {@link T outcomes}. */ SequenceValidator createSequenceValidator(); /** * Checks if the {@code outcomes} of a model are compatible with this {@link SequenceCodec}. * * @param outcomes The possible model outcomes. * * @return {@code true} if {@code outcomes} are type compatible, {@code false} otherwise. */ boolean areOutcomesCompatible(String[] outcomes); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/SequenceValidator.java0100644 0000000 0000000 00000003304 15217274217 033145 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; /** * @param The generic type that is to be validated. */ public interface SequenceValidator { /** * Determines whether a particular continuation of a {@link T sequence} is valid. * This is used to restrict invalid sequences such as those used in start/continue tag-based chunking * or could be used to implement tag dictionary restrictions. * * @param i The index in the {@code inputSequence} for which the new outcome is being proposed. * @param inputSequence The input sequence of {@link T}. * @param outcomesSequence The outcomes so far in this sequence. * @param outcome The next proposed outcome for the outcomes sequence. * * @return {@code true} if the sequence would still be valid with the new outcome, * {@code false} otherwise. */ boolean validSequence(int i, T[] inputSequence, String[] outcomesSequence, String outcome); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/Span.java0100644 0000000 0000000 00000030123 15217274217 030427 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.Serial; import java.io.Serializable; import java.util.Objects; /** * Class for storing start and end integer offsets. * */ public class Span implements Comparable, Serializable { @Serial private static final long serialVersionUID = -7648780019844573507L; private final int start; private final int end; private final double prob; //default is 0 private final String type; /** * Initializes a new {@link Span}. Sets the prob to {@code 0} as default. * * @param s The start position of a {@link Span}. * Must be equal to or greater than {@code 0}. * Must not be greater than {@code e}. * @param e The end position of a {@link Span}, which is {@code +1} * more than the last element in the span. * Must be equal to or greater than {@code 0}. * @param type the type of the span * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public Span(int s, int e, String type) { this(s, e, type, 0d); } /** * Initializes a new {@link Span}. * * @param s The start position of a {@link Span}. * Must be equal to or greater than {@code 0}. * Must not be greater than {@code e}. * @param e The end position of a {@link Span}, which is {@code +1} * more than the last element in the span. * Must be equal to or greater than {@code 0}. * @param type The type of the {@link Span} * @param prob The probability of the {@link Span}. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public Span(int s, int e, String type, double prob) { if (s < 0) { throw new IllegalArgumentException("start index must be zero or greater: " + s); } if (e < 0) { throw new IllegalArgumentException("end index must be zero or greater: " + e); } if (s > e) { throw new IllegalArgumentException("start index must not be larger than end index: " + "start=" + s + ", end=" + e); } start = s; end = e; this.prob = prob; this.type = type; } /** * Initializes a new {@link Span}. Sets the prob to {@code 0} as default. * * @param s The start position of a {@link Span}. * Must be equal to or greater than {@code 0}. * Must not be greater than {@code e}. * @param e The end position of a {@link Span}, which is {@code +1} * more than the last element in the span. * Must be equal to or greater than {@code 0}. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public Span(int s, int e) { this(s, e, null, 0d); } /** * Initializes a new {@link Span}. Sets the prob to {@code 0} as default. * * @param s The start position of a {@link Span}. * Must be equal to or greater than {@code 0}. * Must not be greater than {@code e}. * @param e The end position of a {@link Span}, which is {@code +1} * more than the last element in the span. * Must be equal to or greater than {@code 0}. * @param prob The probability of the {@link Span} * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public Span(int s, int e, double prob) { this(s, e, null, prob); } /** * Initializes a new {@link Span} with an existing {@link Span} which is shifted by an * offset. * * @param span The existing {@link Span}. * @param offset The positive or negative shift offset. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public Span(Span span, int offset) { this(span.start + offset, span.end + offset, span.getType(), span.getProb()); } /** * Creates a new immutable {@link Span} based on an existing {@link Span}, * where the existing {@link Span} did not include the probability. * * @param span The {@link Span} that has no prob or the prob is incorrect and * a new {@link Span} must be generated. * @param prob The probability of the {@link Span}. * * @throws IllegalArgumentException Thrown if given parameters are invalid. */ public Span(Span span, double prob) { this(span.start, span.end, span.getType(), prob); } /** * @return Retrieves the start of a {@link Span}. Guaranteed to be greater than {@code 0}. */ public int getStart() { return start; } /** * Note: * that the returned index is one past the actual end of the span in the * text, or the first element past the end of the span. * * @return Retrieves the end of a {@link Span}. Guaranteed to be greater than {@code 0}. */ public int getEnd() { return end; } /** * @return Retrieves the type of a {@link Span} or {@code null} if not set. */ public String getType() { return type; } /** * @return Returns the length of a {@link Span}. Guaranteed to be greater than {@code 0}. */ public int length() { return end - start; } /** * Identical {@link Span spans} are considered to contain each other. * * @param s The {@link Span} to compare with this {@link Span}. * * @return {@code true} is the specified {{@link Span} s} is contained by this span, * {@code false} otherwise. */ public boolean contains(Span s) { return start <= s.getStart() && s.getEnd() <= end; } /** * An index with the value of end is considered outside the {@link Span}. * * @param index the index to test with this {@link Span}. * * @return {@code true} if the span contains this specified index, {@code false} otherwise. */ public boolean contains(int index) { return start <= index && index < end; } /** * @param s The {@link Span} to compare with this span. * * @return {@code true} if the specified span starts with this span and is contained * in this span, {@code false} otherwise */ public boolean startsWith(Span s) { return getStart() == s.getStart() && contains(s); } /** * Checks if the specified {@link Span} intersects with this span. * * @param s The {@link Span} to compare with this span. * * @return {@code true} is the spans overlap, {@code false} otherwise. */ public boolean intersects(Span s) { int sstart = s.getStart(); //either s's start is in this or this' start is in s return this.contains(s) || s.contains(this) || getStart() <= sstart && sstart < getEnd() || sstart <= getStart() && getStart() < s.getEnd(); } /** * Checks if the specified {@link Span} crosses this span. * * @param s The {@link Span} to compare with this span. * * @return {@code true} is the given {@link Span} overlaps this span and contains a * non-overlapping section, {@code false} otherwise. */ public boolean crosses(Span s) { int sstart = s.getStart(); //either s's start is in this or this' start is in s return !this.contains(s) && !s.contains(this) && (getStart() <= sstart && sstart < getEnd() || sstart <= getStart() && getStart() < s.getEnd()); } /** * @param text The {@link CharSequence text} to analyze. * * @return Retrieves the (sub)string covered by the current {@link Span} of the specified text. * * @throws IllegalArgumentException Thrown if parameters violated a constraint. */ public CharSequence getCoveredText(CharSequence text) { if (getEnd() > text.length()) { throw new IllegalArgumentException("The span " + this + " is outside the given text which has length " + text.length() + "!"); } return text.subSequence(getStart(), getEnd()); } /** * @param text The {@link CharSequence text} to analyze. * * @return A copy of this {@link Span} with leading and trailing white spaces removed, * or the same object if already trimmed. */ public Span trim(CharSequence text) { int newStartOffset = getStart(); for (int i = getStart(); i < getEnd() && StringUtil.isWhitespace(text.charAt(i)); i++) { newStartOffset++; } int newEndOffset = getEnd(); for (int i = getEnd(); i > getStart() && StringUtil.isWhitespace(text.charAt(i - 1)); i--) { newEndOffset--; } if (newStartOffset == getStart() && newEndOffset == getEnd()) { return this; } else if (newStartOffset > newEndOffset) { return new Span(getStart(), getStart(), getType()); } else { return new Span(newStartOffset, newEndOffset, getType()); } } /** * Compares the specified {@link Span} to the current span. * * @param s The {@link Span} instance to compare against. * * @see Comparable#compareTo(Object) */ @Override public int compareTo(Span s) { if (getStart() < s.getStart()) { return -1; } else if (getStart() == s.getStart()) { if (getEnd() > s.getEnd()) { return -1; } else if (getEnd() < s.getEnd()) { return 1; } else { // compare the type if (getType() == null && s.getType() == null) { return 0; } else if (getType() != null && s.getType() != null) { // use type lexicography order return getType().compareTo(s.getType()); } else if (getType() != null) { return -1; } return 1; } } else { return 1; } } @Override public int hashCode() { return Objects.hash(getStart(), getEnd(), getType()); } @Override public boolean equals(Object o) { if (o == this) { return true; } if (o instanceof Span s) { return getStart() == s.getStart() && getEnd() == s.getEnd() && Objects.equals(getType(), s.getType()); } return false; } /** * @return A human-readable representation of this {@link Span}. */ @Override public String toString() { StringBuilder toStringBuffer = new StringBuilder(15); toStringBuffer.append("["); toStringBuffer.append(getStart()); toStringBuffer.append(".."); toStringBuffer.append(getEnd()); toStringBuffer.append(")"); if (getType() != null) { toStringBuffer.append(" "); toStringBuffer.append(getType()); } return toStringBuffer.toString(); } /** * Converts an array of {@link Span spans} to an array of {@link String}. * * @param spans The array used as input. * @param s The {@link CharSequence} used to compute covered text. * @return The converted array of strings. */ public static String[] spansToStrings(Span[] spans, CharSequence s) { String[] tokens = new String[spans.length]; for (int si = 0, sl = spans.length; si < sl; si++) { tokens[si] = spans[si].getCoveredText(s).toString(); } return tokens; } public static String[] spansToStrings(Span[] spans, String[] tokens) { String[] chunks = new String[spans.length]; StringBuilder cb = new StringBuilder(); for (int si = 0, sl = spans.length; si < sl; si++) { cb.setLength(0); for (int ti = spans[si].getStart(); ti < spans[si].getEnd(); ti++) { cb.append(tokens[ti]).append(" "); } chunks[si] = cb.substring(0, cb.length() - 1); } return chunks; } /** * @return Retrieves the probability represented by a {@link Span}. */ public double getProb() { return prob; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/StringList.java0100644 0000000 0000000 00000013724 15217274217 031640 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Objects; import java.util.stream.Collectors; import opennlp.tools.util.jvm.StringInterners; /** * A {@link StringList} is an immutable list of {@link String}s. */ public class StringList implements Iterable { private final String[] tokens; private final boolean caseSensitive; // It is safe to use caching of the hashCode for this class private transient Integer hashCode = null; // initial value is uncomputed /** * Initializes a {@link StringList} instance. By default, this instance is case-sensitive. *

* Note:
* Token String will be interned via {@link StringInterners}. * * @param singleToken One single token */ public StringList(String singleToken) { this(true, singleToken); } /** * Initializes a {@link StringList} instance. By default, this instance is case-sensitive. *

* Note:
* Token Strings will be interned via {@link StringInterners}. * * @param tokens The string parts of the new {@link StringList}. * Must not be an empty tokens array or {@code null}. * * @throws IllegalArgumentException Thrown if parameters were invalid. */ public StringList(String... tokens) { this(true, tokens); } /** * Initializes a {@link StringList} instance. *

* Note:
* Token Strings will be interned via {@link StringInterners}. * * @param isCaseSensitive Whether it will operate case-sensitive, or not. * @param tokens The string parts of the new {@link StringList}. * Must not be an empty tokens array or {@code null}. * * @throws IllegalArgumentException Thrown if parameters were invalid. */ public StringList(boolean isCaseSensitive, String... tokens) { Objects.requireNonNull(tokens, "tokens must not be null"); if (tokens.length == 0) { throw new IllegalArgumentException("tokens must not be empty"); } this.tokens = new String[tokens.length]; for (int i = 0; i < tokens.length; i++) { this.tokens[i] = StringInterners.intern(tokens[i]); } this.caseSensitive = isCaseSensitive; } /** * @param index The index to get a token from. * * @return Retrieves a token from the given {@code index}. */ public String getToken(int index) { return tokens[index]; } /** * @return Retrieves the number of tokens inside this list. */ public int size() { return tokens.length; } /** * @return Retrieves an {@link Iterator} over all tokens. */ @Override public Iterator iterator() { return new Iterator<>() { private int index; @Override public boolean hasNext() { return index < size(); } @Override public String next() { if (hasNext()) { return getToken(index++); } else { throw new NoSuchElementException(); } } @Override public void remove() { throw new UnsupportedOperationException(); } }; } /** * Compares to {@link StringList token list} and ignores the case of the tokens. * Note: This can cause problems with some locales. * * @param tokens The {@link StringList tokens} used for comparison. * * @return {@code true} if identically with ignore the case, {@code false} otherwise. */ public boolean compareToIgnoreCase(StringList tokens) { if (size() == tokens.size()) { for (int i = 0; i < size(); i++) { if (getToken(i).compareToIgnoreCase(tokens.getToken(i)) != 0) { return false; } } } else { return false; } return true; } @Override public int hashCode() { if (hashCode == null) { // compute once and cache to safe CPU cycles during use this.hashCode = StringUtil.toLowerCase(String.join(",", tokens)).hashCode(); } return hashCode; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj instanceof StringList tokenList) { if (caseSensitive) { return Arrays.equals(tokens, tokenList.tokens); } else { return compareToIgnoreCase(tokenList); } } return false; } /** * @return A human-readable representation of this {@link StringList}. */ @Override public String toString() { return Arrays.stream(tokens).collect(Collectors.joining(",", "[", "]")); } /** * @return {@code true}, if this {@link StringList} is case-sensitive. */ public boolean isCaseSensitive() { return caseSensitive; } /** * @return If this {@link StringList} is case-insensitive, * the same instance is returned. Otherwise, a new object is returned. */ public StringList toCaseInsensitive() { if (isCaseSensitive()) { return new StringList(false, tokens); } return this; } /** * @return If this {@link StringList} is case-sensitive, * the same instance is returned. Otherwise, a new object is returned. */ public StringList toCaseSensitive() { if (!isCaseSensitive()) { return new StringList(true, tokens); } return this; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/StringUtil.java0100644 0000000 0000000 00000030635 15217274217 031642 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.nio.CharBuffer; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StringUtil { private static final Logger logger = LoggerFactory.getLogger(StringUtil.class); /** * Determines if the specified {@link Character} is a whitespace. * A character is considered a whitespace when one of the following conditions is met: *

    *
  • It's a {@link Character#isWhitespace(int)} whitespace.
  • *
  • It's a part of the Unicode Zs category ({@link Character#SPACE_SEPARATOR}).
  • *
* * {@link Character#isWhitespace(int)} does not include no-break spaces. * In OpenNLP no-break spaces are also considered as white spaces. * * @param charCode The character to check. * * @return {@code true} if {@code charCode} represents a white space, {@code false} otherwise. */ public static boolean isWhitespace(char charCode) { return Character.isWhitespace(charCode) || Character.getType(charCode) == Character.SPACE_SEPARATOR; } /** * Determines if the specified {@link Character} is a whitespace. * A character is considered a whitespace when one of the following conditions is met: * *
    *
  • Its a {@link Character#isWhitespace(int)} whitespace.
  • *
  • Its a part of the Unicode Zs category ({@link Character#SPACE_SEPARATOR}).
  • *
* * {@link Character#isWhitespace(int)} does not include no-break spaces. * In OpenNLP no-break spaces are also considered as white spaces. * * @param charCode An int representation of a character to check. * * @return {@code true} if {@code charCode} represents a white space, {@code false} otherwise. */ public static boolean isWhitespace(int charCode) { return Character.isWhitespace(charCode) || Character.getType(charCode) == Character.SPACE_SEPARATOR; } /** * Converts a {@link CharSequence} to lower case, independent of the current * {@link java.util.Locale} via {@link Character#toLowerCase(int)} which uses * mapping information from the UnicodeData file. * * @param string The {@link CharSequence} to transform. * @return The lower-cased String. */ public static String toLowerCase(CharSequence string) { int[] cp = string.codePoints().map(Character::toLowerCase).toArray(); return new String(cp, 0, cp.length); } public static CharBuffer toLowerCaseCharBuffer(CharSequence sequence) { CharBuffer result = CharBuffer.allocate(sequence.length()); for (int cp : sequence.codePoints().toArray()) { for (char c : Character.toChars(Character.toLowerCase(cp))) { result.append(c); } } result.clear(); return result; } /* public static CharBuffer toLowerCaseCharBuffer(CharSequence string) { int[] cp = string.codePoints().map(Character::toLowerCase).toArray(); CharBuffer result = CharBuffer.allocate(string.length()); for (int j : cp) { char[] chars = Character.toChars(j); result.put(chars, 0, chars.length); } result.clear(); return result; } */ /** * Converts a {@link CharSequence} to upper case, independent of the current * {@link java.util.Locale} via {@link Character#toUpperCase(char)} which uses * mapping information from the UnicodeData file. * * @param string The {@link CharSequence} to transform. * @return The upper-cased String */ public static String toUpperCase(CharSequence string) { char[] upperCaseChars = new char[string.length()]; for (int i = 0; i < string.length(); i++) { upperCaseChars[i] = Character.toUpperCase(string.charAt(i)); } return new String(upperCaseChars); } /** * @return {@code true} if {@link CharSequence#length()} is {@code 0} or {@code null}, otherwise * {@code false} * * @since 1.5.1 */ public static boolean isEmpty(CharSequence theString) { return theString.length() == 0; } /** * Get the minimum of three values. * * @param a number a * @param b number b * @param c number c * @return the minimum among the three parameters {@code a}, {@code b} or {@code c}. */ private static int minimum(int a, int b, int c) { int minValue; minValue = a; if (b < minValue) { minValue = b; } if (c < minValue) { minValue = c; } return minValue; } /** * Computes the Levenshtein distance of two strings in a matrix. *

* Based on this * * pseudo-code which in turn is based on the paper Wagner, Robert A.; Fischer, Michael J. (1974), * "The String-to-String Correction Problem", Journal of the ACM 21 (1): 168-173 * * @param wordForm The form as input. * @param lemma The target lemma. * @return A 2-dimensional Levenshtein distance matrix. */ public static int[][] levenshteinDistance(String wordForm, String lemma) { int wordLength = wordForm.length(); int lemmaLength = lemma.length(); int cost; int[][] distance = new int[wordLength + 1][lemmaLength + 1]; if (wordLength == 0) { return distance; } if (lemmaLength == 0) { return distance; } //fill in the rows of column 0 for (int i = 0; i <= wordLength; i++) { distance[i][0] = i; } //fill in the columns of row 0 for (int j = 0; j <= lemmaLength; j++) { distance[0][j] = j; } //fill in the rest of the matrix calculating the minimum distance for (int i = 1; i <= wordLength; i++) { int s_i = wordForm.charAt(i - 1); for (int j = 1; j <= lemmaLength; j++) { if (s_i == lemma.charAt(j - 1)) { cost = 0; } else { cost = 1; } //obtain minimum distance from calculating deletion, insertion, substitution distance[i][j] = minimum(distance[i - 1][j] + 1, distance[i][j - 1] + 1, distance[i - 1][j - 1] + cost); } } return distance; } /** * Computes the Shortest Edit Script (SES) to convert a word into its lemma. * This is based on Chrupala's PhD thesis (2008). * * @param wordForm The token. * @param lemma The target lemma. * @param distance A 2-dimensional Levenshtein distance matrix. * @param permutations The number of permutations. */ public static void computeShortestEditScript(String wordForm, String lemma, int[][] distance, StringBuffer permutations) { int n = distance.length; int m = distance[0].length; int wordFormLength = n - 1; int lemmaLength = m - 1; while (true) { if (distance[wordFormLength][lemmaLength] == 0) { break; } if ((lemmaLength > 0 && wordFormLength > 0) && (distance[wordFormLength - 1][lemmaLength - 1] < distance[wordFormLength][lemmaLength])) { permutations.append('R').append(wordFormLength - 1) .append(wordForm.charAt(wordFormLength - 1)).append(lemma.charAt(lemmaLength - 1)); lemmaLength--; wordFormLength--; continue; } if (lemmaLength > 0 && (distance[wordFormLength][lemmaLength - 1] < distance[wordFormLength][lemmaLength])) { permutations.append('I').append(wordFormLength) .append(lemma.charAt(lemmaLength - 1)); lemmaLength--; continue; } if (wordFormLength > 0 && (distance[wordFormLength - 1][lemmaLength] < distance[wordFormLength][lemmaLength])) { permutations.append('D').append(wordFormLength - 1) .append(wordForm.charAt(wordFormLength - 1)); wordFormLength--; continue; } if ((wordFormLength > 0 && lemmaLength > 0) && (distance[wordFormLength - 1][lemmaLength - 1] == distance[wordFormLength][lemmaLength])) { wordFormLength--; lemmaLength--; continue ; } if (wordFormLength > 0 && (distance[wordFormLength - 1][lemmaLength] == distance[wordFormLength][lemmaLength])) { wordFormLength--; continue; } if (lemmaLength > 0 && (distance[wordFormLength][lemmaLength - 1] == distance[wordFormLength][lemmaLength])) { lemmaLength--; } } } /** * Reads the predicted Shortest Edit Script (SES) by a lemmatizer model and applies the * permutations to obtain the lemma from the {@code wordForm}. * * @param wordForm The wordForm as input. * @param permutations The permutations predicted by the lemmatizer model. * @return The decoded lemma. */ public static String decodeShortestEditScript(String wordForm, String permutations) { StringBuffer lemma = new StringBuffer(wordForm).reverse(); int permIndex = 0; while (true) { if (permutations.length() <= permIndex) { break; } //read first letter of permutation string char nextOperation = permutations.charAt(permIndex); if (logger.isTraceEnabled()) { logger.trace("-> NextOP: {}", nextOperation); } //go to the next permutation letter permIndex++; if (nextOperation == 'R') { String charAtPerm = Character.toString(permutations.charAt(permIndex)); int charIndex = Integer.parseInt(charAtPerm); // go to the next character in the permutation buffer // which is the replacement character permIndex++; char replace = permutations.charAt(permIndex); //go to the next char in the permutation buffer // which is the candidate character permIndex++; char with = permutations.charAt(permIndex); if (lemma.length() <= charIndex) { return wordForm; } if (lemma.charAt(charIndex) == replace) { lemma.setCharAt(charIndex, with); } if (logger.isTraceEnabled()) { logger.trace("-> ROP: {}", lemma); } //go to next permutation permIndex++; } else if (nextOperation == 'I') { String charAtPerm = Character.toString(permutations.charAt(permIndex)); int charIndex = Integer.parseInt(charAtPerm); permIndex++; //character to be inserted char in = permutations.charAt(permIndex); if (lemma.length() < charIndex) { return wordForm; } lemma.insert(charIndex, in); if (logger.isTraceEnabled()) { logger.trace("-> IOP {}", lemma); } //go to next permutation permIndex++; } else if (nextOperation == 'D') { String charAtPerm = Character.toString(permutations.charAt(permIndex)); int charIndex = Integer.parseInt(charAtPerm); if (lemma.length() <= charIndex) { return wordForm; } lemma.deleteCharAt(charIndex); permIndex++; // go to next permutation permIndex++; } } return lemma.reverse().toString(); } /** * @param wordForm The word as input. * @param lemma The target lemma. * @return Retrieves the Shortest Edit Script (SES) required to go from a word to a lemma. */ public static String getShortestEditScript(String wordForm, String lemma) { String reversedWF = new StringBuffer(wordForm.toLowerCase(Locale.ROOT)).reverse().toString(); String reversedLemma = new StringBuffer(lemma.toLowerCase(Locale.ROOT)).reverse().toString(); StringBuffer permutations = new StringBuffer(); String ses; if (!reversedWF.equals(reversedLemma)) { int[][]levenDistance = StringUtil.levenshteinDistance(reversedWF, reversedLemma); StringUtil.computeShortestEditScript(reversedWF, reversedLemma, levenDistance, permutations); ses = permutations.toString(); } else { ses = "O"; } return ses; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/TokenTag.java0100644 0000000 0000000 00000003700 15217274217 031243 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.util.Arrays; public record TokenTag(String token, String tag, String[] additionalData) { public TokenTag(String token, String tag, String[] additionalData) { this.token = token; this.tag = tag; if (additionalData != null) { this.additionalData = Arrays.copyOf(additionalData, additionalData.length); } else { this.additionalData = null; } } public static String[] extractTokens(TokenTag[] tuples) { String[] tokens = new String[tuples.length]; for (int i = 0; i < tuples.length; i++) { tokens[i] = tuples[i].token(); } return tokens; } public static String[] extractTags(TokenTag[] tuples) { String[] tags = new String[tuples.length]; for (int i = 0; i < tuples.length; i++) { tags[i] = tuples[i].tag(); } return tags; } public static TokenTag[] create(String[] toks, String[] tags) { TokenTag[] tuples = new TokenTag[toks.length]; for (int i = 0; i < toks.length; i++) { tuples[i] = new TokenTag(toks[i], tags[i], null); } return tuples; } @Override public String toString() { return token + "_" + tag; } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/TrainingConfiguration.java0100644 0000000 0000000 00000002467 15217274217 034043 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import opennlp.tools.ml.model.AbstractModel; import opennlp.tools.monitoring.StopCriteria; import opennlp.tools.monitoring.TrainingProgressMonitor; /** * Configuration used for {@link AbstractModel} training. * @param progMon {@link TrainingProgressMonitor} used to monitor the training progress. * @param stopCriteria {@link StopCriteria} used to abort training when the criteria is met. */ public record TrainingConfiguration(TrainingProgressMonitor progMon, StopCriteria stopCriteria) {} apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/TrainingParameters.java0100644 0000000 0000000 00000054537 15217274217 033344 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.TreeMap; import opennlp.tools.cmdline.CmdLineUtil; import opennlp.tools.ml.EventTrainer; /** * Declares and handles default parameters used for or during training models. */ public class TrainingParameters { public static final String ALGORITHM_PARAM = "Algorithm"; public static final String TRAINER_TYPE_PARAM = "TrainerType"; public static final String ITERATIONS_PARAM = "Iterations"; public static final String CUTOFF_PARAM = "Cutoff"; public static final String THREADS_PARAM = "Threads"; /** * The default number of iterations is 100. */ public static final int ITERATIONS_DEFAULT_VALUE = 100; /** * The default cut off value is 5. */ public static final int CUTOFF_DEFAULT_VALUE = 5; private final Map parameters = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); /** * No-arg constructor to create a default {@link TrainingParameters} instance. */ public TrainingParameters() { } /** * Copy constructor to hand over the config of existing {@link TrainingParameters}. */ public TrainingParameters(TrainingParameters trainingParameters) { this.parameters.putAll(trainingParameters.parameters); } /** * Key-value based constructor to apply a {@link Map} based configuration initialization. */ public TrainingParameters(Map map) { parameters.putAll(map); } /** * {@link InputStream} based constructor that reads in {@link TrainingParameters}. * * @throws IOException Thrown if IO errors occurred. */ public TrainingParameters(InputStream in) throws IOException { Properties properties = new Properties(); properties.load(in); for (Map.Entry entry : properties.entrySet()) { parameters.put((String) entry.getKey(), entry.getValue()); } } /** * @return Retrieves the training algorithm name for a given name space, or {@code null} if unset. */ public String algorithm(String namespace) { return (String)parameters.get(getKey(namespace, ALGORITHM_PARAM)); } /** * @return Retrieves the training algorithm name. or @code null} if not set. */ public String algorithm() { return (String)parameters.get(ALGORITHM_PARAM); } /** * @param namespace The name space to filter or narrow the search space. May be {@code null}. * * @return Retrieves a parameter {@link Map} which can be passed to the train and validate methods. */ public Map getObjectSettings(String namespace) { Map trainingParams = new HashMap<>(); String prefix = namespace + "."; for (Map.Entry entry : parameters.entrySet()) { String key = entry.getKey(); if (namespace != null) { if (key.startsWith(prefix)) { trainingParams.put(key.substring(prefix.length()), entry.getValue()); } } else { if (!key.contains(".")) { trainingParams.put(key, entry.getValue()); } } } return Collections.unmodifiableMap(trainingParams); } /** * @return Retrieves a parameter {@link Map} of all parameters without narrowing. */ public Map getObjectSettings() { return getObjectSettings(null); } /** * @param namespace The name space to filter or narrow the search space. May be {@code null}. * * @return Retrieves {@link TrainingParameters} which can be passed to the train and validate methods. */ public TrainingParameters getParameters(String namespace) { TrainingParameters params = new TrainingParameters(); Map settings = getObjectSettings(namespace); for (Entry entry: settings.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (value instanceof Integer) { params.put(key, (Integer)value); } else if (value instanceof Double) { params.put(key, (Double)value); } else if (value instanceof Boolean) { params.put(key, (Boolean)value); } else { params.put(key, (String)value); } } return params; } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link String} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String namespace, String key, String value) { parameters.putIfAbsent(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link String} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String key, String value) { putIfAbsent(null, key, value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Integer} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String namespace, String key, int value) { parameters.putIfAbsent(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Integer} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String key, int value) { putIfAbsent(null, key, value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Double} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String namespace, String key, double value) { parameters.putIfAbsent(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * The {@code namespace} can be used to prefix the {@code key}. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Double} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String key, double value) { putIfAbsent(null, key, value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Boolean} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String namespace, String key, boolean value) { parameters.putIfAbsent(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}, * if the value was not present before. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Boolean} parameter to put into this {@link TrainingParameters} instance. */ public void putIfAbsent(String key, boolean value) { putIfAbsent(null, key, value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link String} parameter to put into this {@link TrainingParameters} instance. */ public void put(String namespace, String key, String value) { parameters.put(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link String} parameter to put into this {@link TrainingParameters} instance. */ public void put(String key, String value) { put(null, key, value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Integer} parameter to put into this {@link TrainingParameters} instance. */ public void put(String namespace, String key, int value) { parameters.put(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Integer} parameter to put into this {@link TrainingParameters} instance. */ public void put(String key, int value) { put(null, key, value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Double} parameter to put into this {@link TrainingParameters} instance. */ public void put(String namespace, String key, double value) { parameters.put(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Double} parameter to put into this {@link TrainingParameters} instance. */ public void put(String key, double value) { put(null, key, value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * The {@code namespace} can be used to prefix the {@code key}. * * @param namespace A prefix to declare or use a name space under which {@code key} shall be put. * May be {@code null}. * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Boolean} parameter to put into this {@link TrainingParameters} instance. */ public void put(String namespace, String key, boolean value) { parameters.put(getKey(namespace, key), value); } /** * Puts a {@code value} into the current {@link TrainingParameters} under a certain {@code key}. * If the value was present before, the previous value will be overwritten with the specified one. * * @param key The identifying key to put or retrieve a {@code value} with. * @param value The {@link Boolean} parameter to put into this {@link TrainingParameters} instance. */ public void put(String key, boolean value) { put(null, key, value); } /** * Serializes a {@link TrainingParameters} instance via a specified {@link OutputStream}. * * @param out A valid, open {@link OutputStream} to write to. * * @throws IOException Thrown if errors occurred. */ public void serialize(OutputStream out) throws IOException { Properties properties = new Properties(); properties.putAll(parameters); properties.store(out, null); } /** * Obtains a training parameter value. *

* Note: * {@link java.lang.ClassCastException} can be thrown if the value is not {@code String} * * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * @return The {@link String training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public String getStringParameter(String key, String defaultValue) { return getStringParameter(null, key, defaultValue); } /** * Obtains a training parameter value in the specified namespace. *

* Note: * {@link java.lang.ClassCastException} can be thrown if the value is not {@link String} * @param namespace A prefix to declare or use a name space under which {@code key} shall be searched. * May be {@code null}. * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * * @return The {@link String training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public String getStringParameter(String namespace, String key, String defaultValue) { Object value = parameters.get(getKey(namespace, key)); if (value == null) { return defaultValue; } else { return (String)value; } } /** * Obtains a training parameter value. *

* * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * @return The {@link Integer training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public int getIntParameter(String key, int defaultValue) { return getIntParameter(null, key, defaultValue); } /** * Obtains a training parameter value in the specified namespace. *

* @param namespace A prefix to declare or use a name space under which {@code key} shall be searched. * May be {@code null}. * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * * @return The {@link Integer training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public int getIntParameter(String namespace, String key, int defaultValue) { Object value = parameters.get(getKey(namespace, key)); if (value == null) { return defaultValue; } else { try { return (Integer) value; } catch (ClassCastException e) { return Integer.parseInt((String)value); } } } /** * Obtains a training parameter value. *

* * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * @return The {@link Double training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public double getDoubleParameter(String key, double defaultValue) { return getDoubleParameter(null, key, defaultValue); } /** * Obtains a training parameter value in the specified namespace. *

* @param namespace A prefix to declare or use a name space under which {@code key} shall be searched. * May be {@code null}. * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * * @return The {@link Double training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public double getDoubleParameter(String namespace, String key, double defaultValue) { Object value = parameters.get(getKey(namespace, key)); if (value == null) { return defaultValue; } else { try { return (Double) value; } catch (ClassCastException e) { return Double.parseDouble((String)value); } } } /** * Obtains a training parameter value. *

* * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * @return The {@link Boolean training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public boolean getBooleanParameter(String key, boolean defaultValue) { return getBooleanParameter(null, key, defaultValue); } /** * Obtains a training parameter value in the specified namespace. *

* @param namespace A prefix to declare or use a name space under which {@code key} shall be searched. * May be {@code null}. * @param key The identifying key to retrieve a {@code value} with. * @param defaultValue The alternative value to use, if {@code key} was not present. * * @return The {@link Boolean training value} associated with {@code key} if present, * or a {@code defaultValue} if not. */ public boolean getBooleanParameter(String namespace, String key, boolean defaultValue) { Object value = parameters.get(getKey(namespace, key)); if (value == null) { return defaultValue; } else { try { return (Boolean) value; } catch (ClassCastException e) { return Boolean.parseBoolean((String)value); } } } /** * @return Retrieves a new {@link TrainingParameters instance} initialized with default values. */ public static TrainingParameters defaultParams() { TrainingParameters mlParams = new TrainingParameters(); mlParams.put(TrainingParameters.ALGORITHM_PARAM, "MAXENT"); mlParams.put(TrainingParameters.TRAINER_TYPE_PARAM, EventTrainer.EVENT_VALUE); mlParams.put(TrainingParameters.ITERATIONS_PARAM, ITERATIONS_DEFAULT_VALUE); mlParams.put(TrainingParameters.CUTOFF_PARAM, CUTOFF_DEFAULT_VALUE); return mlParams; } /** * @param params The parameters to additionally apply into the new {@link TrainingParameters instance}. * * @return Retrieves a new {@link TrainingParameters instance} initialized with given parameter values. */ public static TrainingParameters setParams(String[] params) { TrainingParameters mlParams = new TrainingParameters(); mlParams.put(TrainingParameters.ALGORITHM_PARAM , "MAXENT"); mlParams.put(TrainingParameters.TRAINER_TYPE_PARAM , EventTrainer.EVENT_VALUE); final String iterationsFlag = "-" + TrainingParameters.ITERATIONS_PARAM.toLowerCase(Locale.ROOT); final String cutoffFlag = "-" + TrainingParameters.CUTOFF_PARAM.toLowerCase(Locale.ROOT); mlParams.put(TrainingParameters.ITERATIONS_PARAM , null != CmdLineUtil.getIntParameter(iterationsFlag , params) ? CmdLineUtil.getIntParameter(iterationsFlag , params) : ITERATIONS_DEFAULT_VALUE); mlParams.put(TrainingParameters.CUTOFF_PARAM , null != CmdLineUtil.getIntParameter(cutoffFlag , params) ? CmdLineUtil.getIntParameter(cutoffFlag , params) : CUTOFF_DEFAULT_VALUE); return mlParams; } /** * @param namespace The namespace used as prefix or {@code null}. * If {@code null} the {@code key} is left unchanged. * @param key The identifying key to process. * * @return Retrieves a prefixed key in the specified {@code namespace}. * If no {@code namespace} was specified the returned String is equal to {@code key}. */ static String getKey(String namespace, String key) { if (namespace == null) { return key; } else { return namespace + "." + key; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/Version.java0100644 0000000 0000000 00000014607 15217274217 031164 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import java.io.IOException; import java.io.InputStream; import java.util.Objects; import java.util.Properties; /** * The {@link Version} class represents the OpenNLP Tools library version. *

* The version has three parts: *

    *
  • Major: OpenNLP Tools libraries with a different major version are not interchangeable.
  • *
  • Minor: OpenNLP Tools libraries with an identical major version, but different * minor version may be interchangeable. See release notes for further details.
  • *
  • Revision: OpenNLP Tools libraries with same major and minor version, but a different * revision, are fully interchangeable.
  • *
*/ public class Version { private static final String DEV_VERSION_STRING = "0.0.0-SNAPSHOT"; public static final Version DEV_VERSION = Version.parse(DEV_VERSION_STRING); private static final String SNAPSHOT_MARKER = "-SNAPSHOT"; private final int major; private final int minor; private final int revision; private final boolean snapshot; /** * Initializes a {@link Version} instance with the provided version elements. * * @param major Must not be negative. * @param minor Must not be negative. * @param revision Must not be negative. * @param snapshot {@code true} if the version represents a snapshot, {@code false} otherwise. */ public Version(int major, int minor, int revision, boolean snapshot) { this.major = major; this.minor = minor; this.revision = revision; this.snapshot = snapshot; } /** * Initializes a {@link Version} instance with the provided version elements. * The {@link Version} will not be a snapshot, yet a release version. * * @param major Must not be negative. * @param minor Must not be negative. * @param revision Must not be negative. */ public Version(int major, int minor, int revision) { this(major, minor, revision, false); } /** * @return Retrieves the major version, guaranteed to be non-negative. */ public int getMajor() { return major; } /** * @return Retrieves the minor version, guaranteed to be non-negative. */ public int getMinor() { return minor; } /** * @return Retrieves the revision version, guaranteed to be non-negative. */ public int getRevision() { return revision; } public boolean isSnapshot() { return snapshot; } /** * The {@link #parse(String)} method can create an instance * of {@link Version} with the returned version value string. * * @return Retrieves a human-readable version representation. */ @Override public String toString() { return getMajor() + "." + getMinor() + "." + getRevision() + (isSnapshot() ? SNAPSHOT_MARKER : ""); } @Override public int hashCode() { return Objects.hash(getMajor(), getMinor(), getRevision(), isSnapshot()); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Version version) { return getMajor() == version.getMajor() && getMinor() == version.getMinor() && getRevision() == version.getRevision() && isSnapshot() == version.isSnapshot(); } return false; } /** * Return a new {@link Version} initialized to the value * represented by the specified {@link String} * * @param version The string to be parsed * * @return The version represented by the string value * * @throws NumberFormatException Thrown if {@code version} does not adhere to a valid form. */ public static Version parse(String version) { int indexFirstDot = version.indexOf('.'); int indexSecondDot = version.indexOf('.', indexFirstDot + 1); if (indexFirstDot == -1 || indexSecondDot == -1) { throw new NumberFormatException("Invalid version format '" + version + "', expected two dots!"); } int indexThirdDot = version.indexOf('.', indexSecondDot + 1); int indexFirstDash = version.indexOf('-'); int versionEnd; if (indexFirstDash == -1 && indexThirdDot == -1) { versionEnd = version.length(); } else if (indexThirdDot != -1) { versionEnd = indexThirdDot; } else { versionEnd = indexFirstDash; } String revision = version.substring(indexSecondDot + 1, versionEnd); final int indexPatchVersionDot = revision.indexOf('.'); if (indexPatchVersionDot != -1) { // A rare extra patch version is present (e.g., 2.5.6.1), which OpenNLP normally doesn't use. // Since it’s equivalent to the latest revision, we ignore it here. revision = revision.substring(0, indexPatchVersionDot); } final boolean snapshot = version.endsWith(SNAPSHOT_MARKER); return new Version(Integer.parseInt(version.substring(0, indexFirstDot)), Integer.parseInt(version.substring(indexFirstDot + 1, indexSecondDot)), Integer.parseInt(revision), snapshot); } /** * @return Retrieves the current version of the OpenNLP Tools library. */ public static Version currentVersion() { Properties manifest = new Properties(); // Try to read the version from the version file if it is available, // otherwise set the version to the development version try (InputStream versionIn = Version.class.getResourceAsStream("opennlp.version")) { if (versionIn != null) { manifest.load(versionIn); } } catch (IOException e) { // ignore error } String versionString = manifest.getProperty("OpenNLP-Version", DEV_VERSION_STRING); if (versionString.equals("${project.version}")) versionString = DEV_VERSION_STRING; return Version.parse(versionString); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/XmlUtil.java0100644 0000000 0000000 00000015237 15217274217 031135 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; public class XmlUtil { private static final Logger logger = LoggerFactory.getLogger(XmlUtil.class); /** * Create a new {@link DocumentBuilder} which processes XML securely. * * @return A valid {@link DocumentBuilder} instance. * @throws IllegalStateException Thrown if errors occurred creating the builder. */ public static DocumentBuilder createDocumentBuilder() { final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); try { documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); } catch (ParserConfigurationException e) { /// {@link XMLConstants.FEATURE_SECURE_PROCESSING} is not supported on Android. /// See {@link DocumentBuilderFactory#setFeature} logger.warn("Failed to enable XMLConstants.FEATURE_SECURE_PROCESSING, it's unsupported on" + " this platform.", e); } try { setAttributeIfSupported(documentBuilderFactory, XMLConstants.ACCESS_EXTERNAL_DTD, ""); setAttributeIfSupported(documentBuilderFactory, XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); setFeatureIfSupported(documentBuilderFactory, "http://apache.org/xml/features/disallow-doctype-decl", true); setFeatureIfSupported(documentBuilderFactory, "http://xml.org/sax/features/external-general-entities", false); setFeatureIfSupported(documentBuilderFactory, "http://xml.org/sax/features/external-parameter-entities", false); setFeatureIfSupported(documentBuilderFactory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); setXIncludeAwareIfSupported(documentBuilderFactory, false); documentBuilderFactory.setExpandEntityReferences(false); return documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new IllegalStateException(e); } } /** * Create a new {@link SAXParser} which processes XML securely. * * @return A valid {@link SAXParser} instance. * @throws IllegalStateException Thrown if errors occurred creating the parser. */ public static SAXParser createSaxParser() { final SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setNamespaceAware(true); setXIncludeAwareIfSupported(spf, false); try { spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); } catch (ParserConfigurationException | SAXException e) { /// {@link XMLConstants.FEATURE_SECURE_PROCESSING} is not supported on Android. /// See {@link SAXParserFactory#setFeature} logger.warn("Failed to enable XMLConstants.FEATURE_SECURE_PROCESSING, it's unsupported on" + " this platform.", e); } setFeatureIfSupported(spf, "http://apache.org/xml/features/disallow-doctype-decl", true); setFeatureIfSupported(spf, "http://xml.org/sax/features/external-general-entities", false); setFeatureIfSupported(spf, "http://xml.org/sax/features/external-parameter-entities", false); setFeatureIfSupported(spf, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); try { final SAXParser parser = spf.newSAXParser(); setPropertyIfSupported(parser, XMLConstants.ACCESS_EXTERNAL_DTD, ""); setPropertyIfSupported(parser, XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); return parser; } catch (ParserConfigurationException | SAXException e) { throw new IllegalStateException(e); } } private static void setFeatureIfSupported(DocumentBuilderFactory factory, String name, boolean value) { try { factory.setFeature(name, value); } catch (ParserConfigurationException e) { logger.warn("Failed to set XML parser feature {}, it's unsupported on this platform.", name, e); } } private static void setAttributeIfSupported(DocumentBuilderFactory factory, String name, Object value) { try { factory.setAttribute(name, value); } catch (IllegalArgumentException e) { logger.warn("Failed to set XML parser attribute {}, it's unsupported on this platform.", name, e); } } private static void setXIncludeAwareIfSupported(DocumentBuilderFactory factory, boolean state) { try { factory.setXIncludeAware(state); } catch (UnsupportedOperationException e) { logger.warn("Failed to set XML parser XInclude awareness, it's unsupported on " + "this platform.", e); } } private static void setPropertyIfSupported(SAXParser parser, String name, Object value) { try { parser.setProperty(name, value); } catch (SAXNotRecognizedException | SAXNotSupportedException e) { logger.warn("Failed to set XML parser property {}, it's unsupported on this platform.", name, e); } } private static void setFeatureIfSupported(SAXParserFactory factory, String name, boolean value) { try { factory.setFeature(name, value); } catch (ParserConfigurationException | SAXException e) { logger.warn("Failed to set XML parser feature {}, it's unsupported on this platform.", name, e); } } private static void setXIncludeAwareIfSupported(SAXParserFactory factory, boolean state) { try { factory.setXIncludeAware(state); } catch (UnsupportedOperationException e) { logger.warn("Failed to set XML parser XInclude awareness, it's unsupported on " + "this platform.", e); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_eval_CrossV0100644 0000000 0000000 00000000167 15217274217 032530 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/CrossValidationPartitioner.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/CrossValidationPartiti0100644 0000000 0000000 00000020522 15217274217 034200 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.eval; import java.io.IOException; import java.util.Collection; import java.util.NoSuchElementException; import opennlp.tools.util.CollectionObjectStream; import opennlp.tools.util.ObjectStream; /** * Provides access to training and test partitions for n-fold cross validation. *

* Cross validation is used to evaluate the performance of a classifier when only * training data is available. The training set is split into n parts * and the training / evaluation is performed {@code n} times on these parts. * The training partition always consists of {@code n - 1} parts and one part is used for testing. *

* To use the {@link CrossValidationPartitioner} a client iterates over the n * {@link TrainingSampleStream stream}. Each {@link TrainingSampleStream} represents * one partition and is used first for training and afterwards for testing. * The {@link TestSampleStream} can be obtained via the * {@link TrainingSampleStream#getTestSampleStream()} method. */ public class CrossValidationPartitioner { /** * The {@link TestSampleStream} iterates over all test elements. * * @param The generic type of samples. */ private static class TestSampleStream implements ObjectStream { private final ObjectStream sampleStream; private final int numberOfPartitions; private final int testIndex; private int index; private boolean isPoisoned; private TestSampleStream(ObjectStream sampleStream, int numberOfPartitions, int testIndex) { this.numberOfPartitions = numberOfPartitions; this.sampleStream = sampleStream; this.testIndex = testIndex; } @Override public E read() throws IOException { if (isPoisoned) { throw new IllegalStateException(); } // skip training samples while (index % numberOfPartitions != testIndex) { sampleStream.read(); index++; } index++; return sampleStream.read(); } /** * @throws UnsupportedOperationException Thrown to signal no implementation is available. */ @Override public void reset() { throw new UnsupportedOperationException(); } @Override public void close() throws IOException { sampleStream.close(); isPoisoned = true; } void poison() { isPoisoned = true; } } /** * The {@link TrainingSampleStream} which iterates over * all training elements. *

* Note: * After the {@link TestSampleStream} was obtained * the {@link TrainingSampleStream} must not be used * anymore, otherwise a {@link IllegalStateException} * is thrown. *

* The {@link ObjectStream streams} must not be used anymore after the * {@link CrossValidationPartitioner} was moved to one of next partitions. * If they are called anyway an {@link IllegalStateException} is thrown. * * @param The generic type of samples. */ public static class TrainingSampleStream implements ObjectStream { private final ObjectStream sampleStream; private final int numberOfPartitions; private final int testIndex; private int index; private boolean isPoisoned; private TestSampleStream testSampleStream; TrainingSampleStream(ObjectStream sampleStream, int numberOfPartitions, int testIndex) { this.numberOfPartitions = numberOfPartitions; this.sampleStream = sampleStream; this.testIndex = testIndex; } @Override public E read() throws IOException { if (testSampleStream != null || isPoisoned) { throw new IllegalStateException(); } // If the test element is reached skip over it to not include it in // the training data if (index % numberOfPartitions == testIndex) { sampleStream.read(); index++; } index++; return sampleStream.read(); } /** * Resets the training sample. Use this if you need to collect things before * training, for example, to collect induced abbreviations or create a POS * Dictionary. * * @throws IOException Thrown if IO errors occurred. * @throws IllegalStateException Thrown if a non-consistent state occurred. */ @Override public void reset() throws IOException { if (testSampleStream != null || isPoisoned) { throw new IllegalStateException(); } this.index = 0; this.sampleStream.reset(); } @Override public void close() throws IOException { sampleStream.close(); poison(); } void poison() { isPoisoned = true; if (testSampleStream != null) testSampleStream.poison(); } /** * Retrieves the {@link ObjectStream} over the test/evaluations * elements and poisons this {@link TrainingSampleStream}. * From now on calls to the hasNext and next methods are forbidden * and will raise an {@link IllegalArgumentException}. * * @return The test sample {@link ObjectStream stream}. */ public ObjectStream getTestSampleStream() throws IOException { if (isPoisoned) { throw new IllegalStateException(); } if (testSampleStream == null) { sampleStream.reset(); testSampleStream = new TestSampleStream<>(sampleStream, numberOfPartitions, testIndex); } return testSampleStream; } } /** * An {@link ObjectStream stream} over the whole set of data samples which * are used for the cross validation. */ private final ObjectStream sampleStream; /** * The number of parts the data is divided into. */ private final int numberOfPartitions; /** * The index of test part. */ private int testIndex; /** * The last handed out {@link TrainingSampleStream}. The reference * is needed to poison the instance to fail fast if it is used * despite the fact that it is forbidden!. */ private TrainingSampleStream lastTrainingSampleStream; /** * Initializes {@link CrossValidationPartitioner} instance. * * @param inElements The {@link ObjectStream} that provides the elements. * @param numberOfPartitions The number of partitions. Must be greater than {@code 0}. */ public CrossValidationPartitioner(ObjectStream inElements, int numberOfPartitions) { this.sampleStream = inElements; this.numberOfPartitions = numberOfPartitions; } /** * Initializes {@link CrossValidationPartitioner} instance. * * @param elements A {@link Collection} that provides the elements. * @param numberOfPartitions The number of partitions. Must be greater than {@code 0}. */ public CrossValidationPartitioner(Collection elements, int numberOfPartitions) { this(new CollectionObjectStream<>(elements), numberOfPartitions); } /** * Checks if there are more partitions available. */ public boolean hasNext() { return testIndex < numberOfPartitions; } /** * Retrieves the next training and test partitions. */ public TrainingSampleStream next() throws IOException { if (hasNext()) { if (lastTrainingSampleStream != null) lastTrainingSampleStream.poison(); sampleStream.reset(); TrainingSampleStream trainingSampleStream = new TrainingSampleStream<>(sampleStream, numberOfPartitions, testIndex); testIndex++; lastTrainingSampleStream = trainingSampleStream; return trainingSampleStream; } else { throw new NoSuchElementException(); } } @Override public String toString() { return "At partition" + (testIndex + 1) + " of " + numberOfPartitions; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_eval_Evalua0100644 0000000 0000000 00000000156 15217274217 032524 xustar000000000 0000000 110 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/EvaluationMonitor.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/EvaluationMonitor.java0100644 0000000 0000000 00000001731 15217274217 034137 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.eval; public interface EvaluationMonitor { void correctlyClassified(T reference, T prediction); void misclassified(T reference, T prediction); } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/Evaluator.java0100644 0000000 0000000 00000006576 15217274217 032436 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.eval; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import opennlp.tools.util.ObjectStream; /** * An abstract base class for evaluators. * Evaluation results are the arithmetic mean of the * scores calculated for each reference sample. */ public abstract class Evaluator { private final List> listeners; @SafeVarargs public Evaluator(EvaluationMonitor... aListeners) { if (aListeners != null) { List> listenersList = new ArrayList<>(aListeners.length); for (EvaluationMonitor evaluationMonitor : aListeners) { if (evaluationMonitor != null) { listenersList.add(evaluationMonitor); } } listeners = Collections.unmodifiableList(listenersList); } else { listeners = Collections.emptyList(); } } /** * Evaluates the given reference {@link T} sample object. *

* The implementation has to update the score after every invocation. * * @param reference A {@link T reference sample}. * * @return The predicted {@link T sample}. */ protected abstract T processSample(T reference); /** * Evaluates the given reference object. The default implementation calls * {@link Evaluator#processSample(Object)} * *

* note: this method will be changed to private in the future. * Implementations should override {@link Evaluator#processSample(Object)} instead. * If this method is overridden, the implementation has to update the score * after every invocation. *

* * @param sample A {@link T sample} to be evaluated. */ public void evaluateSample(T sample) { T predicted = processSample(sample); if (!listeners.isEmpty()) { if (sample.equals(predicted)) { for (EvaluationMonitor listener : listeners) { listener.correctlyClassified(sample, predicted); } } else { for (EvaluationMonitor listener : listeners) { listener.misclassified(sample, predicted); } } } } /** * Reads all {@link ObjectStream sample objects} * and evaluates each instance via the * {@link #evaluateSample(Object)} method. * * @param samples The {@link ObjectStream stream} of reference * which shall be evaluated. * * @throws IOException Thrown if IO errors occurred. */ public void evaluate(ObjectStream samples) throws IOException { T sample; while ((sample = samples.read()) != null) { evaluateSample(sample); } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/FMeasure.java0100644 0000000 0000000 00000013133 15217274217 032166 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.eval; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * The {@link FMeasure} is a utility class for {@link Evaluator evaluators} * which measures precision, recall and the resulting f-measure. *

* Evaluation results are the arithmetic mean of the precision * scores calculated for each reference sample and * the arithmetic mean of the recall scores calculated for * each reference sample. */ public final class FMeasure { /** * |selected| = true positives + false positives
* the count of selected (or retrieved) items. */ private long selected; /** * |target| = true positives + false negatives
* the count of target (or correct) items. */ private long target; /** * Holds the number of true positives found. */ private long truePositive; /** * @return Retrieves the arithmetic mean of the precision scores calculated * for each evaluated sample. */ public double getPrecisionScore() { return selected > 0 ? (double) truePositive / (double) selected : 0; } /** * @return Retrieves the arithmetic mean of the recall score calculated * for each evaluated sample. */ public double getRecallScore() { return target > 0 ? (double) truePositive / (double) target : 0; } /** * {@code f-measure = 2 * precision * recall / (precision + recall)}. * * @return Retrieves the f-measure or {@code -1} if precision + recall {@code <= 0} */ public double getFMeasure() { if (getPrecisionScore() + getRecallScore() > 0) { return 2 * (getPrecisionScore() * getRecallScore()) / (getPrecisionScore() + getRecallScore()); } else { // cannot divide by zero, return error code return -1; } } /** * Updates the score based on the number of true positives and * the number of predictions and references. * * @param references the provided references * @param predictions the predicted spans */ public void updateScores(final Object[] references, final Object[] predictions) { truePositive += countTruePositives(references, predictions); selected += predictions.length; target += references.length; } /** * Merge results into {@link FMeasure metric}. * * @param measure The {@link FMeasure} to merge. */ public void mergeInto(final FMeasure measure) { this.selected += measure.selected; this.target += measure.target; this.truePositive += measure.truePositive; } /** * @return A human-readable {@link String} representation. */ @Override public String toString() { return "Precision: " + getPrecisionScore() + "\n" + "Recall: " + getRecallScore() + "\n" + "F-Measure: " + getFMeasure(); } /** * This method counts the number of objects which are equal and occur in the * references and predictions arrays. * Matched items are removed from the prediction list. * * @param references * The gold standard. * @param predictions * The predictions. * @return The number of true positives. */ static int countTruePositives(final Object[] references, final Object[] predictions) { List predListSpans = new ArrayList<>(predictions.length); Collections.addAll(predListSpans, predictions); int truePositives = 0; Object matchedItem = null; for (Object referenceName : references) { for (Object predListSpan : predListSpans) { if (referenceName.equals(predListSpan)) { matchedItem = predListSpan; truePositives++; } } if (matchedItem != null) { predListSpans.remove(matchedItem); } } return truePositives; } /** * Calculates the precision score for the given reference and predicted spans. * * @param references * The gold standard spans. * @param predictions * The predicted spans. * @return The precision score or {@code NaN} if there are no predicted spans. */ public static double precision(final Object[] references, final Object[] predictions) { if (predictions.length > 0) { return countTruePositives(references, predictions) / (double) predictions.length; } else { return Double.NaN; } } /** * Calculates the recall score for the given reference and predicted spans. * * @param references * The gold standard spans * @param predictions * The predicted spans * * @return The recall score or {@code NaN} if there are no reference spans. */ public static double recall(final Object[] references, final Object[] predictions) { if (references.length > 0) { return countTruePositives(references, predictions) / (double) references.length; } else { return Double.NaN; } } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/eval/Mean.java0100644 0000000 0000000 00000004157 15217274217 031345 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.eval; /** * Calculates the arithmetic mean of values * added with the {@link #add(double)} method. */ public class Mean { /** * The sum of all added values. */ private double sum; /** * The number of times a value was added. */ private long count; /** * Adds a value to the arithmetic mean. * * @param value the value which should be added * to the arithmetic mean. */ public void add(double value) { add(value, 1); } /** * Adds a value {@code count} times to the arithmetic mean. * * @param value the value which should be added * to the arithmetic mean. * * @param count number of times the value should be added to * arithmetic mean. */ public void add(double value, long count) { sum += value * count; this.count += count; } /** * @return Retrieves the mean of all values added with {@link #add(double)} * or {@code 0} if there are zero add values. */ public double mean() { return count > 0 ? sum / count : 0; } /** * @return Retrieves the number of times a value was added to the mean. */ public long count() { return count; } /** * @return A human-readable {@link String} representation. */ @Override public String toString() { return Double.toString(mean()); } } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ext/ExtensionLoader.java0100644 0000000 0000000 00000020542 15217274217 033435 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.ext; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import opennlp.tools.commons.Internal; /** * The {@link ExtensionLoader} is responsible to load extensions to the OpenNLP library. *

* Only classes whose fully-qualified name starts with a registered package prefix are * permitted. The default allowed prefix is {@code opennlp.}, which covers all built-in * factories and serializers. *

* To allow custom extension classes from other packages, either: *

    *
  • Call {@link #registerAllowedPackage(String)} programmatically before loading * any model that uses the custom class.
  • *
  • Set the system property {@code OPENNLP_EXT_ALLOWED_PACKAGES} to a * comma-separated list of package prefixes at JVM startup, e.g. * {@code -DOPENNLP_EXT_ALLOWED_PACKAGES=com.acme.nlp.,com.other.}.
  • *
*

* Note: * Do not use this class, internal use only! */ @Internal public class ExtensionLoader { /** * System property for supplying additional allowed package prefixes. * Value is a comma-separated list, e.g. {@code com.acme.nlp.,com.other.}. *

* This property is read once at class-load time. If it cannot be set via * {@code -D} at JVM startup (e.g. in embedded or test scenarios), call * {@link #registerAllowedPackage(String)} before loading any model that * uses a custom factory or serializer. */ public static final String ALLOWED_PACKAGES_PROPERTY = "OPENNLP_EXT_ALLOWED_PACKAGES"; /** * Package prefixes whose classes are permitted to be instantiated as extensions. * Seeded from {@code opennlp.} plus any prefixes in {@link #ALLOWED_PACKAGES_PROPERTY}. */ private static final Set ALLOWED_PREFIXES = initAllowedPrefixes(); private static Set initAllowedPrefixes() { Set prefixes = new CopyOnWriteArraySet<>(Collections.singleton("opennlp.")); String prop = System.getProperty(ALLOWED_PACKAGES_PROPERTY, ""); if (!prop.isBlank()) { Arrays.stream(prop.split(",")) .map(String::trim) .filter(s -> !s.isBlank()) .map(s -> s.endsWith(".") ? s : s + ".") .forEach(prefixes::add); } return prefixes; } private ExtensionLoader() { } /** * Registers an additional package prefix whose classes are permitted to be * loaded as OpenNLP extensions. Call this once at application startup, before * loading any model that uses a custom factory or serializer from that package. *

* The prefix is normalized to end with {@code '.'} to prevent collision attacks * (e.g. registering {@code "com.acme"} cannot be exploited via {@code "com.acmeevil.*"}). * * @param packagePrefix The package prefix to allow, e.g. {@code "com.example.nlp"}. * Must not be {@code null} or blank. * @throws NullPointerException if {@code packagePrefix} is {@code null}. * @throws IllegalArgumentException if {@code packagePrefix} is blank. */ public static void registerAllowedPackage(String packagePrefix) { Objects.requireNonNull(packagePrefix, "packagePrefix must not be null"); if (packagePrefix.isBlank()) { throw new IllegalArgumentException("packagePrefix must not be blank"); } String normalized = packagePrefix.endsWith(".") ? packagePrefix : packagePrefix + "."; ALLOWED_PREFIXES.add(normalized); } /** * Removes a previously registered package prefix. Has no effect if the prefix * was not registered. The default {@code opennlp.} prefix can also be removed, * though this is not recommended. *

* The prefix is normalized to end with {@code '.'} before removal, matching the * normalization applied in {@link #registerAllowedPackage(String)}. * * @param packagePrefix The package prefix to remove, e.g. {@code "com.example.nlp"}. * Must not be {@code null}. * @throws NullPointerException if {@code packagePrefix} is {@code null}. */ public static void unregisterAllowedPackage(String packagePrefix) { Objects.requireNonNull(packagePrefix, "packagePrefix must not be null"); String normalized = packagePrefix.endsWith(".") ? packagePrefix : packagePrefix + "."; ALLOWED_PREFIXES.remove(normalized); } /** * Instantiates a user provided extension to OpenNLP. *

* The extension is loaded from the class path. *

* Initially, the load is conducted using the public no-arg constructor. * If no such constructor is not found, it is checked if the class follows the * {@code Singleton} pattern: a static field named {@code INSTANCE} that * returns an object of the type {@link T}. * * @param clazz A reference to {@link Class}. * @param extensionClassName The (fully-qualified) name of the class * by which the extension shall be loaded. * * @return the instance of the extension class * * @throws ExtensionNotLoadedException Thrown if the load operation failed or * the class is not in an allowed package. */ @SuppressWarnings("unchecked") public static T instantiateExtension(Class clazz, String extensionClassName) { if (extensionClassName == null) { throw new ExtensionNotLoadedException("extensionClassName must not be null"); } // Validate BEFORE Class.forName() — Class.forName() executes static initializers // (CWE-470), which must not run for untrusted class names. boolean allowed = ALLOWED_PREFIXES.stream().anyMatch(extensionClassName::startsWith); if (!allowed) { throw new ExtensionNotLoadedException( "Class '" + extensionClassName + "' is not in an allowed package. " + "Register the package via ExtensionLoader.registerAllowedPackage() or set " + "the system property " + ALLOWED_PACKAGES_PROPERTY + " at JVM startup."); } // First try to load extension and instantiate extension from class path try { Class extClazz = Class.forName(extensionClassName); if (clazz.isAssignableFrom(extClazz)) { try { return (T) extClazz.getDeclaredConstructor().newInstance(); } catch (InstantiationException | NoSuchMethodException e) { throw new ExtensionNotLoadedException(e); } catch (IllegalAccessException e) { // constructor is private. Try to load using INSTANCE Field instanceField; try { instanceField = extClazz.getDeclaredField("INSTANCE"); } catch (NoSuchFieldException | SecurityException e1) { throw new ExtensionNotLoadedException(e1); } if (instanceField != null) { try { return (T) instanceField.get(null); } catch (IllegalArgumentException | IllegalAccessException e1) { throw new ExtensionNotLoadedException(e1); } } throw new ExtensionNotLoadedException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } else { throw new ExtensionNotLoadedException("Extension class '" + extClazz.getName() + "' needs to have type: " + clazz.getName()); } } catch (ClassNotFoundException e) { // Class is not on classpath } throw new ExtensionNotLoadedException("Unable to find implementation for " + clazz.getName() + ", the class or service " + extensionClassName + " could not be located!"); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_ext_Extensi0100644 0000000 0000000 00000000167 15217274217 032601 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ext/ExtensionNotLoadedException.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ext/ExtensionNotLoadedExcep0100644 0000000 0000000 00000002212 15217274217 034137 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.ext; /** * Exception indicates that an OpenNLP extension could not be loaded. */ @SuppressWarnings("serial") public class ExtensionNotLoadedException extends RuntimeException { public ExtensionNotLoadedException(String message) { super(message); } public ExtensionNotLoadedException(Throwable t) { super(t); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_ext_Extensi0100644 0000000 0000000 00000000160 15217274217 032572 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ext/ExtensionServiceKeys.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ext/ExtensionServiceKeys.ja0100644 0000000 0000000 00000002025 15217274217 034130 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.ext; public final class ExtensionServiceKeys { /** * Property key for the unique {@code id} which identifies an * OpenNLP extension service. */ public static final String ID = "OPENLP_EXTENSION_ID"; } apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/ext/package-info.java0100644 0000000 0000000 00000001570 15217274217 032656 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package containing extension loading code. */ package opennlp.tools.util.ext; ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000173 15217274217 032563 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AdaptiveFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AdaptiveFeatureG0100644 0000000 0000000 00000004737 15217274217 034127 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * An interface for generating features for name entity identification and for * updating document level contexts. *

* * Note:
* Feature generation is not thread safe and a instance of a feature generator * must only be called from one thread. The resources used by a feature * generator are typically shared between many instances of features generators * which are called from many threads and have to be thread safe. */ public interface AdaptiveFeatureGenerator { /** * Adds the appropriate features for the token at the specified {@code index} with the * specified array of {@code previousOutcomes} to the specified list of features. * * @param features The list of features to be added to. * @param tokens The tokens of the sentence or other text unit being processed. * @param index The index of the token which is currently being processed. * @param previousOutcomes The outcomes for the tokens prior to the specified index. */ void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes); /** * Informs a feature generator that the specified tokens have been classified with the * corresponding set of specified {@code outcomes}. * * @param tokens The tokens of the sentence or other text unit which has been processed. * @param outcomes The outcomes associated with the specified tokens. */ default void updateAdaptiveData(String[] tokens, String[] outcomes) {} /** * Informs a feature generator that the context of the adaptive data (typically a document) * is no longer valid. */ default void clearAdaptiveData() {} } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000204 15217274217 032556 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AdditionalContextFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AdditionalContex0100644 0000000 0000000 00000003046 15217274217 034170 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * The {@link AdditionalContextFeatureGenerator} generates the context from the passed * in additional context. */ public class AdditionalContextFeatureGenerator implements AdaptiveFeatureGenerator { private static final String PREFIX = "ne="; private String[][] additionalContext; @Override public void createFeatures(List features, String[] tokens, int index, String[] preds) { if (additionalContext != null && additionalContext.length != 0) { String[] context = additionalContext[index]; for (String s : context) { features.add(PREFIX + s); } } } public void setCurrentContext(String[][] context) { additionalContext = context; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000175 15217274217 032565 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AggregatedFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AggregatedFeatur0100644 0000000 0000000 00000007153 15217274217 034143 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; /** * The {@link AggregatedFeatureGenerator} aggregates a set of * {@link AdaptiveFeatureGenerator feature generators} and calls them * to generate the features. */ public class AggregatedFeatureGenerator implements AdaptiveFeatureGenerator { private Collection generators; /** * Initializes an {@link AggregatedFeatureGenerator} via specified {@code generators}. * * @param generators A collection of generators, {@code null} values are not permitted. */ public AggregatedFeatureGenerator(AdaptiveFeatureGenerator... generators) { for (AdaptiveFeatureGenerator generator : generators) { Objects.requireNonNull(generator, "null values in generators are not permitted"); } this.generators = new ArrayList<>(generators.length); Collections.addAll(this.generators, generators); this.generators = Collections.unmodifiableCollection(this.generators); } /** * Initializes an {@link AggregatedFeatureGenerator} via specified {@code generators}. * * @param generators A collection of generators, {@code null} values are not permitted. */ public AggregatedFeatureGenerator(Collection generators) { this(generators.toArray(new AdaptiveFeatureGenerator[0])); } /** * Calls the {@link AdaptiveFeatureGenerator#clearAdaptiveData()} method * on all aggregated {@link AdaptiveFeatureGenerator feature generators}. */ @Override public void clearAdaptiveData() { for (AdaptiveFeatureGenerator generator : generators) { generator.clearAdaptiveData(); } } /** * Calls the {@link AdaptiveFeatureGenerator#createFeatures(List, String[], int, String[])} * method on all aggregated {@link AdaptiveFeatureGenerator feature generators}. */ @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { for (AdaptiveFeatureGenerator generator : generators) { generator.createFeatures(features, tokens, index, previousOutcomes); } } /** * Calls the {@link AdaptiveFeatureGenerator#updateAdaptiveData(String[], String[])} * method on all aggregated {@link AdaptiveFeatureGenerator feature generators}. */ public void updateAdaptiveData(String[] tokens, String[] outcomes) { for (AdaptiveFeatureGenerator generator : generators) { generator.updateAdaptiveData(tokens, outcomes); } } /** * Retrieves a {@link Collections} of all aggregated * {@link AdaptiveFeatureGenerator feature generators}. * * @return All aggregated generators in use. */ public Collection getGenerators() { return generators; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000204 15217274217 032556 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AggregatedFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/AggregatedFeatur0100644 0000000 0000000 00000003416 15217274217 034141 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.ArrayList; import java.util.List; import java.util.Map; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link AggregatedFeatureGenerator} instances * when {@link #create()} is called. * * @see AggregatedFeatureGenerator */ public class AggregatedFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public AggregatedFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { List aggregatedGenerators = new ArrayList<>(); for (Map.Entry arg : args.entrySet()) { if (arg.getKey().startsWith("generator#")) { aggregatedGenerators.add((AdaptiveFeatureGenerator) arg.getValue()); } } return new AggregatedFeatureGenerator(aggregatedGenerators.toArray( new AdaptiveFeatureGenerator[0])); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000175 15217274217 032565 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BigramNameFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BigramNameFeatur0100644 0000000 0000000 00000003322 15217274217 034105 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * Adds bigram features based on tokens and token classes. * * @see AdaptiveFeatureGenerator */ public class BigramNameFeatureGenerator implements AdaptiveFeatureGenerator { @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { String wc = FeatureGeneratorUtil.tokenFeature(tokens[index]); //bi-gram features if (index > 0) { features.add("pw,w=" + tokens[index - 1] + "," + tokens[index]); String pwc = FeatureGeneratorUtil.tokenFeature(tokens[index - 1]); features.add("pwc,wc=" + pwc + "," + wc); } if (index + 1 < tokens.length) { features.add("w,nw=" + tokens[index] + "," + tokens[index + 1]); String nwc = FeatureGeneratorUtil.tokenFeature(tokens[index + 1]); features.add("wc,nc=" + wc + "," + nwc); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000204 15217274217 032556 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BigramNameFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BigramNameFeatur0100644 0000000 0000000 00000002546 15217274217 034114 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link BigramNameFeatureGenerator} instances * when {@link #create()} is called. * * @see BigramNameFeatureGenerator */ public class BigramNameFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public BigramNameFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new BigramNameFeatureGenerator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000176 15217274217 032566 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownBigramFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownBigramFeatu0100644 0000000 0000000 00000004737 15217274217 034145 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * Generates Brown cluster features for token bigrams. * * @see AdaptiveFeatureGenerator * @see BrownCluster */ public class BrownBigramFeatureGenerator implements AdaptiveFeatureGenerator { private static final String BROWNCLUSTER = "browncluster"; private static final String FEATURE_NEXT_BROWNCLUSTER_BASE = BROWNCLUSTER + ",n" + BROWNCLUSTER + "="; private static final String FEATURE_PREV_BROWNCLUSTER_BASE = "p" + BROWNCLUSTER + "," + BROWNCLUSTER + "="; private final BrownCluster brownCluster; /** * Initializes a {@link BrownBigramFeatureGenerator} generator via a specified * {@link BrownCluster}. * * @param brownCluster The token {@link BrownCluster dictionary} to use. */ public BrownBigramFeatureGenerator(BrownCluster brownCluster) { this.brownCluster = brownCluster; } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { List wc = BrownTokenClasses.getWordClasses(tokens[index], brownCluster); if (index > 0) { List prevWC = BrownTokenClasses.getWordClasses(tokens[index - 1], brownCluster); for (int i = 0; i < wc.size() && i < prevWC.size(); i++) { features.add(FEATURE_PREV_BROWNCLUSTER_BASE + prevWC.get(i) + "," + wc.get(i)); } } if (index + 1 < tokens.length) { List nextWordClasses = BrownTokenClasses.getWordClasses(tokens[index + 1], brownCluster); for (int i = 0; i < wc.size() && i < nextWordClasses.size(); i++) { features.add(FEATURE_NEXT_BROWNCLUSTER_BASE + wc.get(i) + "," + nextWordClasses.get(i)); } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000157 15217274217 032565 xustar000000000 0000000 111 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownCluster.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownCluster.jav0100644 0000000 0000000 00000010045 15217274217 034144 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.SerializableArtifact; /** * Class to load a Brown cluster document in the format: {@code word\tword_class\tprob}. *

* Originally available at: * http://metaoptimize.com/projects/wordreprs/. *

* Further details can be found in the * related research paper. *

* The file containing the clustering lexicon has to be passed as the * value of the dict attribute of each {@link BrownCluster} feature generator. */ public class BrownCluster implements SerializableArtifact { private static final Pattern tabPattern = Pattern.compile("\t"); public static class BrownClusterSerializer implements ArtifactSerializer { @Override public BrownCluster create(InputStream in) throws IOException { return new BrownCluster(in); } @Override public void serialize(BrownCluster artifact, OutputStream out) throws IOException { artifact.serialize(out); } } private final Map tokenToClusterMap = new HashMap<>(); /** * Instatiates a {@link BrownCluster} and its related token to cluster map * via an {@link InputStream}. * * @implNote * Only tokens with frequency bigger than {@code 5} will be added. * * @param in A valid, open {@link InputStream} to read from. * @throws IOException Thrown if errors occurred reading from {@link InputStream in}. */ public BrownCluster(InputStream in) throws IOException { try (BufferedReader breader = new BufferedReader( new InputStreamReader(in, StandardCharsets.UTF_8))) { String line; while ((line = breader.readLine()) != null) { String[] lineArray = tabPattern.split(line); if (lineArray.length == 3) { int freq = Integer.parseInt(lineArray[2]); if (freq > 5 ) { tokenToClusterMap.put(lineArray[1], lineArray[0]); } } else if (lineArray.length == 2) { tokenToClusterMap.put(lineArray[0], lineArray[1]); } } } } /** * Check if a token is in the Brown:paths, token map. * * @param string the token to look-up * @return the brown class if such token is in the brown cluster map. */ public String lookupToken(String string) { return tokenToClusterMap.get(string); } public void serialize(OutputStream out) throws IOException { try (Writer writer = new BufferedWriter(new OutputStreamWriter(out))) { for (Map.Entry entry : tokenToClusterMap.entrySet()) { writer.write(entry.getKey() + "\t" + entry.getValue() + "\n"); } writer.flush(); } } @Override public Class getArtifactSerializerClass() { return BrownClusterSerializer.class; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000214 15217274217 032557 xustar000000000 0000000 140 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownClusterBigramFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownClusterBigr0100644 0000000 0000000 00000004236 15217274217 034176 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.HashMap; import java.util.Map; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ArtifactSerializer; /** * A {@link GeneratorFactory} that produces {@link BrownBigramFeatureGenerator} instances * when {@link #create()} is called. * * @see BrownBigramFeatureGenerator */ public class BrownClusterBigramFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public BrownClusterBigramFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { // if resourceManager is null, we don't instantiate if (resourceManager == null) { return null; } String dictResourceKey = getStr("dict"); Object dictResource = resourceManager.getResource(dictResourceKey); if (!(dictResource instanceof BrownCluster)) { throw new InvalidFormatException("Not a BrownLexicon resource for key: " + dictResourceKey); } return new BrownBigramFeatureGenerator((BrownCluster) dictResource); } @Override public Map> getArtifactSerializerMapping() throws InvalidFormatException { Map> mapping = new HashMap<>(); mapping.put(getStr("dict"), new BrownCluster.BrownClusterSerializer()); return mapping; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000220 15217274217 032554 xustar000000000 0000000 144 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownClusterTokenClassFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownClusterToke0100644 0000000 0000000 00000004262 15217274217 034214 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.HashMap; import java.util.Map; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ArtifactSerializer; /** * A {@link GeneratorFactory} that produces {@link BrownTokenClassFeatureGenerator} instances * when {@link #create()} is called. * * @see BrownTokenClassFeatureGenerator */ public class BrownClusterTokenClassFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public BrownClusterTokenClassFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { // if resourceManager is null, we don't instantiate if (resourceManager == null) { return null; } String dictResourceKey = getStr("dict"); Object dictResource = resourceManager.getResource(dictResourceKey); if (!(dictResource instanceof BrownCluster)) { throw new InvalidFormatException("Not a BrownLexicon resource for key: " + dictResourceKey); } return new BrownTokenClassFeatureGenerator((BrownCluster) dictResource); } @Override public Map> getArtifactSerializerMapping() throws InvalidFormatException { Map> mapping = new HashMap<>(); mapping.put(getStr("dict"), new BrownCluster.BrownClusterSerializer()); return mapping; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000213 15217274217 032556 xustar000000000 0000000 139 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownClusterTokenFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownClusterToke0100644 0000000 0000000 00000004231 15217274217 034210 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.HashMap; import java.util.Map; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ArtifactSerializer; /** * A {@link GeneratorFactory} that produces {@link BrownTokenFeatureGenerator} instances * when {@link #create()} is called. * * @see BrownTokenFeatureGenerator */ public class BrownClusterTokenFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public BrownClusterTokenFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { // if resourceManager is null, we don't instantiate if (resourceManager == null) { return null; } String dictResourceKey = getStr("dict"); Object dictResource = resourceManager.getResource(dictResourceKey); if (!(dictResource instanceof BrownCluster)) { throw new InvalidFormatException("Not a BrownLexicon resource for key: " + dictResourceKey); } return new BrownTokenFeatureGenerator((BrownCluster) dictResource); } @Override public Map> getArtifactSerializerMapping() throws InvalidFormatException { Map> mapping = new HashMap<>(); mapping.put(getStr("dict"), new BrownCluster.BrownClusterSerializer()); return mapping; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000202 15217274217 032554 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownTokenClassFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownTokenClassF0100644 0000000 0000000 00000003543 15217274217 034125 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * Generates {@link BrownCluster} features for current token and token class. * * @see AdaptiveFeatureGenerator * @see BrownCluster */ public class BrownTokenClassFeatureGenerator implements AdaptiveFeatureGenerator { private static final String PREFIX = "c,browncluster="; private final BrownCluster brownLexicon; /** * Instantiates a {@link BrownTokenClassFeatureGenerator} via a specified * {@link BrownCluster}. * * @param dict The token {@link BrownCluster dictionary} to use. */ public BrownTokenClassFeatureGenerator(BrownCluster dict) { this.brownLexicon = dict; } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { String wordShape = FeatureGeneratorUtil.tokenFeature(tokens[index]); List wordClasses = BrownTokenClasses.getWordClasses(tokens[index], brownLexicon); for (String wordClass : wordClasses) { features.add(PREFIX + wordShape + "," + wordClass); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000164 15217274217 032563 xustar000000000 0000000 116 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownTokenClasses.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownTokenClasse0100644 0000000 0000000 00000004177 15217274217 034170 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Obtain the paths listed in the pathLengths array from the Brown class. * This class is not to be instantiated. * * @see BrownCluster */ public class BrownTokenClasses { public static final int[] pathLengths = { 4, 6, 10, 20 }; /** * It provides a list containing the pathLengths for a token if found * in the Map:token,BrownClass. * * @param token The token to be looked up in the brown clustering map * @param brownLexicon The {@link BrownCluster} clustering map * @return A list of the paths for a token. */ public static List getWordClasses(String token, BrownCluster brownLexicon) { if (brownLexicon.lookupToken(token) == null) { return Collections.emptyList(); } else { String brownClass = brownLexicon.lookupToken(token); List pathLengthsList = new ArrayList<>(); pathLengthsList.add(brownClass.substring(0, StrictMath.min(brownClass.length(), pathLengths[0]))); for (int i = 1; i < pathLengths.length; i++) { if (pathLengths[i - 1] < brownClass.length()) { pathLengthsList.add(brownClass.substring(0, StrictMath.min(brownClass.length(), pathLengths[i]))); } } return pathLengthsList; } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000175 15217274217 032565 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownTokenFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/BrownTokenFeatur0100644 0000000 0000000 00000003346 15217274217 034201 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * Generates {@link BrownCluster} features for current token. * * @see AdaptiveFeatureGenerator * @see BrownCluster */ public class BrownTokenFeatureGenerator implements AdaptiveFeatureGenerator { private static final String PREFIX = "browncluster="; private final BrownCluster brownLexicon; /** * Instantiates a {@link BrownTokenFeatureGenerator} via a specified * {@link BrownCluster}. * * @param dict The token {@link BrownCluster dictionary} to use. */ public BrownTokenFeatureGenerator(BrownCluster dict) { this.brownLexicon = dict; } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { List wordClasses = BrownTokenClasses.getWordClasses(tokens[index], brownLexicon); for (String wordClass : wordClasses) { features.add(PREFIX + wordClass); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000171 15217274217 032561 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CachedFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CachedFeatureGen0100644 0000000 0000000 00000006257 15217274217 034063 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.ArrayList; import java.util.List; import opennlp.tools.util.Cache; /** * Caches features of the aggregated {@link AdaptiveFeatureGenerator generators}. * * @see Cache */ public class CachedFeatureGenerator implements AdaptiveFeatureGenerator { private final AdaptiveFeatureGenerator generator; private String[] prevTokens; private final Cache> contextsCache; private long numberOfCacheHits; private long numberOfCacheMisses; @Deprecated public CachedFeatureGenerator(AdaptiveFeatureGenerator... generators) { this.generator = new AggregatedFeatureGenerator(generators); contextsCache = new Cache<>(100); } public CachedFeatureGenerator(AdaptiveFeatureGenerator generator) { this.generator = generator; contextsCache = new Cache<>(100); } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { List cacheFeatures; if (tokens == prevTokens) { cacheFeatures = contextsCache.get(index); if (cacheFeatures != null) { numberOfCacheHits++; features.addAll(cacheFeatures); return; } } else { contextsCache.clear(); prevTokens = tokens; } cacheFeatures = new ArrayList<>(); numberOfCacheMisses++; generator.createFeatures(cacheFeatures, tokens, index, previousOutcomes); contextsCache.put(index, cacheFeatures); features.addAll(cacheFeatures); } @Override public void updateAdaptiveData(String[] tokens, String[] outcomes) { generator.updateAdaptiveData(tokens, outcomes); } @Override public void clearAdaptiveData() { generator.clearAdaptiveData(); } /** * @return Retrieves the number of times a cache hit occurred. */ public long getNumberOfCacheHits() { return numberOfCacheHits; } /** * @return Retrieves the number of times a cache miss occurred. */ public long getNumberOfCacheMisses() { return numberOfCacheMisses; } @Override public String toString() { return super.toString() + ": hits=" + numberOfCacheHits + " misses=" + numberOfCacheMisses + " hit%" + (numberOfCacheHits > 0 ? (double) numberOfCacheHits / (numberOfCacheMisses + numberOfCacheHits) : 0); } public AdaptiveFeatureGenerator getCachedFeatureGenerator() { return generator; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000200 15217274217 032552 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CachedFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CachedFeatureGen0100644 0000000 0000000 00000003064 15217274217 034054 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link CachedFeatureGenerator} instances * when {@link #create()} is called. * * @see CachedFeatureGenerator */ public class CachedFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public CachedFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { AdaptiveFeatureGenerator generator = (AdaptiveFeatureGenerator) args.get("generator#0"); if (generator == null) { throw new InvalidFormatException("Could not find containing generator element!"); } return new CachedFeatureGenerator(generator); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000201 15217274217 032553 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CharacterNgramFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CharacterNgramFe0100644 0000000 0000000 00000004456 15217274217 034101 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; import opennlp.tools.ngram.NGramModel; import opennlp.tools.util.StringList; import opennlp.tools.util.StringUtil; /** * The {@link CharacterNgramFeatureGenerator} uses character ngrams to * generate features about each token. * * @see AdaptiveFeatureGenerator */ public class CharacterNgramFeatureGenerator implements AdaptiveFeatureGenerator { private static final String PREFIX = "ng="; private final int minLength; private final int maxLength; /** * Initializes a {@link CharacterNgramFeatureGenerator} with the specified parameters. * * @param minLength The minimum length to use. Must not be negative. * @param maxLength The maximum length to use. Must not be negative. */ public CharacterNgramFeatureGenerator(int minLength, int maxLength) { this.minLength = minLength; this.maxLength = maxLength; } /** * Initializes a {@link CharacterNgramFeatureGenerator} with default values for ngrams. * The minimal length is set to {@code 2} and maximum length to a value of {@code 5}. */ public CharacterNgramFeatureGenerator() { this(2, 5); } @Override public void createFeatures(List features, String[] tokens, int index, String[] preds) { NGramModel model = new NGramModel(); model.add(tokens[index], minLength, maxLength); for (StringList tokenList : model) { if (tokenList.size() > 0) { features.add(PREFIX + StringUtil.toLowerCase(tokenList.getToken(0))); } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000210 15217274217 032553 xustar000000000 0000000 136 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CharacterNgramFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/CharacterNgramFe0100644 0000000 0000000 00000002626 15217274217 034076 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link CharacterNgramFeatureGenerator} instances * when {@link #create()} is called. * * @see CharacterNgramFeatureGenerator */ public class CharacterNgramFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public CharacterNgramFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new CharacterNgramFeatureGenerator(getInt("min"), getInt("max")); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000204 15217274217 032556 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DefinitionFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DefinitionFeatur0100644 0000000 0000000 00000002554 15217274217 034201 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link OutcomePriorFeatureGenerator} instances * when {@link #create()} is called. * * @see OutcomePriorFeatureGenerator */ public class DefinitionFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public DefinitionFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new OutcomePriorFeatureGenerator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000175 15217274217 032565 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DictionaryFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DictionaryFeatur0100644 0000000 0000000 00000004464 15217274217 034220 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.namefind.DictionaryNameFinder; /** * The {@link DictionaryFeatureGenerator} uses a {@link DictionaryNameFinder} * to generate features for detected names based on the {@link InSpanGenerator}. * * @see Dictionary * @see DictionaryNameFinder * @see InSpanGenerator */ public class DictionaryFeatureGenerator implements AdaptiveFeatureGenerator { private InSpanGenerator isg; /** * Initializes a {@link DictionaryFeatureGenerator} with the specified {@link Dictionary}. * * @param dict The {@link Dictionary} to use. Must not be {@code null}. */ public DictionaryFeatureGenerator(Dictionary dict) { this("", dict); } /** * Initializes a {@link DictionaryFeatureGenerator} with the specified parameters. * * @param prefix The prefix to set. Must not be {@code null} but may be empty. * @param dict The {@link Dictionary} to use. Must not be {@code null}. */ public DictionaryFeatureGenerator(String prefix, Dictionary dict) { setDictionary(prefix, dict); } public void setDictionary(Dictionary dict) { setDictionary("", dict); } public void setDictionary(String name, Dictionary dict) { isg = new InSpanGenerator(name, new DictionaryNameFinder(dict)); } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { isg.createFeatures(features, tokens, index, previousOutcomes); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000204 15217274217 032556 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DictionaryFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DictionaryFeatur0100644 0000000 0000000 00000005664 15217274217 034223 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import opennlp.tools.dictionary.Dictionary; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.DictionarySerializer; /** * A {@link GeneratorFactory} that produces {@link DictionaryFeatureGenerator} instances * when {@link #create()} is called. * * @see DictionaryFeatureGenerator */ public class DictionaryFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { private static final String DICT = "dict"; public DictionaryFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { Dictionary d; if (resourceManager == null) { // load the dictionary directly String dictResourcePath = getStr(DICT); ClassLoader cl = Thread.currentThread().getContextClassLoader(); try (InputStream is = cl.getResourceAsStream(dictResourcePath)) { if (is != null) { d = ((DictionarySerializer) getArtifactSerializerMapping().get(dictResourcePath)).create(is); } else { throw new InvalidFormatException("No dictionary resource at: '" + dictResourcePath); } } catch (IOException e) { throw new InvalidFormatException("Error processing resource at: " + dictResourcePath, e); } } else { // get the dictionary via a resourceManager lookup String dictResourceKey = getStr(DICT); Object dictResource = resourceManager.getResource(dictResourceKey); if (dictResource instanceof Dictionary dict) { d = dict; } else { throw new InvalidFormatException("No dictionary resource for key: " + dictResourceKey); } } return new DictionaryFeatureGenerator(d); } @Override public Map> getArtifactSerializerMapping() throws InvalidFormatException { Map> mapping = new HashMap<>(); mapping.put(getStr(DICT), new DictionarySerializer()); return mapping; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000200 15217274217 032552 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DocumentBeginFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DocumentBeginFea0100644 0000000 0000000 00000002657 15217274217 034105 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * This feature generator creates document begin features. * * @see AdaptiveFeatureGenerator */ public class DocumentBeginFeatureGenerator implements AdaptiveFeatureGenerator { private String[] firstSentence; @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { if (firstSentence == null) { firstSentence = tokens; } if (firstSentence == tokens && index == 0) { features.add("D=begin"); } } @Override public void clearAdaptiveData() { firstSentence = null; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000207 15217274217 032561 xustar000000000 0000000 135 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DocumentBeginFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/DocumentBeginFea0100644 0000000 0000000 00000002565 15217274217 034103 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link DocumentBeginFeatureGenerator} instances * when {@link #create()} is called. * * @see DocumentBeginFeatureGenerator */ public class DocumentBeginFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public DocumentBeginFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new DocumentBeginFeatureGenerator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000203 15217274217 032555 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/FeatureGeneratorResourceProvider.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/FeatureGenerator0100644 0000000 0000000 00000002673 15217274217 034206 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.commons.Internal; /** * The {@link FeatureGeneratorResourceProvider} provides access to the resources * available in the model. Inside the model resources are identified by a name. * * @apiNote This interface is not intended to be implemented by users.
* All implementing classes must be thread safe. */ @Internal public interface FeatureGeneratorResourceProvider { /** * @param resourceIdentifier The identifier which names the resource. * * @return Retrieves the resource object for the given {@code resourceIdentifier}. */ Object getResource(String resourceIdentifier); } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000167 15217274217 032566 xustar000000000 0000000 119 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/FeatureGeneratorUtil.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/FeatureGenerator0100644 0000000 0000000 00000006102 15217274217 034175 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.regex.Pattern; /** * This class provide common utilities for feature generation. */ public class FeatureGeneratorUtil { private static final Pattern capPeriod = Pattern.compile("^[A-ZÄÖÜ]\\.$"); /** * Generates a class name for the specified token. * The classes are as follows where the first matching class is used: *

    *
  • jah - Japanese Hiragana
  • *
  • jak - Japanese Katakana
  • *
  • lc - lowercase alphabetic
  • *
  • 2d - two digits
  • *
  • 4d - four digits
  • *
  • an - alpha-numeric
  • *
  • dd - digits and dashes
  • *
  • ds - digits and slashes
  • *
  • dc - digits and commas
  • *
  • dp - digits and periods
  • *
  • num - digits
  • *
  • sc - single capital letter
  • *
  • ac - all capital letters
  • *
  • ic - initial capital letter
  • *
  • other - other
  • *
* @param token A token or word. * @return The class name that the specified token belongs in. */ public static String tokenFeature(String token) { StringPattern pattern = StringPattern.recognize(token); String feat; if (pattern.isAllHiragana()) { feat = "jah"; } else if (pattern.isAllKatakana()) { feat = "jak"; } else if (pattern.isAllLowerCaseLetter()) { feat = "lc"; } else if (pattern.digits() == 2) { feat = "2d"; } else if (pattern.digits() == 4) { feat = "4d"; } else if (pattern.containsDigit()) { if (pattern.containsLetters()) { feat = "an"; } else if (pattern.containsHyphen()) { feat = "dd"; } else if (pattern.containsSlash()) { feat = "ds"; } else if (pattern.containsComma()) { feat = "dc"; } else if (pattern.containsPeriod()) { feat = "dp"; } else { feat = "num"; } } else if (pattern.isAllCapitalLetter()) { if (token.length() == 1) { feat = "sc"; } else { feat = "ac"; } } else if (capPeriod.matcher(token).find()) { feat = "cp"; } else if (pattern.isInitialCapitalLetter()) { feat = "ic"; } else { feat = "other"; } return (feat); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000163 15217274217 032562 xustar000000000 0000000 115 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/GeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/GeneratorFactory0100644 0000000 0000000 00000050136 15217274217 034217 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.SAXException; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.XmlUtil; import opennlp.tools.util.ext.ExtensionLoader; import opennlp.tools.util.model.ArtifactSerializer; /** * Creates a set of feature generators based on a provided XML descriptor. *

* Example of an XML descriptor: *

* <featureGenerators name="namefind"> * <generator class="opennlp.tools.util.featuregen.CachedFeatureGeneratorFactory"> * <generator class="opennlp.tools.util.featuregen.WindowFeatureGeneratorFactory"> * <int name="prevLength">2</int> * <int name="nextLength">2</int> * <generator class="opennlp.tools.util.featuregen.TokenClassFeatureGeneratorFactory"/> * </generator> * <generator class="opennlp.tools.util.featuregen.WindowFeatureGeneratorFactory"> * <int name="prevLength">2</int> * <int name="nextLength">2</int> * <generator class="opennlp.tools.util.featuregen.TokenFeatureGeneratorFactory"/> * </generator> * <generator class="opennlp.tools.util.featuregen.DefinitionFeatureGeneratorFactory"/> * <generator class="opennlp.tools.util.featuregen.PreviousMapFeatureGeneratorFactory"/> * <generator class="opennlp.tools.util.featuregen.BigramNameFeatureGeneratorFactory"/> * <generator class="opennlp.tools.util.featuregen.SentenceFeatureGeneratorFactory"> * <bool name="begin">true</bool> * <bool name="end">false</bool> * </generator> * </generator> * </featureGenerators> *

* Each XML element is mapped to a {@link GeneratorFactory.AbstractXmlFeatureGeneratorFactory} which * is responsible to process the element and create the specified * {@link AdaptiveFeatureGenerator}. Elements can contain other * elements in this case it is the responsibility of the mapped factory to process * the child elements correctly. *

* In the example above the generators element is mapped to the * {@link AggregatedFeatureGeneratorFactory} which then * creates all the aggregated {@link AdaptiveFeatureGenerator}s to * accomplish this it evaluates the mapping with the same mechanism * and gives the child element to the corresponding factories. All * created generators are added to a new instance of the * {@link AggregatedFeatureGenerator} which is then returned. */ public class GeneratorFactory { /** * Creates an {@link AdaptiveFeatureGenerator} from an provided XML descriptor. *

* Usually this XML descriptor contains a set of nested feature generators * which are then used to generate the features by one of the opennlp * components. * * @param xmlDescriptorIn the {@link InputStream} from which the descriptor * is read, the stream remains open and must be closed by the caller. * @param resourceManager the resource manager which is used to resolve resources * referenced by a key in the descriptor * @return created feature generators * @throws IOException if an error occurs during reading from the descriptor * {@link InputStream} */ public static AdaptiveFeatureGenerator create(InputStream xmlDescriptorIn, FeatureGeneratorResourceProvider resourceManager) throws IOException { final org.w3c.dom.Document xmlDescriptorDOM = createDOM(xmlDescriptorIn); final Element generatorElement = xmlDescriptorDOM.getDocumentElement(); return createGenerator(generatorElement, resourceManager); } /** * Creates an {@link AdaptiveFeatureGenerator} for the provided element. * To accomplish this it looks up the corresponding factory by the * element tag name. The factory is then responsible for the creation * of the generator from the element. * * @param generatorElement must not be {@code null} * @param resourceManager may be {@code null} * @return an {@link AdaptiveFeatureGenerator} * @throws IllegalArgumentException if the given {@link Element generatorElement} is {@code null}. * @throws IllegalStateException if the given {@link Element generatorElement} has * no {@code class} attribute. */ private static AdaptiveFeatureGenerator buildGenerator(Element generatorElement, FeatureGeneratorResourceProvider resourceManager) throws InvalidFormatException { if (generatorElement == null) { throw new IllegalArgumentException("generatorElement must not be NULL"); } final String className = generatorElement.getAttribute("class"); if (className.isBlank()) { throw new InvalidFormatException("generator must have class attribute"); } else { try { final AbstractXmlFeatureGeneratorFactory factory = ExtensionLoader.instantiateExtension(AbstractXmlFeatureGeneratorFactory.class, className); factory.init(generatorElement, resourceManager); return factory.create(); } catch (InvalidFormatException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } } /** * Creates an {@link AdaptiveFeatureGenerator} for the provided element. * To accomplish this it looks up the corresponding factory by the * element tag name. The factory is then responsible for the creation * of the generator from the element. * * @param generatorElement must not be {@code null} * @param resourceManager may be {@code null} * @return an {@link AdaptiveFeatureGenerator} * @throws IllegalArgumentException if the given {@link Element generatorElement} is {@code null} */ private static AdaptiveFeatureGenerator createGenerator(Element generatorElement, FeatureGeneratorResourceProvider resourceManager) throws InvalidFormatException { if (generatorElement == null) { throw new IllegalArgumentException("generatorElement must not be NULL"); } final String elementName = generatorElement.getTagName(); // check it is new format? if ("featureGenerators".equals(elementName)) { final List generators = new ArrayList<>(); final NodeList childNodes = generatorElement.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { final Node childNode = childNodes.item(i); if (childNode instanceof Element elem) { final String type = elem.getTagName(); if ("generator".equals(type)) { generators.add(buildGenerator(elem, resourceManager)); } else { throw new InvalidFormatException("Unexpected element: " + elementName); } } } AdaptiveFeatureGenerator featureGenerator; if (generators.size() == 1) { featureGenerator = generators.get(0); } else if (generators.size() > 1) { featureGenerator = new AggregatedFeatureGenerator(generators.toArray( new AdaptiveFeatureGenerator[0])); } else { throw new InvalidFormatException("featureGenerators must have one or more generators"); } // disallow manually specifying CachedFeatureGenerator if (featureGenerator instanceof CachedFeatureGenerator) { throw new InvalidFormatException("CachedFeatureGeneratorFactory cannot be specified manually." + "Use cache=\"true\" attribute in featureGenerators element instead."); } // check cache usage if (Boolean.parseBoolean(generatorElement.getAttribute("cache"))) { return new CachedFeatureGenerator(featureGenerator); } else { return featureGenerator; } } else { throw new IllegalArgumentException( "[OPENNLP-1174] - Classic configuration format is no longer supported!"); } } private static org.w3c.dom.Document createDOM(InputStream xmlDescriptorIn) throws IOException { final DocumentBuilder documentBuilder = XmlUtil.createDocumentBuilder(); org.w3c.dom.Document xmlDescriptorDOM; try { xmlDescriptorDOM = documentBuilder.parse(xmlDescriptorIn); } catch (SAXException e) { throw new InvalidFormatException("Descriptor is not valid XML!", e); } return xmlDescriptorDOM; } public static Map> extractArtifactSerializerMappings( InputStream xmlDescriptorIn) throws IOException { final org.w3c.dom.Document xmlDescriptorDOM = createDOM(xmlDescriptorIn); final Element element = xmlDescriptorDOM.getDocumentElement(); final String elementName = element.getTagName(); // check it is new format? if ("featureGenerators".equals(elementName)) { return addMappingsFromXmlChildren(element.getChildNodes(), new HashMap<>()); } else { throw new IllegalArgumentException( "[OPENNLP-1174] - Classic configuration format is no longer supported!"); } } private static void extractArtifactSerializerMappings( Map> mapping, Element element) { final String className = element.getAttribute("class"); if (!className.isBlank()) { try { final AbstractXmlFeatureGeneratorFactory factory = ExtensionLoader.instantiateExtension(AbstractXmlFeatureGeneratorFactory.class, className); factory.init(element, null); final Map> map = factory.getArtifactSerializerMapping(); if (map != null) { mapping.putAll(map); } } catch (InvalidFormatException ignored) { } catch (Exception e) { throw new RuntimeException(e); } } addMappingsFromXmlChildren(element.getChildNodes(), mapping); } private static Map> addMappingsFromXmlChildren( final NodeList nodes, final Map> mapping) { for (int i = 0; i < nodes.getLength(); i++) { if (nodes.item(i) instanceof Element childElem) { if ("generator".equals(childElem.getTagName())) { extractArtifactSerializerMappings(mapping, childElem); } } } return mapping; } /** * Provides a {@link List} with all the elements in the xml feature descriptor. * * @param xmlDescriptorIn the xml feature descriptor * @return a list containing all elements * @throws IOException if the given {@link InputStream} cannot be open * @throws InvalidFormatException if xml is not well-formed */ public static List getDescriptorElements(InputStream xmlDescriptorIn) throws IOException { final List elements = new ArrayList<>(); final org.w3c.dom.Document xmlDescriptorDOM = createDOM(xmlDescriptorIn); final XPath xPath = XPathFactory.newInstance().newXPath(); NodeList allElements; try { final XPathExpression exp = xPath.compile("//*"); allElements = (NodeList) exp.evaluate(xmlDescriptorDOM.getDocumentElement(), XPathConstants.NODESET); } catch (XPathExpressionException e) { throw new InvalidFormatException("The hard coded XPath expression should always be valid!"); } for (int i = 0; i < allElements.getLength(); i++) { if (allElements.item(i) instanceof Element customElement) { elements.add(customElement); } } return elements; } public static abstract class AbstractXmlFeatureGeneratorFactory { protected Element generatorElement; protected FeatureGeneratorResourceProvider resourceManager; // to respect the order in AggregatedFeatureGenerator, let's use LinkedHashMap protected LinkedHashMap args; public AbstractXmlFeatureGeneratorFactory() { args = new LinkedHashMap<>(); } public Map> getArtifactSerializerMapping() throws InvalidFormatException { return null; } final void init(Element element, FeatureGeneratorResourceProvider resourceManager) throws InvalidFormatException { this.generatorElement = element; this.resourceManager = resourceManager; List generators = new ArrayList<>(); NodeList childNodes = generatorElement.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node childNode = childNodes.item(i); if (childNode instanceof Element elem) { String type = elem.getTagName(); if (type.equals("generator")) { String key = "generator#" + generators.size(); AdaptiveFeatureGenerator afg = buildGenerator(elem, resourceManager); if (afg != null) { generators.add(afg); args.put(key, afg); } } else { String name = elem.getAttribute("name"); Node cn = elem.getFirstChild(); Text text = (Text) cn; switch (type) { case "int" -> args.put(name, Integer.parseInt(text.getWholeText())); case "long" -> args.put(name, Long.parseLong(text.getWholeText())); case "float" -> args.put(name, Float.parseFloat(text.getWholeText())); case "double" -> args.put(name, Double.parseDouble(text.getWholeText())); case "str" -> args.put(name, text.getWholeText()); case "bool" -> args.put(name, Boolean.parseBoolean(text.getWholeText())); default -> throw new InvalidFormatException( "child element must be one of generator, int, long, float, double," + " str or bool"); } } } } if (generators.size() > 1) { AdaptiveFeatureGenerator aggregatedFeatureGenerator = new AggregatedFeatureGenerator(generators.toArray( new AdaptiveFeatureGenerator[0])); args.put("generator#0", aggregatedFeatureGenerator); } } public int getInt(String name) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { throw new InvalidFormatException("parameter " + name + " must be set!"); } else if (value instanceof Integer) { return (Integer) value; } else { throw new InvalidFormatException("parameter " + name + " must be integer!"); } } public int getInt(String name, int defValue) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { return defValue; } else if (value instanceof Integer) { return (Integer) value; } else { throw new InvalidFormatException("parameter " + name + " must be integer!"); } } public long getLong(String name) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { throw new InvalidFormatException("parameter " + name + " must be set!"); } else if (value instanceof Long) { return (Long) value; } else { throw new InvalidFormatException("parameter " + name + " must be long!"); } } public long getLong(String name, long defValue) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { return defValue; } else if (value instanceof Long) { return (Long) value; } else { throw new InvalidFormatException("parameter " + name + " must be long!"); } } public float getFloat(String name) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { throw new InvalidFormatException("parameter " + name + " must be set!"); } else if (value instanceof Float) { return (Float) value; } else { throw new InvalidFormatException("parameter " + name + " must be float!"); } } public float getFloat(String name, float defValue) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { return defValue; } else if (value instanceof Float) { return (Float) value; } else { throw new InvalidFormatException("parameter " + name + " must be float!"); } } public double getDouble(String name) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { throw new InvalidFormatException("parameter " + name + " must be set!"); } else if (value instanceof Double) { return (Double) value; } else { throw new InvalidFormatException("parameter " + name + " must be double!"); } } public double getDouble(String name, double defValue) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { return defValue; } else if (value instanceof Double) { return (Double) value; } else { throw new InvalidFormatException("parameter " + name + " must be double!"); } } public String getStr(String name) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { throw new InvalidFormatException("parameter " + name + " must be set!"); } else if (value instanceof String) { return (String) value; } else { throw new InvalidFormatException("parameter " + name + " must be double!"); } } public String getStr(String name, String defValue) throws InvalidFormatException { final Object value = args.get(name); if (value == null) { return defValue; } else if (value instanceof String) { return (String) value; } else { throw new InvalidFormatException("parameter " + name + " must be String!"); } } public boolean getBool(String name) throws InvalidFormatException { Object value = args.get(name); if (value == null) { throw new InvalidFormatException("parameter " + name + " must be set!"); } else if (value instanceof Boolean) { return (Boolean) value; } else { throw new InvalidFormatException("parameter " + name + " must be boolean!"); } } public boolean getBool(String name, boolean defValue) throws InvalidFormatException { Object value = args.get(name); if (value == null) { return defValue; } else if (value instanceof Boolean) { return (Boolean) value; } else { throw new InvalidFormatException("parameter " + name + " must be boolean!"); } } /** * @return {@code null} if the subclass uses {@link #resourceManager} to instantiate. * * @throws InvalidFormatException Thrown if the format is incorrect. */ public abstract AdaptiveFeatureGenerator create() throws InvalidFormatException; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000162 15217274217 032561 xustar000000000 0000000 114 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/InSpanGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/InSpanGenerator.0100644 0000000 0000000 00000005270 15217274217 034055 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; import java.util.Objects; import opennlp.tools.namefind.TokenNameFinder; import opennlp.tools.util.Span; /** * Generates features if the tokens are recognized by the provided * {@link TokenNameFinder}. * * @see AdaptiveFeatureGenerator * @see TokenNameFinder * @see Span */ public class InSpanGenerator implements AdaptiveFeatureGenerator { private static final String W_DIC = ":w=dic"; private static final String W_DIC_IS = W_DIC + "="; private final String prefix; private final TokenNameFinder finder; private String[] currentSentence; private Span[] currentNames; /** * Initializes a {@link InSpanGenerator} instance. * * @param prefix The prefix is used to distinguish the generated features * from features generated by other instances of {@link InSpanGenerator}. * Must not be {@code null}. * @param finder The {@link TokenNameFinder} used to detect the names. * Must not be {@code null}. */ public InSpanGenerator(String prefix, TokenNameFinder finder) { this.prefix = Objects.requireNonNull(prefix, "prefix must not be null"); this.finder = Objects.requireNonNull(finder, "finder must not be null"); } @Override public void createFeatures(List features, String[] tokens, int index, String[] preds) { // cache results for sentence if (currentSentence != tokens) { currentSentence = tokens; currentNames = finder.find(tokens); } // iterate over names and check if a span is contained for (Span currentName : currentNames) { if (currentName.contains(index)) { // found a span for the current token features.add(prefix + W_DIC); features.add(prefix + W_DIC_IS + tokens[index]); // TODO: consider generation start and continuation features break; } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000177 15217274217 032567 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/OutcomePriorFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/OutcomePriorFeat0100644 0000000 0000000 00000002452 15217274217 034166 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * The definition feature maps the underlying distribution of outcomes. * * @see AdaptiveFeatureGenerator */ public class OutcomePriorFeatureGenerator implements AdaptiveFeatureGenerator { private static final String OUTCOME_PRIOR_FEATURE = "def"; @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { features.add(OUTCOME_PRIOR_FEATURE); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000200 15217274217 032552 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/POSTaggerNameFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/POSTaggerNameFea0100644 0000000 0000000 00000004431 15217274217 033746 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.Arrays; import java.util.List; import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSTagFormatMapper; import opennlp.tools.postag.POSTagger; import opennlp.tools.postag.POSTaggerME; /** * Adds the token POS tag as feature. Requires a {@link POSTagger} at runtime. * * @see AdaptiveFeatureGenerator * @see POSTagger * @see POSModel */ public class POSTaggerNameFeatureGenerator implements AdaptiveFeatureGenerator { private final POSTagger posTagger; private String[] cachedTokens; private String[] cachedTags; /** * Initializes a {@link POSTaggerNameFeatureGenerator} with the specified {@link POSTagger}. * * @param aPosTagger A POSTagger instance to be used. */ public POSTaggerNameFeatureGenerator(POSTagger aPosTagger) { this.posTagger = aPosTagger; } /** * Initializes a {@link POSTaggerNameFeatureGenerator} with the specified {@link POSModel}. * * @param aPosModel A {@link POSModel} to be used for the internal {@link POSTagger}. */ public POSTaggerNameFeatureGenerator(POSModel aPosModel) { this.posTagger = new POSTaggerME(aPosModel, POSTagFormatMapper.guessFormat(aPosModel)); } @Override public void createFeatures(List feats, String[] toks, int index, String[] preds) { if (!Arrays.equals(this.cachedTokens, toks)) { this.cachedTokens = toks; this.cachedTags = this.posTagger.tag(toks); } feats.add("pos=" + this.cachedTags[index]); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000207 15217274217 032561 xustar000000000 0000000 135 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/POSTaggerNameFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/POSTaggerNameFea0100644 0000000 0000000 00000004072 15217274217 033747 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.HashMap; import java.util.Map; import opennlp.tools.postag.POSModel; import opennlp.tools.util.InvalidFormatException; import opennlp.tools.util.model.ArtifactSerializer; import opennlp.tools.util.model.POSModelSerializer; /** * A {@link GeneratorFactory} that produces {@link POSTaggerNameFeatureGenerator} instances * when {@link #create()} is called. * * @see POSTaggerNameFeatureGenerator */ public class POSTaggerNameFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public POSTaggerNameFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { // if resourceManager is null, we don't instantiate if (resourceManager == null) { return null; } String modelResourceKey = getStr("model"); POSModel model = (POSModel) resourceManager.getResource(modelResourceKey); return new POSTaggerNameFeatureGenerator(model); } @Override public Map> getArtifactSerializerMapping() throws InvalidFormatException { Map> mapping = new HashMap<>(); mapping.put(getStr("model"), new POSModelSerializer()); return mapping; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000174 15217274217 032564 xustar000000000 0000000 124 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PosTaggerFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PosTaggerFeature0100644 0000000 0000000 00000003670 15217274217 034151 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * A POS tagging driven feature generator. Adds words and pos tags of the surrounding context. * * @see AdaptiveFeatureGenerator */ public class PosTaggerFeatureGenerator implements AdaptiveFeatureGenerator { private static final String SB = "S=begin"; @Override public void createFeatures(List features, String[] tokens, int index, String[] tags) { String prev, prevprev = null; String tagprev, tagprevprev; tagprev = tagprevprev = null; if (index - 1 >= 0) { prev = tokens[index - 1]; tagprev = tags[index - 1]; if (index - 2 >= 0) { prevprev = tokens[index - 2]; tagprevprev = tags[index - 2]; } else { prevprev = SB; } } else { prev = SB; } // add the words and pos's of the surrounding context if (prev != null) { if (tagprev != null) { features.add("t=" + tagprev); } if (prevprev != null) { if (tagprevprev != null) { features.add("t2=" + tagprevprev + "," + tagprev); } } } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000203 15217274217 032555 xustar000000000 0000000 131 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PosTaggerFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PosTaggerFeature0100644 0000000 0000000 00000002541 15217274217 034145 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link PosTaggerFeatureGenerator} instances * when {@link #create()} is called. * * @see PosTaggerFeatureGenerator */ public class PosTaggerFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public PosTaggerFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new PosTaggerFeatureGenerator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000171 15217274217 032561 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PrefixFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PrefixFeatureGen0100644 0000000 0000000 00000004436 15217274217 034146 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * A feature generator implementation that generates prefix-based features. * * @see AdaptiveFeatureGenerator */ public class PrefixFeatureGenerator implements AdaptiveFeatureGenerator { private static final String PREFIX = "pre="; /** * The default upper boundary prefix length value is {@code 4}. */ static final int DEFAULT_MAX_LENGTH = 4; private final int prefixLength; /** * Intializes a default {@link PrefixFeatureGenerator}. * The prefixLength length is set to the value of {@link #DEFAULT_MAX_LENGTH}. */ public PrefixFeatureGenerator() { prefixLength = DEFAULT_MAX_LENGTH; } /** * Intializes a {@link PrefixFeatureGenerator} with the specified {@code prefixLength}. * * @param prefixLength The upper boundary prefix length to use. */ public PrefixFeatureGenerator(int prefixLength) { this.prefixLength = prefixLength; } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { String[] prefs = getPrefixes(tokens[index]); for (String pref : prefs) { features.add(PREFIX + pref); } } private String[] getPrefixes(String lex) { int prefixes = StrictMath.min(prefixLength, lex.length()); String[] prefs = new String[prefixes]; for (int li = 0; li < prefixes; li++) { prefs[li] = lex.substring(0, StrictMath.min(li + 1, lex.length())); } return prefs; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000200 15217274217 032552 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PrefixFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PrefixFeatureGen0100644 0000000 0000000 00000002625 15217274217 034144 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link PrefixFeatureGenerator} instances * when {@link #create()} is called. * * @see PrefixFeatureGenerator */ public class PrefixFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public PrefixFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new PrefixFeatureGenerator(getInt("length", PrefixFeatureGenerator.DEFAULT_MAX_LENGTH)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000176 15217274217 032566 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PreviousMapFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PreviousMapFeatu0100644 0000000 0000000 00000003576 15217274217 034206 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This {@link AdaptiveFeatureGenerator} generates features indicating the * outcome associated with a previously occurring word. */ public class PreviousMapFeatureGenerator implements AdaptiveFeatureGenerator { private final Map previousMap = new HashMap<>(); @Override public void createFeatures(List features, String[] tokens, int index, String[] preds) { features.add("pd=" + previousMap.get(tokens[index])); } /** * Generates previous decision features for the token based on contents of the previous map. * * @param tokens The tokens of the sentence or other text unit which has been processed. * @param outcomes The outcomes associated with the specified tokens. */ @Override public void updateAdaptiveData(String[] tokens, String[] outcomes) { for (int i = 0; i < tokens.length; i++) { previousMap.put(tokens[i], outcomes[i]); } } @Override public void clearAdaptiveData() { previousMap.clear(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000205 15217274217 032557 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PreviousMapFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PreviousMapFeatu0100644 0000000 0000000 00000002553 15217274217 034200 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link PreviousMapFeatureGenerator} instances * when {@link #create()} is called. * * @see PreviousMapFeatureGenerator */ public class PreviousMapFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public PreviousMapFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new PreviousMapFeatureGenerator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000201 15217274217 032553 xustar000000000 0000000 129 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PreviousTwoMapFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/PreviousTwoMapFe0100644 0000000 0000000 00000003522 15217274217 034155 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This {@link AdaptiveFeatureGenerator} generates features indicating the * outcome associated with two previously occurring words. * * @see AdaptiveFeatureGenerator */ public class PreviousTwoMapFeatureGenerator implements AdaptiveFeatureGenerator { private final Map previousMap = new HashMap<>(); /** * Generates previous decision features for the token based on contents of the previous map. */ @Override public void createFeatures(List features, String[] tokens, int index, String[] preds) { if (index > 0) { features.add("ppd=" + previousMap.get(tokens[index]) + "," + previousMap.get(tokens[index - 1])); } } @Override public void updateAdaptiveData(String[] tokens, String[] outcomes) { for (int i = 0; i < tokens.length; i++) { previousMap.put(tokens[i], outcomes[i]); } } @Override public void clearAdaptiveData() { previousMap.clear(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000173 15217274217 032563 xustar000000000 0000000 123 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SentenceFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SentenceFeatureG0100644 0000000 0000000 00000003305 15217274217 034124 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * This feature generator creates sentence begin and end features. * * @see AdaptiveFeatureGenerator */ public class SentenceFeatureGenerator implements AdaptiveFeatureGenerator { private final boolean isGenerateFirstWordFeature; private final boolean isGenerateLastWordFeature; public SentenceFeatureGenerator(boolean isGenerateFirstWordFeature, boolean isGenerateLastWordFeature) { this.isGenerateFirstWordFeature = isGenerateFirstWordFeature; this.isGenerateLastWordFeature = isGenerateLastWordFeature; } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { if (isGenerateFirstWordFeature && index == 0) { features.add("S=begin"); } if (isGenerateLastWordFeature && tokens.length == index + 1) { features.add("S=end"); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000202 15217274217 032554 xustar000000000 0000000 130 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SentenceFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SentenceFeatureG0100644 0000000 0000000 00000002610 15217274217 034122 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link SentenceFeatureGenerator} instances * when {@link #create()} is called. * * @see SentenceFeatureGenerator */ public class SentenceFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public SentenceFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new SentenceFeatureGenerator(getBool("begin", true), getBool("end", true)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000160 15217274217 032557 xustar000000000 0000000 112 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/StringPattern.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/StringPattern.ja0100644 0000000 0000000 00000015042 15217274217 034133 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; /** * Recognizes predefined patterns in strings. */ public class StringPattern { private static final int INITAL_CAPITAL_LETTER = 0x1; private static final int ALL_CAPITAL_LETTER = 0x1 << 1; private static final int ALL_LOWERCASE_LETTER = 0x1 << 2; private static final int ALL_LETTERS = 0x1 << 3; private static final int ALL_DIGIT = 0x1 << 4; private static final int ALL_HIRAGANA = 0x1 << 5; private static final int ALL_KATAKANA = 0x1 << 6; private static final int CONTAINS_PERIOD = 0x1 << 7; private static final int CONTAINS_COMMA = 0x1 << 8; private static final int CONTAINS_SLASH = 0x1 << 9; private static final int CONTAINS_DIGIT = 0x1 << 10; private static final int CONTAINS_HYPHEN = 0x1 << 11; private static final int CONTAINS_LETTERS = 0x1 << 12; private static final int CONTAINS_UPPERCASE = 0x1 << 13; private final int pattern; private final int digits; private StringPattern(int pattern, int digits) { this.pattern = pattern; this.digits = digits; } public static StringPattern recognize(String token) { int pattern = ALL_CAPITAL_LETTER | ALL_LOWERCASE_LETTER | ALL_DIGIT | ALL_LETTERS | ALL_HIRAGANA | ALL_KATAKANA; int digits = 0; for (int i = 0; i < token.length(); i++) { final char ch = token.charAt(i); final int letterType = Character.getType(ch); boolean isLetter = letterType == Character.UPPERCASE_LETTER || letterType == Character.LOWERCASE_LETTER || letterType == Character.TITLECASE_LETTER || letterType == Character.MODIFIER_LETTER || letterType == Character.OTHER_LETTER; if (isLetter) { pattern |= CONTAINS_LETTERS; pattern &= ~ALL_DIGIT; if (letterType == Character.UPPERCASE_LETTER) { if (i == 0) { pattern |= INITAL_CAPITAL_LETTER; } pattern |= CONTAINS_UPPERCASE; pattern &= ~ALL_LOWERCASE_LETTER; } else { pattern &= ~ALL_CAPITAL_LETTER; } } else { // contains chars other than letter, this means // it can not be one of these: pattern &= ~ALL_LETTERS; pattern &= ~ALL_CAPITAL_LETTER; pattern &= ~ALL_LOWERCASE_LETTER; if (letterType == Character.DECIMAL_DIGIT_NUMBER) { pattern |= CONTAINS_DIGIT; pattern &= ~(ALL_HIRAGANA | ALL_KATAKANA); digits++; } else { pattern &= ~ALL_DIGIT; } switch (ch) { case ',': pattern |= CONTAINS_COMMA; break; case '.': pattern |= CONTAINS_PERIOD; break; case '/': pattern |= CONTAINS_SLASH; break; case '-': pattern |= CONTAINS_HYPHEN; break; default: break; } } // for Japanese... final int codePoint = token.codePointAt(i); final Character.UnicodeScript us = Character.UnicodeScript.of(codePoint); if (us != Character.UnicodeScript.COMMON) { if (us == Character.UnicodeScript.LATIN) { pattern &= ~(ALL_HIRAGANA | ALL_KATAKANA); } else if (us == Character.UnicodeScript.HAN) { pattern &= ~(ALL_HIRAGANA | ALL_KATAKANA | ALL_LOWERCASE_LETTER); } else if (us == Character.UnicodeScript.HIRAGANA) { pattern &= ~(ALL_KATAKANA | ALL_LOWERCASE_LETTER); } else if (us == Character.UnicodeScript.KATAKANA) { pattern &= ~(ALL_HIRAGANA | ALL_LOWERCASE_LETTER); } } else { if (ch != '・' && ch != 'ー' && ch != '〜') pattern &= ~(ALL_HIRAGANA | ALL_KATAKANA); } } return new StringPattern(pattern, digits); } /** * @return {@code true} if all characters are letters. */ public boolean isAllLetter() { return (pattern & ALL_LETTERS) > 0; } /** * @return {@code true} if first letter is capital. */ public boolean isInitialCapitalLetter() { return (pattern & INITAL_CAPITAL_LETTER) > 0; } /** * @return {@code true} if all letters are capital. */ public boolean isAllCapitalLetter() { return (pattern & ALL_CAPITAL_LETTER) > 0; } /** * @return {@code true} if all letters are lower case. */ public boolean isAllLowerCaseLetter() { return (pattern & ALL_LOWERCASE_LETTER) > 0; } /** * @return {@code true} if all chars are digits. */ public boolean isAllDigit() { return (pattern & ALL_DIGIT) > 0; } /** * @return {@code true} if all chars are hiragana. */ public boolean isAllHiragana() { return (pattern & ALL_HIRAGANA) > 0; } /** * @return {@code true} if all chars are katakana. */ public boolean isAllKatakana() { return (pattern & ALL_KATAKANA) > 0; } /** * Retrieves the number of digits. */ public int digits() { return digits; } /** * @return {@code true} if a period is contained. */ public boolean containsPeriod() { return (pattern & CONTAINS_PERIOD) > 0; } /** * @return {@code true} if a comma is contained. */ public boolean containsComma() { return (pattern & CONTAINS_COMMA) > 0; } /** * @return {@code true} if a slash is contained. */ public boolean containsSlash() { return (pattern & CONTAINS_SLASH) > 0; } /** * @return {@code true} if a digit is contained. */ public boolean containsDigit() { return (pattern & CONTAINS_DIGIT) > 0; } /** * @return {@code true} if a hypen is contained. */ public boolean containsHyphen() { return (pattern & CONTAINS_HYPHEN) > 0; } /** * @return {@code true} if a letters are contained. */ public boolean containsLetters() { return (pattern & CONTAINS_LETTERS) > 0; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000171 15217274217 032561 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SuffixFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SuffixFeatureGen0100644 0000000 0000000 00000004430 15217274217 034147 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * A feature generator implementation that generates suffix-based features. * * @see AdaptiveFeatureGenerator */ public class SuffixFeatureGenerator implements AdaptiveFeatureGenerator { private static final String PREFIX = "suf="; /** * The default upper boundary suffix length value is {@code 4}. */ static final int DEFAULT_MAX_LENGTH = 4; private final int suffixLength; /** * Intializes a {@link SuffixFeatureGenerator}. * The suffix length is set to the value of {@link #DEFAULT_MAX_LENGTH}. */ public SuffixFeatureGenerator() { suffixLength = DEFAULT_MAX_LENGTH; } /** * Intializes a {@link SuffixFeatureGenerator} with the specified {@code suffixLength}. * * @param suffixLength The upper boundary suffix length to use. */ public SuffixFeatureGenerator(int suffixLength) { this.suffixLength = suffixLength; } @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { String[] suffs = getSuffixes(tokens[index]); for (String suff : suffs) { features.add(PREFIX + suff); } } private String[] getSuffixes(String lex) { int suffixes = StrictMath.min(suffixLength, lex.length()); String[] suffs = new String[suffixes]; for (int li = 0; li < suffixes; li++) { suffs[li] = lex.substring(StrictMath.max(lex.length() - li - 1, 0)); } return suffs; } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000200 15217274217 032552 xustar000000000 0000000 128 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SuffixFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/SuffixFeatureGen0100644 0000000 0000000 00000002625 15217274217 034153 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link SuffixFeatureGenerator} instances * when {@link #create()} is called. * * @see SuffixFeatureGenerator */ public class SuffixFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public SuffixFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new SuffixFeatureGenerator(getInt("length", SuffixFeatureGenerator.DEFAULT_MAX_LENGTH)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000175 15217274217 032565 xustar000000000 0000000 125 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenClassFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenClassFeatur0100644 0000000 0000000 00000004267 15217274217 034162 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; import opennlp.tools.util.StringUtil; /** * Generates features for the class of a token. * * @see AdaptiveFeatureGenerator */ public class TokenClassFeatureGenerator implements AdaptiveFeatureGenerator { private static final String TOKEN_CLASS_PREFIX = "wc="; private static final String TOKEN_AND_CLASS_PREFIX = "w&c="; private final boolean generateWordAndClassFeature; /** * Initalizes a {@link TokenClassFeatureGenerator} which won't generate * the {@code w&c} feature per token. */ public TokenClassFeatureGenerator() { this(false); } /** * Initalizes a {@link TokenClassFeatureGenerator}. * * @param generateWordAndClassFeature If {@code true} the {@code w&c} feature will be * generated per token, {@code false} otherwise. */ public TokenClassFeatureGenerator(boolean generateWordAndClassFeature) { this.generateWordAndClassFeature = generateWordAndClassFeature; } @Override public void createFeatures(List features, String[] tokens, int index, String[] preds) { String wordClass = FeatureGeneratorUtil.tokenFeature(tokens[index]); features.add(TOKEN_CLASS_PREFIX + wordClass); if (generateWordAndClassFeature) { features.add(TOKEN_AND_CLASS_PREFIX + StringUtil.toLowerCase(tokens[index]) + "," + wordClass); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000204 15217274217 032556 xustar000000000 0000000 132 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenClassFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenClassFeatur0100644 0000000 0000000 00000002603 15217274217 034152 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link TokenClassFeatureGenerator} instances * when {@link #create()} is called. * * @see TokenClassFeatureGenerator */ public class TokenClassFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public TokenClassFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new TokenClassFeatureGenerator(getBool("wordAndClass", true)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000170 15217274217 032560 xustar000000000 0000000 120 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenFeatureGene0100644 0000000 0000000 00000003420 15217274217 034126 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; import opennlp.tools.util.StringUtil; /** * Generates a feature which contains a token itself. * * @see AdaptiveFeatureGenerator */ public class TokenFeatureGenerator implements AdaptiveFeatureGenerator { private static final String WORD_PREFIX = "w="; private final boolean lowercase; /** * Initializes a {@link TokenFeatureGenerator}. * * @param lowercase Whether or not to use lower-casing. */ public TokenFeatureGenerator(boolean lowercase) { this.lowercase = lowercase; } /** * Initializes a {@link TokenFeatureGenerator}. Lower-casing will be enabled. */ public TokenFeatureGenerator() { this(true); } @Override public void createFeatures(List features, String[] tokens, int index, String[] preds) { if (lowercase) { features.add(WORD_PREFIX + StringUtil.toLowerCase(tokens[index])); } else { features.add(WORD_PREFIX + tokens[index]); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000177 15217274217 032567 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenFeatureGene0100644 0000000 0000000 00000002547 15217274217 034137 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link TokenFeatureGenerator} instances * when {@link #create()} is called. * * @see TokenFeatureGenerator */ public class TokenFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public TokenFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new TokenFeatureGenerator(getBool("lowercase", true)); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000177 15217274217 032567 xustar000000000 0000000 127 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenPatternFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenPatternFeat0100644 0000000 0000000 00000006264 15217274217 034162 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; import java.util.regex.Pattern; import opennlp.tools.tokenize.SimpleTokenizer; import opennlp.tools.tokenize.Tokenizer; import opennlp.tools.util.StringUtil; /** * Partitions tokens into sub-tokens based on character classes and generates * class features for each of the sub-tokens and combinations of those sub-tokens. * * @see AdaptiveFeatureGenerator * @see Tokenizer */ public class TokenPatternFeatureGenerator implements AdaptiveFeatureGenerator { private static final String SUB_TOKEN_PREFIX = "st=" ; private static final String SUB_TOKEN_PART2_PREFIX = "pt2=" ; private static final String SUB_TOKEN_PART3_PREFIX = "pt3=" ; private final Pattern noLetters = Pattern.compile("[^a-zA-Z]"); private final Tokenizer tokenizer; /** * Initializes a {@link TokenPatternFeatureGenerator}. * For tokenization the {@link SimpleTokenizer} is used. */ public TokenPatternFeatureGenerator() { this(SimpleTokenizer.INSTANCE); } /** * Initializes a {@link TokenPatternFeatureGenerator} instance. * * @param supportTokenizer The {@link Tokenizer} to be used. */ public TokenPatternFeatureGenerator(Tokenizer supportTokenizer) { tokenizer = supportTokenizer; } @Override public void createFeatures(List feats, String[] toks, int index, String[] preds) { String[] tokenized = tokenizer.tokenize(toks[index]); if (tokenized.length == 1) { feats.add(SUB_TOKEN_PREFIX + StringUtil.toLowerCase(toks[index])); return; } feats.add("stn=" + tokenized.length); StringBuilder pattern = new StringBuilder(); for (int i = 0; i < tokenized.length; i++) { if (i < tokenized.length - 1) { feats.add(SUB_TOKEN_PART2_PREFIX + FeatureGeneratorUtil.tokenFeature(tokenized[i]) + FeatureGeneratorUtil.tokenFeature(tokenized[i + 1])); } if (i < tokenized.length - 2) { feats.add(SUB_TOKEN_PART3_PREFIX + FeatureGeneratorUtil.tokenFeature(tokenized[i]) + FeatureGeneratorUtil.tokenFeature(tokenized[i + 1]) + FeatureGeneratorUtil.tokenFeature(tokenized[i + 2])); } pattern.append(FeatureGeneratorUtil.tokenFeature(tokenized[i])); if (!noLetters.matcher(tokenized[i]).find()) { feats.add(SUB_TOKEN_PREFIX + StringUtil.toLowerCase(tokenized[i])); } } feats.add("pta=" + pattern); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000206 15217274217 032560 xustar000000000 0000000 134 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenPatternFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TokenPatternFeat0100644 0000000 0000000 00000002557 15217274217 034163 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} instantiates {@link TokenPatternFeatureGenerator} instances * when {@link #create()} is called. * * @see TokenPatternFeatureGenerator */ public class TokenPatternFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public TokenPatternFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new TokenPatternFeatureGenerator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000176 15217274217 032566 xustar000000000 0000000 126 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TrigramNameFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TrigramNameFeatu0100644 0000000 0000000 00000003663 15217274217 034137 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.List; /** * Adds trigram features based on tokens and token classes. * * @see AdaptiveFeatureGenerator */ public class TrigramNameFeatureGenerator implements AdaptiveFeatureGenerator { @Override public void createFeatures(List features, String[] tokens, int index, String[] previousOutcomes) { String wc = FeatureGeneratorUtil.tokenFeature(tokens[index]); // trigram features if (index > 1) { features.add("ppw,pw,w=" + tokens[index - 2] + "," + tokens[index - 1] + "," + tokens[index]); String pwc = FeatureGeneratorUtil.tokenFeature(tokens[index - 1]); String ppwc = FeatureGeneratorUtil.tokenFeature(tokens[index - 2]); features.add("ppwc,pwc,wc=" + ppwc + "," + pwc + "," + wc); } if (index + 2 < tokens.length) { features.add("w,nw,nnw=" + tokens[index] + "," + tokens[index + 1] + "," + tokens[index + 2]); String nwc = FeatureGeneratorUtil.tokenFeature(tokens[index + 1]); String nnwc = FeatureGeneratorUtil.tokenFeature(tokens[index + 2]); features.add("wc,nwc,nnwc=" + wc + "," + nwc + "," + nnwc); } } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000205 15217274217 032557 xustar000000000 0000000 133 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TrigramNameFeatureGeneratorFactory.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/TrigramNameFeatu0100644 0000000 0000000 00000002553 15217274217 034134 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import opennlp.tools.util.InvalidFormatException; /** * A {@link GeneratorFactory} that produces {@link TrigramNameFeatureGenerator} instances * when {@link #create()} is called. * * @see TrigramNameFeatureGenerator */ public class TrigramNameFeatureGeneratorFactory extends GeneratorFactory.AbstractXmlFeatureGeneratorFactory { public TrigramNameFeatureGeneratorFactory() { super(); } @Override public AdaptiveFeatureGenerator create() throws InvalidFormatException { return new TrigramNameFeatureGenerator(); } } ./PaxHeaders.X/apache-opennlp-2.5.12-src_opennlp-tools_src_main_java_opennlp_tools_util_featuregen_0100644 0000000 0000000 00000000171 15217274217 032561 xustar000000000 0000000 121 path=apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/WindowFeatureGenerator.java apache-opennlp-2.5.12-src/opennlp-tools/src/main/java/opennlp/tools/util/featuregen/WindowFeatureGen0100644 0000000 0000000 00000011137 15217274217 034154 0ustar00rootroot0000000 0000000 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package opennlp.tools.util.featuregen; import java.util.ArrayList; import java.util.List; /** * Generates previous (left-sided) and next (right-sided) features for a * given {@link AdaptiveFeatureGenerator}. The window size can be specified. *


* Features: *