File Coverage

blib/lib/Crypt/RandPasswd.pm
Criterion Covered Total %
statement 234 260 90.0
branch 89 116 76.7
condition 130 168 77.3
subroutine 39 40 97.5
pod 10 12 83.3
total 502 596 84.2


line stmt bran cond sub pod time code
1             {
2              
3             package Crypt::RandPasswd;
4              
5 3     3   3523 use 5.006;
  3         12  
  3         127  
6 3     3   16 use strict;
  3         5  
  3         129  
7 3     3   16 use warnings;
  3         7  
  3         102  
8              
9 3     3   15 use vars qw($VERSION);
  3         6  
  3         1057  
10              
11             $VERSION = '0.06';
12              
13              
14             =head1 NAME
15              
16             Crypt::RandPasswd - random password generator based on FIPS-181
17              
18             =head1 SYNOPSIS
19              
20             use Crypt::RandPasswd;
21             ( $word, $hyphenated ) = Crypt::RandPasswd->word( $minlen, $maxlen );
22             $word = Crypt::RandPasswd->word( $minlen, $maxlen );
23             $word = Crypt::RandPasswd->letters( $minlen, $maxlen );
24             $word = Crypt::RandPasswd->chars( $minlen, $maxlen );
25              
26             # override the defaults for these functions:
27             *Crypt::RandPasswd::rng = \&my_random_number_generator;
28             *Crypt::RandPasswd::restrict = \&my_restriction_filter;
29              
30             =head1 DESCRIPTION
31              
32             Crypt::RandPasswd provides three functions that can be used
33             to generate random passwords, constructed from words,
34             letters, or characters.
35              
36             This code is a Perl implementation of the Automated
37             Password Generator standard, like the program described in
38             "A Random Word Generator For Pronounceable Passwords" (not available on-line).
39             This code is a re-engineering of the program contained in Appendix A
40             of FIPS Publication 181, "Standard for Automated Password Generator".
41             In accordance with the standard, the results obtained from this
42             program are logically equivalent to those produced by the standard.
43              
44             =head1 CAVEATS
45              
46             =head2 Bugs
47              
48             The function to generate a password can sometimes take an extremely long time.
49              
50             =head2 Deviations From Standard
51              
52             This implementation deviates in one critical way from the standard
53             upon which it is based: the random number generator in this
54             implementation does not use DES. Instead, it uses perl's built-in
55             C function, which in turn is (usually) built on the
56             pseudo-random number generator functions of the underlying C library.
57              
58             However, the random function can be replaced by the user if desired.
59             (See L.)
60              
61             =head1 Functions
62              
63             =cut
64              
65              
66             sub word($$);
67             sub letters($$);
68             sub chars($$);
69              
70             sub random_chars_in_range($$$$);
71             sub rand_int_in_range($$);
72             sub random_element($);
73              
74             sub rng($);
75             sub restrict($);
76             sub init();
77              
78              
79             sub _random_word($);
80             sub _random_unit($);
81             sub _improper_word(@);
82             sub _have_initial_y(@);
83             sub _have_final_split(@);
84             sub _illegal_placement(@);
85              
86              
87             #
88             # Global Variables:
89             #
90              
91             $Crypt::RandPasswd::seed = undef; # by default; causes srand() to use its own, which can be pretty good.
92             $Crypt::RandPasswd::initialized = 0;
93              
94              
95              
96             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 );
97             my %grams; @grams{@grams} = (); # and a set of same.
98              
99             my @vowel_grams = qw( a e i o u y );
100             my %vowel_grams; @vowel_grams{@vowel_grams} = (); # and a set of same.
101              
102              
103              
104             #
105             # Bit flags
106             #
107              
108 3     3   24 use constant MAX_UNACCEPTABLE => 20 ;
  3         7  
  3         5690  
109              
110             # gram rules:
111 3     3   26 use constant NOT_BEGIN_SYLLABLE => 010 ;
  3         13  
  3         157  
112 3     3   17 use constant NO_FINAL_SPLIT => 004 ;
  3         7  
  3         147  
113 3     3   18 use constant VOWEL => 002 ;
  3         5  
  3         143  
114 3     3   18 use constant ALTERNATE_VOWEL => 001 ;
  3         6  
  3         142  
115 3     3   60 use constant NO_SPECIAL_RULE => 000 ;
  3         6  
  3         140  
116              
117             # digram rules:
118 3     3   15 use constant FRONT => 0200 ;
  3         7  
  3         142  
119 3     3   17 use constant NOT_FRONT => 0100 ;
  3         4  
  3         125  
120 3     3   15 use constant BREAK => 0040 ;
  3         6  
  3         169  
121 3     3   28 use constant PREFIX => 0020 ;
  3         7  
  3         164  
122 3     3   18 use constant ILLEGAL_PAIR => 0010 ;
  3         5  
  3         137  
123 3     3   16 use constant SUFFIX => 0004 ;
  3         7  
  3         1539  
124 3     3   19 use constant BACK => 0002 ;
  3         5  
  3         148  
125 3     3   17 use constant NOT_BACK => 0001 ;
  3         80  
  3         151  
126 3     3   16 use constant ANY_COMBINATION => 0000 ;
  3         6  
  3         96619  
