diff options
| author | fukachan <fukachan> | 2001-01-29 12:56:54 +0000 |
|---|---|---|
| committer | fukachan <fukachan> | 2001-01-29 12:56:54 +0000 |
| commit | d99a1f1566eacd86249355db2012e8028f5a060c (patch) | |
| tree | e97bcbef4be330bc6509ceedf7cd1a943547ab06 /cpan/dist | |
| parent | 1b3a879cf3fc9dee8d23fe452060953c3ff8adf6 (diff) | |
| download | fml8-d99a1f1566eacd86249355db2012e8028f5a060c.tar.gz fml8-d99a1f1566eacd86249355db2012e8028f5a060c.tar.bz2 fml8-d99a1f1566eacd86249355db2012e8028f5a060c.zip | |
Initial revision
Diffstat (limited to 'cpan/dist')
| -rw-r--r-- | cpan/dist/Crypt-RandPasswd/Changes | 8 | ||||
| -rw-r--r-- | cpan/dist/Crypt-RandPasswd/MANIFEST | 6 | ||||
| -rw-r--r-- | cpan/dist/Crypt-RandPasswd/Makefile.PL | 7 | ||||
| -rw-r--r-- | cpan/dist/Crypt-RandPasswd/README | 27 | ||||
| -rw-r--r-- | cpan/dist/Crypt-RandPasswd/lib/Crypt/RandPasswd.pm | 2526 | ||||
| -rw-r--r-- | cpan/dist/Crypt-RandPasswd/test.pl | 35 |
6 files changed, 2609 insertions, 0 deletions
diff --git a/cpan/dist/Crypt-RandPasswd/Changes b/cpan/dist/Crypt-RandPasswd/Changes new file mode 100644 index 00000000..bb6c7c43 --- /dev/null +++ b/cpan/dist/Crypt-RandPasswd/Changes @@ -0,0 +1,8 @@ +Revision history for Perl extension Crypt::RandPasswd. + +0.02 Fri Jul 21 14:19:43 EDT 2000 + - Added README file. + +0.01 Thu Jul 20 17:18:45 EDT 2000 + - original version; created by h2xs 1.19 + diff --git a/cpan/dist/Crypt-RandPasswd/MANIFEST b/cpan/dist/Crypt-RandPasswd/MANIFEST new file mode 100644 index 00000000..a3ea82a1 --- /dev/null +++ b/cpan/dist/Crypt-RandPasswd/MANIFEST @@ -0,0 +1,6 @@ +Changes +MANIFEST +Makefile.PL +README +lib/Crypt/RandPasswd.pm +test.pl diff --git a/cpan/dist/Crypt-RandPasswd/Makefile.PL b/cpan/dist/Crypt-RandPasswd/Makefile.PL new file mode 100644 index 00000000..62003ab5 --- /dev/null +++ b/cpan/dist/Crypt-RandPasswd/Makefile.PL @@ -0,0 +1,7 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Crypt::RandPasswd', + 'VERSION_FROM' => 'lib/Crypt/RandPasswd.pm', # finds $VERSION +); diff --git a/cpan/dist/Crypt-RandPasswd/README b/cpan/dist/Crypt-RandPasswd/README new file mode 100644 index 00000000..0a788544 --- /dev/null +++ b/cpan/dist/Crypt-RandPasswd/README @@ -0,0 +1,27 @@ + +Crypt::RandPasswd - random password generator based on FIPS-181 + +By John Porter (JDPORTER@cpan.org) + +This is an implementation of the Automated Password Generator standard, +defined in FIPS Publication 181, "Standard for Automated Password Generator": +http://www.itl.nist.gov/fipspubs/fip181.htm + + use Crypt::RandPasswd; + ( $word, $hyphenated ) = Crypt::RandPasswd::word( $minlen, $maxlen ); + $word = Crypt::RandPasswd::word( $minlen, $maxlen ); + $word = Crypt::RandPasswd::letters( $minlen, $maxlen ); + $word = Crypt::RandPasswd::chars( $minlen, $maxlen ); + + # override the defaults for these functions: + *Crypt::RandPasswd::rng = \&my_random_number_generator; + *Crypt::RandPasswd::restrict = \&my_restriction_filter; + +The module file can also be run directly as a script: + +# To print the usage statement: +% perl Crypt/RandPasswd.pm -help + +# To print out one password using the default parameter values: +% perl Crypt/RandPasswd.pm + diff --git a/cpan/dist/Crypt-RandPasswd/lib/Crypt/RandPasswd.pm b/cpan/dist/Crypt-RandPasswd/lib/Crypt/RandPasswd.pm new file mode 100644 index 00000000..69ebf99a --- /dev/null +++ b/cpan/dist/Crypt-RandPasswd/lib/Crypt/RandPasswd.pm @@ -0,0 +1,2526 @@ + +{ + +package Crypt::RandPasswd; + +use strict; + +use vars qw($VERSION); + +$VERSION = '0.02'; + + +=head1 NAME + +Crypt::RandPasswd - random password generator based on FIPS-181 + +=head1 SYNOPSIS + + use Crypt::RandPasswd; + ( $word, $hyphenated ) = Crypt::RandPasswd->word( $minlen, $maxlen ); + $word = Crypt::RandPasswd->word( $minlen, $maxlen ); + $word = Crypt::RandPasswd->letters( $minlen, $maxlen ); + $word = Crypt::RandPasswd->chars( $minlen, $maxlen ); + + # override the defaults for these functions: + *Crypt::RandPasswd::rng = \&my_random_number_generator; + *Crypt::RandPasswd::restrict = \&my_restriction_filter; + +=head2 Run as Script + + perl Crypt/RandPasswd.pm -help + +=head1 SEE ALSO + +FIPS 181 - (APG), Automated Password Generator: +http://www.itl.nist.gov/fipspubs/fip181.htm + +=head1 DESCRIPTION + +This code is a Perl language implementation of the Automated +Password Generator standard, like the program described in +"A Random Word Generator For Pronounceable Passwords" (not available on-line). +This code is a re-engineering of the program contained in Appendix A +of FIPS Publication 181, "Standard for Automated Password Generator". +In accordance with the standard, the results obtained from this +program are logically equivalent to those produced by the standard. + +=head1 CAVEATS + +=head2 Bugs + +The function to generate a password can sometimes take an extremely long time. + +=head2 Deviations From Standard + +This implementation deviates in one critical way from the standard +upon which it is based: the random number generator in this +implementation does not use DES. Instead, it uses perl's built-in +C<rand()> function, which in turn is (usually) built on the +pseudo-random number generator functions of the underlying C library. + +However, the random function can be replaced by the user if desired. +(See L</rng>.) + +=head1 Functions + +=cut + + +sub word($$); +sub letters($$); +sub chars($$); + +sub random_chars_in_range($$$$); +sub rand_int_in_range($$); +sub random_element($); + +sub rng($); +sub restrict($); +sub init(); + + +sub _random_word($); +sub _random_unit($); +sub _improper_word(@); +sub _have_initial_y(@); +sub _have_final_split(@); +sub _illegal_placement(@); + + +# +# Global Variables: +# + +$Crypt::RandPasswd::seed = undef; # by default; causes srand() to use its own, which can be pretty good. +$Crypt::RandPasswd::initialized = 0; + + + +my @grams = qw( a b c d e f g h i j k l m n o p r s t u v w x y z ch gh ph rh sh th wh qu ck ); +my %grams; @grams{@grams} = (); # and a set of same. + +my @vowel_grams = qw( a e i o u y ); +my %vowel_grams; @vowel_grams{@vowel_grams} = (); # and a set of same. + + + +# +# Bit flags +# + +use constant MAX_UNACCEPTABLE => 20 ; + +# gram rules: +use constant NOT_BEGIN_SYLLABLE => 010 ; +use constant NO_FINAL_SPLIT => 004 ; +use constant VOWEL => 002 ; +use constant ALTERNATE_VOWEL => 001 ; +use constant NO_SPECIAL_RULE => 000 ; + +# digram rules: +use constant FRONT => 0200 ; +use constant NOT_FRONT => 0100 ; +use constant BREAK => 0040 ; +use constant PREFIX => 0020 ; +use constant ILLEGAL_PAIR => 0010 ; +use constant SUFFIX => 0004 ; +use constant BACK => 0002 ; +use constant NOT_BACK => 0001 ; +use constant ANY_COMBINATION => 0000 ; + +## it used to be that info about units was contained in the C-arrays 'rules' and 'digram'. +## both were indexed numerically. 'rules' was essentially a mapping from a unique +## integer ID (the index) to a gram. 'digram' used the same mapping, but in a +## two-dimensional array. I.e. to represent the digram "ab" ("a","b"), one would +## need to know the numeric ID of "a" and "b", which turn out to be 0 and 1, respectively; +## then use those indices in digram: digram[0][1]. +## The information at the "end" of a lookup in digram[][] was a simple integer +## representing the flag bits for that digram. (The %digram in the current +## implementation is the same.) The rules[] C-array, however, needed to store +## both the bitmask and the string representation of the gram, so it was an array +## of a struct { string, bitmask }. Since %rules is an associative array, indexed +## directly by the gram, it only needs the bitmask at its "end", the same as %digram. +## +## both 'rules' and 'digram' contained bitflags for grams and digrams, respectively. +## additionally, 'rules' contained the string representation of the unit. +## because 'rules' contained both a string and flags for each unit, its contents +## were actually structs of { string, flags }. +## +## 'digram', on the other hand, was simply the bitflags (integers). + +# struct unit { +# char unit_code[5]; # string, usually 1, but up to 4 characters. +# byte flags; +# } rules[34]; + +## the 'rules' C-array used to be indexed by gram index; now %rules is indexed by the gram itself. + +my %rules; + +@rules{ @grams } = ( NO_SPECIAL_RULE ) x @grams; +@rules{ @vowel_grams } = ( VOWEL ) x @vowel_grams; + +$rules{'e'} |= NO_FINAL_SPLIT; +$rules{'y'} |= ALTERNATE_VOWEL; + +$rules{'x'} = +$rules{'ck'} = NOT_BEGIN_SYLLABLE; + + + +# +# the 'digram' C-array, digram[34][34], was indexed by the unit indexes of the two grams; +# now %digram is indexed directly by the two grams. +# +my %digram; + + ############################################################################################## + # BEGIN DIGRAM { + ############################################################################################## + + $digram{'a'}{'a'} = ILLEGAL_PAIR; + $digram{'a'}{'b'} = ANY_COMBINATION; + $digram{'a'}{'c'} = ANY_COMBINATION; + $digram{'a'}{'d'} = ANY_COMBINATION; + $digram{'a'}{'e'} = ILLEGAL_PAIR; + $digram{'a'}{'f'} = ANY_COMBINATION; + $digram{'a'}{'g'} = ANY_COMBINATION; + $digram{'a'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'a'}{'i'} = ANY_COMBINATION; + $digram{'a'}{'j'} = ANY_COMBINATION; + $digram{'a'}{'k'} = ANY_COMBINATION; + $digram{'a'}{'l'} = ANY_COMBINATION; + $digram{'a'}{'m'} = ANY_COMBINATION; + $digram{'a'}{'n'} = ANY_COMBINATION; + $digram{'a'}{'o'} = ILLEGAL_PAIR; + $digram{'a'}{'p'} = ANY_COMBINATION; + $digram{'a'}{'r'} = ANY_COMBINATION; + $digram{'a'}{'s'} = ANY_COMBINATION; + $digram{'a'}{'t'} = ANY_COMBINATION; + $digram{'a'}{'u'} = ANY_COMBINATION; + $digram{'a'}{'v'} = ANY_COMBINATION; + $digram{'a'}{'w'} = ANY_COMBINATION; + $digram{'a'}{'x'} = ANY_COMBINATION; + $digram{'a'}{'y'} = ANY_COMBINATION; + $digram{'a'}{'z'} = ANY_COMBINATION; + $digram{'a'}{'ch'} = ANY_COMBINATION; + $digram{'a'}{'gh'} = ILLEGAL_PAIR; + $digram{'a'}{'ph'} = ANY_COMBINATION; + $digram{'a'}{'rh'} = ILLEGAL_PAIR; + $digram{'a'}{'sh'} = ANY_COMBINATION; + $digram{'a'}{'th'} = ANY_COMBINATION; + $digram{'a'}{'wh'} = ILLEGAL_PAIR; + $digram{'a'}{'qu'} = BREAK | NOT_BACK; + $digram{'a'}{'ck'} = ANY_COMBINATION; + + $digram{'b'}{'a'} = ANY_COMBINATION; + $digram{'b'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'e'} = ANY_COMBINATION; + $digram{'b'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'i'} = ANY_COMBINATION; + $digram{'b'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'l'} = FRONT | SUFFIX | NOT_BACK; + $digram{'b'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'o'} = ANY_COMBINATION; + $digram{'b'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'r'} = FRONT | BACK; + $digram{'b'}{'s'} = NOT_FRONT; + $digram{'b'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'u'} = ANY_COMBINATION; + $digram{'b'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'x'} = ILLEGAL_PAIR; + $digram{'b'}{'y'} = ANY_COMBINATION; + $digram{'b'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'gh'} = ILLEGAL_PAIR; + $digram{'b'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'rh'} = ILLEGAL_PAIR; + $digram{'b'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'wh'} = ILLEGAL_PAIR; + $digram{'b'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'b'}{'ck'} = ILLEGAL_PAIR; + + $digram{'c'}{'a'} = ANY_COMBINATION; + $digram{'c'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'e'} = ANY_COMBINATION; + $digram{'c'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'i'} = ANY_COMBINATION; + $digram{'c'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'l'} = SUFFIX | NOT_BACK; + $digram{'c'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'o'} = ANY_COMBINATION; + $digram{'c'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'r'} = NOT_BACK; + $digram{'c'}{'s'} = NOT_FRONT | BACK; + $digram{'c'}{'t'} = NOT_FRONT | PREFIX; + $digram{'c'}{'u'} = ANY_COMBINATION; + $digram{'c'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'x'} = ILLEGAL_PAIR; + $digram{'c'}{'y'} = ANY_COMBINATION; + $digram{'c'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'ch'} = ILLEGAL_PAIR; + $digram{'c'}{'gh'} = ILLEGAL_PAIR; + $digram{'c'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'rh'} = ILLEGAL_PAIR; + $digram{'c'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'c'}{'wh'} = ILLEGAL_PAIR; + $digram{'c'}{'qu'} = NOT_FRONT | SUFFIX | NOT_BACK; + $digram{'c'}{'ck'} = ILLEGAL_PAIR; + + $digram{'d'}{'a'} = ANY_COMBINATION; + $digram{'d'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'d'} = NOT_FRONT; + $digram{'d'}{'e'} = ANY_COMBINATION; + $digram{'d'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'i'} = ANY_COMBINATION; + $digram{'d'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'o'} = ANY_COMBINATION; + $digram{'d'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'r'} = FRONT | NOT_BACK; + $digram{'d'}{'s'} = NOT_FRONT | BACK; + $digram{'d'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'u'} = ANY_COMBINATION; + $digram{'d'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'x'} = ILLEGAL_PAIR; + $digram{'d'}{'y'} = ANY_COMBINATION; + $digram{'d'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'rh'} = ILLEGAL_PAIR; + $digram{'d'}{'sh'} = NOT_FRONT | NOT_BACK; + $digram{'d'}{'th'} = NOT_FRONT | PREFIX; + $digram{'d'}{'wh'} = ILLEGAL_PAIR; + $digram{'d'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'d'}{'ck'} = ILLEGAL_PAIR; + + $digram{'e'}{'a'} = ANY_COMBINATION; + $digram{'e'}{'b'} = ANY_COMBINATION; + $digram{'e'}{'c'} = ANY_COMBINATION; + $digram{'e'}{'d'} = ANY_COMBINATION; + $digram{'e'}{'e'} = ANY_COMBINATION; + $digram{'e'}{'f'} = ANY_COMBINATION; + $digram{'e'}{'g'} = ANY_COMBINATION; + $digram{'e'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'e'}{'i'} = NOT_BACK; + $digram{'e'}{'j'} = ANY_COMBINATION; + $digram{'e'}{'k'} = ANY_COMBINATION; + $digram{'e'}{'l'} = ANY_COMBINATION; + $digram{'e'}{'m'} = ANY_COMBINATION; + $digram{'e'}{'n'} = ANY_COMBINATION; + $digram{'e'}{'o'} = BREAK; + $digram{'e'}{'p'} = ANY_COMBINATION; + $digram{'e'}{'r'} = ANY_COMBINATION; + $digram{'e'}{'s'} = ANY_COMBINATION; + $digram{'e'}{'t'} = ANY_COMBINATION; + $digram{'e'}{'u'} = ANY_COMBINATION; + $digram{'e'}{'v'} = ANY_COMBINATION; + $digram{'e'}{'w'} = ANY_COMBINATION; + $digram{'e'}{'x'} = ANY_COMBINATION; + $digram{'e'}{'y'} = ANY_COMBINATION; + $digram{'e'}{'z'} = ANY_COMBINATION; + $digram{'e'}{'ch'} = ANY_COMBINATION; + $digram{'e'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'e'}{'ph'} = ANY_COMBINATION; + $digram{'e'}{'rh'} = ILLEGAL_PAIR; + $digram{'e'}{'sh'} = ANY_COMBINATION; + $digram{'e'}{'th'} = ANY_COMBINATION; + $digram{'e'}{'wh'} = ILLEGAL_PAIR; + $digram{'e'}{'qu'} = BREAK | NOT_BACK; + $digram{'e'}{'ck'} = ANY_COMBINATION; + + $digram{'f'}{'a'} = ANY_COMBINATION; + $digram{'f'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'e'} = ANY_COMBINATION; + $digram{'f'}{'f'} = NOT_FRONT; + $digram{'f'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'i'} = ANY_COMBINATION; + $digram{'f'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'l'} = FRONT | SUFFIX | NOT_BACK; + $digram{'f'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'o'} = ANY_COMBINATION; + $digram{'f'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'r'} = FRONT | NOT_BACK; + $digram{'f'}{'s'} = NOT_FRONT; + $digram{'f'}{'t'} = NOT_FRONT; + $digram{'f'}{'u'} = ANY_COMBINATION; + $digram{'f'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'x'} = ILLEGAL_PAIR; + $digram{'f'}{'y'} = NOT_FRONT; + $digram{'f'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'rh'} = ILLEGAL_PAIR; + $digram{'f'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'wh'} = ILLEGAL_PAIR; + $digram{'f'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'f'}{'ck'} = ILLEGAL_PAIR; + + $digram{'g'}{'a'} = ANY_COMBINATION; + $digram{'g'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'e'} = ANY_COMBINATION; + $digram{'g'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'g'} = NOT_FRONT; + $digram{'g'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'i'} = ANY_COMBINATION; + $digram{'g'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'k'} = ILLEGAL_PAIR; + $digram{'g'}{'l'} = FRONT | SUFFIX | NOT_BACK; + $digram{'g'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'o'} = ANY_COMBINATION; + $digram{'g'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'r'} = FRONT | NOT_BACK; + $digram{'g'}{'s'} = NOT_FRONT | BACK; + $digram{'g'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'u'} = ANY_COMBINATION; + $digram{'g'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'x'} = ILLEGAL_PAIR; + $digram{'g'}{'y'} = NOT_FRONT; + $digram{'g'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'gh'} = ILLEGAL_PAIR; + $digram{'g'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'rh'} = ILLEGAL_PAIR; + $digram{'g'}{'sh'} = NOT_FRONT; + $digram{'g'}{'th'} = NOT_FRONT; + $digram{'g'}{'wh'} = ILLEGAL_PAIR; + $digram{'g'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'g'}{'ck'} = ILLEGAL_PAIR; + + $digram{'h'}{'a'} = ANY_COMBINATION; + $digram{'h'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'e'} = ANY_COMBINATION; + $digram{'h'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'h'} = ILLEGAL_PAIR; + $digram{'h'}{'i'} = ANY_COMBINATION; + $digram{'h'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'o'} = ANY_COMBINATION; + $digram{'h'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'s'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'u'} = ANY_COMBINATION; + $digram{'h'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'x'} = ILLEGAL_PAIR; + $digram{'h'}{'y'} = ANY_COMBINATION; + $digram{'h'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'rh'} = ILLEGAL_PAIR; + $digram{'h'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'wh'} = ILLEGAL_PAIR; + $digram{'h'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'h'}{'ck'} = ILLEGAL_PAIR; + + $digram{'i'}{'a'} = ANY_COMBINATION; + $digram{'i'}{'b'} = ANY_COMBINATION; + $digram{'i'}{'c'} = ANY_COMBINATION; + $digram{'i'}{'d'} = ANY_COMBINATION; + $digram{'i'}{'e'} = NOT_FRONT; + $digram{'i'}{'f'} = ANY_COMBINATION; + $digram{'i'}{'g'} = ANY_COMBINATION; + $digram{'i'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'i'}{'i'} = ILLEGAL_PAIR; + $digram{'i'}{'j'} = ANY_COMBINATION; + $digram{'i'}{'k'} = ANY_COMBINATION; + $digram{'i'}{'l'} = ANY_COMBINATION; + $digram{'i'}{'m'} = ANY_COMBINATION; + $digram{'i'}{'n'} = ANY_COMBINATION; + $digram{'i'}{'o'} = BREAK; + $digram{'i'}{'p'} = ANY_COMBINATION; + $digram{'i'}{'r'} = ANY_COMBINATION; + $digram{'i'}{'s'} = ANY_COMBINATION; + $digram{'i'}{'t'} = ANY_COMBINATION; + $digram{'i'}{'u'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'i'}{'v'} = ANY_COMBINATION; + $digram{'i'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'i'}{'x'} = ANY_COMBINATION; + $digram{'i'}{'y'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'i'}{'z'} = ANY_COMBINATION; + $digram{'i'}{'ch'} = ANY_COMBINATION; + $digram{'i'}{'gh'} = NOT_FRONT; + $digram{'i'}{'ph'} = ANY_COMBINATION; + $digram{'i'}{'rh'} = ILLEGAL_PAIR; + $digram{'i'}{'sh'} = ANY_COMBINATION; + $digram{'i'}{'th'} = ANY_COMBINATION; + $digram{'i'}{'wh'} = ILLEGAL_PAIR; + $digram{'i'}{'qu'} = BREAK | NOT_BACK; + $digram{'i'}{'ck'} = ANY_COMBINATION; + + $digram{'j'}{'a'} = ANY_COMBINATION; + $digram{'j'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'e'} = ANY_COMBINATION; + $digram{'j'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'g'} = ILLEGAL_PAIR; + $digram{'j'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'i'} = ANY_COMBINATION; + $digram{'j'}{'j'} = ILLEGAL_PAIR; + $digram{'j'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'o'} = ANY_COMBINATION; + $digram{'j'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'s'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'u'} = ANY_COMBINATION; + $digram{'j'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'x'} = ILLEGAL_PAIR; + $digram{'j'}{'y'} = NOT_FRONT; + $digram{'j'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'rh'} = ILLEGAL_PAIR; + $digram{'j'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'wh'} = ILLEGAL_PAIR; + $digram{'j'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'j'}{'ck'} = ILLEGAL_PAIR; + + $digram{'k'}{'a'} = ANY_COMBINATION; + $digram{'k'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'e'} = ANY_COMBINATION; + $digram{'k'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'i'} = ANY_COMBINATION; + $digram{'k'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'l'} = SUFFIX | NOT_BACK; + $digram{'k'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'n'} = FRONT | SUFFIX | NOT_BACK; + $digram{'k'}{'o'} = ANY_COMBINATION; + $digram{'k'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'r'} = SUFFIX | NOT_BACK; + $digram{'k'}{'s'} = NOT_FRONT | BACK; + $digram{'k'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'u'} = ANY_COMBINATION; + $digram{'k'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'x'} = ILLEGAL_PAIR; + $digram{'k'}{'y'} = NOT_FRONT; + $digram{'k'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'ph'} = NOT_FRONT | PREFIX; + $digram{'k'}{'rh'} = ILLEGAL_PAIR; + $digram{'k'}{'sh'} = NOT_FRONT; + $digram{'k'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'wh'} = ILLEGAL_PAIR; + $digram{'k'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'k'}{'ck'} = ILLEGAL_PAIR; + + $digram{'l'}{'a'} = ANY_COMBINATION; + $digram{'l'}{'b'} = NOT_FRONT | PREFIX; + $digram{'l'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'d'} = NOT_FRONT | PREFIX; + $digram{'l'}{'e'} = ANY_COMBINATION; + $digram{'l'}{'f'} = NOT_FRONT | PREFIX; + $digram{'l'}{'g'} = NOT_FRONT | PREFIX; + $digram{'l'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'i'} = ANY_COMBINATION; + $digram{'l'}{'j'} = NOT_FRONT | PREFIX; + $digram{'l'}{'k'} = NOT_FRONT | PREFIX; + $digram{'l'}{'l'} = NOT_FRONT | PREFIX; + $digram{'l'}{'m'} = NOT_FRONT | PREFIX; + $digram{'l'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'o'} = ANY_COMBINATION; + $digram{'l'}{'p'} = NOT_FRONT | PREFIX; + $digram{'l'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'s'} = NOT_FRONT; + $digram{'l'}{'t'} = NOT_FRONT | PREFIX; + $digram{'l'}{'u'} = ANY_COMBINATION; + $digram{'l'}{'v'} = NOT_FRONT | PREFIX; + $digram{'l'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'x'} = ILLEGAL_PAIR; + $digram{'l'}{'y'} = ANY_COMBINATION; + $digram{'l'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'ch'} = NOT_FRONT | PREFIX; + $digram{'l'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'ph'} = NOT_FRONT | PREFIX; + $digram{'l'}{'rh'} = ILLEGAL_PAIR; + $digram{'l'}{'sh'} = NOT_FRONT | PREFIX; + $digram{'l'}{'th'} = NOT_FRONT | PREFIX; + $digram{'l'}{'wh'} = ILLEGAL_PAIR; + $digram{'l'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'l'}{'ck'} = ILLEGAL_PAIR; + + $digram{'m'}{'a'} = ANY_COMBINATION; + $digram{'m'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'e'} = ANY_COMBINATION; + $digram{'m'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'i'} = ANY_COMBINATION; + $digram{'m'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'m'} = NOT_FRONT; + $digram{'m'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'o'} = ANY_COMBINATION; + $digram{'m'}{'p'} = NOT_FRONT; + $digram{'m'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'s'} = NOT_FRONT; + $digram{'m'}{'t'} = NOT_FRONT; + $digram{'m'}{'u'} = ANY_COMBINATION; + $digram{'m'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'x'} = ILLEGAL_PAIR; + $digram{'m'}{'y'} = ANY_COMBINATION; + $digram{'m'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'ch'} = NOT_FRONT | PREFIX; + $digram{'m'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'ph'} = NOT_FRONT; + $digram{'m'}{'rh'} = ILLEGAL_PAIR; + $digram{'m'}{'sh'} = NOT_FRONT; + $digram{'m'}{'th'} = NOT_FRONT; + $digram{'m'}{'wh'} = ILLEGAL_PAIR; + $digram{'m'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'m'}{'ck'} = ILLEGAL_PAIR; + + $digram{'n'}{'a'} = ANY_COMBINATION; + $digram{'n'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'d'} = NOT_FRONT; + $digram{'n'}{'e'} = ANY_COMBINATION; + $digram{'n'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'g'} = NOT_FRONT | PREFIX; + $digram{'n'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'i'} = ANY_COMBINATION; + $digram{'n'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'k'} = NOT_FRONT | PREFIX; + $digram{'n'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'n'} = NOT_FRONT; + $digram{'n'}{'o'} = ANY_COMBINATION; + $digram{'n'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'s'} = NOT_FRONT; + $digram{'n'}{'t'} = NOT_FRONT; + $digram{'n'}{'u'} = ANY_COMBINATION; + $digram{'n'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'x'} = ILLEGAL_PAIR; + $digram{'n'}{'y'} = NOT_FRONT; + $digram{'n'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'ch'} = NOT_FRONT | PREFIX; + $digram{'n'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'ph'} = NOT_FRONT | PREFIX; + $digram{'n'}{'rh'} = ILLEGAL_PAIR; + $digram{'n'}{'sh'} = NOT_FRONT; + $digram{'n'}{'th'} = NOT_FRONT; + $digram{'n'}{'wh'} = ILLEGAL_PAIR; + $digram{'n'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'n'}{'ck'} = NOT_FRONT | PREFIX; + + $digram{'o'}{'a'} = ANY_COMBINATION; + $digram{'o'}{'b'} = ANY_COMBINATION; + $digram{'o'}{'c'} = ANY_COMBINATION; + $digram{'o'}{'d'} = ANY_COMBINATION; + $digram{'o'}{'e'} = ILLEGAL_PAIR; + $digram{'o'}{'f'} = ANY_COMBINATION; + $digram{'o'}{'g'} = ANY_COMBINATION; + $digram{'o'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'o'}{'i'} = ANY_COMBINATION; + $digram{'o'}{'j'} = ANY_COMBINATION; + $digram{'o'}{'k'} = ANY_COMBINATION; + $digram{'o'}{'l'} = ANY_COMBINATION; + $digram{'o'}{'m'} = ANY_COMBINATION; + $digram{'o'}{'n'} = ANY_COMBINATION; + $digram{'o'}{'o'} = ANY_COMBINATION; + $digram{'o'}{'p'} = ANY_COMBINATION; + $digram{'o'}{'r'} = ANY_COMBINATION; + $digram{'o'}{'s'} = ANY_COMBINATION; + $digram{'o'}{'t'} = ANY_COMBINATION; + $digram{'o'}{'u'} = ANY_COMBINATION; + $digram{'o'}{'v'} = ANY_COMBINATION; + $digram{'o'}{'w'} = ANY_COMBINATION; + $digram{'o'}{'x'} = ANY_COMBINATION; + $digram{'o'}{'y'} = ANY_COMBINATION; + $digram{'o'}{'z'} = ANY_COMBINATION; + $digram{'o'}{'ch'} = ANY_COMBINATION; + $digram{'o'}{'gh'} = NOT_FRONT; + $digram{'o'}{'ph'} = ANY_COMBINATION; + $digram{'o'}{'rh'} = ILLEGAL_PAIR; + $digram{'o'}{'sh'} = ANY_COMBINATION; + $digram{'o'}{'th'} = ANY_COMBINATION; + $digram{'o'}{'wh'} = ILLEGAL_PAIR; + $digram{'o'}{'qu'} = BREAK | NOT_BACK; + $digram{'o'}{'ck'} = ANY_COMBINATION; + + $digram{'p'}{'a'} = ANY_COMBINATION; + $digram{'p'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'e'} = ANY_COMBINATION; + $digram{'p'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'i'} = ANY_COMBINATION; + $digram{'p'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'l'} = SUFFIX | NOT_BACK; + $digram{'p'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'o'} = ANY_COMBINATION; + $digram{'p'}{'p'} = NOT_FRONT | PREFIX; + $digram{'p'}{'r'} = NOT_BACK; + $digram{'p'}{'s'} = NOT_FRONT | BACK; + $digram{'p'}{'t'} = NOT_FRONT | BACK; + $digram{'p'}{'u'} = NOT_FRONT | BACK; + $digram{'p'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'x'} = ILLEGAL_PAIR; + $digram{'p'}{'y'} = ANY_COMBINATION; + $digram{'p'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'rh'} = ILLEGAL_PAIR; + $digram{'p'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'wh'} = ILLEGAL_PAIR; + $digram{'p'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'p'}{'ck'} = ILLEGAL_PAIR; + + $digram{'r'}{'a'} = ANY_COMBINATION; + $digram{'r'}{'b'} = NOT_FRONT | PREFIX; + $digram{'r'}{'c'} = NOT_FRONT | PREFIX; + $digram{'r'}{'d'} = NOT_FRONT | PREFIX; + $digram{'r'}{'e'} = ANY_COMBINATION; + $digram{'r'}{'f'} = NOT_FRONT | PREFIX; + $digram{'r'}{'g'} = NOT_FRONT | PREFIX; + $digram{'r'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'r'}{'i'} = ANY_COMBINATION; + $digram{'r'}{'j'} = NOT_FRONT | PREFIX; + $digram{'r'}{'k'} = NOT_FRONT | PREFIX; + $digram{'r'}{'l'} = NOT_FRONT | PREFIX; + $digram{'r'}{'m'} = NOT_FRONT | PREFIX; + $digram{'r'}{'n'} = NOT_FRONT | PREFIX; + $digram{'r'}{'o'} = ANY_COMBINATION; + $digram{'r'}{'p'} = NOT_FRONT | PREFIX; + $digram{'r'}{'r'} = NOT_FRONT | PREFIX; + $digram{'r'}{'s'} = NOT_FRONT | PREFIX; + $digram{'r'}{'t'} = NOT_FRONT | PREFIX; + $digram{'r'}{'u'} = ANY_COMBINATION; + $digram{'r'}{'v'} = NOT_FRONT | PREFIX; + $digram{'r'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'r'}{'x'} = ILLEGAL_PAIR; + $digram{'r'}{'y'} = ANY_COMBINATION; + $digram{'r'}{'z'} = NOT_FRONT | PREFIX; + $digram{'r'}{'ch'} = NOT_FRONT | PREFIX; + $digram{'r'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'r'}{'ph'} = NOT_FRONT | PREFIX; + $digram{'r'}{'rh'} = ILLEGAL_PAIR; + $digram{'r'}{'sh'} = NOT_FRONT | PREFIX; + $digram{'r'}{'th'} = NOT_FRONT | PREFIX; + $digram{'r'}{'wh'} = ILLEGAL_PAIR; + $digram{'r'}{'qu'} = NOT_FRONT | PREFIX | NOT_BACK; + $digram{'r'}{'ck'} = NOT_FRONT | PREFIX; + + $digram{'s'}{'a'} = ANY_COMBINATION; + $digram{'s'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'c'} = NOT_BACK; + $digram{'s'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'e'} = ANY_COMBINATION; + $digram{'s'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'i'} = ANY_COMBINATION; + $digram{'s'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'k'} = ANY_COMBINATION; + $digram{'s'}{'l'} = FRONT | SUFFIX | NOT_BACK; + $digram{'s'}{'m'} = SUFFIX | NOT_BACK; + $digram{'s'}{'n'} = PREFIX | SUFFIX | NOT_BACK; + $digram{'s'}{'o'} = ANY_COMBINATION; + $digram{'s'}{'p'} = ANY_COMBINATION; + $digram{'s'}{'r'} = NOT_FRONT | NOT_BACK; + $digram{'s'}{'s'} = NOT_FRONT | PREFIX; + $digram{'s'}{'t'} = ANY_COMBINATION; + $digram{'s'}{'u'} = ANY_COMBINATION; + $digram{'s'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'w'} = FRONT | SUFFIX | NOT_BACK; + $digram{'s'}{'x'} = ILLEGAL_PAIR; + $digram{'s'}{'y'} = ANY_COMBINATION; + $digram{'s'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'ch'} = FRONT | SUFFIX | NOT_BACK; + $digram{'s'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'rh'} = ILLEGAL_PAIR; + $digram{'s'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'s'}{'wh'} = ILLEGAL_PAIR; + $digram{'s'}{'qu'} = SUFFIX | NOT_BACK; + $digram{'s'}{'ck'} = NOT_FRONT; + + $digram{'t'}{'a'} = ANY_COMBINATION; + $digram{'t'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'e'} = ANY_COMBINATION; + $digram{'t'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'i'} = ANY_COMBINATION; + $digram{'t'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'o'} = ANY_COMBINATION; + $digram{'t'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'r'} = NOT_BACK; + $digram{'t'}{'s'} = NOT_FRONT | BACK; + $digram{'t'}{'t'} = NOT_FRONT | PREFIX; + $digram{'t'}{'u'} = ANY_COMBINATION; + $digram{'t'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'w'} = FRONT | SUFFIX | NOT_BACK; + $digram{'t'}{'x'} = ILLEGAL_PAIR; + $digram{'t'}{'y'} = ANY_COMBINATION; + $digram{'t'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'ch'} = NOT_FRONT; + $digram{'t'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'ph'} = NOT_FRONT | BACK; + $digram{'t'}{'rh'} = ILLEGAL_PAIR; + $digram{'t'}{'sh'} = NOT_FRONT | BACK; + $digram{'t'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'wh'} = ILLEGAL_PAIR; + $digram{'t'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'t'}{'ck'} = ILLEGAL_PAIR; + + $digram{'u'}{'a'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'u'}{'b'} = ANY_COMBINATION; + $digram{'u'}{'c'} = ANY_COMBINATION; + $digram{'u'}{'d'} = ANY_COMBINATION; + $digram{'u'}{'e'} = NOT_FRONT; + $digram{'u'}{'f'} = ANY_COMBINATION; + $digram{'u'}{'g'} = ANY_COMBINATION; + $digram{'u'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'u'}{'i'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'u'}{'j'} = ANY_COMBINATION; + $digram{'u'}{'k'} = ANY_COMBINATION; + $digram{'u'}{'l'} = ANY_COMBINATION; + $digram{'u'}{'m'} = ANY_COMBINATION; + $digram{'u'}{'n'} = ANY_COMBINATION; + $digram{'u'}{'o'} = NOT_FRONT | BREAK; + $digram{'u'}{'p'} = ANY_COMBINATION; + $digram{'u'}{'r'} = ANY_COMBINATION; + $digram{'u'}{'s'} = ANY_COMBINATION; + $digram{'u'}{'t'} = ANY_COMBINATION; + $digram{'u'}{'u'} = ILLEGAL_PAIR; + $digram{'u'}{'v'} = ANY_COMBINATION; + $digram{'u'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'u'}{'x'} = ANY_COMBINATION; + $digram{'u'}{'y'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'u'}{'z'} = ANY_COMBINATION; + $digram{'u'}{'ch'} = ANY_COMBINATION; + $digram{'u'}{'gh'} = NOT_FRONT | PREFIX; + $digram{'u'}{'ph'} = ANY_COMBINATION; + $digram{'u'}{'rh'} = ILLEGAL_PAIR; + $digram{'u'}{'sh'} = ANY_COMBINATION; + $digram{'u'}{'th'} = ANY_COMBINATION; + $digram{'u'}{'wh'} = ILLEGAL_PAIR; + $digram{'u'}{'qu'} = BREAK | NOT_BACK; + $digram{'u'}{'ck'} = ANY_COMBINATION; + + $digram{'v'}{'a'} = ANY_COMBINATION; + $digram{'v'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'e'} = ANY_COMBINATION; + $digram{'v'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'i'} = ANY_COMBINATION; + $digram{'v'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'o'} = ANY_COMBINATION; + $digram{'v'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'s'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'u'} = ANY_COMBINATION; + $digram{'v'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'x'} = ILLEGAL_PAIR; + $digram{'v'}{'y'} = NOT_FRONT; + $digram{'v'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'rh'} = ILLEGAL_PAIR; + $digram{'v'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'wh'} = ILLEGAL_PAIR; + $digram{'v'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'v'}{'ck'} = ILLEGAL_PAIR; + + $digram{'w'}{'a'} = ANY_COMBINATION; + $digram{'w'}{'b'} = NOT_FRONT | PREFIX; + $digram{'w'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'w'}{'d'} = NOT_FRONT | PREFIX | BACK; + $digram{'w'}{'e'} = ANY_COMBINATION; + $digram{'w'}{'f'} = NOT_FRONT | PREFIX; + $digram{'w'}{'g'} = NOT_FRONT | PREFIX | BACK; + $digram{'w'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'w'}{'i'} = ANY_COMBINATION; + $digram{'w'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'w'}{'k'} = NOT_FRONT | PREFIX; + $digram{'w'}{'l'} = NOT_FRONT | PREFIX | SUFFIX; + $digram{'w'}{'m'} = NOT_FRONT | PREFIX; + $digram{'w'}{'n'} = NOT_FRONT | PREFIX; + $digram{'w'}{'o'} = ANY_COMBINATION; + $digram{'w'}{'p'} = NOT_FRONT | PREFIX; + $digram{'w'}{'r'} = FRONT | SUFFIX | NOT_BACK; + $digram{'w'}{'s'} = NOT_FRONT | PREFIX; + $digram{'w'}{'t'} = NOT_FRONT | PREFIX; + $digram{'w'}{'u'} = ANY_COMBINATION; + $digram{'w'}{'v'} = NOT_FRONT | PREFIX; + $digram{'w'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'w'}{'x'} = NOT_FRONT | PREFIX; + $digram{'w'}{'y'} = ANY_COMBINATION; + $digram{'w'}{'z'} = NOT_FRONT | PREFIX; + $digram{'w'}{'ch'} = NOT_FRONT; + $digram{'w'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'w'}{'ph'} = NOT_FRONT; + $digram{'w'}{'rh'} = ILLEGAL_PAIR; + $digram{'w'}{'sh'} = NOT_FRONT; + $digram{'w'}{'th'} = NOT_FRONT; + $digram{'w'}{'wh'} = ILLEGAL_PAIR; + $digram{'w'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'w'}{'ck'} = NOT_FRONT; + + $digram{'x'}{'a'} = NOT_FRONT; + $digram{'x'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'e'} = NOT_FRONT; + $digram{'x'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'i'} = NOT_FRONT; + $digram{'x'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'o'} = NOT_FRONT; + $digram{'x'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'s'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'u'} = NOT_FRONT; + $digram{'x'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'x'} = ILLEGAL_PAIR; + $digram{'x'}{'y'} = NOT_FRONT; + $digram{'x'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'rh'} = ILLEGAL_PAIR; + $digram{'x'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'wh'} = ILLEGAL_PAIR; + $digram{'x'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'x'}{'ck'} = ILLEGAL_PAIR; + + $digram{'y'}{'a'} = ANY_COMBINATION; + $digram{'y'}{'b'} = NOT_FRONT; + $digram{'y'}{'c'} = NOT_FRONT | NOT_BACK; + $digram{'y'}{'d'} = NOT_FRONT; + $digram{'y'}{'e'} = ANY_COMBINATION; + $digram{'y'}{'f'} = NOT_FRONT | NOT_BACK; + $digram{'y'}{'g'} = NOT_FRONT; + $digram{'y'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'i'} = FRONT | NOT_BACK; + $digram{'y'}{'j'} = NOT_FRONT | NOT_BACK; + $digram{'y'}{'k'} = NOT_FRONT; + $digram{'y'}{'l'} = NOT_FRONT | NOT_BACK; + $digram{'y'}{'m'} = NOT_FRONT; + $digram{'y'}{'n'} = NOT_FRONT; + $digram{'y'}{'o'} = ANY_COMBINATION; + $digram{'y'}{'p'} = NOT_FRONT; + $digram{'y'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'s'} = NOT_FRONT; + $digram{'y'}{'t'} = NOT_FRONT; + $digram{'y'}{'u'} = ANY_COMBINATION; + $digram{'y'}{'v'} = NOT_FRONT | NOT_BACK; + $digram{'y'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'x'} = NOT_FRONT; + $digram{'y'}{'y'} = ILLEGAL_PAIR; + $digram{'y'}{'z'} = NOT_FRONT; + $digram{'y'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'rh'} = ILLEGAL_PAIR; + $digram{'y'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'wh'} = ILLEGAL_PAIR; + $digram{'y'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'y'}{'ck'} = ILLEGAL_PAIR; + + $digram{'z'}{'a'} = ANY_COMBINATION; + $digram{'z'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'e'} = ANY_COMBINATION; + $digram{'z'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'i'} = ANY_COMBINATION; + $digram{'z'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'o'} = ANY_COMBINATION; + $digram{'z'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'r'} = NOT_FRONT | NOT_BACK; + $digram{'z'}{'s'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'t'} = NOT_FRONT; + $digram{'z'}{'u'} = ANY_COMBINATION; + $digram{'z'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'w'} = SUFFIX | NOT_BACK; + $digram{'z'}{'x'} = ILLEGAL_PAIR; + $digram{'z'}{'y'} = ANY_COMBINATION; + $digram{'z'}{'z'} = NOT_FRONT; + $digram{'z'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'rh'} = ILLEGAL_PAIR; + $digram{'z'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'wh'} = ILLEGAL_PAIR; + $digram{'z'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'z'}{'ck'} = ILLEGAL_PAIR; + + $digram{'ch'}{'a'} = ANY_COMBINATION; + $digram{'ch'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'e'} = ANY_COMBINATION; + $digram{'ch'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'i'} = ANY_COMBINATION; + $digram{'ch'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'o'} = ANY_COMBINATION; + $digram{'ch'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'r'} = NOT_BACK; + $digram{'ch'}{'s'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'u'} = ANY_COMBINATION; + $digram{'ch'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'w'} = NOT_FRONT | NOT_BACK; + $digram{'ch'}{'x'} = ILLEGAL_PAIR; + $digram{'ch'}{'y'} = ANY_COMBINATION; + $digram{'ch'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'ch'} = ILLEGAL_PAIR; + $digram{'ch'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'rh'} = ILLEGAL_PAIR; + $digram{'ch'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'wh'} = ILLEGAL_PAIR; + $digram{'ch'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ch'}{'ck'} = ILLEGAL_PAIR; + + $digram{'gh'}{'a'} = ANY_COMBINATION; + $digram{'gh'}{'b'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'c'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'d'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'e'} = ANY_COMBINATION; + $digram{'gh'}{'f'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'g'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'h'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'i'} = FRONT | NOT_BACK; + $digram{'gh'}{'j'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'k'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'l'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'m'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'n'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'o'} = FRONT | NOT_BACK; + $digram{'gh'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'gh'}{'r'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'s'} = NOT_FRONT | PREFIX; + $digram{'gh'}{'t'} = NOT_FRONT | PREFIX; + $digram{'gh'}{'u'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'v'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'w'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'x'} = ILLEGAL_PAIR; + $digram{'gh'}{'y'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'z'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'ch'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'gh'} = ILLEGAL_PAIR; + $digram{'gh'}{'ph'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'rh'} = ILLEGAL_PAIR; + $digram{'gh'}{'sh'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'th'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'wh'} = ILLEGAL_PAIR; + $digram{'gh'}{'qu'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK; + $digram{'gh'}{'ck'} = ILLEGAL_PAIR; + + $digram{'ph'}{'a'} = ANY_COMBINATION; + $digram{'ph'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'e'} = ANY_COMBINATION; + $digram{'ph'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'i'} = ANY_COMBINATION; + $digram{'ph'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'l'} = FRONT | SUFFIX | NOT_BACK; + $digram{'ph'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'o'} = ANY_COMBINATION; + $digram{'ph'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'r'} = NOT_BACK; + $digram{'ph'}{'s'} = NOT_FRONT; + $digram{'ph'}{'t'} = NOT_FRONT; + $digram{'ph'}{'u'} = ANY_COMBINATION; + $digram{'ph'}{'v'} = NOT_FRONT | NOT_BACK; + $digram{'ph'}{'w'} = NOT_FRONT | NOT_BACK; + $digram{'ph'}{'x'} = ILLEGAL_PAIR; + $digram{'ph'}{'y'} = NOT_FRONT; + $digram{'ph'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'ph'} = ILLEGAL_PAIR; + $digram{'ph'}{'rh'} = ILLEGAL_PAIR; + $digram{'ph'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'wh'} = ILLEGAL_PAIR; + $digram{'ph'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ph'}{'ck'} = ILLEGAL_PAIR; + + $digram{'rh'}{'a'} = FRONT | NOT_BACK; + $digram{'rh'}{'b'} = ILLEGAL_PAIR; + $digram{'rh'}{'c'} = ILLEGAL_PAIR; + $digram{'rh'}{'d'} = ILLEGAL_PAIR; + $digram{'rh'}{'e'} = FRONT | NOT_BACK; + $digram{'rh'}{'f'} = ILLEGAL_PAIR; + $digram{'rh'}{'g'} = ILLEGAL_PAIR; + $digram{'rh'}{'h'} = ILLEGAL_PAIR; + $digram{'rh'}{'i'} = FRONT | NOT_BACK; + $digram{'rh'}{'j'} = ILLEGAL_PAIR; + $digram{'rh'}{'k'} = ILLEGAL_PAIR; + $digram{'rh'}{'l'} = ILLEGAL_PAIR; + $digram{'rh'}{'m'} = ILLEGAL_PAIR; + $digram{'rh'}{'n'} = ILLEGAL_PAIR; + $digram{'rh'}{'o'} = FRONT | NOT_BACK; + $digram{'rh'}{'p'} = ILLEGAL_PAIR; + $digram{'rh'}{'r'} = ILLEGAL_PAIR; + $digram{'rh'}{'s'} = ILLEGAL_PAIR; + $digram{'rh'}{'t'} = ILLEGAL_PAIR; + $digram{'rh'}{'u'} = FRONT | NOT_BACK; + $digram{'rh'}{'v'} = ILLEGAL_PAIR; + $digram{'rh'}{'w'} = ILLEGAL_PAIR; + $digram{'rh'}{'x'} = ILLEGAL_PAIR; + $digram{'rh'}{'y'} = FRONT | NOT_BACK; + $digram{'rh'}{'z'} = ILLEGAL_PAIR; + $digram{'rh'}{'ch'} = ILLEGAL_PAIR; + $digram{'rh'}{'gh'} = ILLEGAL_PAIR; + $digram{'rh'}{'ph'} = ILLEGAL_PAIR; + $digram{'rh'}{'rh'} = ILLEGAL_PAIR; + $digram{'rh'}{'sh'} = ILLEGAL_PAIR; + $digram{'rh'}{'th'} = ILLEGAL_PAIR; + $digram{'rh'}{'wh'} = ILLEGAL_PAIR; + $digram{'rh'}{'qu'} = ILLEGAL_PAIR; + $digram{'rh'}{'ck'} = ILLEGAL_PAIR; + + $digram{'sh'}{'a'} = ANY_COMBINATION; + $digram{'sh'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'e'} = ANY_COMBINATION; + $digram{'sh'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'h'} = ILLEGAL_PAIR; + $digram{'sh'}{'i'} = ANY_COMBINATION; + $digram{'sh'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'k'} = NOT_FRONT; + $digram{'sh'}{'l'} = FRONT | SUFFIX | NOT_BACK; + $digram{'sh'}{'m'} = FRONT | SUFFIX | NOT_BACK; + $digram{'sh'}{'n'} = FRONT | SUFFIX | NOT_BACK; + $digram{'sh'}{'o'} = ANY_COMBINATION; + $digram{'sh'}{'p'} = NOT_FRONT; + $digram{'sh'}{'r'} = FRONT | SUFFIX | NOT_BACK; + $digram{'sh'}{'s'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'t'} = SUFFIX; + $digram{'sh'}{'u'} = ANY_COMBINATION; + $digram{'sh'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'w'} = SUFFIX | NOT_BACK; + $digram{'sh'}{'x'} = ILLEGAL_PAIR; + $digram{'sh'}{'y'} = ANY_COMBINATION; + $digram{'sh'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'rh'} = ILLEGAL_PAIR; + $digram{'sh'}{'sh'} = ILLEGAL_PAIR; + $digram{'sh'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'wh'} = ILLEGAL_PAIR; + $digram{'sh'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'sh'}{'ck'} = ILLEGAL_PAIR; + + $digram{'th'}{'a'} = ANY_COMBINATION; + $digram{'th'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'e'} = ANY_COMBINATION; + $digram{'th'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'i'} = ANY_COMBINATION; + $digram{'th'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'o'} = ANY_COMBINATION; + $digram{'th'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'r'} = NOT_BACK; + $digram{'th'}{'s'} = NOT_FRONT | BACK; + $digram{'th'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'u'} = ANY_COMBINATION; + $digram{'th'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'w'} = SUFFIX | NOT_BACK; + $digram{'th'}{'x'} = ILLEGAL_PAIR; + $digram{'th'}{'y'} = ANY_COMBINATION; + $digram{'th'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'rh'} = ILLEGAL_PAIR; + $digram{'th'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'th'} = ILLEGAL_PAIR; + $digram{'th'}{'wh'} = ILLEGAL_PAIR; + $digram{'th'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'th'}{'ck'} = ILLEGAL_PAIR; + + $digram{'wh'}{'a'} = FRONT | NOT_BACK; + $digram{'wh'}{'b'} = ILLEGAL_PAIR; + $digram{'wh'}{'c'} = ILLEGAL_PAIR; + $digram{'wh'}{'d'} = ILLEGAL_PAIR; + $digram{'wh'}{'e'} = FRONT | NOT_BACK; + $digram{'wh'}{'f'} = ILLEGAL_PAIR; + $digram{'wh'}{'g'} = ILLEGAL_PAIR; + $digram{'wh'}{'h'} = ILLEGAL_PAIR; + $digram{'wh'}{'i'} = FRONT | NOT_BACK; + $digram{'wh'}{'j'} = ILLEGAL_PAIR; + $digram{'wh'}{'k'} = ILLEGAL_PAIR; + $digram{'wh'}{'l'} = ILLEGAL_PAIR; + $digram{'wh'}{'m'} = ILLEGAL_PAIR; + $digram{'wh'}{'n'} = ILLEGAL_PAIR; + $digram{'wh'}{'o'} = FRONT | NOT_BACK; + $digram{'wh'}{'p'} = ILLEGAL_PAIR; + $digram{'wh'}{'r'} = ILLEGAL_PAIR; + $digram{'wh'}{'s'} = ILLEGAL_PAIR; + $digram{'wh'}{'t'} = ILLEGAL_PAIR; + $digram{'wh'}{'u'} = ILLEGAL_PAIR; + $digram{'wh'}{'v'} = ILLEGAL_PAIR; + $digram{'wh'}{'w'} = ILLEGAL_PAIR; + $digram{'wh'}{'x'} = ILLEGAL_PAIR; + $digram{'wh'}{'y'} = FRONT | NOT_BACK; + $digram{'wh'}{'z'} = ILLEGAL_PAIR; + $digram{'wh'}{'ch'} = ILLEGAL_PAIR; + $digram{'wh'}{'gh'} = ILLEGAL_PAIR; + $digram{'wh'}{'ph'} = ILLEGAL_PAIR; + $digram{'wh'}{'rh'} = ILLEGAL_PAIR; + $digram{'wh'}{'sh'} = ILLEGAL_PAIR; + $digram{'wh'}{'th'} = ILLEGAL_PAIR; + $digram{'wh'}{'wh'} = ILLEGAL_PAIR; + $digram{'wh'}{'qu'} = ILLEGAL_PAIR; + $digram{'wh'}{'ck'} = ILLEGAL_PAIR; + + $digram{'qu'}{'a'} = ANY_COMBINATION; + $digram{'qu'}{'b'} = ILLEGAL_PAIR; + $digram{'qu'}{'c'} = ILLEGAL_PAIR; + $digram{'qu'}{'d'} = ILLEGAL_PAIR; + $digram{'qu'}{'e'} = ANY_COMBINATION; + $digram{'qu'}{'f'} = ILLEGAL_PAIR; + $digram{'qu'}{'g'} = ILLEGAL_PAIR; + $digram{'qu'}{'h'} = ILLEGAL_PAIR; + $digram{'qu'}{'i'} = ANY_COMBINATION; + $digram{'qu'}{'j'} = ILLEGAL_PAIR; + $digram{'qu'}{'k'} = ILLEGAL_PAIR; + $digram{'qu'}{'l'} = ILLEGAL_PAIR; + $digram{'qu'}{'m'} = ILLEGAL_PAIR; + $digram{'qu'}{'n'} = ILLEGAL_PAIR; + $digram{'qu'}{'o'} = ANY_COMBINATION; + $digram{'qu'}{'p'} = ILLEGAL_PAIR; + $digram{'qu'}{'r'} = ILLEGAL_PAIR; + $digram{'qu'}{'s'} = ILLEGAL_PAIR; + $digram{'qu'}{'t'} = ILLEGAL_PAIR; + $digram{'qu'}{'u'} = ILLEGAL_PAIR; + $digram{'qu'}{'v'} = ILLEGAL_PAIR; + $digram{'qu'}{'w'} = ILLEGAL_PAIR; + $digram{'qu'}{'x'} = ILLEGAL_PAIR; + $digram{'qu'}{'y'} = ILLEGAL_PAIR; + $digram{'qu'}{'z'} = ILLEGAL_PAIR; + $digram{'qu'}{'ch'} = ILLEGAL_PAIR; + $digram{'qu'}{'gh'} = ILLEGAL_PAIR; + $digram{'qu'}{'ph'} = ILLEGAL_PAIR; + $digram{'qu'}{'rh'} = ILLEGAL_PAIR; + $digram{'qu'}{'sh'} = ILLEGAL_PAIR; + $digram{'qu'}{'th'} = ILLEGAL_PAIR; + $digram{'qu'}{'wh'} = ILLEGAL_PAIR; + $digram{'qu'}{'qu'} = ILLEGAL_PAIR; + $digram{'qu'}{'ck'} = ILLEGAL_PAIR; + + $digram{'ck'}{'a'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'b'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'c'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'d'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'e'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'f'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'g'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'h'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'i'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'j'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'k'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'l'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'m'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'n'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'o'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'p'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'r'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'s'} = NOT_FRONT; + $digram{'ck'}{'t'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'u'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'v'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'w'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'x'} = ILLEGAL_PAIR; + $digram{'ck'}{'y'} = NOT_FRONT; + $digram{'ck'}{'z'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'rh'} = ILLEGAL_PAIR; + $digram{'ck'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'th'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'wh'} = ILLEGAL_PAIR; + $digram{'ck'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK; + $digram{'ck'}{'ck'} = ILLEGAL_PAIR; + + ############################################################################################## + # } END DIGRAM + ############################################################################################## + + + +sub report(@) { + $main::DEBUG and print @_; +} + + + + +=head2 word + + word = word( minlen, maxlen ); + ( word, hyphenated_form ) = word( minlen, maxlen ); + +Generates a random word, as well as its hyphenated form. +The length of the returned word will be between minlen and maxlen. + +=cut + +sub word($$) { + @_ > 2 and shift; + my( $minlen, $maxlen ) = @_; + + $minlen <= $maxlen or die "minlen $minlen is greater than maxlen $maxlen"; + + init(); + + # + # Check for zero length words. This is technically not an error, + # so we take the short cut and return empty words. + # + $maxlen or return wantarray ? ('','') : ''; + + my( $word, $hyphenated_word ); + + for ( my $try = 1 ; $try <= MAX_UNACCEPTABLE and not defined $word; $try++ ) { + ( $word, $hyphenated_word ) = _random_word( rand_int_in_range( $minlen, $maxlen ) ); + $word = restrict( $word ); + } + + $word or die "failed to generate an acceptable random password.\n"; + + return wantarray ? ( $word, $hyphenated_word ) : $word; +} + + +=head2 letters + + word = letters( minlen, maxlen ); + +Generates a string of random letters. +The length of the returned word is between minlen and maxlen. +Calls C<random_chars_in_range( 'a' => 'z' )>. + +=cut + +sub letters($$) { + @_ > 2 and shift; + my( $minlen, $maxlen ) = @_; + random_chars_in_range( $minlen, $maxlen, 'a' => 'z' ); # range of lowercase letters in ASCII +} + + +=head2 chars + + word = chars( minlen, maxlen ); + +Generates a string of random printable characters. +The length of the returned word is between minlen and maxlen. +Calls C<random_chars_in_range( '!' => '~' )>. + +=cut + +sub chars($$) { + @_ > 2 and shift; + my( $minlen, $maxlen ) = @_; + random_chars_in_range( $minlen, $maxlen, '!' => '~' ); # range of printable chars in ASCII +} + + + +=head2 random_chars_in_range + + word = random_chars_in_range( minlen, maxlen, lo_char => hi_char ); + +Generates a string of printable characters. +The length of the returned string is between minlen and maxlen. +Each character is selected from the range of ASCII characters +delimited by (lo_char,hi_char). + +=cut + +sub random_chars_in_range($$$$) { + my( $minlen, $maxlen, $lo_char, $hi_char ) = @_; + + $minlen <= $maxlen or die "minlen $minlen is greater than maxlen $maxlen"; + + init(); + + my $string_size = rand_int_in_range( $minlen, $maxlen ); + + my $string; + for ( my $try = 1 ; $try <= MAX_UNACCEPTABLE and not defined $string; $try++ ) { + my $s = ''; + while ( length($s) < $string_size ) { + $s .= chr( rand_int_in_range( ord($lo_char), ord($hi_char) ) ); + } + next if length($s) > $string_size; + $string = restrict( $s ); + } + + $string +} + + + +=head2 rand_int_in_range + + n = rand_int_in_range( min, max ); + +Returns an integer between min and max, inclusive. +Calls C<rng> like so: + + n = min + int( rng( max - min + 1 ) ) + +=cut + +sub rand_int_in_range($$) { + my( $min, $max ) = @_; + $min + int( rng( $max - $min + 1 ) ) +} + + +=head2 random_element + + e = random_element( \@elts ) + +Selects a random element from an array, which is passed by ref. + +=cut + +sub random_element($) { + my $ar = shift; + $ar->[ rand_int_in_range( 0, $#{$ar} ) ] +} + + + +=head2 rng + + r = rng( n ); + +C<rng> is designed to have the same interface as the built-in C<rand> function. +The default implementation here is a simple wrapper around C<rand>, +which is typically a wrapper for some pseudo-random number function in the +underlying C library. + +The reason for having this simple wrapper is so the user can +easily substitute a different random number generator if desired. +Since many rng's have the same interface as C<rand>, replacing C<rng()> +is as simple as + + { + local $^W; # squelch sub redef warning. + *Crypt::RandPasswd::rng = \&my_rng; + } + +See L<rand>. + +=cut + +sub rng($) { + my $x = shift; + rand($x) +} + + + +=head2 restrict + + word = restrict( word ); + +A filter. Returns the arg unchanged if it is allowable; returns undef if not. + +The default version of C<restrict()> allows everything. +You may install a different form to implement other restrictions, +by doing something like this: + + { + local $^W; # squelch sub redef warning. + *Crypt::RandPasswd::restrict = \&my_filter; + } + +=cut + +sub restrict($) { $_[0] } # MUST return a real scalar; returning @_ causes scalar(@_) !!! + + +=head2 init + +This initializes the environment, which by default simply seeds the random number generator. + +=cut + +# can be called multiple times without harm, since it remembers whether +# it has already been called. + +sub init() { + unless ( $Crypt::RandPasswd::initialized ) { + # only do stuff if I haven't already been called before. + + $Crypt::RandPasswd::initialized = 1; + if ( defined $Crypt::RandPasswd::seed ) { + srand( $Crypt::RandPasswd::seed ); + } + else { + srand; # use default, which can be pretty good. + } + } +} + + + + +=head2 _random_word + +This is the routine that returns a random word. +It collects random syllables until a predetermined word length is found. +If a retry threshold is reached, another word is tried. + +returns ( word, hyphenated_word ). + +=cut + +sub _random_word($) { + my( $pwlen ) = @_; + + my $word = ''; + my @word_syllables; + + my $max_retries = ( 4 * $pwlen ) + scalar( @grams ); + + my $tries = 0; # count of retries. + + + # @word_units used to be an array of indices into the 'rules' C-array. + # now it's an array of actual units (grams). + my @word_units; + + # + # Find syllables until the entire word is constructed. + # + while ( length($word) < $pwlen ) { + # + # Get the syllable and find its length. + # + report "About to call get_syllable( $pwlen - length($word) )\n"; + my( $new_syllable, @syllable_units ) = get_syllable( $pwlen - length($word) ); + report "get_syllable returned ( $new_syllable; @syllable_units )\n"; + + # + # If the word has been improperly formed, throw out + # the syllable. The checks performed here are those + # that must be formed on a word basis. The other + # tests are performed entirely within the syllable. + # Otherwise, append the syllable to the word. + # + unless ( + _improper_word( @word_units, @syllable_units ) # join the arrays + || + ( + $word eq '' + and + _have_initial_y( @syllable_units ) + ) + || + ( + length( $word . $new_syllable ) == $pwlen + and + _have_final_split( @syllable_units ) + ) + ) { + $word .= $new_syllable; + push @word_syllables, $new_syllable; + } + + # + # Keep track of the times we have tried to get syllables. + # If we have exceeded the threshold, start from scratch. + # + $tries++; + if ( $tries > $max_retries ) { + $tries = 0; + $word = ''; + @word_syllables = (); + @word_units = (); + } + } + + return( $word, join('-',@word_syllables) ); +} + + + +=head2 _random_unit + +Selects a gram (aka "unit"). +This is the standard random unit generating routine for get_syllable(). + +This routine attempts to return grams (units) with a distribution +approaching that of the distribution of the units in English. + +The distribution of the units may be altered in this procedure without +affecting the digram table or any other programs using the random_word subroutine, +as long as the set of grams (units) is kept consistent throughout this library. + +I<NOTE that where this func used to return a numeric index into +the 'rules' C-array, it now returns a gram.> + +=cut + +my %occurrence_frequencies = ( + 'a' => 10, 'b' => 8, 'c' => 12, 'd' => 12, + 'e' => 12, 'f' => 8, 'g' => 8, 'h' => 6, + 'i' => 10, 'j' => 8, 'k' => 8, 'l' => 6, + 'm' => 6, 'n' => 10, 'o' => 10, 'p' => 6, + 'r' => 10, 's' => 8, 't' => 10, 'u' => 6, + 'v' => 8, 'w' => 8, 'x' => 1, 'y' => 8, + 'z' => 1, 'ch' => 1, 'gh' => 1, 'ph' => 1, + 'rh' => 1, 'sh' => 2, 'th' => 1, 'wh' => 1, + 'qu' => 1, 'ck' => 1, +); + +my @numbers = map { + ( ($_) x $occurrence_frequencies{$_} ) +} @grams; + +my @vowel_numbers = map { + ( ($_) x $occurrence_frequencies{$_} ) +} @vowel_grams; + + + +sub _random_unit($) { + my $type = shift; # byte + + random_element( $type & VOWEL + ? \@vowel_numbers # Sometimes, we are asked to explicitly get a vowel (i.e., if + # a digram pair expects one following it). This is a shortcut + # to do that and avoid looping with rejected consonants. + + : \@numbers # Get any letter according to the English distribution. + ) +} + + + + +=head2 _improper_word + +Check that the word does not contain illegal combinations +that may span syllables. Specifically, these are: + + 1. An illegal pair of units between syllables. + 2. Three consecutive vowel units. + 3. Three consecutive consonant units. + +The checks are made against units (1 or 2 letters), not against +the individual letters, so three consecutive units can have +the length of 6 at most. + +returns boolean + +=cut + +sub _improper_word(@) { + my @units = @_; + + my $failure; # bool, init False. + + for my $unit_count ( 0 .. $#units ) { + # + # Check for ILLEGAL_PAIR. + # This should have been caught for units within a syllable, + # but in some cases it would have gone unnoticed for units between syllables + # (e.g., when saved units in get_syllable() were not used). + # + $unit_count > 0 + and $digram{$units[$unit_count-1]}{$units[$unit_count]} & ILLEGAL_PAIR + and return(1); # Failure! + + next if $unit_count < 2; + # + # Check for consecutive vowels or consonants. + # Because the initial y of a syllable is treated as a consonant rather + # than as a vowel, we exclude y from the first vowel in the vowel test. + # The only problem comes when y ends a syllable and two other vowels start the next, like fly-oint. + # Since such words are still pronounceable, we accept this. + # + # + # Vowel check. + # + ( + ($rules{$units[$unit_count - 2]} & VOWEL) + && + !($rules{$units[$unit_count - 2]} & ALTERNATE_VOWEL) + && + ($rules{$units[$unit_count - 1]} & VOWEL) + && + ($rules{$units[$unit_count ]} & VOWEL) + ) + || + # + # Consonant check. + # + ( + !($rules{$units[$unit_count - 2]} & VOWEL) + && + !($rules{$units[$unit_count - 1]} & VOWEL) + && + !($rules{$units[$unit_count ]} & VOWEL) + ) + and return(1); # Failure! + } + + 0 # success +} + + +=head2 _have_initial_y + +Treating y as a vowel is sometimes a problem. Some words get formed that look irregular. +One special group is when y starts a word and is the only vowel in the first syllable. +The word ycl is one example. We discard words like these. + +return boolean + +=cut + +sub _have_initial_y(@) { + my @units = @_; + + my $vowel_count = 0; + my $normal_vowel_count = 0; + + for my $unit_count ( 0 .. $#units ) { + # + # Count vowels. + # + if ( $rules{$units[$unit_count]} & VOWEL ) { + $vowel_count++; + + # + # Count the vowels that are not: + # 1. 'y' + # 2. at the start of the word. + # + if ( !($rules{$units[$unit_count]} & ALTERNATE_VOWEL) || ($unit_count > 0) ) { + $normal_vowel_count++; + } + } + } + + ($vowel_count <= 1) && ($normal_vowel_count == 0) +} + + +=head2 _have_final_split + +Besides the problem with the letter y, there is one with +a silent e at the end of words, like face or nice. +We allow this silent e, but we do not allow it as the only +vowel at the end of the word or syllables like ble will +be generated. + +returns boolean + +=cut + +sub _have_final_split(@) { + my @units = @_; + + my $vowel_count = 0; + + # + # Count all the vowels in the word. + # + for my $unit_count ( 0 .. $#units ) { + if ( $rules{$units[$unit_count]} & VOWEL ) { + $vowel_count++; + } + } + + # + # Return TRUE iff the only vowel was e, found at the end if the word. + # + ($vowel_count == 1) && ( $rules{$units[$#units]} & NO_FINAL_SPLIT ) +} + + +=head2 get_syllable + +Generate next unit to password, making sure that it follows these rules: + +1. Each syllable must contain exactly 1 or 2 consecutive vowels, where y is considered a vowel. + +2. Syllable end is determined as follows: + + a. Vowel is generated and previous unit is a consonant and syllable already has a vowel. + In this case, new syllable is started and already contains a vowel. + b. A pair determined to be a "break" pair is encountered. + In this case new syllable is started with second unit of this pair. + c. End of password is encountered. + d. "begin" pair is encountered legally. New syllable is started with this pair. + e. "end" pair is legally encountered. New syllable has nothing yet. + +3. Try generating another unit if: + + a. third consecutive vowel and not y. + b. "break" pair generated but no vowel yet in current or previous 2 units are "not_end". + c. "begin" pair generated but no vowel in syllable preceding begin pair, + or both previous 2 pairs are designated "not_end". + d. "end" pair generated but no vowel in current syllable or in "end" pair. + e. "not_begin" pair generated but new syllable must begin (because previous syllable ended as defined in 2 above). + f. vowel is generated and 2a is satisfied, but no syllable break is possible in previous 3 pairs. + g. Second and third units of syllable must begin, and first unit is "alternate_vowel". + + +=cut + +# global (like a C static) +use vars qw( @saved_pair ); +@saved_pair = (); # 0..2 elements, which are units (grams). + +sub get_syllable($) { + my $pwlen = shift; + + # these used to be "out" params: + my $syllable; # string, returned + my @units_in_syllable = (); # array of units, returned + + + # grams: + my $unit; + my $current_unit; + my $last_unit; + + # numbers: + my $vowel_count; + my $tries; + my $length_left; + + # flags: + my $rule_broken; + my $want_vowel; + my $want_another_unit; + + + # + # This is needed if the saved_pair is tried and the syllable then + # discarded because of the retry limit. Since the saved_pair is OK and + # fits in nicely with the preceding syllable, we will always use it. + # + my @hold_saved_pair = @saved_pair; + + my $max_retries = ( 4 * $pwlen ) + scalar( @grams ); + # note that this used to be a macro, which means it could have changed + # dynamically based on the value of $pwlen... + + # + # Loop until valid syllable is found. + # + do { + # + # Try for a new syllable. Initialize all pertinent + # syllable variables. + # + $tries = 0; + @saved_pair = @hold_saved_pair; + $syllable = ""; + $vowel_count = 0; + $current_unit = 0; + $length_left = $pwlen; + $want_another_unit = 1; # true + + # + # This loop finds all the units for the syllable. + # + do { + $want_vowel = 0; # false + + # + # This loop continues until a valid unit is found for the + # current position within the syllable. + # + do { + # + # If there are saved units from the previous syllable, use them up first. + # + + # + # If there were two saved units, the first is guaranteed + # (by checks performed in the previous syllable) to be valid. + # We ignore the checks and place it in this syllable manually. + # + if ( @saved_pair == 2 ) { + $syllable = + $units_in_syllable[0] = pop @saved_pair; + $vowel_count++ if $rules{$syllable} & VOWEL; + $current_unit++; + $length_left -= length $syllable; + } + + if ( @saved_pair ) { + # + # The unit becomes the last unit checked in the previous syllable. + # + $unit = pop @saved_pair; + + # + # The saved units have been used. + # Do not try to reuse them in this syllable + # (unless this particular syllable is rejected + # at which point we start to rebuild it with these same saved units). + # + } + else { + # + # If we don't have to consider the saved units, we generate a random one. + # + $unit = _random_unit( $want_vowel ? VOWEL : NO_SPECIAL_RULE ); + } + + $length_left -= length $unit; + + # + # Prevent having a word longer than expected. + # + $rule_broken = ( $length_left < 0 ); # boolean + + # + # First unit of syllable. + # This is special because the digram tests require 2 units and we don't have that yet. + # Nevertheless, we can perform some checks. + # + if ( $current_unit == 0 ) { + # + # If the shouldn't begin a syllable, don't use it. + # + if ( $rules{$unit} & NOT_BEGIN_SYLLABLE ) { + $rule_broken = 1; # true + # + # If this is the last unit of a word, we have a one unit syllable. + # Since each syllable must have a vowel, we make sure the unit is a vowel. + # Otherwise, we discard it. + # + } + elsif ( $length_left == 0 ) { + if ( $rules{$unit} & VOWEL ) { + $want_another_unit = 0; # false + } + else { + $rule_broken = 1; # true + } + } + } + else { +# +# this ALLOWED thing is only used in this code block. +# note that $unit and $current_unit are (used to be) numeric indices; should now be actual grams. +# +local *ALLOWED = sub { + my $flag = shift; + $digram{$units_in_syllable[$current_unit-1]}{$unit} & $flag +}; + + # + # There are some digram tests that are universally true. We test them out. + # + + if ( + # + # Reject ILLEGAL_PAIRS of units. + # + (ALLOWED(ILLEGAL_PAIR)) + || + + # + # Reject units that will be split between syllables + # when the syllable has no vowels in it. + # + (ALLOWED(BREAK) && ($vowel_count == 0)) + || + + # + # Reject a unit that will end a syllable when no + # previous unit was a vowel and neither is this one. + # + ( + ALLOWED(BACK) + && + ($vowel_count == 0) + && + !($rules{$unit} & VOWEL) + ) + ) { + $rule_broken = 1; # true + } + + if ($current_unit == 1) { + # + # Reject the unit if we are at te starting digram of + # a syllable and it does not fit. + # + if (ALLOWED(NOT_FRONT)) { + $rule_broken = 1; # true + } + } + else { + # + # We are not at the start of a syllable. + # Save the previous unit for later tests. + # + $last_unit = $units_in_syllable[$current_unit - 1]; + + # + # Do not allow syllables where the first letter is y + # and the next pair can begin a syllable. This may + # lead to splits where y is left alone in a syllable. + # Also, the combination does not sound to good even + # if not split. + # + if ( + ( + ($current_unit == 2) + && + ALLOWED(FRONT) + && + ($rules{$units_in_syllable[0]} & ALTERNATE_VOWEL) + ) + || + + # + # If this is the last unit of a word, we should + # reject any digram that cannot end a syllable. + # + ( + ALLOWED(NOT_BACK) + && + ($length_left == 0) + ) + || + + # + # Reject the unit if the digram it forms wants + # to break the syllable, but the resulting + # digram that would end the syllable is not + # allowed to end a syllable. + # + ( + ALLOWED(BREAK) + || + ($digram{ $units_in_syllable[$current_unit-2] }{$last_unit} & NOT_BACK) + ) + || + + # + # Reject the unit if the digram it forms expects a vowel preceding it and there is none. + # + ( + ALLOWED(PREFIX) + && + !($rules{ $units_in_syllable[$current_unit-2] } & VOWEL) + ) + ) { + $rule_broken = 1; # true + } + + # + # The following checks occur when the current unit is a vowel + # and we are not looking at a word ending with an e. + # + if ( + !$rule_broken + && + ($rules{$unit} & VOWEL) + && + ( + ($length_left > 0) + || + !($rules{$last_unit} & NO_FINAL_SPLIT) + ) + ) { + # + # Don't allow 3 consecutive vowels in a syllable. + # Although some words formed like this are OK, like "beau", most are not. + # + if ( ($vowel_count > 1) && ($rules{$last_unit} & VOWEL) ) { + $rule_broken = 1; # true + } + # + # Check for the case of vowels-consonants-vowel, + # which is only legal if the last vowel is an e and we are the end of the word + # (which is not happening here due to a previous check). + # + elsif ( ($vowel_count != 0) && !($rules{$last_unit} & VOWEL) ) { + # + # Try to save the vowel for the next syllable, + # but if the syllable left here is not proper + # (i.e., the resulting last digram cannot legally end it), + # just discard it and try for another. + # + if ( $digram{ $units_in_syllable[ $current_unit - 2] }{$last_unit} & NOT_BACK ) { + $rule_broken = 1; # true + } + else { + @saved_pair = ( $unit ); + $want_another_unit = 0; # false + } + } + } + } + + # + # The unit picked and the digram formed are legal. + # We now determine if we can end the syllable. It may, + # in some cases, mean the last unit(s) may be deferred to + # the next syllable. We also check here to see if the + # digram formed expects a vowel to follow. + # + if ( !$rule_broken and $want_another_unit ) { + # + # This word ends in a silent e. + # + if ( + ( + ($vowel_count != 0) + && + ($rules{$unit} & NO_FINAL_SPLIT) + && + ($length_left == 0) + && + !($rules{$last_unit} & VOWEL) + ) + or + + # + # This syllable ends either because the digram + # is a BACK pair or we would otherwise exceed + # the length of the word. + # + ( ALLOWED(BACK) || ($length_left == 0) ) + ) { + $want_another_unit = 0; # false + } + + # + # Since we have a vowel in the syllable + # already, if the digram calls for the end of the + # syllable, we can legally split it off. We also + # make sure that we are not at the end of the + # dangerous because that syllable may not have + # vowels, or it may not be a legal syllable end, + # and the retrying mechanism will loop infinitely + # with the same digram. + # + elsif ( $vowel_count != 0 and $length_left > 0 ) { + # + # If we must begin a syllable, we do so if + # the only vowel in THIS syllable is not part + # of the digram we are pushing to the next + # syllable. + # + if ( + ALLOWED(FRONT) + && + ($current_unit > 1) + && + !( + ($vowel_count == 1) + && + ($rules{$last_unit} & VOWEL) + ) + ) { + @saved_pair = ( $unit, $last_unit ); + $want_another_unit = 0; # false + } + elsif (ALLOWED (BREAK)) { + @saved_pair = ( $unit ); + $want_another_unit = 0; # false + } + } + elsif (ALLOWED (SUFFIX)) { + $want_vowel = 1; # true + } + } + } + + $tries++; + + # + # If this unit was illegal, redetermine the amount of + # letters left to go in the word. + # + if ( $rule_broken ) { + $length_left += length $unit; + } + } + while ( $rule_broken and $tries <= $max_retries ); + + # + # The unit fit OK. + # + if ( $tries <= $max_retries ) { + # + # If the unit were a vowel, count it in. + # However, if the unit were a y and appear at the start of the syllable, + # treat it like a constant (so that words like "year" can appear and + # not conflict with the 3 consecutive vowel rule). + # + if ( + ($rules{$unit} & VOWEL) + && + ( ($current_unit > 0) || !($rules{$unit} & ALTERNATE_VOWEL) ) + ) { + $vowel_count++; + } + + # + # If a unit or units were to be saved, we must adjust the syllable formed. + # Otherwise, we append the current unit to the syllable. + # + if ( @saved_pair == 2 ) { + # strcpy( &syllable[ strlen( syllable ) - strlen( last_unit ) ], "" ); + my $n = length $last_unit; + $syllable =~ s/.{$n}$//; # DOES THIS WORK? + $length_left += length $last_unit; + $current_unit -= 2; + } + elsif ( @saved_pair == 1 ) { + $current_unit--; + } + else { + $units_in_syllable[ $current_unit ] = $unit; + $syllable .= $unit; + } + } + else { + # + # Whoops! Too many tries. + # We set rule_broken so we can loop in the outer loop and try another syllable. + # + $rule_broken = 1; # true + } + + $current_unit++; + } + while ( $tries <= $max_retries and $want_another_unit ); + } + while ( $rule_broken or _illegal_placement( @units_in_syllable ) ); + + return( $syllable, @units_in_syllable ); +} # sub get_syllable + + + +=head2 alt_get_syllable + +Takes an integer, the maximum number of chars to generate. (or is it minimum?) + +returns a list of ( string, units-in-syllable ) + +I<This is an alternative version of C<get_syllable()>, which +can be useful for unit testing the other functions.> + +=cut + +sub alt_get_syllable($) { # alternative version, has no smarts. + my $pwlen = shift; # max or min? + for ( 0 .. $#grams ) { + my $syl = ''; + my @syl_units = (); + while ( @syl_units < 3 ) { + my $unit = _random_unit( NO_SPECIAL_RULE ); + $syl .= $unit; + push @syl_units, $unit; + length($syl) >= $pwlen and return( $syl, @syl_units ); + } + @syl_units and return( $syl, @syl_units ); + } + return(); # failed +} + + +=head2 _illegal_placement + +goes through an individual syllable and checks for illegal +combinations of letters that go beyond looking at digrams. + +We look at things like 3 consecutive vowels or consonants, +or syllables with consonants between vowels +(unless one of them is the final silent e). + +returns boolean. + +=cut + +sub _illegal_placement(@) { + my @units = @_; + + my $vowel_count = 0; + my $failure = 0; # false + + for my $unit_count ( 0 .. $#units ) { + last if $failure; + + if ( $unit_count >= 1 ) { + # + # Don't allow vowels to be split with consonants in a single syllable. + # If we find such a combination (except for the silent e) we have to discard the syllable. + # + if ( + ( + !( $rules{$units[$unit_count-1]} & VOWEL) + && + ( $rules{$units[$unit_count ]} & VOWEL) + && + !(($rules{$units[$unit_count ]} & NO_FINAL_SPLIT) && ($unit_count == $#units)) + && + $vowel_count + ) + || + + # + # Perform these checks when we have at least 3 units. + # + ( + ($unit_count >= 2) + && + ( + # + # Disallow 3 consecutive consonants. + # + ( + !($rules{$units[$unit_count-2]} & VOWEL) + && + !($rules{$units[$unit_count-1]} & VOWEL) + && + !($rules{$units[$unit_count ]} & VOWEL) + ) + || + + # + # Disallow 3 consecutive vowels, where the first is not a y. + # + ( + ( $rules{$units[$unit_count-2]} & VOWEL) + && + !(($rules{$units[0 ]} & ALTERNATE_VOWEL) && ($unit_count == 2)) + && + ( $rules{$units[$unit_count-1]} & VOWEL) + && + ( $rules{$units[$unit_count ]} & VOWEL) + ) + ) + ) + ) { + $failure = 1; # true + } + } + + # + # Count the vowels in the syllable. + # As mentioned somewhere above, exclude the initial y of a syllable. + # Instead, treat it as a consonant. + # + if ( + ($rules{$units[$unit_count]} & VOWEL) + && + !( + ($rules{$units[0]} & ALTERNATE_VOWEL) + && + ($unit_count == 0) + && + (@units > 1) + ) + ) { + $vowel_count++; + } + } + + $failure; +} + +} + +=head1 AUTHOR + +JDPORTER@cpan.org (John Porter) + +=head1 COPYRIGHT + +This perl module is free software; it may be redistributed and/or modified +under the same terms as Perl itself. + +=cut + +unless ( defined caller ) { + +# this can be used for unit testing or to make the module a stand-alone program. +package main; +use Getopt::Long; + +$^W = 1; + +my $algorithm = 'word'; # default: word +my $maxlen = 8; +my $minlen = 6; +my $num_words = 1; +$main::DEBUG = 0; + +GetOptions( + 'seed=s' => \$Crypt::RandPasswd::seed, + 'algorithm=s' => \$algorithm, # select word, letters, chars + 'max=s' => \$maxlen, + 'min=s' => \$minlen, + 'count=s' => \$num_words, + 'debug!' => \$main::DEBUG, +) + or die "Usage: $0 --count N --min N --max N --algorithm [word|letters|chars] --seed N --[no]debug \n"; + +$minlen <= $maxlen or die "minimum word length ($minlen) must be <= maximum ($maxlen)\n"; + +UNIVERSAL::can( "Crypt::RandPasswd", $algorithm ) or die "Invalid algorithm '$algorithm'\n"; + +print STDERR "$num_words '$algorithm' words of $minlen-$maxlen chars \n" + if $main::DEBUG ; + +for ( 1 .. $num_words ) { + my( $unhyphenated_word, $hyphenated_word ) = Crypt::RandPasswd->$algorithm( $minlen, $maxlen ); + + print + $algorithm eq 'word' + ? "$unhyphenated_word ($hyphenated_word)\n" + : "$unhyphenated_word\n"; +} + +} # end of 'main' code. + +1; + diff --git a/cpan/dist/Crypt-RandPasswd/test.pl b/cpan/dist/Crypt-RandPasswd/test.pl new file mode 100644 index 00000000..b1d51244 --- /dev/null +++ b/cpan/dist/Crypt-RandPasswd/test.pl @@ -0,0 +1,35 @@ +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..5\n"; } +END {print "not ok 1\n" unless $loaded;} +use lib 'lib'; +use Crypt::RandPasswd; +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +my( $minlen, $maxlen ) = ( 6, 8 ); + +my( $unhyphenated_word, $hyphenated_word ) = Crypt::RandPasswd->word( $minlen, $maxlen ); +print "ok 2\n"; + +$unhyphenated_word = Crypt::RandPasswd->word( $minlen, $maxlen ); +print "ok 3\n"; + +$unhyphenated_word = Crypt::RandPasswd->letters( $minlen, $maxlen ); +print "ok 4\n"; + +$unhyphenated_word = Crypt::RandPasswd->chars( $minlen, $maxlen ); +print "ok 5\n"; + |
