generator.py 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367
  1. #============================================================================
  2. # This file is part of Pwman3.
  3. #
  4. # Pwman3 is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License, version 2
  6. # as published by the Free Software Foundation;
  7. #
  8. # Pwman3 is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with Pwman3; if not, write to the Free Software
  15. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. #============================================================================
  17. # Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
  18. #============================================================================
  19. #============================================================================
  20. # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
  21. #============================================================================
  22. """
  23. Functions to generate passwords.
  24. Based heavily on passogva.py (c) 2004 Mo-Tsuki, LLC.
  25. http://dev.mosuki.com/passogva/
  26. Usage:
  27. import pwman.util.generator as PwGen
  28. minlen = 6
  29. maxlen = 8
  30. (word, hypenated_word) = PwGen.generate_password(minlen, maxlen)
  31. """
  32. from Crypto.Random import random
  33. class PasswordGenerationException(Exception):
  34. def __init__(self, message):
  35. self.message = message
  36. def __str__(self):
  37. return self.message
  38. def generate_password(minlen, maxlen, capitals = True, symbols = False, \
  39. numerics = False, special_chars = False):
  40. (password, hyphenated) = generate_password_shazel(minlen, maxlen)
  41. if (capitals):
  42. password = randomly_capitalize(password)
  43. if (symbols):
  44. password = leetify(password)
  45. if (numerics):
  46. password = change_numerics(password)
  47. if (special_chars):
  48. password = random_special_sign(password)
  49. return (password, hyphenated)
  50. def randomly_capitalize(password):
  51. newpassword = str()
  52. for l in password:
  53. if random.randint(0, 1):
  54. l = l.upper()
  55. newpassword = newpassword + l
  56. return newpassword
  57. def leetify(password):
  58. newpassword = str()
  59. for l in password:
  60. if random.randint(0, 1):
  61. l = leetify_char(l)
  62. newpassword = newpassword + l
  63. return newpassword
  64. def random_special_sign(password):
  65. """
  66. replace one letter with a special sign,
  67. this will do the following:
  68. In [203]: for i in range(10):
  69. print random_special_sign("secret")
  70. .....:
  71. secre%
  72. sec\et
  73. secre?
  74. s;cret
  75. se$ret
  76. secr}t
  77. secr*t
  78. ;ecret
  79. s%cret
  80. secre(
  81. note: numbers are not replaced:
  82. In [5]: for i in range(10):
  83. print random_special_sign(password)
  84. ...:
  85. s3cr?t
  86. s3cr$t
  87. s3cre#
  88. $3cret
  89. s3c\et
  90. s3cr-t
  91. }3cret
  92. s3*ret
  93. s3cre:
  94. s3cr@t
  95. In [6]: password = "v3r71mp0rt4nt"
  96. In [7]: for i in range(10):
  97. print random_special_sign(password)
  98. ...:
  99. v3r71mp0rt4)t
  100. v3r71m&0rt4nt
  101. v3r71mp0rt4-t
  102. v3r71mp0rt4&t
  103. v3^71mp0rt4nt
  104. v3r71@p0rt4nt
  105. v3}71mp0rt4nt
  106. v3r71m}0rt4nt
  107. v3r71mp0r*4nt
  108. v3^71mp0rt4nt
  109. """
  110. newpass = str()
  111. specialsigns = ["@", "#", "?", "!", '\\', "|", "$",
  112. "%", "^", "&", "*", "(", ")", ":", ";",
  113. "{", "}", "+","-"]
  114. place = int(random.randint(0, len(password)-1))
  115. while password[place].isdigit():
  116. place = int(random.randint(0, len(password)-1))
  117. randomsign = specialsigns[int(random.randint(0, len(specialsigns)-1))]
  118. for idx, letter in enumerate(password):
  119. if not idx == place:
  120. newpass = newpass + letter
  121. if idx == place:
  122. newpass = newpass + randomsign
  123. return newpass
  124. def change_numerics(password):
  125. newpassword = str()
  126. for l in password:
  127. if random.randint(0, 1):
  128. l = change_numerics_char(l)
  129. newpassword = newpassword + l
  130. return newpassword
  131. #
  132. # Dictionary of mappings for leetness
  133. #
  134. leetlist = {
  135. 'w': "\/\/", 'W': "\/\/", 'e': '3', 'E': '3', 't': '+', 'T': '7',
  136. 'i': '1', 'I': '1', 'o': '0', 'O': '0', 'A': '4', 's': '5', 'S': '$',
  137. 'g': '9', 'K': '|<', 'k': '|<', 'x': '><', 'X': '><', 'c': '<', 'C': '<',
  138. 'v': '\/', 'V': '\/', 'n': '|\|', 'N': '|\|', 'm': '|\/|', 'M': '|\/|'
  139. }
  140. def leetify_char(l):
  141. try:
  142. return leetlist[l]
  143. except KeyError:
  144. return l
  145. numericlist = {
  146. 'e': '3', 'E': '3', 'T': '7',
  147. 'i': '1', 'I': '1', 'o': '0', 'O': '0', 'A': '4', 's': '5', 'S': '5',
  148. 'g': '9', 'q': '9', 'l': '1'
  149. }
  150. def change_numerics_char(l):
  151. try:
  152. return numericlist[l]
  153. except KeyError:
  154. return l
  155. #
  156. # Beyond this point layeth Steve Hazel's code
  157. # Steven Hazel <sah@mosuki.com>
  158. #
  159. # I've added exceptions
  160. #
  161. MIN_LENGTH_PASSWORD = 6
  162. MAX_LENGTH_PASSWORD = 14
  163. grams = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
  164. 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
  165. 'z', 'ch', 'gh', 'ph', 'rh', 'sh', 'th', 'wh', 'qu', 'ck')
  166. vowel_grams = ('a', 'e', 'i', 'o', 'u', 'y')
  167. occurrence_frequencies = {
  168. 'a' : 10, 'b' : 8, 'c' : 12, 'd' : 12,
  169. 'e' : 12, 'f' : 8, 'g' : 8, 'h' : 6,
  170. 'i' : 10, 'j' : 8, 'k' : 8, 'l' : 6,
  171. 'm' : 6, 'n' : 10, 'o' : 10, 'p' : 6,
  172. 'r' : 10, 's' : 8, 't' : 10, 'u' : 6,
  173. 'v' : 8, 'w' : 8, 'x' : 1, 'y' : 8,
  174. 'z' : 1, 'ch' : 1, 'gh' : 1, 'ph' : 1,
  175. 'rh' : 1, 'sh' : 2, 'th' : 1, 'wh' : 1,
  176. 'qu' : 1, 'ck' : 1}
  177. numbers = []
  178. for gram in grams:
  179. for i in range(occurrence_frequencies[gram]):
  180. numbers.append(gram)
  181. vowel_numbers = []
  182. for gram in vowel_grams:
  183. for i in range(occurrence_frequencies[gram]):
  184. vowel_numbers.append(gram)
  185. #
  186. # Bit flags
  187. #
  188. MAX_UNACCEPTABLE = 20
  189. # gram rules:
  190. NOT_BEGIN_SYLLABLE = 0x08
  191. NO_FINAL_SPLIT = 0x04
  192. VOWEL = 0x02
  193. ALTERNATE_VOWEL = 0x01
  194. NO_SPECIAL_RULE = 0x00
  195. # digram rules:
  196. BEGIN = 0x80
  197. NOT_BEGIN = 0x40
  198. BREAK = 0x20
  199. PREFIX = 0x10
  200. ILLEGAL_PAIR = 0x08
  201. SUFFIX = 0x04
  202. END = 0x02
  203. NOT_END = 0x01
  204. ANY_COMBINATION = 0x00
  205. gram_rules = dict()
  206. for gram in grams:
  207. gram_rules[ gram ] = NO_SPECIAL_RULE
  208. for gram in vowel_grams:
  209. gram_rules[ gram ] = VOWEL
  210. gram_rules['e'] |= NO_FINAL_SPLIT
  211. gram_rules['y'] |= ALTERNATE_VOWEL
  212. gram_rules['x'] = NOT_BEGIN_SYLLABLE
  213. gram_rules['ck'] = NOT_BEGIN_SYLLABLE
  214. digram_rules = dict()
  215. ###############################################################################
  216. # BEGIN DIGRAM RULES
  217. ###############################################################################
  218. digram_rules['a'] = dict()
  219. digram_rules['a']['a'] = ILLEGAL_PAIR
  220. digram_rules['a']['b'] = ANY_COMBINATION
  221. digram_rules['a']['c'] = ANY_COMBINATION
  222. digram_rules['a']['d'] = ANY_COMBINATION
  223. digram_rules['a']['e'] = ILLEGAL_PAIR
  224. digram_rules['a']['f'] = ANY_COMBINATION
  225. digram_rules['a']['g'] = ANY_COMBINATION
  226. digram_rules['a']['h'] = NOT_BEGIN | BREAK | NOT_END
  227. digram_rules['a']['i'] = ANY_COMBINATION
  228. digram_rules['a']['j'] = ANY_COMBINATION
  229. digram_rules['a']['k'] = ANY_COMBINATION
  230. digram_rules['a']['l'] = ANY_COMBINATION
  231. digram_rules['a']['m'] = ANY_COMBINATION
  232. digram_rules['a']['n'] = ANY_COMBINATION
  233. digram_rules['a']['o'] = ILLEGAL_PAIR
  234. digram_rules['a']['p'] = ANY_COMBINATION
  235. digram_rules['a']['r'] = ANY_COMBINATION
  236. digram_rules['a']['s'] = ANY_COMBINATION
  237. digram_rules['a']['t'] = ANY_COMBINATION
  238. digram_rules['a']['u'] = ANY_COMBINATION
  239. digram_rules['a']['v'] = ANY_COMBINATION
  240. digram_rules['a']['w'] = ANY_COMBINATION
  241. digram_rules['a']['x'] = ANY_COMBINATION
  242. digram_rules['a']['y'] = ANY_COMBINATION
  243. digram_rules['a']['z'] = ANY_COMBINATION
  244. digram_rules['a']['ch'] = ANY_COMBINATION
  245. digram_rules['a']['gh'] = ILLEGAL_PAIR
  246. digram_rules['a']['ph'] = ANY_COMBINATION
  247. digram_rules['a']['rh'] = ILLEGAL_PAIR
  248. digram_rules['a']['sh'] = ANY_COMBINATION
  249. digram_rules['a']['th'] = ANY_COMBINATION
  250. digram_rules['a']['wh'] = ILLEGAL_PAIR
  251. digram_rules['a']['qu'] = BREAK | NOT_END
  252. digram_rules['a']['ck'] = ANY_COMBINATION
  253. digram_rules['b'] = dict()
  254. digram_rules['b']['a'] = ANY_COMBINATION
  255. digram_rules['b']['b'] = NOT_BEGIN | BREAK | NOT_END
  256. digram_rules['b']['c'] = NOT_BEGIN | BREAK | NOT_END
  257. digram_rules['b']['d'] = NOT_BEGIN | BREAK | NOT_END
  258. digram_rules['b']['e'] = ANY_COMBINATION
  259. digram_rules['b']['f'] = NOT_BEGIN | BREAK | NOT_END
  260. digram_rules['b']['g'] = NOT_BEGIN | BREAK | NOT_END
  261. digram_rules['b']['h'] = NOT_BEGIN | BREAK | NOT_END
  262. digram_rules['b']['i'] = ANY_COMBINATION
  263. digram_rules['b']['j'] = NOT_BEGIN | BREAK | NOT_END
  264. digram_rules['b']['k'] = NOT_BEGIN | BREAK | NOT_END
  265. digram_rules['b']['l'] = BEGIN | SUFFIX | NOT_END
  266. digram_rules['b']['m'] = NOT_BEGIN | BREAK | NOT_END
  267. digram_rules['b']['n'] = NOT_BEGIN | BREAK | NOT_END
  268. digram_rules['b']['o'] = ANY_COMBINATION
  269. digram_rules['b']['p'] = NOT_BEGIN | BREAK | NOT_END
  270. digram_rules['b']['r'] = BEGIN | END
  271. digram_rules['b']['s'] = NOT_BEGIN
  272. digram_rules['b']['t'] = NOT_BEGIN | BREAK | NOT_END
  273. digram_rules['b']['u'] = ANY_COMBINATION
  274. digram_rules['b']['v'] = NOT_BEGIN | BREAK | NOT_END
  275. digram_rules['b']['w'] = NOT_BEGIN | BREAK | NOT_END
  276. digram_rules['b']['x'] = ILLEGAL_PAIR
  277. digram_rules['b']['y'] = ANY_COMBINATION
  278. digram_rules['b']['z'] = NOT_BEGIN | BREAK | NOT_END
  279. digram_rules['b']['ch'] = NOT_BEGIN | BREAK | NOT_END
  280. digram_rules['b']['gh'] = ILLEGAL_PAIR
  281. digram_rules['b']['ph'] = NOT_BEGIN | BREAK | NOT_END
  282. digram_rules['b']['rh'] = ILLEGAL_PAIR
  283. digram_rules['b']['sh'] = NOT_BEGIN | BREAK | NOT_END
  284. digram_rules['b']['th'] = NOT_BEGIN | BREAK | NOT_END
  285. digram_rules['b']['wh'] = ILLEGAL_PAIR
  286. digram_rules['b']['qu'] = NOT_BEGIN | BREAK | NOT_END
  287. digram_rules['b']['ck'] = ILLEGAL_PAIR
  288. digram_rules['c'] = dict()
  289. digram_rules['c']['a'] = ANY_COMBINATION
  290. digram_rules['c']['b'] = NOT_BEGIN | BREAK | NOT_END
  291. digram_rules['c']['c'] = NOT_BEGIN | BREAK | NOT_END
  292. digram_rules['c']['d'] = NOT_BEGIN | BREAK | NOT_END
  293. digram_rules['c']['e'] = ANY_COMBINATION
  294. digram_rules['c']['f'] = NOT_BEGIN | BREAK | NOT_END
  295. digram_rules['c']['g'] = NOT_BEGIN | BREAK | NOT_END
  296. digram_rules['c']['h'] = NOT_BEGIN | BREAK | NOT_END
  297. digram_rules['c']['i'] = ANY_COMBINATION
  298. digram_rules['c']['j'] = NOT_BEGIN | BREAK | NOT_END
  299. digram_rules['c']['k'] = NOT_BEGIN | BREAK | NOT_END
  300. digram_rules['c']['l'] = SUFFIX | NOT_END
  301. digram_rules['c']['m'] = NOT_BEGIN | BREAK | NOT_END
  302. digram_rules['c']['n'] = NOT_BEGIN | BREAK | NOT_END
  303. digram_rules['c']['o'] = ANY_COMBINATION
  304. digram_rules['c']['p'] = NOT_BEGIN | BREAK | NOT_END
  305. digram_rules['c']['r'] = NOT_END
  306. digram_rules['c']['s'] = NOT_BEGIN | END
  307. digram_rules['c']['t'] = NOT_BEGIN | PREFIX
  308. digram_rules['c']['u'] = ANY_COMBINATION
  309. digram_rules['c']['v'] = NOT_BEGIN | BREAK | NOT_END
  310. digram_rules['c']['w'] = NOT_BEGIN | BREAK | NOT_END
  311. digram_rules['c']['x'] = ILLEGAL_PAIR
  312. digram_rules['c']['y'] = ANY_COMBINATION
  313. digram_rules['c']['z'] = NOT_BEGIN | BREAK | NOT_END
  314. digram_rules['c']['ch'] = ILLEGAL_PAIR
  315. digram_rules['c']['gh'] = ILLEGAL_PAIR
  316. digram_rules['c']['ph'] = NOT_BEGIN | BREAK | NOT_END
  317. digram_rules['c']['rh'] = ILLEGAL_PAIR
  318. digram_rules['c']['sh'] = NOT_BEGIN | BREAK | NOT_END
  319. digram_rules['c']['th'] = NOT_BEGIN | BREAK | NOT_END
  320. digram_rules['c']['wh'] = ILLEGAL_PAIR
  321. digram_rules['c']['qu'] = NOT_BEGIN | SUFFIX | NOT_END
  322. digram_rules['c']['ck'] = ILLEGAL_PAIR
  323. digram_rules['d'] = dict()
  324. digram_rules['d']['a'] = ANY_COMBINATION
  325. digram_rules['d']['b'] = NOT_BEGIN | BREAK | NOT_END
  326. digram_rules['d']['c'] = NOT_BEGIN | BREAK | NOT_END
  327. digram_rules['d']['d'] = NOT_BEGIN
  328. digram_rules['d']['e'] = ANY_COMBINATION
  329. digram_rules['d']['f'] = NOT_BEGIN | BREAK | NOT_END
  330. digram_rules['d']['g'] = NOT_BEGIN | BREAK | NOT_END
  331. digram_rules['d']['h'] = NOT_BEGIN | BREAK | NOT_END
  332. digram_rules['d']['i'] = ANY_COMBINATION
  333. digram_rules['d']['j'] = NOT_BEGIN | BREAK | NOT_END
  334. digram_rules['d']['k'] = NOT_BEGIN | BREAK | NOT_END
  335. digram_rules['d']['l'] = NOT_BEGIN | BREAK | NOT_END
  336. digram_rules['d']['m'] = NOT_BEGIN | BREAK | NOT_END
  337. digram_rules['d']['n'] = NOT_BEGIN | BREAK | NOT_END
  338. digram_rules['d']['o'] = ANY_COMBINATION
  339. digram_rules['d']['p'] = NOT_BEGIN | BREAK | NOT_END
  340. digram_rules['d']['r'] = BEGIN | NOT_END
  341. digram_rules['d']['s'] = NOT_BEGIN | END
  342. digram_rules['d']['t'] = NOT_BEGIN | BREAK | NOT_END
  343. digram_rules['d']['u'] = ANY_COMBINATION
  344. digram_rules['d']['v'] = NOT_BEGIN | BREAK | NOT_END
  345. digram_rules['d']['w'] = NOT_BEGIN | BREAK | NOT_END
  346. digram_rules['d']['x'] = ILLEGAL_PAIR
  347. digram_rules['d']['y'] = ANY_COMBINATION
  348. digram_rules['d']['z'] = NOT_BEGIN | BREAK | NOT_END
  349. digram_rules['d']['ch'] = NOT_BEGIN | BREAK | NOT_END
  350. digram_rules['d']['gh'] = NOT_BEGIN | BREAK | NOT_END
  351. digram_rules['d']['ph'] = NOT_BEGIN | BREAK | NOT_END
  352. digram_rules['d']['rh'] = ILLEGAL_PAIR
  353. digram_rules['d']['sh'] = NOT_BEGIN | NOT_END
  354. digram_rules['d']['th'] = NOT_BEGIN | PREFIX
  355. digram_rules['d']['wh'] = ILLEGAL_PAIR
  356. digram_rules['d']['qu'] = NOT_BEGIN | BREAK | NOT_END
  357. digram_rules['d']['ck'] = ILLEGAL_PAIR
  358. digram_rules['e'] = dict()
  359. digram_rules['e']['a'] = ANY_COMBINATION
  360. digram_rules['e']['b'] = ANY_COMBINATION
  361. digram_rules['e']['c'] = ANY_COMBINATION
  362. digram_rules['e']['d'] = ANY_COMBINATION
  363. digram_rules['e']['e'] = ANY_COMBINATION
  364. digram_rules['e']['f'] = ANY_COMBINATION
  365. digram_rules['e']['g'] = ANY_COMBINATION
  366. digram_rules['e']['h'] = NOT_BEGIN | BREAK | NOT_END
  367. digram_rules['e']['i'] = NOT_END
  368. digram_rules['e']['j'] = ANY_COMBINATION
  369. digram_rules['e']['k'] = ANY_COMBINATION
  370. digram_rules['e']['l'] = ANY_COMBINATION
  371. digram_rules['e']['m'] = ANY_COMBINATION
  372. digram_rules['e']['n'] = ANY_COMBINATION
  373. digram_rules['e']['o'] = BREAK
  374. digram_rules['e']['p'] = ANY_COMBINATION
  375. digram_rules['e']['r'] = ANY_COMBINATION
  376. digram_rules['e']['s'] = ANY_COMBINATION
  377. digram_rules['e']['t'] = ANY_COMBINATION
  378. digram_rules['e']['u'] = ANY_COMBINATION
  379. digram_rules['e']['v'] = ANY_COMBINATION
  380. digram_rules['e']['w'] = ANY_COMBINATION
  381. digram_rules['e']['x'] = ANY_COMBINATION
  382. digram_rules['e']['y'] = ANY_COMBINATION
  383. digram_rules['e']['z'] = ANY_COMBINATION
  384. digram_rules['e']['ch'] = ANY_COMBINATION
  385. digram_rules['e']['gh'] = NOT_BEGIN | BREAK | NOT_END
  386. digram_rules['e']['ph'] = ANY_COMBINATION
  387. digram_rules['e']['rh'] = ILLEGAL_PAIR
  388. digram_rules['e']['sh'] = ANY_COMBINATION
  389. digram_rules['e']['th'] = ANY_COMBINATION
  390. digram_rules['e']['wh'] = ILLEGAL_PAIR
  391. digram_rules['e']['qu'] = BREAK | NOT_END
  392. digram_rules['e']['ck'] = ANY_COMBINATION
  393. digram_rules['f'] = dict()
  394. digram_rules['f']['a'] = ANY_COMBINATION
  395. digram_rules['f']['b'] = NOT_BEGIN | BREAK | NOT_END
  396. digram_rules['f']['c'] = NOT_BEGIN | BREAK | NOT_END
  397. digram_rules['f']['d'] = NOT_BEGIN | BREAK | NOT_END
  398. digram_rules['f']['e'] = ANY_COMBINATION
  399. digram_rules['f']['f'] = NOT_BEGIN
  400. digram_rules['f']['g'] = NOT_BEGIN | BREAK | NOT_END
  401. digram_rules['f']['h'] = NOT_BEGIN | BREAK | NOT_END
  402. digram_rules['f']['i'] = ANY_COMBINATION
  403. digram_rules['f']['j'] = NOT_BEGIN | BREAK | NOT_END
  404. digram_rules['f']['k'] = NOT_BEGIN | BREAK | NOT_END
  405. digram_rules['f']['l'] = BEGIN | SUFFIX | NOT_END
  406. digram_rules['f']['m'] = NOT_BEGIN | BREAK | NOT_END
  407. digram_rules['f']['n'] = NOT_BEGIN | BREAK | NOT_END
  408. digram_rules['f']['o'] = ANY_COMBINATION
  409. digram_rules['f']['p'] = NOT_BEGIN | BREAK | NOT_END
  410. digram_rules['f']['r'] = BEGIN | NOT_END
  411. digram_rules['f']['s'] = NOT_BEGIN
  412. digram_rules['f']['t'] = NOT_BEGIN
  413. digram_rules['f']['u'] = ANY_COMBINATION
  414. digram_rules['f']['v'] = NOT_BEGIN | BREAK | NOT_END
  415. digram_rules['f']['w'] = NOT_BEGIN | BREAK | NOT_END
  416. digram_rules['f']['x'] = ILLEGAL_PAIR
  417. digram_rules['f']['y'] = NOT_BEGIN
  418. digram_rules['f']['z'] = NOT_BEGIN | BREAK | NOT_END
  419. digram_rules['f']['ch'] = NOT_BEGIN | BREAK | NOT_END
  420. digram_rules['f']['gh'] = NOT_BEGIN | BREAK | NOT_END
  421. digram_rules['f']['ph'] = NOT_BEGIN | BREAK | NOT_END
  422. digram_rules['f']['rh'] = ILLEGAL_PAIR
  423. digram_rules['f']['sh'] = NOT_BEGIN | BREAK | NOT_END
  424. digram_rules['f']['th'] = NOT_BEGIN | BREAK | NOT_END
  425. digram_rules['f']['wh'] = ILLEGAL_PAIR
  426. digram_rules['f']['qu'] = NOT_BEGIN | BREAK | NOT_END
  427. digram_rules['f']['ck'] = ILLEGAL_PAIR
  428. digram_rules['g'] = dict()
  429. digram_rules['g']['a'] = ANY_COMBINATION
  430. digram_rules['g']['b'] = NOT_BEGIN | BREAK | NOT_END
  431. digram_rules['g']['c'] = NOT_BEGIN | BREAK | NOT_END
  432. digram_rules['g']['d'] = NOT_BEGIN | BREAK | NOT_END
  433. digram_rules['g']['e'] = ANY_COMBINATION
  434. digram_rules['g']['f'] = NOT_BEGIN | BREAK | NOT_END
  435. digram_rules['g']['g'] = NOT_BEGIN
  436. digram_rules['g']['h'] = NOT_BEGIN | BREAK | NOT_END
  437. digram_rules['g']['i'] = ANY_COMBINATION
  438. digram_rules['g']['j'] = NOT_BEGIN | BREAK | NOT_END
  439. digram_rules['g']['k'] = ILLEGAL_PAIR
  440. digram_rules['g']['l'] = BEGIN | SUFFIX | NOT_END
  441. digram_rules['g']['m'] = NOT_BEGIN | BREAK | NOT_END
  442. digram_rules['g']['n'] = NOT_BEGIN | BREAK | NOT_END
  443. digram_rules['g']['o'] = ANY_COMBINATION
  444. digram_rules['g']['p'] = NOT_BEGIN | BREAK | NOT_END
  445. digram_rules['g']['r'] = BEGIN | NOT_END
  446. digram_rules['g']['s'] = NOT_BEGIN | END
  447. digram_rules['g']['t'] = NOT_BEGIN | BREAK | NOT_END
  448. digram_rules['g']['u'] = ANY_COMBINATION
  449. digram_rules['g']['v'] = NOT_BEGIN | BREAK | NOT_END
  450. digram_rules['g']['w'] = NOT_BEGIN | BREAK | NOT_END
  451. digram_rules['g']['x'] = ILLEGAL_PAIR
  452. digram_rules['g']['y'] = NOT_BEGIN
  453. digram_rules['g']['z'] = NOT_BEGIN | BREAK | NOT_END
  454. digram_rules['g']['ch'] = NOT_BEGIN | BREAK | NOT_END
  455. digram_rules['g']['gh'] = ILLEGAL_PAIR
  456. digram_rules['g']['ph'] = NOT_BEGIN | BREAK | NOT_END
  457. digram_rules['g']['rh'] = ILLEGAL_PAIR
  458. digram_rules['g']['sh'] = NOT_BEGIN
  459. digram_rules['g']['th'] = NOT_BEGIN
  460. digram_rules['g']['wh'] = ILLEGAL_PAIR
  461. digram_rules['g']['qu'] = NOT_BEGIN | BREAK | NOT_END
  462. digram_rules['g']['ck'] = ILLEGAL_PAIR
  463. digram_rules['h'] = dict()
  464. digram_rules['h']['a'] = ANY_COMBINATION
  465. digram_rules['h']['b'] = NOT_BEGIN | BREAK | NOT_END
  466. digram_rules['h']['c'] = NOT_BEGIN | BREAK | NOT_END
  467. digram_rules['h']['d'] = NOT_BEGIN | BREAK | NOT_END
  468. digram_rules['h']['e'] = ANY_COMBINATION
  469. digram_rules['h']['f'] = NOT_BEGIN | BREAK | NOT_END
  470. digram_rules['h']['g'] = NOT_BEGIN | BREAK | NOT_END
  471. digram_rules['h']['h'] = ILLEGAL_PAIR
  472. digram_rules['h']['i'] = ANY_COMBINATION
  473. digram_rules['h']['j'] = NOT_BEGIN | BREAK | NOT_END
  474. digram_rules['h']['k'] = NOT_BEGIN | BREAK | NOT_END
  475. digram_rules['h']['l'] = NOT_BEGIN | BREAK | NOT_END
  476. digram_rules['h']['m'] = NOT_BEGIN | BREAK | NOT_END
  477. digram_rules['h']['n'] = NOT_BEGIN | BREAK | NOT_END
  478. digram_rules['h']['o'] = ANY_COMBINATION
  479. digram_rules['h']['p'] = NOT_BEGIN | BREAK | NOT_END
  480. digram_rules['h']['r'] = NOT_BEGIN | BREAK | NOT_END
  481. digram_rules['h']['s'] = NOT_BEGIN | BREAK | NOT_END
  482. digram_rules['h']['t'] = NOT_BEGIN | BREAK | NOT_END
  483. digram_rules['h']['u'] = ANY_COMBINATION
  484. digram_rules['h']['v'] = NOT_BEGIN | BREAK | NOT_END
  485. digram_rules['h']['w'] = NOT_BEGIN | BREAK | NOT_END
  486. digram_rules['h']['x'] = ILLEGAL_PAIR
  487. digram_rules['h']['y'] = ANY_COMBINATION
  488. digram_rules['h']['z'] = NOT_BEGIN | BREAK | NOT_END
  489. digram_rules['h']['ch'] = NOT_BEGIN | BREAK | NOT_END
  490. digram_rules['h']['gh'] = NOT_BEGIN | BREAK | NOT_END
  491. digram_rules['h']['ph'] = NOT_BEGIN | BREAK | NOT_END
  492. digram_rules['h']['rh'] = ILLEGAL_PAIR
  493. digram_rules['h']['sh'] = NOT_BEGIN | BREAK | NOT_END
  494. digram_rules['h']['th'] = NOT_BEGIN | BREAK | NOT_END
  495. digram_rules['h']['wh'] = ILLEGAL_PAIR
  496. digram_rules['h']['qu'] = NOT_BEGIN | BREAK | NOT_END
  497. digram_rules['h']['ck'] = ILLEGAL_PAIR
  498. digram_rules['i'] = dict()
  499. digram_rules['i']['a'] = ANY_COMBINATION
  500. digram_rules['i']['b'] = ANY_COMBINATION
  501. digram_rules['i']['c'] = ANY_COMBINATION
  502. digram_rules['i']['d'] = ANY_COMBINATION
  503. digram_rules['i']['e'] = NOT_BEGIN
  504. digram_rules['i']['f'] = ANY_COMBINATION
  505. digram_rules['i']['g'] = ANY_COMBINATION
  506. digram_rules['i']['h'] = NOT_BEGIN | BREAK | NOT_END
  507. digram_rules['i']['i'] = ILLEGAL_PAIR
  508. digram_rules['i']['j'] = ANY_COMBINATION
  509. digram_rules['i']['k'] = ANY_COMBINATION
  510. digram_rules['i']['l'] = ANY_COMBINATION
  511. digram_rules['i']['m'] = ANY_COMBINATION
  512. digram_rules['i']['n'] = ANY_COMBINATION
  513. digram_rules['i']['o'] = BREAK
  514. digram_rules['i']['p'] = ANY_COMBINATION
  515. digram_rules['i']['r'] = ANY_COMBINATION
  516. digram_rules['i']['s'] = ANY_COMBINATION
  517. digram_rules['i']['t'] = ANY_COMBINATION
  518. digram_rules['i']['u'] = NOT_BEGIN | BREAK | NOT_END
  519. digram_rules['i']['v'] = ANY_COMBINATION
  520. digram_rules['i']['w'] = NOT_BEGIN | BREAK | NOT_END
  521. digram_rules['i']['x'] = ANY_COMBINATION
  522. digram_rules['i']['y'] = NOT_BEGIN | BREAK | NOT_END
  523. digram_rules['i']['z'] = ANY_COMBINATION
  524. digram_rules['i']['ch'] = ANY_COMBINATION
  525. digram_rules['i']['gh'] = NOT_BEGIN
  526. digram_rules['i']['ph'] = ANY_COMBINATION
  527. digram_rules['i']['rh'] = ILLEGAL_PAIR
  528. digram_rules['i']['sh'] = ANY_COMBINATION
  529. digram_rules['i']['th'] = ANY_COMBINATION
  530. digram_rules['i']['wh'] = ILLEGAL_PAIR
  531. digram_rules['i']['qu'] = BREAK | NOT_END
  532. digram_rules['i']['ck'] = ANY_COMBINATION
  533. digram_rules['j'] = dict()
  534. digram_rules['j']['a'] = ANY_COMBINATION
  535. digram_rules['j']['b'] = NOT_BEGIN | BREAK | NOT_END
  536. digram_rules['j']['c'] = NOT_BEGIN | BREAK | NOT_END
  537. digram_rules['j']['d'] = NOT_BEGIN | BREAK | NOT_END
  538. digram_rules['j']['e'] = ANY_COMBINATION
  539. digram_rules['j']['f'] = NOT_BEGIN | BREAK | NOT_END
  540. digram_rules['j']['g'] = ILLEGAL_PAIR
  541. digram_rules['j']['h'] = NOT_BEGIN | BREAK | NOT_END
  542. digram_rules['j']['i'] = ANY_COMBINATION
  543. digram_rules['j']['j'] = ILLEGAL_PAIR
  544. digram_rules['j']['k'] = NOT_BEGIN | BREAK | NOT_END
  545. digram_rules['j']['l'] = NOT_BEGIN | BREAK | NOT_END
  546. digram_rules['j']['m'] = NOT_BEGIN | BREAK | NOT_END
  547. digram_rules['j']['n'] = NOT_BEGIN | BREAK | NOT_END
  548. digram_rules['j']['o'] = ANY_COMBINATION
  549. digram_rules['j']['p'] = NOT_BEGIN | BREAK | NOT_END
  550. digram_rules['j']['r'] = NOT_BEGIN | BREAK | NOT_END
  551. digram_rules['j']['s'] = NOT_BEGIN | BREAK | NOT_END
  552. digram_rules['j']['t'] = NOT_BEGIN | BREAK | NOT_END
  553. digram_rules['j']['u'] = ANY_COMBINATION
  554. digram_rules['j']['v'] = NOT_BEGIN | BREAK | NOT_END
  555. digram_rules['j']['w'] = NOT_BEGIN | BREAK | NOT_END
  556. digram_rules['j']['x'] = ILLEGAL_PAIR
  557. digram_rules['j']['y'] = NOT_BEGIN
  558. digram_rules['j']['z'] = NOT_BEGIN | BREAK | NOT_END
  559. digram_rules['j']['ch'] = NOT_BEGIN | BREAK | NOT_END
  560. digram_rules['j']['gh'] = NOT_BEGIN | BREAK | NOT_END
  561. digram_rules['j']['ph'] = NOT_BEGIN | BREAK | NOT_END
  562. digram_rules['j']['rh'] = ILLEGAL_PAIR
  563. digram_rules['j']['sh'] = NOT_BEGIN | BREAK | NOT_END
  564. digram_rules['j']['th'] = NOT_BEGIN | BREAK | NOT_END
  565. digram_rules['j']['wh'] = ILLEGAL_PAIR
  566. digram_rules['j']['qu'] = NOT_BEGIN | BREAK | NOT_END
  567. digram_rules['j']['ck'] = ILLEGAL_PAIR
  568. digram_rules['k'] = dict()
  569. digram_rules['k']['a'] = ANY_COMBINATION
  570. digram_rules['k']['b'] = NOT_BEGIN | BREAK | NOT_END
  571. digram_rules['k']['c'] = NOT_BEGIN | BREAK | NOT_END
  572. digram_rules['k']['d'] = NOT_BEGIN | BREAK | NOT_END
  573. digram_rules['k']['e'] = ANY_COMBINATION
  574. digram_rules['k']['f'] = NOT_BEGIN | BREAK | NOT_END
  575. digram_rules['k']['g'] = NOT_BEGIN | BREAK | NOT_END
  576. digram_rules['k']['h'] = NOT_BEGIN | BREAK | NOT_END
  577. digram_rules['k']['i'] = ANY_COMBINATION
  578. digram_rules['k']['j'] = NOT_BEGIN | BREAK | NOT_END
  579. digram_rules['k']['k'] = NOT_BEGIN | BREAK | NOT_END
  580. digram_rules['k']['l'] = SUFFIX | NOT_END
  581. digram_rules['k']['m'] = NOT_BEGIN | BREAK | NOT_END
  582. digram_rules['k']['n'] = BEGIN | SUFFIX | NOT_END
  583. digram_rules['k']['o'] = ANY_COMBINATION
  584. digram_rules['k']['p'] = NOT_BEGIN | BREAK | NOT_END
  585. digram_rules['k']['r'] = SUFFIX | NOT_END
  586. digram_rules['k']['s'] = NOT_BEGIN | END
  587. digram_rules['k']['t'] = NOT_BEGIN | BREAK | NOT_END
  588. digram_rules['k']['u'] = ANY_COMBINATION
  589. digram_rules['k']['v'] = NOT_BEGIN | BREAK | NOT_END
  590. digram_rules['k']['w'] = NOT_BEGIN | BREAK | NOT_END
  591. digram_rules['k']['x'] = ILLEGAL_PAIR
  592. digram_rules['k']['y'] = NOT_BEGIN
  593. digram_rules['k']['z'] = NOT_BEGIN | BREAK | NOT_END
  594. digram_rules['k']['ch'] = NOT_BEGIN | BREAK | NOT_END
  595. digram_rules['k']['gh'] = NOT_BEGIN | BREAK | NOT_END
  596. digram_rules['k']['ph'] = NOT_BEGIN | PREFIX
  597. digram_rules['k']['rh'] = ILLEGAL_PAIR
  598. digram_rules['k']['sh'] = NOT_BEGIN
  599. digram_rules['k']['th'] = NOT_BEGIN | BREAK | NOT_END
  600. digram_rules['k']['wh'] = ILLEGAL_PAIR
  601. digram_rules['k']['qu'] = NOT_BEGIN | BREAK | NOT_END
  602. digram_rules['k']['ck'] = ILLEGAL_PAIR
  603. digram_rules['l'] = dict()
  604. digram_rules['l']['a'] = ANY_COMBINATION
  605. digram_rules['l']['b'] = NOT_BEGIN | PREFIX
  606. digram_rules['l']['c'] = NOT_BEGIN | BREAK | NOT_END
  607. digram_rules['l']['d'] = NOT_BEGIN | PREFIX
  608. digram_rules['l']['e'] = ANY_COMBINATION
  609. digram_rules['l']['f'] = NOT_BEGIN | PREFIX
  610. digram_rules['l']['g'] = NOT_BEGIN | PREFIX
  611. digram_rules['l']['h'] = NOT_BEGIN | BREAK | NOT_END
  612. digram_rules['l']['i'] = ANY_COMBINATION
  613. digram_rules['l']['j'] = NOT_BEGIN | PREFIX
  614. digram_rules['l']['k'] = NOT_BEGIN | PREFIX
  615. digram_rules['l']['l'] = NOT_BEGIN | PREFIX
  616. digram_rules['l']['m'] = NOT_BEGIN | PREFIX
  617. digram_rules['l']['n'] = NOT_BEGIN | BREAK | NOT_END
  618. digram_rules['l']['o'] = ANY_COMBINATION
  619. digram_rules['l']['p'] = NOT_BEGIN | PREFIX
  620. digram_rules['l']['r'] = NOT_BEGIN | BREAK | NOT_END
  621. digram_rules['l']['s'] = NOT_BEGIN
  622. digram_rules['l']['t'] = NOT_BEGIN | PREFIX
  623. digram_rules['l']['u'] = ANY_COMBINATION
  624. digram_rules['l']['v'] = NOT_BEGIN | PREFIX
  625. digram_rules['l']['w'] = NOT_BEGIN | BREAK | NOT_END
  626. digram_rules['l']['x'] = ILLEGAL_PAIR
  627. digram_rules['l']['y'] = ANY_COMBINATION
  628. digram_rules['l']['z'] = NOT_BEGIN | BREAK | NOT_END
  629. digram_rules['l']['ch'] = NOT_BEGIN | PREFIX
  630. digram_rules['l']['gh'] = NOT_BEGIN | BREAK | NOT_END
  631. digram_rules['l']['ph'] = NOT_BEGIN | PREFIX
  632. digram_rules['l']['rh'] = ILLEGAL_PAIR
  633. digram_rules['l']['sh'] = NOT_BEGIN | PREFIX
  634. digram_rules['l']['th'] = NOT_BEGIN | PREFIX
  635. digram_rules['l']['wh'] = ILLEGAL_PAIR
  636. digram_rules['l']['qu'] = NOT_BEGIN | BREAK | NOT_END
  637. digram_rules['l']['ck'] = ILLEGAL_PAIR
  638. digram_rules['m'] = dict()
  639. digram_rules['m']['a'] = ANY_COMBINATION
  640. digram_rules['m']['b'] = NOT_BEGIN | BREAK | NOT_END
  641. digram_rules['m']['c'] = NOT_BEGIN | BREAK | NOT_END
  642. digram_rules['m']['d'] = NOT_BEGIN | BREAK | NOT_END
  643. digram_rules['m']['e'] = ANY_COMBINATION
  644. digram_rules['m']['f'] = NOT_BEGIN | BREAK | NOT_END
  645. digram_rules['m']['g'] = NOT_BEGIN | BREAK | NOT_END
  646. digram_rules['m']['h'] = NOT_BEGIN | BREAK | NOT_END
  647. digram_rules['m']['i'] = ANY_COMBINATION
  648. digram_rules['m']['j'] = NOT_BEGIN | BREAK | NOT_END
  649. digram_rules['m']['k'] = NOT_BEGIN | BREAK | NOT_END
  650. digram_rules['m']['l'] = NOT_BEGIN | BREAK | NOT_END
  651. digram_rules['m']['m'] = NOT_BEGIN
  652. digram_rules['m']['n'] = NOT_BEGIN | BREAK | NOT_END
  653. digram_rules['m']['o'] = ANY_COMBINATION
  654. digram_rules['m']['p'] = NOT_BEGIN
  655. digram_rules['m']['r'] = NOT_BEGIN | BREAK | NOT_END
  656. digram_rules['m']['s'] = NOT_BEGIN
  657. digram_rules['m']['t'] = NOT_BEGIN
  658. digram_rules['m']['u'] = ANY_COMBINATION
  659. digram_rules['m']['v'] = NOT_BEGIN | BREAK | NOT_END
  660. digram_rules['m']['w'] = NOT_BEGIN | BREAK | NOT_END
  661. digram_rules['m']['x'] = ILLEGAL_PAIR
  662. digram_rules['m']['y'] = ANY_COMBINATION
  663. digram_rules['m']['z'] = NOT_BEGIN | BREAK | NOT_END
  664. digram_rules['m']['ch'] = NOT_BEGIN | PREFIX
  665. digram_rules['m']['gh'] = NOT_BEGIN | BREAK | NOT_END
  666. digram_rules['m']['ph'] = NOT_BEGIN
  667. digram_rules['m']['rh'] = ILLEGAL_PAIR
  668. digram_rules['m']['sh'] = NOT_BEGIN
  669. digram_rules['m']['th'] = NOT_BEGIN
  670. digram_rules['m']['wh'] = ILLEGAL_PAIR
  671. digram_rules['m']['qu'] = NOT_BEGIN | BREAK | NOT_END
  672. digram_rules['m']['ck'] = ILLEGAL_PAIR
  673. digram_rules['n'] = dict()
  674. digram_rules['n']['a'] = ANY_COMBINATION
  675. digram_rules['n']['b'] = NOT_BEGIN | BREAK | NOT_END
  676. digram_rules['n']['c'] = NOT_BEGIN | BREAK | NOT_END
  677. digram_rules['n']['d'] = NOT_BEGIN
  678. digram_rules['n']['e'] = ANY_COMBINATION
  679. digram_rules['n']['f'] = NOT_BEGIN | BREAK | NOT_END
  680. digram_rules['n']['g'] = NOT_BEGIN | PREFIX
  681. digram_rules['n']['h'] = NOT_BEGIN | BREAK | NOT_END
  682. digram_rules['n']['i'] = ANY_COMBINATION
  683. digram_rules['n']['j'] = NOT_BEGIN | BREAK | NOT_END
  684. digram_rules['n']['k'] = NOT_BEGIN | PREFIX
  685. digram_rules['n']['l'] = NOT_BEGIN | BREAK | NOT_END
  686. digram_rules['n']['m'] = NOT_BEGIN | BREAK | NOT_END
  687. digram_rules['n']['n'] = NOT_BEGIN
  688. digram_rules['n']['o'] = ANY_COMBINATION
  689. digram_rules['n']['p'] = NOT_BEGIN | BREAK | NOT_END
  690. digram_rules['n']['r'] = NOT_BEGIN | BREAK | NOT_END
  691. digram_rules['n']['s'] = NOT_BEGIN
  692. digram_rules['n']['t'] = NOT_BEGIN
  693. digram_rules['n']['u'] = ANY_COMBINATION
  694. digram_rules['n']['v'] = NOT_BEGIN | BREAK | NOT_END
  695. digram_rules['n']['w'] = NOT_BEGIN | BREAK | NOT_END
  696. digram_rules['n']['x'] = ILLEGAL_PAIR
  697. digram_rules['n']['y'] = NOT_BEGIN
  698. digram_rules['n']['z'] = NOT_BEGIN | BREAK | NOT_END
  699. digram_rules['n']['ch'] = NOT_BEGIN | PREFIX
  700. digram_rules['n']['gh'] = NOT_BEGIN | BREAK | NOT_END
  701. digram_rules['n']['ph'] = NOT_BEGIN | PREFIX
  702. digram_rules['n']['rh'] = ILLEGAL_PAIR
  703. digram_rules['n']['sh'] = NOT_BEGIN
  704. digram_rules['n']['th'] = NOT_BEGIN
  705. digram_rules['n']['wh'] = ILLEGAL_PAIR
  706. digram_rules['n']['qu'] = NOT_BEGIN | BREAK | NOT_END
  707. digram_rules['n']['ck'] = NOT_BEGIN | PREFIX
  708. digram_rules['o'] = dict()
  709. digram_rules['o']['a'] = ANY_COMBINATION
  710. digram_rules['o']['b'] = ANY_COMBINATION
  711. digram_rules['o']['c'] = ANY_COMBINATION
  712. digram_rules['o']['d'] = ANY_COMBINATION
  713. digram_rules['o']['e'] = ILLEGAL_PAIR
  714. digram_rules['o']['f'] = ANY_COMBINATION
  715. digram_rules['o']['g'] = ANY_COMBINATION
  716. digram_rules['o']['h'] = NOT_BEGIN | BREAK | NOT_END
  717. digram_rules['o']['i'] = ANY_COMBINATION
  718. digram_rules['o']['j'] = ANY_COMBINATION
  719. digram_rules['o']['k'] = ANY_COMBINATION
  720. digram_rules['o']['l'] = ANY_COMBINATION
  721. digram_rules['o']['m'] = ANY_COMBINATION
  722. digram_rules['o']['n'] = ANY_COMBINATION
  723. digram_rules['o']['o'] = ANY_COMBINATION
  724. digram_rules['o']['p'] = ANY_COMBINATION
  725. digram_rules['o']['r'] = ANY_COMBINATION
  726. digram_rules['o']['s'] = ANY_COMBINATION
  727. digram_rules['o']['t'] = ANY_COMBINATION
  728. digram_rules['o']['u'] = ANY_COMBINATION
  729. digram_rules['o']['v'] = ANY_COMBINATION
  730. digram_rules['o']['w'] = ANY_COMBINATION
  731. digram_rules['o']['x'] = ANY_COMBINATION
  732. digram_rules['o']['y'] = ANY_COMBINATION
  733. digram_rules['o']['z'] = ANY_COMBINATION
  734. digram_rules['o']['ch'] = ANY_COMBINATION
  735. digram_rules['o']['gh'] = NOT_BEGIN
  736. digram_rules['o']['ph'] = ANY_COMBINATION
  737. digram_rules['o']['rh'] = ILLEGAL_PAIR
  738. digram_rules['o']['sh'] = ANY_COMBINATION
  739. digram_rules['o']['th'] = ANY_COMBINATION
  740. digram_rules['o']['wh'] = ILLEGAL_PAIR
  741. digram_rules['o']['qu'] = BREAK | NOT_END
  742. digram_rules['o']['ck'] = ANY_COMBINATION
  743. digram_rules['p'] = dict()
  744. digram_rules['p']['a'] = ANY_COMBINATION
  745. digram_rules['p']['b'] = NOT_BEGIN | BREAK | NOT_END
  746. digram_rules['p']['c'] = NOT_BEGIN | BREAK | NOT_END
  747. digram_rules['p']['d'] = NOT_BEGIN | BREAK | NOT_END
  748. digram_rules['p']['e'] = ANY_COMBINATION
  749. digram_rules['p']['f'] = NOT_BEGIN | BREAK | NOT_END
  750. digram_rules['p']['g'] = NOT_BEGIN | BREAK | NOT_END
  751. digram_rules['p']['h'] = NOT_BEGIN | BREAK | NOT_END
  752. digram_rules['p']['i'] = ANY_COMBINATION
  753. digram_rules['p']['j'] = NOT_BEGIN | BREAK | NOT_END
  754. digram_rules['p']['k'] = NOT_BEGIN | BREAK | NOT_END
  755. digram_rules['p']['l'] = SUFFIX | NOT_END
  756. digram_rules['p']['m'] = NOT_BEGIN | BREAK | NOT_END
  757. digram_rules['p']['n'] = NOT_BEGIN | BREAK | NOT_END
  758. digram_rules['p']['o'] = ANY_COMBINATION
  759. digram_rules['p']['p'] = NOT_BEGIN | PREFIX
  760. digram_rules['p']['r'] = NOT_END
  761. digram_rules['p']['s'] = NOT_BEGIN | END
  762. digram_rules['p']['t'] = NOT_BEGIN | END
  763. digram_rules['p']['u'] = NOT_BEGIN | END
  764. digram_rules['p']['v'] = NOT_BEGIN | BREAK | NOT_END
  765. digram_rules['p']['w'] = NOT_BEGIN | BREAK | NOT_END
  766. digram_rules['p']['x'] = ILLEGAL_PAIR
  767. digram_rules['p']['y'] = ANY_COMBINATION
  768. digram_rules['p']['z'] = NOT_BEGIN | BREAK | NOT_END
  769. digram_rules['p']['ch'] = NOT_BEGIN | BREAK | NOT_END
  770. digram_rules['p']['gh'] = NOT_BEGIN | BREAK | NOT_END
  771. digram_rules['p']['ph'] = NOT_BEGIN | BREAK | NOT_END
  772. digram_rules['p']['rh'] = ILLEGAL_PAIR
  773. digram_rules['p']['sh'] = NOT_BEGIN | BREAK | NOT_END
  774. digram_rules['p']['th'] = NOT_BEGIN | BREAK | NOT_END
  775. digram_rules['p']['wh'] = ILLEGAL_PAIR
  776. digram_rules['p']['qu'] = NOT_BEGIN | BREAK | NOT_END
  777. digram_rules['p']['ck'] = ILLEGAL_PAIR
  778. digram_rules['r'] = dict()
  779. digram_rules['r']['a'] = ANY_COMBINATION
  780. digram_rules['r']['b'] = NOT_BEGIN | PREFIX
  781. digram_rules['r']['c'] = NOT_BEGIN | PREFIX
  782. digram_rules['r']['d'] = NOT_BEGIN | PREFIX
  783. digram_rules['r']['e'] = ANY_COMBINATION
  784. digram_rules['r']['f'] = NOT_BEGIN | PREFIX
  785. digram_rules['r']['g'] = NOT_BEGIN | PREFIX
  786. digram_rules['r']['h'] = NOT_BEGIN | BREAK | NOT_END
  787. digram_rules['r']['i'] = ANY_COMBINATION
  788. digram_rules['r']['j'] = NOT_BEGIN | PREFIX
  789. digram_rules['r']['k'] = NOT_BEGIN | PREFIX
  790. digram_rules['r']['l'] = NOT_BEGIN | PREFIX
  791. digram_rules['r']['m'] = NOT_BEGIN | PREFIX
  792. digram_rules['r']['n'] = NOT_BEGIN | PREFIX
  793. digram_rules['r']['o'] = ANY_COMBINATION
  794. digram_rules['r']['p'] = NOT_BEGIN | PREFIX
  795. digram_rules['r']['r'] = NOT_BEGIN | PREFIX
  796. digram_rules['r']['s'] = NOT_BEGIN | PREFIX
  797. digram_rules['r']['t'] = NOT_BEGIN | PREFIX
  798. digram_rules['r']['u'] = ANY_COMBINATION
  799. digram_rules['r']['v'] = NOT_BEGIN | PREFIX
  800. digram_rules['r']['w'] = NOT_BEGIN | BREAK | NOT_END
  801. digram_rules['r']['x'] = ILLEGAL_PAIR
  802. digram_rules['r']['y'] = ANY_COMBINATION
  803. digram_rules['r']['z'] = NOT_BEGIN | PREFIX
  804. digram_rules['r']['ch'] = NOT_BEGIN | PREFIX
  805. digram_rules['r']['gh'] = NOT_BEGIN | BREAK | NOT_END
  806. digram_rules['r']['ph'] = NOT_BEGIN | PREFIX
  807. digram_rules['r']['rh'] = ILLEGAL_PAIR
  808. digram_rules['r']['sh'] = NOT_BEGIN | PREFIX
  809. digram_rules['r']['th'] = NOT_BEGIN | PREFIX
  810. digram_rules['r']['wh'] = ILLEGAL_PAIR
  811. digram_rules['r']['qu'] = NOT_BEGIN | PREFIX | NOT_END
  812. digram_rules['r']['ck'] = NOT_BEGIN | PREFIX
  813. digram_rules['s'] = dict()
  814. digram_rules['s']['a'] = ANY_COMBINATION
  815. digram_rules['s']['b'] = NOT_BEGIN | BREAK | NOT_END
  816. digram_rules['s']['c'] = NOT_END
  817. digram_rules['s']['d'] = NOT_BEGIN | BREAK | NOT_END
  818. digram_rules['s']['e'] = ANY_COMBINATION
  819. digram_rules['s']['f'] = NOT_BEGIN | BREAK | NOT_END
  820. digram_rules['s']['g'] = NOT_BEGIN | BREAK | NOT_END
  821. digram_rules['s']['h'] = NOT_BEGIN | BREAK | NOT_END
  822. digram_rules['s']['i'] = ANY_COMBINATION
  823. digram_rules['s']['j'] = NOT_BEGIN | BREAK | NOT_END
  824. digram_rules['s']['k'] = ANY_COMBINATION
  825. digram_rules['s']['l'] = BEGIN | SUFFIX | NOT_END
  826. digram_rules['s']['m'] = SUFFIX | NOT_END
  827. digram_rules['s']['n'] = PREFIX | SUFFIX | NOT_END
  828. digram_rules['s']['o'] = ANY_COMBINATION
  829. digram_rules['s']['p'] = ANY_COMBINATION
  830. digram_rules['s']['r'] = NOT_BEGIN | NOT_END
  831. digram_rules['s']['s'] = NOT_BEGIN | PREFIX
  832. digram_rules['s']['t'] = ANY_COMBINATION
  833. digram_rules['s']['u'] = ANY_COMBINATION
  834. digram_rules['s']['v'] = NOT_BEGIN | BREAK | NOT_END
  835. digram_rules['s']['w'] = BEGIN | SUFFIX | NOT_END
  836. digram_rules['s']['x'] = ILLEGAL_PAIR
  837. digram_rules['s']['y'] = ANY_COMBINATION
  838. digram_rules['s']['z'] = NOT_BEGIN | BREAK | NOT_END
  839. digram_rules['s']['ch'] = BEGIN | SUFFIX | NOT_END
  840. digram_rules['s']['gh'] = NOT_BEGIN | BREAK | NOT_END
  841. digram_rules['s']['ph'] = NOT_BEGIN | BREAK | NOT_END
  842. digram_rules['s']['rh'] = ILLEGAL_PAIR
  843. digram_rules['s']['sh'] = NOT_BEGIN | BREAK | NOT_END
  844. digram_rules['s']['th'] = NOT_BEGIN | BREAK | NOT_END
  845. digram_rules['s']['wh'] = ILLEGAL_PAIR
  846. digram_rules['s']['qu'] = SUFFIX | NOT_END
  847. digram_rules['s']['ck'] = NOT_BEGIN
  848. digram_rules['t'] = dict()
  849. digram_rules['t']['a'] = ANY_COMBINATION
  850. digram_rules['t']['b'] = NOT_BEGIN | BREAK | NOT_END
  851. digram_rules['t']['c'] = NOT_BEGIN | BREAK | NOT_END
  852. digram_rules['t']['d'] = NOT_BEGIN | BREAK | NOT_END
  853. digram_rules['t']['e'] = ANY_COMBINATION
  854. digram_rules['t']['f'] = NOT_BEGIN | BREAK | NOT_END
  855. digram_rules['t']['g'] = NOT_BEGIN | BREAK | NOT_END
  856. digram_rules['t']['h'] = NOT_BEGIN | BREAK | NOT_END
  857. digram_rules['t']['i'] = ANY_COMBINATION
  858. digram_rules['t']['j'] = NOT_BEGIN | BREAK | NOT_END
  859. digram_rules['t']['k'] = NOT_BEGIN | BREAK | NOT_END
  860. digram_rules['t']['l'] = NOT_BEGIN | BREAK | NOT_END
  861. digram_rules['t']['m'] = NOT_BEGIN | BREAK | NOT_END
  862. digram_rules['t']['n'] = NOT_BEGIN | BREAK | NOT_END
  863. digram_rules['t']['o'] = ANY_COMBINATION
  864. digram_rules['t']['p'] = NOT_BEGIN | BREAK | NOT_END
  865. digram_rules['t']['r'] = NOT_END
  866. digram_rules['t']['s'] = NOT_BEGIN | END
  867. digram_rules['t']['t'] = NOT_BEGIN | PREFIX
  868. digram_rules['t']['u'] = ANY_COMBINATION
  869. digram_rules['t']['v'] = NOT_BEGIN | BREAK | NOT_END
  870. digram_rules['t']['w'] = BEGIN | SUFFIX | NOT_END
  871. digram_rules['t']['x'] = ILLEGAL_PAIR
  872. digram_rules['t']['y'] = ANY_COMBINATION
  873. digram_rules['t']['z'] = NOT_BEGIN | BREAK | NOT_END
  874. digram_rules['t']['ch'] = NOT_BEGIN
  875. digram_rules['t']['gh'] = NOT_BEGIN | BREAK | NOT_END
  876. digram_rules['t']['ph'] = NOT_BEGIN | END
  877. digram_rules['t']['rh'] = ILLEGAL_PAIR
  878. digram_rules['t']['sh'] = NOT_BEGIN | END
  879. digram_rules['t']['th'] = NOT_BEGIN | BREAK | NOT_END
  880. digram_rules['t']['wh'] = ILLEGAL_PAIR
  881. digram_rules['t']['qu'] = NOT_BEGIN | BREAK | NOT_END
  882. digram_rules['t']['ck'] = ILLEGAL_PAIR
  883. digram_rules['u'] = dict()
  884. digram_rules['u']['a'] = NOT_BEGIN | BREAK | NOT_END
  885. digram_rules['u']['b'] = ANY_COMBINATION
  886. digram_rules['u']['c'] = ANY_COMBINATION
  887. digram_rules['u']['d'] = ANY_COMBINATION
  888. digram_rules['u']['e'] = NOT_BEGIN
  889. digram_rules['u']['f'] = ANY_COMBINATION
  890. digram_rules['u']['g'] = ANY_COMBINATION
  891. digram_rules['u']['h'] = NOT_BEGIN | BREAK | NOT_END
  892. digram_rules['u']['i'] = NOT_BEGIN | BREAK | NOT_END
  893. digram_rules['u']['j'] = ANY_COMBINATION
  894. digram_rules['u']['k'] = ANY_COMBINATION
  895. digram_rules['u']['l'] = ANY_COMBINATION
  896. digram_rules['u']['m'] = ANY_COMBINATION
  897. digram_rules['u']['n'] = ANY_COMBINATION
  898. digram_rules['u']['o'] = NOT_BEGIN | BREAK
  899. digram_rules['u']['p'] = ANY_COMBINATION
  900. digram_rules['u']['r'] = ANY_COMBINATION
  901. digram_rules['u']['s'] = ANY_COMBINATION
  902. digram_rules['u']['t'] = ANY_COMBINATION
  903. digram_rules['u']['u'] = ILLEGAL_PAIR
  904. digram_rules['u']['v'] = ANY_COMBINATION
  905. digram_rules['u']['w'] = NOT_BEGIN | BREAK | NOT_END
  906. digram_rules['u']['x'] = ANY_COMBINATION
  907. digram_rules['u']['y'] = NOT_BEGIN | BREAK | NOT_END
  908. digram_rules['u']['z'] = ANY_COMBINATION
  909. digram_rules['u']['ch'] = ANY_COMBINATION
  910. digram_rules['u']['gh'] = NOT_BEGIN | PREFIX
  911. digram_rules['u']['ph'] = ANY_COMBINATION
  912. digram_rules['u']['rh'] = ILLEGAL_PAIR
  913. digram_rules['u']['sh'] = ANY_COMBINATION
  914. digram_rules['u']['th'] = ANY_COMBINATION
  915. digram_rules['u']['wh'] = ILLEGAL_PAIR
  916. digram_rules['u']['qu'] = BREAK | NOT_END
  917. digram_rules['u']['ck'] = ANY_COMBINATION
  918. digram_rules['v'] = dict()
  919. digram_rules['v']['a'] = ANY_COMBINATION
  920. digram_rules['v']['b'] = NOT_BEGIN | BREAK | NOT_END
  921. digram_rules['v']['c'] = NOT_BEGIN | BREAK | NOT_END
  922. digram_rules['v']['d'] = NOT_BEGIN | BREAK | NOT_END
  923. digram_rules['v']['e'] = ANY_COMBINATION
  924. digram_rules['v']['f'] = NOT_BEGIN | BREAK | NOT_END
  925. digram_rules['v']['g'] = NOT_BEGIN | BREAK | NOT_END
  926. digram_rules['v']['h'] = NOT_BEGIN | BREAK | NOT_END
  927. digram_rules['v']['i'] = ANY_COMBINATION
  928. digram_rules['v']['j'] = NOT_BEGIN | BREAK | NOT_END
  929. digram_rules['v']['k'] = NOT_BEGIN | BREAK | NOT_END
  930. digram_rules['v']['l'] = NOT_BEGIN | BREAK | NOT_END
  931. digram_rules['v']['m'] = NOT_BEGIN | BREAK | NOT_END
  932. digram_rules['v']['n'] = NOT_BEGIN | BREAK | NOT_END
  933. digram_rules['v']['o'] = ANY_COMBINATION
  934. digram_rules['v']['p'] = NOT_BEGIN | BREAK | NOT_END
  935. digram_rules['v']['r'] = NOT_BEGIN | BREAK | NOT_END
  936. digram_rules['v']['s'] = NOT_BEGIN | BREAK | NOT_END
  937. digram_rules['v']['t'] = NOT_BEGIN | BREAK | NOT_END
  938. digram_rules['v']['u'] = ANY_COMBINATION
  939. digram_rules['v']['v'] = NOT_BEGIN | BREAK | NOT_END
  940. digram_rules['v']['w'] = NOT_BEGIN | BREAK | NOT_END
  941. digram_rules['v']['x'] = ILLEGAL_PAIR
  942. digram_rules['v']['y'] = NOT_BEGIN
  943. digram_rules['v']['z'] = NOT_BEGIN | BREAK | NOT_END
  944. digram_rules['v']['ch'] = NOT_BEGIN | BREAK | NOT_END
  945. digram_rules['v']['gh'] = NOT_BEGIN | BREAK | NOT_END
  946. digram_rules['v']['ph'] = NOT_BEGIN | BREAK | NOT_END
  947. digram_rules['v']['rh'] = ILLEGAL_PAIR
  948. digram_rules['v']['sh'] = NOT_BEGIN | BREAK | NOT_END
  949. digram_rules['v']['th'] = NOT_BEGIN | BREAK | NOT_END
  950. digram_rules['v']['wh'] = ILLEGAL_PAIR
  951. digram_rules['v']['qu'] = NOT_BEGIN | BREAK | NOT_END
  952. digram_rules['v']['ck'] = ILLEGAL_PAIR
  953. digram_rules['w'] = dict()
  954. digram_rules['w']['a'] = ANY_COMBINATION
  955. digram_rules['w']['b'] = NOT_BEGIN | PREFIX
  956. digram_rules['w']['c'] = NOT_BEGIN | BREAK | NOT_END
  957. digram_rules['w']['d'] = NOT_BEGIN | PREFIX | END
  958. digram_rules['w']['e'] = ANY_COMBINATION
  959. digram_rules['w']['f'] = NOT_BEGIN | PREFIX
  960. digram_rules['w']['g'] = NOT_BEGIN | PREFIX | END
  961. digram_rules['w']['h'] = NOT_BEGIN | BREAK | NOT_END
  962. digram_rules['w']['i'] = ANY_COMBINATION
  963. digram_rules['w']['j'] = NOT_BEGIN | BREAK | NOT_END
  964. digram_rules['w']['k'] = NOT_BEGIN | PREFIX
  965. digram_rules['w']['l'] = NOT_BEGIN | PREFIX | SUFFIX
  966. digram_rules['w']['m'] = NOT_BEGIN | PREFIX
  967. digram_rules['w']['n'] = NOT_BEGIN | PREFIX
  968. digram_rules['w']['o'] = ANY_COMBINATION
  969. digram_rules['w']['p'] = NOT_BEGIN | PREFIX
  970. digram_rules['w']['r'] = BEGIN | SUFFIX | NOT_END
  971. digram_rules['w']['s'] = NOT_BEGIN | PREFIX
  972. digram_rules['w']['t'] = NOT_BEGIN | PREFIX
  973. digram_rules['w']['u'] = ANY_COMBINATION
  974. digram_rules['w']['v'] = NOT_BEGIN | PREFIX
  975. digram_rules['w']['w'] = NOT_BEGIN | BREAK | NOT_END
  976. digram_rules['w']['x'] = NOT_BEGIN | PREFIX
  977. digram_rules['w']['y'] = ANY_COMBINATION
  978. digram_rules['w']['z'] = NOT_BEGIN | PREFIX
  979. digram_rules['w']['ch'] = NOT_BEGIN
  980. digram_rules['w']['gh'] = NOT_BEGIN | BREAK | NOT_END
  981. digram_rules['w']['ph'] = NOT_BEGIN
  982. digram_rules['w']['rh'] = ILLEGAL_PAIR
  983. digram_rules['w']['sh'] = NOT_BEGIN
  984. digram_rules['w']['th'] = NOT_BEGIN
  985. digram_rules['w']['wh'] = ILLEGAL_PAIR
  986. digram_rules['w']['qu'] = NOT_BEGIN | BREAK | NOT_END
  987. digram_rules['w']['ck'] = NOT_BEGIN
  988. digram_rules['x'] = dict()
  989. digram_rules['x']['a'] = NOT_BEGIN
  990. digram_rules['x']['b'] = NOT_BEGIN | BREAK | NOT_END
  991. digram_rules['x']['c'] = NOT_BEGIN | BREAK | NOT_END
  992. digram_rules['x']['d'] = NOT_BEGIN | BREAK | NOT_END
  993. digram_rules['x']['e'] = NOT_BEGIN
  994. digram_rules['x']['f'] = NOT_BEGIN | BREAK | NOT_END
  995. digram_rules['x']['g'] = NOT_BEGIN | BREAK | NOT_END
  996. digram_rules['x']['h'] = NOT_BEGIN | BREAK | NOT_END
  997. digram_rules['x']['i'] = NOT_BEGIN
  998. digram_rules['x']['j'] = NOT_BEGIN | BREAK | NOT_END
  999. digram_rules['x']['k'] = NOT_BEGIN | BREAK | NOT_END
  1000. digram_rules['x']['l'] = NOT_BEGIN | BREAK | NOT_END
  1001. digram_rules['x']['m'] = NOT_BEGIN | BREAK | NOT_END
  1002. digram_rules['x']['n'] = NOT_BEGIN | BREAK | NOT_END
  1003. digram_rules['x']['o'] = NOT_BEGIN
  1004. digram_rules['x']['p'] = NOT_BEGIN | BREAK | NOT_END
  1005. digram_rules['x']['r'] = NOT_BEGIN | BREAK | NOT_END
  1006. digram_rules['x']['s'] = NOT_BEGIN | BREAK | NOT_END
  1007. digram_rules['x']['t'] = NOT_BEGIN | BREAK | NOT_END
  1008. digram_rules['x']['u'] = NOT_BEGIN
  1009. digram_rules['x']['v'] = NOT_BEGIN | BREAK | NOT_END
  1010. digram_rules['x']['w'] = NOT_BEGIN | BREAK | NOT_END
  1011. digram_rules['x']['x'] = ILLEGAL_PAIR
  1012. digram_rules['x']['y'] = NOT_BEGIN
  1013. digram_rules['x']['z'] = NOT_BEGIN | BREAK | NOT_END
  1014. digram_rules['x']['ch'] = NOT_BEGIN | BREAK | NOT_END
  1015. digram_rules['x']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1016. digram_rules['x']['ph'] = NOT_BEGIN | BREAK | NOT_END
  1017. digram_rules['x']['rh'] = ILLEGAL_PAIR
  1018. digram_rules['x']['sh'] = NOT_BEGIN | BREAK | NOT_END
  1019. digram_rules['x']['th'] = NOT_BEGIN | BREAK | NOT_END
  1020. digram_rules['x']['wh'] = ILLEGAL_PAIR
  1021. digram_rules['x']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1022. digram_rules['x']['ck'] = ILLEGAL_PAIR
  1023. digram_rules['y'] = dict()
  1024. digram_rules['y']['a'] = ANY_COMBINATION
  1025. digram_rules['y']['b'] = NOT_BEGIN
  1026. digram_rules['y']['c'] = NOT_BEGIN | NOT_END
  1027. digram_rules['y']['d'] = NOT_BEGIN
  1028. digram_rules['y']['e'] = ANY_COMBINATION
  1029. digram_rules['y']['f'] = NOT_BEGIN | NOT_END
  1030. digram_rules['y']['g'] = NOT_BEGIN
  1031. digram_rules['y']['h'] = NOT_BEGIN | BREAK | NOT_END
  1032. digram_rules['y']['i'] = BEGIN | NOT_END
  1033. digram_rules['y']['j'] = NOT_BEGIN | NOT_END
  1034. digram_rules['y']['k'] = NOT_BEGIN
  1035. digram_rules['y']['l'] = NOT_BEGIN | NOT_END
  1036. digram_rules['y']['m'] = NOT_BEGIN
  1037. digram_rules['y']['n'] = NOT_BEGIN
  1038. digram_rules['y']['o'] = ANY_COMBINATION
  1039. digram_rules['y']['p'] = NOT_BEGIN
  1040. digram_rules['y']['r'] = NOT_BEGIN | BREAK | NOT_END
  1041. digram_rules['y']['s'] = NOT_BEGIN
  1042. digram_rules['y']['t'] = NOT_BEGIN
  1043. digram_rules['y']['u'] = ANY_COMBINATION
  1044. digram_rules['y']['v'] = NOT_BEGIN | NOT_END
  1045. digram_rules['y']['w'] = NOT_BEGIN | BREAK | NOT_END
  1046. digram_rules['y']['x'] = NOT_BEGIN
  1047. digram_rules['y']['y'] = ILLEGAL_PAIR
  1048. digram_rules['y']['z'] = NOT_BEGIN
  1049. digram_rules['y']['ch'] = NOT_BEGIN | BREAK | NOT_END
  1050. digram_rules['y']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1051. digram_rules['y']['ph'] = NOT_BEGIN | BREAK | NOT_END
  1052. digram_rules['y']['rh'] = ILLEGAL_PAIR
  1053. digram_rules['y']['sh'] = NOT_BEGIN | BREAK | NOT_END
  1054. digram_rules['y']['th'] = NOT_BEGIN | BREAK | NOT_END
  1055. digram_rules['y']['wh'] = ILLEGAL_PAIR
  1056. digram_rules['y']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1057. digram_rules['y']['ck'] = ILLEGAL_PAIR
  1058. digram_rules['z'] = dict()
  1059. digram_rules['z']['a'] = ANY_COMBINATION
  1060. digram_rules['z']['b'] = NOT_BEGIN | BREAK | NOT_END
  1061. digram_rules['z']['c'] = NOT_BEGIN | BREAK | NOT_END
  1062. digram_rules['z']['d'] = NOT_BEGIN | BREAK | NOT_END
  1063. digram_rules['z']['e'] = ANY_COMBINATION
  1064. digram_rules['z']['f'] = NOT_BEGIN | BREAK | NOT_END
  1065. digram_rules['z']['g'] = NOT_BEGIN | BREAK | NOT_END
  1066. digram_rules['z']['h'] = NOT_BEGIN | BREAK | NOT_END
  1067. digram_rules['z']['i'] = ANY_COMBINATION
  1068. digram_rules['z']['j'] = NOT_BEGIN | BREAK | NOT_END
  1069. digram_rules['z']['k'] = NOT_BEGIN | BREAK | NOT_END
  1070. digram_rules['z']['l'] = NOT_BEGIN | BREAK | NOT_END
  1071. digram_rules['z']['m'] = NOT_BEGIN | BREAK | NOT_END
  1072. digram_rules['z']['n'] = NOT_BEGIN | BREAK | NOT_END
  1073. digram_rules['z']['o'] = ANY_COMBINATION
  1074. digram_rules['z']['p'] = NOT_BEGIN | BREAK | NOT_END
  1075. digram_rules['z']['r'] = NOT_BEGIN | NOT_END
  1076. digram_rules['z']['s'] = NOT_BEGIN | BREAK | NOT_END
  1077. digram_rules['z']['t'] = NOT_BEGIN
  1078. digram_rules['z']['u'] = ANY_COMBINATION
  1079. digram_rules['z']['v'] = NOT_BEGIN | BREAK | NOT_END
  1080. digram_rules['z']['w'] = SUFFIX | NOT_END
  1081. digram_rules['z']['x'] = ILLEGAL_PAIR
  1082. digram_rules['z']['y'] = ANY_COMBINATION
  1083. digram_rules['z']['z'] = NOT_BEGIN
  1084. digram_rules['z']['ch'] = NOT_BEGIN | BREAK | NOT_END
  1085. digram_rules['z']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1086. digram_rules['z']['ph'] = NOT_BEGIN | BREAK | NOT_END
  1087. digram_rules['z']['rh'] = ILLEGAL_PAIR
  1088. digram_rules['z']['sh'] = NOT_BEGIN | BREAK | NOT_END
  1089. digram_rules['z']['th'] = NOT_BEGIN | BREAK | NOT_END
  1090. digram_rules['z']['wh'] = ILLEGAL_PAIR
  1091. digram_rules['z']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1092. digram_rules['z']['ck'] = ILLEGAL_PAIR
  1093. digram_rules['ch'] = dict()
  1094. digram_rules['ch']['a'] = ANY_COMBINATION
  1095. digram_rules['ch']['b'] = NOT_BEGIN | BREAK | NOT_END
  1096. digram_rules['ch']['c'] = NOT_BEGIN | BREAK | NOT_END
  1097. digram_rules['ch']['d'] = NOT_BEGIN | BREAK | NOT_END
  1098. digram_rules['ch']['e'] = ANY_COMBINATION
  1099. digram_rules['ch']['f'] = NOT_BEGIN | BREAK | NOT_END
  1100. digram_rules['ch']['g'] = NOT_BEGIN | BREAK | NOT_END
  1101. digram_rules['ch']['h'] = NOT_BEGIN | BREAK | NOT_END
  1102. digram_rules['ch']['i'] = ANY_COMBINATION
  1103. digram_rules['ch']['j'] = NOT_BEGIN | BREAK | NOT_END
  1104. digram_rules['ch']['k'] = NOT_BEGIN | BREAK | NOT_END
  1105. digram_rules['ch']['l'] = NOT_BEGIN | BREAK | NOT_END
  1106. digram_rules['ch']['m'] = NOT_BEGIN | BREAK | NOT_END
  1107. digram_rules['ch']['n'] = NOT_BEGIN | BREAK | NOT_END
  1108. digram_rules['ch']['o'] = ANY_COMBINATION
  1109. digram_rules['ch']['p'] = NOT_BEGIN | BREAK | NOT_END
  1110. digram_rules['ch']['r'] = NOT_END
  1111. digram_rules['ch']['s'] = NOT_BEGIN | BREAK | NOT_END
  1112. digram_rules['ch']['t'] = NOT_BEGIN | BREAK | NOT_END
  1113. digram_rules['ch']['u'] = ANY_COMBINATION
  1114. digram_rules['ch']['v'] = NOT_BEGIN | BREAK | NOT_END
  1115. digram_rules['ch']['w'] = NOT_BEGIN | NOT_END
  1116. digram_rules['ch']['x'] = ILLEGAL_PAIR
  1117. digram_rules['ch']['y'] = ANY_COMBINATION
  1118. digram_rules['ch']['z'] = NOT_BEGIN | BREAK | NOT_END
  1119. digram_rules['ch']['ch'] = ILLEGAL_PAIR
  1120. digram_rules['ch']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1121. digram_rules['ch']['ph'] = NOT_BEGIN | BREAK | NOT_END
  1122. digram_rules['ch']['rh'] = ILLEGAL_PAIR
  1123. digram_rules['ch']['sh'] = NOT_BEGIN | BREAK | NOT_END
  1124. digram_rules['ch']['th'] = NOT_BEGIN | BREAK | NOT_END
  1125. digram_rules['ch']['wh'] = ILLEGAL_PAIR
  1126. digram_rules['ch']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1127. digram_rules['ch']['ck'] = ILLEGAL_PAIR
  1128. digram_rules['gh'] = dict()
  1129. digram_rules['gh']['a'] = ANY_COMBINATION
  1130. digram_rules['gh']['b'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1131. digram_rules['gh']['c'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1132. digram_rules['gh']['d'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1133. digram_rules['gh']['e'] = ANY_COMBINATION
  1134. digram_rules['gh']['f'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1135. digram_rules['gh']['g'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1136. digram_rules['gh']['h'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1137. digram_rules['gh']['i'] = BEGIN | NOT_END
  1138. digram_rules['gh']['j'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1139. digram_rules['gh']['k'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1140. digram_rules['gh']['l'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1141. digram_rules['gh']['m'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1142. digram_rules['gh']['n'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1143. digram_rules['gh']['o'] = BEGIN | NOT_END
  1144. digram_rules['gh']['p'] = NOT_BEGIN | BREAK | NOT_END
  1145. digram_rules['gh']['r'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1146. digram_rules['gh']['s'] = NOT_BEGIN | PREFIX
  1147. digram_rules['gh']['t'] = NOT_BEGIN | PREFIX
  1148. digram_rules['gh']['u'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1149. digram_rules['gh']['v'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1150. digram_rules['gh']['w'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1151. digram_rules['gh']['x'] = ILLEGAL_PAIR
  1152. digram_rules['gh']['y'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1153. digram_rules['gh']['z'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1154. digram_rules['gh']['ch'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1155. digram_rules['gh']['gh'] = ILLEGAL_PAIR
  1156. digram_rules['gh']['ph'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1157. digram_rules['gh']['rh'] = ILLEGAL_PAIR
  1158. digram_rules['gh']['sh'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1159. digram_rules['gh']['th'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1160. digram_rules['gh']['wh'] = ILLEGAL_PAIR
  1161. digram_rules['gh']['qu'] = NOT_BEGIN | BREAK | PREFIX | NOT_END
  1162. digram_rules['gh']['ck'] = ILLEGAL_PAIR
  1163. digram_rules['ph'] = dict()
  1164. digram_rules['ph']['a'] = ANY_COMBINATION
  1165. digram_rules['ph']['b'] = NOT_BEGIN | BREAK | NOT_END
  1166. digram_rules['ph']['c'] = NOT_BEGIN | BREAK | NOT_END
  1167. digram_rules['ph']['d'] = NOT_BEGIN | BREAK | NOT_END
  1168. digram_rules['ph']['e'] = ANY_COMBINATION
  1169. digram_rules['ph']['f'] = NOT_BEGIN | BREAK | NOT_END
  1170. digram_rules['ph']['g'] = NOT_BEGIN | BREAK | NOT_END
  1171. digram_rules['ph']['h'] = NOT_BEGIN | BREAK | NOT_END
  1172. digram_rules['ph']['i'] = ANY_COMBINATION
  1173. digram_rules['ph']['j'] = NOT_BEGIN | BREAK | NOT_END
  1174. digram_rules['ph']['k'] = NOT_BEGIN | BREAK | NOT_END
  1175. digram_rules['ph']['l'] = BEGIN | SUFFIX | NOT_END
  1176. digram_rules['ph']['m'] = NOT_BEGIN | BREAK | NOT_END
  1177. digram_rules['ph']['n'] = NOT_BEGIN | BREAK | NOT_END
  1178. digram_rules['ph']['o'] = ANY_COMBINATION
  1179. digram_rules['ph']['p'] = NOT_BEGIN | BREAK | NOT_END
  1180. digram_rules['ph']['r'] = NOT_END
  1181. digram_rules['ph']['s'] = NOT_BEGIN
  1182. digram_rules['ph']['t'] = NOT_BEGIN
  1183. digram_rules['ph']['u'] = ANY_COMBINATION
  1184. digram_rules['ph']['v'] = NOT_BEGIN | NOT_END
  1185. digram_rules['ph']['w'] = NOT_BEGIN | NOT_END
  1186. digram_rules['ph']['x'] = ILLEGAL_PAIR
  1187. digram_rules['ph']['y'] = NOT_BEGIN
  1188. digram_rules['ph']['z'] = NOT_BEGIN | BREAK | NOT_END
  1189. digram_rules['ph']['ch'] = NOT_BEGIN | BREAK | NOT_END
  1190. digram_rules['ph']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1191. digram_rules['ph']['ph'] = ILLEGAL_PAIR
  1192. digram_rules['ph']['rh'] = ILLEGAL_PAIR
  1193. digram_rules['ph']['sh'] = NOT_BEGIN | BREAK | NOT_END
  1194. digram_rules['ph']['th'] = NOT_BEGIN | BREAK | NOT_END
  1195. digram_rules['ph']['wh'] = ILLEGAL_PAIR
  1196. digram_rules['ph']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1197. digram_rules['ph']['ck'] = ILLEGAL_PAIR
  1198. digram_rules['rh'] = dict()
  1199. digram_rules['rh']['a'] = BEGIN | NOT_END
  1200. digram_rules['rh']['b'] = ILLEGAL_PAIR
  1201. digram_rules['rh']['c'] = ILLEGAL_PAIR
  1202. digram_rules['rh']['d'] = ILLEGAL_PAIR
  1203. digram_rules['rh']['e'] = BEGIN | NOT_END
  1204. digram_rules['rh']['f'] = ILLEGAL_PAIR
  1205. digram_rules['rh']['g'] = ILLEGAL_PAIR
  1206. digram_rules['rh']['h'] = ILLEGAL_PAIR
  1207. digram_rules['rh']['i'] = BEGIN | NOT_END
  1208. digram_rules['rh']['j'] = ILLEGAL_PAIR
  1209. digram_rules['rh']['k'] = ILLEGAL_PAIR
  1210. digram_rules['rh']['l'] = ILLEGAL_PAIR
  1211. digram_rules['rh']['m'] = ILLEGAL_PAIR
  1212. digram_rules['rh']['n'] = ILLEGAL_PAIR
  1213. digram_rules['rh']['o'] = BEGIN | NOT_END
  1214. digram_rules['rh']['p'] = ILLEGAL_PAIR
  1215. digram_rules['rh']['r'] = ILLEGAL_PAIR
  1216. digram_rules['rh']['s'] = ILLEGAL_PAIR
  1217. digram_rules['rh']['t'] = ILLEGAL_PAIR
  1218. digram_rules['rh']['u'] = BEGIN | NOT_END
  1219. digram_rules['rh']['v'] = ILLEGAL_PAIR
  1220. digram_rules['rh']['w'] = ILLEGAL_PAIR
  1221. digram_rules['rh']['x'] = ILLEGAL_PAIR
  1222. digram_rules['rh']['y'] = BEGIN | NOT_END
  1223. digram_rules['rh']['z'] = ILLEGAL_PAIR
  1224. digram_rules['rh']['ch'] = ILLEGAL_PAIR
  1225. digram_rules['rh']['gh'] = ILLEGAL_PAIR
  1226. digram_rules['rh']['ph'] = ILLEGAL_PAIR
  1227. digram_rules['rh']['rh'] = ILLEGAL_PAIR
  1228. digram_rules['rh']['sh'] = ILLEGAL_PAIR
  1229. digram_rules['rh']['th'] = ILLEGAL_PAIR
  1230. digram_rules['rh']['wh'] = ILLEGAL_PAIR
  1231. digram_rules['rh']['qu'] = ILLEGAL_PAIR
  1232. digram_rules['rh']['ck'] = ILLEGAL_PAIR
  1233. digram_rules['sh'] = dict()
  1234. digram_rules['sh']['a'] = ANY_COMBINATION
  1235. digram_rules['sh']['b'] = NOT_BEGIN | BREAK | NOT_END
  1236. digram_rules['sh']['c'] = NOT_BEGIN | BREAK | NOT_END
  1237. digram_rules['sh']['d'] = NOT_BEGIN | BREAK | NOT_END
  1238. digram_rules['sh']['e'] = ANY_COMBINATION
  1239. digram_rules['sh']['f'] = NOT_BEGIN | BREAK | NOT_END
  1240. digram_rules['sh']['g'] = NOT_BEGIN | BREAK | NOT_END
  1241. digram_rules['sh']['h'] = ILLEGAL_PAIR
  1242. digram_rules['sh']['i'] = ANY_COMBINATION
  1243. digram_rules['sh']['j'] = NOT_BEGIN | BREAK | NOT_END
  1244. digram_rules['sh']['k'] = NOT_BEGIN
  1245. digram_rules['sh']['l'] = BEGIN | SUFFIX | NOT_END
  1246. digram_rules['sh']['m'] = BEGIN | SUFFIX | NOT_END
  1247. digram_rules['sh']['n'] = BEGIN | SUFFIX | NOT_END
  1248. digram_rules['sh']['o'] = ANY_COMBINATION
  1249. digram_rules['sh']['p'] = NOT_BEGIN
  1250. digram_rules['sh']['r'] = BEGIN | SUFFIX | NOT_END
  1251. digram_rules['sh']['s'] = NOT_BEGIN | BREAK | NOT_END
  1252. digram_rules['sh']['t'] = SUFFIX
  1253. digram_rules['sh']['u'] = ANY_COMBINATION
  1254. digram_rules['sh']['v'] = NOT_BEGIN | BREAK | NOT_END
  1255. digram_rules['sh']['w'] = SUFFIX | NOT_END
  1256. digram_rules['sh']['x'] = ILLEGAL_PAIR
  1257. digram_rules['sh']['y'] = ANY_COMBINATION
  1258. digram_rules['sh']['z'] = NOT_BEGIN | BREAK | NOT_END
  1259. digram_rules['sh']['ch'] = NOT_BEGIN | BREAK | NOT_END
  1260. digram_rules['sh']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1261. digram_rules['sh']['ph'] = NOT_BEGIN | BREAK | NOT_END
  1262. digram_rules['sh']['rh'] = ILLEGAL_PAIR
  1263. digram_rules['sh']['sh'] = ILLEGAL_PAIR
  1264. digram_rules['sh']['th'] = NOT_BEGIN | BREAK | NOT_END
  1265. digram_rules['sh']['wh'] = ILLEGAL_PAIR
  1266. digram_rules['sh']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1267. digram_rules['sh']['ck'] = ILLEGAL_PAIR
  1268. digram_rules['th'] = dict()
  1269. digram_rules['th']['a'] = ANY_COMBINATION
  1270. digram_rules['th']['b'] = NOT_BEGIN | BREAK | NOT_END
  1271. digram_rules['th']['c'] = NOT_BEGIN | BREAK | NOT_END
  1272. digram_rules['th']['d'] = NOT_BEGIN | BREAK | NOT_END
  1273. digram_rules['th']['e'] = ANY_COMBINATION
  1274. digram_rules['th']['f'] = NOT_BEGIN | BREAK | NOT_END
  1275. digram_rules['th']['g'] = NOT_BEGIN | BREAK | NOT_END
  1276. digram_rules['th']['h'] = NOT_BEGIN | BREAK | NOT_END
  1277. digram_rules['th']['i'] = ANY_COMBINATION
  1278. digram_rules['th']['j'] = NOT_BEGIN | BREAK | NOT_END
  1279. digram_rules['th']['k'] = NOT_BEGIN | BREAK | NOT_END
  1280. digram_rules['th']['l'] = NOT_BEGIN | BREAK | NOT_END
  1281. digram_rules['th']['m'] = NOT_BEGIN | BREAK | NOT_END
  1282. digram_rules['th']['n'] = NOT_BEGIN | BREAK | NOT_END
  1283. digram_rules['th']['o'] = ANY_COMBINATION
  1284. digram_rules['th']['p'] = NOT_BEGIN | BREAK | NOT_END
  1285. digram_rules['th']['r'] = NOT_END
  1286. digram_rules['th']['s'] = NOT_BEGIN | END
  1287. digram_rules['th']['t'] = NOT_BEGIN | BREAK | NOT_END
  1288. digram_rules['th']['u'] = ANY_COMBINATION
  1289. digram_rules['th']['v'] = NOT_BEGIN | BREAK | NOT_END
  1290. digram_rules['th']['w'] = SUFFIX | NOT_END
  1291. digram_rules['th']['x'] = ILLEGAL_PAIR
  1292. digram_rules['th']['y'] = ANY_COMBINATION
  1293. digram_rules['th']['z'] = NOT_BEGIN | BREAK | NOT_END
  1294. digram_rules['th']['ch'] = NOT_BEGIN | BREAK | NOT_END
  1295. digram_rules['th']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1296. digram_rules['th']['ph'] = NOT_BEGIN | BREAK | NOT_END
  1297. digram_rules['th']['rh'] = ILLEGAL_PAIR
  1298. digram_rules['th']['sh'] = NOT_BEGIN | BREAK | NOT_END
  1299. digram_rules['th']['th'] = ILLEGAL_PAIR
  1300. digram_rules['th']['wh'] = ILLEGAL_PAIR
  1301. digram_rules['th']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1302. digram_rules['th']['ck'] = ILLEGAL_PAIR
  1303. digram_rules['wh'] = dict()
  1304. digram_rules['wh']['a'] = BEGIN | NOT_END
  1305. digram_rules['wh']['b'] = ILLEGAL_PAIR
  1306. digram_rules['wh']['c'] = ILLEGAL_PAIR
  1307. digram_rules['wh']['d'] = ILLEGAL_PAIR
  1308. digram_rules['wh']['e'] = BEGIN | NOT_END
  1309. digram_rules['wh']['f'] = ILLEGAL_PAIR
  1310. digram_rules['wh']['g'] = ILLEGAL_PAIR
  1311. digram_rules['wh']['h'] = ILLEGAL_PAIR
  1312. digram_rules['wh']['i'] = BEGIN | NOT_END
  1313. digram_rules['wh']['j'] = ILLEGAL_PAIR
  1314. digram_rules['wh']['k'] = ILLEGAL_PAIR
  1315. digram_rules['wh']['l'] = ILLEGAL_PAIR
  1316. digram_rules['wh']['m'] = ILLEGAL_PAIR
  1317. digram_rules['wh']['n'] = ILLEGAL_PAIR
  1318. digram_rules['wh']['o'] = BEGIN | NOT_END
  1319. digram_rules['wh']['p'] = ILLEGAL_PAIR
  1320. digram_rules['wh']['r'] = ILLEGAL_PAIR
  1321. digram_rules['wh']['s'] = ILLEGAL_PAIR
  1322. digram_rules['wh']['t'] = ILLEGAL_PAIR
  1323. digram_rules['wh']['u'] = ILLEGAL_PAIR
  1324. digram_rules['wh']['v'] = ILLEGAL_PAIR
  1325. digram_rules['wh']['w'] = ILLEGAL_PAIR
  1326. digram_rules['wh']['x'] = ILLEGAL_PAIR
  1327. digram_rules['wh']['y'] = BEGIN | NOT_END
  1328. digram_rules['wh']['z'] = ILLEGAL_PAIR
  1329. digram_rules['wh']['ch'] = ILLEGAL_PAIR
  1330. digram_rules['wh']['gh'] = ILLEGAL_PAIR
  1331. digram_rules['wh']['ph'] = ILLEGAL_PAIR
  1332. digram_rules['wh']['rh'] = ILLEGAL_PAIR
  1333. digram_rules['wh']['sh'] = ILLEGAL_PAIR
  1334. digram_rules['wh']['th'] = ILLEGAL_PAIR
  1335. digram_rules['wh']['wh'] = ILLEGAL_PAIR
  1336. digram_rules['wh']['qu'] = ILLEGAL_PAIR
  1337. digram_rules['wh']['ck'] = ILLEGAL_PAIR
  1338. digram_rules['qu'] = dict()
  1339. digram_rules['qu']['a'] = ANY_COMBINATION
  1340. digram_rules['qu']['b'] = ILLEGAL_PAIR
  1341. digram_rules['qu']['c'] = ILLEGAL_PAIR
  1342. digram_rules['qu']['d'] = ILLEGAL_PAIR
  1343. digram_rules['qu']['e'] = ANY_COMBINATION
  1344. digram_rules['qu']['f'] = ILLEGAL_PAIR
  1345. digram_rules['qu']['g'] = ILLEGAL_PAIR
  1346. digram_rules['qu']['h'] = ILLEGAL_PAIR
  1347. digram_rules['qu']['i'] = ANY_COMBINATION
  1348. digram_rules['qu']['j'] = ILLEGAL_PAIR
  1349. digram_rules['qu']['k'] = ILLEGAL_PAIR
  1350. digram_rules['qu']['l'] = ILLEGAL_PAIR
  1351. digram_rules['qu']['m'] = ILLEGAL_PAIR
  1352. digram_rules['qu']['n'] = ILLEGAL_PAIR
  1353. digram_rules['qu']['o'] = ANY_COMBINATION
  1354. digram_rules['qu']['p'] = ILLEGAL_PAIR
  1355. digram_rules['qu']['r'] = ILLEGAL_PAIR
  1356. digram_rules['qu']['s'] = ILLEGAL_PAIR
  1357. digram_rules['qu']['t'] = ILLEGAL_PAIR
  1358. digram_rules['qu']['u'] = ILLEGAL_PAIR
  1359. digram_rules['qu']['v'] = ILLEGAL_PAIR
  1360. digram_rules['qu']['w'] = ILLEGAL_PAIR
  1361. digram_rules['qu']['x'] = ILLEGAL_PAIR
  1362. digram_rules['qu']['y'] = ILLEGAL_PAIR
  1363. digram_rules['qu']['z'] = ILLEGAL_PAIR
  1364. digram_rules['qu']['ch'] = ILLEGAL_PAIR
  1365. digram_rules['qu']['gh'] = ILLEGAL_PAIR
  1366. digram_rules['qu']['ph'] = ILLEGAL_PAIR
  1367. digram_rules['qu']['rh'] = ILLEGAL_PAIR
  1368. digram_rules['qu']['sh'] = ILLEGAL_PAIR
  1369. digram_rules['qu']['th'] = ILLEGAL_PAIR
  1370. digram_rules['qu']['wh'] = ILLEGAL_PAIR
  1371. digram_rules['qu']['qu'] = ILLEGAL_PAIR
  1372. digram_rules['qu']['ck'] = ILLEGAL_PAIR
  1373. digram_rules['ck'] = dict()
  1374. digram_rules['ck']['a'] = NOT_BEGIN | BREAK | NOT_END
  1375. digram_rules['ck']['b'] = NOT_BEGIN | BREAK | NOT_END
  1376. digram_rules['ck']['c'] = NOT_BEGIN | BREAK | NOT_END
  1377. digram_rules['ck']['d'] = NOT_BEGIN | BREAK | NOT_END
  1378. digram_rules['ck']['e'] = NOT_BEGIN | BREAK | NOT_END
  1379. digram_rules['ck']['f'] = NOT_BEGIN | BREAK | NOT_END
  1380. digram_rules['ck']['g'] = NOT_BEGIN | BREAK | NOT_END
  1381. digram_rules['ck']['h'] = NOT_BEGIN | BREAK | NOT_END
  1382. digram_rules['ck']['i'] = NOT_BEGIN | BREAK | NOT_END
  1383. digram_rules['ck']['j'] = NOT_BEGIN | BREAK | NOT_END
  1384. digram_rules['ck']['k'] = NOT_BEGIN | BREAK | NOT_END
  1385. digram_rules['ck']['l'] = NOT_BEGIN | BREAK | NOT_END
  1386. digram_rules['ck']['m'] = NOT_BEGIN | BREAK | NOT_END
  1387. digram_rules['ck']['n'] = NOT_BEGIN | BREAK | NOT_END
  1388. digram_rules['ck']['o'] = NOT_BEGIN | BREAK | NOT_END
  1389. digram_rules['ck']['p'] = NOT_BEGIN | BREAK | NOT_END
  1390. digram_rules['ck']['r'] = NOT_BEGIN | BREAK | NOT_END
  1391. digram_rules['ck']['s'] = NOT_BEGIN
  1392. digram_rules['ck']['t'] = NOT_BEGIN | BREAK | NOT_END
  1393. digram_rules['ck']['u'] = NOT_BEGIN | BREAK | NOT_END
  1394. digram_rules['ck']['v'] = NOT_BEGIN | BREAK | NOT_END
  1395. digram_rules['ck']['w'] = NOT_BEGIN | BREAK | NOT_END
  1396. digram_rules['ck']['x'] = ILLEGAL_PAIR
  1397. digram_rules['ck']['y'] = NOT_BEGIN
  1398. digram_rules['ck']['z'] = NOT_BEGIN | BREAK | NOT_END
  1399. digram_rules['ck']['ch'] = NOT_BEGIN | BREAK | NOT_END
  1400. digram_rules['ck']['gh'] = NOT_BEGIN | BREAK | NOT_END
  1401. digram_rules['ck']['ph'] = NOT_BEGIN | BREAK | NOT_END
  1402. digram_rules['ck']['rh'] = ILLEGAL_PAIR
  1403. digram_rules['ck']['sh'] = NOT_BEGIN | BREAK | NOT_END
  1404. digram_rules['ck']['th'] = NOT_BEGIN | BREAK | NOT_END
  1405. digram_rules['ck']['wh'] = ILLEGAL_PAIR
  1406. digram_rules['ck']['qu'] = NOT_BEGIN | BREAK | NOT_END
  1407. digram_rules['ck']['ck'] = ILLEGAL_PAIR
  1408. ###############################################################################
  1409. # END DIGRAM RULES
  1410. ###############################################################################
  1411. def marked(flag, first_unit, second_unit):
  1412. return digram_rules[first_unit][second_unit] & flag
  1413. # Generates a random word, as well as its hyphenated form. The
  1414. # length of the returned word will be between minlen and maxlen.
  1415. def generate_password_shazel(minlen = MIN_LENGTH_PASSWORD,
  1416. maxlen = MAX_LENGTH_PASSWORD):
  1417. if (minlen > maxlen):
  1418. raise PasswordGenerationException("minlen minlen is greater than maxlen maxlen.")
  1419. #
  1420. # Check for zero length words. This is technically not an error,
  1421. # so we take the short cut and return empty words.
  1422. #
  1423. if (maxlen == 0):
  1424. raise PasswordGenerationException("maxlen must be greater than 0.")
  1425. word = ''
  1426. for i in range(MAX_UNACCEPTABLE):
  1427. results = _random_word(random.randint(minlen, maxlen))
  1428. word = results[0]
  1429. hyphenated_word = results[1]
  1430. if (word != ''):
  1431. break
  1432. if (word == "" and (minlen > 0)):
  1433. raise PasswordGenerationException("failed to generate an acceptable random password.")
  1434. return (word, hyphenated_word)
  1435. # Selects a random element from an array.
  1436. def random_element(ar):
  1437. try:
  1438. keys = ar.keys()
  1439. except:
  1440. keys = range(len(ar))
  1441. return ar[ keys[random.randint(0, len(keys) - 1)] ]
  1442. # This is the routine that returns a random word. It collects random
  1443. # syllables until a predetermined word length is found. If a retry
  1444. # threshold is reached, another word is tried.
  1445. def _random_word(pwlen):
  1446. word = ''
  1447. word_syllables = []
  1448. max_retries = (4 * pwlen) + len(grams)
  1449. tries = 0 # count of retries.
  1450. # word_units used to be an array of indices into the 'rules' C-array.
  1451. # now it's an array of actual units (grams).
  1452. word_units = []
  1453. saved_pair = []
  1454. #
  1455. # Find syllables until the entire word is constructed.
  1456. #
  1457. while(len(word) < pwlen):
  1458. #
  1459. # Get the syllable and find its length.
  1460. #
  1461. new_syllable, syllable_units, saved_pair = get_syllable(pwlen - len(word), saved_pair)
  1462. #
  1463. # Append the syllable units to the word units.
  1464. #
  1465. word_units = word_units + syllable_units
  1466. #
  1467. # If the word has been improperly formed, throw out
  1468. # the syllable. The checks performed here are those
  1469. # that must be formed on a word basis. The other
  1470. # tests are performed entirely within the syllable.
  1471. # Otherwise, append the syllable to the word.
  1472. #
  1473. if not (
  1474. _improper_word(word_units)
  1475. or
  1476. (
  1477. word == ''
  1478. and
  1479. _have_initial_y(syllable_units)
  1480. )
  1481. or
  1482. (
  1483. len(word + new_syllable) == pwlen
  1484. and
  1485. _have_final_split(syllable_units)
  1486. )
  1487. ):
  1488. word = word + new_syllable
  1489. word_syllables.append(new_syllable)
  1490. #
  1491. # Keep track of the times we have tried to get syllables.
  1492. # If we have exceeded the threshold, start from scratch.
  1493. #
  1494. tries = tries + 1
  1495. if (tries > max_retries):
  1496. tries = 0
  1497. word = ''
  1498. word_syllables = []
  1499. word_units = []
  1500. return (word, '-'.join(word_syllables))
  1501. # Selects a gram (aka "unit"). This is the standard random unit
  1502. # generating routine for get_syllable().
  1503. #
  1504. # This routine attempts to return grams (units) with a distribution
  1505. # approaching that of the distribution of the units in English.
  1506. #
  1507. # The distribution of the units may be altered in this procedure
  1508. # without affecting the digram table or any other programs using the
  1509. # random_word function, as long as the set of grams (units) is kept
  1510. # consistent throughout this library.
  1511. def _random_unit(type):
  1512. if (type & VOWEL):
  1513. # Sometimes, we are asked to explicitly get a vowel (i.e., if
  1514. # a digram pair expects one following it). This is a
  1515. # shortcut to do that and avoid looping with rejected
  1516. # consonants.
  1517. return random_element(vowel_numbers)
  1518. else:
  1519. # Get any letter according to the English distribution.
  1520. return random_element(numbers)
  1521. # Check that the word does not contain illegal combinations
  1522. # that may span syllables. Specifically, these are:
  1523. #
  1524. # 1. An illegal pair of units between syllables.
  1525. # 2. Three consecutive vowel units.
  1526. # 3. Three consecutive consonant units.
  1527. #
  1528. # The checks are made against units (1 or 2 letters), not against
  1529. # the individual letters, so three consecutive units can have
  1530. # the length of 6 at most.
  1531. def _improper_word(units):
  1532. failure = 0
  1533. for unit_count in range(len(units)):
  1534. #
  1535. # Check for ILLEGAL_PAIR.
  1536. # This should have been caught for units within a syllable,
  1537. # but in some cases it would have gone unnoticed for units between syllables
  1538. # (e.g., when saved units in get_syllable() were not used).
  1539. #
  1540. if (unit_count > 0
  1541. and digram_rules[units[unit_count-1]][units[unit_count]]
  1542. & ILLEGAL_PAIR):
  1543. return 1 # Failure!
  1544. if (unit_count >= 2):
  1545. #
  1546. # Check for consecutive vowels or consonants. Because the
  1547. # initial y of a syllable is treated as a consonant rather
  1548. # than as a vowel, we exclude y from the first vowel in the
  1549. # vowel test. The only problem comes when y ends a syllable
  1550. # and two other vowels start the next, like fly-oint. Since
  1551. # such words are still pronounceable, we accept this.
  1552. #
  1553. #
  1554. # Vowel check.
  1555. #
  1556. if ((
  1557. (gram_rules[units[unit_count - 2]] & VOWEL)
  1558. and
  1559. not (gram_rules[units[unit_count - 2]] & ALTERNATE_VOWEL)
  1560. and
  1561. (gram_rules[units[unit_count - 1]] & VOWEL)
  1562. and
  1563. (gram_rules[units[unit_count ]] & VOWEL)
  1564. )
  1565. or
  1566. #
  1567. # Consonant check.
  1568. #
  1569. (
  1570. not (gram_rules[units[unit_count - 2]] & VOWEL)
  1571. and
  1572. not (gram_rules[units[unit_count - 1]] & VOWEL)
  1573. and
  1574. not (gram_rules[units[unit_count ]] & VOWEL)
  1575. )):
  1576. return 1 # Failure!
  1577. return 0 # success
  1578. # Treating y as a vowel is sometimes a problem. Some words get
  1579. # formed that look irregular. One special group is when y starts a
  1580. # word and is the only vowel in the first syllable. The word ycl is
  1581. # one example. We discard words like these.
  1582. def _have_initial_y(units):
  1583. vowel_count = 0
  1584. normal_vowel_count = 0
  1585. for unit_count in range(len(units)):
  1586. #
  1587. # Count vowels.
  1588. #
  1589. if (gram_rules[units[unit_count]] & VOWEL):
  1590. vowel_count = vowel_count + 1
  1591. #
  1592. # Count the vowels that are not:
  1593. # 1. 'y'
  1594. # 2. at the start of the word.
  1595. #
  1596. if (not (gram_rules[units[unit_count]] & ALTERNATE_VOWEL) or (unit_count > 0)):
  1597. normal_vowel_count = normal_vowel_count + 1
  1598. return (vowel_count <= 1) and (normal_vowel_count == 0)
  1599. # Besides the problem with the letter y, there is one with a silent e
  1600. # at the end of words, like face or nice. We allow this silent e,
  1601. # but we do not allow it as the only vowel at the end of the word or
  1602. # syllables like ble will be generated.
  1603. def _have_final_split(units):
  1604. vowel_count = 0
  1605. #
  1606. # Count all the vowels in the word.
  1607. #
  1608. for unit_count in range(len(units)):
  1609. if (gram_rules[units[unit_count]] & VOWEL):
  1610. vowel_count = vowel_count + 1
  1611. #
  1612. # Return TRUE iff the only vowel was e, found at the end if the word.
  1613. #
  1614. return ((vowel_count == 1)
  1615. and (gram_rules[units[len(units) - 1]] & NO_FINAL_SPLIT))
  1616. def digram_is_invalid(first_unit, second_unit, current_unit_num,
  1617. length_left, units_in_syllable, vowel_count):
  1618. #
  1619. # Reject ILLEGAL_PAIRS of units.
  1620. #
  1621. if (marked(ILLEGAL_PAIR,
  1622. first_unit,
  1623. second_unit)):
  1624. return 1
  1625. #
  1626. # Reject units that will be split between
  1627. # syllables when the syllable has no vowels
  1628. # in it.
  1629. #
  1630. if (marked(BREAK,
  1631. first_unit,
  1632. second_unit) and
  1633. (vowel_count == 0)):
  1634. return 1
  1635. #
  1636. # Reject a unit that will end a syllable when
  1637. # no previous unit was a vowel and neither is
  1638. # this one.
  1639. #
  1640. if (marked(END,
  1641. first_unit,
  1642. second_unit) and
  1643. (vowel_count == 0) and
  1644. not (gram_rules[second_unit] & VOWEL)):
  1645. return 1
  1646. if (current_unit_num == 1):
  1647. #
  1648. # Reject the unit if we are at the starting
  1649. # digram of a syllable and it does not fit.
  1650. #
  1651. if (marked(NOT_BEGIN,
  1652. first_unit,
  1653. second_unit)):
  1654. return 1
  1655. else:
  1656. # We are not at the start of a syllable.
  1657. #
  1658. # Do not allow syllables where the first letter is y
  1659. # and the next pair can begin a syllable. This may
  1660. # lead to splits where y is left alone in a syllable.
  1661. # Also, the combination does not sound to good even
  1662. # if not split.
  1663. #
  1664. if ((current_unit_num == 2) and
  1665. marked(BEGIN,
  1666. first_unit,
  1667. second_unit) and
  1668. (gram_rules[units_in_syllable[0]] &
  1669. ALTERNATE_VOWEL)):
  1670. return 1
  1671. #
  1672. # If this is the last unit of a word, we
  1673. # should reject any digram that cannot end a
  1674. # syllable.
  1675. #
  1676. if (marked(NOT_END,
  1677. first_unit,
  1678. second_unit) and
  1679. (length_left == 0)):
  1680. return 1
  1681. #
  1682. # Reject the unit if the digram it forms wants
  1683. # to break the syllable, but the resulting
  1684. # digram that would end the syllable is not
  1685. # allowed to end a syllable.
  1686. #
  1687. if (marked(BREAK,
  1688. first_unit,
  1689. second_unit) and
  1690. (digram_rules[units_in_syllable[current_unit_num-2]]
  1691. [first_unit] & NOT_END)):
  1692. return 1
  1693. #
  1694. # Reject the unit if the digram it forms
  1695. # expects a vowel preceding it and there
  1696. # is none.
  1697. #
  1698. if (marked(PREFIX,
  1699. first_unit,
  1700. second_unit) and
  1701. not (gram_rules[ units_in_syllable[current_unit_num-2] ] &
  1702. VOWEL)):
  1703. return 1
  1704. return 0
  1705. # Generate next unit to password, making sure that it follows these rules:
  1706. #
  1707. # 1. Each syllable must contain exactly 1 or 2 consecutive vowels,
  1708. # where y is considered a vowel.
  1709. #
  1710. # 2. Syllable end is determined as follows:
  1711. #
  1712. # a. Vowel is generated and previous unit is a consonant and
  1713. # syllable already has a vowel. In this case, new syllable is
  1714. # started and already contains a vowel.
  1715. # b. A pair determined to be a "break" pair is encountered.
  1716. # In this case new syllable is started with second unit of this pair.
  1717. # c. End of password is encountered.
  1718. # d. "begin" pair is encountered legally. New syllable is started
  1719. # with this pair.
  1720. # e. "end" pair is legally encountered. New syllable has nothing yet.
  1721. #
  1722. # 3. Try generating another unit if:
  1723. #
  1724. # a. third consecutive vowel and not y.
  1725. # b. "break" pair generated but no vowel yet in current or
  1726. # previous 2 units are "not_end".
  1727. # c. "begin" pair generated but no vowel in syllable preceding begin pair,
  1728. # or both previous 2 pairs are designated "not_end".
  1729. # d. "end" pair generated but no vowel in current syllable or in
  1730. # "end" pair.
  1731. # e. "not_begin" pair generated but new syllable must begin
  1732. # (because previous syllable ended as defined in 2 above).
  1733. # f. vowel is generated and 2a is satisfied, but no syllable break
  1734. # is possible in previous 3 pairs.
  1735. # g. Second and third units of syllable must begin, and first unit
  1736. # is "alternate_vowel".
  1737. def get_syllable(pwlen, saved_pair):
  1738. #
  1739. # This is needed if the saved_pair is tried and the syllable then
  1740. # discarded because of the retry limit. Since the saved_pair is OK and
  1741. # fits in nicely with the preceding syllable, we will always use it.
  1742. #
  1743. hold_saved_pair = saved_pair
  1744. max_retries = (4 * pwlen) + len(grams)
  1745. max_loops = 100
  1746. num_loops = 0
  1747. #
  1748. # Loop until valid syllable is found.
  1749. #
  1750. while True: # do: ftso python while: not PEP 315.
  1751. #
  1752. # Try for a new syllable. Initialize all pertinent
  1753. # syllable variables.
  1754. #
  1755. syllable = "" # string, returned
  1756. units_in_syllable = dict() # array of units, returned
  1757. # grams:
  1758. unit = ''
  1759. current_unit = 0
  1760. last_unit = ''
  1761. # numbers:
  1762. vowel_count = 0
  1763. tries = 0
  1764. length_left = pwlen
  1765. # flags:
  1766. rule_broken = 0
  1767. want_vowel = 0
  1768. want_another_unit = 1
  1769. saved_pair = hold_saved_pair
  1770. #
  1771. # This loop finds all the units for the syllable.
  1772. #
  1773. while True: # do: ftso python while: not PEP 315.
  1774. want_vowel = 0
  1775. #
  1776. # This loop continues until a valid unit is found for the
  1777. # current position within the syllable.
  1778. #
  1779. while True: # do: ftso python while: not PEP 315.
  1780. rule_broken = 0
  1781. #
  1782. # If there are saved units from the previous
  1783. # syllable, use them up first.
  1784. #
  1785. #
  1786. # If there were two saved units, the first is
  1787. # guaranteed (by checks performed in the previous
  1788. # syllable) to be valid. We ignore the checks and
  1789. # place it in this syllable manually.
  1790. #
  1791. if (len(saved_pair) == 2):
  1792. syllable = saved_pair.pop()
  1793. units_in_syllable[0] = syllable
  1794. if (gram_rules[syllable] & VOWEL):
  1795. vowel_count = vowel_count + 1
  1796. current_unit = current_unit + 1
  1797. length_left -= len(syllable)
  1798. if (len(saved_pair) > 0):
  1799. #
  1800. # The unit becomes the last unit checked in the
  1801. # previous syllable.
  1802. #
  1803. unit = saved_pair.pop()
  1804. #
  1805. # The saved units have been used. Do not try to
  1806. # reuse them in this syllable (unless this
  1807. # particular syllable is rejected at which point
  1808. # we start to rebuild it with these same saved
  1809. # units).
  1810. #
  1811. else:
  1812. #
  1813. # If we don't have to consider the saved units,
  1814. # we generate a random one.
  1815. #
  1816. if (want_vowel):
  1817. unit = _random_unit(VOWEL)
  1818. else:
  1819. unit = _random_unit(NO_SPECIAL_RULE)
  1820. length_left -= len(unit)
  1821. rule_broken = 0
  1822. #
  1823. # Prevent having a word longer than expected.
  1824. #
  1825. if (length_left < 0):
  1826. rule_broken = 1
  1827. #
  1828. # First unit of syllable. This is special because
  1829. # the digram tests require 2 units and we don't have
  1830. # that yet. Nevertheless, we can perform some
  1831. # checks.
  1832. #
  1833. if (current_unit == 0):
  1834. #
  1835. # If this shouldn't begin a syllable, don't use it.
  1836. #
  1837. if (gram_rules[unit] & NOT_BEGIN_SYLLABLE):
  1838. rule_broken = 1
  1839. elif (length_left == 0):
  1840. #
  1841. # If this is the last unit of a word, we have
  1842. # a one unit syllable. Since each syllable
  1843. # must have a vowel, we make sure the unit is
  1844. # a vowel. Otherwise, we discard it.
  1845. #
  1846. if (gram_rules[unit] & VOWEL):
  1847. want_another_unit = 0
  1848. else:
  1849. rule_broken = 1
  1850. else:
  1851. #
  1852. # We are not at the start of a syllable.
  1853. # Save the previous unit for later tests.
  1854. #
  1855. last_unit = units_in_syllable[current_unit-1]
  1856. #
  1857. # There are some digram tests that are
  1858. # universally true. We test them out.
  1859. #
  1860. if (digram_is_invalid(last_unit,
  1861. unit,
  1862. current_unit,
  1863. length_left,
  1864. units_in_syllable,
  1865. vowel_count)):
  1866. rule_broken = 1
  1867. #
  1868. # The following checks occur when the current
  1869. # unit is a vowel and we are not looking at a
  1870. # word ending with an e.
  1871. #
  1872. if (not rule_broken and
  1873. (gram_rules[unit] & VOWEL) and
  1874. ((length_left > 0)
  1875. or not (gram_rules[last_unit] & NO_FINAL_SPLIT))):
  1876. #
  1877. # Don't allow 3 consecutive vowels in a
  1878. # syllable. Although some words formed
  1879. # like this are OK, like "beau", most are
  1880. # not.
  1881. #
  1882. if ((vowel_count > 1) and
  1883. (gram_rules[last_unit] & VOWEL)):
  1884. rule_broken = 1
  1885. #
  1886. # Check for the case of
  1887. # vowels-consonants-vowel, which is only
  1888. # legal if the last vowel is an e and we
  1889. # are the end of the word (which is not
  1890. # happening here due to a previous
  1891. # check).
  1892. #
  1893. elif ((vowel_count != 0) and not (gram_rules[last_unit] & VOWEL)):
  1894. #
  1895. # Try to save the vowel for the next
  1896. # syllable, but if the syllable left here
  1897. # is not proper (i.e., the resulting last
  1898. # digram cannot legally end it), just
  1899. # discard it and try for another.
  1900. #
  1901. if (digram_rules[ units_in_syllable[ current_unit - 2] ][last_unit] & NOT_END):
  1902. rule_broken = 1
  1903. else:
  1904. saved_pair = [unit]
  1905. want_another_unit = 0
  1906. #
  1907. # The unit picked and the digram formed are legal.
  1908. # We now determine if we can end the syllable. It may,
  1909. # in some cases, mean the last unit(s) may be deferred to
  1910. # the next syllable. We also check here to see if the
  1911. # digram formed expects a vowel to follow.
  1912. #
  1913. if (not rule_broken and want_another_unit):
  1914. if ((vowel_count != 0) and
  1915. (gram_rules[unit] & NO_FINAL_SPLIT) and
  1916. (length_left == 0) and
  1917. not (gram_rules[last_unit] & VOWEL)):
  1918. #
  1919. # This word ends in a silent e.
  1920. #
  1921. want_another_unit = 0
  1922. elif (marked(END,
  1923. last_unit,
  1924. unit)
  1925. or (length_left == 0)):
  1926. #
  1927. # This syllable ends either because the
  1928. # digram is a END pair or we would
  1929. # otherwise exceed the length of the
  1930. # word.
  1931. #
  1932. want_another_unit = 0
  1933. elif (vowel_count != 0 and length_left > 0):
  1934. #
  1935. # Since we have a vowel in the syllable
  1936. # already, if the digram calls for the end of the
  1937. # syllable, we can legally split it off. We also
  1938. # make sure that we are not at the end of the
  1939. # dangerous because that syllable may not have
  1940. # vowels, or it may not be a legal syllable end,
  1941. # and the retrying mechanism will loop infinitely
  1942. # with the same digram.
  1943. #
  1944. #
  1945. # If we must begin a syllable, we do so if
  1946. # the only vowel in THIS syllable is not part
  1947. # of the digram we are pushing to the next
  1948. # syllable.
  1949. #
  1950. if (marked(BEGIN,
  1951. last_unit,
  1952. unit) and
  1953. (current_unit > 1) and
  1954. not ((vowel_count == 1) and
  1955. (gram_rules[last_unit] & VOWEL))):
  1956. saved_pair = [unit, last_unit]
  1957. want_another_unit = 0
  1958. elif (
  1959. marked(BREAK,
  1960. last_unit,
  1961. unit)):
  1962. saved_pair = [unit]
  1963. want_another_unit = 0
  1964. elif (
  1965. marked(SUFFIX,
  1966. last_unit,
  1967. unit)):
  1968. want_vowel = 1
  1969. tries = tries + 1
  1970. #
  1971. # If this unit was illegal, redetermine the amount of
  1972. # letters left to go in the word.
  1973. #
  1974. if (rule_broken):
  1975. length_left += len(unit)
  1976. if not (rule_broken and tries <= max_retries):
  1977. break
  1978. #
  1979. # The unit fit OK.
  1980. #
  1981. if (tries <= max_retries):
  1982. #
  1983. # If the unit were a vowel, count it in. However, if
  1984. # the unit were a y and appear at the start of the
  1985. # syllable, treat it like a constant (so that words
  1986. # like "year" can appear and not conflict with the 3
  1987. # consecutive vowel rule).
  1988. #
  1989. if (
  1990. (gram_rules[unit] & VOWEL)
  1991. and
  1992. ((current_unit > 0) or not (gram_rules[unit] & ALTERNATE_VOWEL))
  1993. ):
  1994. vowel_count = vowel_count + 1
  1995. #
  1996. # If a unit or units were to be saved, we must adjust
  1997. # the syllable formed. Otherwise, we append the
  1998. # current unit to the syllable.
  1999. #
  2000. if (len(saved_pair) == 2):
  2001. syllable = syllable[0:
  2002. len(syllable) -
  2003. len(last_unit)]
  2004. length_left += len(last_unit)
  2005. current_unit -= 2
  2006. elif (len(saved_pair) == 1):
  2007. current_unit = current_unit - 1
  2008. else:
  2009. units_in_syllable[ current_unit ] = unit
  2010. syllable = syllable + unit
  2011. else:
  2012. #
  2013. # Whoops! Too many tries. We set rule_broken so we
  2014. # can loop in the outer loop and try another
  2015. # syllable.
  2016. #
  2017. rule_broken = 1
  2018. current_unit = current_unit + 1
  2019. if not (tries <= max_retries and want_another_unit):
  2020. break
  2021. num_loops = num_loops + 1
  2022. if not ((rule_broken or _illegal_placement(units_in_syllable))):
  2023. break
  2024. return (syllable, units_in_syllable.values(), saved_pair)
  2025. # goes through an individual syllable and checks for illegal
  2026. # combinations of letters that go beyond looking at digrams.
  2027. #
  2028. # We look at things like 3 consecutive vowels or consonants, or
  2029. # syllables with consonants between vowels (unless one of them is the
  2030. # final silent e).
  2031. def _illegal_placement(units):
  2032. vowel_count = 0
  2033. failure = 0
  2034. for unit_count in range(len(units)):
  2035. if (failure):
  2036. break
  2037. if (unit_count >= 1):
  2038. #
  2039. # Don't allow vowels to be split with consonants in a
  2040. # single syllable. If we find such a combination (except
  2041. # for the silent e) we have to discard the syllable.
  2042. #
  2043. if (
  2044. (
  2045. not (gram_rules[units[unit_count-1]] & VOWEL)
  2046. and
  2047. (gram_rules[units[unit_count ]] & VOWEL)
  2048. and
  2049. not ((gram_rules[units[unit_count ]] & NO_FINAL_SPLIT) and (unit_count == len(units)))
  2050. and
  2051. vowel_count
  2052. )
  2053. or
  2054. #
  2055. # Perform these checks when we have at least 3 units.
  2056. #
  2057. (
  2058. (unit_count >= 2)
  2059. and
  2060. (
  2061. #
  2062. # Disallow 3 consecutive consonants.
  2063. #
  2064. (
  2065. not (gram_rules[units[unit_count-2]] & VOWEL)
  2066. and
  2067. not (gram_rules[units[unit_count-1]] & VOWEL)
  2068. and
  2069. not (gram_rules[units[unit_count]] & VOWEL)
  2070. )
  2071. or
  2072. #
  2073. # Disallow 3 consecutive vowels, where the
  2074. # first is not a y.
  2075. #
  2076. (
  2077. (gram_rules[units[unit_count-2]] & VOWEL)
  2078. and
  2079. not ((gram_rules[units[0]] & ALTERNATE_VOWEL)
  2080. and (unit_count == 2))
  2081. and
  2082. (gram_rules[units[unit_count-1]] & VOWEL)
  2083. and
  2084. (gram_rules[units[unit_count]] & VOWEL)
  2085. )
  2086. )
  2087. )
  2088. ):
  2089. failure = 1
  2090. #
  2091. # Count the vowels in the syllable. As mentioned somewhere
  2092. # above, exclude the initial y of a syllable. Instead, treat
  2093. # it as a consonant.
  2094. #
  2095. if (
  2096. (gram_rules[units[unit_count]] & VOWEL)
  2097. and
  2098. not (
  2099. (gram_rules[units[0]] & ALTERNATE_VOWEL)
  2100. and
  2101. (unit_count == 0)
  2102. and
  2103. (len(units) > 1)
  2104. )
  2105. ):
  2106. vowel_count = vowel_count + 1
  2107. return failure