127              
128             ## it used to be that info about units was contained in the C-arrays 'rules' and 'digram'.
129             ## both were indexed numerically. 'rules' was essentially a mapping from a unique
130             ## integer ID (the index) to a gram. 'digram' used the same mapping, but in a
131             ## two-dimensional array. I.e. to represent the digram "ab" ("a","b"), one would
132             ## need to know the numeric ID of "a" and "b", which turn out to be 0 and 1, respectively;
133             ## then use those indices in digram: digram[0][1].
134             ## The information at the "end" of a lookup in digram[][] was a simple integer
135             ## representing the flag bits for that digram. (The %digram in the current
136             ## implementation is the same.) The rules[] C-array, however, needed to store
137             ## both the bitmask and the string representation of the gram, so it was an array
138             ## of a struct { string, bitmask }. Since %rules is an associative array, indexed
139             ## directly by the gram, it only needs the bitmask at its "end", the same as %digram.
140             ##
141             ## both 'rules' and 'digram' contained bitflags for grams and digrams, respectively.
142             ## additionally, 'rules' contained the string representation of the unit.
143             ## because 'rules' contained both a string and flags for each unit, its contents
144             ## were actually structs of { string, flags }.
145             ##
146             ## 'digram', on the other hand, was simply the bitflags (integers).
147              
148             # struct unit {
149             # char unit_code[5]; # string, usually 1, but up to 4 characters.
150             # byte flags;
151             # } rules[34];
152              
153             ## the 'rules' C-array used to be indexed by gram index; now %rules is indexed by the gram itself.
154              
155             my %rules;
156              
157             @rules{ @grams } = ( NO_SPECIAL_RULE ) x @grams;
158             @rules{ @vowel_grams } = ( VOWEL ) x @vowel_grams;
159              
160             $rules{'e'} |= NO_FINAL_SPLIT;
161             $rules{'y'} |= ALTERNATE_VOWEL;
162              
163             $rules{'x'} =
164             $rules{'ck'} = NOT_BEGIN_SYLLABLE;
165              
166              
167              
168             #
169             # the 'digram' C-array, digram[34][34], was indexed by the unit indexes of the two grams;
170             # now %digram is indexed directly by the two grams.
171             #
172             my %digram;
173              
174             ##############################################################################################
175             # BEGIN DIGRAM {
176             ##############################################################################################
177              
178             $digram{'a'}{'a'} = ILLEGAL_PAIR;
179             $digram{'a'}{'b'} = ANY_COMBINATION;
180             $digram{'a'}{'c'} = ANY_COMBINATION;
181             $digram{'a'}{'d'} = ANY_COMBINATION;
182             $digram{'a'}{'e'} = ILLEGAL_PAIR;
183             $digram{'a'}{'f'} = ANY_COMBINATION;
184             $digram{'a'}{'g'} = ANY_COMBINATION;
185             $digram{'a'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
186             $digram{'a'}{'i'} = ANY_COMBINATION;
187             $digram{'a'}{'j'} = ANY_COMBINATION;
188             $digram{'a'}{'k'} = ANY_COMBINATION;
189             $digram{'a'}{'l'} = ANY_COMBINATION;
190             $digram{'a'}{'m'} = ANY_COMBINATION;
191             $digram{'a'}{'n'} = ANY_COMBINATION;
192             $digram{'a'}{'o'} = ILLEGAL_PAIR;
193             $digram{'a'}{'p'} = ANY_COMBINATION;
194             $digram{'a'}{'r'} = ANY_COMBINATION;
195             $digram{'a'}{'s'} = ANY_COMBINATION;
196             $digram{'a'}{'t'} = ANY_COMBINATION;
197             $digram{'a'}{'u'} = ANY_COMBINATION;
198             $digram{'a'}{'v'} = ANY_COMBINATION;
199             $digram{'a'}{'w'} = ANY_COMBINATION;
200             $digram{'a'}{'x'} = ANY_COMBINATION;
201             $digram{'a'}{'y'} = ANY_COMBINATION;
202             $digram{'a'}{'z'} = ANY_COMBINATION;
203             $digram{'a'}{'ch'} = ANY_COMBINATION;
204             $digram{'a'}{'gh'} = ILLEGAL_PAIR;
205             $digram{'a'}{'ph'} = ANY_COMBINATION;
206             $digram{'a'}{'rh'} = ILLEGAL_PAIR;
207             $digram{'a'}{'sh'} = ANY_COMBINATION;
208             $digram{'a'}{'th'} = ANY_COMBINATION;
209             $digram{'a'}{'wh'} = ILLEGAL_PAIR;
210             $digram{'a'}{'qu'} = BREAK | NOT_BACK;
211             $digram{'a'}{'ck'} = ANY_COMBINATION;
212              
213             $digram{'b'}{'a'} = ANY_COMBINATION;
214             $digram{'b'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
215             $digram{'b'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
216             $digram{'b'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
217             $digram{'b'}{'e'} = ANY_COMBINATION;
218             $digram{'b'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
219             $digram{'b'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
220             $digram{'b'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
221             $digram{'b'}{'i'} = ANY_COMBINATION;
222             $digram{'b'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
223             $digram{'b'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
224             $digram{'b'}{'l'} = FRONT | SUFFIX | NOT_BACK;
225             $digram{'b'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
226             $digram{'b'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
227             $digram{'b'}{'o'} = ANY_COMBINATION;
228             $digram{'b'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
229             $digram{'b'}{'r'} = FRONT | BACK;
230             $digram{'b'}{'s'} = NOT_FRONT;
231             $digram{'b'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
232             $digram{'b'}{'u'} = ANY_COMBINATION;
233             $digram{'b'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
234             $digram{'b'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
235             $digram{'b'}{'x'} = ILLEGAL_PAIR;
236             $digram{'b'}{'y'} = ANY_COMBINATION;
237             $digram{'b'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
238             $digram{'b'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
239             $digram{'b'}{'gh'} = ILLEGAL_PAIR;
240             $digram{'b'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
241             $digram{'b'}{'rh'} = ILLEGAL_PAIR;
242             $digram{'b'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
243             $digram{'b'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
244             $digram{'b'}{'wh'} = ILLEGAL_PAIR;
245             $digram{'b'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
246             $digram{'b'}{'ck'} = ILLEGAL_PAIR;
247              
248             $digram{'c'}{'a'} = ANY_COMBINATION;
249             $digram{'c'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
250             $digram{'c'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
251             $digram{'c'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
252             $digram{'c'}{'e'} = ANY_COMBINATION;
253             $digram{'c'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
254             $digram{'c'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
255             $digram{'c'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
256             $digram{'c'}{'i'} = ANY_COMBINATION;
257             $digram{'c'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
258             $digram{'c'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
259             $digram{'c'}{'l'} = SUFFIX | NOT_BACK;
260             $digram{'c'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
261             $digram{'c'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
262             $digram{'c'}{'o'} = ANY_COMBINATION;
263             $digram{'c'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
264             $digram{'c'}{'r'} = NOT_BACK;
265             $digram{'c'}{'s'} = NOT_FRONT | BACK;
266             $digram{'c'}{'t'} = NOT_FRONT | PREFIX;
267             $digram{'c'}{'u'} = ANY_COMBINATION;
268             $digram{'c'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
269             $digram{'c'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
270             $digram{'c'}{'x'} = ILLEGAL_PAIR;
271             $digram{'c'}{'y'} = ANY_COMBINATION;
272             $digram{'c'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
273             $digram{'c'}{'ch'} = ILLEGAL_PAIR;
274             $digram{'c'}{'gh'} = ILLEGAL_PAIR;
275             $digram{'c'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
276             $digram{'c'}{'rh'} = ILLEGAL_PAIR;
277             $digram{'c'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
278             $digram{'c'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
279             $digram{'c'}{'wh'} = ILLEGAL_PAIR;
280             $digram{'c'}{'qu'} = NOT_FRONT | SUFFIX | NOT_BACK;
281             $digram{'c'}{'ck'} = ILLEGAL_PAIR;
282              
283             $digram{'d'}{'a'} = ANY_COMBINATION;
284             $digram{'d'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
285             $digram{'d'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
286             $digram{'d'}{'d'} = NOT_FRONT;
287             $digram{'d'}{'e'} = ANY_COMBINATION;
288             $digram{'d'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
289             $digram{'d'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
290             $digram{'d'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
291             $digram{'d'}{'i'} = ANY_COMBINATION;
292             $digram{'d'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
293             $digram{'d'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
294             $digram{'d'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
295             $digram{'d'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
296             $digram{'d'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
297             $digram{'d'}{'o'} = ANY_COMBINATION;
298             $digram{'d'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
299             $digram{'d'}{'r'} = FRONT | NOT_BACK;
300             $digram{'d'}{'s'} = NOT_FRONT | BACK;
301             $digram{'d'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
302             $digram{'d'}{'u'} = ANY_COMBINATION;
303             $digram{'d'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
304             $digram{'d'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
305             $digram{'d'}{'x'} = ILLEGAL_PAIR;
306             $digram{'d'}{'y'} = ANY_COMBINATION;
307             $digram{'d'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
308             $digram{'d'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
309             $digram{'d'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
310             $digram{'d'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
311             $digram{'d'}{'rh'} = ILLEGAL_PAIR;
312             $digram{'d'}{'sh'} = NOT_FRONT | NOT_BACK;
313             $digram{'d'}{'th'} = NOT_FRONT | PREFIX;
314             $digram{'d'}{'wh'} = ILLEGAL_PAIR;
315             $digram{'d'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
316             $digram{'d'}{'ck'} = ILLEGAL_PAIR;
317              
318             $digram{'e'}{'a'} = ANY_COMBINATION;
319             $digram{'e'}{'b'} = ANY_COMBINATION;
320             $digram{'e'}{'c'} = ANY_COMBINATION;
321             $digram{'e'}{'d'} = ANY_COMBINATION;
322             $digram{'e'}{'e'} = ANY_COMBINATION;
323             $digram{'e'}{'f'} = ANY_COMBINATION;
324             $digram{'e'}{'g'} = ANY_COMBINATION;
325             $digram{'e'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
326             $digram{'e'}{'i'} = NOT_BACK;
327             $digram{'e'}{'j'} = ANY_COMBINATION;
328             $digram{'e'}{'k'} = ANY_COMBINATION;
329             $digram{'e'}{'l'} = ANY_COMBINATION;
330             $digram{'e'}{'m'} = ANY_COMBINATION;
331             $digram{'e'}{'n'} = ANY_COMBINATION;
332             $digram{'e'}{'o'} = BREAK;
333             $digram{'e'}{'p'} = ANY_COMBINATION;
334             $digram{'e'}{'r'} = ANY_COMBINATION;
335             $digram{'e'}{'s'} = ANY_COMBINATION;
336             $digram{'e'}{'t'} = ANY_COMBINATION;
337             $digram{'e'}{'u'} = ANY_COMBINATION;
338             $digram{'e'}{'v'} = ANY_COMBINATION;
339             $digram{'e'}{'w'} = ANY_COMBINATION;
340             $digram{'e'}{'x'} = ANY_COMBINATION;
341             $digram{'e'}{'y'} = ANY_COMBINATION;
342             $digram{'e'}{'z'} = ANY_COMBINATION;
343             $digram{'e'}{'ch'} = ANY_COMBINATION;
344             $digram{'e'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
345             $digram{'e'}{'ph'} = ANY_COMBINATION;
346             $digram{'e'}{'rh'} = ILLEGAL_PAIR;
347             $digram{'e'}{'sh'} = ANY_COMBINATION;
348             $digram{'e'}{'th'} = ANY_COMBINATION;
349             $digram{'e'}{'wh'} = ILLEGAL_PAIR;
350             $digram{'e'}{'qu'} = BREAK | NOT_BACK;
351             $digram{'e'}{'ck'} = ANY_COMBINATION;
352              
353             $digram{'f'}{'a'} = ANY_COMBINATION;
354             $digram{'f'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
355             $digram{'f'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
356             $digram{'f'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
357             $digram{'f'}{'e'} = ANY_COMBINATION;
358             $digram{'f'}{'f'} = NOT_FRONT;
359             $digram{'f'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
360             $digram{'f'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
361             $digram{'f'}{'i'} = ANY_COMBINATION;
362             $digram{'f'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
363             $digram{'f'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
364             $digram{'f'}{'l'} = FRONT | SUFFIX | NOT_BACK;
365             $digram{'f'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
366             $digram{'f'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
367             $digram{'f'}{'o'} = ANY_COMBINATION;
368             $digram{'f'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
369             $digram{'f'}{'r'} = FRONT | NOT_BACK;
370             $digram{'f'}{'s'} = NOT_FRONT;
371             $digram{'f'}{'t'} = NOT_FRONT;
372             $digram{'f'}{'u'} = ANY_COMBINATION;
373             $digram{'f'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
374             $digram{'f'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
375             $digram{'f'}{'x'} = ILLEGAL_PAIR;
376             $digram{'f'}{'y'} = NOT_FRONT;
377             $digram{'f'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
378             $digram{'f'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
379             $digram{'f'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
380             $digram{'f'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
381             $digram{'f'}{'rh'} = ILLEGAL_PAIR;
382             $digram{'f'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
383             $digram{'f'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
384             $digram{'f'}{'wh'} = ILLEGAL_PAIR;
385             $digram{'f'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
386             $digram{'f'}{'ck'} = ILLEGAL_PAIR;
387              
388             $digram{'g'}{'a'} = ANY_COMBINATION;
389             $digram{'g'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
390             $digram{'g'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
391             $digram{'g'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
392             $digram{'g'}{'e'} = ANY_COMBINATION;
393             $digram{'g'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
394             $digram{'g'}{'g'} = NOT_FRONT;
395             $digram{'g'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
396             $digram{'g'}{'i'} = ANY_COMBINATION;
397             $digram{'g'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
398             $digram{'g'}{'k'} = ILLEGAL_PAIR;
399             $digram{'g'}{'l'} = FRONT | SUFFIX | NOT_BACK;
400             $digram{'g'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
401             $digram{'g'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
402             $digram{'g'}{'o'} = ANY_COMBINATION;
403             $digram{'g'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
404             $digram{'g'}{'r'} = FRONT | NOT_BACK;
405             $digram{'g'}{'s'} = NOT_FRONT | BACK;
406             $digram{'g'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
407             $digram{'g'}{'u'} = ANY_COMBINATION;
408             $digram{'g'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
409             $digram{'g'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
410             $digram{'g'}{'x'} = ILLEGAL_PAIR;
411             $digram{'g'}{'y'} = NOT_FRONT;
412             $digram{'g'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
413             $digram{'g'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
414             $digram{'g'}{'gh'} = ILLEGAL_PAIR;
415             $digram{'g'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
416             $digram{'g'}{'rh'} = ILLEGAL_PAIR;
417             $digram{'g'}{'sh'} = NOT_FRONT;
418             $digram{'g'}{'th'} = NOT_FRONT;
419             $digram{'g'}{'wh'} = ILLEGAL_PAIR;
420             $digram{'g'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
421             $digram{'g'}{'ck'} = ILLEGAL_PAIR;
422              
423             $digram{'h'}{'a'} = ANY_COMBINATION;
424             $digram{'h'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
425             $digram{'h'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
426             $digram{'h'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
427             $digram{'h'}{'e'} = ANY_COMBINATION;
428             $digram{'h'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
429             $digram{'h'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
430             $digram{'h'}{'h'} = ILLEGAL_PAIR;
431             $digram{'h'}{'i'} = ANY_COMBINATION;
432             $digram{'h'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
433             $digram{'h'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
434             $digram{'h'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
435             $digram{'h'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
436             $digram{'h'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
437             $digram{'h'}{'o'} = ANY_COMBINATION;
438             $digram{'h'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
439             $digram{'h'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
440             $digram{'h'}{'s'} = NOT_FRONT | BREAK | NOT_BACK;
441             $digram{'h'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
442             $digram{'h'}{'u'} = ANY_COMBINATION;
443             $digram{'h'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
444             $digram{'h'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
445             $digram{'h'}{'x'} = ILLEGAL_PAIR;
446             $digram{'h'}{'y'} = ANY_COMBINATION;
447             $digram{'h'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
448             $digram{'h'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
449             $digram{'h'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
450             $digram{'h'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
451             $digram{'h'}{'rh'} = ILLEGAL_PAIR;
452             $digram{'h'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
453             $digram{'h'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
454             $digram{'h'}{'wh'} = ILLEGAL_PAIR;
455             $digram{'h'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
456             $digram{'h'}{'ck'} = ILLEGAL_PAIR;
457              
458             $digram{'i'}{'a'} = ANY_COMBINATION;
459             $digram{'i'}{'b'} = ANY_COMBINATION;
460             $digram{'i'}{'c'} = ANY_COMBINATION;
461             $digram{'i'}{'d'} = ANY_COMBINATION;
462             $digram{'i'}{'e'} = NOT_FRONT;
463             $digram{'i'}{'f'} = ANY_COMBINATION;
464             $digram{'i'}{'g'} = ANY_COMBINATION;
465             $digram{'i'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
466             $digram{'i'}{'i'} = ILLEGAL_PAIR;
467             $digram{'i'}{'j'} = ANY_COMBINATION;
468             $digram{'i'}{'k'} = ANY_COMBINATION;
469             $digram{'i'}{'l'} = ANY_COMBINATION;
470             $digram{'i'}{'m'} = ANY_COMBINATION;
471             $digram{'i'}{'n'} = ANY_COMBINATION;
472             $digram{'i'}{'o'} = BREAK;
473             $digram{'i'}{'p'} = ANY_COMBINATION;
474             $digram{'i'}{'r'} = ANY_COMBINATION;
475             $digram{'i'}{'s'} = ANY_COMBINATION;
476             $digram{'i'}{'t'} = ANY_COMBINATION;
477             $digram{'i'}{'u'} = NOT_FRONT | BREAK | NOT_BACK;
478             $digram{'i'}{'v'} = ANY_COMBINATION;
479             $digram{'i'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
480             $digram{'i'}{'x'} = ANY_COMBINATION;
481             $digram{'i'}{'y'} = NOT_FRONT | BREAK | NOT_BACK;
482             $digram{'i'}{'z'} = ANY_COMBINATION;
483             $digram{'i'}{'ch'} = ANY_COMBINATION;
484             $digram{'i'}{'gh'} = NOT_FRONT;
485             $digram{'i'}{'ph'} = ANY_COMBINATION;
486             $digram{'i'}{'rh'} = ILLEGAL_PAIR;
487             $digram{'i'}{'sh'} = ANY_COMBINATION;
488             $digram{'i'}{'th'} = ANY_COMBINATION;
489             $digram{'i'}{'wh'} = ILLEGAL_PAIR;
490             $digram{'i'}{'qu'} = BREAK | NOT_BACK;
491             $digram{'i'}{'ck'} = ANY_COMBINATION;
492              
493             $digram{'j'}{'a'} = ANY_COMBINATION;
494             $digram{'j'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
495             $digram{'j'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
496             $digram{'j'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
497             $digram{'j'}{'e'} = ANY_COMBINATION;
498             $digram{'j'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
499             $digram{'j'}{'g'} = ILLEGAL_PAIR;
500             $digram{'j'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
501             $digram{'j'}{'i'} = ANY_COMBINATION;
502             $digram{'j'}{'j'} = ILLEGAL_PAIR;
503             $digram{'j'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
504             $digram{'j'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
505             $digram{'j'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
506             $digram{'j'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
507             $digram{'j'}{'o'} = ANY_COMBINATION;
508             $digram{'j'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
509             $digram{'j'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
510             $digram{'j'}{'s'} = NOT_FRONT | BREAK | NOT_BACK;
511             $digram{'j'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
512             $digram{'j'}{'u'} = ANY_COMBINATION;
513             $digram{'j'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
514             $digram{'j'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
515             $digram{'j'}{'x'} = ILLEGAL_PAIR;
516             $digram{'j'}{'y'} = NOT_FRONT;
517             $digram{'j'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
518             $digram{'j'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
519             $digram{'j'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
520             $digram{'j'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
521             $digram{'j'}{'rh'} = ILLEGAL_PAIR;
522             $digram{'j'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
523             $digram{'j'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
524             $digram{'j'}{'wh'} = ILLEGAL_PAIR;
525             $digram{'j'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
526             $digram{'j'}{'ck'} = ILLEGAL_PAIR;
527              
528             $digram{'k'}{'a'} = ANY_COMBINATION;
529             $digram{'k'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
530             $digram{'k'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
531             $digram{'k'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
532             $digram{'k'}{'e'} = ANY_COMBINATION;
533             $digram{'k'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
534             $digram{'k'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
535             $digram{'k'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
536             $digram{'k'}{'i'} = ANY_COMBINATION;
537             $digram{'k'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
538             $digram{'k'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
539             $digram{'k'}{'l'} = SUFFIX | NOT_BACK;
540             $digram{'k'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
541             $digram{'k'}{'n'} = FRONT | SUFFIX | NOT_BACK;
542             $digram{'k'}{'o'} = ANY_COMBINATION;
543             $digram{'k'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
544             $digram{'k'}{'r'} = SUFFIX | NOT_BACK;
545             $digram{'k'}{'s'} = NOT_FRONT | BACK;
546             $digram{'k'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
547             $digram{'k'}{'u'} = ANY_COMBINATION;
548             $digram{'k'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
549             $digram{'k'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
550             $digram{'k'}{'x'} = ILLEGAL_PAIR;
551             $digram{'k'}{'y'} = NOT_FRONT;
552             $digram{'k'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
553             $digram{'k'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
554             $digram{'k'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
555             $digram{'k'}{'ph'} = NOT_FRONT | PREFIX;
556             $digram{'k'}{'rh'} = ILLEGAL_PAIR;
557             $digram{'k'}{'sh'} = NOT_FRONT;
558             $digram{'k'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
559             $digram{'k'}{'wh'} = ILLEGAL_PAIR;
560             $digram{'k'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
561             $digram{'k'}{'ck'} = ILLEGAL_PAIR;
562              
563             $digram{'l'}{'a'} = ANY_COMBINATION;
564             $digram{'l'}{'b'} = NOT_FRONT | PREFIX;
565             $digram{'l'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
566             $digram{'l'}{'d'} = NOT_FRONT | PREFIX;
567             $digram{'l'}{'e'} = ANY_COMBINATION;
568             $digram{'l'}{'f'} = NOT_FRONT | PREFIX;
569             $digram{'l'}{'g'} = NOT_FRONT | PREFIX;
570             $digram{'l'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
571             $digram{'l'}{'i'} = ANY_COMBINATION;
572             $digram{'l'}{'j'} = NOT_FRONT | PREFIX;
573             $digram{'l'}{'k'} = NOT_FRONT | PREFIX;
574             $digram{'l'}{'l'} = NOT_FRONT | PREFIX;
575             $digram{'l'}{'m'} = NOT_FRONT | PREFIX;
576             $digram{'l'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
577             $digram{'l'}{'o'} = ANY_COMBINATION;
578             $digram{'l'}{'p'} = NOT_FRONT | PREFIX;
579             $digram{'l'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
580             $digram{'l'}{'s'} = NOT_FRONT;
581             $digram{'l'}{'t'} = NOT_FRONT | PREFIX;
582             $digram{'l'}{'u'} = ANY_COMBINATION;
583             $digram{'l'}{'v'} = NOT_FRONT | PREFIX;
584             $digram{'l'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
585             $digram{'l'}{'x'} = ILLEGAL_PAIR;
586             $digram{'l'}{'y'} = ANY_COMBINATION;
587             $digram{'l'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
588             $digram{'l'}{'ch'} = NOT_FRONT | PREFIX;
589             $digram{'l'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
590             $digram{'l'}{'ph'} = NOT_FRONT | PREFIX;
591             $digram{'l'}{'rh'} = ILLEGAL_PAIR;
592             $digram{'l'}{'sh'} = NOT_FRONT | PREFIX;
593             $digram{'l'}{'th'} = NOT_FRONT | PREFIX;
594             $digram{'l'}{'wh'} = ILLEGAL_PAIR;
595             $digram{'l'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
596             $digram{'l'}{'ck'} = ILLEGAL_PAIR;
597              
598             $digram{'m'}{'a'} = ANY_COMBINATION;
599             $digram{'m'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
600             $digram{'m'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
601             $digram{'m'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
602             $digram{'m'}{'e'} = ANY_COMBINATION;
603             $digram{'m'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
604             $digram{'m'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
605             $digram{'m'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
606             $digram{'m'}{'i'} = ANY_COMBINATION;
607             $digram{'m'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
608             $digram{'m'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
609             $digram{'m'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
610             $digram{'m'}{'m'} = NOT_FRONT;
611             $digram{'m'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
612             $digram{'m'}{'o'} = ANY_COMBINATION;
613             $digram{'m'}{'p'} = NOT_FRONT;
614             $digram{'m'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
615             $digram{'m'}{'s'} = NOT_FRONT;
616             $digram{'m'}{'t'} = NOT_FRONT;
617             $digram{'m'}{'u'} = ANY_COMBINATION;
618             $digram{'m'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
619             $digram{'m'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
620             $digram{'m'}{'x'} = ILLEGAL_PAIR;
621             $digram{'m'}{'y'} = ANY_COMBINATION;
622             $digram{'m'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
623             $digram{'m'}{'ch'} = NOT_FRONT | PREFIX;
624             $digram{'m'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
625             $digram{'m'}{'ph'} = NOT_FRONT;
626             $digram{'m'}{'rh'} = ILLEGAL_PAIR;
627             $digram{'m'}{'sh'} = NOT_FRONT;
628             $digram{'m'}{'th'} = NOT_FRONT;
629             $digram{'m'}{'wh'} = ILLEGAL_PAIR;
630             $digram{'m'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
631             $digram{'m'}{'ck'} = ILLEGAL_PAIR;
632              
633             $digram{'n'}{'a'} = ANY_COMBINATION;
634             $digram{'n'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
635             $digram{'n'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
636             $digram{'n'}{'d'} = NOT_FRONT;
637             $digram{'n'}{'e'} = ANY_COMBINATION;
638             $digram{'n'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
639             $digram{'n'}{'g'} = NOT_FRONT | PREFIX;
640             $digram{'n'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
641             $digram{'n'}{'i'} = ANY_COMBINATION;
642             $digram{'n'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
643             $digram{'n'}{'k'} = NOT_FRONT | PREFIX;
644             $digram{'n'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
645             $digram{'n'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
646             $digram{'n'}{'n'} = NOT_FRONT;
647             $digram{'n'}{'o'} = ANY_COMBINATION;
648             $digram{'n'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
649             $digram{'n'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
650             $digram{'n'}{'s'} = NOT_FRONT;
651             $digram{'n'}{'t'} = NOT_FRONT;
652             $digram{'n'}{'u'} = ANY_COMBINATION;
653             $digram{'n'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
654             $digram{'n'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
655             $digram{'n'}{'x'} = ILLEGAL_PAIR;
656             $digram{'n'}{'y'} = NOT_FRONT;
657             $digram{'n'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
658             $digram{'n'}{'ch'} = NOT_FRONT | PREFIX;
659             $digram{'n'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
660             $digram{'n'}{'ph'} = NOT_FRONT | PREFIX;
661             $digram{'n'}{'rh'} = ILLEGAL_PAIR;
662             $digram{'n'}{'sh'} = NOT_FRONT;
663             $digram{'n'}{'th'} = NOT_FRONT;
664             $digram{'n'}{'wh'} = ILLEGAL_PAIR;
665             $digram{'n'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
666             $digram{'n'}{'ck'} = NOT_FRONT | PREFIX;
667              
668             $digram{'o'}{'a'} = ANY_COMBINATION;
669             $digram{'o'}{'b'} = ANY_COMBINATION;
670             $digram{'o'}{'c'} = ANY_COMBINATION;
671             $digram{'o'}{'d'} = ANY_COMBINATION;
672             $digram{'o'}{'e'} = ILLEGAL_PAIR;
673             $digram{'o'}{'f'} = ANY_COMBINATION;
674             $digram{'o'}{'g'} = ANY_COMBINATION;
675             $digram{'o'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
676             $digram{'o'}{'i'} = ANY_COMBINATION;
677             $digram{'o'}{'j'} = ANY_COMBINATION;
678             $digram{'o'}{'k'} = ANY_COMBINATION;
679             $digram{'o'}{'l'} = ANY_COMBINATION;
680             $digram{'o'}{'m'} = ANY_COMBINATION;
681             $digram{'o'}{'n'} = ANY_COMBINATION;
682             $digram{'o'}{'o'} = ANY_COMBINATION;
683             $digram{'o'}{'p'} = ANY_COMBINATION;
684             $digram{'o'}{'r'} = ANY_COMBINATION;
685             $digram{'o'}{'s'} = ANY_COMBINATION;
686             $digram{'o'}{'t'} = ANY_COMBINATION;
687             $digram{'o'}{'u'} = ANY_COMBINATION;
688             $digram{'o'}{'v'} = ANY_COMBINATION;
689             $digram{'o'}{'w'} = ANY_COMBINATION;
690             $digram{'o'}{'x'} = ANY_COMBINATION;
691             $digram{'o'}{'y'} = ANY_COMBINATION;
692             $digram{'o'}{'z'} = ANY_COMBINATION;
693             $digram{'o'}{'ch'} = ANY_COMBINATION;
694             $digram{'o'}{'gh'} = NOT_FRONT;
695             $digram{'o'}{'ph'} = ANY_COMBINATION;
696             $digram{'o'}{'rh'} = ILLEGAL_PAIR;
697             $digram{'o'}{'sh'} = ANY_COMBINATION;
698             $digram{'o'}{'th'} = ANY_COMBINATION;
699             $digram{'o'}{'wh'} = ILLEGAL_PAIR;
700             $digram{'o'}{'qu'} = BREAK | NOT_BACK;
701             $digram{'o'}{'ck'} = ANY_COMBINATION;
702              
703             $digram{'p'}{'a'} = ANY_COMBINATION;
704             $digram{'p'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
705             $digram{'p'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
706             $digram{'p'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
707             $digram{'p'}{'e'} = ANY_COMBINATION;
708             $digram{'p'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
709             $digram{'p'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
710             $digram{'p'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
711             $digram{'p'}{'i'} = ANY_COMBINATION;
712             $digram{'p'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
713             $digram{'p'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
714             $digram{'p'}{'l'} = SUFFIX | NOT_BACK;
715             $digram{'p'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
716             $digram{'p'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
717             $digram{'p'}{'o'} = ANY_COMBINATION;
718             $digram{'p'}{'p'} = NOT_FRONT | PREFIX;
719             $digram{'p'}{'r'} = NOT_BACK;
720             $digram{'p'}{'s'} = NOT_FRONT | BACK;
721             $digram{'p'}{'t'} = NOT_FRONT | BACK;
722             $digram{'p'}{'u'} = NOT_FRONT | BACK;
723             $digram{'p'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
724             $digram{'p'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
725             $digram{'p'}{'x'} = ILLEGAL_PAIR;
726             $digram{'p'}{'y'} = ANY_COMBINATION;
727             $digram{'p'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
728             $digram{'p'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
729             $digram{'p'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
730             $digram{'p'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
731             $digram{'p'}{'rh'} = ILLEGAL_PAIR;
732             $digram{'p'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
733             $digram{'p'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
734             $digram{'p'}{'wh'} = ILLEGAL_PAIR;
735             $digram{'p'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
736             $digram{'p'}{'ck'} = ILLEGAL_PAIR;
737              
738             $digram{'r'}{'a'} = ANY_COMBINATION;
739             $digram{'r'}{'b'} = NOT_FRONT | PREFIX;
740             $digram{'r'}{'c'} = NOT_FRONT | PREFIX;
741             $digram{'r'}{'d'} = NOT_FRONT | PREFIX;
742             $digram{'r'}{'e'} = ANY_COMBINATION;
743             $digram{'r'}{'f'} = NOT_FRONT | PREFIX;
744             $digram{'r'}{'g'} = NOT_FRONT | PREFIX;
745             $digram{'r'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
746             $digram{'r'}{'i'} = ANY_COMBINATION;
747             $digram{'r'}{'j'} = NOT_FRONT | PREFIX;
748             $digram{'r'}{'k'} = NOT_FRONT | PREFIX;
749             $digram{'r'}{'l'} = NOT_FRONT | PREFIX;
750             $digram{'r'}{'m'} = NOT_FRONT | PREFIX;
751             $digram{'r'}{'n'} = NOT_FRONT | PREFIX;
752             $digram{'r'}{'o'} = ANY_COMBINATION;
753             $digram{'r'}{'p'} = NOT_FRONT | PREFIX;
754             $digram{'r'}{'r'} = NOT_FRONT | PREFIX;
755             $digram{'r'}{'s'} = NOT_FRONT | PREFIX;
756             $digram{'r'}{'t'} = NOT_FRONT | PREFIX;
757             $digram{'r'}{'u'} = ANY_COMBINATION;
758             $digram{'r'}{'v'} = NOT_FRONT | PREFIX;
759             $digram{'r'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
760             $digram{'r'}{'x'} = ILLEGAL_PAIR;
761             $digram{'r'}{'y'} = ANY_COMBINATION;
762             $digram{'r'}{'z'} = NOT_FRONT | PREFIX;
763             $digram{'r'}{'ch'} = NOT_FRONT | PREFIX;
764             $digram{'r'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
765             $digram{'r'}{'ph'} = NOT_FRONT | PREFIX;
766             $digram{'r'}{'rh'} = ILLEGAL_PAIR;
767             $digram{'r'}{'sh'} = NOT_FRONT | PREFIX;
768             $digram{'r'}{'th'} = NOT_FRONT | PREFIX;
769             $digram{'r'}{'wh'} = ILLEGAL_PAIR;
770             $digram{'r'}{'qu'} = NOT_FRONT | PREFIX | NOT_BACK;
771             $digram{'r'}{'ck'} = NOT_FRONT | PREFIX;
772              
773             $digram{'s'}{'a'} = ANY_COMBINATION;
774             $digram{'s'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
775             $digram{'s'}{'c'} = NOT_BACK;
776             $digram{'s'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
777             $digram{'s'}{'e'} = ANY_COMBINATION;
778             $digram{'s'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
779             $digram{'s'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
780             $digram{'s'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
781             $digram{'s'}{'i'} = ANY_COMBINATION;
782             $digram{'s'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
783             $digram{'s'}{'k'} = ANY_COMBINATION;
784             $digram{'s'}{'l'} = FRONT | SUFFIX | NOT_BACK;
785             $digram{'s'}{'m'} = SUFFIX | NOT_BACK;
786             $digram{'s'}{'n'} = PREFIX | SUFFIX | NOT_BACK;
787             $digram{'s'}{'o'} = ANY_COMBINATION;
788             $digram{'s'}{'p'} = ANY_COMBINATION;
789             $digram{'s'}{'r'} = NOT_FRONT | NOT_BACK;
790             $digram{'s'}{'s'} = NOT_FRONT | PREFIX;
791             $digram{'s'}{'t'} = ANY_COMBINATION;
792             $digram{'s'}{'u'} = ANY_COMBINATION;
793             $digram{'s'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
794             $digram{'s'}{'w'} = FRONT | SUFFIX | NOT_BACK;
795             $digram{'s'}{'x'} = ILLEGAL_PAIR;
796             $digram{'s'}{'y'} = ANY_COMBINATION;
797             $digram{'s'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
798             $digram{'s'}{'ch'} = FRONT | SUFFIX | NOT_BACK;
799             $digram{'s'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
800             $digram{'s'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
801             $digram{'s'}{'rh'} = ILLEGAL_PAIR;
802             $digram{'s'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
803             $digram{'s'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
804             $digram{'s'}{'wh'} = ILLEGAL_PAIR;
805             $digram{'s'}{'qu'} = SUFFIX | NOT_BACK;
806             $digram{'s'}{'ck'} = NOT_FRONT;
807              
808             $digram{'t'}{'a'} = ANY_COMBINATION;
809             $digram{'t'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
810             $digram{'t'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
811             $digram{'t'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
812             $digram{'t'}{'e'} = ANY_COMBINATION;
813             $digram{'t'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
814             $digram{'t'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
815             $digram{'t'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
816             $digram{'t'}{'i'} = ANY_COMBINATION;
817             $digram{'t'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
818             $digram{'t'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
819             $digram{'t'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
820             $digram{'t'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
821             $digram{'t'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
822             $digram{'t'}{'o'} = ANY_COMBINATION;
823             $digram{'t'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
824             $digram{'t'}{'r'} = NOT_BACK;
825             $digram{'t'}{'s'} = NOT_FRONT | BACK;
826             $digram{'t'}{'t'} = NOT_FRONT | PREFIX;
827             $digram{'t'}{'u'} = ANY_COMBINATION;
828             $digram{'t'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
829             $digram{'t'}{'w'} = FRONT | SUFFIX | NOT_BACK;
830             $digram{'t'}{'x'} = ILLEGAL_PAIR;
831             $digram{'t'}{'y'} = ANY_COMBINATION;
832             $digram{'t'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
833             $digram{'t'}{'ch'} = NOT_FRONT;
834             $digram{'t'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
835             $digram{'t'}{'ph'} = NOT_FRONT | BACK;
836             $digram{'t'}{'rh'} = ILLEGAL_PAIR;
837             $digram{'t'}{'sh'} = NOT_FRONT | BACK;
838             $digram{'t'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
839             $digram{'t'}{'wh'} = ILLEGAL_PAIR;
840             $digram{'t'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
841             $digram{'t'}{'ck'} = ILLEGAL_PAIR;
842              
843             $digram{'u'}{'a'} = NOT_FRONT | BREAK | NOT_BACK;
844             $digram{'u'}{'b'} = ANY_COMBINATION;
845             $digram{'u'}{'c'} = ANY_COMBINATION;
846             $digram{'u'}{'d'} = ANY_COMBINATION;
847             $digram{'u'}{'e'} = NOT_FRONT;
848             $digram{'u'}{'f'} = ANY_COMBINATION;
849             $digram{'u'}{'g'} = ANY_COMBINATION;
850             $digram{'u'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
851             $digram{'u'}{'i'} = NOT_FRONT | BREAK | NOT_BACK;
852             $digram{'u'}{'j'} = ANY_COMBINATION;
853             $digram{'u'}{'k'} = ANY_COMBINATION;
854             $digram{'u'}{'l'} = ANY_COMBINATION;
855             $digram{'u'}{'m'} = ANY_COMBINATION;
856             $digram{'u'}{'n'} = ANY_COMBINATION;
857             $digram{'u'}{'o'} = NOT_FRONT | BREAK;
858             $digram{'u'}{'p'} = ANY_COMBINATION;
859             $digram{'u'}{'r'} = ANY_COMBINATION;
860             $digram{'u'}{'s'} = ANY_COMBINATION;
861             $digram{'u'}{'t'} = ANY_COMBINATION;
862             $digram{'u'}{'u'} = ILLEGAL_PAIR;
863             $digram{'u'}{'v'} = ANY_COMBINATION;
864             $digram{'u'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
865             $digram{'u'}{'x'} = ANY_COMBINATION;
866             $digram{'u'}{'y'} = NOT_FRONT | BREAK | NOT_BACK;
867             $digram{'u'}{'z'} = ANY_COMBINATION;
868             $digram{'u'}{'ch'} = ANY_COMBINATION;
869             $digram{'u'}{'gh'} = NOT_FRONT | PREFIX;
870             $digram{'u'}{'ph'} = ANY_COMBINATION;
871             $digram{'u'}{'rh'} = ILLEGAL_PAIR;
872             $digram{'u'}{'sh'} = ANY_COMBINATION;
873             $digram{'u'}{'th'} = ANY_COMBINATION;
874             $digram{'u'}{'wh'} = ILLEGAL_PAIR;
875             $digram{'u'}{'qu'} = BREAK | NOT_BACK;
876             $digram{'u'}{'ck'} = ANY_COMBINATION;
877              
878             $digram{'v'}{'a'} = ANY_COMBINATION;
879             $digram{'v'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
880             $digram{'v'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
881             $digram{'v'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
882             $digram{'v'}{'e'} = ANY_COMBINATION;
883             $digram{'v'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
884             $digram{'v'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
885             $digram{'v'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
886             $digram{'v'}{'i'} = ANY_COMBINATION;
887             $digram{'v'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
888             $digram{'v'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
889             $digram{'v'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
890             $digram{'v'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
891             $digram{'v'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
892             $digram{'v'}{'o'} = ANY_COMBINATION;
893             $digram{'v'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
894             $digram{'v'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
895             $digram{'v'}{'s'} = NOT_FRONT | BREAK | NOT_BACK;
896             $digram{'v'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
897             $digram{'v'}{'u'} = ANY_COMBINATION;
898             $digram{'v'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
899             $digram{'v'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
900             $digram{'v'}{'x'} = ILLEGAL_PAIR;
901             $digram{'v'}{'y'} = NOT_FRONT;
902             $digram{'v'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
903             $digram{'v'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
904             $digram{'v'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
905             $digram{'v'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
906             $digram{'v'}{'rh'} = ILLEGAL_PAIR;
907             $digram{'v'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
908             $digram{'v'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
909             $digram{'v'}{'wh'} = ILLEGAL_PAIR;
910             $digram{'v'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
911             $digram{'v'}{'ck'} = ILLEGAL_PAIR;
912              
913             $digram{'w'}{'a'} = ANY_COMBINATION;
914             $digram{'w'}{'b'} = NOT_FRONT | PREFIX;
915             $digram{'w'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
916             $digram{'w'}{'d'} = NOT_FRONT | PREFIX | BACK;
917             $digram{'w'}{'e'} = ANY_COMBINATION;
918             $digram{'w'}{'f'} = NOT_FRONT | PREFIX;
919             $digram{'w'}{'g'} = NOT_FRONT | PREFIX | BACK;
920             $digram{'w'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
921             $digram{'w'}{'i'} = ANY_COMBINATION;
922             $digram{'w'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
923             $digram{'w'}{'k'} = NOT_FRONT | PREFIX;
924             $digram{'w'}{'l'} = NOT_FRONT | PREFIX | SUFFIX;
925             $digram{'w'}{'m'} = NOT_FRONT | PREFIX;
926             $digram{'w'}{'n'} = NOT_FRONT | PREFIX;
927             $digram{'w'}{'o'} = ANY_COMBINATION;
928             $digram{'w'}{'p'} = NOT_FRONT | PREFIX;
929             $digram{'w'}{'r'} = FRONT | SUFFIX | NOT_BACK;
930             $digram{'w'}{'s'} = NOT_FRONT | PREFIX;
931             $digram{'w'}{'t'} = NOT_FRONT | PREFIX;
932             $digram{'w'}{'u'} = ANY_COMBINATION;
933             $digram{'w'}{'v'} = NOT_FRONT | PREFIX;
934             $digram{'w'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
935             $digram{'w'}{'x'} = NOT_FRONT | PREFIX;
936             $digram{'w'}{'y'} = ANY_COMBINATION;
937             $digram{'w'}{'z'} = NOT_FRONT | PREFIX;
938             $digram{'w'}{'ch'} = NOT_FRONT;
939             $digram{'w'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
940             $digram{'w'}{'ph'} = NOT_FRONT;
941             $digram{'w'}{'rh'} = ILLEGAL_PAIR;
942             $digram{'w'}{'sh'} = NOT_FRONT;
943             $digram{'w'}{'th'} = NOT_FRONT;
944             $digram{'w'}{'wh'} = ILLEGAL_PAIR;
945             $digram{'w'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
946             $digram{'w'}{'ck'} = NOT_FRONT;
947              
948             $digram{'x'}{'a'} = NOT_FRONT;
949             $digram{'x'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
950             $digram{'x'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
951             $digram{'x'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
952             $digram{'x'}{'e'} = NOT_FRONT;
953             $digram{'x'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
954             $digram{'x'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
955             $digram{'x'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
956             $digram{'x'}{'i'} = NOT_FRONT;
957             $digram{'x'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
958             $digram{'x'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
959             $digram{'x'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
960             $digram{'x'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
961             $digram{'x'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
962             $digram{'x'}{'o'} = NOT_FRONT;
963             $digram{'x'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
964             $digram{'x'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
965             $digram{'x'}{'s'} = NOT_FRONT | BREAK | NOT_BACK;
966             $digram{'x'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
967             $digram{'x'}{'u'} = NOT_FRONT;
968             $digram{'x'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
969             $digram{'x'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
970             $digram{'x'}{'x'} = ILLEGAL_PAIR;
971             $digram{'x'}{'y'} = NOT_FRONT;
972             $digram{'x'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
973             $digram{'x'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
974             $digram{'x'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
975             $digram{'x'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
976             $digram{'x'}{'rh'} = ILLEGAL_PAIR;
977             $digram{'x'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
978             $digram{'x'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
979             $digram{'x'}{'wh'} = ILLEGAL_PAIR;
980             $digram{'x'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
981             $digram{'x'}{'ck'} = ILLEGAL_PAIR;
982              
983             $digram{'y'}{'a'} = ANY_COMBINATION;
984             $digram{'y'}{'b'} = NOT_FRONT;
985             $digram{'y'}{'c'} = NOT_FRONT | NOT_BACK;
986             $digram{'y'}{'d'} = NOT_FRONT;
987             $digram{'y'}{'e'} = ANY_COMBINATION;
988             $digram{'y'}{'f'} = NOT_FRONT | NOT_BACK;
989             $digram{'y'}{'g'} = NOT_FRONT;
990             $digram{'y'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
991             $digram{'y'}{'i'} = FRONT | NOT_BACK;
992             $digram{'y'}{'j'} = NOT_FRONT | NOT_BACK;
993             $digram{'y'}{'k'} = NOT_FRONT;
994             $digram{'y'}{'l'} = NOT_FRONT | NOT_BACK;
995             $digram{'y'}{'m'} = NOT_FRONT;
996             $digram{'y'}{'n'} = NOT_FRONT;
997             $digram{'y'}{'o'} = ANY_COMBINATION;
998             $digram{'y'}{'p'} = NOT_FRONT;
999             $digram{'y'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
1000             $digram{'y'}{'s'} = NOT_FRONT;
1001             $digram{'y'}{'t'} = NOT_FRONT;
1002             $digram{'y'}{'u'} = ANY_COMBINATION;
1003             $digram{'y'}{'v'} = NOT_FRONT | NOT_BACK;
1004             $digram{'y'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
1005             $digram{'y'}{'x'} = NOT_FRONT;
1006             $digram{'y'}{'y'} = ILLEGAL_PAIR;
1007             $digram{'y'}{'z'} = NOT_FRONT;
1008             $digram{'y'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
1009             $digram{'y'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
1010             $digram{'y'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
1011             $digram{'y'}{'rh'} = ILLEGAL_PAIR;
1012             $digram{'y'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
1013             $digram{'y'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
1014             $digram{'y'}{'wh'} = ILLEGAL_PAIR;
1015             $digram{'y'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
1016             $digram{'y'}{'ck'} = ILLEGAL_PAIR;
1017              
1018             $digram{'z'}{'a'} = ANY_COMBINATION;
1019             $digram{'z'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
1020             $digram{'z'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
1021             $digram{'z'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
1022             $digram{'z'}{'e'} = ANY_COMBINATION;
1023             $digram{'z'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
1024             $digram{'z'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
1025             $digram{'z'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
1026             $digram{'z'}{'i'} = ANY_COMBINATION;
1027             $digram{'z'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
1028             $digram{'z'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
1029             $digram{'z'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
1030             $digram{'z'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
1031             $digram{'z'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
1032             $digram{'z'}{'o'} = ANY_COMBINATION;
1033             $digram{'z'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
1034             $digram{'z'}{'r'} = NOT_FRONT | NOT_BACK;
1035             $digram{'z'}{'s'} = NOT_FRONT | BREAK | NOT_BACK;
1036             $digram{'z'}{'t'} = NOT_FRONT;
1037             $digram{'z'}{'u'} = ANY_COMBINATION;
1038             $digram{'z'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
1039             $digram{'z'}{'w'} = SUFFIX | NOT_BACK;
1040             $digram{'z'}{'x'} = ILLEGAL_PAIR;
1041             $digram{'z'}{'y'} = ANY_COMBINATION;
1042             $digram{'z'}{'z'} = NOT_FRONT;
1043             $digram{'z'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
1044             $digram{'z'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
1045             $digram{'z'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
1046             $digram{'z'}{'rh'} = ILLEGAL_PAIR;
1047             $digram{'z'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
1048             $digram{'z'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
1049             $digram{'z'}{'wh'} = ILLEGAL_PAIR;
1050             $digram{'z'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
1051             $digram{'z'}{'ck'} = ILLEGAL_PAIR;
1052              
1053             $digram{'ch'}{'a'} = ANY_COMBINATION;
1054             $digram{'ch'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
1055             $digram{'ch'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
1056             $digram{'ch'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
1057             $digram{'ch'}{'e'} = ANY_COMBINATION;
1058             $digram{'ch'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
1059             $digram{'ch'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
1060             $digram{'ch'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
1061             $digram{'ch'}{'i'} = ANY_COMBINATION;
1062             $digram{'ch'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
1063             $digram{'ch'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
1064             $digram{'ch'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
1065             $digram{'ch'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
1066             $digram{'ch'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
1067             $digram{'ch'}{'o'} = ANY_COMBINATION;
1068             $digram{'ch'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
1069             $digram{'ch'}{'r'} = NOT_BACK;
1070             $digram{'ch'}{'s'} = NOT_FRONT | BREAK | NOT_BACK;
1071             $digram{'ch'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
1072             $digram{'ch'}{'u'} = ANY_COMBINATION;
1073             $digram{'ch'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
1074             $digram{'ch'}{'w'} = NOT_FRONT | NOT_BACK;
1075             $digram{'ch'}{'x'} = ILLEGAL_PAIR;
1076             $digram{'ch'}{'y'} = ANY_COMBINATION;
1077             $digram{'ch'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
1078             $digram{'ch'}{'ch'} = ILLEGAL_PAIR;
1079             $digram{'ch'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
1080             $digram{'ch'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
1081             $digram{'ch'}{'rh'} = ILLEGAL_PAIR;
1082             $digram{'ch'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
1083             $digram{'ch'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
1084             $digram{'ch'}{'wh'} = ILLEGAL_PAIR;
1085             $digram{'ch'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
1086             $digram{'ch'}{'ck'} = ILLEGAL_PAIR;
1087              
1088             $digram{'gh'}{'a'} = ANY_COMBINATION;
1089             $digram{'gh'}{'b'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1090             $digram{'gh'}{'c'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1091             $digram{'gh'}{'d'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1092             $digram{'gh'}{'e'} = ANY_COMBINATION;
1093             $digram{'gh'}{'f'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1094             $digram{'gh'}{'g'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1095             $digram{'gh'}{'h'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1096             $digram{'gh'}{'i'} = FRONT | NOT_BACK;
1097             $digram{'gh'}{'j'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1098             $digram{'gh'}{'k'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1099             $digram{'gh'}{'l'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1100             $digram{'gh'}{'m'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1101             $digram{'gh'}{'n'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1102             $digram{'gh'}{'o'} = FRONT | NOT_BACK;
1103             $digram{'gh'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
1104             $digram{'gh'}{'r'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1105             $digram{'gh'}{'s'} = NOT_FRONT | PREFIX;
1106             $digram{'gh'}{'t'} = NOT_FRONT | PREFIX;
1107             $digram{'gh'}{'u'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1108             $digram{'gh'}{'v'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1109             $digram{'gh'}{'w'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1110             $digram{'gh'}{'x'} = ILLEGAL_PAIR;
1111             $digram{'gh'}{'y'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1112             $digram{'gh'}{'z'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1113             $digram{'gh'}{'ch'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1114             $digram{'gh'}{'gh'} = ILLEGAL_PAIR;
1115             $digram{'gh'}{'ph'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1116             $digram{'gh'}{'rh'} = ILLEGAL_PAIR;
1117             $digram{'gh'}{'sh'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1118             $digram{'gh'}{'th'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1119             $digram{'gh'}{'wh'} = ILLEGAL_PAIR;
1120             $digram{'gh'}{'qu'} = NOT_FRONT | BREAK | PREFIX | NOT_BACK;
1121             $digram{'gh'}{'ck'} = ILLEGAL_PAIR;
1122              
1123             $digram{'ph'}{'a'} = ANY_COMBINATION;
1124             $digram{'ph'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
1125             $digram{'ph'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
1126             $digram{'ph'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
1127             $digram{'ph'}{'e'} = ANY_COMBINATION;
1128             $digram{'ph'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
1129             $digram{'ph'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
1130             $digram{'ph'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
1131             $digram{'ph'}{'i'} = ANY_COMBINATION;
1132             $digram{'ph'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
1133             $digram{'ph'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
1134             $digram{'ph'}{'l'} = FRONT | SUFFIX | NOT_BACK;
1135             $digram{'ph'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
1136             $digram{'ph'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
1137             $digram{'ph'}{'o'} = ANY_COMBINATION;
1138             $digram{'ph'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
1139             $digram{'ph'}{'r'} = NOT_BACK;
1140             $digram{'ph'}{'s'} = NOT_FRONT;
1141             $digram{'ph'}{'t'} = NOT_FRONT;
1142             $digram{'ph'}{'u'} = ANY_COMBINATION;
1143             $digram{'ph'}{'v'} = NOT_FRONT | NOT_BACK;
1144             $digram{'ph'}{'w'} = NOT_FRONT | NOT_BACK;
1145             $digram{'ph'}{'x'} = ILLEGAL_PAIR;
1146             $digram{'ph'}{'y'} = NOT_FRONT;
1147             $digram{'ph'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
1148             $digram{'ph'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
1149             $digram{'ph'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
1150             $digram{'ph'}{'ph'} = ILLEGAL_PAIR;
1151             $digram{'ph'}{'rh'} = ILLEGAL_PAIR;
1152             $digram{'ph'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
1153             $digram{'ph'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
1154             $digram{'ph'}{'wh'} = ILLEGAL_PAIR;
1155             $digram{'ph'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
1156             $digram{'ph'}{'ck'} = ILLEGAL_PAIR;
1157              
1158             $digram{'rh'}{'a'} = FRONT | NOT_BACK;
1159             $digram{'rh'}{'b'} = ILLEGAL_PAIR;
1160             $digram{'rh'}{'c'} = ILLEGAL_PAIR;
1161             $digram{'rh'}{'d'} = ILLEGAL_PAIR;
1162             $digram{'rh'}{'e'} = FRONT | NOT_BACK;
1163             $digram{'rh'}{'f'} = ILLEGAL_PAIR;
1164             $digram{'rh'}{'g'} = ILLEGAL_PAIR;
1165             $digram{'rh'}{'h'} = ILLEGAL_PAIR;
1166             $digram{'rh'}{'i'} = FRONT | NOT_BACK;
1167             $digram{'rh'}{'j'} = ILLEGAL_PAIR;
1168             $digram{'rh'}{'k'} = ILLEGAL_PAIR;
1169             $digram{'rh'}{'l'} = ILLEGAL_PAIR;
1170             $digram{'rh'}{'m'} = ILLEGAL_PAIR;
1171             $digram{'rh'}{'n'} = ILLEGAL_PAIR;
1172             $digram{'rh'}{'o'} = FRONT | NOT_BACK;
1173             $digram{'rh'}{'p'} = ILLEGAL_PAIR;
1174             $digram{'rh'}{'r'} = ILLEGAL_PAIR;
1175             $digram{'rh'}{'s'} = ILLEGAL_PAIR;
1176             $digram{'rh'}{'t'} = ILLEGAL_PAIR;
1177             $digram{'rh'}{'u'} = FRONT | NOT_BACK;
1178             $digram{'rh'}{'v'} = ILLEGAL_PAIR;
1179             $digram{'rh'}{'w'} = ILLEGAL_PAIR;
1180             $digram{'rh'}{'x'} = ILLEGAL_PAIR;
1181             $digram{'rh'}{'y'} = FRONT | NOT_BACK;
1182             $digram{'rh'}{'z'} = ILLEGAL_PAIR;
1183             $digram{'rh'}{'ch'} = ILLEGAL_PAIR;
1184             $digram{'rh'}{'gh'} = ILLEGAL_PAIR;
1185             $digram{'rh'}{'ph'} = ILLEGAL_PAIR;
1186             $digram{'rh'}{'rh'} = ILLEGAL_PAIR;
1187             $digram{'rh'}{'sh'} = ILLEGAL_PAIR;
1188             $digram{'rh'}{'th'} = ILLEGAL_PAIR;
1189             $digram{'rh'}{'wh'} = ILLEGAL_PAIR;
1190             $digram{'rh'}{'qu'} = ILLEGAL_PAIR;
1191             $digram{'rh'}{'ck'} = ILLEGAL_PAIR;
1192              
1193             $digram{'sh'}{'a'} = ANY_COMBINATION;
1194             $digram{'sh'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
1195             $digram{'sh'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
1196             $digram{'sh'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
1197             $digram{'sh'}{'e'} = ANY_COMBINATION;
1198             $digram{'sh'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
1199             $digram{'sh'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
1200             $digram{'sh'}{'h'} = ILLEGAL_PAIR;
1201             $digram{'sh'}{'i'} = ANY_COMBINATION;
1202             $digram{'sh'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
1203             $digram{'sh'}{'k'} = NOT_FRONT;
1204             $digram{'sh'}{'l'} = FRONT | SUFFIX | NOT_BACK;
1205             $digram{'sh'}{'m'} = FRONT | SUFFIX | NOT_BACK;
1206             $digram{'sh'}{'n'} = FRONT | SUFFIX | NOT_BACK;
1207             $digram{'sh'}{'o'} = ANY_COMBINATION;
1208             $digram{'sh'}{'p'} = NOT_FRONT;
1209             $digram{'sh'}{'r'} = FRONT | SUFFIX | NOT_BACK;
1210             $digram{'sh'}{'s'} = NOT_FRONT | BREAK | NOT_BACK;
1211             $digram{'sh'}{'t'} = SUFFIX;
1212             $digram{'sh'}{'u'} = ANY_COMBINATION;
1213             $digram{'sh'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
1214             $digram{'sh'}{'w'} = SUFFIX | NOT_BACK;
1215             $digram{'sh'}{'x'} = ILLEGAL_PAIR;
1216             $digram{'sh'}{'y'} = ANY_COMBINATION;
1217             $digram{'sh'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
1218             $digram{'sh'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
1219             $digram{'sh'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
1220             $digram{'sh'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
1221             $digram{'sh'}{'rh'} = ILLEGAL_PAIR;
1222             $digram{'sh'}{'sh'} = ILLEGAL_PAIR;
1223             $digram{'sh'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
1224             $digram{'sh'}{'wh'} = ILLEGAL_PAIR;
1225             $digram{'sh'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
1226             $digram{'sh'}{'ck'} = ILLEGAL_PAIR;
1227              
1228             $digram{'th'}{'a'} = ANY_COMBINATION;
1229             $digram{'th'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
1230             $digram{'th'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
1231             $digram{'th'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
1232             $digram{'th'}{'e'} = ANY_COMBINATION;
1233             $digram{'th'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
1234             $digram{'th'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
1235             $digram{'th'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
1236             $digram{'th'}{'i'} = ANY_COMBINATION;
1237             $digram{'th'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
1238             $digram{'th'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
1239             $digram{'th'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
1240             $digram{'th'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
1241             $digram{'th'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
1242             $digram{'th'}{'o'} = ANY_COMBINATION;
1243             $digram{'th'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
1244             $digram{'th'}{'r'} = NOT_BACK;
1245             $digram{'th'}{'s'} = NOT_FRONT | BACK;
1246             $digram{'th'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
1247             $digram{'th'}{'u'} = ANY_COMBINATION;
1248             $digram{'th'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
1249             $digram{'th'}{'w'} = SUFFIX | NOT_BACK;
1250             $digram{'th'}{'x'} = ILLEGAL_PAIR;
1251             $digram{'th'}{'y'} = ANY_COMBINATION;
1252             $digram{'th'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
1253             $digram{'th'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
1254             $digram{'th'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
1255             $digram{'th'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
1256             $digram{'th'}{'rh'} = ILLEGAL_PAIR;
1257             $digram{'th'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
1258             $digram{'th'}{'th'} = ILLEGAL_PAIR;
1259             $digram{'th'}{'wh'} = ILLEGAL_PAIR;
1260             $digram{'th'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
1261             $digram{'th'}{'ck'} = ILLEGAL_PAIR;
1262              
1263             $digram{'wh'}{'a'} = FRONT | NOT_BACK;
1264             $digram{'wh'}{'b'} = ILLEGAL_PAIR;
1265             $digram{'wh'}{'c'} = ILLEGAL_PAIR;
1266             $digram{'wh'}{'d'} = ILLEGAL_PAIR;
1267             $digram{'wh'}{'e'} = FRONT | NOT_BACK;
1268             $digram{'wh'}{'f'} = ILLEGAL_PAIR;
1269             $digram{'wh'}{'g'} = ILLEGAL_PAIR;
1270             $digram{'wh'}{'h'} = ILLEGAL_PAIR;
1271             $digram{'wh'}{'i'} = FRONT | NOT_BACK;
1272             $digram{'wh'}{'j'} = ILLEGAL_PAIR;
1273             $digram{'wh'}{'k'} = ILLEGAL_PAIR;
1274             $digram{'wh'}{'l'} = ILLEGAL_PAIR;
1275             $digram{'wh'}{'m'} = ILLEGAL_PAIR;
1276             $digram{'wh'}{'n'} = ILLEGAL_PAIR;
1277             $digram{'wh'}{'o'} = FRONT | NOT_BACK;
1278             $digram{'wh'}{'p'} = ILLEGAL_PAIR;
1279             $digram{'wh'}{'r'} = ILLEGAL_PAIR;
1280             $digram{'wh'}{'s'} = ILLEGAL_PAIR;
1281             $digram{'wh'}{'t'} = ILLEGAL_PAIR;
1282             $digram{'wh'}{'u'} = ILLEGAL_PAIR;
1283             $digram{'wh'}{'v'} = ILLEGAL_PAIR;
1284             $digram{'wh'}{'w'} = ILLEGAL_PAIR;
1285             $digram{'wh'}{'x'} = ILLEGAL_PAIR;
1286             $digram{'wh'}{'y'} = FRONT | NOT_BACK;
1287             $digram{'wh'}{'z'} = ILLEGAL_PAIR;
1288             $digram{'wh'}{'ch'} = ILLEGAL_PAIR;
1289             $digram{'wh'}{'gh'} = ILLEGAL_PAIR;
1290             $digram{'wh'}{'ph'} = ILLEGAL_PAIR;
1291             $digram{'wh'}{'rh'} = ILLEGAL_PAIR;
1292             $digram{'wh'}{'sh'} = ILLEGAL_PAIR;
1293             $digram{'wh'}{'th'} = ILLEGAL_PAIR;
1294             $digram{'wh'}{'wh'} = ILLEGAL_PAIR;
1295             $digram{'wh'}{'qu'} = ILLEGAL_PAIR;
1296             $digram{'wh'}{'ck'} = ILLEGAL_PAIR;
1297              
1298             $digram{'qu'}{'a'} = ANY_COMBINATION;
1299             $digram{'qu'}{'b'} = ILLEGAL_PAIR;
1300             $digram{'qu'}{'c'} = ILLEGAL_PAIR;
1301             $digram{'qu'}{'d'} = ILLEGAL_PAIR;
1302             $digram{'qu'}{'e'} = ANY_COMBINATION;
1303             $digram{'qu'}{'f'} = ILLEGAL_PAIR;
1304             $digram{'qu'}{'g'} = ILLEGAL_PAIR;
1305             $digram{'qu'}{'h'} = ILLEGAL_PAIR;
1306             $digram{'qu'}{'i'} = ANY_COMBINATION;
1307             $digram{'qu'}{'j'} = ILLEGAL_PAIR;
1308             $digram{'qu'}{'k'} = ILLEGAL_PAIR;
1309             $digram{'qu'}{'l'} = ILLEGAL_PAIR;
1310             $digram{'qu'}{'m'} = ILLEGAL_PAIR;
1311             $digram{'qu'}{'n'} = ILLEGAL_PAIR;
1312             $digram{'qu'}{'o'} = ANY_COMBINATION;
1313             $digram{'qu'}{'p'} = ILLEGAL_PAIR;
1314             $digram{'qu'}{'r'} = ILLEGAL_PAIR;
1315             $digram{'qu'}{'s'} = ILLEGAL_PAIR;
1316             $digram{'qu'}{'t'} = ILLEGAL_PAIR;
1317             $digram{'qu'}{'u'} = ILLEGAL_PAIR;
1318             $digram{'qu'}{'v'} = ILLEGAL_PAIR;
1319             $digram{'qu'}{'w'} = ILLEGAL_PAIR;
1320             $digram{'qu'}{'x'} = ILLEGAL_PAIR;
1321             $digram{'qu'}{'y'} = ILLEGAL_PAIR;
1322             $digram{'qu'}{'z'} = ILLEGAL_PAIR;
1323             $digram{'qu'}{'ch'} = ILLEGAL_PAIR;
1324             $digram{'qu'}{'gh'} = ILLEGAL_PAIR;
1325             $digram{'qu'}{'ph'} = ILLEGAL_PAIR;
1326             $digram{'qu'}{'rh'} = ILLEGAL_PAIR;
1327             $digram{'qu'}{'sh'} = ILLEGAL_PAIR;
1328             $digram{'qu'}{'th'} = ILLEGAL_PAIR;
1329             $digram{'qu'}{'wh'} = ILLEGAL_PAIR;
1330             $digram{'qu'}{'qu'} = ILLEGAL_PAIR;
1331             $digram{'qu'}{'ck'} = ILLEGAL_PAIR;
1332              
1333             $digram{'ck'}{'a'} = NOT_FRONT | BREAK | NOT_BACK;
1334             $digram{'ck'}{'b'} = NOT_FRONT | BREAK | NOT_BACK;
1335             $digram{'ck'}{'c'} = NOT_FRONT | BREAK | NOT_BACK;
1336             $digram{'ck'}{'d'} = NOT_FRONT | BREAK | NOT_BACK;
1337             $digram{'ck'}{'e'} = NOT_FRONT | BREAK | NOT_BACK;
1338             $digram{'ck'}{'f'} = NOT_FRONT | BREAK | NOT_BACK;
1339             $digram{'ck'}{'g'} = NOT_FRONT | BREAK | NOT_BACK;
1340             $digram{'ck'}{'h'} = NOT_FRONT | BREAK | NOT_BACK;
1341             $digram{'ck'}{'i'} = NOT_FRONT | BREAK | NOT_BACK;
1342             $digram{'ck'}{'j'} = NOT_FRONT | BREAK | NOT_BACK;
1343             $digram{'ck'}{'k'} = NOT_FRONT | BREAK | NOT_BACK;
1344             $digram{'ck'}{'l'} = NOT_FRONT | BREAK | NOT_BACK;
1345             $digram{'ck'}{'m'} = NOT_FRONT | BREAK | NOT_BACK;
1346             $digram{'ck'}{'n'} = NOT_FRONT | BREAK | NOT_BACK;
1347             $digram{'ck'}{'o'} = NOT_FRONT | BREAK | NOT_BACK;
1348             $digram{'ck'}{'p'} = NOT_FRONT | BREAK | NOT_BACK;
1349             $digram{'ck'}{'r'} = NOT_FRONT | BREAK | NOT_BACK;
1350             $digram{'ck'}{'s'} = NOT_FRONT;
1351             $digram{'ck'}{'t'} = NOT_FRONT | BREAK | NOT_BACK;
1352             $digram{'ck'}{'u'} = NOT_FRONT | BREAK | NOT_BACK;
1353             $digram{'ck'}{'v'} = NOT_FRONT | BREAK | NOT_BACK;
1354             $digram{'ck'}{'w'} = NOT_FRONT | BREAK | NOT_BACK;
1355             $digram{'ck'}{'x'} = ILLEGAL_PAIR;
1356             $digram{'ck'}{'y'} = NOT_FRONT;
1357             $digram{'ck'}{'z'} = NOT_FRONT | BREAK | NOT_BACK;
1358             $digram{'ck'}{'ch'} = NOT_FRONT | BREAK | NOT_BACK;
1359             $digram{'ck'}{'gh'} = NOT_FRONT | BREAK | NOT_BACK;
1360             $digram{'ck'}{'ph'} = NOT_FRONT | BREAK | NOT_BACK;
1361             $digram{'ck'}{'rh'} = ILLEGAL_PAIR;
1362             $digram{'ck'}{'sh'} = NOT_FRONT | BREAK | NOT_BACK;
1363             $digram{'ck'}{'th'} = NOT_FRONT | BREAK | NOT_BACK;
1364             $digram{'ck'}{'wh'} = ILLEGAL_PAIR;
1365             $digram{'ck'}{'qu'} = NOT_FRONT | BREAK | NOT_BACK;
1366             $digram{'ck'}{'ck'} = ILLEGAL_PAIR;
1367              
1368             ##############################################################################################
1369             # } END DIGRAM
1370             ##############################################################################################
1371              
1372              
1373              
1374             sub report(@) {
1375 230 50   230 0 480 $main::DEBUG and print @_;
1376             }
1377              
1378              
1379              
1380              
1381             =head2 word
1382              
1383             word = word( minlen, maxlen );
1384             ( word, hyphenated_form ) = word( minlen, maxlen );
1385              
1386             Generates a random word, as well as its hyphenated form.
1387             The length of the returned word will be between minlen and maxlen.
1388              
1389             =cut
1390              
1391             sub word($$) {
1392 20 50   20 1 10521 @_ > 2 and shift;
1393 20         43 my( $minlen, $maxlen ) = @_;
1394              
1395 20 50       47 $minlen <= $maxlen or die "minlen $minlen is greater than maxlen $maxlen";
1396              
1397 20         47 init();
1398              
1399             #
1400             # Check for zero length words. This is technically not an error,
1401             # so we take the short cut and return empty words.
1402             #
1403 20 0       50 $maxlen or return wantarray ? ('','') : '';
    50          
1404              
1405 20         20 my( $word, $hyphenated_word );
1406              
1407 20   66     104 for ( my $try = 1 ; $try <= MAX_UNACCEPTABLE and not defined $word; $try++ ) {
1408 20         35 ( $word, $hyphenated_word ) = _random_word( rand_int_in_range( $minlen, $maxlen ) );
1409 20         61 $word = restrict( $word );
1410             }
1411              
1412 20 50       42 $word or die "failed to generate an acceptable random password.\n";
1413              
1414 20 50       88 return wantarray ? ( $word, $hyphenated_word ) : $word;
1415             }
1416              
1417              
1418             =head2 letters
1419              
1420             word = letters( minlen, maxlen );
1421              
1422             Generates a string of random letters.
1423             The length of the returned word is between minlen and maxlen.
1424             Calls C 'z' )>.
1425              
1426             =cut
1427              
1428             sub letters($$) {
1429 20 50   20 1 9016 @_ > 2 and shift;
1430 20         36 my( $minlen, $maxlen ) = @_;
1431 20         47 random_chars_in_range( $minlen, $maxlen, 'a' => 'z' ); # range of lowercase letters in ASCII
1432             }
1433              
1434              
1435             =head2 chars
1436              
1437             word = chars( minlen, maxlen );
1438              
1439             Generates a string of random printable characters.
1440             The length of the returned word is between minlen and maxlen.
1441             Calls C '~' )>.
1442              
1443             =cut
1444              
1445             sub chars($$) {
1446 20 50   20 1 9032 @_ > 2 and shift;
1447 20         34 my( $minlen, $maxlen ) = @_;
1448 20         44 random_chars_in_range( $minlen, $maxlen, '!' => '~' ); # range of printable chars in ASCII
1449             }
1450              
1451              
1452              
1453             =head2 random_chars_in_range
1454              
1455             word = random_chars_in_range( minlen, maxlen, lo_char => hi_char );
1456            
1457             Generates a string of printable characters.
1458             The length of the returned string is between minlen and maxlen.
1459             Each character is selected from the range of ASCII characters
1460             delimited by (lo_char,hi_char).
1461              
1462             =cut
1463              
1464             sub random_chars_in_range($$$$) {
1465 40     40 1 67 my( $minlen, $maxlen, $lo_char, $hi_char ) = @_;
1466              
1467 40 50       96 $minlen <= $maxlen or die "minlen $minlen is greater than maxlen $maxlen";
1468              
1469 40         77 init();
1470              
1471 40         76 my $string_size = rand_int_in_range( $minlen, $maxlen );
1472              
1473 40         53 my $string;
1474 40   66     209 for ( my $try = 1 ; $try <= MAX_UNACCEPTABLE and not defined $string; $try++ ) {
1475 40         54 my $s = '';
1476 40         89 while ( length($s) < $string_size ) {
1477 527         940 $s .= chr( rand_int_in_range( ord($lo_char), ord($hi_char) ) );
1478             }
1479 40 50       89 next if length($s) > $string_size;
1480 40         77 $string = restrict( $s );
1481             }
1482              
1483 40         131 $string
1484             }
1485              
1486              
1487              
1488             =head2 rand_int_in_range
1489              
1490             n = rand_int_in_range( min, max );
1491              
1492             Returns an integer between min and max, inclusive.
1493             Calls C like so:
1494              
1495             n = min + int( rng( max - min + 1 ) )
1496              
1497             =cut
1498              
1499             sub rand_int_in_range($$) {
1500 22600     22600 1 31629 my( $min, $max ) = @_;
1501 22600         41127 $min + int( rng( $max - $min + 1 ) )
1502             }
1503              
1504              
1505             =head2 random_element
1506              
1507             e = random_element( \@elts )
1508              
1509             Selects a random element from an array, which is passed by ref.
1510              
1511             =cut
1512              
1513             sub random_element($) {
1514 22013     22013 1 22969 my $ar = shift;
1515 22013         28566 $ar->[ rand_int_in_range( 0, $#{$ar} ) ]
  22013         40327  
1516             }
1517              
1518              
1519              
1520             =head2 rng
1521              
1522             r = rng( n );
1523              
1524             C is designed to have the same interface as the built-in C function.
1525             The default implementation here is a simple wrapper around C,
1526             which is typically a wrapper for some pseudo-random number function in the
1527             underlying C library.
1528              
1529             The reason for having this simple wrapper is so the user can
1530             easily substitute a different random number generator if desired.
1531             Since many rng's have the same interface as C, replacing C
1532             is as simple as
1533              
1534             {
1535             local $^W; # squelch sub redef warning.
1536             *Crypt::RandPasswd::rng = \&my_rng;
1537             }
1538              
1539             See L.
1540              
1541             =cut
1542              
1543             sub rng($) {
1544 22600     22600 1 23201 my $x = shift;
1545 22600         74779 rand($x)
1546             }
1547              
1548              
1549              
1550             =head2 restrict
1551              
1552             word = restrict( word );
1553              
1554             A filter. Returns the arg unchanged if it is allowable; returns undef if not.
1555              
1556             The default version of C allows everything.
1557             You may install a different form to implement other restrictions,
1558             by doing something like this:
1559              
1560             {
1561             local $^W; # squelch sub redef warning.
1562             *Crypt::RandPasswd::restrict = \&my_filter;
1563             }
1564              
1565             =cut
1566              
1567 60     60 1 361 sub restrict($) { $_[0] } # MUST return a real scalar; returning @_ causes scalar(@_) !!!
1568              
1569              
1570             =head2 init
1571              
1572             This initializes the environment, which by default simply seeds the random number generator.
1573              
1574             =cut
1575              
1576             # can be called multiple times without harm, since it remembers whether
1577             # it has already been called.
1578              
1579             sub init() {
1580 60 100   60 1 167 unless ( $Crypt::RandPasswd::initialized ) {
1581             # only do stuff if I haven't already been called before.
1582              
1583 3         8 $Crypt::RandPasswd::initialized = 1;
1584 3 50       15 if ( defined $Crypt::RandPasswd::seed ) {
1585 0         0 srand( $Crypt::RandPasswd::seed );
1586             }
1587             else {
1588 3         138 srand; # use default, which can be pretty good.
1589             }
1590             }
1591             }
1592              
1593              
1594              
1595             #
1596             # _random_word
1597             #
1598             # This is the routine that returns a random word.
1599             # It collects random syllables until a predetermined word length is found.
1600             # If a retry threshold is reached, another word is tried.
1601             #
1602             # returns ( word, hyphenated_word ).
1603             #
1604              
1605             sub _random_word($) {
1606 20     20   25 my( $pwlen ) = @_;
1607              
1608 20         28 my $word = '';
1609 20         27 my @word_syllables;
1610              
1611 20         33 my $max_retries = ( 4 * $pwlen ) + scalar( @grams );
1612              
1613 20         26 my $tries = 0; # count of retries.
1614              
1615              
1616             # @word_units used to be an array of indices into the 'rules' C-array.
1617             # now it's an array of actual units (grams).
1618 20         22 my @word_units;
1619              
1620             #
1621             # Find syllables until the entire word is constructed.
1622             #
1623 20         74 while ( length($word) < $pwlen ) {
1624             #
1625             # Get the syllable and find its length.
1626             #
1627 115         324 report "About to call get_syllable( $pwlen - length($word) )\n";
1628 115         243 my( $new_syllable, @syllable_units ) = get_syllable( $pwlen - length($word) );
1629 115         434 report "get_syllable returned ( $new_syllable; @syllable_units )\n";
1630              
1631             #
1632             # If the word has been improperly formed, throw out
1633             # the syllable. The checks performed here are those
1634             # that must be formed on a word basis. The other
1635             # tests are performed entirely within the syllable.
1636             # Otherwise, append the syllable to the word.
1637             #
1638 115 100 66     219 unless (
      33        
      100        
      33        
1639             _improper_word( @word_units, @syllable_units ) # join the arrays
1640             ||
1641             (
1642             $word eq ''
1643             and
1644             _have_initial_y( @syllable_units )
1645             )
1646             ||
1647             (
1648             length( $word . $new_syllable ) == $pwlen
1649             and
1650             _have_final_split( @syllable_units )
1651             )
1652             ) {
1653 109         145 $word .= $new_syllable;
1654 109         169 push @word_syllables, $new_syllable;
1655             }
1656              
1657             #
1658             # Keep track of the times we have tried to get syllables.
1659             # If we have exceeded the threshold, start from scratch.
1660             #
1661 115         138 $tries++;
1662 115 50       369 if ( $tries > $max_retries ) {
1663 0         0 $tries = 0;
1664 0         0 $word = '';
1665 0         0 @word_syllables = ();
1666 0         0 @word_units = ();
1667             }
1668             }
1669              
1670 20         104 return( $word, join('-',@word_syllables) );
1671             }
1672              
1673              
1674             #
1675             # _random_unit
1676             #
1677             # Selects a gram (aka "unit").
1678             # This is the standard random unit generating routine for get_syllable().
1679             #
1680             # This routine attempts to return grams (units) with a distribution
1681             # approaching that of the distribution of the units in English.
1682             #
1683             # The distribution of the units may be altered in this procedure without
1684             # affecting the digram table or any other programs using the random_word subroutine,
1685             # as long as the set of grams (units) is kept consistent throughout this library.
1686             #
1687             # I
1688             # the 'rules' C-array, it now returns a gram.>
1689             #
1690              
1691             my %occurrence_frequencies = (
1692             'a' => 10, 'b' => 8, 'c' => 12, 'd' => 12,
1693             'e' => 12, 'f' => 8, 'g' => 8, 'h' => 6,
1694             'i' => 10, 'j' => 8, 'k' => 8, 'l' => 6,
1695             'm' => 6, 'n' => 10, 'o' => 10, 'p' => 6,
1696             'r' => 10, 's' => 8, 't' => 10, 'u' => 6,
1697             'v' => 8, 'w' => 8, 'x' => 1, 'y' => 8,
1698             'z' => 1, 'ch' => 1, 'gh' => 1, 'ph' => 1,
1699             'rh' => 1, 'sh' => 2, 'th' => 1, 'wh' => 1,
1700             'qu' => 1, 'ck' => 1,
1701             );
1702              
1703             my @numbers = map {
1704             ( ($_) x $occurrence_frequencies{$_} )
1705             } @grams;
1706              
1707             my @vowel_numbers = map {
1708             ( ($_) x $occurrence_frequencies{$_} )
1709             } @vowel_grams;
1710              
1711              
1712              
1713             sub _random_unit($) {
1714 22013     22013   23734 my $type = shift; # byte
1715              
1716 22013 50       51222 random_element( $type & VOWEL
1717             ? \@vowel_numbers # Sometimes, we are asked to explicitly get a vowel (i.e., if
1718             # a digram pair expects one following it). This is a shortcut
1719             # to do that and avoid looping with rejected consonants.
1720              
1721             : \@numbers # Get any letter according to the English distribution.
1722             )
1723             }
1724              
1725              
1726              
1727             #
1728             # _improper_word
1729             #
1730             # Check that the word does not contain illegal combinations
1731             # that may span syllables. Specifically, these are:
1732             #
1733             # 1. An illegal pair of units between syllables.
1734             # 2. Three consecutive vowel units.
1735             # 3. Three consecutive consonant units.
1736             #
1737             # The checks are made against units (1 or 2 letters), not against
1738             # the individual letters, so three consecutive units can have
1739             # the length of 6 at most.
1740             #
1741             # returns boolean
1742             #
1743              
1744             sub _improper_word(@) {
1745 115     115   186 my @units = @_;
1746              
1747 115         105 my $failure; # bool, init False.
1748              
1749 115         228 for my $unit_count ( 0 .. $#units ) {
1750             #
1751             # Check for ILLEGAL_PAIR.
1752             # This should have been caught for units within a syllable,
1753             # but in some cases it would have gone unnoticed for units between syllables
1754             # (e.g., when saved units in get_syllable() were not used).
1755             #
1756 279 50 66     983 $unit_count > 0
1757             and $digram{$units[$unit_count-1]}{$units[$unit_count]} & ILLEGAL_PAIR
1758             and return(1); # Failure!
1759              
1760 279 100       540 next if $unit_count < 2;
1761             #
1762             # Check for consecutive vowels or consonants.
1763             # Because the initial y of a syllable is treated as a consonant rather
1764             # than as a vowel, we exclude y from the first vowel in the vowel test.
1765             # The only problem comes when y ends a syllable and two other vowels start the next, like fly-oint.
1766             # Since such words are still pronounceable, we accept this.
1767             #
1768             #
1769             # Vowel check.
1770             #
1771             (
1772 76 50 100     827 ($rules{$units[$unit_count - 2]} & VOWEL)
      100        
      66        
      33        
      33        
1773             &&
1774             !($rules{$units[$unit_count - 2]} & ALTERNATE_VOWEL)
1775             &&
1776             ($rules{$units[$unit_count - 1]} & VOWEL)
1777             &&
1778             ($rules{$units[$unit_count ]} & VOWEL)
1779             )
1780             ||
1781             #
1782             # Consonant check.
1783             #
1784             (
1785             !($rules{$units[$unit_count - 2]} & VOWEL)
1786             &&
1787             !($rules{$units[$unit_count - 1]} & VOWEL)
1788             &&
1789             !($rules{$units[$unit_count ]} & VOWEL)
1790             )
1791             and return(1); # Failure!
1792             }
1793              
1794             0 # success
1795 115         779 }
1796              
1797              
1798             #
1799             # _have_initial_y
1800             #
1801             # Treating y as a vowel is sometimes a problem. Some words get formed that look irregular.
1802             # One special group is when y starts a word and is the only vowel in the first syllable.
1803             # The word ycl is one example. We discard words like these.
1804             #
1805             # return boolean
1806             #
1807              
1808             sub _have_initial_y(@) {
1809 20     20   46 my @units = @_;
1810              
1811 20         27 my $vowel_count = 0;
1812 20         27 my $normal_vowel_count = 0;
1813              
1814 20         33 for my $unit_count ( 0 .. $#units ) {
1815             #
1816             # Count vowels.
1817             #
1818 74 100       188 if ( $rules{$units[$unit_count]} & VOWEL ) {
1819 27         32 $vowel_count++;
1820              
1821             #
1822             # Count the vowels that are not:
1823             # 1. 'y'
1824             # 2. at the start of the word.
1825             #
1826 27 50 66     120 if ( !($rules{$units[$unit_count]} & ALTERNATE_VOWEL) || ($unit_count > 0) ) {
1827 27         38 $normal_vowel_count++;
1828             }
1829             }
1830             }
1831              
1832 20 100       169 ($vowel_count <= 1) && ($normal_vowel_count == 0)
1833             }
1834              
1835             #
1836             # _have_final_split
1837             #
1838             # Besides the problem with the letter y, there is one with
1839             # a silent e at the end of words, like face or nice.
1840             # We allow this silent e, but we do not allow it as the only
1841             # vowel at the end of the word or syllables like ble will
1842             # be generated.
1843             #
1844             # returns boolean
1845             #
1846              
1847             sub _have_final_split(@) {
1848 26     26   45 my @units = @_;
1849              
1850 26         37 my $vowel_count = 0;
1851              
1852             #
1853             # Count all the vowels in the word.
1854             #
1855 26         52 for my $unit_count ( 0 .. $#units ) {
1856 40 100       104 if ( $rules{$units[$unit_count]} & VOWEL ) {
1857 31         53 $vowel_count++;
1858             }
1859             }
1860              
1861             #
1862             # Return TRUE iff the only vowel was e, found at the end if the word.
1863             #
1864 26 100       196 ($vowel_count == 1) && ( $rules{$units[$#units]} & NO_FINAL_SPLIT )
1865             }
1866              
1867              
1868             =head2 get_syllable
1869              
1870             Generate next unit to password, making sure that it follows these rules:
1871              
1872             1. Each syllable must contain exactly 1 or 2 consecutive vowels, where y is considered a vowel.
1873              
1874             2. Syllable end is determined as follows:
1875              
1876             a. Vowel is generated and previous unit is a consonant and syllable already has a vowel.
1877             In this case, new syllable is started and already contains a vowel.
1878             b. A pair determined to be a "break" pair is encountered.
1879             In this case new syllable is started with second unit of this pair.
1880             c. End of password is encountered.
1881             d. "begin" pair is encountered legally. New syllable is started with this pair.
1882             e. "end" pair is legally encountered. New syllable has nothing yet.
1883              
1884             3. Try generating another unit if:
1885              
1886             a. third consecutive vowel and not y.
1887             b. "break" pair generated but no vowel yet in current or previous 2 units are "not_end".
1888             c. "begin" pair generated but no vowel in syllable preceding begin pair,
1889             or both previous 2 pairs are designated "not_end".
1890             d. "end" pair generated but no vowel in current syllable or in "end" pair.
1891             e. "not_begin" pair generated but new syllable must begin (because previous syllable ended as defined in 2 above).
1892             f. vowel is generated and 2a is satisfied, but no syllable break is possible in previous 3 pairs.
1893             g. Second and third units of syllable must begin, and first unit is "alternate_vowel".
1894              
1895              
1896             =cut
1897              
1898             # global (like a C static)
1899 3     3   44 use vars qw( @saved_pair );
  3         6  
  3         8327  
1900             @saved_pair = (); # 0..2 elements, which are units (grams).
1901              
1902             sub get_syllable($) {
1903 115     115 1 122 my $pwlen = shift;
1904              
1905             # these used to be "out" params:
1906 115         122 my $syllable; # string, returned
1907 115         147 my @units_in_syllable = (); # array of units, returned
1908              
1909              
1910             # grams:
1911 115         145 my $unit;
1912             my $current_unit;
1913 0         0 my $last_unit;
1914              
1915             # numbers:
1916 0         0 my $vowel_count;
1917 0         0 my $tries;
1918 0         0 my $length_left;
1919 0         0 my $outer_tries;
1920              
1921             # flags:
1922 0         0 my $rule_broken;
1923 0         0 my $want_vowel;
1924 0         0 my $want_another_unit;
1925              
1926              
1927             #
1928             # This is needed if the saved_pair is tried and the syllable then
1929             # discarded because of the retry limit. Since the saved_pair is OK and
1930             # fits in nicely with the preceding syllable, we will always use it.
1931             #
1932 115         167 my @hold_saved_pair = @saved_pair;
1933              
1934 115         178 my $max_retries = ( 4 * $pwlen ) + scalar( @grams );
1935             # note that this used to be a macro, which means it could have changed
1936             # dynamically based on the value of $pwlen...
1937              
1938             #
1939             # Loop until valid syllable is found.
1940             #
1941 115         126 $outer_tries = 0;
1942 115   100     123 do {
      66        
1943 508         681 ++$outer_tries;
1944             #
1945             # Try for a new syllable. Initialize all pertinent
1946             # syllable variables.
1947             #
1948 508         530 $tries = 0;
1949 508         1052 @saved_pair = @hold_saved_pair;
1950 508         618 $syllable = "";
1951 508         575 $vowel_count = 0;
1952 508         467 $current_unit = 0;
1953 508         599 $length_left = $pwlen;
1954 508         533 $want_another_unit = 1; # true
1955              
1956             #
1957             # This loop finds all the units for the syllable.
1958             #
1959 508   100     544 do {
1960 1376         1441 $want_vowel = 0; # false
1961              
1962             #
1963             # This loop continues until a valid unit is found for the
1964             # current position within the syllable.
1965             #
1966 1376   100     1552 do {
1967             #
1968             # If there are saved units from the previous syllable, use them up first.
1969             #
1970              
1971             #
1972             # If there were two saved units, the first is guaranteed
1973             # (by checks performed in the previous syllable) to be valid.
1974             # We ignore the checks and place it in this syllable manually.
1975             #
1976 22465 100       42129 if ( @saved_pair == 2 ) {
1977 264         589 $syllable =
1978             $units_in_syllable[0] = pop @saved_pair;
1979 264 50       753 $vowel_count++ if $rules{$syllable} & VOWEL;
1980 264         275 $current_unit++;
1981 264         379 $length_left -= length $syllable;
1982             }
1983              
1984 22465 100       34966 if ( @saved_pair ) {
1985             #
1986             # The unit becomes the last unit checked in the previous syllable.
1987             #
1988 452         696 $unit = pop @saved_pair;
1989              
1990             #
1991             # The saved units have been used.
1992             # Do not try to reuse them in this syllable
1993             # (unless this particular syllable is rejected
1994             # at which point we start to rebuild it with these same saved units).
1995             #
1996             }
1997             else {
1998             #
1999             # If we don't have to consider the saved units, we generate a random one.
2000             #
2001 22013 50       42192 $unit = _random_unit( $want_vowel ? VOWEL : NO_SPECIAL_RULE );
2002             }
2003              
2004 22465         39334 $length_left -= length $unit;
2005              
2006             #
2007             # Prevent having a word longer than expected.
2008             #
2009 22465         27031 $rule_broken = ( $length_left < 0 ); # boolean
2010              
2011             #
2012             # First unit of syllable.
2013             # This is special because the digram tests require 2 units and we don't have that yet.
2014             # Nevertheless, we can perform some checks.
2015             #
2016 22465 100       34478 if ( $current_unit == 0 ) {
2017             #
2018             # If the shouldn't begin a syllable, don't use it.
2019             #
2020 266 50       750 if ( $rules{$unit} & NOT_BEGIN_SYLLABLE ) {
    100          
2021 0         0 $rule_broken = 1; # true
2022             #
2023             # If this is the last unit of a word, we have a one unit syllable.
2024             # Since each syllable must have a vowel, we make sure the unit is a vowel.
2025             # Otherwise, we discard it.
2026             #
2027             }
2028             elsif ( $length_left == 0 ) {
2029 34 100       65 if ( $rules{$unit} & VOWEL ) {
2030 15         23 $want_another_unit = 0; # false
2031             }
2032             else {
2033 19         26 $rule_broken = 1; # true
2034             }
2035             }
2036             }
2037             else {
2038             #
2039             # this ALLOWED thing is only used in this code block.
2040             # note that $unit and $current_unit are (used to be) numeric indices; should now be actual grams.
2041             #
2042             local *ALLOWED = sub {
2043 128161     128161   144494 my $flag = shift;
2044 128161         593051 $digram{$units_in_syllable[$current_unit-1]}{$unit} & $flag
2045 22199         71321 };
2046              
2047             #
2048             # There are some digram tests that are universally true. We test them out.
2049             #
2050              
2051 22199 100 100     40894 if (
      66        
      100        
      66        
      66        
2052             #
2053             # Reject ILLEGAL_PAIRS of units.
2054             #
2055             (ALLOWED(ILLEGAL_PAIR))
2056             ||
2057              
2058             #
2059             # Reject units that will be split between syllables
2060             # when the syllable has no vowels in it.
2061             #
2062             (ALLOWED(BREAK) && ($vowel_count == 0))
2063             ||
2064              
2065             #
2066             # Reject a unit that will end a syllable when no
2067             # previous unit was a vowel and neither is this one.
2068             #
2069             (
2070             ALLOWED(BACK)
2071             &&
2072             ($vowel_count == 0)
2073             &&
2074             !($rules{$unit} & VOWEL)
2075             )
2076             ) {
2077 3925         4772 $rule_broken = 1; # true
2078             }
2079              
2080 22199 100       42895 if ($current_unit == 1) {
2081             #
2082             # Reject the unit if we are at the starting digram of
2083             # a syllable and it does not fit.
2084             #
2085 658 100       986 if (ALLOWED(NOT_FRONT)) {
2086 124         169 $rule_broken = 1; # true
2087             }
2088             }
2089             else {
2090             #
2091             # We are not at the start of a syllable.
2092             # Save the previous unit for later tests.
2093             #
2094 21541         34298 $last_unit = $units_in_syllable[$current_unit - 1];
2095              
2096             #
2097             # Do not allow syllables where the first letter is y
2098             # and the next pair can begin a syllable. This may
2099             # lead to splits where y is left alone in a syllable.
2100             # Also, the combination does not sound to good even
2101             # if not split.
2102             #
2103 21541 100 100     58493 if (
      66        
      100        
      33        
      100        
      66        
      100        
      66        
2104             (
2105             ($current_unit == 2)
2106             &&
2107             ALLOWED(FRONT)
2108             &&
2109             ($rules{$units_in_syllable[0]} & ALTERNATE_VOWEL)
2110             )
2111             ||
2112              
2113             #
2114             # If this is the last unit of a word, we should
2115             # reject any digram that cannot end a syllable.
2116             #
2117             (
2118             ALLOWED(NOT_BACK)
2119             &&
2120             ($length_left == 0)
2121             )
2122             ||
2123              
2124             #
2125             # Reject the unit if the digram it forms wants
2126             # to break the syllable, but the resulting
2127             # digram that would end the syllable is not
2128             # allowed to end a syllable.
2129             #
2130             (
2131             ALLOWED(BREAK)
2132             ||
2133             ($digram{ $units_in_syllable[$current_unit-2] }{$last_unit} & NOT_BACK)
2134             )
2135             ||
2136              
2137             #
2138             # Reject the unit if the digram it forms expects a vowel preceding it and there is none.
2139             #
2140             (
2141             ALLOWED(PREFIX)
2142             &&
2143             !($rules{ $units_in_syllable[$current_unit-2] } & VOWEL)
2144             )
2145             ) {
2146 21153         31476 $rule_broken = 1; # true
2147             }
2148              
2149             #
2150             # The following checks occur when the current unit is a vowel
2151             # and we are not looking at a word ending with an e.
2152             #
2153 21541 50 100     53189 if (
      66        
      66        
2154             !$rule_broken
2155             &&
2156             ($rules{$unit} & VOWEL)
2157             &&
2158             (
2159             ($length_left > 0)
2160             ||
2161             !($rules{$last_unit} & NO_FINAL_SPLIT)
2162             )
2163             ) {
2164             #
2165             # Don't allow 3 consecutive vowels in a syllable.
2166             # Although some words formed like this are OK, like "beau", most are not.
2167             #
2168 183 100 100     1161 if ( ($vowel_count > 1) && ($rules{$last_unit} & VOWEL) ) {
    100 100        
2169 12         21 $rule_broken = 1; # true
2170             }
2171             #
2172             # Check for the case of vowels-consonants-vowel,
2173             # which is only legal if the last vowel is an e and we are the end of the word
2174             # (which is not happening here due to a previous check).
2175             #
2176             elsif ( ($vowel_count != 0) && !($rules{$last_unit} & VOWEL) ) {
2177             #
2178             # Try to save the vowel for the next syllable,
2179             # but if the syllable left here is not proper
2180             # (i.e., the resulting last digram cannot legally end it),
2181             # just discard it and try for another.
2182             #
2183 160 50       389 if ( $digram{ $units_in_syllable[ $current_unit - 2] }{$last_unit} & NOT_BACK ) {
2184 0         0 $rule_broken = 1; # true
2185             }
2186             else {
2187 160         278 @saved_pair = ( $unit );
2188 160         237 $want_another_unit = 0; # false
2189             }
2190             }
2191             }
2192             }
2193              
2194             #
2195             # The unit picked and the digram formed are legal.
2196             # We now determine if we can end the syllable. It may,
2197             # in some cases, mean the last unit(s) may be deferred to
2198             # the next syllable. We also check here to see if the
2199             # digram formed expects a vowel to follow.
2200             #
2201 22199 100 100     82967 if ( !$rule_broken and $want_another_unit ) {
2202             #
2203             # This word ends in a silent e.
2204             #
2205 680 100 100     3492 if (
    100 66        
    100 33        
      100        
      33        
      66        
2206             (
2207             ($vowel_count != 0)
2208             &&
2209             ($rules{$unit} & NO_FINAL_SPLIT)
2210             &&
2211             ($length_left == 0)
2212             &&
2213             !($rules{$last_unit} & VOWEL)
2214             )
2215             or
2216              
2217             #
2218             # This syllable ends either because the digram
2219             # is a BACK pair or we would otherwise exceed
2220             # the length of the word.
2221             #
2222             ( ALLOWED(BACK) || ($length_left == 0) )
2223             ) {
2224 24         78 $want_another_unit = 0; # false
2225             }
2226              
2227             #
2228             # Since we have a vowel in the syllable
2229             # already, if the digram calls for the end of the
2230             # syllable, we can legally split it off. We also
2231             # make sure that we are not at the end of the
2232             # dangerous because that syllable may not have
2233             # vowels, or it may not be a legal syllable end,
2234             # and the retrying mechanism will loop infinitely
2235             # with the same digram.
2236             #
2237             elsif ( $vowel_count != 0 and $length_left > 0 ) {
2238             #
2239             # If we must begin a syllable, we do so if
2240             # the only vowel in THIS syllable is not part
2241             # of the digram we are pushing to the next
2242             # syllable.
2243             #
2244 341 100 66     551 if (
    100 100        
      100        
2245             ALLOWED(FRONT)
2246             &&
2247             ($current_unit > 1)
2248             &&
2249             !(
2250             ($vowel_count == 1)
2251             &&
2252             ($rules{$last_unit} & VOWEL)
2253             )
2254             ) {
2255 15         42 @saved_pair = ( $unit, $last_unit );
2256 15         46 $want_another_unit = 0; # false
2257             }
2258             elsif (ALLOWED (BREAK)) {
2259 2         6 @saved_pair = ( $unit );
2260 2         7 $want_another_unit = 0; # false
2261             }
2262             }
2263             elsif (ALLOWED (SUFFIX)) {
2264 154         514 $want_vowel = 1; # true
2265             }
2266             }
2267             }
2268              
2269 22465         23311 $tries++;
2270              
2271             #
2272             # If this unit was illegal, redetermine the amount of
2273             # letters left to go in the word.
2274             #
2275 22465 100       45380 if ( $rule_broken ) {
2276 21381         93123 $length_left += length $unit;
2277             }
2278             }
2279             while ( $rule_broken and $tries <= $max_retries );
2280              
2281             #
2282             # The unit fit OK.
2283             #
2284 1376 100       2399 if ( $tries <= $max_retries ) {
2285             #
2286             # If the unit were a vowel, count it in.
2287             # However, if the unit were a y and appear at the start of the syllable,
2288             # treat it like a constant (so that words like "year" can appear and
2289             # not conflict with the 3 consecutive vowel rule).
2290             #
2291 1084 100 100     3564 if (
      66        
2292             ($rules{$unit} & VOWEL)
2293             &&
2294             ( ($current_unit > 0) || !($rules{$unit} & ALTERNATE_VOWEL) )
2295             ) {
2296 446         467 $vowel_count++;
2297             }
2298              
2299             #
2300             # If a unit or units were to be saved, we must adjust the syllable formed.
2301             # Otherwise, we append the current unit to the syllable.
2302             #
2303 1084 100       2439 if ( @saved_pair == 2 ) {
    100          
2304             # strcpy( &syllable[ strlen( syllable ) - strlen( last_unit ) ], "" );
2305 15         33 my $n = length $last_unit;
2306 15         203 $syllable =~ s/.{$n}$//; # DOES THIS WORK?
2307 15         23 $length_left += length $last_unit;
2308 15         30 $current_unit -= 2;
2309             }
2310             elsif ( @saved_pair == 1 ) {
2311 162         203 $current_unit--;
2312             }
2313             else {
2314 907         1317 $units_in_syllable[ $current_unit ] = $unit;
2315 907         1226 $syllable .= $unit;
2316             }
2317             }
2318             else {
2319             #
2320             # Whoops! Too many tries.
2321             # We set rule_broken so we can loop in the outer loop and try another syllable.
2322             #
2323 292         381 $rule_broken = 1; # true
2324             }
2325              
2326 1376         6885 $current_unit++;
2327             }
2328             while ( $tries <= $max_retries and $want_another_unit );
2329             }
2330             while ( $outer_tries < $max_retries && ($rule_broken or _illegal_placement( @units_in_syllable )) );
2331              
2332 115 100       251 return ('') if $outer_tries >= $max_retries;
2333              
2334 110         468 return( $syllable, @units_in_syllable );
2335             } # sub get_syllable
2336              
2337              
2338             #
2339             # alt_get_syllable
2340             #
2341             # Takes an integer, the maximum number of chars to generate. (or is it minimum?)
2342             #
2343             # returns a list of ( string, units-in-syllable )
2344             #
2345             # I, which
2346             # can be useful for unit testing the other functions.>
2347             #
2348              
2349             sub alt_get_syllable($) { # alternative version, has no smarts.
2350 0     0 0 0 my $pwlen = shift; # max or min?
2351 0         0 for ( 0 .. $#grams ) {
2352 0         0 my $syl = '';
2353 0         0 my @syl_units = ();
2354 0         0 while ( @syl_units < 3 ) {
2355 0         0 my $unit = _random_unit( NO_SPECIAL_RULE );
2356 0         0 $syl .= $unit;
2357 0         0 push @syl_units, $unit;
2358 0 0       0 length($syl) >= $pwlen and return( $syl, @syl_units );
2359             }
2360 0 0       0 @syl_units and return( $syl, @syl_units );
2361             }
2362 0         0 return(); # failed
2363             }
2364              
2365              
2366             #
2367             # _illegal_placement
2368             #
2369             # goes through an individual syllable and checks for illegal
2370             # combinations of letters that go beyond looking at digrams.
2371             #
2372             # We look at things like 3 consecutive vowels or consonants,
2373             # or syllables with consonants between vowels
2374             # (unless one of them is the final silent e).
2375             #
2376             # returns boolean.
2377             #
2378              
2379             sub _illegal_placement(@) {
2380 215     215   475 my @units = @_;
2381              
2382 215         227 my $vowel_count = 0;
2383 215         216 my $failure = 0; # false
2384              
2385 215         461 for my $unit_count ( 0 .. $#units ) {
2386 798 100       1371 last if $failure;
2387              
2388 723 100       1240 if ( $unit_count >= 1 ) {
2389             #
2390             # Don't allow vowels to be split with consonants in a single syllable.
2391             # If we find such a combination (except for the silent e) we have to discard the syllable.
2392             #
2393 508 100 100     5446 if (
      66        
      66        
      100        
      66        
      66        
      66        
2394             (
2395             !( $rules{$units[$unit_count-1]} & VOWEL)
2396             &&
2397             ( $rules{$units[$unit_count ]} & VOWEL)
2398             &&
2399             !(($rules{$units[$unit_count ]} & NO_FINAL_SPLIT) && ($unit_count == $#units))
2400             &&
2401             $vowel_count
2402             )
2403             ||
2404              
2405             #
2406             # Perform these checks when we have at least 3 units.
2407             #
2408             (
2409             ($unit_count >= 2)
2410             &&
2411             (
2412             #
2413             # Disallow 3 consecutive consonants.
2414             #
2415             (
2416             !($rules{$units[$unit_count-2]} & VOWEL)
2417             &&
2418             !($rules{$units[$unit_count-1]} & VOWEL)
2419             &&
2420             !($rules{$units[$unit_count ]} & VOWEL)
2421             )
2422             ||
2423              
2424             #
2425             # Disallow 3 consecutive vowels, where the first is not a y.
2426             #
2427             (
2428             ( $rules{$units[$unit_count-2]} & VOWEL)
2429             &&
2430             !(($rules{$units[0 ]} & ALTERNATE_VOWEL) && ($unit_count == 2))
2431             &&
2432             ( $rules{$units[$unit_count-1]} & VOWEL)
2433             &&
2434             ( $rules{$units[$unit_count ]} & VOWEL)
2435             )
2436             )
2437             )
2438             ) {
2439 105         135 $failure = 1; # true
2440             }
2441             }
2442              
2443             #
2444             # Count the vowels in the syllable.
2445             # As mentioned somewhere above, exclude the initial y of a syllable.
2446             # Instead, treat it as a consonant.
2447             #
2448 723 100 100     2793 if (
      100        
2449             ($rules{$units[$unit_count]} & VOWEL)
2450             &&
2451             !(
2452             ($rules{$units[0]} & ALTERNATE_VOWEL)
2453             &&
2454             ($unit_count == 0)
2455             &&
2456             (@units > 1)
2457             )
2458             ) {
2459 258         350 $vowel_count++;
2460             }
2461             }
2462              
2463 215         928 $failure;
2464             }
2465              
2466             }
2467              
2468             unless ( defined caller ) {
2469              
2470             # this can be used for unit testing or to make the module a stand-alone program.
2471             package main;
2472 3     3   4596 use Getopt::Long;
  3         44387  
  3         20  
2473              
2474             $^W = 1;
2475              
2476             my $algorithm = 'word'; # default: word
2477             my $maxlen = 8;
2478             my $minlen = 6;
2479             my $num_words = 1;
2480             $main::DEBUG = 0;
2481              
2482             GetOptions(
2483             'seed=s' => \$Crypt::RandPasswd::seed,
2484             'algorithm=s' => \$algorithm, # select word, letters, chars
2485             'max=s' => \$maxlen,
2486             'min=s' => \$minlen,
2487             'count=s' => \$num_words,
2488             'debug!' => \$main::DEBUG,
2489             )
2490             or die "Usage: $0 --count N --min N --max N --algorithm [word|letters|chars] --seed N --[no]debug \n";
2491              
2492             $minlen <= $maxlen or die "minimum word length ($minlen) must be <= maximum ($maxlen)\n";
2493              
2494             UNIVERSAL::can( "Crypt::RandPasswd", $algorithm ) or die "Invalid algorithm '$algorithm'\n";
2495              
2496             print STDERR "$num_words '$algorithm' words of $minlen-$maxlen chars \n"
2497             if $main::DEBUG ;
2498              
2499             for ( 1 .. $num_words ) {
2500             my( $unhyphenated_word, $hyphenated_word ) = Crypt::RandPasswd->$algorithm( $minlen, $maxlen );
2501              
2502             print
2503             $algorithm eq 'word'
2504             ? "$unhyphenated_word ($hyphenated_word)\n"
2505             : "$unhyphenated_word\n";
2506             }
2507              
2508             } # end of 'main' code.
2509              
2510             1;
2511              
2512             =head1 SEE ALSO
2513              
2514             L - a review of modules of CPAN for random password generation.
2515              
2516             Some of the better modules:
2517             L, L,
2518             L, L,
2519             L.
2520              
2521             FIPS 181 - (APG), Automated Password Generator:
2522             http://www.itl.nist.gov/fipspubs/fip181.htm
2523              
2524             =head1 REPOSITORY
2525              
2526             L
2527              
2528             =head1 AUTHOR
2529              
2530             JDPORTER@cpan.org (John Porter)
2531              
2532             Now maintained by Neil Bowers Eneilb@cpan.orgE
2533              
2534             =head1 COPYRIGHT
2535              
2536             This perl module is free software; it may be redistributed and/or modified
2537             under the same terms as Perl itself.
2538              
2539             =cut
2540