From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- extensions/auth/gssapi.h | 848 + extensions/auth/moz.build | 27 + extensions/auth/nsAuth.h | 27 + extensions/auth/nsAuthFactory.cpp | 247 + extensions/auth/nsAuthGSSAPI.cpp | 603 + extensions/auth/nsAuthGSSAPI.h | 63 + extensions/auth/nsAuthSASL.cpp | 151 + extensions/auth/nsAuthSASL.h | 38 + extensions/auth/nsAuthSSPI.cpp | 666 + extensions/auth/nsAuthSSPI.h | 59 + extensions/auth/nsAuthSambaNTLM.cpp | 296 + extensions/auth/nsAuthSambaNTLM.h | 52 + extensions/auth/nsHttpNegotiateAuth.cpp | 731 + extensions/auth/nsHttpNegotiateAuth.h | 44 + extensions/build.mk | 18 + extensions/confvars.sh | 8 + extensions/cookie/moz.build | 30 + extensions/cookie/nsCookieModule.cpp | 51 + extensions/cookie/nsCookiePermission.cpp | 273 + extensions/cookie/nsCookiePermission.h | 48 + extensions/cookie/nsCookiePromptService.cpp | 101 + extensions/cookie/nsCookiePromptService.h | 29 + extensions/cookie/nsICookieAcceptDialog.idl | 21 + extensions/cookie/nsICookiePromptService.idl | 45 + extensions/cookie/nsPermission.cpp | 201 + extensions/cookie/nsPermission.h | 43 + extensions/cookie/nsPermissionManager.cpp | 2918 ++ extensions/cookie/nsPermissionManager.h | 295 + extensions/cookie/nsPopupWindowManager.cpp | 111 + extensions/cookie/nsPopupWindowManager.h | 39 + extensions/cookie/test/beltzner.jpg | Bin 0 -> 9995 bytes extensions/cookie/test/beltzner.jpg^headers^ | 3 + extensions/cookie/test/browser.ini | 3 + extensions/cookie/test/browser_test_favicon.js | 28 + extensions/cookie/test/damonbowling.jpg | Bin 0 -> 44008 bytes extensions/cookie/test/damonbowling.jpg^headers^ | 2 + extensions/cookie/test/file_chromecommon.js | 15 + .../cookie/test/file_domain_hierarchy_inner.html | 14 + .../test/file_domain_hierarchy_inner_inner.html | 14 + .../file_domain_hierarchy_inner_inner_inner.html | 14 + extensions/cookie/test/file_domain_inner.html | 14 + .../cookie/test/file_domain_inner_inner.html | 14 + extensions/cookie/test/file_image_inner.html | 15 + extensions/cookie/test/file_image_inner_inner.html | 20 + extensions/cookie/test/file_loadflags_inner.html | 17 + extensions/cookie/test/file_localhost_inner.html | 14 + extensions/cookie/test/file_loopback_inner.html | 14 + extensions/cookie/test/file_subdomain_inner.html | 14 + extensions/cookie/test/file_testcommon.js | 70 + extensions/cookie/test/file_testloadflags.js | 104 + .../cookie/test/file_testloadflags_chromescript.js | 112 + extensions/cookie/test/image1.png | Bin 0 -> 821 bytes extensions/cookie/test/image1.png^headers^ | 3 + extensions/cookie/test/image2.png | Bin 0 -> 821 bytes extensions/cookie/test/image2.png^headers^ | 3 + extensions/cookie/test/mochitest.ini | 41 + extensions/cookie/test/moz.build | 15 + extensions/cookie/test/test1.css | 2 + extensions/cookie/test/test1.css^headers^ | 3 + extensions/cookie/test/test2.css | 2 + extensions/cookie/test/test2.css^headers^ | 3 + .../test/test_different_domain_in_hierarchy.html | 15 + extensions/cookie/test/test_differentdomain.html | 15 + extensions/cookie/test/test_image.html | 14 + extensions/cookie/test/test_loadflags.html | 21 + extensions/cookie/test/test_same_base_domain.html | 15 + .../cookie/test/test_same_base_domain_2.html | 15 + .../cookie/test/test_same_base_domain_3.html | 15 + .../cookie/test/test_same_base_domain_4.html | 15 + .../cookie/test/test_same_base_domain_5.html | 15 + .../cookie/test/test_same_base_domain_6.html | 15 + extensions/cookie/test/test_samedomain.html | 15 + extensions/cookie/test/unit/cookieprompt.js | 22 + extensions/cookie/test/unit/cookieprompt.manifest | 2 + extensions/cookie/test/unit/head_cookies.js | 570 + extensions/cookie/test/unit/test_bug526789.js | 248 + extensions/cookie/test/unit/test_bug650522.js | 16 + extensions/cookie/test/unit/test_bug667087.js | 16 + .../cookie/test/unit/test_cookies_async_failure.js | 600 + .../cookie/test/unit/test_cookies_persistence.js | 78 + .../test/unit/test_cookies_privatebrowsing.js | 115 + .../cookie/test/unit/test_cookies_profile_close.js | 92 + extensions/cookie/test/unit/test_cookies_read.js | 122 + .../cookie/test/unit/test_cookies_sync_failure.js | 286 + .../cookie/test/unit/test_cookies_thirdparty.js | 147 + .../test/unit/test_cookies_thirdparty_session.js | 69 + .../cookie/test/unit/test_domain_eviction.js | 153 + extensions/cookie/test/unit/test_eviction.js | 249 + .../cookie/test/unit/test_permmanager_cleardata.js | 68 + .../cookie/test/unit/test_permmanager_defaults.js | 295 + .../test/unit/test_permmanager_expiration.js | 82 + .../test/unit/test_permmanager_getAllForURI.js | 78 + .../unit/test_permmanager_getPermissionObject.js | 95 + .../cookie/test/unit/test_permmanager_idn.js | 49 + .../unit/test_permmanager_load_invalid_entries.js | 142 + .../test/unit/test_permmanager_local_files.js | 43 + .../cookie/test/unit/test_permmanager_matches.js | 183 + .../test/unit/test_permmanager_matchesuri.js | 150 + .../test/unit/test_permmanager_migrate_4-7.js | 207 + .../test_permmanager_migrate_4-7_no_history.js | 226 + .../test/unit/test_permmanager_migrate_5-7a.js | 284 + .../test/unit/test_permmanager_migrate_5-7b.js | 168 + .../test/unit/test_permmanager_migrate_6-7a.js | 284 + .../test/unit/test_permmanager_migrate_6-7b.js | 162 + .../test/unit/test_permmanager_migrate_7-8.js | 246 + .../test/unit/test_permmanager_notifications.js | 140 + .../cookie/test/unit/test_permmanager_removeall.js | 36 + .../test/unit/test_permmanager_removeforapp.js | 99 + .../test/unit/test_permmanager_removepermission.js | 67 + .../test/unit/test_permmanager_removesince.js | 69 + .../test/unit/test_permmanager_subdomains.js | 57 + .../cookie/test/unit/test_schema_2_migration.js | 207 + .../cookie/test/unit/test_schema_3_migration.js | 125 + extensions/cookie/test/unit/xpcshell.ini | 48 + extensions/cookie/test/unit_ipc/test_child.js | 59 + extensions/cookie/test/unit_ipc/test_parent.js | 59 + extensions/cookie/test/unit_ipc/xpcshell.ini | 7 + extensions/gio/moz.build | 13 + extensions/gio/nsGIOProtocolHandler.cpp | 1131 + extensions/moz.build | 7 + extensions/moz.configure | 5 + extensions/permissions/moz.build | 12 + extensions/permissions/nsContentBlocker.cpp | 377 + extensions/permissions/nsContentBlocker.h | 53 + extensions/permissions/nsModuleFactory.cpp | 37 + extensions/pref/autoconfig/moz.build | 9 + extensions/pref/autoconfig/public/moz.build | 13 + .../pref/autoconfig/public/nsIAutoConfig.idl | 26 + .../pref/autoconfig/public/nsIReadConfig.idl | 24 + extensions/pref/autoconfig/src/moz.build | 18 + extensions/pref/autoconfig/src/nsAutoConfig.cpp | 532 + extensions/pref/autoconfig/src/nsAutoConfig.h | 54 + extensions/pref/autoconfig/src/nsConfigFactory.cpp | 41 + .../pref/autoconfig/src/nsJSConfigTriggers.cpp | 138 + extensions/pref/autoconfig/src/nsReadConfig.cpp | 300 + extensions/pref/autoconfig/src/nsReadConfig.h | 41 + extensions/pref/autoconfig/src/prefcalls.js | 230 + .../autoconfig/test/unit/autoconfig-latin1.cfg | 6 + .../pref/autoconfig/test/unit/autoconfig-utf8.cfg | 6 + extensions/pref/autoconfig/test/unit/autoconfig.js | 4 + .../test/unit/test_autoconfig_nonascii.js | 97 + extensions/pref/autoconfig/test/unit/xpcshell.ini | 10 + extensions/pref/moz.build | 8 + .../hunspell/glue/PRemoteSpellcheckEngine.ipdl | 22 + .../hunspell/glue/RemoteSpellCheckEngineChild.cpp | 21 + .../hunspell/glue/RemoteSpellCheckEngineChild.h | 27 + .../hunspell/glue/RemoteSpellCheckEngineParent.cpp | 63 + .../hunspell/glue/RemoteSpellCheckEngineParent.h | 39 + .../hunspell/glue/hunspell_alloc_hooks.h | 58 + .../hunspell/glue/hunspell_fopen_hooks.h | 87 + extensions/spellcheck/hunspell/glue/moz.build | 39 + .../spellcheck/hunspell/glue/mozHunspell.cpp | 623 + extensions/spellcheck/hunspell/glue/mozHunspell.h | 125 + .../hunspell/glue/mozHunspellAllocator.h | 16 + .../hunspell/glue/mozHunspellDirProvider.cpp | 140 + .../hunspell/glue/mozHunspellDirProvider.h | 77 + extensions/spellcheck/hunspell/moz.build | 12 + extensions/spellcheck/hunspell/src/README | 21 + extensions/spellcheck/hunspell/src/README.mozilla | 2 + extensions/spellcheck/hunspell/src/affentry.cxx | 1068 + extensions/spellcheck/hunspell/src/affentry.hxx | 232 + extensions/spellcheck/hunspell/src/affixmgr.cxx | 5117 ++ extensions/spellcheck/hunspell/src/affixmgr.hxx | 390 + extensions/spellcheck/hunspell/src/atypes.hxx | 145 + extensions/spellcheck/hunspell/src/baseaffix.hxx | 77 + extensions/spellcheck/hunspell/src/csutil.cxx | 2850 + extensions/spellcheck/hunspell/src/csutil.hxx | 325 + extensions/spellcheck/hunspell/src/filemgr.cxx | 120 + extensions/spellcheck/hunspell/src/filemgr.hxx | 101 + extensions/spellcheck/hunspell/src/hashmgr.cxx | 1147 + extensions/spellcheck/hunspell/src/hashmgr.hxx | 149 + extensions/spellcheck/hunspell/src/htypes.hxx | 71 + extensions/spellcheck/hunspell/src/hunspell.cxx | 1895 + extensions/spellcheck/hunspell/src/hunspell.h | 162 + extensions/spellcheck/hunspell/src/hunspell.hxx | 258 + extensions/spellcheck/hunspell/src/hunvisapi.h | 18 + extensions/spellcheck/hunspell/src/hunzip.cxx | 263 + extensions/spellcheck/hunspell/src/hunzip.hxx | 87 + extensions/spellcheck/hunspell/src/langnum.hxx | 78 + .../spellcheck/hunspell/src/license.hunspell | 61 + extensions/spellcheck/hunspell/src/license.myspell | 61 + extensions/spellcheck/hunspell/src/moz.build | 38 + extensions/spellcheck/hunspell/src/patches/1322666 | 24 + extensions/spellcheck/hunspell/src/phonet.cxx | 274 + extensions/spellcheck/hunspell/src/phonet.hxx | 52 + extensions/spellcheck/hunspell/src/replist.cxx | 193 + extensions/spellcheck/hunspell/src/replist.hxx | 107 + extensions/spellcheck/hunspell/src/suggestmgr.cxx | 2192 + extensions/spellcheck/hunspell/src/suggestmgr.hxx | 198 + extensions/spellcheck/hunspell/src/w_char.hxx | 75 + .../hunspell/tests/unit/data/1463589-utf.aff | 4 + .../hunspell/tests/unit/data/1463589-utf.dic | 2 + .../hunspell/tests/unit/data/1463589-utf.sug | 5 + .../hunspell/tests/unit/data/1463589-utf.test | 4 + .../hunspell/tests/unit/data/1463589-utf.wrong | 5 + .../hunspell/tests/unit/data/1463589.aff | 3 + .../hunspell/tests/unit/data/1463589.dic | 2 + .../hunspell/tests/unit/data/1463589.sug | 5 + .../hunspell/tests/unit/data/1463589.test | 4 + .../hunspell/tests/unit/data/1463589.wrong | 5 + .../hunspell/tests/unit/data/1592880.aff | 20 + .../hunspell/tests/unit/data/1592880.dic | 4 + .../hunspell/tests/unit/data/1592880.good | 3 + .../hunspell/tests/unit/data/1592880.test | 4 + .../hunspell/tests/unit/data/1695964.aff | 10 + .../hunspell/tests/unit/data/1695964.dic | 3 + .../hunspell/tests/unit/data/1695964.sug | 3 + .../hunspell/tests/unit/data/1695964.test | 4 + .../hunspell/tests/unit/data/1695964.wrong | 3 + .../hunspell/tests/unit/data/1706659.aff | 13 + .../hunspell/tests/unit/data/1706659.dic | 4 + .../hunspell/tests/unit/data/1706659.test | 4 + .../hunspell/tests/unit/data/1706659.wrong | 3 + .../hunspell/tests/unit/data/1975530.aff | 6 + .../hunspell/tests/unit/data/1975530.dic | 3 + .../hunspell/tests/unit/data/1975530.good | 3 + .../hunspell/tests/unit/data/1975530.test | 4 + .../hunspell/tests/unit/data/1975530.wrong | 1 + .../hunspell/tests/unit/data/2970240.aff | 5 + .../hunspell/tests/unit/data/2970240.dic | 4 + .../hunspell/tests/unit/data/2970240.good | 1 + .../hunspell/tests/unit/data/2970240.test | 4 + .../hunspell/tests/unit/data/2970240.wrong | 1 + .../hunspell/tests/unit/data/2970242.aff | 4 + .../hunspell/tests/unit/data/2970242.dic | 4 + .../hunspell/tests/unit/data/2970242.good | 5 + .../hunspell/tests/unit/data/2970242.test | 4 + .../hunspell/tests/unit/data/2970242.wrong | 1 + .../hunspell/tests/unit/data/2999225.aff | 6 + .../hunspell/tests/unit/data/2999225.dic | 4 + .../hunspell/tests/unit/data/2999225.good | 2 + .../hunspell/tests/unit/data/2999225.test | 4 + .../spellcheck/hunspell/tests/unit/data/IJ.aff | 8 + .../spellcheck/hunspell/tests/unit/data/IJ.dic | 3 + .../spellcheck/hunspell/tests/unit/data/IJ.good | 2 + .../spellcheck/hunspell/tests/unit/data/IJ.sug | 1 + .../spellcheck/hunspell/tests/unit/data/IJ.test | 4 + .../spellcheck/hunspell/tests/unit/data/IJ.wrong | 1 + .../hunspell/tests/unit/data/Makefile.am | 693 + .../hunspell/tests/unit/data/Makefile.in | 1416 + .../hunspell/tests/unit/data/affixes.aff | 7 + .../hunspell/tests/unit/data/affixes.dic | 4 + .../hunspell/tests/unit/data/affixes.good | 7 + .../hunspell/tests/unit/data/affixes.test | 4 + .../spellcheck/hunspell/tests/unit/data/alias.aff | 12 + .../spellcheck/hunspell/tests/unit/data/alias.dic | 2 + .../spellcheck/hunspell/tests/unit/data/alias.good | 4 + .../spellcheck/hunspell/tests/unit/data/alias.test | 4 + .../spellcheck/hunspell/tests/unit/data/alias2.aff | 17 + .../spellcheck/hunspell/tests/unit/data/alias2.dic | 2 + .../hunspell/tests/unit/data/alias2.good | 4 + .../hunspell/tests/unit/data/alias2.morph | 12 + .../hunspell/tests/unit/data/alias2.test | 4 + .../spellcheck/hunspell/tests/unit/data/alias3.aff | 18 + .../spellcheck/hunspell/tests/unit/data/alias3.dic | 2 + .../hunspell/tests/unit/data/alias3.good | 4 + .../hunspell/tests/unit/data/alias3.morph | 8 + .../hunspell/tests/unit/data/alias3.test | 4 + .../hunspell/tests/unit/data/allcaps-utf.aff | 6 + .../hunspell/tests/unit/data/allcaps-utf.dic | 3 + .../hunspell/tests/unit/data/allcaps-utf.good | 4 + .../hunspell/tests/unit/data/allcaps-utf.sug | 3 + .../hunspell/tests/unit/data/allcaps-utf.test | 4 + .../hunspell/tests/unit/data/allcaps-utf.wrong | 3 + .../hunspell/tests/unit/data/allcaps.aff | 5 + .../hunspell/tests/unit/data/allcaps.dic | 3 + .../hunspell/tests/unit/data/allcaps.good | 4 + .../hunspell/tests/unit/data/allcaps.sug | 3 + .../hunspell/tests/unit/data/allcaps.test | 4 + .../hunspell/tests/unit/data/allcaps.wrong | 3 + .../hunspell/tests/unit/data/allcaps2.aff | 6 + .../hunspell/tests/unit/data/allcaps2.dic | 4 + .../hunspell/tests/unit/data/allcaps2.good | 4 + .../hunspell/tests/unit/data/allcaps2.sug | 2 + .../hunspell/tests/unit/data/allcaps2.test | 4 + .../hunspell/tests/unit/data/allcaps2.wrong | 2 + .../hunspell/tests/unit/data/allcaps3.aff | 10 + .../hunspell/tests/unit/data/allcaps3.dic | 7 + .../hunspell/tests/unit/data/allcaps3.good | 13 + .../hunspell/tests/unit/data/allcaps3.test | 4 + .../hunspell/tests/unit/data/allcaps3.wrong | 4 + .../spellcheck/hunspell/tests/unit/data/arabic.aff | 6 + .../spellcheck/hunspell/tests/unit/data/arabic.dic | 2 + .../hunspell/tests/unit/data/arabic.test | 4 + .../hunspell/tests/unit/data/arabic.wrong | 1 + .../hunspell/tests/unit/data/base-utf.aff | 198 + .../hunspell/tests/unit/data/base-utf.dic | 29 + .../hunspell/tests/unit/data/base-utf.good | 27 + .../hunspell/tests/unit/data/base-utf.sug | 11 + .../hunspell/tests/unit/data/base-utf.test | 4 + .../hunspell/tests/unit/data/base-utf.wrong | 11 + .../spellcheck/hunspell/tests/unit/data/base.aff | 192 + .../spellcheck/hunspell/tests/unit/data/base.dic | 29 + .../spellcheck/hunspell/tests/unit/data/base.good | 27 + .../spellcheck/hunspell/tests/unit/data/base.sug | 11 + .../spellcheck/hunspell/tests/unit/data/base.test | 4 + .../spellcheck/hunspell/tests/unit/data/base.wrong | 11 + .../spellcheck/hunspell/tests/unit/data/break.aff | 8 + .../spellcheck/hunspell/tests/unit/data/break.dic | 4 + .../spellcheck/hunspell/tests/unit/data/break.good | 7 + .../spellcheck/hunspell/tests/unit/data/break.test | 4 + .../hunspell/tests/unit/data/break.wrong | 12 + .../hunspell/tests/unit/data/breakdefault.aff | 6 + .../hunspell/tests/unit/data/breakdefault.dic | 6 + .../hunspell/tests/unit/data/breakdefault.good | 7 + .../hunspell/tests/unit/data/breakdefault.sug | 3 + .../hunspell/tests/unit/data/breakdefault.test | 4 + .../hunspell/tests/unit/data/breakdefault.wrong | 3 + .../hunspell/tests/unit/data/breakoff.aff | 7 + .../hunspell/tests/unit/data/breakoff.dic | 6 + .../hunspell/tests/unit/data/breakoff.good | 3 + .../hunspell/tests/unit/data/breakoff.test | 4 + .../hunspell/tests/unit/data/breakoff.wrong | 5 + .../hunspell/tests/unit/data/checkcompoundcase.aff | 3 + .../hunspell/tests/unit/data/checkcompoundcase.dic | 5 + .../tests/unit/data/checkcompoundcase.good | 5 + .../tests/unit/data/checkcompoundcase.test | 4 + .../tests/unit/data/checkcompoundcase.wrong | 3 + .../tests/unit/data/checkcompoundcase2.aff | 3 + .../tests/unit/data/checkcompoundcase2.dic | 3 + .../tests/unit/data/checkcompoundcase2.good | 2 + .../tests/unit/data/checkcompoundcase2.test | 4 + .../tests/unit/data/checkcompoundcase2.wrong | 1 + .../tests/unit/data/checkcompoundcaseutf.aff | 3 + .../tests/unit/data/checkcompoundcaseutf.dic | 3 + .../tests/unit/data/checkcompoundcaseutf.good | 2 + .../tests/unit/data/checkcompoundcaseutf.test | 4 + .../tests/unit/data/checkcompoundcaseutf.wrong | 1 + .../hunspell/tests/unit/data/checkcompounddup.aff | 3 + .../hunspell/tests/unit/data/checkcompounddup.dic | 3 + .../hunspell/tests/unit/data/checkcompounddup.good | 5 + .../hunspell/tests/unit/data/checkcompounddup.test | 4 + .../tests/unit/data/checkcompounddup.wrong | 3 + .../tests/unit/data/checkcompoundpattern.aff | 5 + .../tests/unit/data/checkcompoundpattern.dic | 5 + .../tests/unit/data/checkcompoundpattern.good | 2 + .../tests/unit/data/checkcompoundpattern.test | 4 + .../tests/unit/data/checkcompoundpattern.wrong | 4 + .../tests/unit/data/checkcompoundpattern2.aff | 7 + .../tests/unit/data/checkcompoundpattern2.dic | 3 + .../tests/unit/data/checkcompoundpattern2.good | 3 + .../tests/unit/data/checkcompoundpattern2.test | 4 + .../tests/unit/data/checkcompoundpattern2.wrong | 1 + .../tests/unit/data/checkcompoundpattern3.aff | 6 + .../tests/unit/data/checkcompoundpattern3.dic | 5 + .../tests/unit/data/checkcompoundpattern3.good | 9 + .../tests/unit/data/checkcompoundpattern3.test | 4 + .../tests/unit/data/checkcompoundpattern3.wrong | 8 + .../tests/unit/data/checkcompoundpattern4.aff | 8 + .../tests/unit/data/checkcompoundpattern4.dic | 6 + .../tests/unit/data/checkcompoundpattern4.good | 2 + .../tests/unit/data/checkcompoundpattern4.test | 4 + .../tests/unit/data/checkcompoundpattern4.wrong | 2 + .../hunspell/tests/unit/data/checkcompoundrep.aff | 8 + .../hunspell/tests/unit/data/checkcompoundrep.dic | 5 + .../hunspell/tests/unit/data/checkcompoundrep.good | 2 + .../hunspell/tests/unit/data/checkcompoundrep.test | 4 + .../tests/unit/data/checkcompoundrep.wrong | 3 + .../tests/unit/data/checkcompoundtriple.aff | 3 + .../tests/unit/data/checkcompoundtriple.dic | 5 + .../tests/unit/data/checkcompoundtriple.good | 6 + .../tests/unit/data/checkcompoundtriple.test | 4 + .../tests/unit/data/checkcompoundtriple.wrong | 2 + .../hunspell/tests/unit/data/checksharps.aff | 4 + .../hunspell/tests/unit/data/checksharps.dic | 7 + .../hunspell/tests/unit/data/checksharps.good | 13 + .../hunspell/tests/unit/data/checksharps.sug | 1 + .../hunspell/tests/unit/data/checksharps.test | 4 + .../hunspell/tests/unit/data/checksharps.wrong | 1 + .../hunspell/tests/unit/data/checksharpsutf.aff | 5 + .../hunspell/tests/unit/data/checksharpsutf.dic | 7 + .../hunspell/tests/unit/data/checksharpsutf.good | 13 + .../hunspell/tests/unit/data/checksharpsutf.sug | 1 + .../hunspell/tests/unit/data/checksharpsutf.test | 4 + .../hunspell/tests/unit/data/checksharpsutf.wrong | 1 + .../hunspell/tests/unit/data/circumfix.aff | 16 + .../hunspell/tests/unit/data/circumfix.dic | 2 + .../hunspell/tests/unit/data/circumfix.good | 4 + .../hunspell/tests/unit/data/circumfix.morph | 12 + .../hunspell/tests/unit/data/circumfix.test | 4 + .../hunspell/tests/unit/data/circumfix.wrong | 2 + .../hunspell/tests/unit/data/colons-in-words.aff | 3 + .../hunspell/tests/unit/data/colons-in-words.dic | 4 + .../hunspell/tests/unit/data/colons-in-words.test | 4 + .../hunspell/tests/unit/data/complexprefixes.aff | 9 + .../hunspell/tests/unit/data/complexprefixes.dic | 3 + .../hunspell/tests/unit/data/complexprefixes.good | 3 + .../hunspell/tests/unit/data/complexprefixes.test | 4 + .../hunspell/tests/unit/data/complexprefixes.wrong | 2 + .../hunspell/tests/unit/data/complexprefixes2.aff | 12 + .../hunspell/tests/unit/data/complexprefixes2.dic | 3 + .../hunspell/tests/unit/data/complexprefixes2.good | 4 + .../hunspell/tests/unit/data/complexprefixes2.test | 4 + .../tests/unit/data/complexprefixesutf.aff | 12 + .../tests/unit/data/complexprefixesutf.dic | 2 + .../tests/unit/data/complexprefixesutf.good | 3 + .../tests/unit/data/complexprefixesutf.test | 4 + .../tests/unit/data/complexprefixesutf.wrong | 2 + .../hunspell/tests/unit/data/compoundaffix.aff | 7 + .../hunspell/tests/unit/data/compoundaffix.dic | 3 + .../hunspell/tests/unit/data/compoundaffix.good | 6 + .../hunspell/tests/unit/data/compoundaffix.test | 4 + .../hunspell/tests/unit/data/compoundaffix.wrong | 3 + .../hunspell/tests/unit/data/compoundaffix2.aff | 8 + .../hunspell/tests/unit/data/compoundaffix2.dic | 3 + .../hunspell/tests/unit/data/compoundaffix2.good | 8 + .../hunspell/tests/unit/data/compoundaffix2.test | 4 + .../hunspell/tests/unit/data/compoundaffix3.aff | 8 + .../hunspell/tests/unit/data/compoundaffix3.dic | 3 + .../hunspell/tests/unit/data/compoundaffix3.good | 5 + .../hunspell/tests/unit/data/compoundaffix3.test | 4 + .../hunspell/tests/unit/data/compoundaffix3.wrong | 6 + .../hunspell/tests/unit/data/compoundflag.aff | 3 + .../hunspell/tests/unit/data/compoundflag.dic | 5 + .../hunspell/tests/unit/data/compoundflag.good | 3 + .../hunspell/tests/unit/data/compoundflag.test | 4 + .../hunspell/tests/unit/data/compoundflag.wrong | 4 + .../hunspell/tests/unit/data/compoundrule.aff | 3 + .../hunspell/tests/unit/data/compoundrule.dic | 5 + .../hunspell/tests/unit/data/compoundrule.good | 2 + .../hunspell/tests/unit/data/compoundrule.test | 4 + .../hunspell/tests/unit/data/compoundrule.wrong | 39 + .../hunspell/tests/unit/data/compoundrule2.aff | 3 + .../hunspell/tests/unit/data/compoundrule2.dic | 5 + .../hunspell/tests/unit/data/compoundrule2.good | 37 + .../hunspell/tests/unit/data/compoundrule2.test | 4 + .../hunspell/tests/unit/data/compoundrule2.wrong | 8 + .../hunspell/tests/unit/data/compoundrule3.aff | 3 + .../hunspell/tests/unit/data/compoundrule3.dic | 5 + .../hunspell/tests/unit/data/compoundrule3.good | 7 + .../hunspell/tests/unit/data/compoundrule3.test | 4 + .../hunspell/tests/unit/data/compoundrule3.wrong | 41 + .../hunspell/tests/unit/data/compoundrule4.aff | 7 + .../hunspell/tests/unit/data/compoundrule4.dic | 24 + .../hunspell/tests/unit/data/compoundrule4.good | 29 + .../hunspell/tests/unit/data/compoundrule4.test | 6 + .../hunspell/tests/unit/data/compoundrule4.wrong | 5 + .../hunspell/tests/unit/data/compoundrule5.aff | 7 + .../hunspell/tests/unit/data/compoundrule5.dic | 14 + .../hunspell/tests/unit/data/compoundrule5.good | 7 + .../hunspell/tests/unit/data/compoundrule5.morph | 21 + .../hunspell/tests/unit/data/compoundrule5.test | 4 + .../hunspell/tests/unit/data/compoundrule5.wrong | 1 + .../hunspell/tests/unit/data/compoundrule6.aff | 4 + .../hunspell/tests/unit/data/compoundrule6.dic | 5 + .../hunspell/tests/unit/data/compoundrule6.good | 4 + .../hunspell/tests/unit/data/compoundrule6.test | 4 + .../hunspell/tests/unit/data/compoundrule6.wrong | 4 + .../hunspell/tests/unit/data/compoundrule7.aff | 8 + .../hunspell/tests/unit/data/compoundrule7.dic | 24 + .../hunspell/tests/unit/data/compoundrule7.good | 29 + .../hunspell/tests/unit/data/compoundrule7.test | 6 + .../hunspell/tests/unit/data/compoundrule7.wrong | 5 + .../hunspell/tests/unit/data/compoundrule8.aff | 8 + .../hunspell/tests/unit/data/compoundrule8.dic | 24 + .../hunspell/tests/unit/data/compoundrule8.good | 29 + .../hunspell/tests/unit/data/compoundrule8.test | 6 + .../hunspell/tests/unit/data/compoundrule8.wrong | 5 + .../hunspell/tests/unit/data/condition-utf.aff | 42 + .../hunspell/tests/unit/data/condition-utf.dic | 2 + .../hunspell/tests/unit/data/condition-utf.good | 19 + .../hunspell/tests/unit/data/condition-utf.test | 4 + .../hunspell/tests/unit/data/condition-utf.wrong | 18 + .../hunspell/tests/unit/data/condition.aff | 62 + .../hunspell/tests/unit/data/condition.dic | 6 + .../hunspell/tests/unit/data/condition.good | 26 + .../hunspell/tests/unit/data/condition.test | 4 + .../hunspell/tests/unit/data/condition.wrong | 21 + .../hunspell/tests/unit/data/conditionalprefix.aff | 11 + .../hunspell/tests/unit/data/conditionalprefix.dic | 3 + .../tests/unit/data/conditionalprefix.good | 6 + .../tests/unit/data/conditionalprefix.morph | 20 + .../tests/unit/data/conditionalprefix.test | 4 + .../tests/unit/data/conditionalprefix.wrong | 2 + .../hunspell/tests/unit/data/digits-in-words.aff | 9 + .../hunspell/tests/unit/data/digits-in-words.dic | 12 + .../hunspell/tests/unit/data/digits-in-words.test | 4 + .../hunspell/tests/unit/data/digits-in-words.wrong | 1 + .../hunspell/tests/unit/data/encoding.aff | 1 + .../hunspell/tests/unit/data/encoding.dic | 3 + .../hunspell/tests/unit/data/encoding.good | 4 + .../hunspell/tests/unit/data/encoding.test | 4 + .../spellcheck/hunspell/tests/unit/data/flag.aff | 13 + .../spellcheck/hunspell/tests/unit/data/flag.dic | 2 + .../spellcheck/hunspell/tests/unit/data/flag.good | 8 + .../spellcheck/hunspell/tests/unit/data/flag.test | 4 + .../hunspell/tests/unit/data/flaglong.aff | 14 + .../hunspell/tests/unit/data/flaglong.dic | 2 + .../hunspell/tests/unit/data/flaglong.good | 8 + .../hunspell/tests/unit/data/flaglong.test | 4 + .../hunspell/tests/unit/data/flagnum.aff | 14 + .../hunspell/tests/unit/data/flagnum.dic | 2 + .../hunspell/tests/unit/data/flagnum.good | 8 + .../hunspell/tests/unit/data/flagnum.test | 4 + .../hunspell/tests/unit/data/flagutf8.aff | 15 + .../hunspell/tests/unit/data/flagutf8.dic | 2 + .../hunspell/tests/unit/data/flagutf8.good | 8 + .../hunspell/tests/unit/data/flagutf8.test | 4 + .../hunspell/tests/unit/data/fogemorpheme.aff | 12 + .../hunspell/tests/unit/data/fogemorpheme.dic | 3 + .../hunspell/tests/unit/data/fogemorpheme.good | 3 + .../hunspell/tests/unit/data/fogemorpheme.test | 4 + .../hunspell/tests/unit/data/fogemorpheme.wrong | 3 + .../hunspell/tests/unit/data/forbiddenword.aff | 11 + .../hunspell/tests/unit/data/forbiddenword.dic | 8 + .../hunspell/tests/unit/data/forbiddenword.good | 3 + .../hunspell/tests/unit/data/forbiddenword.test | 4 + .../hunspell/tests/unit/data/forbiddenword.wrong | 4 + .../hunspell/tests/unit/data/forceucase.aff | 4 + .../hunspell/tests/unit/data/forceucase.dic | 4 + .../hunspell/tests/unit/data/forceucase.good | 7 + .../hunspell/tests/unit/data/forceucase.sug | 2 + .../hunspell/tests/unit/data/forceucase.test | 4 + .../hunspell/tests/unit/data/forceucase.wrong | 2 + .../hunspell/tests/unit/data/fullstrip.aff | 15 + .../hunspell/tests/unit/data/fullstrip.dic | 4 + .../hunspell/tests/unit/data/fullstrip.good | 9 + .../hunspell/tests/unit/data/fullstrip.test | 4 + .../hunspell/tests/unit/data/germancompounding.aff | 91 + .../hunspell/tests/unit/data/germancompounding.dic | 5 + .../tests/unit/data/germancompounding.good | 20 + .../tests/unit/data/germancompounding.test | 4 + .../tests/unit/data/germancompounding.wrong | 50 + .../tests/unit/data/germancompoundingold.aff | 96 + .../tests/unit/data/germancompoundingold.dic | 5 + .../tests/unit/data/germancompoundingold.good | 14 + .../tests/unit/data/germancompoundingold.test | 4 + .../tests/unit/data/germancompoundingold.wrong | 50 + .../spellcheck/hunspell/tests/unit/data/i35725.aff | 203 + .../spellcheck/hunspell/tests/unit/data/i35725.dic | 15 + .../hunspell/tests/unit/data/i35725.good | 1 + .../spellcheck/hunspell/tests/unit/data/i35725.sug | 10 + .../hunspell/tests/unit/data/i35725.test | 4 + .../hunspell/tests/unit/data/i35725.wrong | 10 + .../spellcheck/hunspell/tests/unit/data/i53643.aff | 2 + .../spellcheck/hunspell/tests/unit/data/i53643.dic | 2 + .../hunspell/tests/unit/data/i53643.good | 19 + .../hunspell/tests/unit/data/i53643.test | 4 + .../hunspell/tests/unit/data/i53643.wrong | 4 + .../spellcheck/hunspell/tests/unit/data/i54633.aff | 2 + .../spellcheck/hunspell/tests/unit/data/i54633.dic | 2 + .../hunspell/tests/unit/data/i54633.good | 2 + .../spellcheck/hunspell/tests/unit/data/i54633.sug | 2 + .../hunspell/tests/unit/data/i54633.test | 4 + .../hunspell/tests/unit/data/i54633.wrong | 2 + .../spellcheck/hunspell/tests/unit/data/i54980.aff | 2 + .../spellcheck/hunspell/tests/unit/data/i54980.dic | 3 + .../hunspell/tests/unit/data/i54980.good | 4 + .../hunspell/tests/unit/data/i54980.test | 4 + .../spellcheck/hunspell/tests/unit/data/i58202.aff | 4 + .../spellcheck/hunspell/tests/unit/data/i58202.dic | 5 + .../hunspell/tests/unit/data/i58202.good | 10 + .../spellcheck/hunspell/tests/unit/data/i58202.sug | 13 + .../hunspell/tests/unit/data/i58202.test | 4 + .../hunspell/tests/unit/data/i58202.wrong | 13 + .../spellcheck/hunspell/tests/unit/data/i68568.aff | 7 + .../spellcheck/hunspell/tests/unit/data/i68568.dic | 2 + .../hunspell/tests/unit/data/i68568.test | 4 + .../hunspell/tests/unit/data/i68568.wrong | 5 + .../hunspell/tests/unit/data/i68568utf.aff | 8 + .../hunspell/tests/unit/data/i68568utf.dic | 2 + .../hunspell/tests/unit/data/i68568utf.test | 4 + .../hunspell/tests/unit/data/i68568utf.wrong | 5 + .../spellcheck/hunspell/tests/unit/data/iconv.aff | 10 + .../spellcheck/hunspell/tests/unit/data/iconv.dic | 5 + .../spellcheck/hunspell/tests/unit/data/iconv.good | 6 + .../spellcheck/hunspell/tests/unit/data/iconv.test | 4 + .../spellcheck/hunspell/tests/unit/data/ignore.aff | 5 + .../spellcheck/hunspell/tests/unit/data/ignore.dic | 3 + .../hunspell/tests/unit/data/ignore.good | 6 + .../hunspell/tests/unit/data/ignore.test | 4 + .../hunspell/tests/unit/data/ignoreutf.aff | 6 + .../hunspell/tests/unit/data/ignoreutf.dic | 10 + .../hunspell/tests/unit/data/ignoreutf.good | 9 + .../hunspell/tests/unit/data/ignoreutf.test | 4 + .../hunspell/tests/unit/data/keepcase.aff | 3 + .../hunspell/tests/unit/data/keepcase.dic | 5 + .../hunspell/tests/unit/data/keepcase.good | 4 + .../hunspell/tests/unit/data/keepcase.sug | 8 + .../hunspell/tests/unit/data/keepcase.test | 4 + .../hunspell/tests/unit/data/keepcase.wrong | 8 + .../spellcheck/hunspell/tests/unit/data/korean.aff | 1 + .../spellcheck/hunspell/tests/unit/data/korean.dic | 3 + .../hunspell/tests/unit/data/korean.good | 2 + .../hunspell/tests/unit/data/korean.test | 4 + .../hunspell/tests/unit/data/korean.wrong | 1 + .../spellcheck/hunspell/tests/unit/data/map.aff | 9 + .../spellcheck/hunspell/tests/unit/data/map.dic | 4 + .../spellcheck/hunspell/tests/unit/data/map.sug | 3 + .../spellcheck/hunspell/tests/unit/data/map.test | 4 + .../spellcheck/hunspell/tests/unit/data/map.wrong | 3 + .../spellcheck/hunspell/tests/unit/data/maputf.aff | 11 + .../spellcheck/hunspell/tests/unit/data/maputf.dic | 4 + .../spellcheck/hunspell/tests/unit/data/maputf.sug | 3 + .../hunspell/tests/unit/data/maputf.test | 4 + .../hunspell/tests/unit/data/maputf.wrong | 3 + .../spellcheck/hunspell/tests/unit/data/morph.aff | 12 + .../spellcheck/hunspell/tests/unit/data/morph.dic | 10 + .../spellcheck/hunspell/tests/unit/data/morph.good | 26 + .../hunspell/tests/unit/data/morph.morph | 48 + .../spellcheck/hunspell/tests/unit/data/morph.test | 4 + .../hunspell/tests/unit/data/needaffix.aff | 5 + .../hunspell/tests/unit/data/needaffix.dic | 3 + .../hunspell/tests/unit/data/needaffix.good | 3 + .../hunspell/tests/unit/data/needaffix.test | 4 + .../hunspell/tests/unit/data/needaffix.wrong | 1 + .../hunspell/tests/unit/data/needaffix2.aff | 2 + .../hunspell/tests/unit/data/needaffix2.dic | 5 + .../hunspell/tests/unit/data/needaffix2.good | 5 + .../hunspell/tests/unit/data/needaffix2.morph | 13 + .../hunspell/tests/unit/data/needaffix2.test | 4 + .../hunspell/tests/unit/data/needaffix3.aff | 8 + .../hunspell/tests/unit/data/needaffix3.dic | 2 + .../hunspell/tests/unit/data/needaffix3.good | 2 + .../hunspell/tests/unit/data/needaffix3.test | 4 + .../hunspell/tests/unit/data/needaffix3.wrong | 1 + .../hunspell/tests/unit/data/needaffix4.aff | 2 + .../hunspell/tests/unit/data/needaffix4.dic | 5 + .../hunspell/tests/unit/data/needaffix4.good | 5 + .../hunspell/tests/unit/data/needaffix4.test | 4 + .../hunspell/tests/unit/data/needaffix5.aff | 13 + .../hunspell/tests/unit/data/needaffix5.dic | 2 + .../hunspell/tests/unit/data/needaffix5.good | 11 + .../hunspell/tests/unit/data/needaffix5.test | 4 + .../hunspell/tests/unit/data/needaffix5.wrong | 3 + .../hunspell/tests/unit/data/ngram-utf-fix.aff | 21 + .../hunspell/tests/unit/data/ngram-utf-fix.dic | 2 + .../hunspell/tests/unit/data/ngram-utf-fix.good | 1 + .../hunspell/tests/unit/data/ngram-utf-fix.sug | 2 + .../hunspell/tests/unit/data/ngram-utf-fix.test | 4 + .../hunspell/tests/unit/data/ngram-utf-fix.wrong | 2 + .../hunspell/tests/unit/data/nosuggest.aff | 5 + .../hunspell/tests/unit/data/nosuggest.dic | 3 + .../hunspell/tests/unit/data/nosuggest.good | 3 + .../hunspell/tests/unit/data/nosuggest.sug | 0 .../hunspell/tests/unit/data/nosuggest.test | 4 + .../hunspell/tests/unit/data/nosuggest.wrong | 3 + .../spellcheck/hunspell/tests/unit/data/oconv.aff | 12 + .../spellcheck/hunspell/tests/unit/data/oconv.dic | 4 + .../spellcheck/hunspell/tests/unit/data/oconv.good | 2 + .../spellcheck/hunspell/tests/unit/data/oconv.sug | 3 + .../spellcheck/hunspell/tests/unit/data/oconv.test | 4 + .../hunspell/tests/unit/data/oconv.wrong | 3 + .../hunspell/tests/unit/data/onlyincompound.aff | 5 + .../hunspell/tests/unit/data/onlyincompound.dic | 3 + .../hunspell/tests/unit/data/onlyincompound.good | 4 + .../hunspell/tests/unit/data/onlyincompound.sug | 0 .../hunspell/tests/unit/data/onlyincompound.test | 4 + .../hunspell/tests/unit/data/onlyincompound.wrong | 2 + .../hunspell/tests/unit/data/onlyincompound2.aff | 12 + .../hunspell/tests/unit/data/onlyincompound2.dic | 3 + .../hunspell/tests/unit/data/onlyincompound2.good | 3 + .../hunspell/tests/unit/data/onlyincompound2.test | 4 + .../hunspell/tests/unit/data/onlyincompound2.wrong | 3 + .../hunspell/tests/unit/data/opentaal-cpdpat.aff | 13 + .../hunspell/tests/unit/data/opentaal-cpdpat.dic | 4 + .../hunspell/tests/unit/data/opentaal-cpdpat.good | 1 + .../hunspell/tests/unit/data/opentaal-cpdpat.test | 4 + .../hunspell/tests/unit/data/opentaal-cpdpat.wrong | 1 + .../hunspell/tests/unit/data/opentaal-cpdpat2.aff | 27 + .../hunspell/tests/unit/data/opentaal-cpdpat2.dic | 4 + .../hunspell/tests/unit/data/opentaal-cpdpat2.good | 1 + .../hunspell/tests/unit/data/opentaal-cpdpat2.test | 4 + .../tests/unit/data/opentaal-cpdpat2.wrong | 1 + .../tests/unit/data/opentaal-forbiddenword1.aff | 9 + .../tests/unit/data/opentaal-forbiddenword1.dic | 5 + .../tests/unit/data/opentaal-forbiddenword1.good | 3 + .../tests/unit/data/opentaal-forbiddenword1.sug | 1 + .../tests/unit/data/opentaal-forbiddenword1.test | 4 + .../tests/unit/data/opentaal-forbiddenword1.wrong | 5 + .../tests/unit/data/opentaal-forbiddenword2.aff | 7 + .../tests/unit/data/opentaal-forbiddenword2.dic | 5 + .../tests/unit/data/opentaal-forbiddenword2.good | 4 + .../tests/unit/data/opentaal-forbiddenword2.sug | 1 + .../tests/unit/data/opentaal-forbiddenword2.test | 4 + .../tests/unit/data/opentaal-forbiddenword2.wrong | 5 + .../hunspell/tests/unit/data/opentaal-keepcase.aff | 8 + .../hunspell/tests/unit/data/opentaal-keepcase.dic | 7 + .../tests/unit/data/opentaal-keepcase.good | 4 + .../hunspell/tests/unit/data/opentaal-keepcase.sug | 8 + .../tests/unit/data/opentaal-keepcase.test | 4 + .../tests/unit/data/opentaal-keepcase.wrong | 8 + .../spellcheck/hunspell/tests/unit/data/phone.aff | 255 + .../spellcheck/hunspell/tests/unit/data/phone.dic | 11 + .../spellcheck/hunspell/tests/unit/data/phone.sug | 1 + .../spellcheck/hunspell/tests/unit/data/phone.test | 4 + .../hunspell/tests/unit/data/phone.wrong | 1 + .../spellcheck/hunspell/tests/unit/data/rep.aff | 21 + .../spellcheck/hunspell/tests/unit/data/rep.dic | 15 + .../spellcheck/hunspell/tests/unit/data/rep.sug | 8 + .../spellcheck/hunspell/tests/unit/data/rep.test | 4 + .../spellcheck/hunspell/tests/unit/data/rep.wrong | 11 + .../spellcheck/hunspell/tests/unit/data/reputf.aff | 9 + .../spellcheck/hunspell/tests/unit/data/reputf.dic | 2 + .../spellcheck/hunspell/tests/unit/data/reputf.sug | 1 + .../hunspell/tests/unit/data/reputf.test | 4 + .../hunspell/tests/unit/data/reputf.wrong | 1 + .../hunspell/tests/unit/data/simplifiedtriple.aff | 8 + .../hunspell/tests/unit/data/simplifiedtriple.dic | 3 + .../hunspell/tests/unit/data/simplifiedtriple.good | 3 + .../hunspell/tests/unit/data/simplifiedtriple.test | 4 + .../tests/unit/data/simplifiedtriple.wrong | 1 + .../spellcheck/hunspell/tests/unit/data/slash.aff | 4 + .../spellcheck/hunspell/tests/unit/data/slash.dic | 5 + .../spellcheck/hunspell/tests/unit/data/slash.good | 4 + .../spellcheck/hunspell/tests/unit/data/slash.test | 4 + .../spellcheck/hunspell/tests/unit/data/sug.aff | 15 + .../spellcheck/hunspell/tests/unit/data/sug.dic | 11 + .../spellcheck/hunspell/tests/unit/data/sug.sug | 12 + .../spellcheck/hunspell/tests/unit/data/sug.test | 4 + .../spellcheck/hunspell/tests/unit/data/sug.wrong | 12 + .../suggestiontest/List_of_common_misspellings.txt | 4020 ++ .../tests/unit/data/suggestiontest/Makefile.am | 6 + .../tests/unit/data/suggestiontest/Makefile.in | 435 + .../hunspell/tests/unit/data/suggestiontest/README | 16 + .../tests/unit/data/suggestiontest/prepare | 40 + .../hunspell/tests/unit/data/suggestiontest/test | 25 + .../spellcheck/hunspell/tests/unit/data/sugutf.aff | 15 + .../spellcheck/hunspell/tests/unit/data/sugutf.dic | 11 + .../spellcheck/hunspell/tests/unit/data/sugutf.sug | 12 + .../hunspell/tests/unit/data/sugutf.test | 4 + .../hunspell/tests/unit/data/sugutf.wrong | 12 + .../spellcheck/hunspell/tests/unit/data/test.sh | 111 + .../hunspell/tests/unit/data/utf8-bom.aff | 3 + .../hunspell/tests/unit/data/utf8-bom.dic | 2 + .../hunspell/tests/unit/data/utf8-bom.good | 2 + .../hunspell/tests/unit/data/utf8-bom.test | 4 + .../hunspell/tests/unit/data/utf8-bom2.aff | 3 + .../hunspell/tests/unit/data/utf8-bom2.dic | 2 + .../hunspell/tests/unit/data/utf8-bom2.good | 2 + .../hunspell/tests/unit/data/utf8-bom2.test | 4 + .../hunspell/tests/unit/data/utf8-nonbmp.aff | 1 + .../hunspell/tests/unit/data/utf8-nonbmp.dic | 5 + .../hunspell/tests/unit/data/utf8-nonbmp.good | 5 + .../hunspell/tests/unit/data/utf8-nonbmp.sug | 2 + .../hunspell/tests/unit/data/utf8-nonbmp.test | 4 + .../hunspell/tests/unit/data/utf8-nonbmp.wrong | 2 + .../spellcheck/hunspell/tests/unit/data/utf8.aff | 10 + .../spellcheck/hunspell/tests/unit/data/utf8.dic | 3 + .../spellcheck/hunspell/tests/unit/data/utf8.good | 9 + .../spellcheck/hunspell/tests/unit/data/utf8.test | 4 + .../hunspell/tests/unit/data/utfcompound.aff | 3 + .../hunspell/tests/unit/data/utfcompound.dic | 9 + .../hunspell/tests/unit/data/utfcompound.good | 5 + .../hunspell/tests/unit/data/utfcompound.test | 4 + .../hunspell/tests/unit/data/utfcompound.wrong | 7 + .../spellcheck/hunspell/tests/unit/data/warn.aff | 13 + .../spellcheck/hunspell/tests/unit/data/warn.dic | 3 + .../spellcheck/hunspell/tests/unit/data/warn.good | 2 + .../spellcheck/hunspell/tests/unit/data/warn.test | 4 + .../hunspell/tests/unit/data/zeroaffix.aff | 12 + .../hunspell/tests/unit/data/zeroaffix.dic | 3 + .../hunspell/tests/unit/data/zeroaffix.good | 3 + .../hunspell/tests/unit/data/zeroaffix.morph | 13 + .../hunspell/tests/unit/data/zeroaffix.test | 4 + .../hunspell/tests/unit/test_hunspell.js | 220 + .../spellcheck/hunspell/tests/unit/xpcshell.ini | 7 + extensions/spellcheck/idl/moz.build | 15 + .../spellcheck/idl/mozIPersonalDictionary.idl | 77 + .../spellcheck/idl/mozISpellCheckingEngine.idl | 96 + extensions/spellcheck/idl/mozISpellI18NManager.idl | 21 + extensions/spellcheck/idl/mozISpellI18NUtil.idl | 47 + extensions/spellcheck/locales/Makefile.in | 7 + .../locales/en-US/hunspell/README_en_US.txt | 347 + .../locales/en-US/hunspell/README_mozilla.txt | 6 + .../hunspell/dictionary-sources/5-mozilla-added | 5740 ++ .../hunspell/dictionary-sources/5-mozilla-removed | 1 + .../hunspell/dictionary-sources/5-mozilla-specific | 74 + .../en-US/hunspell/dictionary-sources/README | 56 + .../hunspell/dictionary-sources/edit-dictionary | 31 + .../hunspell/dictionary-sources/install-new-dict | 39 + .../hunspell/dictionary-sources/make-new-dict | 69 + .../dictionary-sources/mozilla-specific.txt | 37 + .../orig/README_en_US-custom.txt | 348 + .../dictionary-sources/orig/en_US-custom.aff | 205 + .../dictionary-sources/orig/en_US-custom.dic | 49468 ++++++++++++++++++ .../spellcheck/locales/en-US/hunspell/en-US.aff | 203 + .../spellcheck/locales/en-US/hunspell/en-US.dic | 52349 +++++++++++++++++++ extensions/spellcheck/locales/moz.build | 6 + extensions/spellcheck/moz.build | 10 + extensions/spellcheck/src/moz.build | 34 + extensions/spellcheck/src/mozEnglishWordUtils.cpp | 284 + extensions/spellcheck/src/mozEnglishWordUtils.h | 42 + .../spellcheck/src/mozInlineSpellChecker.cpp | 2043 + extensions/spellcheck/src/mozInlineSpellChecker.h | 272 + .../spellcheck/src/mozInlineSpellWordUtil.cpp | 1085 + extensions/spellcheck/src/mozInlineSpellWordUtil.h | 179 + .../spellcheck/src/mozPersonalDictionary.cpp | 471 + extensions/spellcheck/src/mozPersonalDictionary.h | 83 + extensions/spellcheck/src/mozSpellChecker.cpp | 565 + extensions/spellcheck/src/mozSpellChecker.h | 76 + .../spellcheck/src/mozSpellCheckerFactory.cpp | 73 + extensions/spellcheck/src/mozSpellI18NManager.cpp | 32 + extensions/spellcheck/src/mozSpellI18NManager.h | 30 + .../spellcheck/tests/chrome/base/base_utf.aff | 198 + .../spellcheck/tests/chrome/base/base_utf.dic | 29 + extensions/spellcheck/tests/chrome/chrome.ini | 9 + extensions/spellcheck/tests/chrome/map/maputf.aff | 11 + extensions/spellcheck/tests/chrome/map/maputf.dic | 4 + .../tests/chrome/test_add_remove_dictionaries.xul | 129 + .../tests/mochitest/helper_bug1170484.js | 15 + .../spellcheck/tests/mochitest/mochitest.ini | 6 + .../tests/mochitest/test_bug1170484.html | 56 + extensions/universalchardet/moz.build | 9 + .../universalchardet/src/base/CharDistribution.cpp | 46 + .../universalchardet/src/base/CharDistribution.h | 204 + extensions/universalchardet/src/base/JISFreq.tab | 554 + extensions/universalchardet/src/base/JpCntx.cpp | 198 + extensions/universalchardet/src/base/JpCntx.h | 107 + extensions/universalchardet/src/base/moz.build | 22 + .../universalchardet/src/base/nsCharSetProber.cpp | 92 + .../universalchardet/src/base/nsCharSetProber.h | 42 + .../src/base/nsCodingStateMachine.h | 85 + .../universalchardet/src/base/nsEUCJPProber.cpp | 69 + .../universalchardet/src/base/nsEUCJPProber.h | 43 + .../src/base/nsEscCharsetProber.cpp | 46 + .../universalchardet/src/base/nsEscCharsetProber.h | 32 + extensions/universalchardet/src/base/nsEscSM.cpp | 63 + .../universalchardet/src/base/nsLatin1Prober.cpp | 149 + .../universalchardet/src/base/nsLatin1Prober.h | 36 + .../src/base/nsMBCSGroupProber.cpp | 177 + .../universalchardet/src/base/nsMBCSGroupProber.h | 42 + extensions/universalchardet/src/base/nsMBCSSM.cpp | 188 + extensions/universalchardet/src/base/nsPkgInt.h | 57 + .../universalchardet/src/base/nsSJISProber.cpp | 68 + .../universalchardet/src/base/nsSJISProber.h | 44 + .../universalchardet/src/base/nsUTF8Prober.cpp | 55 + .../universalchardet/src/base/nsUTF8Prober.h | 31 + .../src/base/nsUniversalDetector.cpp | 240 + .../src/base/nsUniversalDetector.h | 44 + extensions/universalchardet/src/moz.build | 8 + extensions/universalchardet/src/xpcom/moz.build | 16 + .../src/xpcom/nsUdetXPCOMWrapper.cpp | 130 + .../src/xpcom/nsUdetXPCOMWrapper.h | 77 + .../src/xpcom/nsUniversalCharDetDll.h | 11 + .../src/xpcom/nsUniversalCharDetModule.cpp | 52 + .../tests/CharsetDetectionTests.js | 94 + .../universalchardet/tests/bug306272_text.html | 9 + .../universalchardet/tests/bug421271_text.html | 5 + .../tests/bug426271_text-euc-jp.html | 11 + .../tests/bug426271_text-utf-8.html | 11 + .../universalchardet/tests/bug431054_text.html | 5 + .../universalchardet/tests/bug547487_text.html | 1 + .../universalchardet/tests/bug620106_text.html | 1045 + .../universalchardet/tests/bug631751be_text.html | Bin 0 -> 354 bytes .../universalchardet/tests/bug631751le_text.html | Bin 0 -> 366 bytes .../universalchardet/tests/bug638318_text.html | Bin 0 -> 1108 bytes extensions/universalchardet/tests/bug811363-1.text | 1 + extensions/universalchardet/tests/bug811363-2.text | 3 + extensions/universalchardet/tests/bug811363-3.text | 3 + extensions/universalchardet/tests/bug811363-4.text | 3 + extensions/universalchardet/tests/bug811363-5.text | 3 + extensions/universalchardet/tests/bug811363-6.text | 3 + extensions/universalchardet/tests/bug811363-7.text | 3 + extensions/universalchardet/tests/bug811363-8.text | 3 + extensions/universalchardet/tests/bug811363-9.text | 2 + .../tests/bug811363-invalid-1.text | 4 + .../tests/bug811363-invalid-2.text | 3 + .../tests/bug811363-invalid-3.text | 2 + .../tests/bug811363-invalid-4.text | 1 + .../tests/bug811363-invalid-5.text | 3 + extensions/universalchardet/tests/chrome.ini | 52 + extensions/universalchardet/tests/moz.build | 8 + .../universalchardet/tests/test_bug306272.html | 31 + .../universalchardet/tests/test_bug421271.html | 37 + .../tests/test_bug426271-euc-jp.html | 31 + .../tests/test_bug426271-utf-8.html | 32 + .../tests/test_bug431054-japanese.html | 30 + .../universalchardet/tests/test_bug431054.html | 34 + .../universalchardet/tests/test_bug547487.html | 36 + .../universalchardet/tests/test_bug631751be.html | 31 + .../universalchardet/tests/test_bug631751le.html | 31 + .../universalchardet/tests/test_bug638318.html | 31 + .../universalchardet/tests/test_bug811363-1-1.html | 30 + .../universalchardet/tests/test_bug811363-1-2.html | 30 + .../universalchardet/tests/test_bug811363-1-3.html | 30 + .../universalchardet/tests/test_bug811363-1-4.html | 30 + .../universalchardet/tests/test_bug811363-1-5.html | 30 + .../universalchardet/tests/test_bug811363-2-1.html | 30 + .../universalchardet/tests/test_bug811363-2-2.html | 30 + .../universalchardet/tests/test_bug811363-2-3.html | 30 + .../universalchardet/tests/test_bug811363-2-4.html | 30 + .../universalchardet/tests/test_bug811363-2-5.html | 30 + .../universalchardet/tests/test_bug811363-2-6.html | 30 + .../universalchardet/tests/test_bug811363-2-7.html | 30 + .../universalchardet/tests/test_bug811363-2-8.html | 30 + .../universalchardet/tests/test_bug811363-2-9.html | 30 + 887 files changed, 169301 insertions(+) create mode 100644 extensions/auth/gssapi.h create mode 100644 extensions/auth/moz.build create mode 100644 extensions/auth/nsAuth.h create mode 100644 extensions/auth/nsAuthFactory.cpp create mode 100644 extensions/auth/nsAuthGSSAPI.cpp create mode 100644 extensions/auth/nsAuthGSSAPI.h create mode 100644 extensions/auth/nsAuthSASL.cpp create mode 100644 extensions/auth/nsAuthSASL.h create mode 100644 extensions/auth/nsAuthSSPI.cpp create mode 100644 extensions/auth/nsAuthSSPI.h create mode 100644 extensions/auth/nsAuthSambaNTLM.cpp create mode 100644 extensions/auth/nsAuthSambaNTLM.h create mode 100644 extensions/auth/nsHttpNegotiateAuth.cpp create mode 100644 extensions/auth/nsHttpNegotiateAuth.h create mode 100644 extensions/build.mk create mode 100755 extensions/confvars.sh create mode 100644 extensions/cookie/moz.build create mode 100644 extensions/cookie/nsCookieModule.cpp create mode 100644 extensions/cookie/nsCookiePermission.cpp create mode 100644 extensions/cookie/nsCookiePermission.h create mode 100644 extensions/cookie/nsCookiePromptService.cpp create mode 100644 extensions/cookie/nsCookiePromptService.h create mode 100644 extensions/cookie/nsICookieAcceptDialog.idl create mode 100644 extensions/cookie/nsICookiePromptService.idl create mode 100644 extensions/cookie/nsPermission.cpp create mode 100644 extensions/cookie/nsPermission.h create mode 100644 extensions/cookie/nsPermissionManager.cpp create mode 100644 extensions/cookie/nsPermissionManager.h create mode 100644 extensions/cookie/nsPopupWindowManager.cpp create mode 100644 extensions/cookie/nsPopupWindowManager.h create mode 100644 extensions/cookie/test/beltzner.jpg create mode 100644 extensions/cookie/test/beltzner.jpg^headers^ create mode 100644 extensions/cookie/test/browser.ini create mode 100644 extensions/cookie/test/browser_test_favicon.js create mode 100644 extensions/cookie/test/damonbowling.jpg create mode 100644 extensions/cookie/test/damonbowling.jpg^headers^ create mode 100644 extensions/cookie/test/file_chromecommon.js create mode 100644 extensions/cookie/test/file_domain_hierarchy_inner.html create mode 100644 extensions/cookie/test/file_domain_hierarchy_inner_inner.html create mode 100644 extensions/cookie/test/file_domain_hierarchy_inner_inner_inner.html create mode 100644 extensions/cookie/test/file_domain_inner.html create mode 100644 extensions/cookie/test/file_domain_inner_inner.html create mode 100644 extensions/cookie/test/file_image_inner.html create mode 100644 extensions/cookie/test/file_image_inner_inner.html create mode 100644 extensions/cookie/test/file_loadflags_inner.html create mode 100644 extensions/cookie/test/file_localhost_inner.html create mode 100644 extensions/cookie/test/file_loopback_inner.html create mode 100644 extensions/cookie/test/file_subdomain_inner.html create mode 100644 extensions/cookie/test/file_testcommon.js create mode 100644 extensions/cookie/test/file_testloadflags.js create mode 100644 extensions/cookie/test/file_testloadflags_chromescript.js create mode 100644 extensions/cookie/test/image1.png create mode 100644 extensions/cookie/test/image1.png^headers^ create mode 100644 extensions/cookie/test/image2.png create mode 100644 extensions/cookie/test/image2.png^headers^ create mode 100644 extensions/cookie/test/mochitest.ini create mode 100644 extensions/cookie/test/moz.build create mode 100644 extensions/cookie/test/test1.css create mode 100644 extensions/cookie/test/test1.css^headers^ create mode 100644 extensions/cookie/test/test2.css create mode 100644 extensions/cookie/test/test2.css^headers^ create mode 100644 extensions/cookie/test/test_different_domain_in_hierarchy.html create mode 100644 extensions/cookie/test/test_differentdomain.html create mode 100644 extensions/cookie/test/test_image.html create mode 100644 extensions/cookie/test/test_loadflags.html create mode 100644 extensions/cookie/test/test_same_base_domain.html create mode 100644 extensions/cookie/test/test_same_base_domain_2.html create mode 100644 extensions/cookie/test/test_same_base_domain_3.html create mode 100644 extensions/cookie/test/test_same_base_domain_4.html create mode 100644 extensions/cookie/test/test_same_base_domain_5.html create mode 100644 extensions/cookie/test/test_same_base_domain_6.html create mode 100644 extensions/cookie/test/test_samedomain.html create mode 100644 extensions/cookie/test/unit/cookieprompt.js create mode 100644 extensions/cookie/test/unit/cookieprompt.manifest create mode 100644 extensions/cookie/test/unit/head_cookies.js create mode 100644 extensions/cookie/test/unit/test_bug526789.js create mode 100644 extensions/cookie/test/unit/test_bug650522.js create mode 100644 extensions/cookie/test/unit/test_bug667087.js create mode 100644 extensions/cookie/test/unit/test_cookies_async_failure.js create mode 100644 extensions/cookie/test/unit/test_cookies_persistence.js create mode 100644 extensions/cookie/test/unit/test_cookies_privatebrowsing.js create mode 100644 extensions/cookie/test/unit/test_cookies_profile_close.js create mode 100644 extensions/cookie/test/unit/test_cookies_read.js create mode 100644 extensions/cookie/test/unit/test_cookies_sync_failure.js create mode 100644 extensions/cookie/test/unit/test_cookies_thirdparty.js create mode 100644 extensions/cookie/test/unit/test_cookies_thirdparty_session.js create mode 100644 extensions/cookie/test/unit/test_domain_eviction.js create mode 100644 extensions/cookie/test/unit/test_eviction.js create mode 100644 extensions/cookie/test/unit/test_permmanager_cleardata.js create mode 100644 extensions/cookie/test/unit/test_permmanager_defaults.js create mode 100644 extensions/cookie/test/unit/test_permmanager_expiration.js create mode 100644 extensions/cookie/test/unit/test_permmanager_getAllForURI.js create mode 100644 extensions/cookie/test/unit/test_permmanager_getPermissionObject.js create mode 100644 extensions/cookie/test/unit/test_permmanager_idn.js create mode 100644 extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js create mode 100644 extensions/cookie/test/unit/test_permmanager_local_files.js create mode 100644 extensions/cookie/test/unit/test_permmanager_matches.js create mode 100644 extensions/cookie/test/unit/test_permmanager_matchesuri.js create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_4-7.js create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_6-7b.js create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_7-8.js create mode 100644 extensions/cookie/test/unit/test_permmanager_notifications.js create mode 100644 extensions/cookie/test/unit/test_permmanager_removeall.js create mode 100644 extensions/cookie/test/unit/test_permmanager_removeforapp.js create mode 100644 extensions/cookie/test/unit/test_permmanager_removepermission.js create mode 100644 extensions/cookie/test/unit/test_permmanager_removesince.js create mode 100644 extensions/cookie/test/unit/test_permmanager_subdomains.js create mode 100644 extensions/cookie/test/unit/test_schema_2_migration.js create mode 100644 extensions/cookie/test/unit/test_schema_3_migration.js create mode 100644 extensions/cookie/test/unit/xpcshell.ini create mode 100644 extensions/cookie/test/unit_ipc/test_child.js create mode 100644 extensions/cookie/test/unit_ipc/test_parent.js create mode 100644 extensions/cookie/test/unit_ipc/xpcshell.ini create mode 100644 extensions/gio/moz.build create mode 100644 extensions/gio/nsGIOProtocolHandler.cpp create mode 100644 extensions/moz.build create mode 100644 extensions/moz.configure create mode 100644 extensions/permissions/moz.build create mode 100644 extensions/permissions/nsContentBlocker.cpp create mode 100644 extensions/permissions/nsContentBlocker.h create mode 100644 extensions/permissions/nsModuleFactory.cpp create mode 100644 extensions/pref/autoconfig/moz.build create mode 100644 extensions/pref/autoconfig/public/moz.build create mode 100644 extensions/pref/autoconfig/public/nsIAutoConfig.idl create mode 100644 extensions/pref/autoconfig/public/nsIReadConfig.idl create mode 100644 extensions/pref/autoconfig/src/moz.build create mode 100644 extensions/pref/autoconfig/src/nsAutoConfig.cpp create mode 100644 extensions/pref/autoconfig/src/nsAutoConfig.h create mode 100644 extensions/pref/autoconfig/src/nsConfigFactory.cpp create mode 100644 extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp create mode 100644 extensions/pref/autoconfig/src/nsReadConfig.cpp create mode 100644 extensions/pref/autoconfig/src/nsReadConfig.h create mode 100644 extensions/pref/autoconfig/src/prefcalls.js create mode 100644 extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg create mode 100644 extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg create mode 100644 extensions/pref/autoconfig/test/unit/autoconfig.js create mode 100644 extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js create mode 100644 extensions/pref/autoconfig/test/unit/xpcshell.ini create mode 100644 extensions/pref/moz.build create mode 100644 extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl create mode 100644 extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp create mode 100644 extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h create mode 100644 extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp create mode 100644 extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h create mode 100644 extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h create mode 100644 extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h create mode 100644 extensions/spellcheck/hunspell/glue/moz.build create mode 100644 extensions/spellcheck/hunspell/glue/mozHunspell.cpp create mode 100644 extensions/spellcheck/hunspell/glue/mozHunspell.h create mode 100644 extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h create mode 100644 extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp create mode 100644 extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h create mode 100644 extensions/spellcheck/hunspell/moz.build create mode 100644 extensions/spellcheck/hunspell/src/README create mode 100644 extensions/spellcheck/hunspell/src/README.mozilla create mode 100644 extensions/spellcheck/hunspell/src/affentry.cxx create mode 100644 extensions/spellcheck/hunspell/src/affentry.hxx create mode 100644 extensions/spellcheck/hunspell/src/affixmgr.cxx create mode 100644 extensions/spellcheck/hunspell/src/affixmgr.hxx create mode 100644 extensions/spellcheck/hunspell/src/atypes.hxx create mode 100644 extensions/spellcheck/hunspell/src/baseaffix.hxx create mode 100644 extensions/spellcheck/hunspell/src/csutil.cxx create mode 100644 extensions/spellcheck/hunspell/src/csutil.hxx create mode 100644 extensions/spellcheck/hunspell/src/filemgr.cxx create mode 100644 extensions/spellcheck/hunspell/src/filemgr.hxx create mode 100644 extensions/spellcheck/hunspell/src/hashmgr.cxx create mode 100644 extensions/spellcheck/hunspell/src/hashmgr.hxx create mode 100644 extensions/spellcheck/hunspell/src/htypes.hxx create mode 100644 extensions/spellcheck/hunspell/src/hunspell.cxx create mode 100644 extensions/spellcheck/hunspell/src/hunspell.h create mode 100644 extensions/spellcheck/hunspell/src/hunspell.hxx create mode 100644 extensions/spellcheck/hunspell/src/hunvisapi.h create mode 100644 extensions/spellcheck/hunspell/src/hunzip.cxx create mode 100644 extensions/spellcheck/hunspell/src/hunzip.hxx create mode 100644 extensions/spellcheck/hunspell/src/langnum.hxx create mode 100644 extensions/spellcheck/hunspell/src/license.hunspell create mode 100644 extensions/spellcheck/hunspell/src/license.myspell create mode 100644 extensions/spellcheck/hunspell/src/moz.build create mode 100644 extensions/spellcheck/hunspell/src/patches/1322666 create mode 100644 extensions/spellcheck/hunspell/src/phonet.cxx create mode 100644 extensions/spellcheck/hunspell/src/phonet.hxx create mode 100644 extensions/spellcheck/hunspell/src/replist.cxx create mode 100644 extensions/spellcheck/hunspell/src/replist.hxx create mode 100644 extensions/spellcheck/hunspell/src/suggestmgr.cxx create mode 100644 extensions/spellcheck/hunspell/src/suggestmgr.hxx create mode 100644 extensions/spellcheck/hunspell/src/w_char.hxx create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1463589.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1592880.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1592880.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1592880.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1592880.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1695964.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1695964.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1695964.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1695964.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1695964.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1706659.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1706659.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1706659.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1706659.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1975530.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1975530.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1975530.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1975530.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/1975530.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970240.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970240.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970240.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970240.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970240.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970242.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970242.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970242.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970242.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2970242.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2999225.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2999225.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2999225.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/2999225.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/IJ.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/IJ.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/IJ.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/IJ.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/IJ.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/IJ.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/Makefile.am create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/Makefile.in create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/affixes.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/affixes.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/affixes.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/affixes.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias2.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias3.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias3.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias3.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias3.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/alias3.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps2.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps2.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps3.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps3.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps3.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps3.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/allcaps3.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/arabic.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/arabic.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/arabic.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/arabic.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base-utf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base-utf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base-utf.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base-utf.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base-utf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base-utf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/base.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/break.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/break.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/break.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/break.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/break.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakdefault.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakdefault.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakdefault.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakdefault.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakdefault.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakdefault.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakoff.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakoff.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakoff.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakoff.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/breakoff.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharps.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharps.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharps.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharps.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharps.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharps.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/circumfix.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/circumfix.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/circumfix.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/circumfix.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/circumfix.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/circumfix.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundflag.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundflag.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundflag.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundflag.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundflag.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition-utf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition-utf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition-utf.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition-utf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition-utf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/condition.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/encoding.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/encoding.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/encoding.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/encoding.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flag.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flag.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flag.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flag.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flaglong.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flaglong.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flaglong.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flaglong.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagnum.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagnum.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagnum.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagnum.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagutf8.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagutf8.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagutf8.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/flagutf8.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forceucase.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forceucase.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forceucase.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forceucase.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forceucase.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/forceucase.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fullstrip.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fullstrip.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fullstrip.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/fullstrip.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompounding.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompounding.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompounding.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompounding.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompounding.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i35725.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i35725.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i35725.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i35725.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i35725.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i35725.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i53643.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i53643.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i53643.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i53643.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i53643.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54633.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54633.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54633.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54633.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54633.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54633.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54980.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54980.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54980.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i54980.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i58202.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i58202.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i58202.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i58202.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i58202.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i58202.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568utf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568utf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568utf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/i68568utf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/iconv.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/iconv.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/iconv.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/iconv.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignore.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignore.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignore.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignore.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/keepcase.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/keepcase.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/keepcase.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/keepcase.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/keepcase.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/keepcase.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/korean.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/korean.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/korean.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/korean.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/korean.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/map.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/map.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/map.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/map.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/map.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/maputf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/maputf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/maputf.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/maputf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/maputf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/morph.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/morph.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/morph.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/morph.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/morph.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix2.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix3.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix3.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix3.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix3.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix3.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix4.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix4.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix4.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix4.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix5.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix5.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix5.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix5.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/needaffix5.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/nosuggest.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/nosuggest.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/nosuggest.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/nosuggest.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/nosuggest.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/nosuggest.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/oconv.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/oconv.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/oconv.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/oconv.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/oconv.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/oconv.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/phone.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/phone.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/phone.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/phone.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/phone.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/rep.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/rep.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/rep.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/rep.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/rep.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/reputf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/reputf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/reputf.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/reputf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/reputf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/slash.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/slash.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/slash.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/slash.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sug.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sug.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sug.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sug.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sug.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/List_of_common_misspellings.txt create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.am create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.in create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/README create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/prepare create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sugutf.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sugutf.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sugutf.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sugutf.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/sugutf.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/test.sh create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.sug create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utf8.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utfcompound.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utfcompound.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utfcompound.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utfcompound.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/utfcompound.wrong create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/warn.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/warn.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/warn.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/warn.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.aff create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.dic create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.good create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.morph create mode 100644 extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.test create mode 100644 extensions/spellcheck/hunspell/tests/unit/test_hunspell.js create mode 100644 extensions/spellcheck/hunspell/tests/unit/xpcshell.ini create mode 100644 extensions/spellcheck/idl/moz.build create mode 100644 extensions/spellcheck/idl/mozIPersonalDictionary.idl create mode 100644 extensions/spellcheck/idl/mozISpellCheckingEngine.idl create mode 100644 extensions/spellcheck/idl/mozISpellI18NManager.idl create mode 100644 extensions/spellcheck/idl/mozISpellI18NUtil.idl create mode 100644 extensions/spellcheck/locales/Makefile.in create mode 100644 extensions/spellcheck/locales/en-US/hunspell/README_en_US.txt create mode 100644 extensions/spellcheck/locales/en-US/hunspell/README_mozilla.txt create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-added create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-removed create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-specific create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/README create mode 100755 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/edit-dictionary create mode 100755 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/install-new-dict create mode 100755 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/make-new-dict create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/mozilla-specific.txt create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/README_en_US-custom.txt create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.aff create mode 100644 extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.dic create mode 100644 extensions/spellcheck/locales/en-US/hunspell/en-US.aff create mode 100644 extensions/spellcheck/locales/en-US/hunspell/en-US.dic create mode 100644 extensions/spellcheck/locales/moz.build create mode 100644 extensions/spellcheck/moz.build create mode 100644 extensions/spellcheck/src/moz.build create mode 100644 extensions/spellcheck/src/mozEnglishWordUtils.cpp create mode 100644 extensions/spellcheck/src/mozEnglishWordUtils.h create mode 100644 extensions/spellcheck/src/mozInlineSpellChecker.cpp create mode 100644 extensions/spellcheck/src/mozInlineSpellChecker.h create mode 100644 extensions/spellcheck/src/mozInlineSpellWordUtil.cpp create mode 100644 extensions/spellcheck/src/mozInlineSpellWordUtil.h create mode 100644 extensions/spellcheck/src/mozPersonalDictionary.cpp create mode 100644 extensions/spellcheck/src/mozPersonalDictionary.h create mode 100644 extensions/spellcheck/src/mozSpellChecker.cpp create mode 100644 extensions/spellcheck/src/mozSpellChecker.h create mode 100644 extensions/spellcheck/src/mozSpellCheckerFactory.cpp create mode 100644 extensions/spellcheck/src/mozSpellI18NManager.cpp create mode 100644 extensions/spellcheck/src/mozSpellI18NManager.h create mode 100644 extensions/spellcheck/tests/chrome/base/base_utf.aff create mode 100644 extensions/spellcheck/tests/chrome/base/base_utf.dic create mode 100644 extensions/spellcheck/tests/chrome/chrome.ini create mode 100644 extensions/spellcheck/tests/chrome/map/maputf.aff create mode 100644 extensions/spellcheck/tests/chrome/map/maputf.dic create mode 100644 extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul create mode 100644 extensions/spellcheck/tests/mochitest/helper_bug1170484.js create mode 100644 extensions/spellcheck/tests/mochitest/mochitest.ini create mode 100644 extensions/spellcheck/tests/mochitest/test_bug1170484.html create mode 100644 extensions/universalchardet/moz.build create mode 100644 extensions/universalchardet/src/base/CharDistribution.cpp create mode 100644 extensions/universalchardet/src/base/CharDistribution.h create mode 100644 extensions/universalchardet/src/base/JISFreq.tab create mode 100644 extensions/universalchardet/src/base/JpCntx.cpp create mode 100644 extensions/universalchardet/src/base/JpCntx.h create mode 100644 extensions/universalchardet/src/base/moz.build create mode 100644 extensions/universalchardet/src/base/nsCharSetProber.cpp create mode 100644 extensions/universalchardet/src/base/nsCharSetProber.h create mode 100644 extensions/universalchardet/src/base/nsCodingStateMachine.h create mode 100644 extensions/universalchardet/src/base/nsEUCJPProber.cpp create mode 100644 extensions/universalchardet/src/base/nsEUCJPProber.h create mode 100644 extensions/universalchardet/src/base/nsEscCharsetProber.cpp create mode 100644 extensions/universalchardet/src/base/nsEscCharsetProber.h create mode 100644 extensions/universalchardet/src/base/nsEscSM.cpp create mode 100644 extensions/universalchardet/src/base/nsLatin1Prober.cpp create mode 100644 extensions/universalchardet/src/base/nsLatin1Prober.h create mode 100644 extensions/universalchardet/src/base/nsMBCSGroupProber.cpp create mode 100644 extensions/universalchardet/src/base/nsMBCSGroupProber.h create mode 100644 extensions/universalchardet/src/base/nsMBCSSM.cpp create mode 100644 extensions/universalchardet/src/base/nsPkgInt.h create mode 100644 extensions/universalchardet/src/base/nsSJISProber.cpp create mode 100644 extensions/universalchardet/src/base/nsSJISProber.h create mode 100644 extensions/universalchardet/src/base/nsUTF8Prober.cpp create mode 100644 extensions/universalchardet/src/base/nsUTF8Prober.h create mode 100644 extensions/universalchardet/src/base/nsUniversalDetector.cpp create mode 100644 extensions/universalchardet/src/base/nsUniversalDetector.h create mode 100644 extensions/universalchardet/src/moz.build create mode 100644 extensions/universalchardet/src/xpcom/moz.build create mode 100644 extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.cpp create mode 100644 extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.h create mode 100644 extensions/universalchardet/src/xpcom/nsUniversalCharDetDll.h create mode 100644 extensions/universalchardet/src/xpcom/nsUniversalCharDetModule.cpp create mode 100644 extensions/universalchardet/tests/CharsetDetectionTests.js create mode 100644 extensions/universalchardet/tests/bug306272_text.html create mode 100644 extensions/universalchardet/tests/bug421271_text.html create mode 100644 extensions/universalchardet/tests/bug426271_text-euc-jp.html create mode 100644 extensions/universalchardet/tests/bug426271_text-utf-8.html create mode 100644 extensions/universalchardet/tests/bug431054_text.html create mode 100644 extensions/universalchardet/tests/bug547487_text.html create mode 100644 extensions/universalchardet/tests/bug620106_text.html create mode 100644 extensions/universalchardet/tests/bug631751be_text.html create mode 100644 extensions/universalchardet/tests/bug631751le_text.html create mode 100644 extensions/universalchardet/tests/bug638318_text.html create mode 100644 extensions/universalchardet/tests/bug811363-1.text create mode 100644 extensions/universalchardet/tests/bug811363-2.text create mode 100644 extensions/universalchardet/tests/bug811363-3.text create mode 100644 extensions/universalchardet/tests/bug811363-4.text create mode 100644 extensions/universalchardet/tests/bug811363-5.text create mode 100644 extensions/universalchardet/tests/bug811363-6.text create mode 100644 extensions/universalchardet/tests/bug811363-7.text create mode 100644 extensions/universalchardet/tests/bug811363-8.text create mode 100644 extensions/universalchardet/tests/bug811363-9.text create mode 100644 extensions/universalchardet/tests/bug811363-invalid-1.text create mode 100644 extensions/universalchardet/tests/bug811363-invalid-2.text create mode 100644 extensions/universalchardet/tests/bug811363-invalid-3.text create mode 100644 extensions/universalchardet/tests/bug811363-invalid-4.text create mode 100644 extensions/universalchardet/tests/bug811363-invalid-5.text create mode 100644 extensions/universalchardet/tests/chrome.ini create mode 100644 extensions/universalchardet/tests/moz.build create mode 100644 extensions/universalchardet/tests/test_bug306272.html create mode 100644 extensions/universalchardet/tests/test_bug421271.html create mode 100644 extensions/universalchardet/tests/test_bug426271-euc-jp.html create mode 100644 extensions/universalchardet/tests/test_bug426271-utf-8.html create mode 100644 extensions/universalchardet/tests/test_bug431054-japanese.html create mode 100644 extensions/universalchardet/tests/test_bug431054.html create mode 100644 extensions/universalchardet/tests/test_bug547487.html create mode 100644 extensions/universalchardet/tests/test_bug631751be.html create mode 100644 extensions/universalchardet/tests/test_bug631751le.html create mode 100644 extensions/universalchardet/tests/test_bug638318.html create mode 100644 extensions/universalchardet/tests/test_bug811363-1-1.html create mode 100644 extensions/universalchardet/tests/test_bug811363-1-2.html create mode 100644 extensions/universalchardet/tests/test_bug811363-1-3.html create mode 100644 extensions/universalchardet/tests/test_bug811363-1-4.html create mode 100644 extensions/universalchardet/tests/test_bug811363-1-5.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-1.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-2.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-3.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-4.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-5.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-6.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-7.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-8.html create mode 100644 extensions/universalchardet/tests/test_bug811363-2-9.html (limited to 'extensions') diff --git a/extensions/auth/gssapi.h b/extensions/auth/gssapi.h new file mode 100644 index 000000000..a3ce3d8c5 --- /dev/null +++ b/extensions/auth/gssapi.h @@ -0,0 +1,848 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + ****** END LICENSE BLOCK ***** */ + +#ifndef GSSAPI_H_ +#define GSSAPI_H_ + +/* + * Also define _GSSAPI_H_ as that is what the Kerberos 5 code defines and + * what header files on some systems look for. + */ +#define _GSSAPI_H_ + +/* + * On Mac OS X, Kerberos/Kerberos.h is used to gain access to certain + * system-specific Kerberos functions, but on 10.4, that file also brings + * in other headers that conflict with this one. + */ +#define _GSSAPI_GENERIC_H_ +#define _GSSAPI_KRB5_H_ + +/* + * Define windows specific needed parameters. + */ + +#ifndef GSS_CALLCONV +#if defined(_WIN32) +#define GSS_CALLCONV __stdcall +#define GSS_CALLCONV_C __cdecl +#else +#define GSS_CALLCONV +#define GSS_CALLCONV_C +#endif +#endif /* GSS_CALLCONV */ + +#ifdef GSS_USE_FUNCTION_POINTERS +#ifdef _WIN32 +#undef GSS_CALLCONV +#define GSS_CALLCONV +#define GSS_FUNC(f) (__stdcall *f##_type) +#else +#define GSS_FUNC(f) (*f##_type) +#endif +#define GSS_MAKE_TYPEDEF typedef +#else +#define GSS_FUNC(f) f +#define GSS_MAKE_TYPEDEF +#endif + +/* + * First, include stddef.h to get size_t defined. + */ +#include + +/* + * Configure set the following + */ + +#ifndef SIZEOF_LONG +#undef SIZEOF_LONG +#endif +#ifndef SIZEOF_SHORT +#undef SIZEOF_SHORT +#endif + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#if defined(XP_MACOSX) +# pragma pack(push,2) +#endif + +/* + * If the platform supports the xom.h header file, it should be + * included here. + */ +/* #include */ + + +/* + * Now define the three implementation-dependent types. + */ + +typedef void * gss_name_t ; +typedef void * gss_ctx_id_t ; +typedef void * gss_cred_id_t ; + + +/* + * The following type must be defined as the smallest natural + * unsigned integer supported by the platform that has at least + * 32 bits of precision. + */ + +#if SIZEOF_LONG == 4 +typedef unsigned long gss_uint32; +#elif SIZEOF_SHORT == 4 +typedef unsigned short gss_uint32; +#else +typedef unsigned int gss_uint32; +#endif + +#ifdef OM_STRING + +/* + * We have included the xom.h header file. Verify that OM_uint32 + * is defined correctly. + */ + +#if sizeof(gss_uint32) != sizeof(OM_uint32) +#error Incompatible definition of OM_uint32 from xom.h +#endif + +typedef OM_object_identifier gss_OID_desc, *gss_OID; + +#else /* !OM_STRING */ + +/* + * We can't use X/Open definitions, so roll our own. + */ +typedef gss_uint32 OM_uint32; +typedef struct gss_OID_desc_struct { + OM_uint32 length; + void *elements; +} gss_OID_desc, *gss_OID; + +#endif /* !OM_STRING */ + +typedef struct gss_OID_set_desc_struct { + size_t count; + gss_OID elements; +} gss_OID_set_desc, *gss_OID_set; + + +/* + * For now, define a QOP-type as an OM_uint32 + */ +typedef OM_uint32 gss_qop_t; + +typedef int gss_cred_usage_t; + + +typedef struct gss_buffer_desc_struct { + size_t length; + void *value; +} gss_buffer_desc, *gss_buffer_t; + +typedef struct gss_channel_bindings_struct { + OM_uint32 initiator_addrtype; + gss_buffer_desc initiator_address; + OM_uint32 acceptor_addrtype; + gss_buffer_desc acceptor_address; + gss_buffer_desc application_data; +} *gss_channel_bindings_t; + + +/* + * Flag bits for context-level services. + */ +#define GSS_C_DELEG_FLAG 1 +#define GSS_C_MUTUAL_FLAG 2 +#define GSS_C_REPLAY_FLAG 4 +#define GSS_C_SEQUENCE_FLAG 8 +#define GSS_C_CONF_FLAG 16 +#define GSS_C_INTEG_FLAG 32 +#define GSS_C_ANON_FLAG 64 +#define GSS_C_PROT_READY_FLAG 128 +#define GSS_C_TRANS_FLAG 256 + +/* + * Credential usage options + */ +#define GSS_C_BOTH 0 +#define GSS_C_INITIATE 1 +#define GSS_C_ACCEPT 2 + +/* + * Status code types for gss_display_status + */ +#define GSS_C_GSS_CODE 1 +#define GSS_C_MECH_CODE 2 + +/* + * The constant definitions for channel-bindings address families + */ +#define GSS_C_AF_UNSPEC 0 +#define GSS_C_AF_LOCAL 1 +#define GSS_C_AF_INET 2 +#define GSS_C_AF_IMPLINK 3 +#define GSS_C_AF_PUP 4 +#define GSS_C_AF_CHAOS 5 +#define GSS_C_AF_NS 6 +#define GSS_C_AF_NBS 7 +#define GSS_C_AF_ECMA 8 +#define GSS_C_AF_DATAKIT 9 +#define GSS_C_AF_CCITT 10 +#define GSS_C_AF_SNA 11 +#define GSS_C_AF_DECnet 12 +#define GSS_C_AF_DLI 13 +#define GSS_C_AF_LAT 14 +#define GSS_C_AF_HYLINK 15 +#define GSS_C_AF_APPLETALK 16 +#define GSS_C_AF_BSC 17 +#define GSS_C_AF_DSS 18 +#define GSS_C_AF_OSI 19 +#define GSS_C_AF_X25 21 + +#define GSS_C_AF_NULLADDR 255 + +/* + * Various Null values + */ +#define GSS_C_NO_NAME ((gss_name_t) 0) +#define GSS_C_NO_BUFFER ((gss_buffer_t) 0) +#define GSS_C_NO_OID ((gss_OID) 0) +#define GSS_C_NO_OID_SET ((gss_OID_set) 0) +#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0) +#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0) +#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0) +#define GSS_C_EMPTY_BUFFER {0, nullptr} + +/* + * Some alternate names for a couple of the above + * values. These are defined for V1 compatibility. + */ +#define GSS_C_NULL_OID GSS_C_NO_OID +#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET + +/* + * Define the default Quality of Protection for per-message + * services. Note that an implementation that offers multiple + * levels of QOP may define GSS_C_QOP_DEFAULT to be either zero + * (as done here) to mean "default protection", or to a specific + * explicit QOP value. However, a value of 0 should always be + * interpreted by a GSSAPI implementation as a request for the + * default protection level. + */ +#define GSS_C_QOP_DEFAULT 0 + +/* + * Expiration time of 2^32-1 seconds means infinite lifetime for a + * credential or security context + */ +#define GSS_C_INDEFINITE 0xfffffffful + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x01"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant + * GSS_C_NT_USER_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_USER_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x02"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}. + * The constant GSS_C_NT_MACHINE_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_MACHINE_UID_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x03"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) string_uid_name(3)}. + * The constant GSS_C_NT_STRING_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_STRING_UID_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x02"}, + * corresponding to an object-identifier value of + * {iso(1) org(3) dod(6) internet(1) security(5) + * nametypes(6) gss-host-based-services(2)). The constant + * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point + * to that gss_OID_desc. This is a deprecated OID value, and + * implementations wishing to support hostbased-service names + * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID, + * defined below, to identify such names; + * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym + * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input + * parameter, but should not be emitted by GSSAPI + * implementations + */ +extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x04"}, corresponding to an + * object-identifier value of {iso(1) member-body(2) + * Unites States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4)}. The constant + * GSS_C_NT_HOSTBASED_SERVICE should be initialized + * to point to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_HOSTBASED_SERVICE; + + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\01\x05\x06\x03"}, + * corresponding to an object identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 3(gss-anonymous-name)}. The constant + * and GSS_C_NT_ANONYMOUS should be initialized to point + * to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_ANONYMOUS; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x04"}, + * corresponding to an object-identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 4(gss-api-exported-name)}. The constant + * GSS_C_NT_EXPORT_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_EXPORT_NAME; + +/* Major status codes */ + +#define GSS_S_COMPLETE 0 + +/* + * Some "helper" definitions to make the status code macros obvious. + */ +#define GSS_C_CALLING_ERROR_OFFSET 24 +#define GSS_C_ROUTINE_ERROR_OFFSET 16 +#define GSS_C_SUPPLEMENTARY_OFFSET 0 +#define GSS_C_CALLING_ERROR_MASK 0377ul +#define GSS_C_ROUTINE_ERROR_MASK 0377ul +#define GSS_C_SUPPLEMENTARY_MASK 0177777ul + +/* + * The macros that test status codes for error conditions. + * Note that the GSS_ERROR() macro has changed slightly from + * the V1 GSSAPI so that it now evaluates its argument + * only once. + */ +#define GSS_CALLING_ERROR(x) \ +(x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET)) +#define GSS_ROUTINE_ERROR(x) \ + (x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)) +#define GSS_SUPPLEMENTARY_INFO(x) \ + (x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET)) +#define GSS_ERROR(x) \ + (x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \ + (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))) + +/* + * Now the actual status code definitions + */ + +/* + * Calling errors: + */ +#define GSS_S_CALL_INACCESSIBLE_READ \ + (1ul << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_INACCESSIBLE_WRITE \ + (2ul << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_BAD_STRUCTURE \ + (3ul << GSS_C_CALLING_ERROR_OFFSET) + +/* + * Routine errors: + */ +#define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_MIC GSS_S_BAD_SIG +#define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET) + +/* + * Supplementary info bits: + */ +#define GSS_S_CONTINUE_NEEDED (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) +#define GSS_S_DUPLICATE_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) +#define GSS_S_OLD_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) +#define GSS_S_UNSEQ_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) +#define GSS_S_GAP_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) + +/* + * Finally, function prototypes for the GSS-API routines. + */ + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_acquire_cred) +(OM_uint32 *, /* minor_status */ + const gss_name_t, /* desired_name */ + OM_uint32, /* time_req */ + const gss_OID_set, /* desired_mechs */ + gss_cred_usage_t, /* cred_usage */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 * /* time_rec */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_release_cred) +(OM_uint32 *, /* minor_status */ + gss_cred_id_t * /* cred_handle */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_init_sec_context) +(OM_uint32 *, /* minor_status */ + const gss_cred_id_t, /* initiator_cred_handle */ + gss_ctx_id_t *, /* context_handle */ + const gss_name_t, /* target_name */ + const gss_OID, /* mech_type */ + OM_uint32, /* req_flags */ + OM_uint32, /* time_req */ + const gss_channel_bindings_t, /* input_chan_bindings */ + const gss_buffer_t, /* input_token */ + gss_OID *, /* actual_mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 *, /* ret_flags */ + OM_uint32 * /* time_rec */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_accept_sec_context) +(OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + const gss_cred_id_t, /* acceptor_cred_handle */ + const gss_buffer_t, /* input_token_buffer */ + const gss_channel_bindings_t, /* input_chan_bindings */ + gss_name_t *, /* src_name */ + gss_OID *, /* mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 *, /* ret_flags */ + OM_uint32 *, /* time_rec */ + gss_cred_id_t * /* delegated_cred_handle */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_process_context_token) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + const gss_buffer_t /* token_buffer */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_delete_sec_context) +(OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_buffer_t /* output_token */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_context_time) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + OM_uint32 * /* time_rec */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_get_mic) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + gss_qop_t, /* qop_req */ + const gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + ); + + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_verify_mic) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + const gss_buffer_t, /* message_buffer */ + const gss_buffer_t, /* token_buffer */ + gss_qop_t * /* qop_state */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_wrap) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + gss_qop_t, /* qop_req */ + const gss_buffer_t, /* input_message_buffer */ + int *, /* conf_state */ + gss_buffer_t /* output_message_buffer */ + ); + + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_unwrap) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + const gss_buffer_t, /* input_message_buffer */ + gss_buffer_t, /* output_message_buffer */ + int *, /* conf_state */ + gss_qop_t * /* qop_state */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_display_status) +(OM_uint32 *, /* minor_status */ + OM_uint32, /* status_value */ + int, /* status_type */ + const gss_OID, /* mech_type */ + OM_uint32 *, /* message_context */ + gss_buffer_t /* status_string */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_indicate_mechs) +(OM_uint32 *, /* minor_status */ + gss_OID_set * /* mech_set */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_compare_name) +(OM_uint32 *, /* minor_status */ + const gss_name_t, /* name1 */ + const gss_name_t, /* name2 */ + int * /* name_equal */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_display_name) +(OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_buffer_t, /* output_name_buffer */ + gss_OID * /* output_name_type */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_import_name) +(OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* input_name_buffer */ + const gss_OID, /* input_name_type */ + gss_name_t * /* output_name */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_export_name) +(OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_buffer_t /* exported_name */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_release_name) +(OM_uint32 *, /* minor_status */ + gss_name_t * /* input_name */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_release_buffer) +(OM_uint32 *, /* minor_status */ + gss_buffer_t /* buffer */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_release_oid_set) +(OM_uint32 *, /* minor_status */ + gss_OID_set * /* set */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_inquire_cred) +(OM_uint32 *, /* minor_status */ + const gss_cred_id_t, /* cred_handle */ + gss_name_t *, /* name */ + OM_uint32 *, /* lifetime */ + gss_cred_usage_t *, /* cred_usage */ + gss_OID_set * /* mechanisms */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_inquire_context) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + gss_name_t *, /* src_name */ + gss_name_t *, /* targ_name */ + OM_uint32 *, /* lifetime_rec */ + gss_OID *, /* mech_type */ + OM_uint32 *, /* ctx_flags */ + int *, /* locally_initiated */ + int * /* open */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_wrap_size_limit) +(OM_uint32 *, /* minor_status */ + const gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + gss_qop_t, /* qop_req */ + OM_uint32, /* req_output_size */ + OM_uint32 * /* max_input_size */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_add_cred) +(OM_uint32 *, /* minor_status */ + const gss_cred_id_t, /* input_cred_handle */ + const gss_name_t, /* desired_name */ + const gss_OID, /* desired_mech */ + gss_cred_usage_t, /* cred_usage */ + OM_uint32, /* initiator_time_req */ + OM_uint32, /* acceptor_time_req */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 *, /* initiator_time_rec */ + OM_uint32 * /* acceptor_time_rec */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_inquire_cred_by_mech) +(OM_uint32 *, /* minor_status */ + const gss_cred_id_t, /* cred_handle */ + const gss_OID, /* mech_type */ + gss_name_t *, /* name */ + OM_uint32 *, /* initiator_lifetime */ + OM_uint32 *, /* acceptor_lifetime */ + gss_cred_usage_t * /* cred_usage */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_export_sec_context) +(OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_buffer_t /* interprocess_token */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_import_sec_context) +(OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* interprocess_token */ + gss_ctx_id_t * /* context_handle */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_create_empty_oid_set) +(OM_uint32 *, /* minor_status */ + gss_OID_set * /* oid_set */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_add_oid_set_member) +(OM_uint32 *, /* minor_status */ + const gss_OID, /* member_oid */ + gss_OID_set * /* oid_set */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_test_oid_set_member) +(OM_uint32 *, /* minor_status */ + const gss_OID, /* member */ + const gss_OID_set, /* set */ + int * /* present */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_inquire_names_for_mech) +(OM_uint32 *, /* minor_status */ + const gss_OID, /* mechanism */ + gss_OID_set * /* name_types */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_inquire_mechs_for_name) +(OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_OID_set * /* mech_types */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_canonicalize_name) +(OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + const gss_OID, /* mech_type */ + gss_name_t * /* output_name */ + ); + +GSS_MAKE_TYPEDEF +OM_uint32 +GSS_CALLCONV GSS_FUNC(gss_duplicate_name) +(OM_uint32 *, /* minor_status */ + const gss_name_t, /* src_name */ + gss_name_t * /* dest_name */ + ); + + /* + * The following routines are obsolete variants of gss_get_mic, + * gss_verify_mic, gss_wrap and gss_unwrap. They should be + * provided by GSSAPI V2 implementations for backwards + * compatibility with V1 applications. Distinct entrypoints + * (as opposed to #defines) should be provided, both to allow + * GSSAPI V1 applications to link against GSSAPI V2 implementations, + * and to retain the slight parameter type differences between the + * obsolete versions of these routines and their current forms. + */ + + GSS_MAKE_TYPEDEF + OM_uint32 + GSS_CALLCONV GSS_FUNC(gss_sign) + (OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* qop_req */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + ); + + + GSS_MAKE_TYPEDEF + OM_uint32 + GSS_CALLCONV GSS_FUNC(gss_verify) + (OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t, /* token_buffer */ + int * /* qop_state */ + ); + + GSS_MAKE_TYPEDEF + OM_uint32 + GSS_CALLCONV GSS_FUNC(gss_seal) + (OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + int, /* qop_req */ + gss_buffer_t, /* input_message_buffer */ + int *, /* conf_state */ + gss_buffer_t /* output_message_buffer */ + ); + + + GSS_MAKE_TYPEDEF + OM_uint32 + GSS_CALLCONV GSS_FUNC(gss_unseal) + (OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* input_message_buffer */ + gss_buffer_t, /* output_message_buffer */ + int *, /* conf_state */ + int * /* qop_state */ + ); + + +#if defined(XP_MACOSX) +# pragma pack(pop) +#endif + +EXTERN_C_END + +#endif /* GSSAPI_H_ */ + diff --git a/extensions/auth/moz.build b/extensions/auth/moz.build new file mode 100644 index 000000000..a925fdad0 --- /dev/null +++ b/extensions/auth/moz.build @@ -0,0 +1,27 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'nsAuthFactory.cpp', + 'nsAuthGSSAPI.cpp', +] + +SOURCES += [ + 'nsAuthSASL.cpp', + 'nsHttpNegotiateAuth.cpp', # contains constants whose names conflict with constants in other files +] + +if CONFIG['OS_ARCH'] == 'WINNT': + SOURCES += [ + 'nsAuthSSPI.cpp', + ] + DEFINES['USE_SSPI'] = True +else: + UNIFIED_SOURCES += [ + 'nsAuthSambaNTLM.cpp', + ] + +FINAL_LIBRARY = 'xul' diff --git a/extensions/auth/nsAuth.h b/extensions/auth/nsAuth.h new file mode 100644 index 000000000..a32072cdb --- /dev/null +++ b/extensions/auth/nsAuth.h @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAuth_h__ +#define nsAuth_h__ + +/* types of packages */ +enum pType { + PACKAGE_TYPE_KERBEROS, + PACKAGE_TYPE_NEGOTIATE, + PACKAGE_TYPE_NTLM +}; + +#include "mozilla/Logging.h" + +// +// in order to do logging, the following environment variables need to be set: +// +// set NSPR_LOG_MODULES=negotiateauth:4 +// set NSPR_LOG_FILE=negotiateauth.log +// +extern mozilla::LazyLogModule gNegotiateLog; + +#define LOG(args) MOZ_LOG(gNegotiateLog, mozilla::LogLevel::Debug, args) + +#endif /* !defined( nsAuth_h__ ) */ diff --git a/extensions/auth/nsAuthFactory.cpp b/extensions/auth/nsAuthFactory.cpp new file mode 100644 index 000000000..d026a900b --- /dev/null +++ b/extensions/auth/nsAuthFactory.cpp @@ -0,0 +1,247 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ModuleUtils.h" +#include "nsAuth.h" + +//----------------------------------------------------------------------------- + +#define NS_HTTPNEGOTIATEAUTH_CID \ +{ /* 75c80fd0-accb-432c-af59-ec60668c3990 */ \ + 0x75c80fd0, \ + 0xaccb, \ + 0x432c, \ + {0xaf, 0x59, 0xec, 0x60, 0x66, 0x8c, 0x39, 0x90} \ +} + +#include "nsHttpNegotiateAuth.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpNegotiateAuth) +//----------------------------------------------------------------------------- + +#define NS_NEGOTIATEAUTH_CID \ +{ /* 96ec4163-efc8-407a-8735-007fb26be4e8 */ \ + 0x96ec4163, \ + 0xefc8, \ + 0x407a, \ + {0x87, 0x35, 0x00, 0x7f, 0xb2, 0x6b, 0xe4, 0xe8} \ +} +#define NS_GSSAUTH_CID \ +{ /* dc8e21a0-03e4-11da-8cd6-0800200c9a66 */ \ + 0xdc8e21a0, \ + 0x03e4, \ + 0x11da, \ + {0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \ +} + +#include "nsAuthGSSAPI.h" + +#if defined( USE_SSPI ) +#include "nsAuthSSPI.h" + +static nsresult +nsSysNTLMAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsAuthSSPI *auth = new nsAuthSSPI(PACKAGE_TYPE_NTLM); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(auth); + nsresult rv = auth->QueryInterface(iid, result); + NS_RELEASE(auth); + return rv; +} + +static nsresult +nsKerbSSPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsAuthSSPI *auth = new nsAuthSSPI(PACKAGE_TYPE_KERBEROS); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(auth); + nsresult rv = auth->QueryInterface(iid, result); + NS_RELEASE(auth); + return rv; +} + +#define NS_SYSNTLMAUTH_CID \ +{ /* dc195987-6e9a-47bc-b1fd-ab895d398833 */ \ + 0xdc195987, \ + 0x6e9a, \ + 0x47bc, \ + {0xb1, 0xfd, 0xab, 0x89, 0x5d, 0x39, 0x88, 0x33} \ +} + +#define NS_NEGOTIATEAUTHSSPI_CID \ +{ /* 78d3b0c0-0241-11da-8cd6-0800200c9a66 */ \ + 0x78d3b0c0, \ + 0x0241, \ + 0x11da, \ + {0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \ +} + +#define NS_KERBAUTHSSPI_CID \ +{ /* 8c3a0e20-03e5-11da-8cd6-0800200c9a66 */ \ + 0x8c3a0e20, \ + 0x03e5, \ + 0x11da, \ + {0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \ +} + +#else + +#define NS_SAMBANTLMAUTH_CID \ +{ /* bc54f001-6eb0-4e32-9f49-7e064d8e70ef */ \ + 0xbc54f001, \ + 0x6eb0, \ + 0x4e32, \ + {0x9f, 0x49, 0x7e, 0x06, 0x4d, 0x8e, 0x70, 0xef} \ +} + +#include "nsAuthSambaNTLM.h" +static nsresult +nsSambaNTLMAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + RefPtr auth = new nsAuthSambaNTLM(); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = auth->SpawnNTLMAuthHelper(); + if (NS_FAILED(rv)) { + // Failure here probably means that cached credentials were not available + return rv; + } + + return auth->QueryInterface(iid, result); +} + +#endif + +static nsresult +nsKerbGSSAPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsAuthGSSAPI *auth = new nsAuthGSSAPI(PACKAGE_TYPE_KERBEROS); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(auth); + nsresult rv = auth->QueryInterface(iid, result); + NS_RELEASE(auth); + return rv; +} + +static nsresult +nsGSSAPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsAuthGSSAPI *auth = new nsAuthGSSAPI(PACKAGE_TYPE_NEGOTIATE); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(auth); + nsresult rv = auth->QueryInterface(iid, result); + NS_RELEASE(auth); + return rv; +} + + +#if defined( USE_SSPI ) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAuthSSPI) +#endif + +#define NS_AUTHSASL_CID \ +{ /* 815e42e0-72cc-480f-934b-148e33c228a6 */ \ + 0x815e42e0, \ + 0x72cc, \ + 0x480f, \ + {0x93, 0x4b, 0x14, 0x8e, 0x33, 0xc2, 0x28, 0xa6} \ +} + +#include "nsAuthSASL.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAuthSASL) + +NS_DEFINE_NAMED_CID(NS_GSSAUTH_CID); +NS_DEFINE_NAMED_CID(NS_NEGOTIATEAUTH_CID); +#if defined( USE_SSPI ) +NS_DEFINE_NAMED_CID(NS_NEGOTIATEAUTHSSPI_CID); +NS_DEFINE_NAMED_CID(NS_KERBAUTHSSPI_CID); +NS_DEFINE_NAMED_CID(NS_SYSNTLMAUTH_CID); +#else +NS_DEFINE_NAMED_CID(NS_SAMBANTLMAUTH_CID); +#endif +NS_DEFINE_NAMED_CID(NS_HTTPNEGOTIATEAUTH_CID); +NS_DEFINE_NAMED_CID(NS_AUTHSASL_CID); + + +static const mozilla::Module::CIDEntry kAuthCIDs[] = { + { &kNS_GSSAUTH_CID, false, nullptr, nsKerbGSSAPIAuthConstructor }, + { &kNS_NEGOTIATEAUTH_CID, false, nullptr, nsGSSAPIAuthConstructor }, +#if defined( USE_SSPI ) + { &kNS_NEGOTIATEAUTHSSPI_CID, false, nullptr, nsAuthSSPIConstructor }, + { &kNS_KERBAUTHSSPI_CID, false, nullptr, nsKerbSSPIAuthConstructor }, + { &kNS_SYSNTLMAUTH_CID, false, nullptr, nsSysNTLMAuthConstructor }, +#else + { &kNS_SAMBANTLMAUTH_CID, false, nullptr, nsSambaNTLMAuthConstructor }, +#endif + { &kNS_HTTPNEGOTIATEAUTH_CID, false, nullptr, nsHttpNegotiateAuthConstructor }, + { &kNS_AUTHSASL_CID, false, nullptr, nsAuthSASLConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kAuthContracts[] = { + { NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss", &kNS_GSSAUTH_CID }, + { NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss", &kNS_NEGOTIATEAUTH_CID }, +#if defined( USE_SSPI ) + { NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi", &kNS_NEGOTIATEAUTHSSPI_CID }, + { NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi", &kNS_KERBAUTHSSPI_CID }, + { NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", &kNS_SYSNTLMAUTH_CID }, +#else + { NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", &kNS_SAMBANTLMAUTH_CID }, +#endif + { NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "negotiate", &kNS_HTTPNEGOTIATEAUTH_CID }, + { NS_AUTH_MODULE_CONTRACTID_PREFIX "sasl-gssapi", &kNS_AUTHSASL_CID }, + { nullptr } +}; + +//----------------------------------------------------------------------------- +mozilla::LazyLogModule gNegotiateLog("negotiateauth"); + +// setup nspr logging ... +static nsresult +InitNegotiateAuth() +{ + return NS_OK; +} + +static void +DestroyNegotiateAuth() +{ + nsAuthGSSAPI::Shutdown(); +} + +static const mozilla::Module kAuthModule = { + mozilla::Module::kVersion, + kAuthCIDs, + kAuthContracts, + nullptr, + nullptr, + InitNegotiateAuth, + DestroyNegotiateAuth +}; + +NSMODULE_DEFN(nsAuthModule) = &kAuthModule; diff --git a/extensions/auth/nsAuthGSSAPI.cpp b/extensions/auth/nsAuthGSSAPI.cpp new file mode 100644 index 000000000..f63b30eff --- /dev/null +++ b/extensions/auth/nsAuthGSSAPI.cpp @@ -0,0 +1,603 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// +// GSSAPI Authentication Support Module +// +// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt +// (formerly draft-brezak-spnego-http-04.txt) +// +// Also described here: +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp +// +// + +#include "mozilla/ArrayUtils.h" + +#include "prlink.h" +#include "nsCOMPtr.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIServiceManager.h" +#include "nsNativeCharsetUtils.h" +#include "mozilla/Telemetry.h" + +#include "nsAuthGSSAPI.h" + +#ifdef XP_MACOSX +#include +#endif + +#ifdef XP_MACOSX +typedef KLStatus (*KLCacheHasValidTickets_type)( + KLPrincipal, + KLKerberosVersion, + KLBoolean *, + KLPrincipal *, + char **); +#endif + +#if defined(HAVE_RES_NINIT) +#include +#include +#include +#include +#endif + +using namespace mozilla; + +//----------------------------------------------------------------------------- + +// We define GSS_C_NT_HOSTBASED_SERVICE explicitly since it may be referenced +// by by a different name depending on the implementation of gss but always +// has the same value + +static gss_OID_desc gss_c_nt_hostbased_service = + { 10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04" }; + +static const char kNegotiateAuthGssLib[] = + "network.negotiate-auth.gsslib"; +static const char kNegotiateAuthNativeImp[] = + "network.negotiate-auth.using-native-gsslib"; + +static struct GSSFunction { + const char *str; + PRFuncPtr func; +} gssFuncs[] = { + { "gss_display_status", nullptr }, + { "gss_init_sec_context", nullptr }, + { "gss_indicate_mechs", nullptr }, + { "gss_release_oid_set", nullptr }, + { "gss_delete_sec_context", nullptr }, + { "gss_import_name", nullptr }, + { "gss_release_buffer", nullptr }, + { "gss_release_name", nullptr }, + { "gss_wrap", nullptr }, + { "gss_unwrap", nullptr } +}; + +static bool gssNativeImp = true; +static PRLibrary* gssLibrary = nullptr; + +#define gss_display_status_ptr ((gss_display_status_type)*gssFuncs[0].func) +#define gss_init_sec_context_ptr ((gss_init_sec_context_type)*gssFuncs[1].func) +#define gss_indicate_mechs_ptr ((gss_indicate_mechs_type)*gssFuncs[2].func) +#define gss_release_oid_set_ptr ((gss_release_oid_set_type)*gssFuncs[3].func) +#define gss_delete_sec_context_ptr ((gss_delete_sec_context_type)*gssFuncs[4].func) +#define gss_import_name_ptr ((gss_import_name_type)*gssFuncs[5].func) +#define gss_release_buffer_ptr ((gss_release_buffer_type)*gssFuncs[6].func) +#define gss_release_name_ptr ((gss_release_name_type)*gssFuncs[7].func) +#define gss_wrap_ptr ((gss_wrap_type)*gssFuncs[8].func) +#define gss_unwrap_ptr ((gss_unwrap_type)*gssFuncs[9].func) + +#ifdef XP_MACOSX +static PRFuncPtr KLCacheHasValidTicketsPtr; +#define KLCacheHasValidTickets_ptr \ + ((KLCacheHasValidTickets_type)*KLCacheHasValidTicketsPtr) +#endif + +static nsresult +gssInit() +{ + nsXPIDLCString libPath; + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + prefs->GetCharPref(kNegotiateAuthGssLib, getter_Copies(libPath)); + prefs->GetBoolPref(kNegotiateAuthNativeImp, &gssNativeImp); + } + + PRLibrary *lib = nullptr; + + if (!libPath.IsEmpty()) { + LOG(("Attempting to load user specified library [%s]\n", libPath.get())); + gssNativeImp = false; + lib = PR_LoadLibrary(libPath.get()); + } + else { +#ifdef XP_WIN + char *libName = PR_GetLibraryName(nullptr, "gssapi32"); + if (libName) { + lib = PR_LoadLibrary("gssapi32"); + PR_FreeLibraryName(libName); + } +#elif defined(__OpenBSD__) + /* OpenBSD doesn't register inter-library dependencies in basesystem + * libs therefor we need to load all the libraries gssapi depends on, + * in the correct order and with LD_GLOBAL for GSSAPI auth to work + * fine. + */ + + const char *const verLibNames[] = { + "libasn1.so", + "libcrypto.so", + "libroken.so", + "libheimbase.so", + "libcom_err.so", + "libkrb5.so", + "libgssapi.so" + }; + + PRLibSpec libSpec; + for (size_t i = 0; i < ArrayLength(verLibNames); ++i) { + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = verLibNames[i]; + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_GLOBAL); + } + +#else + + const char *const libNames[] = { + "gss", + "gssapi_krb5", + "gssapi" + }; + + const char *const verLibNames[] = { + "libgssapi_krb5.so.2", /* MIT - FC, Suse10, Debian */ + "libgssapi.so.4", /* Heimdal - Suse10, MDK */ + "libgssapi.so.1" /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/ + }; + + for (size_t i = 0; i < ArrayLength(verLibNames) && !lib; ++i) { + lib = PR_LoadLibrary(verLibNames[i]); + + /* The CITI libgssapi library calls exit() during + * initialization if it's not correctly configured. Try to + * ensure that we never use this library for our GSSAPI + * support, as its just a wrapper library, anyway. + * See Bugzilla #325433 + */ + if (lib && + PR_FindFunctionSymbol(lib, + "internal_krb5_gss_initialize") && + PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) { + LOG(("CITI libgssapi found, which calls exit(). Skipping\n")); + PR_UnloadLibrary(lib); + lib = nullptr; + } + } + + for (size_t i = 0; i < ArrayLength(libNames) && !lib; ++i) { + char *libName = PR_GetLibraryName(nullptr, libNames[i]); + if (libName) { + lib = PR_LoadLibrary(libName); + PR_FreeLibraryName(libName); + + if (lib && + PR_FindFunctionSymbol(lib, + "internal_krb5_gss_initialize") && + PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) { + LOG(("CITI libgssapi found, which calls exit(). Skipping\n")); + PR_UnloadLibrary(lib); + lib = nullptr; + } + } + } +#endif + } + + if (!lib) { + LOG(("Fail to load gssapi library\n")); + return NS_ERROR_FAILURE; + } + + LOG(("Attempting to load gss functions\n")); + + for (size_t i = 0; i < ArrayLength(gssFuncs); ++i) { + gssFuncs[i].func = PR_FindFunctionSymbol(lib, gssFuncs[i].str); + if (!gssFuncs[i].func) { + LOG(("Fail to load %s function from gssapi library\n", gssFuncs[i].str)); + PR_UnloadLibrary(lib); + return NS_ERROR_FAILURE; + } + } +#ifdef XP_MACOSX + if (gssNativeImp && + !(KLCacheHasValidTicketsPtr = + PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) { + LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n")); + PR_UnloadLibrary(lib); + return NS_ERROR_FAILURE; + } +#endif + + gssLibrary = lib; + return NS_OK; +} + +// Generate proper GSSAPI error messages from the major and +// minor status codes. +void +LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix) +{ + if (!MOZ_LOG_TEST(gNegotiateLog, LogLevel::Debug)) { + return; + } + + OM_uint32 new_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status1_string; + gss_buffer_desc status2_string; + OM_uint32 ret; + nsAutoCString errorStr; + errorStr.Assign(prefix); + + if (!gssLibrary) + return; + + errorStr += ": "; + do { + ret = gss_display_status_ptr(&new_stat, + maj_stat, + GSS_C_GSS_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status1_string); + errorStr.Append((const char *) status1_string.value, status1_string.length); + gss_release_buffer_ptr(&new_stat, &status1_string); + + errorStr += '\n'; + ret = gss_display_status_ptr(&new_stat, + min_stat, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status2_string); + errorStr.Append((const char *) status2_string.value, status2_string.length); + errorStr += '\n'; + } while (!GSS_ERROR(ret) && msg_ctx != 0); + + LOG(("%s\n", errorStr.get())); +} + +//----------------------------------------------------------------------------- + +nsAuthGSSAPI::nsAuthGSSAPI(pType package) + : mServiceFlags(REQ_DEFAULT) +{ + OM_uint32 minstat; + OM_uint32 majstat; + gss_OID_set mech_set; + gss_OID item; + + unsigned int i; + static gss_OID_desc gss_krb5_mech_oid_desc = + { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; + static gss_OID_desc gss_spnego_mech_oid_desc = + { 6, (void *) "\x2b\x06\x01\x05\x05\x02" }; + + LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n")); + + mComplete = false; + + if (!gssLibrary && NS_FAILED(gssInit())) + return; + + mCtx = GSS_C_NO_CONTEXT; + mMechOID = &gss_krb5_mech_oid_desc; + + // if the type is kerberos we accept it as default + // and exit + + if (package == PACKAGE_TYPE_KERBEROS) + return; + + // Now, look at the list of supported mechanisms, + // if SPNEGO is found, then use it. + // Otherwise, set the desired mechanism to + // GSS_C_NO_OID and let the system try to use + // the default mechanism. + // + // Using Kerberos directly (instead of negotiating + // with SPNEGO) may work in some cases depending + // on how smart the server side is. + + majstat = gss_indicate_mechs_ptr(&minstat, &mech_set); + if (GSS_ERROR(majstat)) + return; + + if (mech_set) { + for (i=0; icount; i++) { + item = &mech_set->elements[i]; + if (item->length == gss_spnego_mech_oid_desc.length && + !memcmp(item->elements, gss_spnego_mech_oid_desc.elements, + item->length)) { + // ok, we found it + mMechOID = &gss_spnego_mech_oid_desc; + break; + } + } + gss_release_oid_set_ptr(&minstat, &mech_set); + } +} + +void +nsAuthGSSAPI::Reset() +{ + if (gssLibrary && mCtx != GSS_C_NO_CONTEXT) { + OM_uint32 minor_status; + gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER); + } + mCtx = GSS_C_NO_CONTEXT; + mComplete = false; +} + +/* static */ void +nsAuthGSSAPI::Shutdown() +{ + if (gssLibrary) { + PR_UnloadLibrary(gssLibrary); + gssLibrary = nullptr; + } +} + +/* Limitations apply to this class's thread safety. See the header file */ +NS_IMPL_ISUPPORTS(nsAuthGSSAPI, nsIAuthModule) + +NS_IMETHODIMP +nsAuthGSSAPI::Init(const char *serviceName, + uint32_t serviceFlags, + const char16_t *domain, + const char16_t *username, + const char16_t *password) +{ + // we don't expect to be passed any user credentials + NS_ASSERTION(!domain && !username && !password, "unexpected credentials"); + + // it's critial that the caller supply a service name to be used + NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG); + + LOG(("entering nsAuthGSSAPI::Init()\n")); + + if (!gssLibrary) + return NS_ERROR_NOT_INITIALIZED; + + mServiceName = serviceName; + mServiceFlags = serviceFlags; + + static bool sTelemetrySent = false; + if (!sTelemetrySent) { + mozilla::Telemetry::Accumulate( + mozilla::Telemetry::NTLM_MODULE_USED_2, + serviceFlags & nsIAuthModule::REQ_PROXY_AUTH + ? NTLM_MODULE_KERBEROS_PROXY + : NTLM_MODULE_KERBEROS_DIRECT); + sTelemetrySent = true; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsAuthGSSAPI::GetNextToken(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + OM_uint32 major_status, minor_status; + OM_uint32 req_flags = 0; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER; + gss_name_t server; + nsAutoCString userbuf; + nsresult rv; + + LOG(("entering nsAuthGSSAPI::GetNextToken()\n")); + + if (!gssLibrary) + return NS_ERROR_NOT_INITIALIZED; + + // If they've called us again after we're complete, reset to start afresh. + if (mComplete) + Reset(); + + if (mServiceFlags & REQ_DELEGATE) + req_flags |= GSS_C_DELEG_FLAG; + + if (mServiceFlags & REQ_MUTUAL_AUTH) + req_flags |= GSS_C_MUTUAL_FLAG; + + input_token.value = (void *)mServiceName.get(); + input_token.length = mServiceName.Length() + 1; + +#if defined(HAVE_RES_NINIT) + res_ninit(&_res); +#endif + major_status = gss_import_name_ptr(&minor_status, + &input_token, + &gss_c_nt_hostbased_service, + &server); + input_token.value = nullptr; + input_token.length = 0; + if (GSS_ERROR(major_status)) { + LogGssError(major_status, minor_status, "gss_import_name() failed"); + return NS_ERROR_FAILURE; + } + + if (inToken) { + input_token.length = inTokenLen; + input_token.value = (void *) inToken; + in_token_ptr = &input_token; + } + else if (mCtx != GSS_C_NO_CONTEXT) { + // If there is no input token, then we are starting a new + // authentication sequence. If we have already initialized our + // security context, then we're in trouble because it means that the + // first sequence failed. We need to bail or else we might end up in + // an infinite loop. + LOG(("Cannot restart authentication sequence!")); + return NS_ERROR_UNEXPECTED; + } + +#if defined(XP_MACOSX) + // Suppress Kerberos prompts to get credentials. See bug 240643. + // We can only use Mac OS X specific kerb functions if we are using + // the native lib + KLBoolean found; + bool doingMailTask = mServiceName.Find("imap@") || + mServiceName.Find("pop@") || + mServiceName.Find("smtp@") || + mServiceName.Find("ldap@"); + + if (!doingMailTask && (gssNativeImp && + (KLCacheHasValidTickets_ptr(nullptr, kerberosVersion_V5, &found, nullptr, nullptr) != klNoErr || !found))) + { + major_status = GSS_S_FAILURE; + minor_status = 0; + } + else +#endif /* XP_MACOSX */ + major_status = gss_init_sec_context_ptr(&minor_status, + GSS_C_NO_CREDENTIAL, + &mCtx, + server, + mMechOID, + req_flags, + GSS_C_INDEFINITE, + GSS_C_NO_CHANNEL_BINDINGS, + in_token_ptr, + nullptr, + &output_token, + nullptr, + nullptr); + + if (GSS_ERROR(major_status)) { + LogGssError(major_status, minor_status, "gss_init_sec_context() failed"); + Reset(); + rv = NS_ERROR_FAILURE; + goto end; + } + if (major_status == GSS_S_COMPLETE) { + // Mark ourselves as being complete, so that if we're called again + // we know to start afresh. + mComplete = true; + } + else if (major_status == GSS_S_CONTINUE_NEEDED) { + // + // The important thing is that we do NOT reset the + // context here because it will be needed on the + // next call. + // + } + + *outTokenLen = output_token.length; + if (output_token.length != 0) + *outToken = nsMemory::Clone(output_token.value, output_token.length); + else + *outToken = nullptr; + + gss_release_buffer_ptr(&minor_status, &output_token); + + if (major_status == GSS_S_COMPLETE) + rv = NS_SUCCESS_AUTH_FINISHED; + else + rv = NS_OK; + +end: + gss_release_name_ptr(&minor_status, &server); + + LOG((" leaving nsAuthGSSAPI::GetNextToken [rv=%x]", rv)); + return rv; +} + +NS_IMETHODIMP +nsAuthGSSAPI::Unwrap(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + OM_uint32 major_status, minor_status; + + gss_buffer_desc input_token; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + input_token.value = (void *) inToken; + input_token.length = inTokenLen; + + major_status = gss_unwrap_ptr(&minor_status, + mCtx, + &input_token, + &output_token, + nullptr, + nullptr); + if (GSS_ERROR(major_status)) { + LogGssError(major_status, minor_status, "gss_unwrap() failed"); + Reset(); + gss_release_buffer_ptr(&minor_status, &output_token); + return NS_ERROR_FAILURE; + } + + *outTokenLen = output_token.length; + + if (output_token.length) + *outToken = nsMemory::Clone(output_token.value, output_token.length); + else + *outToken = nullptr; + + gss_release_buffer_ptr(&minor_status, &output_token); + + return NS_OK; +} + +NS_IMETHODIMP +nsAuthGSSAPI::Wrap(const void *inToken, + uint32_t inTokenLen, + bool confidential, + void **outToken, + uint32_t *outTokenLen) +{ + OM_uint32 major_status, minor_status; + + gss_buffer_desc input_token; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + input_token.value = (void *) inToken; + input_token.length = inTokenLen; + + major_status = gss_wrap_ptr(&minor_status, + mCtx, + confidential, + GSS_C_QOP_DEFAULT, + &input_token, + nullptr, + &output_token); + + if (GSS_ERROR(major_status)) { + LogGssError(major_status, minor_status, "gss_wrap() failed"); + Reset(); + gss_release_buffer_ptr(&minor_status, &output_token); + return NS_ERROR_FAILURE; + } + + *outTokenLen = output_token.length; + + /* it is not possible for output_token.length to be zero */ + *outToken = nsMemory::Clone(output_token.value, output_token.length); + gss_release_buffer_ptr(&minor_status, &output_token); + + return NS_OK; +} + diff --git a/extensions/auth/nsAuthGSSAPI.h b/extensions/auth/nsAuthGSSAPI.h new file mode 100644 index 000000000..6c663e935 --- /dev/null +++ b/extensions/auth/nsAuthGSSAPI.h @@ -0,0 +1,63 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAuthGSSAPI_h__ +#define nsAuthGSSAPI_h__ + +#include "nsAuth.h" +#include "nsIAuthModule.h" +#include "nsString.h" +#include "mozilla/Attributes.h" + +#define GSS_USE_FUNCTION_POINTERS 1 + +#include "gssapi.h" + +// The nsAuthGSSAPI class provides responses for the GSS-API Negotiate method +// as specified by Microsoft in draft-brezak-spnego-http-04.txt + +/* Some remarks on thread safety ... + * + * The thread safety of this class depends largely upon the thread safety of + * the underlying GSSAPI and Kerberos libraries. This code just loads the + * system GSSAPI library, and whilst it avoids loading known bad libraries, + * it cannot determine the thread safety of the the code it loads. + * + * When used with a non-threadsafe library, it is not safe to simultaneously + * use multiple instantiations of this class. + * + * When used with a threadsafe Kerberos library, multiple instantiations of + * this class may happily co-exist. Methods may be sequentially called from + * multiple threads. The nature of the GSSAPI protocol is such that a correct + * implementation will never call methods in parallel, as the results of the + * last call are required as input to the next. + */ + +class nsAuthGSSAPI final : public nsIAuthModule +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIAUTHMODULE + + explicit nsAuthGSSAPI(pType package); + + static void Shutdown(); + +private: + ~nsAuthGSSAPI() { Reset(); } + + void Reset(); + gss_OID GetOID() { return mMechOID; } + +private: + gss_ctx_id_t mCtx; + gss_OID mMechOID; + nsCString mServiceName; + uint32_t mServiceFlags; + nsString mUsername; + bool mComplete; +}; + +#endif /* nsAuthGSSAPI_h__ */ diff --git a/extensions/auth/nsAuthSASL.cpp b/extensions/auth/nsAuthSASL.cpp new file mode 100644 index 000000000..2c72cb0ac --- /dev/null +++ b/extensions/auth/nsAuthSASL.cpp @@ -0,0 +1,151 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsComponentManagerUtils.h" +#include "nsNativeCharsetUtils.h" +#include "nsIServiceManager.h" +#include "nsIPrefService.h" + +#include "nsAuthSASL.h" + +static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi"; + +nsAuthSASL::nsAuthSASL() +{ + mSASLReady = false; +} + +void nsAuthSASL::Reset() +{ + mSASLReady = false; +} + +/* Limitations apply to this class's thread safety. See the header file */ +NS_IMPL_ISUPPORTS(nsAuthSASL, nsIAuthModule) + +NS_IMETHODIMP +nsAuthSASL::Init(const char *serviceName, + uint32_t serviceFlags, + const char16_t *domain, + const char16_t *username, + const char16_t *password) +{ + nsresult rv; + + NS_ASSERTION(username, "SASL requires a username"); + NS_ASSERTION(!domain && !password, "unexpected credentials"); + + mUsername = username; + + // If we're doing SASL, we should do mutual auth + serviceFlags |= REQ_MUTUAL_AUTH; + + // Find out whether we should be trying SSPI or not + const char *contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss"; + + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + bool val; + rv = prefs->GetBoolPref(kNegotiateAuthSSPI, &val); + if (NS_SUCCEEDED(rv) && val) + contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi"; + } + + mInnerModule = do_CreateInstance(contractID, &rv); + // if we can't create the GSSAPI module, then bail + NS_ENSURE_SUCCESS(rv, rv); + + mInnerModule->Init(serviceName, serviceFlags, nullptr, nullptr, nullptr); + + return NS_OK; +} + +NS_IMETHODIMP +nsAuthSASL::GetNextToken(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + nsresult rv; + void *unwrappedToken; + char *message; + uint32_t unwrappedTokenLen, messageLen; + nsAutoCString userbuf; + + if (!mInnerModule) + return NS_ERROR_NOT_INITIALIZED; + + if (mSASLReady) { + // If the server COMPLETEs with an empty token, Cyrus sends us that token. + // I don't think this is correct, but we need to handle that behaviour. + // Cyrus ignores the contents of our reply token. + if (inTokenLen == 0) { + *outToken = nullptr; + *outTokenLen = 0; + return NS_OK; + } + // We've completed the GSSAPI portion of the handshake, and are + // now ready to do the SASL security layer and authzid negotiation + + // Input packet from the server needs to be unwrapped. + rv = mInnerModule->Unwrap(inToken, inTokenLen, &unwrappedToken, + &unwrappedTokenLen); + if (NS_FAILED(rv)) { + Reset(); + return rv; + } + + // If we were doing security layers then we'd care what the + // server had sent us. We're not, so all we had to do was make + // sure that the signature was correct with the above unwrap() + free(unwrappedToken); + + NS_CopyUnicodeToNative(mUsername, userbuf); + messageLen = userbuf.Length() + 4 + 1; + message = (char *)moz_xmalloc(messageLen); + if (!message) { + Reset(); + return NS_ERROR_OUT_OF_MEMORY; + } + message[0] = 0x01; // No security layer + message[1] = 0x00; + message[2] = 0x00; + message[3] = 0x00; // Maxbuf must be zero if we've got no sec layer + strcpy(message+4, userbuf.get()); + // Userbuf should not be nullptr terminated, so trim the trailing nullptr + // when wrapping the message + rv = mInnerModule->Wrap((void *) message, messageLen-1, false, + outToken, outTokenLen); + free(message); + Reset(); // All done + return NS_SUCCEEDED(rv) ? NS_SUCCESS_AUTH_FINISHED : rv; + } + rv = mInnerModule->GetNextToken(inToken, inTokenLen, outToken, + outTokenLen); + if (rv == NS_SUCCESS_AUTH_FINISHED) { + mSASLReady = true; + rv = NS_OK; + } + return rv; +} + +NS_IMETHODIMP +nsAuthSASL::Unwrap(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsAuthSASL::Wrap(const void *inToken, + uint32_t inTokenLen, + bool confidential, + void **outToken, + uint32_t *outTokenLen) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/extensions/auth/nsAuthSASL.h b/extensions/auth/nsAuthSASL.h new file mode 100644 index 000000000..0cbd79a98 --- /dev/null +++ b/extensions/auth/nsAuthSASL.h @@ -0,0 +1,38 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAuthSASL_h__ +#define nsAuthSASL_h__ + +#include "nsIAuthModule.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "mozilla/Attributes.h" + +/* This class is implemented using the nsAuthGSSAPI class, and the same + * thread safety constraints which are documented in nsAuthGSSAPI.h + * apply to this class + */ + +class nsAuthSASL final : public nsIAuthModule +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIAUTHMODULE + + nsAuthSASL(); + +private: + ~nsAuthSASL() { Reset(); } + + void Reset(); + + nsCOMPtr mInnerModule; + nsString mUsername; + bool mSASLReady; +}; + +#endif /* nsAuthSASL_h__ */ + diff --git a/extensions/auth/nsAuthSSPI.cpp b/extensions/auth/nsAuthSSPI.cpp new file mode 100644 index 000000000..eb577d3bf --- /dev/null +++ b/extensions/auth/nsAuthSSPI.cpp @@ -0,0 +1,666 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// +// Negotiate Authentication Support Module +// +// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt +// (formerly draft-brezak-spnego-http-04.txt) +// +// Also described here: +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp +// + +#include "nsAuthSSPI.h" +#include "nsIServiceManager.h" +#include "nsIDNSService.h" +#include "nsIDNSRecord.h" +#include "nsNetCID.h" +#include "nsCOMPtr.h" +#include "nsICryptoHash.h" +#include "mozilla/Telemetry.h" + +#include + +#define SEC_SUCCESS(Status) ((Status) >= 0) + +#ifndef KERB_WRAP_NO_ENCRYPT +#define KERB_WRAP_NO_ENCRYPT 0x80000001 +#endif + +#ifndef SECBUFFER_PADDING +#define SECBUFFER_PADDING 9 +#endif + +#ifndef SECBUFFER_STREAM +#define SECBUFFER_STREAM 10 +#endif + +//----------------------------------------------------------------------------- + +static const wchar_t *const pTypeName [] = { + L"Kerberos", + L"Negotiate", + L"NTLM" +}; + +#ifdef DEBUG +#define CASE_(_x) case _x: return # _x; +static const char *MapErrorCode(int rc) +{ + switch (rc) { + CASE_(SEC_E_OK) + CASE_(SEC_I_CONTINUE_NEEDED) + CASE_(SEC_I_COMPLETE_NEEDED) + CASE_(SEC_I_COMPLETE_AND_CONTINUE) + CASE_(SEC_E_INCOMPLETE_MESSAGE) + CASE_(SEC_I_INCOMPLETE_CREDENTIALS) + CASE_(SEC_E_INVALID_HANDLE) + CASE_(SEC_E_TARGET_UNKNOWN) + CASE_(SEC_E_LOGON_DENIED) + CASE_(SEC_E_INTERNAL_ERROR) + CASE_(SEC_E_NO_CREDENTIALS) + CASE_(SEC_E_NO_AUTHENTICATING_AUTHORITY) + CASE_(SEC_E_INSUFFICIENT_MEMORY) + CASE_(SEC_E_INVALID_TOKEN) + } + return ""; +} +#else +#define MapErrorCode(_rc) "" +#endif + +//----------------------------------------------------------------------------- + +static PSecurityFunctionTableW sspi; + +static nsresult +InitSSPI() +{ + LOG((" InitSSPI\n")); + + sspi = InitSecurityInterfaceW(); + if (!sspi) { + LOG(("InitSecurityInterfaceW failed")); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +//----------------------------------------------------------------------------- + +static nsresult +MakeSN(const char *principal, nsCString &result) +{ + nsresult rv; + + nsAutoCString buf(principal); + + // The service name looks like "protocol@hostname", we need to map + // this to a value that SSPI expects. To be consistent with IE, we + // need to map '@' to '/' and canonicalize the hostname. + int32_t index = buf.FindChar('@'); + if (index == kNotFound) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + // This could be expensive if our DNS cache cannot satisfy the request. + // However, we should have at least hit the OS resolver once prior to + // reaching this code, so provided the OS resolver has this information + // cached, we should not have to worry about blocking on this function call + // for very long. NOTE: because we ask for the canonical hostname, we + // might end up requiring extra network activity in cases where the OS + // resolver might not have enough information to satisfy the request from + // its cache. This is not an issue in versions of Windows up to WinXP. + nsCOMPtr record; + rv = dns->Resolve(Substring(buf, index + 1), + nsIDNSService::RESOLVE_CANONICAL_NAME, + getter_AddRefs(record)); + if (NS_FAILED(rv)) + return rv; + + nsAutoCString cname; + rv = record->GetCanonicalName(cname); + if (NS_SUCCEEDED(rv)) { + result = StringHead(buf, index) + NS_LITERAL_CSTRING("/") + cname; + LOG(("Using SPN of [%s]\n", result.get())); + } + return rv; +} + +//----------------------------------------------------------------------------- + +nsAuthSSPI::nsAuthSSPI(pType package) + : mServiceFlags(REQ_DEFAULT) + , mMaxTokenLen(0) + , mPackage(package) + , mCertDERData(nullptr) + , mCertDERLength(0) +{ + memset(&mCred, 0, sizeof(mCred)); + memset(&mCtxt, 0, sizeof(mCtxt)); +} + +nsAuthSSPI::~nsAuthSSPI() +{ + Reset(); + + if (mCred.dwLower || mCred.dwUpper) { +#ifdef __MINGW32__ + (sspi->FreeCredentialsHandle)(&mCred); +#else + (sspi->FreeCredentialHandle)(&mCred); +#endif + memset(&mCred, 0, sizeof(mCred)); + } +} + +void +nsAuthSSPI::Reset() +{ + mIsFirst = true; + + if (mCertDERData){ + free(mCertDERData); + mCertDERData = nullptr; + mCertDERLength = 0; + } + + if (mCtxt.dwLower || mCtxt.dwUpper) { + (sspi->DeleteSecurityContext)(&mCtxt); + memset(&mCtxt, 0, sizeof(mCtxt)); + } +} + +NS_IMPL_ISUPPORTS(nsAuthSSPI, nsIAuthModule) + +NS_IMETHODIMP +nsAuthSSPI::Init(const char *serviceName, + uint32_t serviceFlags, + const char16_t *domain, + const char16_t *username, + const char16_t *password) +{ + LOG((" nsAuthSSPI::Init\n")); + + mIsFirst = true; + mCertDERLength = 0; + mCertDERData = nullptr; + + // The caller must supply a service name to be used. (For why we now require + // a service name for NTLM, see bug 487872.) + NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG); + + nsresult rv; + + // XXX lazy initialization like this assumes that we are single threaded + if (!sspi) { + rv = InitSSPI(); + if (NS_FAILED(rv)) + return rv; + } + SEC_WCHAR *package; + + package = (SEC_WCHAR *) pTypeName[(int)mPackage]; + + if (mPackage == PACKAGE_TYPE_NTLM) { + // (bug 535193) For NTLM, just use the uri host, do not do canonical host lookups. + // The incoming serviceName is in the format: "protocol@hostname", SSPI expects + // "/", so swap the '@' for a '/'. + mServiceName.Assign(serviceName); + int32_t index = mServiceName.FindChar('@'); + if (index == kNotFound) + return NS_ERROR_UNEXPECTED; + mServiceName.Replace(index, 1, '/'); + } + else { + // Kerberos requires the canonical host, MakeSN takes care of this through a + // DNS lookup. + rv = MakeSN(serviceName, mServiceName); + if (NS_FAILED(rv)) + return rv; + } + + mServiceFlags = serviceFlags; + + SECURITY_STATUS rc; + + PSecPkgInfoW pinfo; + rc = (sspi->QuerySecurityPackageInfoW)(package, &pinfo); + if (rc != SEC_E_OK) { + LOG(("%s package not found\n", package)); + return NS_ERROR_UNEXPECTED; + } + mMaxTokenLen = pinfo->cbMaxToken; + (sspi->FreeContextBuffer)(pinfo); + + MS_TimeStamp useBefore; + + SEC_WINNT_AUTH_IDENTITY_W ai; + SEC_WINNT_AUTH_IDENTITY_W *pai = nullptr; + + // domain, username, and password will be null if nsHttpNTLMAuth's ChallengeReceived + // returns false for identityInvalid. Use default credentials in this case by passing + // null for pai. + if (username && password) { + // Keep a copy of these strings for the duration + mUsername.Assign(username); + mPassword.Assign(password); + mDomain.Assign(domain); + ai.Domain = reinterpret_cast(mDomain.BeginWriting()); + ai.DomainLength = mDomain.Length(); + ai.User = reinterpret_cast(mUsername.BeginWriting()); + ai.UserLength = mUsername.Length(); + ai.Password = reinterpret_cast(mPassword.BeginWriting()); + ai.PasswordLength = mPassword.Length(); + ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + pai = &ai; + } + + rc = (sspi->AcquireCredentialsHandleW)(nullptr, + package, + SECPKG_CRED_OUTBOUND, + nullptr, + pai, + nullptr, + nullptr, + &mCred, + &useBefore); + if (rc != SEC_E_OK) + return NS_ERROR_UNEXPECTED; + + static bool sTelemetrySent = false; + if (!sTelemetrySent) { + mozilla::Telemetry::Accumulate( + mozilla::Telemetry::NTLM_MODULE_USED_2, + serviceFlags & nsIAuthModule::REQ_PROXY_AUTH + ? NTLM_MODULE_WIN_API_PROXY + : NTLM_MODULE_WIN_API_DIRECT); + sTelemetrySent = true; + } + + LOG(("AcquireCredentialsHandle() succeeded.\n")); + return NS_OK; +} + +// The arguments inToken and inTokenLen are used to pass in the server +// certificate (when available) in the first call of the function. The +// second time these arguments hold an input token. +NS_IMETHODIMP +nsAuthSSPI::GetNextToken(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + // String for end-point bindings. + const char end_point[] = "tls-server-end-point:"; + const int end_point_length = sizeof(end_point) - 1; + const int hash_size = 32; // Size of a SHA256 hash. + const int cbt_size = hash_size + end_point_length; + + SECURITY_STATUS rc; + MS_TimeStamp ignored; + + DWORD ctxAttr, ctxReq = 0; + CtxtHandle *ctxIn; + SecBufferDesc ibd, obd; + // Optional second input buffer for the CBT (Channel Binding Token) + SecBuffer ib[2], ob; + // Pointer to the block of memory that stores the CBT + char* sspi_cbt = nullptr; + SEC_CHANNEL_BINDINGS pendpoint_binding; + + LOG(("entering nsAuthSSPI::GetNextToken()\n")); + + if (!mCred.dwLower && !mCred.dwUpper) { + LOG(("nsAuthSSPI::GetNextToken(), not initialized. exiting.")); + return NS_ERROR_NOT_INITIALIZED; + } + + if (mServiceFlags & REQ_DELEGATE) + ctxReq |= ISC_REQ_DELEGATE; + if (mServiceFlags & REQ_MUTUAL_AUTH) + ctxReq |= ISC_REQ_MUTUAL_AUTH; + + if (inToken) { + if (mIsFirst) { + // First time if it comes with a token, + // the token represents the server certificate. + mIsFirst = false; + mCertDERLength = inTokenLen; + mCertDERData = moz_xmalloc(inTokenLen); + if (!mCertDERData) + return NS_ERROR_OUT_OF_MEMORY; + memcpy(mCertDERData, inToken, inTokenLen); + + // We are starting a new authentication sequence. + // If we have already initialized our + // security context, then we're in trouble because it means that the + // first sequence failed. We need to bail or else we might end up in + // an infinite loop. + if (mCtxt.dwLower || mCtxt.dwUpper) { + LOG(("Cannot restart authentication sequence!")); + return NS_ERROR_UNEXPECTED; + } + ctxIn = nullptr; + // The certificate needs to be erased before being passed + // to InitializeSecurityContextW(). + inToken = nullptr; + inTokenLen = 0; + } else { + ibd.ulVersion = SECBUFFER_VERSION; + ibd.cBuffers = 0; + ibd.pBuffers = ib; + + // If we have stored a certificate, the Channel Binding Token + // needs to be generated and sent in the first input buffer. + if (mCertDERLength > 0) { + // First we create a proper Endpoint Binding structure. + pendpoint_binding.dwInitiatorAddrType = 0; + pendpoint_binding.cbInitiatorLength = 0; + pendpoint_binding.dwInitiatorOffset = 0; + pendpoint_binding.dwAcceptorAddrType = 0; + pendpoint_binding.cbAcceptorLength = 0; + pendpoint_binding.dwAcceptorOffset = 0; + pendpoint_binding.cbApplicationDataLength = cbt_size; + pendpoint_binding.dwApplicationDataOffset = + sizeof(SEC_CHANNEL_BINDINGS); + + // Then add it to the array of sec buffers accordingly. + ib[ibd.cBuffers].BufferType = SECBUFFER_CHANNEL_BINDINGS; + ib[ibd.cBuffers].cbBuffer = + pendpoint_binding.cbApplicationDataLength + + pendpoint_binding.dwApplicationDataOffset; + + sspi_cbt = (char *) moz_xmalloc(ib[ibd.cBuffers].cbBuffer); + if (!sspi_cbt){ + return NS_ERROR_OUT_OF_MEMORY; + } + + // Helper to write in the memory block that stores the CBT + char* sspi_cbt_ptr = sspi_cbt; + + ib[ibd.cBuffers].pvBuffer = sspi_cbt; + ibd.cBuffers++; + + memcpy(sspi_cbt_ptr, &pendpoint_binding, + pendpoint_binding.dwApplicationDataOffset); + sspi_cbt_ptr += pendpoint_binding.dwApplicationDataOffset; + + memcpy(sspi_cbt_ptr, end_point, end_point_length); + sspi_cbt_ptr += end_point_length; + + // Start hashing. We are always doing SHA256, but depending + // on the certificate, a different alogirthm might be needed. + nsAutoCString hashString; + + nsresult rv; + nsCOMPtr crypto; + crypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + rv = crypto->Init(nsICryptoHash::SHA256); + if (NS_SUCCEEDED(rv)) + rv = crypto->Update((unsigned char*)mCertDERData, mCertDERLength); + if (NS_SUCCEEDED(rv)) + rv = crypto->Finish(false, hashString); + if (NS_FAILED(rv)) { + free(mCertDERData); + mCertDERData = nullptr; + mCertDERLength = 0; + free(sspi_cbt); + return rv; + } + + // Once the hash has been computed, we store it in memory right + // after the Endpoint structure and the "tls-server-end-point:" + // char array. + memcpy(sspi_cbt_ptr, hashString.get(), hash_size); + + // Free memory used to store the server certificate + free(mCertDERData); + mCertDERData = nullptr; + mCertDERLength = 0; + } // End of CBT computation. + + // We always need this SECBUFFER. + ib[ibd.cBuffers].BufferType = SECBUFFER_TOKEN; + ib[ibd.cBuffers].cbBuffer = inTokenLen; + ib[ibd.cBuffers].pvBuffer = (void *) inToken; + ibd.cBuffers++; + ctxIn = &mCtxt; + } + } else { // First time and without a token (no server certificate) + // We are starting a new authentication sequence. If we have already + // initialized our security context, then we're in trouble because it + // means that the first sequence failed. We need to bail or else we + // might end up in an infinite loop. + if (mCtxt.dwLower || mCtxt.dwUpper || mCertDERData || mCertDERLength) { + LOG(("Cannot restart authentication sequence!")); + return NS_ERROR_UNEXPECTED; + } + ctxIn = nullptr; + mIsFirst = false; + } + + obd.ulVersion = SECBUFFER_VERSION; + obd.cBuffers = 1; + obd.pBuffers = &ob; + ob.BufferType = SECBUFFER_TOKEN; + ob.cbBuffer = mMaxTokenLen; + ob.pvBuffer = moz_xmalloc(ob.cbBuffer); + if (!ob.pvBuffer){ + if (sspi_cbt) + free(sspi_cbt); + return NS_ERROR_OUT_OF_MEMORY; + } + memset(ob.pvBuffer, 0, ob.cbBuffer); + + NS_ConvertUTF8toUTF16 wSN(mServiceName); + SEC_WCHAR *sn = (SEC_WCHAR *) wSN.get(); + + rc = (sspi->InitializeSecurityContextW)(&mCred, + ctxIn, + sn, + ctxReq, + 0, + SECURITY_NATIVE_DREP, + inToken ? &ibd : nullptr, + 0, + &mCtxt, + &obd, + &ctxAttr, + &ignored); + if (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_OK) { + + if (rc == SEC_E_OK) + LOG(("InitializeSecurityContext: succeeded.\n")); + else + LOG(("InitializeSecurityContext: continue.\n")); + + if (sspi_cbt) + free(sspi_cbt); + + if (!ob.cbBuffer) { + free(ob.pvBuffer); + ob.pvBuffer = nullptr; + } + *outToken = ob.pvBuffer; + *outTokenLen = ob.cbBuffer; + + if (rc == SEC_E_OK) + return NS_SUCCESS_AUTH_FINISHED; + + return NS_OK; + } + + LOG(("InitializeSecurityContext failed [rc=%d:%s]\n", rc, MapErrorCode(rc))); + Reset(); + free(ob.pvBuffer); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsAuthSSPI::Unwrap(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + SECURITY_STATUS rc; + SecBufferDesc ibd; + SecBuffer ib[2]; + + ibd.cBuffers = 2; + ibd.pBuffers = ib; + ibd.ulVersion = SECBUFFER_VERSION; + + // SSPI Buf + ib[0].BufferType = SECBUFFER_STREAM; + ib[0].cbBuffer = inTokenLen; + ib[0].pvBuffer = moz_xmalloc(ib[0].cbBuffer); + if (!ib[0].pvBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(ib[0].pvBuffer, inToken, inTokenLen); + + // app data + ib[1].BufferType = SECBUFFER_DATA; + ib[1].cbBuffer = 0; + ib[1].pvBuffer = nullptr; + + rc = (sspi->DecryptMessage)( + &mCtxt, + &ibd, + 0, // no sequence numbers + nullptr + ); + + if (SEC_SUCCESS(rc)) { + // check if ib[1].pvBuffer is really just ib[0].pvBuffer, in which + // case we can let the caller free it. Otherwise, we need to + // clone it, and free the original + if (ib[0].pvBuffer == ib[1].pvBuffer) { + *outToken = ib[1].pvBuffer; + } + else { + *outToken = nsMemory::Clone(ib[1].pvBuffer, ib[1].cbBuffer); + free(ib[0].pvBuffer); + if (!*outToken) + return NS_ERROR_OUT_OF_MEMORY; + } + *outTokenLen = ib[1].cbBuffer; + } + else + free(ib[0].pvBuffer); + + if (!SEC_SUCCESS(rc)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// utility class used to free memory on exit +class secBuffers +{ +public: + + SecBuffer ib[3]; + + secBuffers() { memset(&ib, 0, sizeof(ib)); } + + ~secBuffers() + { + if (ib[0].pvBuffer) + free(ib[0].pvBuffer); + + if (ib[1].pvBuffer) + free(ib[1].pvBuffer); + + if (ib[2].pvBuffer) + free(ib[2].pvBuffer); + } +}; + +NS_IMETHODIMP +nsAuthSSPI::Wrap(const void *inToken, + uint32_t inTokenLen, + bool confidential, + void **outToken, + uint32_t *outTokenLen) +{ + SECURITY_STATUS rc; + + SecBufferDesc ibd; + secBuffers bufs; + SecPkgContext_Sizes sizes; + + rc = (sspi->QueryContextAttributesW)( + &mCtxt, + SECPKG_ATTR_SIZES, + &sizes); + + if (!SEC_SUCCESS(rc)) + return NS_ERROR_FAILURE; + + ibd.cBuffers = 3; + ibd.pBuffers = bufs.ib; + ibd.ulVersion = SECBUFFER_VERSION; + + // SSPI + bufs.ib[0].cbBuffer = sizes.cbSecurityTrailer; + bufs.ib[0].BufferType = SECBUFFER_TOKEN; + bufs.ib[0].pvBuffer = moz_xmalloc(sizes.cbSecurityTrailer); + + if (!bufs.ib[0].pvBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + // APP Data + bufs.ib[1].BufferType = SECBUFFER_DATA; + bufs.ib[1].pvBuffer = moz_xmalloc(inTokenLen); + bufs.ib[1].cbBuffer = inTokenLen; + + if (!bufs.ib[1].pvBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(bufs.ib[1].pvBuffer, inToken, inTokenLen); + + // SSPI + bufs.ib[2].BufferType = SECBUFFER_PADDING; + bufs.ib[2].cbBuffer = sizes.cbBlockSize; + bufs.ib[2].pvBuffer = moz_xmalloc(bufs.ib[2].cbBuffer); + + if (!bufs.ib[2].pvBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + rc = (sspi->EncryptMessage)(&mCtxt, + confidential ? 0 : KERB_WRAP_NO_ENCRYPT, + &ibd, 0); + + if (SEC_SUCCESS(rc)) { + int len = bufs.ib[0].cbBuffer + bufs.ib[1].cbBuffer + bufs.ib[2].cbBuffer; + char *p = (char *) moz_xmalloc(len); + + if (!p) + return NS_ERROR_OUT_OF_MEMORY; + + *outToken = (void *) p; + *outTokenLen = len; + + memcpy(p, bufs.ib[0].pvBuffer, bufs.ib[0].cbBuffer); + p += bufs.ib[0].cbBuffer; + + memcpy(p,bufs.ib[1].pvBuffer, bufs.ib[1].cbBuffer); + p += bufs.ib[1].cbBuffer; + + memcpy(p,bufs.ib[2].pvBuffer, bufs.ib[2].cbBuffer); + + return NS_OK; + } + + return NS_ERROR_FAILURE; +} diff --git a/extensions/auth/nsAuthSSPI.h b/extensions/auth/nsAuthSSPI.h new file mode 100644 index 000000000..752b22aef --- /dev/null +++ b/extensions/auth/nsAuthSSPI.h @@ -0,0 +1,59 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAuthSSPI_h__ +#define nsAuthSSPI_h__ + +#include "nsAuth.h" +#include "nsIAuthModule.h" +#include "nsString.h" + +#include + +#define SECURITY_WIN32 1 +#include +#include +#include + +// The nsNegotiateAuth class provides responses for the GSS-API Negotiate method +// as specified by Microsoft in draft-brezak-spnego-http-04.txt + +// It can also be configured to talk raw NTLM. This implementation of NTLM has +// the advantage of being able to access the user's logon credentials. This +// implementation of NTLM should only be used for single-signon. It should be +// avoided when authenticating over the internet since it may use a lower-grade +// version of password hashing depending on the version of Windows being used. + +class nsAuthSSPI final : public nsIAuthModule +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIAUTHMODULE + + nsAuthSSPI(pType package = PACKAGE_TYPE_NEGOTIATE); + +private: + ~nsAuthSSPI(); + + void Reset(); + + typedef TimeStamp MS_TimeStamp; + +private: + CredHandle mCred; + CtxtHandle mCtxt; + nsCString mServiceName; + uint32_t mServiceFlags; + uint32_t mMaxTokenLen; + pType mPackage; + nsString mDomain; + nsString mUsername; + nsString mPassword; + bool mIsFirst; + void* mCertDERData; + uint32_t mCertDERLength; +}; + +#endif /* nsAuthSSPI_h__ */ diff --git a/extensions/auth/nsAuthSambaNTLM.cpp b/extensions/auth/nsAuthSambaNTLM.cpp new file mode 100644 index 000000000..1406c15e0 --- /dev/null +++ b/extensions/auth/nsAuthSambaNTLM.cpp @@ -0,0 +1,296 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsAuth.h" +#include "nsAuthSambaNTLM.h" +#include "prenv.h" +#include "plbase64.h" +#include "prerror.h" +#include "mozilla/Telemetry.h" + +#include + +nsAuthSambaNTLM::nsAuthSambaNTLM() + : mInitialMessage(nullptr), mChildPID(nullptr), mFromChildFD(nullptr), + mToChildFD(nullptr) +{ +} + +nsAuthSambaNTLM::~nsAuthSambaNTLM() +{ + // ntlm_auth reads from stdin regularly so closing our file handles + // should cause it to exit. + Shutdown(); + free(mInitialMessage); +} + +void +nsAuthSambaNTLM::Shutdown() +{ + if (mFromChildFD) { + PR_Close(mFromChildFD); + mFromChildFD = nullptr; + } + if (mToChildFD) { + PR_Close(mToChildFD); + mToChildFD = nullptr; + } + if (mChildPID) { + int32_t exitCode; + PR_WaitProcess(mChildPID, &exitCode); + mChildPID = nullptr; + } +} + +NS_IMPL_ISUPPORTS(nsAuthSambaNTLM, nsIAuthModule) + +static bool +SpawnIOChild(char* const* aArgs, PRProcess** aPID, + PRFileDesc** aFromChildFD, PRFileDesc** aToChildFD) +{ + PRFileDesc* toChildPipeRead; + PRFileDesc* toChildPipeWrite; + if (PR_CreatePipe(&toChildPipeRead, &toChildPipeWrite) != PR_SUCCESS) + return false; + PR_SetFDInheritable(toChildPipeRead, true); + PR_SetFDInheritable(toChildPipeWrite, false); + + PRFileDesc* fromChildPipeRead; + PRFileDesc* fromChildPipeWrite; + if (PR_CreatePipe(&fromChildPipeRead, &fromChildPipeWrite) != PR_SUCCESS) { + PR_Close(toChildPipeRead); + PR_Close(toChildPipeWrite); + return false; + } + PR_SetFDInheritable(fromChildPipeRead, false); + PR_SetFDInheritable(fromChildPipeWrite, true); + + PRProcessAttr* attr = PR_NewProcessAttr(); + if (!attr) { + PR_Close(fromChildPipeRead); + PR_Close(fromChildPipeWrite); + PR_Close(toChildPipeRead); + PR_Close(toChildPipeWrite); + return false; + } + + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, toChildPipeRead); + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, fromChildPipeWrite); + + PRProcess* process = PR_CreateProcess(aArgs[0], aArgs, nullptr, attr); + PR_DestroyProcessAttr(attr); + PR_Close(fromChildPipeWrite); + PR_Close(toChildPipeRead); + if (!process) { + LOG(("ntlm_auth exec failure [%d]", PR_GetError())); + PR_Close(fromChildPipeRead); + PR_Close(toChildPipeWrite); + return false; + } + + *aPID = process; + *aFromChildFD = fromChildPipeRead; + *aToChildFD = toChildPipeWrite; + return true; +} + +static bool WriteString(PRFileDesc* aFD, const nsACString& aString) +{ + int32_t length = aString.Length(); + const char* s = aString.BeginReading(); + LOG(("Writing to ntlm_auth: %s", s)); + + while (length > 0) { + int result = PR_Write(aFD, s, length); + if (result <= 0) + return false; + s += result; + length -= result; + } + return true; +} + +static bool ReadLine(PRFileDesc* aFD, nsACString& aString) +{ + // ntlm_auth is defined to only send one line in response to each of our + // input lines. So this simple unbuffered strategy works as long as we + // read the response immediately after sending one request. + aString.Truncate(); + for (;;) { + char buf[1024]; + int result = PR_Read(aFD, buf, sizeof(buf)); + if (result <= 0) + return false; + aString.Append(buf, result); + if (buf[result - 1] == '\n') { + LOG(("Read from ntlm_auth: %s", nsPromiseFlatCString(aString).get())); + return true; + } + } +} + +/** + * Returns a heap-allocated array of PRUint8s, and stores the length in aLen. + * Returns nullptr if there's an error of any kind. + */ +static uint8_t* ExtractMessage(const nsACString& aLine, uint32_t* aLen) +{ + // ntlm_auth sends blobs to us as base64-encoded strings after the "xx " + // preamble on the response line. + int32_t length = aLine.Length(); + // The caller should verify there is a valid "xx " prefix and the line + // is terminated with a \n + NS_ASSERTION(length >= 4, "Line too short..."); + const char* line = aLine.BeginReading(); + const char* s = line + 3; + length -= 4; // lose first 3 chars plus trailing \n + NS_ASSERTION(s[length] == '\n', "aLine not newline-terminated"); + + if (length & 3) { + // The base64 encoded block must be multiple of 4. If not, something + // screwed up. + NS_WARNING("Base64 encoded block should be a multiple of 4 chars"); + return nullptr; + } + + // Calculate the exact length. I wonder why there isn't a function for this + // in plbase64. + int32_t numEquals; + for (numEquals = 0; numEquals < length; ++numEquals) { + if (s[length - 1 - numEquals] != '=') + break; + } + *aLen = (length/4)*3 - numEquals; + return reinterpret_cast(PL_Base64Decode(s, length, nullptr)); +} + +nsresult +nsAuthSambaNTLM::SpawnNTLMAuthHelper() +{ + const char* username = PR_GetEnv("USER"); + if (!username) + return NS_ERROR_FAILURE; + + const char* const args[] = { + "ntlm_auth", + "--helper-protocol", "ntlmssp-client-1", + "--use-cached-creds", + "--username", username, + nullptr + }; + + bool isOK = SpawnIOChild(const_cast(args), &mChildPID, &mFromChildFD, &mToChildFD); + if (!isOK) + return NS_ERROR_FAILURE; + + if (!WriteString(mToChildFD, NS_LITERAL_CSTRING("YR\n"))) + return NS_ERROR_FAILURE; + nsCString line; + if (!ReadLine(mFromChildFD, line)) + return NS_ERROR_FAILURE; + if (!StringBeginsWith(line, NS_LITERAL_CSTRING("YR "))) { + // Something went wrong. Perhaps no credentials are accessible. + return NS_ERROR_FAILURE; + } + + // It gave us an initial client-to-server request packet. Save that + // because we'll need it later. + mInitialMessage = ExtractMessage(line, &mInitialMessageLen); + if (!mInitialMessage) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +nsAuthSambaNTLM::Init(const char *serviceName, + uint32_t serviceFlags, + const char16_t *domain, + const char16_t *username, + const char16_t *password) +{ + NS_ASSERTION(!username && !domain && !password, "unexpected credentials"); + + static bool sTelemetrySent = false; + if (!sTelemetrySent) { + mozilla::Telemetry::Accumulate( + mozilla::Telemetry::NTLM_MODULE_USED_2, + serviceFlags & nsIAuthModule::REQ_PROXY_AUTH + ? NTLM_MODULE_SAMBA_AUTH_PROXY + : NTLM_MODULE_SAMBA_AUTH_DIRECT); + sTelemetrySent = true; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsAuthSambaNTLM::GetNextToken(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + if (!inToken) { + /* someone wants our initial message */ + *outToken = nsMemory::Clone(mInitialMessage, mInitialMessageLen); + if (!*outToken) + return NS_ERROR_OUT_OF_MEMORY; + *outTokenLen = mInitialMessageLen; + return NS_OK; + } + + /* inToken must be a type 2 message. Get ntlm_auth to generate our response */ + char* encoded = PL_Base64Encode(static_cast(inToken), inTokenLen, nullptr); + if (!encoded) + return NS_ERROR_OUT_OF_MEMORY; + + nsCString request; + request.AssignLiteral("TT "); + request.Append(encoded); + free(encoded); + request.Append('\n'); + + if (!WriteString(mToChildFD, request)) + return NS_ERROR_FAILURE; + nsCString line; + if (!ReadLine(mFromChildFD, line)) + return NS_ERROR_FAILURE; + if (!StringBeginsWith(line, NS_LITERAL_CSTRING("KK ")) && + !StringBeginsWith(line, NS_LITERAL_CSTRING("AF "))) { + // Something went wrong. Perhaps no credentials are accessible. + return NS_ERROR_FAILURE; + } + uint8_t* buf = ExtractMessage(line, outTokenLen); + if (!buf) + return NS_ERROR_FAILURE; + *outToken = nsMemory::Clone(buf, *outTokenLen); + free(buf); + if (!*outToken) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // We're done. Close our file descriptors now and reap the helper + // process. + Shutdown(); + return NS_SUCCESS_AUTH_FINISHED; +} + +NS_IMETHODIMP +nsAuthSambaNTLM::Unwrap(const void *inToken, + uint32_t inTokenLen, + void **outToken, + uint32_t *outTokenLen) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsAuthSambaNTLM::Wrap(const void *inToken, + uint32_t inTokenLen, + bool confidential, + void **outToken, + uint32_t *outTokenLen) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/extensions/auth/nsAuthSambaNTLM.h b/extensions/auth/nsAuthSambaNTLM.h new file mode 100644 index 000000000..26b21b667 --- /dev/null +++ b/extensions/auth/nsAuthSambaNTLM.h @@ -0,0 +1,52 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAuthSambaNTLM_h__ +#define nsAuthSambaNTLM_h__ + +#include "nsIAuthModule.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "prio.h" +#include "prproces.h" +#include "mozilla/Attributes.h" + +/** + * This is an implementation of NTLM authentication that does single-signon + * by obtaining the user's Unix username, parsing it into DOMAIN\name format, + * and then asking Samba's ntlm_auth tool to do the authentication for us + * using the user's password cached in winbindd, if available. If the + * password is not available then this component fails to instantiate so + * nsHttpNTLMAuth will fall back to a different NTLM implementation. + * NOTE: at time of writing, this requires patches to be added to the stock + * Samba winbindd and ntlm_auth! + */ +class nsAuthSambaNTLM final : public nsIAuthModule +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIAUTHMODULE + + nsAuthSambaNTLM(); + + // We spawn the ntlm_auth helper from the module constructor, because + // that lets us fail to instantiate the module if ntlm_auth isn't + // available, triggering fallback to the built-in NTLM support (which + // doesn't support single signon, of course) + nsresult SpawnNTLMAuthHelper(); + +private: + ~nsAuthSambaNTLM(); + + void Shutdown(); + + uint8_t* mInitialMessage; /* free with free() */ + uint32_t mInitialMessageLen; + PRProcess* mChildPID; + PRFileDesc* mFromChildFD; + PRFileDesc* mToChildFD; +}; + +#endif /* nsAuthSambaNTLM_h__ */ diff --git a/extensions/auth/nsHttpNegotiateAuth.cpp b/extensions/auth/nsHttpNegotiateAuth.cpp new file mode 100644 index 000000000..adea54b85 --- /dev/null +++ b/extensions/auth/nsHttpNegotiateAuth.cpp @@ -0,0 +1,731 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// +// HTTP Negotiate Authentication Support Module +// +// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt +// (formerly draft-brezak-spnego-http-04.txt) +// +// Also described here: +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp +// + +#include +#include + +#include "nsAuth.h" +#include "nsHttpNegotiateAuth.h" + +#include "nsIHttpAuthenticableChannel.h" +#include "nsIProxiedChannel.h" +#include "nsIAuthModule.h" +#include "nsIServiceManager.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIProxyInfo.h" +#include "nsIURI.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsNetCID.h" +#include "plbase64.h" +#include "plstr.h" +#include "mozilla/Base64.h" +#include "prprf.h" +#include "mozilla/Logging.h" +#include "prmem.h" +#include "prnetdb.h" +#include "mozilla/Likely.h" +#include "mozilla/Sprintf.h" +#include "nsIChannel.h" +#include "nsNetUtil.h" +#include "nsThreadUtils.h" +#include "nsIHttpAuthenticatorCallback.h" +#include "mozilla/Mutex.h" +#include "nsICancelable.h" + +using mozilla::Base64Decode; + +//----------------------------------------------------------------------------- + +static const char kNegotiate[] = "Negotiate"; +static const char kNegotiateAuthTrustedURIs[] = "network.negotiate-auth.trusted-uris"; +static const char kNegotiateAuthDelegationURIs[] = "network.negotiate-auth.delegation-uris"; +static const char kNegotiateAuthAllowProxies[] = "network.negotiate-auth.allow-proxies"; +static const char kNegotiateAuthAllowNonFqdn[] = "network.negotiate-auth.allow-non-fqdn"; +static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi"; +static const char kSSOinPBmode[] = "network.auth.private-browsing-sso"; + +#define kNegotiateLen (sizeof(kNegotiate)-1) +#define DEFAULT_THREAD_TIMEOUT_MS 30000 + +//----------------------------------------------------------------------------- + +// Return false when the channel comes from a Private browsing window. +static bool +TestNotInPBMode(nsIHttpAuthenticableChannel *authChannel, bool proxyAuth) +{ + // Proxy should go all the time, it's not considered a privacy leak + // to send default credentials to a proxy. + if (proxyAuth) { + return true; + } + + nsCOMPtr bareChannel = do_QueryInterface(authChannel); + MOZ_ASSERT(bareChannel); + + if (!NS_UsePrivateBrowsing(bareChannel)) { + return true; + } + + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + bool ssoInPb; + if (NS_SUCCEEDED(prefs->GetBoolPref(kSSOinPBmode, &ssoInPb)) && ssoInPb) { + return true; + } + + // When the "Never remember history" option is set, all channels are + // set PB mode flag, but here we want to make an exception, users + // want their credentials go out. + bool dontRememberHistory; + if (NS_SUCCEEDED(prefs->GetBoolPref("browser.privatebrowsing.autostart", + &dontRememberHistory)) && + dontRememberHistory) { + return true; + } + } + + return false; +} + +NS_IMETHODIMP +nsHttpNegotiateAuth::GetAuthFlags(uint32_t *flags) +{ + // + // Negotiate Auth creds should not be reused across multiple requests. + // Only perform the negotiation when it is explicitly requested by the + // server. Thus, do *NOT* use the "REUSABLE_CREDENTIALS" flag here. + // + // CONNECTION_BASED is specified instead of REQUEST_BASED since we need + // to complete a sequence of transactions with the server over the same + // connection. + // + *flags = CONNECTION_BASED | IDENTITY_IGNORED; + return NS_OK; +} + +// +// Always set *identityInvalid == FALSE here. This +// will prevent the browser from popping up the authentication +// prompt window. Because GSSAPI does not have an API +// for fetching initial credentials (ex: A Kerberos TGT), +// there is no correct way to get the users credentials. +// +NS_IMETHODIMP +nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel, + const char *challenge, + bool isProxyAuth, + nsISupports **sessionState, + nsISupports **continuationState, + bool *identityInvalid) +{ + nsIAuthModule *module = (nsIAuthModule *) *continuationState; + + *identityInvalid = false; + if (module) + return NS_OK; + + nsresult rv; + + nsCOMPtr uri; + rv = authChannel->GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv)) + return rv; + + uint32_t req_flags = nsIAuthModule::REQ_DEFAULT; + nsAutoCString service; + + if (isProxyAuth) { + if (!TestBoolPref(kNegotiateAuthAllowProxies)) { + LOG(("nsHttpNegotiateAuth::ChallengeReceived proxy auth blocked\n")); + return NS_ERROR_ABORT; + } + + req_flags |= nsIAuthModule::REQ_PROXY_AUTH; + nsCOMPtr proxyInfo; + authChannel->GetProxyInfo(getter_AddRefs(proxyInfo)); + NS_ENSURE_STATE(proxyInfo); + + proxyInfo->GetHost(service); + } + else { + bool allowed = TestNotInPBMode(authChannel, isProxyAuth) && + (TestNonFqdn(uri) || + TestPref(uri, kNegotiateAuthTrustedURIs)); + if (!allowed) { + LOG(("nsHttpNegotiateAuth::ChallengeReceived URI blocked\n")); + return NS_ERROR_ABORT; + } + + bool delegation = TestPref(uri, kNegotiateAuthDelegationURIs); + if (delegation) { + LOG((" using REQ_DELEGATE\n")); + req_flags |= nsIAuthModule::REQ_DELEGATE; + } + + rv = uri->GetAsciiHost(service); + if (NS_FAILED(rv)) + return rv; + } + + LOG((" service = %s\n", service.get())); + + // + // The correct service name for IIS servers is "HTTP/f.q.d.n", so + // construct the proper service name for passing to "gss_import_name". + // + // TODO: Possibly make this a configurable service name for use + // with non-standard servers that use stuff like "khttp/f.q.d.n" + // instead. + // + service.Insert("HTTP@", 0); + + const char *contractID; + if (TestBoolPref(kNegotiateAuthSSPI)) { + LOG((" using negotiate-sspi\n")); + contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi"; + } + else { + LOG((" using negotiate-gss\n")); + contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss"; + } + + rv = CallCreateInstance(contractID, &module); + + if (NS_FAILED(rv)) { + LOG((" Failed to load Negotiate Module \n")); + return rv; + } + + rv = module->Init(service.get(), req_flags, nullptr, nullptr, nullptr); + + if (NS_FAILED(rv)) { + NS_RELEASE(module); + return rv; + } + + *continuationState = module; + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsHttpNegotiateAuth, nsIHttpAuthenticator) + +namespace { + +// +// GetNextTokenCompleteEvent +// +// This event is fired on main thread when async call of +// nsHttpNegotiateAuth::GenerateCredentials is finished. During the Run() +// method the nsIHttpAuthenticatorCallback::OnCredsAvailable is called with +// obtained credentials, flags and NS_OK when successful, otherwise +// NS_ERROR_FAILURE is returned as a result of failed operation. +// +class GetNextTokenCompleteEvent final : public nsIRunnable, + public nsICancelable +{ + virtual ~GetNextTokenCompleteEvent() + { + if (mCreds) { + free(mCreds); + } + }; + +public: + NS_DECL_THREADSAFE_ISUPPORTS + + explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback) + : mCallback(aCallback) + , mCreds(nullptr) + , mCancelled(false) + { + } + + NS_IMETHODIMP DispatchSuccess(char *aCreds, + uint32_t aFlags, + already_AddRefed aSessionState, + already_AddRefed aContinuationState) + { + // Called from worker thread + MOZ_ASSERT(!NS_IsMainThread()); + + mCreds = aCreds; + mFlags = aFlags; + mResult = NS_OK; + mSessionState = aSessionState; + mContinuationState = aContinuationState; + return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); + } + + NS_IMETHODIMP DispatchError(already_AddRefed aSessionState, + already_AddRefed aContinuationState) + { + // Called from worker thread + MOZ_ASSERT(!NS_IsMainThread()); + + mResult = NS_ERROR_FAILURE; + mSessionState = aSessionState; + mContinuationState = aContinuationState; + return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); + } + + NS_IMETHODIMP Run() override + { + // Runs on main thread + MOZ_ASSERT(NS_IsMainThread()); + + if (!mCancelled) { + nsCOMPtr callback; + callback.swap(mCallback); + callback->OnCredsGenerated(mCreds, mFlags, mResult, mSessionState, mContinuationState); + } + return NS_OK; + } + + NS_IMETHODIMP Cancel(nsresult aReason) override + { + // Supposed to be called from main thread + MOZ_ASSERT(NS_IsMainThread()); + + mCancelled = true; + return NS_OK; + } + +private: + nsCOMPtr mCallback; + char *mCreds; // This class owns it, freed in destructor + uint32_t mFlags; + nsresult mResult; + bool mCancelled; + nsCOMPtr mSessionState; + nsCOMPtr mContinuationState; +}; + +NS_IMPL_ISUPPORTS(GetNextTokenCompleteEvent, nsIRunnable, nsICancelable) + +// +// GetNextTokenRunnable +// +// This runnable is created by GenerateCredentialsAsync and it runs +// in nsHttpNegotiateAuth::mNegotiateThread and calling GenerateCredentials. +// +class GetNextTokenRunnable final : public mozilla::Runnable +{ + virtual ~GetNextTokenRunnable() {} + public: + GetNextTokenRunnable(nsIHttpAuthenticableChannel *authChannel, + const char *challenge, + bool isProxyAuth, + const char16_t *domain, + const char16_t *username, + const char16_t *password, + nsISupports *sessionState, + nsISupports *continuationState, + GetNextTokenCompleteEvent *aCompleteEvent + ) + : mAuthChannel(authChannel) + , mChallenge(challenge) + , mIsProxyAuth(isProxyAuth) + , mDomain(domain) + , mUsername(username) + , mPassword(password) + , mSessionState(sessionState) + , mContinuationState(continuationState) + , mCompleteEvent(aCompleteEvent) + { + } + + NS_IMETHODIMP Run() override + { + // Runs on worker thread + MOZ_ASSERT(!NS_IsMainThread()); + + char *creds; + uint32_t flags; + nsresult rv = ObtainCredentialsAndFlags(&creds, &flags); + + // Passing session and continuation state this way to not touch + // referencing of the object that may not be thread safe. + // Not having a thread safe referencing doesn't mean the object + // cannot be used on multiple threads (one example is nsAuthSSPI.) + // This ensures state objects will be destroyed on the main thread + // when not changed by GenerateCredentials. + if (NS_FAILED(rv)) { + return mCompleteEvent->DispatchError(mSessionState.forget(), + mContinuationState.forget()); + } + + return mCompleteEvent->DispatchSuccess(creds, flags, + mSessionState.forget(), + mContinuationState.forget()); + } + + NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags) + { + nsresult rv; + + // Use negotiate service to call GenerateCredentials outside of main thread + nsAutoCString contractId; + contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX); + contractId.Append("negotiate"); + nsCOMPtr authenticator = + do_GetService(contractId.get(), &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsISupports *sessionState = mSessionState; + nsISupports *continuationState = mContinuationState; + // The continuationState is for the sake of completeness propagated + // to the caller (despite it is not changed in any GenerateCredentials + // implementation). + // + // The only implementation that use sessionState is the + // nsHttpDigestAuth::GenerateCredentials. Since there's no reason + // to implement nsHttpDigestAuth::GenerateCredentialsAsync + // because digest auth does not block the main thread, we won't + // propagate changes to sessionState to the caller because of + // the change is too complicated on the caller side. + // + // Should any of the session or continuation states change inside + // this method, they must be threadsafe. + rv = authenticator->GenerateCredentials(mAuthChannel, + mChallenge.get(), + mIsProxyAuth, + mDomain.get(), + mUsername.get(), + mPassword.get(), + &sessionState, + &continuationState, + aFlags, + aCreds); + if (mSessionState != sessionState) { + mSessionState = sessionState; + } + if (mContinuationState != continuationState) { + mContinuationState = continuationState; + } + return rv; + } + private: + nsCOMPtr mAuthChannel; + nsCString mChallenge; + bool mIsProxyAuth; + nsString mDomain; + nsString mUsername; + nsString mPassword; + nsCOMPtr mSessionState; + nsCOMPtr mContinuationState; + RefPtr mCompleteEvent; +}; + +} // anonymous namespace + +NS_IMETHODIMP +nsHttpNegotiateAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel, + nsIHttpAuthenticatorCallback* aCallback, + const char *challenge, + bool isProxyAuth, + const char16_t *domain, + const char16_t *username, + const char16_t *password, + nsISupports *sessionState, + nsISupports *continuationState, + nsICancelable **aCancelable) +{ + NS_ENSURE_ARG(aCallback); + NS_ENSURE_ARG_POINTER(aCancelable); + + RefPtr cancelEvent = + new GetNextTokenCompleteEvent(aCallback); + + + nsCOMPtr getNextTokenRunnable = + new GetNextTokenRunnable(authChannel, + challenge, + isProxyAuth, + domain, + username, + password, + sessionState, + continuationState, + cancelEvent); + cancelEvent.forget(aCancelable); + + nsresult rv; + if (!mNegotiateThread) { + mNegotiateThread = + new mozilla::LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS, + NS_LITERAL_CSTRING("NegotiateAuth")); + NS_ENSURE_TRUE(mNegotiateThread, NS_ERROR_OUT_OF_MEMORY); + } + rv = mNegotiateThread->Dispatch(getNextTokenRunnable, NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +// +// GenerateCredentials +// +// This routine is responsible for creating the correct authentication +// blob to pass to the server that requested "Negotiate" authentication. +// +NS_IMETHODIMP +nsHttpNegotiateAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel, + const char *challenge, + bool isProxyAuth, + const char16_t *domain, + const char16_t *username, + const char16_t *password, + nsISupports **sessionState, + nsISupports **continuationState, + uint32_t *flags, + char **creds) +{ + // ChallengeReceived must have been called previously. + nsIAuthModule *module = (nsIAuthModule *) *continuationState; + NS_ENSURE_TRUE(module, NS_ERROR_NOT_INITIALIZED); + + *flags = USING_INTERNAL_IDENTITY; + + LOG(("nsHttpNegotiateAuth::GenerateCredentials() [challenge=%s]\n", challenge)); + + NS_ASSERTION(creds, "null param"); + +#ifdef DEBUG + bool isGssapiAuth = + !PL_strncasecmp(challenge, kNegotiate, kNegotiateLen); + NS_ASSERTION(isGssapiAuth, "Unexpected challenge"); +#endif + + // + // If the "Negotiate:" header had some data associated with it, + // that data should be used as the input to this call. This may + // be a continuation of an earlier call because GSSAPI authentication + // often takes multiple round-trips to complete depending on the + // context flags given. We want to use MUTUAL_AUTHENTICATION which + // generally *does* require multiple round-trips. Don't assume + // auth can be completed in just 1 call. + // + unsigned int len = strlen(challenge); + + void *inToken, *outToken; + uint32_t inTokenLen, outTokenLen; + + if (len > kNegotiateLen) { + challenge += kNegotiateLen; + while (*challenge == ' ') + challenge++; + len = strlen(challenge); + + // strip off any padding (see bug 230351) + while (challenge[len - 1] == '=') + len--; + + // + // Decode the response that followed the "Negotiate" token + // + nsresult rv = + Base64Decode(challenge, len, (char**)&inToken, &inTokenLen); + + if (NS_FAILED(rv)) { + return rv; + } + } + else { + // + // Initializing, don't use an input token. + // + inToken = nullptr; + inTokenLen = 0; + } + + nsresult rv = module->GetNextToken(inToken, inTokenLen, &outToken, &outTokenLen); + + free(inToken); + + if (NS_FAILED(rv)) + return rv; + + if (outTokenLen == 0) { + LOG((" No output token to send, exiting")); + return NS_ERROR_FAILURE; + } + + // + // base64 encode the output token. + // + char *encoded_token = PL_Base64Encode((char *)outToken, outTokenLen, nullptr); + + free(outToken); + + if (!encoded_token) + return NS_ERROR_OUT_OF_MEMORY; + + LOG((" Sending a token of length %d\n", outTokenLen)); + + // allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0") + const int bufsize = kNegotiateLen + 1 + strlen(encoded_token) + 1; + *creds = (char *) moz_xmalloc(bufsize); + if (MOZ_UNLIKELY(!*creds)) + rv = NS_ERROR_OUT_OF_MEMORY; + else + snprintf(*creds, bufsize, "%s %s", kNegotiate, encoded_token); + + PR_Free(encoded_token); + return rv; +} + +bool +nsHttpNegotiateAuth::TestBoolPref(const char *pref) +{ + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (!prefs) + return false; + + bool val; + nsresult rv = prefs->GetBoolPref(pref, &val); + if (NS_FAILED(rv)) + return false; + + return val; +} + +bool +nsHttpNegotiateAuth::TestNonFqdn(nsIURI *uri) +{ + nsAutoCString host; + PRNetAddr addr; + + if (!TestBoolPref(kNegotiateAuthAllowNonFqdn)) + return false; + + if (NS_FAILED(uri->GetAsciiHost(host))) + return false; + + // return true if host does not contain a dot and is not an ip address + return !host.IsEmpty() && !host.Contains('.') && + PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS; +} + +bool +nsHttpNegotiateAuth::TestPref(nsIURI *uri, const char *pref) +{ + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (!prefs) + return false; + + nsAutoCString scheme, host; + int32_t port; + + if (NS_FAILED(uri->GetScheme(scheme))) + return false; + if (NS_FAILED(uri->GetAsciiHost(host))) + return false; + if (NS_FAILED(uri->GetPort(&port))) + return false; + + char *hostList; + if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList) + return false; + + // pseudo-BNF + // ---------- + // + // url-list base-url ( base-url "," LWS )* + // base-url ( scheme-part | host-part | scheme-part host-part ) + // scheme-part scheme "://" + // host-part host [":" port] + // + // for example: + // "https://, http://office.foo.com" + // + + char *start = hostList, *end; + for (;;) { + // skip past any whitespace + while (*start == ' ' || *start == '\t') + ++start; + end = strchr(start, ','); + if (!end) + end = start + strlen(start); + if (start == end) + break; + if (MatchesBaseURI(scheme, host, port, start, end)) + return true; + if (*end == '\0') + break; + start = end + 1; + } + + free(hostList); + return false; +} + +bool +nsHttpNegotiateAuth::MatchesBaseURI(const nsCSubstring &matchScheme, + const nsCSubstring &matchHost, + int32_t matchPort, + const char *baseStart, + const char *baseEnd) +{ + // check if scheme://host:port matches baseURI + + // parse the base URI + const char *hostStart, *schemeEnd = strstr(baseStart, "://"); + if (schemeEnd) { + // the given scheme must match the parsed scheme exactly + if (!matchScheme.Equals(Substring(baseStart, schemeEnd))) + return false; + hostStart = schemeEnd + 3; + } + else + hostStart = baseStart; + + // XXX this does not work for IPv6-literals + const char *hostEnd = strchr(hostStart, ':'); + if (hostEnd && hostEnd < baseEnd) { + // the given port must match the parsed port exactly + int port = atoi(hostEnd + 1); + if (matchPort != (int32_t) port) + return false; + } + else + hostEnd = baseEnd; + + + // if we didn't parse out a host, then assume we got a match. + if (hostStart == hostEnd) + return true; + + uint32_t hostLen = hostEnd - hostStart; + + // matchHost must either equal host or be a subdomain of host + if (matchHost.Length() < hostLen) + return false; + + const char *end = matchHost.EndReading(); + if (PL_strncasecmp(end - hostLen, hostStart, hostLen) == 0) { + // if matchHost ends with host from the base URI, then make sure it is + // either an exact match, or prefixed with a dot. we don't want + // "foobar.com" to match "bar.com" + if (matchHost.Length() == hostLen || + *(end - hostLen) == '.' || + *(end - hostLen - 1) == '.') + return true; + } + + return false; +} diff --git a/extensions/auth/nsHttpNegotiateAuth.h b/extensions/auth/nsHttpNegotiateAuth.h new file mode 100644 index 000000000..4c84616d8 --- /dev/null +++ b/extensions/auth/nsHttpNegotiateAuth.h @@ -0,0 +1,44 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsHttpNegotiateAuth_h__ +#define nsHttpNegotiateAuth_h__ + +#include "nsIHttpAuthenticator.h" +#include "nsIURI.h" +#include "nsSubstring.h" +#include "mozilla/Attributes.h" +#include "mozilla/LazyIdleThread.h" + +// The nsHttpNegotiateAuth class provides responses for the GSS-API Negotiate method +// as specified by Microsoft in draft-brezak-spnego-http-04.txt + +class nsHttpNegotiateAuth final : public nsIHttpAuthenticator +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIHTTPAUTHENTICATOR + +private: + ~nsHttpNegotiateAuth() {} + + // returns the value of the given boolean pref + bool TestBoolPref(const char *pref); + + // tests if the host part of an uri is fully qualified + bool TestNonFqdn(nsIURI *uri); + + // returns true if URI is accepted by the list of hosts in the pref + bool TestPref(nsIURI *, const char *pref); + + bool MatchesBaseURI(const nsCSubstring &scheme, + const nsCSubstring &host, + int32_t port, + const char *baseStart, + const char *baseEnd); + // Thread for GenerateCredentialsAsync + RefPtr mNegotiateThread; +}; +#endif /* nsHttpNegotiateAuth_h__ */ diff --git a/extensions/build.mk b/extensions/build.mk new file mode 100644 index 000000000..e3b0db93d --- /dev/null +++ b/extensions/build.mk @@ -0,0 +1,18 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +ifneq (extensions,$(MOZ_BUILD_APP)) +$(error This file shouldn't be included without --enable-application=extensions) +endif + +ifndef MOZ_EXTENSIONS +$(error You forgot to set --enable-extensions) +endif + +TIERS += app +tier_app_dirs += extensions + +installer: + @echo Check each extension for an installer. + @exit 1 diff --git a/extensions/confvars.sh b/extensions/confvars.sh new file mode 100755 index 000000000..a53faf33d --- /dev/null +++ b/extensions/confvars.sh @@ -0,0 +1,8 @@ +#! /bin/sh +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOZ_APP_NAME=mozilla +MOZ_APP_DISPLAYNAME=Mozilla +MOZ_APP_VERSION=$MOZILLA_VERSION diff --git a/extensions/cookie/moz.build b/extensions/cookie/moz.build new file mode 100644 index 000000000..36de41f95 --- /dev/null +++ b/extensions/cookie/moz.build @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +TEST_DIRS += ['test'] + +XPIDL_SOURCES += [ + 'nsICookieAcceptDialog.idl', + 'nsICookiePromptService.idl', +] + +XPIDL_MODULE = 'cookie' + +UNIFIED_SOURCES += [ + 'nsCookieModule.cpp', + 'nsCookiePermission.cpp', + 'nsCookiePromptService.cpp', + 'nsPermission.cpp', + 'nsPermissionManager.cpp', + 'nsPopupWindowManager.cpp', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/extensions/cookie/nsCookieModule.cpp b/extensions/cookie/nsCookieModule.cpp new file mode 100644 index 000000000..1157e0c5d --- /dev/null +++ b/extensions/cookie/nsCookieModule.cpp @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "mozilla/ModuleUtils.h" +#include "nsIServiceManager.h" +#include "nsPermissionManager.h" +#include "nsPopupWindowManager.h" +#include "nsICategoryManager.h" +#include "nsCookiePromptService.h" +#include "nsCookiePermission.h" +#include "nsXPIDLString.h" + +// Define the constructor function for the objects +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPermissionManager, + nsPermissionManager::GetXPCOMSingleton) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPopupWindowManager, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePermission) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePromptService) + +NS_DEFINE_NAMED_CID(NS_PERMISSIONMANAGER_CID); +NS_DEFINE_NAMED_CID(NS_POPUPWINDOWMANAGER_CID); +NS_DEFINE_NAMED_CID(NS_COOKIEPROMPTSERVICE_CID); +NS_DEFINE_NAMED_CID(NS_COOKIEPERMISSION_CID); + + +static const mozilla::Module::CIDEntry kCookieCIDs[] = { + { &kNS_PERMISSIONMANAGER_CID, false, nullptr, nsIPermissionManagerConstructor }, + { &kNS_POPUPWINDOWMANAGER_CID, false, nullptr, nsPopupWindowManagerConstructor }, + { &kNS_COOKIEPROMPTSERVICE_CID, false, nullptr, nsCookiePromptServiceConstructor }, + { &kNS_COOKIEPERMISSION_CID, false, nullptr, nsCookiePermissionConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kCookieContracts[] = { + { NS_PERMISSIONMANAGER_CONTRACTID, &kNS_PERMISSIONMANAGER_CID }, + { NS_POPUPWINDOWMANAGER_CONTRACTID, &kNS_POPUPWINDOWMANAGER_CID }, + { NS_COOKIEPROMPTSERVICE_CONTRACTID, &kNS_COOKIEPROMPTSERVICE_CID }, + { NS_COOKIEPERMISSION_CONTRACTID, &kNS_COOKIEPERMISSION_CID }, + { nullptr } +}; + +static const mozilla::Module kCookieModule = { + mozilla::Module::kVersion, + kCookieCIDs, + kCookieContracts +}; + +NSMODULE_DEFN(nsCookieModule) = &kCookieModule; diff --git a/extensions/cookie/nsCookiePermission.cpp b/extensions/cookie/nsCookiePermission.cpp new file mode 100644 index 000000000..7dfc943f0 --- /dev/null +++ b/extensions/cookie/nsCookiePermission.cpp @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCookiePermission.h" + +#include "mozIThirdPartyUtil.h" +#include "nsICookie2.h" +#include "nsIServiceManager.h" +#include "nsICookiePromptService.h" +#include "nsICookieManager2.h" +#include "nsNetUtil.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIProtocolHandler.h" +#include "nsIURI.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIChannel.h" +#include "nsIHttpChannelInternal.h" +#include "nsIDOMWindow.h" +#include "nsIPrincipal.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsILoadContext.h" +#include "nsIScriptObjectPrincipal.h" +#include "nsNetCID.h" +#include "prtime.h" + +/**************************************************************** + ************************ nsCookiePermission ******************** + ****************************************************************/ + +// values for mCookiesLifetimePolicy +// 0 == accept normally +// 1 == ask before accepting, no more supported, treated like ACCEPT_NORMALLY (Bug 606655). +// 2 == downgrade to session +// 3 == limit lifetime to N days +static const uint32_t ACCEPT_NORMALLY = 0; +static const uint32_t ASK_BEFORE_ACCEPT = 1; +static const uint32_t ACCEPT_SESSION = 2; +static const uint32_t ACCEPT_FOR_N_DAYS = 3; + +static const bool kDefaultPolicy = true; +static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy"; +static const char kCookiesLifetimeDays[] = "network.cookie.lifetime.days"; + +static const char kCookiesPrefsMigrated[] = "network.cookie.prefsMigrated"; +// obsolete pref names for migration +static const char kCookiesLifetimeEnabled[] = "network.cookie.lifetime.enabled"; +static const char kCookiesLifetimeBehavior[] = "network.cookie.lifetime.behavior"; + +static const char kPermissionType[] = "cookie"; + +NS_IMPL_ISUPPORTS(nsCookiePermission, + nsICookiePermission, + nsIObserver) + +bool +nsCookiePermission::Init() +{ + // Initialize nsIPermissionManager and fetch relevant prefs. This is only + // required for some methods on nsICookiePermission, so it should be done + // lazily. + nsresult rv; + mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); + if (NS_FAILED(rv)) return false; + mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv); + if (NS_FAILED(rv)) return false; + + // failure to access the pref service is non-fatal... + nsCOMPtr prefBranch = + do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefBranch) { + prefBranch->AddObserver(kCookiesLifetimePolicy, this, false); + prefBranch->AddObserver(kCookiesLifetimeDays, this, false); + PrefChanged(prefBranch, nullptr); + + // migration code for original cookie prefs + bool migrated; + rv = prefBranch->GetBoolPref(kCookiesPrefsMigrated, &migrated); + if (NS_FAILED(rv) || !migrated) { + bool lifetimeEnabled = false; + prefBranch->GetBoolPref(kCookiesLifetimeEnabled, &lifetimeEnabled); + + // if they're limiting lifetime, use the appropriate limited lifetime pref + if (lifetimeEnabled) { + int32_t lifetimeBehavior; + prefBranch->GetIntPref(kCookiesLifetimeBehavior, &lifetimeBehavior); + if (lifetimeBehavior) + prefBranch->SetIntPref(kCookiesLifetimePolicy, ACCEPT_FOR_N_DAYS); + else + prefBranch->SetIntPref(kCookiesLifetimePolicy, ACCEPT_SESSION); + } + prefBranch->SetBoolPref(kCookiesPrefsMigrated, true); + } + } + + return true; +} + +void +nsCookiePermission::PrefChanged(nsIPrefBranch *aPrefBranch, + const char *aPref) +{ + int32_t val; + +#define PREF_CHANGED(_P) (!aPref || !strcmp(aPref, _P)) + + if (PREF_CHANGED(kCookiesLifetimePolicy) && + NS_SUCCEEDED(aPrefBranch->GetIntPref(kCookiesLifetimePolicy, &val))) { + if (val != static_cast(ACCEPT_SESSION) && val != static_cast(ACCEPT_FOR_N_DAYS)) { + val = ACCEPT_NORMALLY; + } + mCookiesLifetimePolicy = val; + } + + if (PREF_CHANGED(kCookiesLifetimeDays) && + NS_SUCCEEDED(aPrefBranch->GetIntPref(kCookiesLifetimeDays, &val))) + // save cookie lifetime in seconds instead of days + mCookiesLifetimeSec = (int64_t)val * 24 * 60 * 60; +} + +NS_IMETHODIMP +nsCookiePermission::SetAccess(nsIURI *aURI, + nsCookieAccess aAccess) +{ + // Lazily initialize ourselves + if (!EnsureInitialized()) + return NS_ERROR_UNEXPECTED; + + // + // NOTE: nsCookieAccess values conveniently match up with + // the permission codes used by nsIPermissionManager. + // this is nice because it avoids conversion code. + // + return mPermMgr->Add(aURI, kPermissionType, aAccess, + nsIPermissionManager::EXPIRE_NEVER, 0); +} + +NS_IMETHODIMP +nsCookiePermission::CanAccess(nsIURI *aURI, + nsIChannel *aChannel, + nsCookieAccess *aResult) +{ + // Check this protocol doesn't allow cookies + bool hasFlags; + nsresult rv = + NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS, + &hasFlags); + if (NS_FAILED(rv) || hasFlags) { + *aResult = ACCESS_DENY; + return NS_OK; + } + + // Lazily initialize ourselves + if (!EnsureInitialized()) + return NS_ERROR_UNEXPECTED; + + // finally, check with permission manager... + rv = mPermMgr->TestPermission(aURI, kPermissionType, (uint32_t *) aResult); + if (NS_SUCCEEDED(rv)) { + if (*aResult == nsICookiePermission::ACCESS_SESSION) { + *aResult = nsICookiePermission::ACCESS_ALLOW; + } + } + + return rv; +} + +NS_IMETHODIMP +nsCookiePermission::CanSetCookie(nsIURI *aURI, + nsIChannel *aChannel, + nsICookie2 *aCookie, + bool *aIsSession, + int64_t *aExpiry, + bool *aResult) +{ + NS_ASSERTION(aURI, "null uri"); + + *aResult = kDefaultPolicy; + + // Lazily initialize ourselves + if (!EnsureInitialized()) + return NS_ERROR_UNEXPECTED; + + uint32_t perm; + mPermMgr->TestPermission(aURI, kPermissionType, &perm); + bool isThirdParty = false; + switch (perm) { + case nsICookiePermission::ACCESS_SESSION: + *aIsSession = true; + MOZ_FALLTHROUGH; + + case nsICookiePermission::ACCESS_ALLOW: + *aResult = true; + break; + + case nsICookiePermission::ACCESS_DENY: + *aResult = false; + break; + + case nsICookiePermission::ACCESS_ALLOW_FIRST_PARTY_ONLY: + mThirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &isThirdParty); + // If it's third party, we can't set the cookie + if (isThirdParty) + *aResult = false; + break; + + case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY: + mThirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &isThirdParty); + // If it's third party, check whether cookies are already set + if (isThirdParty) { + nsresult rv; + nsCOMPtr cookieManager = do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + *aResult = false; + break; + } + uint32_t priorCookieCount = 0; + nsAutoCString hostFromURI; + aURI->GetHost(hostFromURI); + cookieManager->CountCookiesFromHost(hostFromURI, &priorCookieCount); + *aResult = priorCookieCount != 0; + } + break; + + default: + // the permission manager has nothing to say about this cookie - + // so, we apply the default prefs to it. + NS_ASSERTION(perm == nsIPermissionManager::UNKNOWN_ACTION, "unknown permission"); + + // now we need to figure out what type of accept policy we're dealing with + // if we accept cookies normally, just bail and return + if (mCookiesLifetimePolicy == ACCEPT_NORMALLY) { + *aResult = true; + return NS_OK; + } + + // declare this here since it'll be used in all of the remaining cases + int64_t currentTime = PR_Now() / PR_USEC_PER_SEC; + int64_t delta = *aExpiry - currentTime; + + // We are accepting the cookie, but, + // if it's not a session cookie, we may have to limit its lifetime. + if (!*aIsSession && delta > 0) { + if (mCookiesLifetimePolicy == ACCEPT_SESSION) { + // limit lifetime to session + *aIsSession = true; + } else if (delta > mCookiesLifetimeSec) { + // limit lifetime to specified time + *aExpiry = currentTime + mCookiesLifetimeSec; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCookiePermission::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + nsCOMPtr prefBranch = do_QueryInterface(aSubject); + NS_ASSERTION(!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic), + "unexpected topic - we only deal with pref changes!"); + + if (prefBranch) + PrefChanged(prefBranch, NS_LossyConvertUTF16toASCII(aData).get()); + return NS_OK; +} diff --git a/extensions/cookie/nsCookiePermission.h b/extensions/cookie/nsCookiePermission.h new file mode 100644 index 000000000..d683f206a --- /dev/null +++ b/extensions/cookie/nsCookiePermission.h @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsCookiePermission_h__ +#define nsCookiePermission_h__ + +#include "nsICookiePermission.h" +#include "nsIPermissionManager.h" +#include "nsIObserver.h" +#include "nsCOMPtr.h" +#include "mozIThirdPartyUtil.h" + +class nsIPrefBranch; + +class nsCookiePermission : public nsICookiePermission + , public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOOKIEPERMISSION + NS_DECL_NSIOBSERVER + + nsCookiePermission() + : mCookiesLifetimeSec(INT64_MAX) + , mCookiesLifetimePolicy(0) // ACCEPT_NORMALLY + {} + + bool Init(); + void PrefChanged(nsIPrefBranch *, const char *); + +private: + virtual ~nsCookiePermission() {} + + bool EnsureInitialized() { return (mPermMgr != nullptr && mThirdPartyUtil != nullptr) || Init(); }; + + nsCOMPtr mPermMgr; + nsCOMPtr mThirdPartyUtil; + + int64_t mCookiesLifetimeSec; // lifetime limit specified in seconds + uint8_t mCookiesLifetimePolicy; // pref for how long cookies are stored +}; + +// {EF565D0A-AB9A-4A13-9160-0644CDFD859A} +#define NS_COOKIEPERMISSION_CID \ + {0xEF565D0A, 0xAB9A, 0x4A13, {0x91, 0x60, 0x06, 0x44, 0xcd, 0xfd, 0x85, 0x9a }} + +#endif diff --git a/extensions/cookie/nsCookiePromptService.cpp b/extensions/cookie/nsCookiePromptService.cpp new file mode 100644 index 000000000..258193ab8 --- /dev/null +++ b/extensions/cookie/nsCookiePromptService.cpp @@ -0,0 +1,101 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "nsCookiePromptService.h" +#include "nsICookie.h" +#include "nsICookieAcceptDialog.h" +#include "nsIDOMWindow.h" +#include "nsPIDOMWindow.h" +#include "nsIWindowWatcher.h" +#include "nsIServiceManager.h" +#include "nsString.h" +#include "nsIDialogParamBlock.h" +#include "nsIMutableArray.h" +#include "mozilla/dom/ScriptSettings.h" + +/**************************************************************** + ************************ nsCookiePromptService ***************** + ****************************************************************/ + +NS_IMPL_ISUPPORTS(nsCookiePromptService, nsICookiePromptService) + +nsCookiePromptService::nsCookiePromptService() { +} + +nsCookiePromptService::~nsCookiePromptService() { +} + +NS_IMETHODIMP +nsCookiePromptService::CookieDialog(mozIDOMWindowProxy *aParent, + nsICookie *aCookie, + const nsACString &aHostname, + int32_t aCookiesFromHost, + bool aChangingCookie, + bool *aRememberDecision, + int32_t *aAccept) +{ + nsresult rv; + + nsCOMPtr block = do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID,&rv); + if (NS_FAILED(rv)) return rv; + + block->SetInt(nsICookieAcceptDialog::ACCEPT_COOKIE, 1); + block->SetString(nsICookieAcceptDialog::HOSTNAME, NS_ConvertUTF8toUTF16(aHostname).get()); + block->SetInt(nsICookieAcceptDialog::COOKIESFROMHOST, aCookiesFromHost); + block->SetInt(nsICookieAcceptDialog::CHANGINGCOOKIE, aChangingCookie ? 1 : 0); + + nsCOMPtr objects = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = objects->AppendElement(aCookie, false); + if (NS_FAILED(rv)) return rv; + + block->SetObjects(objects); + + nsCOMPtr wwatcher = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr arguments = do_QueryInterface(block); + + nsCOMPtr parent(aParent); + if (!parent) // if no parent provided, consult the window watcher: + wwatcher->GetActiveWindow(getter_AddRefs(parent)); + + if (parent) { + auto* privateParent = nsPIDOMWindowOuter::From(parent); + if (privateParent) + privateParent = privateParent->GetPrivateRoot(); + parent = privateParent; + } + + // We're opening a chrome window and passing in a nsIDialogParamBlock. Setting + // the nsIDialogParamBlock as the .arguments property on the chrome window + // requires system principals on the stack, so we use an AutoNoJSAPI for that. + mozilla::dom::AutoNoJSAPI nojsapi; + + // The cookie dialog will be modal for the root chrome window rather than the + // tab containing the permission-requesting page. This removes confusion + // about which monitor is displaying the dialog (see bug 470356), but also + // avoids unwanted tab switches (see bug 405239). + nsCOMPtr dialog; + rv = wwatcher->OpenWindow(parent, "chrome://cookie/content/cookieAcceptDialog.xul", "_blank", + "centerscreen,chrome,modal,titlebar", arguments, + getter_AddRefs(dialog)); + + if (NS_FAILED(rv)) return rv; + + // get back output parameters + int32_t tempValue; + block->GetInt(nsICookieAcceptDialog::ACCEPT_COOKIE, &tempValue); + *aAccept = tempValue; + + // GetInt returns a int32_t; we need to sanitize it into bool + block->GetInt(nsICookieAcceptDialog::REMEMBER_DECISION, &tempValue); + *aRememberDecision = (tempValue == 1); + + return rv; +} + diff --git a/extensions/cookie/nsCookiePromptService.h b/extensions/cookie/nsCookiePromptService.h new file mode 100644 index 000000000..a6e10fce4 --- /dev/null +++ b/extensions/cookie/nsCookiePromptService.h @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsCookiePromptService_h__ +#define nsCookiePromptService_h__ + +#include "nsICookiePromptService.h" + +class nsCookiePromptService : public nsICookiePromptService { + + virtual ~nsCookiePromptService(); + +public: + + nsCookiePromptService(); + + NS_DECL_NSICOOKIEPROMPTSERVICE + NS_DECL_ISUPPORTS + +private: + +}; + +// {CE002B28-92B7-4701-8621-CC925866FB87} +#define NS_COOKIEPROMPTSERVICE_CID \ + {0xCE002B28, 0x92B7, 0x4701, {0x86, 0x21, 0xCC, 0x92, 0x58, 0x66, 0xFB, 0x87}} + +#endif diff --git a/extensions/cookie/nsICookieAcceptDialog.idl b/extensions/cookie/nsICookieAcceptDialog.idl new file mode 100644 index 000000000..b02339780 --- /dev/null +++ b/extensions/cookie/nsICookieAcceptDialog.idl @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +/* + + This file contains some constants for the cookie accept dialog + + */ + +[scriptable, uuid(3F2F0D2C-BDEA-4B5A-AFC6-FCF18F66B97E)] +interface nsICookieAcceptDialog: nsISupports { + + const short ACCEPT_COOKIE=0; + const short REMEMBER_DECISION=1; + const short HOSTNAME=2; + const short COOKIESFROMHOST=3; + const short CHANGINGCOOKIE=4; +}; diff --git a/extensions/cookie/nsICookiePromptService.idl b/extensions/cookie/nsICookiePromptService.idl new file mode 100644 index 000000000..163da6a26 --- /dev/null +++ b/extensions/cookie/nsICookiePromptService.idl @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +/** + * An interface to open a dialog to ask to permission to accept the cookie. + */ + +interface mozIDOMWindowProxy; +interface nsICookie; + +[scriptable, uuid(65ca07c3-6241-4de1-bf41-3336470499db)] +interface nsICookiePromptService : nsISupports +{ + const uint32_t DENY_COOKIE = 0; + const uint32_t ACCEPT_COOKIE = 1; + const uint32_t ACCEPT_SESSION_COOKIE = 2; + + /* Open a dialog that asks for permission to accept a cookie + * + * @param parent + * @param cookie + * @param hostname the host that wants to set the cookie, + * not the domain: part of the cookie + * @param cookiesFromHost the number of cookies there are already for this host + * @param changingCookie are we changing this cookie? + * @param rememberDecision should we set the matching permission for this host? + * @returns 0 == deny cookie + * 1 == accept cookie + * 2 == accept cookie for current session + */ + + long cookieDialog(in mozIDOMWindowProxy parent, + in nsICookie cookie, + in ACString hostname, + in long cookiesFromHost, + in boolean changingCookie, + out boolean rememberDecision); +}; + +%{C++ +#define NS_COOKIEPROMPTSERVICE_CONTRACTID "@mozilla.org/embedcomp/cookieprompt-service;1" +%} diff --git a/extensions/cookie/nsPermission.cpp b/extensions/cookie/nsPermission.cpp new file mode 100644 index 000000000..3d1eb140a --- /dev/null +++ b/extensions/cookie/nsPermission.cpp @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPermission.h" +#include "nsContentUtils.h" +#include "nsIClassInfoImpl.h" +#include "nsIEffectiveTLDService.h" +#include "mozilla/BasePrincipal.h" + +// nsPermission Implementation + +NS_IMPL_CLASSINFO(nsPermission, nullptr, 0, {0}) +NS_IMPL_ISUPPORTS_CI(nsPermission, nsIPermission) + +nsPermission::nsPermission(nsIPrincipal* aPrincipal, + const nsACString &aType, + uint32_t aCapability, + uint32_t aExpireType, + int64_t aExpireTime) + : mPrincipal(aPrincipal) + , mType(aType) + , mCapability(aCapability) + , mExpireType(aExpireType) + , mExpireTime(aExpireTime) +{ +} + +already_AddRefed +nsPermission::Create(nsIPrincipal* aPrincipal, + const nsACString &aType, + uint32_t aCapability, + uint32_t aExpireType, + int64_t aExpireTime) +{ + NS_ENSURE_TRUE(aPrincipal, nullptr); + nsCOMPtr principal = + mozilla::BasePrincipal::Cast(aPrincipal)->CloneStrippingUserContextIdAndFirstPartyDomain(); + + NS_ENSURE_TRUE(principal, nullptr); + + RefPtr permission = + new nsPermission(principal, aType, aCapability, aExpireType, aExpireTime); + return permission.forget(); +} + +NS_IMETHODIMP +nsPermission::GetPrincipal(nsIPrincipal** aPrincipal) +{ + nsCOMPtr copy = mPrincipal; + copy.forget(aPrincipal); + return NS_OK; +} + +NS_IMETHODIMP +nsPermission::GetType(nsACString &aType) +{ + aType = mType; + return NS_OK; +} + +NS_IMETHODIMP +nsPermission::GetCapability(uint32_t *aCapability) +{ + *aCapability = mCapability; + return NS_OK; +} + +NS_IMETHODIMP +nsPermission::GetExpireType(uint32_t *aExpireType) +{ + *aExpireType = mExpireType; + return NS_OK; +} + +NS_IMETHODIMP +nsPermission::GetExpireTime(int64_t *aExpireTime) +{ + *aExpireTime = mExpireTime; + return NS_OK; +} + +NS_IMETHODIMP +nsPermission::Matches(nsIPrincipal* aPrincipal, bool aExactHost, bool* aMatches) +{ + NS_ENSURE_ARG_POINTER(aPrincipal); + NS_ENSURE_ARG_POINTER(aMatches); + + *aMatches = false; + + nsCOMPtr principal = + mozilla::BasePrincipal::Cast(aPrincipal)->CloneStrippingUserContextIdAndFirstPartyDomain(); + + if (!principal) { + *aMatches = false; + return NS_OK; + } + + // If the principals are equal, then they match. + if (mPrincipal->Equals(principal)) { + *aMatches = true; + return NS_OK; + } + + // If we are matching with an exact host, we're done now - the permissions don't match + // otherwise, we need to start comparing subdomains! + if (aExactHost) { + return NS_OK; + } + + // Compare their OriginAttributes + const mozilla::PrincipalOriginAttributes& theirAttrs = mozilla::BasePrincipal::Cast(principal)->OriginAttributesRef(); + const mozilla::PrincipalOriginAttributes& ourAttrs = mozilla::BasePrincipal::Cast(mPrincipal)->OriginAttributesRef(); + + if (theirAttrs != ourAttrs) { + return NS_OK; + } + + nsCOMPtr theirURI; + nsresult rv = principal->GetURI(getter_AddRefs(theirURI)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr ourURI; + rv = mPrincipal->GetURI(getter_AddRefs(ourURI)); + NS_ENSURE_SUCCESS(rv, rv); + + // Compare schemes + nsAutoCString theirScheme; + rv = theirURI->GetScheme(theirScheme); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString ourScheme; + rv = ourURI->GetScheme(ourScheme); + NS_ENSURE_SUCCESS(rv, rv); + + if (theirScheme != ourScheme) { + return NS_OK; + } + + // Compare ports + int32_t theirPort; + rv = theirURI->GetPort(&theirPort); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t ourPort; + rv = ourURI->GetPort(&ourPort); + NS_ENSURE_SUCCESS(rv, rv); + + if (theirPort != ourPort) { + return NS_OK; + } + + // Check if the host or any subdomain of their host matches. + nsAutoCString theirHost; + rv = theirURI->GetHost(theirHost); + if (NS_FAILED(rv) || theirHost.IsEmpty()) { + return NS_OK; + } + + nsAutoCString ourHost; + rv = ourURI->GetHost(ourHost); + if (NS_FAILED(rv) || ourHost.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + if (!tldService) { + NS_ERROR("Should have a tld service!"); + return NS_ERROR_FAILURE; + } + + // This loop will not loop forever, as GetNextSubDomain will eventually fail + // with NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS. + while (theirHost != ourHost) { + rv = tldService->GetNextSubDomain(theirHost, theirHost); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { + return NS_OK; + } else { + return rv; + } + } + } + + *aMatches = true; + return NS_OK; +} + +NS_IMETHODIMP +nsPermission::MatchesURI(nsIURI* aURI, bool aExactHost, bool* aMatches) +{ + NS_ENSURE_ARG_POINTER(aURI); + + mozilla::PrincipalOriginAttributes attrs; + nsCOMPtr principal = mozilla::BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); + + return Matches(principal, aExactHost, aMatches); +} diff --git a/extensions/cookie/nsPermission.h b/extensions/cookie/nsPermission.h new file mode 100644 index 000000000..6beb8aef4 --- /dev/null +++ b/extensions/cookie/nsPermission.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsPermission_h__ +#define nsPermission_h__ + +#include "nsIPermission.h" +#include "nsString.h" + +//////////////////////////////////////////////////////////////////////////////// + +class nsPermission : public nsIPermission +{ +public: + // nsISupports + NS_DECL_ISUPPORTS + NS_DECL_NSIPERMISSION + + static already_AddRefed Create(nsIPrincipal* aPrincipal, + const nsACString &aType, + uint32_t aCapability, + uint32_t aExpireType, + int64_t aExpireTime); + +protected: + nsPermission(nsIPrincipal* aPrincipal, + const nsACString &aType, + uint32_t aCapability, + uint32_t aExpireType, + int64_t aExpireTime); + + virtual ~nsPermission() {}; + + nsCOMPtr mPrincipal; + nsCString mType; + uint32_t mCapability; + uint32_t mExpireType; + int64_t mExpireTime; +}; + +#endif // nsPermission_h__ diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp new file mode 100644 index 000000000..d3696dd94 --- /dev/null +++ b/extensions/cookie/nsPermissionManager.cpp @@ -0,0 +1,2918 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Attributes.h" +#include "mozilla/DebugOnly.h" + +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/Services.h" +#include "mozilla/Unused.h" +#include "nsPermissionManager.h" +#include "nsPermission.h" +#include "nsCRT.h" +#include "nsNetUtil.h" +#include "nsCOMArray.h" +#include "nsArrayEnumerator.h" +#include "nsTArray.h" +#include "nsReadableUtils.h" +#include "nsILineInputStream.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsDirectoryServiceDefs.h" +#include "prprf.h" +#include "mozilla/storage.h" +#include "mozilla/Attributes.h" +#include "nsXULAppAPI.h" +#include "nsIPrincipal.h" +#include "nsContentUtils.h" +#include "nsIScriptSecurityManager.h" +#include "nsIAppsService.h" +#include "mozIApplication.h" +#include "nsIEffectiveTLDService.h" +#include "nsPIDOMWindow.h" +#include "nsIDocument.h" +#include "mozilla/net/NeckoMessageUtils.h" +#include "mozilla/Preferences.h" +#include "nsReadLine.h" +#include "mozilla/Telemetry.h" +#include "nsIConsoleService.h" +#include "nsINavHistoryService.h" +#include "nsToolkitCompsCID.h" +#include "nsIObserverService.h" + +static nsPermissionManager *gPermissionManager = nullptr; + +using mozilla::dom::ContentParent; +using mozilla::dom::ContentChild; +using mozilla::Unused; // ha! + +static bool +IsChildProcess() +{ + return XRE_IsContentProcess(); +} + +/** + * @returns The child process object, or if we are not in the child + * process, nullptr. + */ +static ContentChild* +ChildProcess() +{ + if (IsChildProcess()) { + ContentChild* cpc = ContentChild::GetSingleton(); + if (!cpc) + NS_RUNTIMEABORT("Content Process is nullptr!"); + return cpc; + } + + return nullptr; +} + +static void +LogToConsole(const nsAString& aMsg) +{ + nsCOMPtr console(do_GetService("@mozilla.org/consoleservice;1")); + if (!console) { + NS_WARNING("Failed to log message to console."); + return; + } + + nsAutoString msg(aMsg); + console->LogStringMessage(msg.get()); +} + +#define ENSURE_NOT_CHILD_PROCESS_(onError) \ + PR_BEGIN_MACRO \ + if (IsChildProcess()) { \ + NS_ERROR("Cannot perform action in content process!"); \ + onError \ + } \ + PR_END_MACRO + +#define ENSURE_NOT_CHILD_PROCESS \ + ENSURE_NOT_CHILD_PROCESS_({ return NS_ERROR_NOT_AVAILABLE; }) + +#define ENSURE_NOT_CHILD_PROCESS_NORET \ + ENSURE_NOT_CHILD_PROCESS_(;) + +//////////////////////////////////////////////////////////////////////////////// + +namespace { + +nsresult +GetOriginFromPrincipal(nsIPrincipal* aPrincipal, nsACString& aOrigin) +{ + nsresult rv = aPrincipal->GetOriginNoSuffix(aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString suffix; + rv = aPrincipal->GetOriginSuffix(suffix); + NS_ENSURE_SUCCESS(rv, rv); + + mozilla::PrincipalOriginAttributes attrs; + if (!attrs.PopulateFromSuffix(suffix)) { + return NS_ERROR_FAILURE; + } + + // mPrivateBrowsingId must be set to false because PermissionManager is not supposed to have + // any knowledge of private browsing. Allowing it to be true changes the suffix being hashed. + attrs.mPrivateBrowsingId = 0; + + // Disable userContext and firstParty isolation for permissions. + attrs.StripUserContextIdAndFirstPartyDomain(); + + attrs.CreateSuffix(suffix); + aOrigin.Append(suffix); + return NS_OK; +} + +nsresult +GetPrincipalFromOrigin(const nsACString& aOrigin, nsIPrincipal** aPrincipal) +{ + nsAutoCString originNoSuffix; + mozilla::PrincipalOriginAttributes attrs; + if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) { + return NS_ERROR_FAILURE; + } + + // Disable userContext and firstParty isolation for permissions. + attrs.StripUserContextIdAndFirstPartyDomain(); + + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs); + principal.forget(aPrincipal); + return NS_OK; +} + +nsresult +GetPrincipal(nsIURI* aURI, uint32_t aAppId, bool aIsInIsolatedMozBrowserElement, nsIPrincipal** aPrincipal) +{ + mozilla::PrincipalOriginAttributes attrs(aAppId, aIsInIsolatedMozBrowserElement); + nsCOMPtr principal = mozilla::BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); + + principal.forget(aPrincipal); + return NS_OK; +} + +nsresult +GetPrincipal(nsIURI* aURI, nsIPrincipal** aPrincipal) +{ + mozilla::PrincipalOriginAttributes attrs; + nsCOMPtr principal = mozilla::BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); + + principal.forget(aPrincipal); + return NS_OK; +} + +nsCString +GetNextSubDomainForHost(const nsACString& aHost) +{ + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + if (!tldService) { + NS_ERROR("Should have a tld service!"); + return EmptyCString(); + } + + nsCString subDomain; + nsresult rv = tldService->GetNextSubDomain(aHost, subDomain); + // We can fail if there is no more subdomain or if the host can't have a + // subdomain. + if (NS_FAILED(rv)) { + return EmptyCString(); + } + + return subDomain; +} + +class ClearOriginDataObserver final : public nsIObserver { + ~ClearOriginDataObserver() {} + +public: + NS_DECL_ISUPPORTS + + // nsIObserver implementation. + NS_IMETHOD + Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) override + { + MOZ_ASSERT(!nsCRT::strcmp(aTopic, "clear-origin-attributes-data")); + + nsCOMPtr permManager = do_GetService("@mozilla.org/permissionmanager;1"); + return permManager->RemovePermissionsWithAttributes(nsDependentString(aData)); + } +}; + +NS_IMPL_ISUPPORTS(ClearOriginDataObserver, nsIObserver) + +class MOZ_STACK_CLASS UpgradeHostToOriginHelper { +public: + virtual nsresult Insert(const nsACString& aOrigin, const nsAFlatCString& aType, + uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime) = 0; +}; + +class MOZ_STACK_CLASS UpgradeHostToOriginDBMigration final : public UpgradeHostToOriginHelper { +public: + UpgradeHostToOriginDBMigration(mozIStorageConnection* aDBConn, int64_t* aID) : mDBConn(aDBConn) + , mID(aID) + { + mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "INSERT INTO moz_hosts_new " + "(id, origin, type, permission, expireType, expireTime, modificationTime) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(mStmt)); + } + + nsresult + Insert(const nsACString& aOrigin, const nsAFlatCString& aType, + uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime) final + { + nsresult rv = mStmt->BindInt64ByIndex(0, *mID); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(1, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(2, aType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(3, aPermission); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(4, aExpireType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(5, aExpireTime); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(6, aModificationTime); + NS_ENSURE_SUCCESS(rv, rv); + + // Increment the working identifier, as we are about to use this one + (*mID)++; + + rv = mStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + +private: + nsCOMPtr mStmt; + nsCOMPtr mDBConn; + int64_t* mID; +}; + +class MOZ_STACK_CLASS UpgradeHostToOriginHostfileImport final : public UpgradeHostToOriginHelper { +public: + UpgradeHostToOriginHostfileImport(nsPermissionManager* aPm, + nsPermissionManager::DBOperationType aOperation, + int64_t aID) : mPm(aPm) + , mOperation(aOperation) + , mID(aID) + {} + + nsresult + Insert(const nsACString& aOrigin, const nsAFlatCString& aType, + uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime) final + { + nsCOMPtr principal; + nsresult rv = GetPrincipalFromOrigin(aOrigin, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + return mPm->AddInternal(principal, aType, aPermission, mID, + aExpireType, aExpireTime, aModificationTime, + nsPermissionManager::eDontNotify, mOperation); + } + +private: + RefPtr mPm; + nsPermissionManager::DBOperationType mOperation; + int64_t mID; +}; + +class MOZ_STACK_CLASS UpgradeIPHostToOriginDB final : public UpgradeHostToOriginHelper { +public: + UpgradeIPHostToOriginDB(mozIStorageConnection* aDBConn, int64_t* aID) : mDBConn(aDBConn) + , mID(aID) + { + mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "INSERT INTO moz_perms" + "(id, origin, type, permission, expireType, expireTime, modificationTime) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(mStmt)); + + mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT id FROM moz_perms WHERE origin = ?1 AND type = ?2"), + getter_AddRefs(mLookupStmt)); + } + + nsresult + Insert(const nsACString& aOrigin, const nsAFlatCString& aType, + uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime) final + { + // Every time the migration code wants to insert an origin into + // the database we need to check to see if someone has already + // created a permissions entry for that permission. If they have, + // we don't want to insert a duplicate row. + // + // We can afford to do this lookup unconditionally and not perform + // caching, as a origin type pair should only be attempted to be + // inserted once. + + nsresult rv = mLookupStmt->Reset(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mLookupStmt->BindUTF8StringByIndex(0, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mLookupStmt->BindUTF8StringByIndex(1, aType); + NS_ENSURE_SUCCESS(rv, rv); + + // Check if we already have the row in the database, if we do, then + // we don't want to be inserting it again. + bool moreStmts = false; + if (NS_FAILED(mLookupStmt->ExecuteStep(&moreStmts)) || moreStmts) { + mLookupStmt->Reset(); + NS_WARNING("A permissions entry was going to be re-migrated, " + "but was already found in the permissions database."); + return NS_OK; + } + + // Actually insert the statement into the database. + rv = mStmt->BindInt64ByIndex(0, *mID); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(1, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(2, aType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(3, aPermission); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(4, aExpireType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(5, aExpireTime); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(6, aModificationTime); + NS_ENSURE_SUCCESS(rv, rv); + + // Increment the working identifier, as we are about to use this one + (*mID)++; + + rv = mStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + +private: + nsCOMPtr mStmt; + nsCOMPtr mLookupStmt; + nsCOMPtr mDBConn; + int64_t* mID; +}; + + +nsresult +UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aType, + uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime, uint32_t aAppId, bool aIsInIsolatedMozBrowserElement, + UpgradeHostToOriginHelper* aHelper) +{ + if (aHost.EqualsLiteral("")) { + // We no longer support the magic host + NS_WARNING("The magic host is no longer supported. " + "It is being removed from the permissions database."); + return NS_OK; + } + + // First, we check to see if the host is a valid URI. If it is, it can be imported directly + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aHost); + if (NS_SUCCEEDED(rv)) { + // It was previously possible to insert useless entries to your permissions database + // for URIs which have a null principal. This acts as a cleanup, getting rid of + // these useless database entries + bool nullpScheme = false; + if (NS_SUCCEEDED(uri->SchemeIs("moz-nullprincipal", &nullpScheme)) && nullpScheme) { + NS_WARNING("A moz-nullprincipal: permission is being discarded."); + return NS_OK; + } + + nsCOMPtr principal; + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString origin; + rv = GetOriginFromPrincipal(principal, origin); + NS_ENSURE_SUCCESS(rv, rv); + + return aHelper->Insert(origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); + return NS_OK; + } + + // The user may use this host at non-standard ports or protocols, we can use their history + // to guess what ports and protocols we want to add permissions for. + // We find every URI which they have visited with this host (or a subdomain of this host), + // and try to add it as a principal. + bool foundHistory = false; + + nsCOMPtr histSrv = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID); + + if (histSrv) { + nsCOMPtr histQuery; + rv = histSrv->GetNewQuery(getter_AddRefs(histQuery)); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the eTLD+1 of the domain + nsAutoCString eTLD1; + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + MOZ_ASSERT(tldService); // We should always have a tldService + if (tldService) { + rv = tldService->GetBaseDomainFromHost(aHost, 0, eTLD1); + } + + if (!tldService || NS_FAILED(rv)) { + // If the lookup on the tldService for the base domain for the host failed, + // that means that we just want to directly use the host as the host name + // for the lookup. + eTLD1 = aHost; + } + + // We want to only find history items for this particular eTLD+1, and subdomains + rv = histQuery->SetDomain(eTLD1); + NS_ENSURE_SUCCESS(rv, rv); + + rv = histQuery->SetDomainIsHost(false); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr histQueryOpts; + rv = histSrv->GetNewQueryOptions(getter_AddRefs(histQueryOpts)); + NS_ENSURE_SUCCESS(rv, rv); + + // We want to get the URIs for every item in the user's history with the given host + rv = histQueryOpts->SetResultType(nsINavHistoryQueryOptions::RESULTS_AS_URI); + NS_ENSURE_SUCCESS(rv, rv); + + // We only search history, because searching both bookmarks and history + // is not supported, and history tends to be more comprehensive. + rv = histQueryOpts->SetQueryType(nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY); + NS_ENSURE_SUCCESS(rv, rv); + + // We include hidden URIs (such as those visited via iFrames) as they may have permissions too + rv = histQueryOpts->SetIncludeHidden(true); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr histResult; + rv = histSrv->ExecuteQuery(histQuery, histQueryOpts, getter_AddRefs(histResult)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr histResultContainer; + rv = histResult->GetRoot(getter_AddRefs(histResultContainer)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = histResultContainer->SetContainerOpen(true); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t childCount = 0; + rv = histResultContainer->GetChildCount(&childCount); + NS_ENSURE_SUCCESS(rv, rv); + + nsTHashtable insertedOrigins; + for (uint32_t i = 0; i < childCount; i++) { + nsCOMPtr child; + histResultContainer->GetChild(i, getter_AddRefs(child)); + if (NS_WARN_IF(NS_FAILED(rv))) continue; + + uint32_t type; + rv = child->GetType(&type); + if (NS_WARN_IF(NS_FAILED(rv)) || type != nsINavHistoryResultNode::RESULT_TYPE_URI) { + NS_WARNING("Unexpected non-RESULT_TYPE_URI node in " + "UpgradeHostToOriginAndInsert()"); + continue; + } + + nsAutoCString uriSpec; + rv = child->GetUri(uriSpec); + if (NS_WARN_IF(NS_FAILED(rv))) continue; + + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), uriSpec); + if (NS_WARN_IF(NS_FAILED(rv))) continue; + + // Use the provided host - this URI may be for a subdomain, rather than the host we care about. + rv = uri->SetHost(aHost); + if (NS_WARN_IF(NS_FAILED(rv))) continue; + + // We now have a URI which we can make a nsIPrincipal out of + nsCOMPtr principal; + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); + if (NS_WARN_IF(NS_FAILED(rv))) continue; + + nsAutoCString origin; + rv = GetOriginFromPrincipal(principal, origin); + if (NS_WARN_IF(NS_FAILED(rv))) continue; + + // Ensure that we don't insert the same origin repeatedly + if (insertedOrigins.Contains(origin)) { + continue; + } + + foundHistory = true; + rv = aHelper->Insert(origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Insert failed"); + insertedOrigins.PutEntry(origin); + } + + rv = histResultContainer->SetContainerOpen(false); + NS_ENSURE_SUCCESS(rv, rv); + } + + // If we didn't find any origins for this host in the poermissions database, + // we can insert the default http:// and https:// permissions into the database. + // This has a relatively high liklihood of applying the permission to the correct + // origin. + if (!foundHistory) { + nsAutoCString hostSegment; + nsCOMPtr principal; + nsAutoCString origin; + + // If this is an ipv6 URI, we need to surround it in '[', ']' before trying to + // parse it as a URI. + if (aHost.FindChar(':') != -1) { + hostSegment.Assign("["); + hostSegment.Append(aHost); + hostSegment.Append("]"); + } else { + hostSegment.Assign(aHost); + } + + // http:// URI default + rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + hostSegment); + NS_ENSURE_SUCCESS(rv, rv); + + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = GetOriginFromPrincipal(principal, origin); + NS_ENSURE_SUCCESS(rv, rv); + + aHelper->Insert(origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); + + // https:// URI default + rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + hostSegment); + NS_ENSURE_SUCCESS(rv, rv); + + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = GetOriginFromPrincipal(principal, origin); + NS_ENSURE_SUCCESS(rv, rv); + + aHelper->Insert(origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); + } + + return NS_OK; +} + +static bool +IsExpandedPrincipal(nsIPrincipal* aPrincipal) +{ + nsCOMPtr ep = do_QueryInterface(aPrincipal); + return !!ep; +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// + +nsPermissionManager::PermissionKey::PermissionKey(nsIPrincipal* aPrincipal) +{ + MOZ_ALWAYS_SUCCEEDS(GetOriginFromPrincipal(aPrincipal, mOrigin)); +} + +/** + * Simple callback used by |AsyncClose| to trigger a treatment once + * the database is closed. + * + * Note: Beware that, if you hold onto a |CloseDatabaseListener| from a + * |nsPermissionManager|, this will create a cycle. + * + * Note: Once the callback has been called this DeleteFromMozHostListener cannot + * be reused. + */ +class CloseDatabaseListener final : public mozIStorageCompletionCallback +{ + ~CloseDatabaseListener() {} + +public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGECOMPLETIONCALLBACK + /** + * @param aManager The owning manager. + * @param aRebuildOnSuccess If |true|, reinitialize the database once + * it has been closed. Otherwise, do nothing such. + */ + CloseDatabaseListener(nsPermissionManager* aManager, + bool aRebuildOnSuccess); + +protected: + RefPtr mManager; + bool mRebuildOnSuccess; +}; + +NS_IMPL_ISUPPORTS(CloseDatabaseListener, mozIStorageCompletionCallback) + +CloseDatabaseListener::CloseDatabaseListener(nsPermissionManager* aManager, + bool aRebuildOnSuccess) + : mManager(aManager) + , mRebuildOnSuccess(aRebuildOnSuccess) +{ +} + +NS_IMETHODIMP +CloseDatabaseListener::Complete(nsresult, nsISupports*) +{ + // Help breaking cycles + RefPtr manager = mManager.forget(); + if (mRebuildOnSuccess && !manager->mIsShuttingDown) { + return manager->InitDB(true); + } + return NS_OK; +} + + +/** + * Simple callback used by |RemoveAllInternal| to trigger closing + * the database and reinitializing it. + * + * Note: Beware that, if you hold onto a |DeleteFromMozHostListener| from a + * |nsPermissionManager|, this will create a cycle. + * + * Note: Once the callback has been called this DeleteFromMozHostListener cannot + * be reused. + */ +class DeleteFromMozHostListener final : public mozIStorageStatementCallback +{ + ~DeleteFromMozHostListener() {} + +public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGESTATEMENTCALLBACK + + /** + * @param aManager The owning manager. + */ + explicit DeleteFromMozHostListener(nsPermissionManager* aManager); + +protected: + RefPtr mManager; +}; + +NS_IMPL_ISUPPORTS(DeleteFromMozHostListener, mozIStorageStatementCallback) + +DeleteFromMozHostListener:: +DeleteFromMozHostListener(nsPermissionManager* aManager) + : mManager(aManager) +{ +} + +NS_IMETHODIMP DeleteFromMozHostListener::HandleResult(mozIStorageResultSet *) +{ + MOZ_CRASH("Should not get any results"); +} + +NS_IMETHODIMP DeleteFromMozHostListener::HandleError(mozIStorageError *) +{ + // Errors are handled in |HandleCompletion| + return NS_OK; +} + +NS_IMETHODIMP DeleteFromMozHostListener::HandleCompletion(uint16_t aReason) +{ + // Help breaking cycles + RefPtr manager = mManager.forget(); + + if (aReason == REASON_ERROR) { + manager->CloseDB(true); + } + + return NS_OK; +} + +/* static */ void +nsPermissionManager::ClearOriginDataObserverInit() +{ + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + observerService->AddObserver(new ClearOriginDataObserver(), "clear-origin-attributes-data", /* ownsWeak= */ false); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsPermissionManager Implementation + +#define PERMISSIONS_FILE_NAME "permissions.sqlite" +#define HOSTS_SCHEMA_VERSION 9 + +#define HOSTPERM_FILE_NAME "hostperm.1" + +// Default permissions are read from a URL - this is the preference we read +// to find that URL. If not set, don't use any default permissions. +static const char kDefaultsUrlPrefName[] = "permissions.manager.defaultsUrl"; + +static const char kPermissionChangeNotification[] = PERM_CHANGE_NOTIFICATION; + +NS_IMPL_ISUPPORTS(nsPermissionManager, nsIPermissionManager, nsIObserver, nsISupportsWeakReference) + +nsPermissionManager::nsPermissionManager() + : mMemoryOnlyDB(false) + , mLargestID(0) + , mIsShuttingDown(false) +{ +} + +nsPermissionManager::~nsPermissionManager() +{ + RemoveAllFromMemory(); + gPermissionManager = nullptr; +} + +// static +nsIPermissionManager* +nsPermissionManager::GetXPCOMSingleton() +{ + if (gPermissionManager) { + NS_ADDREF(gPermissionManager); + return gPermissionManager; + } + + // Create a new singleton nsPermissionManager. + // We AddRef only once since XPCOM has rules about the ordering of module + // teardowns - by the time our module destructor is called, it's too late to + // Release our members, since GC cycles have already been completed and + // would result in serious leaks. + // See bug 209571. + gPermissionManager = new nsPermissionManager(); + if (gPermissionManager) { + NS_ADDREF(gPermissionManager); + if (NS_FAILED(gPermissionManager->Init())) { + NS_RELEASE(gPermissionManager); + } + } + + return gPermissionManager; +} + +nsresult +nsPermissionManager::Init() +{ + // If the 'permissions.memory_only' pref is set to true, then don't write any + // permission settings to disk, but keep them in a memory-only database. + mMemoryOnlyDB = mozilla::Preferences::GetBool("permissions.memory_only", false); + + if (IsChildProcess()) { + // Stop here; we don't need the DB in the child process + return FetchPermissions(); + } + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + if (observerService) { + observerService->AddObserver(this, "profile-before-change", true); + observerService->AddObserver(this, "profile-do-change", true); + } + + // ignore failure here, since it's non-fatal (we can run fine without + // persistent storage - e.g. if there's no profile). + // XXX should we tell the user about this? + InitDB(false); + + return NS_OK; +} + +NS_IMETHODIMP +nsPermissionManager::RefreshPermission() { + NS_ENSURE_TRUE(IsChildProcess(), NS_ERROR_FAILURE); + + nsresult rv = RemoveAllFromMemory(); + NS_ENSURE_SUCCESS(rv, rv); + rv = FetchPermissions(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult +nsPermissionManager::OpenDatabase(nsIFile* aPermissionsFile) +{ + nsresult rv; + nsCOMPtr storage = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + if (!storage) { + return NS_ERROR_UNEXPECTED; + } + // cache a connection to the hosts database + if (mMemoryOnlyDB) { + rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn)); + } else { + rv = storage->OpenDatabase(aPermissionsFile, getter_AddRefs(mDBConn)); + } + return rv; +} + +nsresult +nsPermissionManager::InitDB(bool aRemoveFile) +{ + nsCOMPtr permissionsFile; + nsresult rv = NS_GetSpecialDirectory(NS_APP_PERMISSION_PARENT_DIR, getter_AddRefs(permissionsFile)); + if (NS_FAILED(rv)) { + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(permissionsFile)); + } + NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED); + + rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(PERMISSIONS_FILE_NAME)); + NS_ENSURE_SUCCESS(rv, rv); + + if (aRemoveFile) { + bool exists = false; + rv = permissionsFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + if (exists) { + rv = permissionsFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + rv = OpenDatabase(permissionsFile); + if (rv == NS_ERROR_FILE_CORRUPTED) { + LogToConsole(NS_LITERAL_STRING("permissions.sqlite is corrupted! Try again!")); + + // Add telemetry probe + mozilla::Telemetry::Accumulate(mozilla::Telemetry::PERMISSIONS_SQL_CORRUPTED, 1); + + // delete corrupted permissions.sqlite and try again + rv = permissionsFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("Corrupted permissions.sqlite has been removed.")); + + rv = OpenDatabase(permissionsFile); + NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!")); + } else if (NS_FAILED(rv)) { + return rv; + } + + bool ready; + mDBConn->GetConnectionReady(&ready); + if (!ready) { + LogToConsole(NS_LITERAL_STRING("Fail to get connection to permissions.sqlite! Try again!")); + + // delete and try again + rv = permissionsFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("Defective permissions.sqlite has been removed.")); + + // Add telemetry probe + mozilla::Telemetry::Accumulate(mozilla::Telemetry::DEFECTIVE_PERMISSIONS_SQL_REMOVED, 1); + + rv = OpenDatabase(permissionsFile); + NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!")); + + mDBConn->GetConnectionReady(&ready); + if (!ready) + return NS_ERROR_UNEXPECTED; + } + + + bool tableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), &tableExists); + if (!tableExists) { + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &tableExists); + } + if (!tableExists) { + rv = CreateTable(); + NS_ENSURE_SUCCESS(rv, rv); + } else { + // table already exists; check the schema version before reading + int32_t dbSchemaVersion; + rv = mDBConn->GetSchemaVersion(&dbSchemaVersion); + NS_ENSURE_SUCCESS(rv, rv); + + switch (dbSchemaVersion) { + // upgrading. + // every time you increment the database schema, you need to implement + // the upgrading code from the previous version to the new one. + // fall through to current version + + case 1: + { + // previous non-expiry version of database. Upgrade it by adding the + // expiration columns + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts ADD expireType INTEGER")); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts ADD expireTime INTEGER")); + NS_ENSURE_SUCCESS(rv, rv); + } + + // fall through to the next upgrade + MOZ_FALLTHROUGH; + + // TODO: we want to make default version as version 2 in order to fix bug 784875. + case 0: + case 2: + { + // Add appId/isInBrowserElement fields. + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts ADD appId INTEGER")); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts ADD isInBrowserElement INTEGER")); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDBConn->SetSchemaVersion(3); + NS_ENSURE_SUCCESS(rv, rv); + } + + // fall through to the next upgrade + MOZ_FALLTHROUGH; + + // Version 3->4 is the creation of the modificationTime field. + case 3: + { + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts ADD modificationTime INTEGER")); + NS_ENSURE_SUCCESS(rv, rv); + + // We leave the modificationTime at zero for all existing records; using + // now() would mean, eg, that doing "remove all from the last hour" + // within the first hour after migration would remove all permissions. + + rv = mDBConn->SetSchemaVersion(4); + NS_ENSURE_SUCCESS(rv, rv); + } + + // fall through to the next upgrade + MOZ_FALLTHROUGH; + + // In version 5, host appId, and isInBrowserElement were merged into a + // single origin entry + // + // In version 6, the tables were renamed for backwards compatability reasons + // with version 4 and earlier. + // + // In version 7, a bug in the migration used for version 4->5 was discovered + // which could have triggered data-loss. Because of that, all users with a + // version 4, 5, or 6 database will be re-migrated from the backup database. + // (bug 1186034). This migration bug is not present after bug 1185340, and the + // re-migration ensures that all users have the fix. + case 5: + // This branch could also be reached via dbSchemaVersion == 3, in which case + // we want to fall through to the dbSchemaVersion == 4 case. + // The easiest way to do that is to perform this extra check here to make + // sure that we didn't get here via a fallthrough from v3 + if (dbSchemaVersion == 5) { + // In version 5, the backup database is named moz_hosts_v4. We perform + // the version 5->6 migration to get the tables to have consistent + // naming conventions. + + // Version 5->6 is the renaming of moz_hosts to moz_perms, and + // moz_hosts_v4 to moz_hosts (bug 1185343) + // + // In version 5, we performed the modifications to the permissions + // database in place, this meant that if you upgraded to a version which + // used V5, and then downgraded to a version which used v4 or earlier, + // the fallback path would drop the table, and your permissions data + // would be lost. This migration undoes that mistake, by restoring the + // old moz_hosts table (if it was present), and instead using the new + // table moz_perms for the new permissions schema. + // + // NOTE: If you downgrade, store new permissions, and then upgrade + // again, these new permissions won't be migrated or reflected in the + // updated database. This migration only occurs once, as if moz_perms + // exists, it will skip creating it. In addition, permissions added + // after the migration will not be visible in previous versions of + // firefox. + + bool permsTableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), &permsTableExists); + if (!permsTableExists) { + // Move the upgraded database to moz_perms + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts RENAME TO moz_perms")); + NS_ENSURE_SUCCESS(rv, rv); + } else { + NS_WARNING("moz_hosts was not renamed to moz_perms, " + "as a moz_perms table already exists"); + + // In the situation where a moz_perms table already exists, but the + // schema is lower than 6, a migration has already previously occured + // to V6, but a downgrade has caused the moz_hosts table to be + // dropped. This should only occur in the case of a downgrade to a V5 + // database, which was only present in a few day's nightlies. As that + // version was likely used only on a temporary basis, we assume that + // the database from the previous V6 has the permissions which the + // user actually wants to use. We have to get rid of moz_hosts such + // that moz_hosts_v4 can be moved into its place if it exists. + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_hosts")); + NS_ENSURE_SUCCESS(rv, rv); + } + +#ifdef DEBUG + // The moz_hosts table shouldn't exist anymore + bool hostsTableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &hostsTableExists); + MOZ_ASSERT(!hostsTableExists); +#endif + + // Rename moz_hosts_v4 back to it's original location, if it exists + bool v4TableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_v4"), &v4TableExists); + if (v4TableExists) { + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts_v4 RENAME TO moz_hosts")); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = mDBConn->SetSchemaVersion(6); + NS_ENSURE_SUCCESS(rv, rv); + } + + // fall through to the next upgrade + MOZ_FALLTHROUGH; + + // At this point, the version 5 table has been migrated to a version 6 table + // We are guaranteed to have at least one of moz_hosts and moz_perms. If + // we have moz_hosts, we will migrate moz_hosts into moz_perms (even if + // we already have a moz_perms, as we need a re-migration due to bug 1186034). + // + // After this migration, we are guaranteed to have both a moz_hosts (for backwards + // compatability), and a moz_perms table. The moz_hosts table will have a v4 schema, + // and the moz_perms table will have a v6 schema. + case 4: + case 6: + { + bool hostsTableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &hostsTableExists); + if (hostsTableExists) { + bool migrationError = false; + + // Both versions 4 and 6 have a version 4 formatted hosts table named + // moz_hosts. We can migrate this table to our version 7 table moz_perms. + // If moz_perms is present, then we can use it as a basis for comparison. + + rv = mDBConn->BeginTransaction(); + NS_ENSURE_SUCCESS(rv, rv); + + bool tableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_new"), &tableExists); + if (tableExists) { + NS_WARNING("The temporary database moz_hosts_new already exists, dropping it."); + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_hosts_new")); + NS_ENSURE_SUCCESS(rv, rv); + } + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE moz_hosts_new (" + " id INTEGER PRIMARY KEY" + ",origin TEXT" + ",type TEXT" + ",permission INTEGER" + ",expireType INTEGER" + ",expireTime INTEGER" + ",modificationTime INTEGER" + ")")); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr stmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT host, type, permission, expireType, expireTime, " + "modificationTime, appId, isInBrowserElement FROM moz_hosts"), + getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, rv); + + int64_t id = 0; + nsAutoCString host, type; + uint32_t permission; + uint32_t expireType; + int64_t expireTime; + int64_t modificationTime; + uint32_t appId; + bool isInBrowserElement; + bool hasResult; + + while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { + // Read in the old row + rv = stmt->GetUTF8String(0, host); + if (NS_WARN_IF(NS_FAILED(rv))) { + migrationError = true; + continue; + } + rv = stmt->GetUTF8String(1, type); + if (NS_WARN_IF(NS_FAILED(rv))) { + migrationError = true; + continue; + } + permission = stmt->AsInt32(2); + expireType = stmt->AsInt32(3); + expireTime = stmt->AsInt64(4); + modificationTime = stmt->AsInt64(5); + if (NS_WARN_IF(stmt->AsInt64(6) < 0)) { + migrationError = true; + continue; + } + appId = static_cast(stmt->AsInt64(6)); + isInBrowserElement = static_cast(stmt->AsInt32(7)); + + // Perform the meat of the migration by deferring to the + // UpgradeHostToOriginAndInsert function. + UpgradeHostToOriginDBMigration upHelper(mDBConn, &id); + rv = UpgradeHostToOriginAndInsert(host, type, permission, + expireType, expireTime, + modificationTime, appId, + isInBrowserElement, + &upHelper); + if (NS_FAILED(rv)) { + NS_WARNING("Unexpected failure when upgrading migrating permission " + "from host to origin"); + migrationError = true; + } + } + + // We don't drop the moz_hosts table such that it is avaliable for + // backwards-compatability and for future migrations in case of + // migration errors in the current code. + // Create a marker empty table which will indicate that the moz_hosts + // table is intended to act as a backup. If this table is not present, + // then the moz_hosts table was created as a random empty table. + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE moz_hosts_is_backup (dummy INTEGER PRIMARY KEY)")); + NS_ENSURE_SUCCESS(rv, rv); + + bool permsTableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), &permsTableExists); + if (permsTableExists) { + // The user already had a moz_perms table, and we are performing a + // re-migration. We count the rows in the old table for telemetry, + // and then back up their old database as moz_perms_v6 + + nsCOMPtr countStmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_perms"), + getter_AddRefs(countStmt)); + bool hasResult = false; + if (NS_SUCCEEDED(rv) && + NS_SUCCEEDED(countStmt->ExecuteStep(&hasResult)) && + hasResult) { + int32_t permsCount = countStmt->AsInt32(0); + + // The id variable contains the number of rows inserted into the + // moz_hosts_new table (as one ID was used per entry) + uint32_t telemetryValue; + if (permsCount > id) { + telemetryValue = 3; // NEW > OLD + } else if (permsCount == id) { + telemetryValue = 2; // NEW == OLD + } else if (permsCount == 0) { + telemetryValue = 0; // NEW = 0 + } else { + telemetryValue = 1; // NEW < OLD + } + + // Report the telemetry value to telemetry + mozilla::Telemetry::Accumulate( + mozilla::Telemetry::PERMISSIONS_REMIGRATION_COMPARISON, + telemetryValue); + } else { + NS_WARNING("Could not count the rows in moz_perms"); + } + + // Back up the old moz_perms database as moz_perms_v6 before we + // move the new table into its position + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_perms RENAME TO moz_perms_v6")); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE moz_hosts_new RENAME TO moz_perms")); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDBConn->CommitTransaction(); + NS_ENSURE_SUCCESS(rv, rv); + + mozilla::Telemetry::Accumulate(mozilla::Telemetry::PERMISSIONS_MIGRATION_7_ERROR, + NS_WARN_IF(migrationError)); + } else { + // We don't have a moz_hosts table, so we create one for downgrading purposes. + // This table is empty. + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE moz_hosts (" + " id INTEGER PRIMARY KEY" + ",host TEXT" + ",type TEXT" + ",permission INTEGER" + ",expireType INTEGER" + ",expireTime INTEGER" + ",modificationTime INTEGER" + ",appId INTEGER" + ",isInBrowserElement INTEGER" + ")")); + NS_ENSURE_SUCCESS(rv, rv); + + // We are guaranteed to have a moz_perms table at this point. + } + +#ifdef DEBUG + { + // At this point, both the moz_hosts and moz_perms tables should exist + bool hostsTableExists = false; + bool permsTableExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &hostsTableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), &permsTableExists); + MOZ_ASSERT(hostsTableExists && permsTableExists); + } +#endif + + rv = mDBConn->SetSchemaVersion(7); + NS_ENSURE_SUCCESS(rv, rv); + } + + // fall through to the next upgrade + MOZ_FALLTHROUGH; + + // The version 7-8 migration is the re-migration of localhost and ip-address + // entries due to errors in the previous version 7 migration which caused + // localhost and ip-address entries to be incorrectly discarded. + // The version 7 migration logic has been corrected, and thus this logic only + // needs to execute if the user is currently on version 7. + case 7: + { + // This migration will be relatively expensive as we need to perform + // database lookups for each origin which we want to insert. Fortunately, + // it shouldn't be too expensive as we only want to insert a small number + // of entries created for localhost or IP addresses. + + // We only want to perform the re-migration if moz_hosts is a backup + bool hostsIsBackupExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"), + &hostsIsBackupExists); + + // Only perform this migration if the original schema version was 7, and + // the moz_hosts table is a backup. + if (dbSchemaVersion == 7 && hostsIsBackupExists) { + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + MOZ_ASSERT(tldService); // We should always have a tldService + + nsCOMPtr stmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT host, type, permission, expireType, expireTime, " + "modificationTime, appId, isInBrowserElement FROM moz_hosts"), + getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr idStmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT MAX(id) FROM moz_hosts"), getter_AddRefs(idStmt)); + int64_t id = 0; + bool hasResult = false; + if (NS_SUCCEEDED(rv) && + NS_SUCCEEDED(idStmt->ExecuteStep(&hasResult)) && + hasResult) { + id = idStmt->AsInt32(0) + 1; + } + + nsAutoCString host, type; + uint32_t permission; + uint32_t expireType; + int64_t expireTime; + int64_t modificationTime; + uint32_t appId; + bool isInBrowserElement; + + while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { + // Read in the old row + rv = stmt->GetUTF8String(0, host); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + nsAutoCString eTLD1; + rv = tldService->GetBaseDomainFromHost(host, 0, eTLD1); + if (NS_SUCCEEDED(rv)) { + // We only care about entries which the tldService can't handle + continue; + } + + rv = stmt->GetUTF8String(1, type); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + permission = stmt->AsInt32(2); + expireType = stmt->AsInt32(3); + expireTime = stmt->AsInt64(4); + modificationTime = stmt->AsInt64(5); + if (NS_WARN_IF(stmt->AsInt64(6) < 0)) { + continue; + } + appId = static_cast(stmt->AsInt64(6)); + isInBrowserElement = static_cast(stmt->AsInt32(7)); + + // Perform the meat of the migration by deferring to the + // UpgradeHostToOriginAndInsert function. + UpgradeIPHostToOriginDB upHelper(mDBConn, &id); + rv = UpgradeHostToOriginAndInsert(host, type, permission, + expireType, expireTime, + modificationTime, appId, + isInBrowserElement, + &upHelper); + if (NS_FAILED(rv)) { + NS_WARNING("Unexpected failure when upgrading migrating permission " + "from host to origin"); + } + } + } + + // Even if we didn't perform the migration, we want to bump the schema + // version to 8. + rv = mDBConn->SetSchemaVersion(8); + NS_ENSURE_SUCCESS(rv, rv); + } + + // fall through to the next upgrade + MOZ_FALLTHROUGH; + + // The version 8-9 migration removes the unnecessary backup moz-hosts database contents. + // as the data no longer needs to be migrated + case 8: + { + // We only want to clear out the old table if it is a backup. If it isn't a backup, + // we don't need to touch it. + bool hostsIsBackupExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"), + &hostsIsBackupExists); + if (hostsIsBackupExists) { + // Delete everything from the backup, we want to keep around the table so that + // you can still downgrade and not break things, but we don't need to keep the + // rows around. + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_hosts")); + NS_ENSURE_SUCCESS(rv, rv); + + // The table is no longer a backup, so get rid of it. + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_hosts_is_backup")); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = mDBConn->SetSchemaVersion(9); + NS_ENSURE_SUCCESS(rv, rv); + } + + // fall through to the next upgrade + MOZ_FALLTHROUGH; + + // current version. + case HOSTS_SCHEMA_VERSION: + break; + + // downgrading. + // if columns have been added to the table, we can still use the ones we + // understand safely. if columns have been deleted or altered, just + // blow away the table and start from scratch! if you change the way + // a column is interpreted, make sure you also change its name so this + // check will catch it. + default: + { + // check if all the expected columns exist + nsCOMPtr stmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT origin, type, permission, expireType, expireTime, " + "modificationTime FROM moz_perms"), + getter_AddRefs(stmt)); + if (NS_SUCCEEDED(rv)) + break; + + // our columns aren't there - drop the table! + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_perms")); + NS_ENSURE_SUCCESS(rv, rv); + + rv = CreateTable(); + NS_ENSURE_SUCCESS(rv, rv); + } + break; + } + } + + // cache frequently used statements (for insertion, deletion, and updating) + rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING( + "INSERT INTO moz_perms " + "(id, origin, type, permission, expireType, expireTime, modificationTime) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(mStmtInsert)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING( + "DELETE FROM moz_perms " + "WHERE id = ?1"), getter_AddRefs(mStmtDelete)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING( + "UPDATE moz_perms " + "SET permission = ?2, expireType= ?3, expireTime = ?4, modificationTime = ?5 WHERE id = ?1"), + getter_AddRefs(mStmtUpdate)); + NS_ENSURE_SUCCESS(rv, rv); + + // Always import default permissions. + ImportDefaults(); + // check whether to import or just read in the db + if (tableExists) + return Read(); + + return Import(); +} + +// sets the schema version and creates the moz_perms table. +nsresult +nsPermissionManager::CreateTable() +{ + // set the schema version, before creating the table + nsresult rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION); + if (NS_FAILED(rv)) return rv; + + // create the table + // SQL also lives in automation.py.in. If you change this SQL change that + // one too + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE moz_perms (" + " id INTEGER PRIMARY KEY" + ",origin TEXT" + ",type TEXT" + ",permission INTEGER" + ",expireType INTEGER" + ",expireTime INTEGER" + ",modificationTime INTEGER" + ")")); + if (NS_FAILED(rv)) return rv; + + // We also create a legacy V4 table, for backwards compatability, + // and to ensure that downgrades don't trigger a schema version change. + return mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE moz_hosts (" + " id INTEGER PRIMARY KEY" + ",host TEXT" + ",type TEXT" + ",permission INTEGER" + ",expireType INTEGER" + ",expireTime INTEGER" + ",modificationTime INTEGER" + ",appId INTEGER" + ",isInBrowserElement INTEGER" + ")")); +} + +NS_IMETHODIMP +nsPermissionManager::Add(nsIURI *aURI, + const char *aType, + uint32_t aPermission, + uint32_t aExpireType, + int64_t aExpireTime) +{ + NS_ENSURE_ARG_POINTER(aURI); + + nsCOMPtr principal; + nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + return AddFromPrincipal(principal, aType, aPermission, aExpireType, aExpireTime); +} + +NS_IMETHODIMP +nsPermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal, + const char* aType, uint32_t aPermission, + uint32_t aExpireType, int64_t aExpireTime) +{ + ENSURE_NOT_CHILD_PROCESS; + NS_ENSURE_ARG_POINTER(aPrincipal); + NS_ENSURE_ARG_POINTER(aType); + NS_ENSURE_TRUE(aExpireType == nsIPermissionManager::EXPIRE_NEVER || + aExpireType == nsIPermissionManager::EXPIRE_TIME || + aExpireType == nsIPermissionManager::EXPIRE_SESSION, + NS_ERROR_INVALID_ARG); + + // Skip addition if the permission is already expired. Note that EXPIRE_SESSION only + // honors expireTime if it is nonzero. + if ((aExpireType == nsIPermissionManager::EXPIRE_TIME || + (aExpireType == nsIPermissionManager::EXPIRE_SESSION && aExpireTime != 0)) && + aExpireTime <= (PR_Now() / 1000)) { + return NS_OK; + } + + // We don't add the system principal because it actually has no URI and we + // always allow action for them. + if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { + return NS_OK; + } + + // Null principals can't meaningfully have persisted permissions attached to + // them, so we don't allow adding permissions for them. + if (aPrincipal->GetIsNullPrincipal()) { + return NS_OK; + } + + // Permissions may not be added to expanded principals. + if (IsExpandedPrincipal(aPrincipal)) { + return NS_ERROR_INVALID_ARG; + } + + // A modificationTime of zero will cause AddInternal to use now(). + int64_t modificationTime = 0; + + return AddInternal(aPrincipal, nsDependentCString(aType), aPermission, 0, + aExpireType, aExpireTime, modificationTime, eNotify, eWriteToDB); +} + +nsresult +nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal, + const nsAFlatCString &aType, + uint32_t aPermission, + int64_t aID, + uint32_t aExpireType, + int64_t aExpireTime, + int64_t aModificationTime, + NotifyOperationType aNotifyOperation, + DBOperationType aDBOperation, + const bool aIgnoreSessionPermissions) +{ + nsAutoCString origin; + nsresult rv = GetOriginFromPrincipal(aPrincipal, origin); + NS_ENSURE_SUCCESS(rv, rv); + + if (!IsChildProcess()) { + IPC::Permission permission(origin, aType, aPermission, + aExpireType, aExpireTime); + + nsTArray cplist; + ContentParent::GetAll(cplist); + for (uint32_t i = 0; i < cplist.Length(); ++i) { + ContentParent* cp = cplist[i]; + // On platforms where we use a preallocated template process we don't + // want to notify this process about session specific permissions so + // new tabs or apps created on it won't inherit the session permissions. + if (cp->IsPreallocated() && + aExpireType == nsIPermissionManager::EXPIRE_SESSION) + continue; + if (cp->NeedsPermissionsUpdate()) + Unused << cp->SendAddPermission(permission); + } + } + + // look up the type index + int32_t typeIndex = GetTypeIndex(aType.get(), true); + NS_ENSURE_TRUE(typeIndex != -1, NS_ERROR_OUT_OF_MEMORY); + + // When an entry already exists, PutEntry will return that, instead + // of adding a new one + RefPtr key = new PermissionKey(aPrincipal); + PermissionHashKey* entry = mPermissionTable.PutEntry(key); + if (!entry) return NS_ERROR_FAILURE; + if (!entry->GetKey()) { + mPermissionTable.RemoveEntry(entry); + return NS_ERROR_OUT_OF_MEMORY; + } + + // figure out the transaction type, and get any existing permission value + OperationType op; + int32_t index = entry->GetPermissionIndex(typeIndex); + if (index == -1) { + if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) + op = eOperationNone; + else + op = eOperationAdding; + + } else { + PermissionEntry oldPermissionEntry = entry->GetPermissions()[index]; + + // remove the permission if the permission is UNKNOWN, update the + // permission if its value or expire type have changed OR if the time has + // changed and the expire type is time, otherwise, don't modify. There's + // no need to modify a permission that doesn't expire with time when the + // only thing changed is the expire time. + if (aPermission == oldPermissionEntry.mPermission && + aExpireType == oldPermissionEntry.mExpireType && + (aExpireType == nsIPermissionManager::EXPIRE_NEVER || + aExpireTime == oldPermissionEntry.mExpireTime)) + op = eOperationNone; + else if (oldPermissionEntry.mID == cIDPermissionIsDefault) + // The existing permission is one added as a default and the new permission + // doesn't exactly match so we are replacing the default. This is true + // even if the new permission is UNKNOWN_ACTION (which means a "logical + // remove" of the default) + op = eOperationReplacingDefault; + else if (aID == cIDPermissionIsDefault) + // We are adding a default permission but a "real" permission already + // exists. This almost-certainly means we just did a removeAllSince and + // are re-importing defaults - so we can ignore this. + op = eOperationNone; + else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) + op = eOperationRemoving; + else + op = eOperationChanging; + } + + // child processes should *always* be passed a modificationTime of zero. + MOZ_ASSERT(!IsChildProcess() || aModificationTime == 0); + + // do the work for adding, deleting, or changing a permission: + // update the in-memory list, write to the db, and notify consumers. + int64_t id; + if (aModificationTime == 0) { + aModificationTime = PR_Now() / 1000; + } + + switch (op) { + case eOperationNone: + { + // nothing to do + return NS_OK; + } + + case eOperationAdding: + { + if (aDBOperation == eWriteToDB) { + // we'll be writing to the database - generate a known unique id + id = ++mLargestID; + } else { + // we're reading from the database - use the id already assigned + id = aID; + } + +#ifdef MOZ_B2G + // When we do the initial addition of the permissions we don't want to + // inherit session specific permissions from other tabs or apps + // so we ignore them and set the permission to PROMPT_ACTION if it was + // previously allowed or denied by the user. + if (aIgnoreSessionPermissions && + aExpireType == nsIPermissionManager::EXPIRE_SESSION) { + aPermission = nsIPermissionManager::PROMPT_ACTION; + aExpireType = nsIPermissionManager::EXPIRE_NEVER; + } +#endif // MOZ_B2G + + entry->GetPermissions().AppendElement(PermissionEntry(id, typeIndex, aPermission, + aExpireType, aExpireTime, + aModificationTime)); + + if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION) { + UpdateDB(op, mStmtInsert, id, origin, aType, aPermission, aExpireType, aExpireTime, aModificationTime); + } + + if (aNotifyOperation == eNotify) { + NotifyObserversWithPermission(aPrincipal, + mTypeArray[typeIndex], + aPermission, + aExpireType, + aExpireTime, + u"added"); + } + + break; + } + + case eOperationRemoving: + { + PermissionEntry oldPermissionEntry = entry->GetPermissions()[index]; + id = oldPermissionEntry.mID; + entry->GetPermissions().RemoveElementAt(index); + + if (aDBOperation == eWriteToDB) + // We care only about the id here so we pass dummy values for all other + // parameters. + UpdateDB(op, mStmtDelete, id, EmptyCString(), EmptyCString(), 0, + nsIPermissionManager::EXPIRE_NEVER, 0, 0); + + if (aNotifyOperation == eNotify) { + NotifyObserversWithPermission(aPrincipal, + mTypeArray[typeIndex], + oldPermissionEntry.mPermission, + oldPermissionEntry.mExpireType, + oldPermissionEntry.mExpireTime, + u"deleted"); + } + + // If there are no more permissions stored for that entry, clear it. + if (entry->GetPermissions().IsEmpty()) { + mPermissionTable.RemoveEntry(entry); + } + + break; + } + + case eOperationChanging: + { + id = entry->GetPermissions()[index].mID; + + // If the new expireType is EXPIRE_SESSION, then we have to keep a + // copy of the previous permission/expireType values. This cached value will be + // used when restoring the permissions of an app. + if (entry->GetPermissions()[index].mExpireType != nsIPermissionManager::EXPIRE_SESSION && + aExpireType == nsIPermissionManager::EXPIRE_SESSION) { + entry->GetPermissions()[index].mNonSessionPermission = entry->GetPermissions()[index].mPermission; + entry->GetPermissions()[index].mNonSessionExpireType = entry->GetPermissions()[index].mExpireType; + entry->GetPermissions()[index].mNonSessionExpireTime = entry->GetPermissions()[index].mExpireTime; + } else if (aExpireType != nsIPermissionManager::EXPIRE_SESSION) { + entry->GetPermissions()[index].mNonSessionPermission = aPermission; + entry->GetPermissions()[index].mNonSessionExpireType = aExpireType; + entry->GetPermissions()[index].mNonSessionExpireTime = aExpireTime; + } + + entry->GetPermissions()[index].mPermission = aPermission; + entry->GetPermissions()[index].mExpireType = aExpireType; + entry->GetPermissions()[index].mExpireTime = aExpireTime; + entry->GetPermissions()[index].mModificationTime = aModificationTime; + + if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION) + // We care only about the id, the permission and expireType/expireTime/modificationTime here. + // We pass dummy values for all other parameters. + UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(), + aPermission, aExpireType, aExpireTime, aModificationTime); + + if (aNotifyOperation == eNotify) { + NotifyObserversWithPermission(aPrincipal, + mTypeArray[typeIndex], + aPermission, + aExpireType, + aExpireTime, + u"changed"); + } + + break; + } + case eOperationReplacingDefault: + { + // this is handling the case when we have an existing permission + // entry that was created as a "default" (and thus isn't in the DB) with + // an explicit permission (that may include UNKNOWN_ACTION.) + // Note we will *not* get here if we are replacing an already replaced + // default value - that is handled as eOperationChanging. + + // So this is a hybrid of eOperationAdding (as we are writing a new entry + // to the DB) and eOperationChanging (as we are replacing the in-memory + // repr and sending a "changed" notification). + + // We want a new ID even if not writing to the DB, so the modified entry + // in memory doesn't have the magic cIDPermissionIsDefault value. + id = ++mLargestID; + + // The default permission being replaced can't have session expiry. + NS_ENSURE_TRUE(entry->GetPermissions()[index].mExpireType != nsIPermissionManager::EXPIRE_SESSION, + NS_ERROR_UNEXPECTED); + // We don't support the new entry having any expiry - supporting that would + // make things far more complex and none of the permissions we set as a + // default support that. + NS_ENSURE_TRUE(aExpireType == EXPIRE_NEVER, NS_ERROR_UNEXPECTED); + + // update the existing entry in memory. + entry->GetPermissions()[index].mID = id; + entry->GetPermissions()[index].mPermission = aPermission; + entry->GetPermissions()[index].mExpireType = aExpireType; + entry->GetPermissions()[index].mExpireTime = aExpireTime; + entry->GetPermissions()[index].mModificationTime = aModificationTime; + + // If requested, create the entry in the DB. + if (aDBOperation == eWriteToDB) { + UpdateDB(eOperationAdding, mStmtInsert, id, origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); + } + + if (aNotifyOperation == eNotify) { + NotifyObserversWithPermission(aPrincipal, + mTypeArray[typeIndex], + aPermission, + aExpireType, + aExpireTime, + u"changed"); + } + + } + break; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsPermissionManager::Remove(nsIURI* aURI, + const char* aType) +{ + NS_ENSURE_ARG_POINTER(aURI); + + nsCOMPtr principal; + nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + return RemoveFromPrincipal(principal, aType); +} + +NS_IMETHODIMP +nsPermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal, + const char* aType) +{ + ENSURE_NOT_CHILD_PROCESS; + NS_ENSURE_ARG_POINTER(aPrincipal); + NS_ENSURE_ARG_POINTER(aType); + + // System principals are never added to the database, no need to remove them. + if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { + return NS_OK; + } + + // Permissions may not be added to expanded principals. + if (IsExpandedPrincipal(aPrincipal)) { + return NS_ERROR_INVALID_ARG; + } + + // AddInternal() handles removal, just let it do the work + return AddInternal(aPrincipal, + nsDependentCString(aType), + nsIPermissionManager::UNKNOWN_ACTION, + 0, + nsIPermissionManager::EXPIRE_NEVER, + 0, + 0, + eNotify, + eWriteToDB); +} + +NS_IMETHODIMP +nsPermissionManager::RemovePermission(nsIPermission* aPerm) +{ + if (!aPerm) { + return NS_OK; + } + nsCOMPtr principal; + nsresult rv = aPerm->GetPrincipal(getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString type; + rv = aPerm->GetType(type); + NS_ENSURE_SUCCESS(rv, rv); + + // Permissions are uniquely identified by their principal and type. + // We remove the permission using these two pieces of data. + return RemoveFromPrincipal(principal, type.get()); +} + +NS_IMETHODIMP +nsPermissionManager::RemoveAll() +{ + ENSURE_NOT_CHILD_PROCESS; + return RemoveAllInternal(true); +} + +NS_IMETHODIMP +nsPermissionManager::RemoveAllSince(int64_t aSince) +{ + ENSURE_NOT_CHILD_PROCESS; + return RemoveAllModifiedSince(aSince); +} + +void +nsPermissionManager::CloseDB(bool aRebuildOnSuccess) +{ + // Null the statements, this will finalize them. + mStmtInsert = nullptr; + mStmtDelete = nullptr; + mStmtUpdate = nullptr; + if (mDBConn) { + mozIStorageCompletionCallback* cb = new CloseDatabaseListener(this, + aRebuildOnSuccess); + mozilla::DebugOnly rv = mDBConn->AsyncClose(cb); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + mDBConn = nullptr; // Avoid race conditions + } +} + +nsresult +nsPermissionManager::RemoveAllInternal(bool aNotifyObservers) +{ + // Remove from memory and notify immediately. Since the in-memory + // database is authoritative, we do not need confirmation from the + // on-disk database to notify observers. + RemoveAllFromMemory(); + + // Re-import the defaults + ImportDefaults(); + + if (aNotifyObservers) { + NotifyObservers(nullptr, u"cleared"); + } + + // clear the db + if (mDBConn) { + nsCOMPtr removeStmt; + nsresult rv = mDBConn-> + CreateAsyncStatement(NS_LITERAL_CSTRING( + "DELETE FROM moz_perms" + ), getter_AddRefs(removeStmt)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + if (!removeStmt) { + return NS_ERROR_UNEXPECTED; + } + nsCOMPtr pending; + mozIStorageStatementCallback* cb = new DeleteFromMozHostListener(this); + rv = removeStmt->ExecuteAsync(cb, getter_AddRefs(pending)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsPermissionManager::TestExactPermission(nsIURI *aURI, + const char *aType, + uint32_t *aPermission) +{ + nsCOMPtr principal; + nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + return TestExactPermissionFromPrincipal(principal, aType, aPermission); +} + +NS_IMETHODIMP +nsPermissionManager::TestExactPermissionFromPrincipal(nsIPrincipal* aPrincipal, + const char* aType, + uint32_t* aPermission) +{ + return CommonTestPermission(aPrincipal, aType, aPermission, true, true); +} + +NS_IMETHODIMP +nsPermissionManager::TestExactPermanentPermission(nsIPrincipal* aPrincipal, + const char* aType, + uint32_t* aPermission) +{ + return CommonTestPermission(aPrincipal, aType, aPermission, true, false); +} + +NS_IMETHODIMP +nsPermissionManager::TestPermission(nsIURI *aURI, + const char *aType, + uint32_t *aPermission) +{ + nsCOMPtr principal; + nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + return TestPermissionFromPrincipal(principal, aType, aPermission); +} + +NS_IMETHODIMP +nsPermissionManager::TestPermissionFromWindow(mozIDOMWindow* aWindow, + const char* aType, + uint32_t* aPermission) +{ + NS_ENSURE_ARG(aWindow); + nsCOMPtr window = nsPIDOMWindowInner::From(aWindow); + + // Get the document for security check + nsCOMPtr document = window->GetExtantDoc(); + NS_ENSURE_TRUE(document, NS_NOINTERFACE); + + nsCOMPtr principal = document->NodePrincipal(); + return TestPermissionFromPrincipal(principal, aType, aPermission); +} + +NS_IMETHODIMP +nsPermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal, + const char* aType, + uint32_t* aPermission) +{ + return CommonTestPermission(aPrincipal, aType, aPermission, false, true); +} + +NS_IMETHODIMP +nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal, + const char* aType, + bool aExactHostMatch, + nsIPermission** aResult) +{ + NS_ENSURE_ARG_POINTER(aPrincipal); + NS_ENSURE_ARG_POINTER(aType); + + *aResult = nullptr; + + if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { + return NS_OK; + } + + // Querying the permission object of an nsEP is non-sensical. + if (IsExpandedPrincipal(aPrincipal)) { + return NS_ERROR_INVALID_ARG; + } + + int32_t typeIndex = GetTypeIndex(aType, false); + // If type == -1, the type isn't known, + // so just return NS_OK + if (typeIndex == -1) return NS_OK; + + PermissionHashKey* entry = GetPermissionHashKey(aPrincipal, typeIndex, aExactHostMatch); + if (!entry) { + return NS_OK; + } + + // We don't call GetPermission(typeIndex) because that returns a fake + // UNKNOWN_ACTION entry if there is no match. + int32_t idx = entry->GetPermissionIndex(typeIndex); + if (-1 == idx) { + return NS_OK; + } + + nsCOMPtr principal; + nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + PermissionEntry& perm = entry->GetPermissions()[idx]; + nsCOMPtr r = nsPermission::Create(principal, + mTypeArray.ElementAt(perm.mType), + perm.mPermission, + perm.mExpireType, + perm.mExpireTime); + if (NS_WARN_IF(!r)) { + return NS_ERROR_FAILURE; + } + r.forget(aResult); + return NS_OK; +} + +nsresult +nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal, + const char *aType, + uint32_t *aPermission, + bool aExactHostMatch, + bool aIncludingSession) +{ + NS_ENSURE_ARG_POINTER(aPrincipal); + NS_ENSURE_ARG_POINTER(aType); + + if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { + *aPermission = nsIPermissionManager::ALLOW_ACTION; + return NS_OK; + } + + // Set the default. + *aPermission = nsIPermissionManager::UNKNOWN_ACTION; + + // For expanded principals, we want to iterate over the whitelist and see + // if the permission is granted for any of them. + nsCOMPtr ep = do_QueryInterface(aPrincipal); + if (ep) { + nsTArray>* whitelist; + nsresult rv = ep->GetWhiteList(&whitelist); + NS_ENSURE_SUCCESS(rv, rv); + + for (size_t i = 0; i < whitelist->Length(); ++i) { + uint32_t perm; + rv = CommonTestPermission(whitelist->ElementAt(i), aType, &perm, aExactHostMatch, + aIncludingSession); + NS_ENSURE_SUCCESS(rv, rv); + if (perm == nsIPermissionManager::ALLOW_ACTION) { + *aPermission = perm; + return NS_OK; + } else if (perm == nsIPermissionManager::PROMPT_ACTION) { + // Store it, but keep going to see if we can do better. + *aPermission = perm; + } + } + + return NS_OK; + } + + int32_t typeIndex = GetTypeIndex(aType, false); + // If type == -1, the type isn't known, + // so just return NS_OK + if (typeIndex == -1) return NS_OK; + + PermissionHashKey* entry = GetPermissionHashKey(aPrincipal, typeIndex, aExactHostMatch); + if (!entry || + (!aIncludingSession && + entry->GetPermission(typeIndex).mNonSessionExpireType == + nsIPermissionManager::EXPIRE_SESSION)) { + return NS_OK; + } + + *aPermission = aIncludingSession + ? entry->GetPermission(typeIndex).mPermission + : entry->GetPermission(typeIndex).mNonSessionPermission; + + return NS_OK; +} + +// Returns PermissionHashKey for a given { host, appId, isInBrowserElement } tuple. +// This is not simply using PermissionKey because we will walk-up domains in +// case of |host| contains sub-domains. +// Returns null if nothing found. +// Also accepts host on the format "". This will perform an exact match +// lookup as the string doesn't contain any dots. +nsPermissionManager::PermissionHashKey* +nsPermissionManager::GetPermissionHashKey(nsIPrincipal* aPrincipal, + uint32_t aType, + bool aExactHostMatch) +{ + PermissionHashKey* entry = nullptr; + + RefPtr key = new PermissionKey(aPrincipal); + entry = mPermissionTable.GetEntry(key); + + if (entry) { + PermissionEntry permEntry = entry->GetPermission(aType); + + // if the entry is expired, remove and keep looking for others. + // Note that EXPIRE_SESSION only honors expireTime if it is nonzero. + if ((permEntry.mExpireType == nsIPermissionManager::EXPIRE_TIME || + (permEntry.mExpireType == nsIPermissionManager::EXPIRE_SESSION && + permEntry.mExpireTime != 0)) && + permEntry.mExpireTime <= (PR_Now() / 1000)) { + entry = nullptr; + RemoveFromPrincipal(aPrincipal, mTypeArray[aType].get()); + } else if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { + entry = nullptr; + } + } + + if (entry) { + return entry; + } + + // If aExactHostMatch wasn't true, we can check if the base domain has a permission entry. + if (!aExactHostMatch) { + nsCOMPtr uri; + nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv)) { + return nullptr; + } + + nsAutoCString host; + rv = uri->GetHost(host); + if (NS_FAILED(rv)) { + return nullptr; + } + + nsCString domain = GetNextSubDomainForHost(host); + if (domain.IsEmpty()) { + return nullptr; + } + + // Create a new principal which is identical to the current one, but with the new host + nsCOMPtr newURI; + rv = uri->Clone(getter_AddRefs(newURI)); + if (NS_FAILED(rv)) { + return nullptr; + } + + rv = newURI->SetHost(domain); + if (NS_FAILED(rv)) { + return nullptr; + } + + // Copy the attributes over + mozilla::PrincipalOriginAttributes attrs = + mozilla::BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(); + + // Disable userContext and firstParty isolation for permissions. + attrs.StripUserContextIdAndFirstPartyDomain(); + + nsCOMPtr principal = + mozilla::BasePrincipal::CreateCodebasePrincipal(newURI, attrs); + + return GetPermissionHashKey(principal, aType, aExactHostMatch); + } + + // No entry, really... + return nullptr; +} + +NS_IMETHODIMP nsPermissionManager::GetEnumerator(nsISimpleEnumerator **aEnum) +{ + // roll an nsCOMArray of all our permissions, then hand out an enumerator + nsCOMArray array; + + for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { + PermissionHashKey* entry = iter.Get(); + for (const auto& permEntry : entry->GetPermissions()) { + // Given how "default" permissions work and the possibility of them being + // overridden with UNKNOWN_ACTION, we might see this value here - but we + // do *not* want to return them via the enumerator. + if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { + continue; + } + + nsCOMPtr principal; + nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + continue; + } + + nsCOMPtr permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + array.AppendObject(permission); + } + } + + return NS_NewArrayEnumerator(aEnum, array); +} + +NS_IMETHODIMP nsPermissionManager::GetAllForURI(nsIURI* aURI, nsISimpleEnumerator **aEnum) +{ + nsCOMArray array; + + nsCOMPtr principal; + nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + RefPtr key = new PermissionKey(principal); + PermissionHashKey* entry = mPermissionTable.GetEntry(key); + + if (entry) { + for (const auto& permEntry : entry->GetPermissions()) { + // Only return custom permissions + if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { + continue; + } + + nsCOMPtr permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + array.AppendObject(permission); + } + } + + return NS_NewArrayEnumerator(aEnum, array); +} + +NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) +{ + ENSURE_NOT_CHILD_PROCESS; + + if (!nsCRT::strcmp(aTopic, "profile-before-change")) { + // The profile is about to change, + // or is going away because the application is shutting down. + mIsShuttingDown = true; + RemoveAllFromMemory(); + CloseDB(false); + } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) { + // the profile has already changed; init the db from the new location + InitDB(false); + } + + return NS_OK; +} + +nsresult +nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime) +{ + ENSURE_NOT_CHILD_PROCESS; + + nsCOMArray array; + for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { + PermissionHashKey* entry = iter.Get(); + for (const auto& permEntry : entry->GetPermissions()) { + if (aModificationTime > permEntry.mModificationTime) { + continue; + } + + nsCOMPtr principal; + nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + continue; + } + + nsCOMPtr permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + array.AppendObject(permission); + } + } + + for (int32_t i = 0; i principal; + nsAutoCString type; + + nsresult rv = array[i]->GetPrincipal(getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + NS_ERROR("GetPrincipal() failed!"); + continue; + } + + rv = array[i]->GetType(type); + if (NS_FAILED(rv)) { + NS_ERROR("GetType() failed!"); + continue; + } + + // AddInternal handles removal, so let it do the work... + AddInternal( + principal, + type, + nsIPermissionManager::UNKNOWN_ACTION, + 0, + nsIPermissionManager::EXPIRE_NEVER, 0, 0, + nsPermissionManager::eNotify, + nsPermissionManager::eWriteToDB); + } + // now re-import any defaults as they may now be required if we just deleted + // an override. + ImportDefaults(); + return NS_OK; +} + +NS_IMETHODIMP +nsPermissionManager::RemovePermissionsWithAttributes(const nsAString& aPattern) +{ + ENSURE_NOT_CHILD_PROCESS; + mozilla::OriginAttributesPattern pattern; + if (!pattern.Init(aPattern)) { + return NS_ERROR_INVALID_ARG; + } + + return RemovePermissionsWithAttributes(pattern); +} + +nsresult +nsPermissionManager::RemovePermissionsWithAttributes(mozilla::OriginAttributesPattern& aPattern) +{ + nsCOMArray permissions; + for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { + PermissionHashKey* entry = iter.Get(); + + nsCOMPtr principal; + nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + continue; + } + + if (!aPattern.Matches(mozilla::BasePrincipal::Cast(principal)->OriginAttributesRef())) { + continue; + } + + for (const auto& permEntry : entry->GetPermissions()) { + nsCOMPtr permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + permissions.AppendObject(permission); + } + } + + for (int32_t i = 0; i < permissions.Count(); ++i) { + nsCOMPtr principal; + nsAutoCString type; + + permissions[i]->GetPrincipal(getter_AddRefs(principal)); + permissions[i]->GetType(type); + + AddInternal(principal, + type, + nsIPermissionManager::UNKNOWN_ACTION, + 0, + nsIPermissionManager::EXPIRE_NEVER, + 0, + 0, + nsPermissionManager::eNotify, + nsPermissionManager::eWriteToDB); + } + + return NS_OK; +} + +//***************************************************************************** +//*** nsPermissionManager private methods +//***************************************************************************** + +nsresult +nsPermissionManager::RemoveAllFromMemory() +{ + mLargestID = 0; + mTypeArray.Clear(); + mPermissionTable.Clear(); + + return NS_OK; +} + +// Returns -1 on failure +int32_t +nsPermissionManager::GetTypeIndex(const char *aType, + bool aAdd) +{ + for (uint32_t i = 0; i < mTypeArray.Length(); ++i) + if (mTypeArray[i].Equals(aType)) + return i; + + if (!aAdd) { + // Not found, but that is ok - we were just looking. + return -1; + } + + // This type was not registered before. + // append it to the array, without copy-constructing the string + nsCString *elem = mTypeArray.AppendElement(); + if (!elem) + return -1; + + elem->Assign(aType); + return mTypeArray.Length() - 1; +} + +// wrapper function for mangling (host,type,perm,expireType,expireTime) +// set into an nsIPermission. +void +nsPermissionManager::NotifyObserversWithPermission(nsIPrincipal* aPrincipal, + const nsCString &aType, + uint32_t aPermission, + uint32_t aExpireType, + int64_t aExpireTime, + const char16_t *aData) +{ + nsCOMPtr permission = + nsPermission::Create(aPrincipal, aType, aPermission, + aExpireType, aExpireTime); + if (permission) + NotifyObservers(permission, aData); +} + +// notify observers that the permission list changed. there are four possible +// values for aData: +// "deleted" means a permission was deleted. aPermission is the deleted permission. +// "added" means a permission was added. aPermission is the added permission. +// "changed" means a permission was altered. aPermission is the new permission. +// "cleared" means the entire permission list was cleared. aPermission is null. +void +nsPermissionManager::NotifyObservers(nsIPermission *aPermission, + const char16_t *aData) +{ + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + if (observerService) + observerService->NotifyObservers(aPermission, + kPermissionChangeNotification, + aData); +} + +nsresult +nsPermissionManager::Read() +{ + ENSURE_NOT_CHILD_PROCESS; + + nsresult rv; + + // delete expired permissions before we read in the db + { + // this deletion has its own scope so the write lock is released when done. + nsCOMPtr stmtDeleteExpired; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "DELETE FROM moz_perms WHERE expireType = ?1 AND expireTime <= ?2"), + getter_AddRefs(stmtDeleteExpired)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmtDeleteExpired->BindInt32ByIndex(0, nsIPermissionManager::EXPIRE_TIME); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmtDeleteExpired->BindInt64ByIndex(1, PR_Now() / 1000); + NS_ENSURE_SUCCESS(rv, rv); + + bool hasResult; + rv = stmtDeleteExpired->ExecuteStep(&hasResult); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCOMPtr stmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT id, origin, type, permission, expireType, expireTime, modificationTime " + "FROM moz_perms"), getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, rv); + + int64_t id; + nsAutoCString origin, type; + uint32_t permission; + uint32_t expireType; + int64_t expireTime; + int64_t modificationTime; + bool hasResult; + bool readError = false; + + while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { + // explicitly set our entry id counter for use in AddInternal(), + // and keep track of the largest id so we know where to pick up. + id = stmt->AsInt64(0); + if (id > mLargestID) + mLargestID = id; + + rv = stmt->GetUTF8String(1, origin); + if (NS_FAILED(rv)) { + readError = true; + continue; + } + + rv = stmt->GetUTF8String(2, type); + if (NS_FAILED(rv)) { + readError = true; + continue; + } + + permission = stmt->AsInt32(3); + expireType = stmt->AsInt32(4); + + // convert into int64_t values (milliseconds) + expireTime = stmt->AsInt64(5); + modificationTime = stmt->AsInt64(6); + + nsCOMPtr principal; + nsresult rv = GetPrincipalFromOrigin(origin, getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + readError = true; + continue; + } + + rv = AddInternal(principal, type, permission, id, expireType, expireTime, + modificationTime, eDontNotify, eNoDBOperation); + if (NS_FAILED(rv)) { + readError = true; + continue; + } + } + + if (readError) { + NS_ERROR("Error occured while reading the permissions database!"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +static const char kMatchTypeHost[] = "host"; +static const char kMatchTypeOrigin[] = "origin"; + +// Import() will read a file from the profile directory and add them to the +// database before deleting the file - ie, this is a one-shot operation that +// will not succeed on subsequent runs as the file imported from is removed. +nsresult +nsPermissionManager::Import() +{ + nsresult rv; + + nsCOMPtr permissionsFile; + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(permissionsFile)); + if (NS_FAILED(rv)) return rv; + + rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(HOSTPERM_FILE_NAME)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr fileInputStream; + rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), + permissionsFile); + NS_ENSURE_SUCCESS(rv, rv); + + rv = _DoImport(fileInputStream, mDBConn); + NS_ENSURE_SUCCESS(rv, rv); + + // we successfully imported and wrote to the DB - delete the old file. + permissionsFile->Remove(false); + return NS_OK; +} + +// ImportDefaults will read a URL with default permissions and add them to the +// in-memory copy of permissions. The database is *not* written to. +nsresult +nsPermissionManager::ImportDefaults() +{ + nsCString defaultsURL = mozilla::Preferences::GetCString(kDefaultsUrlPrefName); + if (defaultsURL.IsEmpty()) { // == Don't use built-in permissions. + return NS_OK; + } + + nsCOMPtr defaultsURI; + nsresult rv = NS_NewURI(getter_AddRefs(defaultsURI), defaultsURL); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr channel; + rv = NS_NewChannel(getter_AddRefs(channel), + defaultsURI, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, + nsIContentPolicy::TYPE_OTHER); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr inputStream; + rv = channel->Open2(getter_AddRefs(inputStream)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = _DoImport(inputStream, nullptr); + inputStream->Close(); + return rv; +} + +// _DoImport reads the specified stream and adds the parsed elements. If +// |conn| is passed, the imported data will be written to the database, but if +// |conn| is null the data will be added only to the in-memory copy of the +// database. +nsresult +nsPermissionManager::_DoImport(nsIInputStream *inputStream, mozIStorageConnection *conn) +{ + ENSURE_NOT_CHILD_PROCESS; + + nsresult rv; + // start a transaction on the storage db, to optimize insertions. + // transaction will automically commit on completion + // (note the transaction is a no-op if a null connection is passed) + mozStorageTransaction transaction(conn, true); + + // The DB operation - we only try and write if a connection was passed. + DBOperationType operation = conn ? eWriteToDB : eNoDBOperation; + // and if no DB connection was passed we assume this is a "default" permission, + // so use the special ID which indicates this. + int64_t id = conn ? 0 : cIDPermissionIsDefault; + + /* format is: + * matchtype \t type \t permission \t host + * Only "host" is supported for matchtype + * type is a string that identifies the type of permission (e.g. "cookie") + * permission is an integer between 1 and 15 + */ + + // Ideally we'd do this with nsILineInputString, but this is called with an + // nsIInputStream that comes from a resource:// URI, which doesn't support + // that interface. So NS_ReadLine to the rescue... + nsLineBuffer lineBuffer; + nsCString line; + bool isMore = true; + do { + rv = NS_ReadLine(inputStream, &lineBuffer, line, &isMore); + NS_ENSURE_SUCCESS(rv, rv); + + if (line.IsEmpty() || line.First() == '#') { + continue; + } + + nsTArray lineArray; + + // Split the line at tabs + ParseString(line, '\t', lineArray); + + if (lineArray[0].EqualsLiteral(kMatchTypeHost) && + lineArray.Length() == 4) { + nsresult error = NS_OK; + uint32_t permission = lineArray[2].ToInteger(&error); + if (NS_FAILED(error)) + continue; + + // the import file format doesn't handle modification times, so we use + // 0, which AddInternal will convert to now() + int64_t modificationTime = 0; + + UpgradeHostToOriginHostfileImport upHelper(this, operation, id); + error = UpgradeHostToOriginAndInsert(lineArray[3], lineArray[1], permission, + nsIPermissionManager::EXPIRE_NEVER, 0, + modificationTime, nsIScriptSecurityManager::NO_APP_ID, + false, &upHelper); + if (NS_FAILED(error)) { + NS_WARNING("There was a problem importing a host permission"); + } + } else if (lineArray[0].EqualsLiteral(kMatchTypeOrigin) && + lineArray.Length() == 4) { + nsresult error = NS_OK; + uint32_t permission = lineArray[2].ToInteger(&error); + if (NS_FAILED(error)) + continue; + + nsCOMPtr principal; + error = GetPrincipalFromOrigin(lineArray[3], getter_AddRefs(principal)); + if (NS_FAILED(error)) { + NS_WARNING("Couldn't import an origin permission - malformed origin"); + continue; + } + + // the import file format doesn't handle modification times, so we use + // 0, which AddInternal will convert to now() + int64_t modificationTime = 0; + + error = AddInternal(principal, lineArray[1], permission, id, + nsIPermissionManager::EXPIRE_NEVER, 0, + modificationTime, + eDontNotify, operation); + if (NS_FAILED(error)) { + NS_WARNING("There was a problem importing an origin permission"); + } + } + + } while (isMore); + + return NS_OK; +} + +void +nsPermissionManager::UpdateDB(OperationType aOp, + mozIStorageAsyncStatement* aStmt, + int64_t aID, + const nsACString &aOrigin, + const nsACString &aType, + uint32_t aPermission, + uint32_t aExpireType, + int64_t aExpireTime, + int64_t aModificationTime) +{ + ENSURE_NOT_CHILD_PROCESS_NORET; + + nsresult rv; + + // no statement is ok - just means we don't have a profile + if (!aStmt) + return; + + switch (aOp) { + case eOperationAdding: + { + rv = aStmt->BindInt64ByIndex(0, aID); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindUTF8StringByIndex(1, aOrigin); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindUTF8StringByIndex(2, aType); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(3, aPermission); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(4, aExpireType); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(5, aExpireTime); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(6, aModificationTime); + break; + } + + case eOperationRemoving: + { + rv = aStmt->BindInt64ByIndex(0, aID); + break; + } + + case eOperationChanging: + { + rv = aStmt->BindInt64ByIndex(0, aID); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(1, aPermission); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(2, aExpireType); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(3, aExpireTime); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(4, aModificationTime); + break; + } + + default: + { + NS_NOTREACHED("need a valid operation in UpdateDB()!"); + rv = NS_ERROR_UNEXPECTED; + break; + } + } + + if (NS_FAILED(rv)) { + NS_WARNING("db change failed!"); + return; + } + + nsCOMPtr pending; + rv = aStmt->ExecuteAsync(nullptr, getter_AddRefs(pending)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); +} + +NS_IMETHODIMP +nsPermissionManager::UpdateExpireTime(nsIPrincipal* aPrincipal, + const char* aType, + bool aExactHostMatch, + uint64_t aSessionExpireTime, + uint64_t aPersistentExpireTime) +{ + NS_ENSURE_ARG_POINTER(aPrincipal); + NS_ENSURE_ARG_POINTER(aType); + + uint64_t nowms = PR_Now() / 1000; + if (aSessionExpireTime < nowms || aPersistentExpireTime < nowms) { + return NS_ERROR_INVALID_ARG; + } + + if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { + return NS_OK; + } + + // Setting the expire time of an nsEP is non-sensical. + if (IsExpandedPrincipal(aPrincipal)) { + return NS_ERROR_INVALID_ARG; + } + + int32_t typeIndex = GetTypeIndex(aType, false); + // If type == -1, the type isn't known, + // so just return NS_OK + if (typeIndex == -1) return NS_OK; + + PermissionHashKey* entry = GetPermissionHashKey(aPrincipal, typeIndex, aExactHostMatch); + if (!entry) { + return NS_OK; + } + + int32_t idx = entry->GetPermissionIndex(typeIndex); + if (-1 == idx) { + return NS_OK; + } + + PermissionEntry& perm = entry->GetPermissions()[idx]; + if (perm.mExpireType == EXPIRE_TIME) { + perm.mExpireTime = aPersistentExpireTime; + } else if (perm.mExpireType == EXPIRE_SESSION && perm.mExpireTime != 0) { + perm.mExpireTime = aSessionExpireTime; + } + return NS_OK; +} + +nsresult +nsPermissionManager::FetchPermissions() { + MOZ_ASSERT(IsChildProcess(), "FetchPermissions can only be invoked in child process"); + // Get the permissions from the parent process + InfallibleTArray perms; + ChildProcess()->SendReadPermissions(&perms); + + for (uint32_t i = 0; i < perms.Length(); i++) { + const IPC::Permission &perm = perms[i]; + + nsCOMPtr principal; + nsresult rv = GetPrincipalFromOrigin(perm.origin, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + // The child process doesn't care about modification times - it neither + // reads nor writes, nor removes them based on the date - so 0 (which + // will end up as now()) is fine. + uint64_t modificationTime = 0; + AddInternal(principal, perm.type, perm.capability, 0, perm.expireType, + perm.expireTime, modificationTime, eNotify, eNoDBOperation, + true /* ignoreSessionPermissions */); + } + return NS_OK; +} diff --git a/extensions/cookie/nsPermissionManager.h b/extensions/cookie/nsPermissionManager.h new file mode 100644 index 000000000..4b21500b1 --- /dev/null +++ b/extensions/cookie/nsPermissionManager.h @@ -0,0 +1,295 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsPermissionManager_h__ +#define nsPermissionManager_h__ + +#include "nsIPermissionManager.h" +#include "nsIObserver.h" +#include "nsWeakReference.h" +#include "nsCOMPtr.h" +#include "nsIInputStream.h" +#include "nsTHashtable.h" +#include "nsTArray.h" +#include "nsString.h" +#include "nsPermission.h" +#include "nsHashKeys.h" +#include "nsCOMArray.h" +#include "nsDataHashtable.h" + +namespace mozilla { +class OriginAttributesPattern; +} + +class nsIPermission; +class mozIStorageConnection; +class mozIStorageAsyncStatement; + +//////////////////////////////////////////////////////////////////////////////// + +class nsPermissionManager final : public nsIPermissionManager, + public nsIObserver, + public nsSupportsWeakReference +{ +public: + class PermissionEntry + { + public: + PermissionEntry(int64_t aID, uint32_t aType, uint32_t aPermission, + uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime) + : mID(aID) + , mType(aType) + , mPermission(aPermission) + , mExpireType(aExpireType) + , mExpireTime(aExpireTime) + , mModificationTime(aModificationTime) + , mNonSessionPermission(aPermission) + , mNonSessionExpireType(aExpireType) + , mNonSessionExpireTime(aExpireTime) + {} + + int64_t mID; + uint32_t mType; + uint32_t mPermission; + uint32_t mExpireType; + int64_t mExpireTime; + int64_t mModificationTime; + uint32_t mNonSessionPermission; + uint32_t mNonSessionExpireType; + uint32_t mNonSessionExpireTime; + }; + + /** + * PermissionKey is the key used by PermissionHashKey hash table. + * + * NOTE: It could be implementing nsIHashable but there is no reason to worry + * with XPCOM interfaces while we don't need to. + */ + class PermissionKey + { + public: + explicit PermissionKey(nsIPrincipal* aPrincipal); + explicit PermissionKey(const nsACString& aOrigin) + : mOrigin(aOrigin) + { + } + + bool operator==(const PermissionKey& aKey) const { + return mOrigin.Equals(aKey.mOrigin); + } + + PLDHashNumber GetHashCode() const { + return mozilla::HashString(mOrigin); + } + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PermissionKey) + + nsCString mOrigin; + + private: + // Default ctor shouldn't be used. + PermissionKey() = delete; + + // Dtor shouldn't be used outside of the class. + ~PermissionKey() {}; + }; + + class PermissionHashKey : public nsRefPtrHashKey + { + public: + explicit PermissionHashKey(const PermissionKey* aPermissionKey) + : nsRefPtrHashKey(aPermissionKey) + {} + + PermissionHashKey(const PermissionHashKey& toCopy) + : nsRefPtrHashKey(toCopy) + , mPermissions(toCopy.mPermissions) + {} + + bool KeyEquals(const PermissionKey* aKey) const + { + return *aKey == *GetKey(); + } + + static PLDHashNumber HashKey(const PermissionKey* aKey) + { + return aKey->GetHashCode(); + } + + // Force the hashtable to use the copy constructor when shuffling entries + // around, otherwise the Auto part of our AutoTArray won't be happy! + enum { ALLOW_MEMMOVE = false }; + + inline nsTArray & GetPermissions() + { + return mPermissions; + } + + inline int32_t GetPermissionIndex(uint32_t aType) const + { + for (uint32_t i = 0; i < mPermissions.Length(); ++i) + if (mPermissions[i].mType == aType) + return i; + + return -1; + } + + inline PermissionEntry GetPermission(uint32_t aType) const + { + for (uint32_t i = 0; i < mPermissions.Length(); ++i) + if (mPermissions[i].mType == aType) + return mPermissions[i]; + + // unknown permission... return relevant data + return PermissionEntry(-1, aType, nsIPermissionManager::UNKNOWN_ACTION, + nsIPermissionManager::EXPIRE_NEVER, 0, 0); + } + + private: + AutoTArray mPermissions; + }; + + // nsISupports + NS_DECL_ISUPPORTS + NS_DECL_NSIPERMISSIONMANAGER + NS_DECL_NSIOBSERVER + + nsPermissionManager(); + static nsIPermissionManager* GetXPCOMSingleton(); + nsresult Init(); + + // enums for AddInternal() + enum OperationType { + eOperationNone, + eOperationAdding, + eOperationRemoving, + eOperationChanging, + eOperationReplacingDefault + }; + + enum DBOperationType { + eNoDBOperation, + eWriteToDB + }; + + enum NotifyOperationType { + eDontNotify, + eNotify + }; + + // A special value for a permission ID that indicates the ID was loaded as + // a default value. These will never be written to the database, but may + // be overridden with an explicit permission (including UNKNOWN_ACTION) + static const int64_t cIDPermissionIsDefault = -1; + + nsresult AddInternal(nsIPrincipal* aPrincipal, + const nsAFlatCString &aType, + uint32_t aPermission, + int64_t aID, + uint32_t aExpireType, + int64_t aExpireTime, + int64_t aModificationTime, + NotifyOperationType aNotifyOperation, + DBOperationType aDBOperation, + const bool aIgnoreSessionPermissions = false); + + /** + * Initialize the "clear-origin-attributes-data" observing. + * Will create a nsPermissionManager instance if needed. + * That way, we can prevent have nsPermissionManager created at startup just + * to be able to clear data when an application is uninstalled. + */ + static void ClearOriginDataObserverInit(); + + nsresult + RemovePermissionsWithAttributes(mozilla::OriginAttributesPattern& aAttrs); + +private: + virtual ~nsPermissionManager(); + + int32_t GetTypeIndex(const char *aTypeString, + bool aAdd); + + PermissionHashKey* GetPermissionHashKey(nsIPrincipal* aPrincipal, + uint32_t aType, + bool aExactHostMatch); + + nsresult CommonTestPermission(nsIPrincipal* aPrincipal, + const char *aType, + uint32_t *aPermission, + bool aExactHostMatch, + bool aIncludingSession); + + nsresult OpenDatabase(nsIFile* permissionsFile); + nsresult InitDB(bool aRemoveFile); + nsresult CreateTable(); + nsresult Import(); + nsresult ImportDefaults(); + nsresult _DoImport(nsIInputStream *inputStream, mozIStorageConnection *aConn); + nsresult Read(); + void NotifyObserversWithPermission(nsIPrincipal* aPrincipal, + const nsCString &aType, + uint32_t aPermission, + uint32_t aExpireType, + int64_t aExpireTime, + const char16_t *aData); + void NotifyObservers(nsIPermission *aPermission, const char16_t *aData); + + // Finalize all statements, close the DB and null it. + // if aRebuildOnSuccess, reinitialize database + void CloseDB(bool aRebuildOnSuccess = false); + + nsresult RemoveAllInternal(bool aNotifyObservers); + nsresult RemoveAllFromMemory(); + static void UpdateDB(OperationType aOp, + mozIStorageAsyncStatement* aStmt, + int64_t aID, + const nsACString& aOrigin, + const nsACString& aType, + uint32_t aPermission, + uint32_t aExpireType, + int64_t aExpireTime, + int64_t aModificationTime); + + /** + * This method removes all permissions modified after the specified time. + */ + nsresult + RemoveAllModifiedSince(int64_t aModificationTime); + + /** + * Retrieve permissions from chrome process. + */ + nsresult + FetchPermissions(); + + nsCOMPtr mDBConn; + nsCOMPtr mStmtInsert; + nsCOMPtr mStmtDelete; + nsCOMPtr mStmtUpdate; + + bool mMemoryOnlyDB; + + nsTHashtable mPermissionTable; + // a unique, monotonically increasing id used to identify each database entry + int64_t mLargestID; + + // An array to store the strings identifying the different types. + nsTArray mTypeArray; + + // Initially, |false|. Set to |true| once shutdown has started, to avoid + // reopening the database. + bool mIsShuttingDown; + + friend class DeleteFromMozHostListener; + friend class CloseDatabaseListener; +}; + +// {4F6B5E00-0C36-11d5-A535-0010A401EB10} +#define NS_PERMISSIONMANAGER_CID \ +{ 0x4f6b5e00, 0xc36, 0x11d5, { 0xa5, 0x35, 0x0, 0x10, 0xa4, 0x1, 0xeb, 0x10 } } + +#endif /* nsPermissionManager_h__ */ diff --git a/extensions/cookie/nsPopupWindowManager.cpp b/extensions/cookie/nsPopupWindowManager.cpp new file mode 100644 index 000000000..d95fb7440 --- /dev/null +++ b/extensions/cookie/nsPopupWindowManager.cpp @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPopupWindowManager.h" + +#include "nsCRT.h" +#include "nsIServiceManager.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIPrincipal.h" +#include "nsIURI.h" +#include "mozilla/Services.h" + +/** + * The Popup Window Manager maintains popup window permissions by website. + */ + +static const char kPopupDisablePref[] = "dom.disable_open_during_load"; + +//***************************************************************************** +//*** nsPopupWindowManager object management and nsISupports +//***************************************************************************** + +nsPopupWindowManager::nsPopupWindowManager() : + mPolicy(ALLOW_POPUP) +{ +} + +nsPopupWindowManager::~nsPopupWindowManager() +{ +} + +NS_IMPL_ISUPPORTS(nsPopupWindowManager, + nsIPopupWindowManager, + nsIObserver, + nsISupportsWeakReference) + +nsresult +nsPopupWindowManager::Init() +{ + nsresult rv; + mPermissionManager = mozilla::services::GetPermissionManager(); + + nsCOMPtr prefBranch = + do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + bool permission; + rv = prefBranch->GetBoolPref(kPopupDisablePref, &permission); + if (NS_FAILED(rv)) { + permission = true; + } + mPolicy = permission ? (uint32_t) DENY_POPUP : (uint32_t) ALLOW_POPUP; + + prefBranch->AddObserver(kPopupDisablePref, this, true); + } + + return NS_OK; +} + +//***************************************************************************** +//*** nsPopupWindowManager::nsIPopupWindowManager +//***************************************************************************** + +NS_IMETHODIMP +nsPopupWindowManager::TestPermission(nsIPrincipal* aPrincipal, + uint32_t *aPermission) +{ + NS_ENSURE_ARG_POINTER(aPrincipal); + NS_ENSURE_ARG_POINTER(aPermission); + + uint32_t permit; + *aPermission = mPolicy; + + if (mPermissionManager) { + if (NS_SUCCEEDED(mPermissionManager->TestPermissionFromPrincipal(aPrincipal, "popup", &permit))) { + // Share some constants between interfaces? + if (permit == nsIPermissionManager::ALLOW_ACTION) { + *aPermission = ALLOW_POPUP; + } else if (permit == nsIPermissionManager::DENY_ACTION) { + *aPermission = DENY_POPUP; + } + } + } + + return NS_OK; +} + +//***************************************************************************** +//*** nsPopupWindowManager::nsIObserver +//***************************************************************************** +NS_IMETHODIMP +nsPopupWindowManager::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + nsCOMPtr prefBranch = do_QueryInterface(aSubject); + NS_ASSERTION(!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic), + "unexpected topic - we only deal with pref changes!"); + + if (prefBranch) { + // refresh our local copy of the "disable popups" pref + bool permission = true; + prefBranch->GetBoolPref(kPopupDisablePref, &permission); + + mPolicy = permission ? (uint32_t) DENY_POPUP : (uint32_t) ALLOW_POPUP; + } + + return NS_OK; +} diff --git a/extensions/cookie/nsPopupWindowManager.h b/extensions/cookie/nsPopupWindowManager.h new file mode 100644 index 000000000..dd83b5abb --- /dev/null +++ b/extensions/cookie/nsPopupWindowManager.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsPopupWindowManager_h__ +#define nsPopupWindowManager_h__ + +#include "nsCOMPtr.h" + +#include "nsIObserver.h" +#include "nsIPermissionManager.h" +#include "nsIPopupWindowManager.h" +#include "nsWeakReference.h" + +class nsPopupWindowManager : public nsIPopupWindowManager, + public nsIObserver, + public nsSupportsWeakReference { + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPOPUPWINDOWMANAGER + NS_DECL_NSIOBSERVER + + nsPopupWindowManager(); + nsresult Init(); + +private: + virtual ~nsPopupWindowManager(); + + uint32_t mPolicy; + nsCOMPtr mPermissionManager; +}; + +// {822bcd11-6432-48be-9e9d-36f7804b7747} +#define NS_POPUPWINDOWMANAGER_CID \ + {0x822bcd11, 0x6432, 0x48be, {0x9e, 0x9d, 0x36, 0xf7, 0x80, 0x4b, 0x77, 0x47}} + +#endif /* nsPopupWindowManager_h__ */ diff --git a/extensions/cookie/test/beltzner.jpg b/extensions/cookie/test/beltzner.jpg new file mode 100644 index 000000000..75849bc40 Binary files /dev/null and b/extensions/cookie/test/beltzner.jpg differ diff --git a/extensions/cookie/test/beltzner.jpg^headers^ b/extensions/cookie/test/beltzner.jpg^headers^ new file mode 100644 index 000000000..cb51f2701 --- /dev/null +++ b/extensions/cookie/test/beltzner.jpg^headers^ @@ -0,0 +1,3 @@ +Cache-Control: no-store +Set-Cookie: mike=beltzer + diff --git a/extensions/cookie/test/browser.ini b/extensions/cookie/test/browser.ini new file mode 100644 index 000000000..da7b1548f --- /dev/null +++ b/extensions/cookie/test/browser.ini @@ -0,0 +1,3 @@ +[DEFAULT] + +[browser_test_favicon.js] diff --git a/extensions/cookie/test/browser_test_favicon.js b/extensions/cookie/test/browser_test_favicon.js new file mode 100644 index 000000000..a89a70017 --- /dev/null +++ b/extensions/cookie/test/browser_test_favicon.js @@ -0,0 +1,28 @@ +// tests third party cookie blocking using a favicon load directly from chrome. +// in this case, the docshell of the channel is chrome, not content; thus +// the cookie should be considered third party. + +function test() { + waitForExplicitFinish(); + + Services.prefs.setIntPref("network.cookie.cookieBehavior", 1); + + Services.obs.addObserver(function (theSubject, theTopic, theData) { + var uri = theSubject.QueryInterface(Components.interfaces.nsIURI); + var domain = uri.host; + + if (domain == "example.org") { + ok(true, "foreign favicon cookie was blocked"); + + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + Services.obs.removeObserver(arguments.callee, "cookie-rejected"); + + finish(); + } + }, "cookie-rejected", false); + + // kick off a favicon load + gBrowser.setIcon(gBrowser.selectedTab, "http://example.org/tests/extensions/cookie/test/damonbowling.jpg", + Services.scriptSecurityManager.getSystemPrincipal()); +} diff --git a/extensions/cookie/test/damonbowling.jpg b/extensions/cookie/test/damonbowling.jpg new file mode 100644 index 000000000..8bdb2b604 Binary files /dev/null and b/extensions/cookie/test/damonbowling.jpg differ diff --git a/extensions/cookie/test/damonbowling.jpg^headers^ b/extensions/cookie/test/damonbowling.jpg^headers^ new file mode 100644 index 000000000..77f4f4908 --- /dev/null +++ b/extensions/cookie/test/damonbowling.jpg^headers^ @@ -0,0 +1,2 @@ +Cache-Control: no-store +Set-Cookie: damon=bowling diff --git a/extensions/cookie/test/file_chromecommon.js b/extensions/cookie/test/file_chromecommon.js new file mode 100644 index 000000000..4383876b2 --- /dev/null +++ b/extensions/cookie/test/file_chromecommon.js @@ -0,0 +1,15 @@ +let { classes: Cc, utils: Cu, interfaces: Ci } = Components; + +let cs = Cc["@mozilla.org/cookiemanager;1"] + .getService(Ci.nsICookieManager2); + +addMessageListener("getCookieCountAndClear", () => { + let count = 0; + for (let list = cs.enumerator; list.hasMoreElements(); list.getNext()) + ++count; + cs.removeAll(); + + sendAsyncMessage("getCookieCountAndClear:return", { count }); +}); + +cs.removeAll(); diff --git a/extensions/cookie/test/file_domain_hierarchy_inner.html b/extensions/cookie/test/file_domain_hierarchy_inner.html new file mode 100644 index 000000000..1a3734597 --- /dev/null +++ b/extensions/cookie/test/file_domain_hierarchy_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_domain_hierarchy_inner_inner.html b/extensions/cookie/test/file_domain_hierarchy_inner_inner.html new file mode 100644 index 000000000..3075b971a --- /dev/null +++ b/extensions/cookie/test/file_domain_hierarchy_inner_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_domain_hierarchy_inner_inner_inner.html b/extensions/cookie/test/file_domain_hierarchy_inner_inner_inner.html new file mode 100644 index 000000000..e8d09338b --- /dev/null +++ b/extensions/cookie/test/file_domain_hierarchy_inner_inner_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_domain_inner.html b/extensions/cookie/test/file_domain_inner.html new file mode 100644 index 000000000..1a05c45f8 --- /dev/null +++ b/extensions/cookie/test/file_domain_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_domain_inner_inner.html b/extensions/cookie/test/file_domain_inner_inner.html new file mode 100644 index 000000000..7bc0e44a9 --- /dev/null +++ b/extensions/cookie/test/file_domain_inner_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_image_inner.html b/extensions/cookie/test/file_image_inner.html new file mode 100644 index 000000000..aada82d71 --- /dev/null +++ b/extensions/cookie/test/file_image_inner.html @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/extensions/cookie/test/file_image_inner_inner.html b/extensions/cookie/test/file_image_inner_inner.html new file mode 100644 index 000000000..1989b53de --- /dev/null +++ b/extensions/cookie/test/file_image_inner_inner.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/extensions/cookie/test/file_loadflags_inner.html b/extensions/cookie/test/file_loadflags_inner.html new file mode 100644 index 000000000..5a7a6ccc1 --- /dev/null +++ b/extensions/cookie/test/file_loadflags_inner.html @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/extensions/cookie/test/file_localhost_inner.html b/extensions/cookie/test/file_localhost_inner.html new file mode 100644 index 000000000..db9917f00 --- /dev/null +++ b/extensions/cookie/test/file_localhost_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_loopback_inner.html b/extensions/cookie/test/file_loopback_inner.html new file mode 100644 index 000000000..e6c115c50 --- /dev/null +++ b/extensions/cookie/test/file_loopback_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_subdomain_inner.html b/extensions/cookie/test/file_subdomain_inner.html new file mode 100644 index 000000000..5f608b811 --- /dev/null +++ b/extensions/cookie/test/file_subdomain_inner.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/extensions/cookie/test/file_testcommon.js b/extensions/cookie/test/file_testcommon.js new file mode 100644 index 000000000..3ee53c52c --- /dev/null +++ b/extensions/cookie/test/file_testcommon.js @@ -0,0 +1,70 @@ +const SCRIPT_URL = SimpleTest.getTestFileURL("file_chromecommon.js"); + +var gExpectedCookies; +var gExpectedLoads; + +var gPopup; + +var gScript; + +var gLoads = 0; + +function setupTest(uri, cookies, loads) { + SimpleTest.waitForExplicitFinish(); + + var prefSet = new Promise(resolve => { + SpecialPowers.pushPrefEnv({ set: [["network.cookie.cookieBehavior", 1]] }, resolve); + }); + + gScript = SpecialPowers.loadChromeScript(SCRIPT_URL); + gExpectedCookies = cookies; + gExpectedLoads = loads; + + // Listen for MessageEvents. + window.addEventListener("message", messageReceiver, false); + + prefSet.then(() => { + // load a window which contains an iframe; each will attempt to set + // cookies from their respective domains. + gPopup = window.open(uri, 'hai', 'width=100,height=100'); + }); +} + +function finishTest() { + gScript.destroy(); + SimpleTest.finish(); +} + +/** Receives MessageEvents to this window. */ +// Count and check loads. +function messageReceiver(evt) { + is(evt.data, "message", "message data received from popup"); + if (evt.data != "message") { + gPopup.close(); + window.removeEventListener("message", messageReceiver, false); + + finishTest(); + return; + } + + // only run the test when all our children are done loading & setting cookies + if (++gLoads == gExpectedLoads) { + gPopup.close(); + window.removeEventListener("message", messageReceiver, false); + + runTest(); + } +} + +// runTest() is run by messageReceiver(). +// Count and check cookies. +function runTest() { + // set a cookie from a domain of "localhost" + document.cookie = "oh=hai"; + + gScript.addMessageListener("getCookieCountAndClear:return", ({ count }) => { + is(count, gExpectedCookies, "total number of cookies"); + finishTest(); + }); + gScript.sendAsyncMessage("getCookieCountAndClear"); +} diff --git a/extensions/cookie/test/file_testloadflags.js b/extensions/cookie/test/file_testloadflags.js new file mode 100644 index 000000000..9cf4a15a6 --- /dev/null +++ b/extensions/cookie/test/file_testloadflags.js @@ -0,0 +1,104 @@ +const SCRIPT_URL = SimpleTest.getTestFileURL('file_testloadflags_chromescript.js'); + +var gExpectedCookies; +var gExpectedHeaders; +var gExpectedLoads; + +var gObs; +var gPopup; + +var gHeaders = 0; +var gLoads = 0; + +// setupTest() is run from 'onload='. +function setupTest(uri, domain, cookies, loads, headers) { + info("setupTest uri: " + uri + " domain: " + domain + " cookies: " + cookies + + " loads: " + loads + " headers: " + headers); + + SimpleTest.waitForExplicitFinish(); + + var prefSet = new Promise(resolve => { + SpecialPowers.pushPrefEnv({ set: [["network.cookie.cookieBehavior", 1]] }, resolve); + }); + + gExpectedCookies = cookies; + gExpectedLoads = loads; + gExpectedHeaders = headers; + + gScript = SpecialPowers.loadChromeScript(SCRIPT_URL); + gScript.addMessageListener("info", ({ str }) => info(str)); + gScript.addMessageListener("ok", ({ c, m }) => ok(c, m)); + gScript.addMessageListener("observer:gotCookie", ({ cookie, uri }) => { + isnot(cookie.indexOf("oh=hai"), -1, + "cookie 'oh=hai' is in header for " + uri); + ++gHeaders; + }); + + var scriptReady = new Promise(resolve => { + gScript.addMessageListener("init:return", resolve); + gScript.sendAsyncMessage("init", { domain }); + }); + + // Listen for MessageEvents. + window.addEventListener("message", messageReceiver, false); + + Promise.all([ prefSet, scriptReady ]).then(() => { + // load a window which contains an iframe; each will attempt to set + // cookies from their respective domains. + gPopup = window.open(uri, 'hai', 'width=100,height=100'); + }); +} + +function finishTest() +{ + gScript.addMessageListener("shutdown:return", () => { + gScript.destroy(); + SimpleTest.finish(); + }); + gScript.sendAsyncMessage("shutdown"); +} + +/** Receives MessageEvents to this window. */ +// Count and check loads. +function messageReceiver(evt) +{ + ok(evt.data == "f_lf_i msg data img" || evt.data == "f_lf_i msg data page", + "message data received from popup"); + if (evt.data == "f_lf_i msg data img") { + info("message data received from popup for image"); + } + if (evt.data == "f_lf_i msg data page") { + info("message data received from popup for page"); + } + if (evt.data != "f_lf_i msg data img" && evt.data != "f_lf_i msg data page") { + info("got this message but don't know what it is " + evt.data); + gPopup.close(); + window.removeEventListener("message", messageReceiver, false); + + finishTest(); + return; + } + + // only run the test when all our children are done loading & setting cookies + if (++gLoads == gExpectedLoads) { + gPopup.close(); + window.removeEventListener("message", messageReceiver, false); + + runTest(); + } +} + +// runTest() is run by messageReceiver(). +// Check headers, and count and check cookies. +function runTest() { + // set a cookie from a domain of "localhost" + document.cookie = "o=noes"; + + is(gHeaders, gExpectedHeaders, "number of observed request headers"); + gScript.addMessageListener("getCookieCount:return", ({ count }) => { + is(count, gExpectedCookies, "total number of cookies"); + finishTest(); + }); + + gScript.sendAsyncMessage("getCookieCount"); +} diff --git a/extensions/cookie/test/file_testloadflags_chromescript.js b/extensions/cookie/test/file_testloadflags_chromescript.js new file mode 100644 index 000000000..26eedacd9 --- /dev/null +++ b/extensions/cookie/test/file_testloadflags_chromescript.js @@ -0,0 +1,112 @@ +let { classes: Cc, interfaces: Ci } = Components; + +var gObs; + +function info(s) { + sendAsyncMessage("info", { str: String(s) }); +} + +function ok(c, m) { + sendAsyncMessage("ok", { c, m }); +} + +function is(a, b, m) { + ok(Object.is(a, b), m + " (" + a + " === " + b + ")"); +} + +// Count headers. +function obs() { + info("adding observer"); + + this.os = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); + this.os.addObserver(this, "http-on-modify-request", false); +} + +obs.prototype = { + observe(theSubject, theTopic, theData) { + info("theSubject " + theSubject); + info("theTopic " + theTopic); + info("theData " + theData); + + var channel = theSubject.QueryInterface(Ci.nsIHttpChannel); + info("channel " + channel); + try { + info("channel.URI " + channel.URI); + info("channel.URI.spec " + channel.URI.spec); + channel.visitRequestHeaders({ + visitHeader: function(aHeader, aValue) { + info(aHeader + ": " + aValue); + }}); + } catch (err) { + ok(false, "catch error " + err); + } + + // Ignore notifications we don't care about (like favicons) + if (channel.URI.spec.indexOf( + "http://example.org/tests/extensions/cookie/test/") == -1) { + info("ignoring this one"); + return; + } + + sendAsyncMessage("observer:gotCookie", + { cookie: channel.getRequestHeader("Cookie"), + uri: channel.URI.spec }); + }, + + remove() { + info("removing observer"); + + this.os.removeObserver(this, "http-on-modify-request"); + this.os = null; + } +} + +function getCookieCount(cs) { + let count = 0; + let list = cs.enumerator; + while (list.hasMoreElements()) { + let cookie = list.getNext().QueryInterface(Ci.nsICookie); + info("cookie: " + cookie); + info("cookie host " + cookie.host + " path " + cookie.path + " name " + cookie.name + + " value " + cookie.value + " isSecure " + cookie.isSecure + " expires " + cookie.expires); + ++count; + } + + return count; +} + +addMessageListener("init", ({ domain }) => { + let cs = Cc["@mozilla.org/cookiemanager;1"] + .getService(Ci.nsICookieManager2); + + info("we are going to remove these cookies"); + + let count = getCookieCount(cs); + info(count + " cookies"); + + cs.removeAll(); + cs.add(domain, "", "oh", "hai", false, false, true, Math.pow(2, 62), {}); + is(cs.countCookiesFromHost(domain), 1, "number of cookies for domain " + domain); + + gObs = new obs(); + sendAsyncMessage("init:return"); +}); + +addMessageListener("getCookieCount", () => { + let cs = Cc["@mozilla.org/cookiemanager;1"] + .getService(Ci.nsICookieManager); + let count = getCookieCount(cs); + + cs.removeAll(); + sendAsyncMessage("getCookieCount:return", { count }); +}); + +addMessageListener("shutdown", () => { + gObs.remove(); + + let cs = Cc["@mozilla.org/cookiemanager;1"] + .getService(Ci.nsICookieManager2); + cs.removeAll(); + sendAsyncMessage("shutdown:return"); +}); diff --git a/extensions/cookie/test/image1.png b/extensions/cookie/test/image1.png new file mode 100644 index 000000000..272d67c0c Binary files /dev/null and b/extensions/cookie/test/image1.png differ diff --git a/extensions/cookie/test/image1.png^headers^ b/extensions/cookie/test/image1.png^headers^ new file mode 100644 index 000000000..2390289e0 --- /dev/null +++ b/extensions/cookie/test/image1.png^headers^ @@ -0,0 +1,3 @@ +Cache-Control: no-store +Set-Cookie: foo=bar + diff --git a/extensions/cookie/test/image2.png b/extensions/cookie/test/image2.png new file mode 100644 index 000000000..272d67c0c Binary files /dev/null and b/extensions/cookie/test/image2.png differ diff --git a/extensions/cookie/test/image2.png^headers^ b/extensions/cookie/test/image2.png^headers^ new file mode 100644 index 000000000..6c0eea5ab --- /dev/null +++ b/extensions/cookie/test/image2.png^headers^ @@ -0,0 +1,3 @@ +Cache-Control: no-store +Set-Cookie: foo2=bar2 + diff --git a/extensions/cookie/test/mochitest.ini b/extensions/cookie/test/mochitest.ini new file mode 100644 index 000000000..673fad7b8 --- /dev/null +++ b/extensions/cookie/test/mochitest.ini @@ -0,0 +1,41 @@ +[DEFAULT] +support-files = + beltzner.jpg + beltzner.jpg^headers^ + damonbowling.jpg + damonbowling.jpg^headers^ + file_chromecommon.js + file_domain_hierarchy_inner.html + file_domain_hierarchy_inner_inner.html + file_domain_hierarchy_inner_inner_inner.html + file_domain_inner.html + file_domain_inner_inner.html + file_image_inner.html + file_image_inner_inner.html + file_loadflags_inner.html + file_localhost_inner.html + file_loopback_inner.html + file_subdomain_inner.html + file_testcommon.js + file_testloadflags.js + file_testloadflags_chromescript.js + image1.png + image1.png^headers^ + image2.png + image2.png^headers^ + test1.css + test1.css^headers^ + test2.css + test2.css^headers^ + +[test_different_domain_in_hierarchy.html] +[test_differentdomain.html] +[test_image.html] +[test_loadflags.html] +[test_same_base_domain.html] +[test_same_base_domain_2.html] +[test_same_base_domain_3.html] +[test_same_base_domain_4.html] +[test_same_base_domain_5.html] +[test_same_base_domain_6.html] +[test_samedomain.html] diff --git a/extensions/cookie/test/moz.build b/extensions/cookie/test/moz.build new file mode 100644 index 000000000..7474661d8 --- /dev/null +++ b/extensions/cookie/test/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +XPCSHELL_TESTS_MANIFESTS += [ + 'unit/xpcshell.ini', + 'unit_ipc/xpcshell.ini', +] + +MOCHITEST_MANIFESTS += ['mochitest.ini'] + +BROWSER_CHROME_MANIFESTS += ['browser.ini'] + diff --git a/extensions/cookie/test/test1.css b/extensions/cookie/test/test1.css new file mode 100644 index 000000000..139597f9c --- /dev/null +++ b/extensions/cookie/test/test1.css @@ -0,0 +1,2 @@ + + diff --git a/extensions/cookie/test/test1.css^headers^ b/extensions/cookie/test/test1.css^headers^ new file mode 100644 index 000000000..729babb5a --- /dev/null +++ b/extensions/cookie/test/test1.css^headers^ @@ -0,0 +1,3 @@ +Cache-Control: no-cache +Set-Cookie: css=bar + diff --git a/extensions/cookie/test/test2.css b/extensions/cookie/test/test2.css new file mode 100644 index 000000000..139597f9c --- /dev/null +++ b/extensions/cookie/test/test2.css @@ -0,0 +1,2 @@ + + diff --git a/extensions/cookie/test/test2.css^headers^ b/extensions/cookie/test/test2.css^headers^ new file mode 100644 index 000000000..b12d32c72 --- /dev/null +++ b/extensions/cookie/test/test2.css^headers^ @@ -0,0 +1,3 @@ +Cache-Control: no-cache +Set-Cookie: css2=bar2 + diff --git a/extensions/cookie/test/test_different_domain_in_hierarchy.html b/extensions/cookie/test/test_different_domain_in_hierarchy.html new file mode 100644 index 000000000..61bc58539 --- /dev/null +++ b/extensions/cookie/test/test_different_domain_in_hierarchy.html @@ -0,0 +1,15 @@ + + + + Test cookie requests from within a window hierarchy of different base domains + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_differentdomain.html b/extensions/cookie/test/test_differentdomain.html new file mode 100644 index 000000000..a74bceaf4 --- /dev/null +++ b/extensions/cookie/test/test_differentdomain.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_image.html b/extensions/cookie/test/test_image.html new file mode 100644 index 000000000..f39a19894 --- /dev/null +++ b/extensions/cookie/test/test_image.html @@ -0,0 +1,14 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_loadflags.html b/extensions/cookie/test/test_loadflags.html new file mode 100644 index 000000000..3eea710f2 --- /dev/null +++ b/extensions/cookie/test/test_loadflags.html @@ -0,0 +1,21 @@ + + + + Test for Cross domain access to properties + + + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_same_base_domain.html b/extensions/cookie/test/test_same_base_domain.html new file mode 100644 index 000000000..9232b4e09 --- /dev/null +++ b/extensions/cookie/test/test_same_base_domain.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_same_base_domain_2.html b/extensions/cookie/test/test_same_base_domain_2.html new file mode 100644 index 000000000..d692524c5 --- /dev/null +++ b/extensions/cookie/test/test_same_base_domain_2.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_same_base_domain_3.html b/extensions/cookie/test/test_same_base_domain_3.html new file mode 100644 index 000000000..f0cd687f9 --- /dev/null +++ b/extensions/cookie/test/test_same_base_domain_3.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_same_base_domain_4.html b/extensions/cookie/test/test_same_base_domain_4.html new file mode 100644 index 000000000..0a4026fe2 --- /dev/null +++ b/extensions/cookie/test/test_same_base_domain_4.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_same_base_domain_5.html b/extensions/cookie/test/test_same_base_domain_5.html new file mode 100644 index 000000000..49b2379b6 --- /dev/null +++ b/extensions/cookie/test/test_same_base_domain_5.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_same_base_domain_6.html b/extensions/cookie/test/test_same_base_domain_6.html new file mode 100644 index 000000000..9056739a6 --- /dev/null +++ b/extensions/cookie/test/test_same_base_domain_6.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/test_samedomain.html b/extensions/cookie/test/test_samedomain.html new file mode 100644 index 000000000..9051d3b39 --- /dev/null +++ b/extensions/cookie/test/test_samedomain.html @@ -0,0 +1,15 @@ + + + + Test for Cross domain access to properties + + + + +

+
+
+
+ + diff --git a/extensions/cookie/test/unit/cookieprompt.js b/extensions/cookie/test/unit/cookieprompt.js new file mode 100644 index 000000000..c0a17e006 --- /dev/null +++ b/extensions/cookie/test/unit/cookieprompt.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +var Ci = Components.interfaces; + +function CookiePromptService() { +} + +CookiePromptService.prototype = { + classID: Components.ID("{509b5540-c87c-11dd-ad8b-0800200c9a66}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsICookiePromptService]), + + cookieDialog: function(parent, cookie, hostname, + cookiesFromHost, changingCookie, + rememberDecision) { + return 0; + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CookiePromptService]); diff --git a/extensions/cookie/test/unit/cookieprompt.manifest b/extensions/cookie/test/unit/cookieprompt.manifest new file mode 100644 index 000000000..5a3bcad40 --- /dev/null +++ b/extensions/cookie/test/unit/cookieprompt.manifest @@ -0,0 +1,2 @@ +component {509b5540-c87c-11dd-ad8b-0800200c9a66} cookieprompt.js +contract @mozilla.org/embedcomp/cookieprompt-service;1 {509b5540-c87c-11dd-ad8b-0800200c9a66} diff --git a/extensions/cookie/test/unit/head_cookies.js b/extensions/cookie/test/unit/head_cookies.js new file mode 100644 index 000000000..fe4c0a53d --- /dev/null +++ b/extensions/cookie/test/unit/head_cookies.js @@ -0,0 +1,570 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/NetUtil.jsm"); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cr = Components.results; + +XPCOMUtils.defineLazyServiceGetter(Services, "cookies", + "@mozilla.org/cookieService;1", + "nsICookieService"); +XPCOMUtils.defineLazyServiceGetter(Services, "cookiemgr", + "@mozilla.org/cookiemanager;1", + "nsICookieManager2"); + +XPCOMUtils.defineLazyServiceGetter(Services, "etld", + "@mozilla.org/network/effective-tld-service;1", + "nsIEffectiveTLDService"); + +function do_check_throws(f, result, stack) +{ + if (!stack) + stack = Components.stack.caller; + + try { + f(); + } catch (exc) { + if (exc.result == result) + return; + do_throw("expected result " + result + ", caught " + exc, stack); + } + do_throw("expected result " + result + ", none thrown", stack); +} + +// Helper to step a generator function and catch a StopIteration exception. +function do_run_generator(generator) +{ + try { + generator.next(); + } catch (e) { + if (e != StopIteration) + do_throw("caught exception " + e, Components.stack.caller); + } +} + +// Helper to finish a generator function test. +function do_finish_generator_test(generator) +{ + do_execute_soon(function() { + generator.close(); + do_test_finished(); + }); +} + +function _observer(generator, topic) { + Services.obs.addObserver(this, topic, false); + + this.generator = generator; + this.topic = topic; +} + +_observer.prototype = { + observe: function (subject, topic, data) { + do_check_eq(this.topic, topic); + + Services.obs.removeObserver(this, this.topic); + + // Continue executing the generator function. + if (this.generator) + do_run_generator(this.generator); + + this.generator = null; + this.topic = null; + } +} + +// Close the cookie database. If a generator is supplied, it will be invoked +// once the close is complete. +function do_close_profile(generator) { + // Register an observer for db close. + let obs = new _observer(generator, "cookie-db-closed"); + + // Close the db. + let service = Services.cookies.QueryInterface(Ci.nsIObserver); + service.observe(null, "profile-before-change", "shutdown-persist"); +} + +// Load the cookie database. If a generator is supplied, it will be invoked +// once the load is complete. +function do_load_profile(generator) { + // Register an observer for read completion. + let obs = new _observer(generator, "cookie-db-read"); + + // Load the profile. + let service = Services.cookies.QueryInterface(Ci.nsIObserver); + service.observe(null, "profile-do-change", ""); +} + +// Set a single session cookie using http and test the cookie count +// against 'expected' +function do_set_single_http_cookie(uri, channel, expected) { + Services.cookies.setCookieStringFromHttp(uri, null, null, "foo=bar", null, channel); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected); +} + +// Set four cookies; with & without channel, http and non-http; and test +// the cookie count against 'expected' after each set. +function do_set_cookies(uri, channel, session, expected) { + let suffix = session ? "" : "; max-age=1000"; + + // without channel + Services.cookies.setCookieString(uri, null, "oh=hai" + suffix, null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[0]); + // with channel + Services.cookies.setCookieString(uri, null, "can=has" + suffix, channel); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[1]); + // without channel, from http + Services.cookies.setCookieStringFromHttp(uri, null, null, "cheez=burger" + suffix, null, null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[2]); + // with channel, from http + Services.cookies.setCookieStringFromHttp(uri, null, null, "hot=dog" + suffix, null, channel); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[3]); +} + +function do_count_enumerator(enumerator) { + let i = 0; + while (enumerator.hasMoreElements()) { + enumerator.getNext(); + ++i; + } + return i; +} + +function do_count_cookies() { + return do_count_enumerator(Services.cookiemgr.enumerator); +} + +// Helper object to store cookie data. +function Cookie(name, + value, + host, + path, + expiry, + lastAccessed, + creationTime, + isSession, + isSecure, + isHttpOnly) +{ + this.name = name; + this.value = value; + this.host = host; + this.path = path; + this.expiry = expiry; + this.lastAccessed = lastAccessed; + this.creationTime = creationTime; + this.isSession = isSession; + this.isSecure = isSecure; + this.isHttpOnly = isHttpOnly; + + let strippedHost = host.charAt(0) == '.' ? host.slice(1) : host; + + try { + this.baseDomain = Services.etld.getBaseDomainFromHost(strippedHost); + } catch (e) { + if (e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS || + e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) + this.baseDomain = strippedHost; + } +} + +// Object representing a database connection and associated statements. The +// implementation varies depending on schema version. +function CookieDatabaseConnection(file, schema) +{ + // Manually generate a cookies.sqlite file with appropriate rows, columns, + // and schema version. If it already exists, just set up our statements. + let exists = file.exists(); + + this.db = Services.storage.openDatabase(file); + this.schema = schema; + if (!exists) + this.db.schemaVersion = schema; + + switch (schema) { + case 1: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER)"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT INTO moz_cookies ( \ + id, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :id, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies WHERE id = :id"); + + break; + } + + case 2: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + lastAccessed INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER)"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT OR REPLACE INTO moz_cookies ( \ + id, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + lastAccessed, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :id, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :lastAccessed, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies WHERE id = :id"); + + this.stmtUpdate = this.db.createStatement( + "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"); + + break; + } + + case 3: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + baseDomain TEXT, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + lastAccessed INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER)"); + + this.db.executeSimpleSQL( + "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT INTO moz_cookies ( \ + id, \ + baseDomain, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + lastAccessed, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :id, \ + :baseDomain, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :lastAccessed, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies WHERE id = :id"); + + this.stmtUpdate = this.db.createStatement( + "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"); + + break; + } + + case 4: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + baseDomain TEXT, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + lastAccessed INTEGER, \ + creationTime INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER \ + CONSTRAINT moz_uniqueid UNIQUE (name, host, path))"); + + this.db.executeSimpleSQL( + "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"); + + this.db.executeSimpleSQL( + "PRAGMA journal_mode = WAL"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT INTO moz_cookies ( \ + baseDomain, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + lastAccessed, \ + creationTime, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :baseDomain, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :lastAccessed, \ + :creationTime, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies \ + WHERE name = :name AND host = :host AND path = :path"); + + this.stmtUpdate = this.db.createStatement( + "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ + WHERE name = :name AND host = :host AND path = :path"); + + break; + } + + default: + do_throw("unrecognized schemaVersion!"); + } +} + +CookieDatabaseConnection.prototype = +{ + insertCookie: function(cookie) + { + if (!(cookie instanceof Cookie)) + do_throw("not a cookie"); + + switch (this.schema) + { + case 1: + this.stmtInsert.bindByName("id", cookie.creationTime); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + case 2: + this.stmtInsert.bindByName("id", cookie.creationTime); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + case 3: + this.stmtInsert.bindByName("id", cookie.creationTime); + this.stmtInsert.bindByName("baseDomain", cookie.baseDomain); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + case 4: + this.stmtInsert.bindByName("baseDomain", cookie.baseDomain); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); + this.stmtInsert.bindByName("creationTime", cookie.creationTime); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + default: + do_throw("unrecognized schemaVersion!"); + } + + do_execute_stmt(this.stmtInsert); + }, + + deleteCookie: function(cookie) + { + if (!(cookie instanceof Cookie)) + do_throw("not a cookie"); + + switch (this.db.schemaVersion) + { + case 1: + case 2: + case 3: + this.stmtDelete.bindByName("id", cookie.creationTime); + break; + + case 4: + this.stmtDelete.bindByName("name", cookie.name); + this.stmtDelete.bindByName("host", cookie.host); + this.stmtDelete.bindByName("path", cookie.path); + break; + + default: + do_throw("unrecognized schemaVersion!"); + } + + do_execute_stmt(this.stmtDelete); + }, + + updateCookie: function(cookie) + { + if (!(cookie instanceof Cookie)) + do_throw("not a cookie"); + + switch (this.db.schemaVersion) + { + case 1: + do_throw("can't update a schema 1 cookie!"); + + case 2: + case 3: + this.stmtUpdate.bindByName("id", cookie.creationTime); + this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed); + break; + + case 4: + this.stmtDelete.bindByName("name", cookie.name); + this.stmtDelete.bindByName("host", cookie.host); + this.stmtDelete.bindByName("path", cookie.path); + this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed); + break; + + default: + do_throw("unrecognized schemaVersion!"); + } + + do_execute_stmt(this.stmtUpdate); + }, + + close: function() + { + this.stmtInsert.finalize(); + this.stmtDelete.finalize(); + if (this.stmtUpdate) + this.stmtUpdate.finalize(); + this.db.close(); + + this.stmtInsert = null; + this.stmtDelete = null; + this.stmtUpdate = null; + this.db = null; + } +} + +function do_get_cookie_file(profile) +{ + let file = profile.clone(); + file.append("cookies.sqlite"); + return file; +} + +// Count the cookies from 'host' in a database. If 'host' is null, count all +// cookies. +function do_count_cookies_in_db(connection, host) +{ + let select = null; + if (host) { + select = connection.createStatement( + "SELECT COUNT(1) FROM moz_cookies WHERE host = :host"); + select.bindByName("host", host); + } else { + select = connection.createStatement( + "SELECT COUNT(1) FROM moz_cookies"); + } + + select.executeStep(); + let result = select.getInt32(0); + select.reset(); + select.finalize(); + return result; +} + +// Execute 'stmt', ensuring that we reset it if it throws. +function do_execute_stmt(stmt) +{ + try { + stmt.executeStep(); + stmt.reset(); + } catch (e) { + stmt.reset(); + throw e; + } +} diff --git a/extensions/cookie/test/unit/test_bug526789.js b/extensions/cookie/test/unit/test_bug526789.js new file mode 100644 index 000000000..0eac1d492 --- /dev/null +++ b/extensions/cookie/test/unit/test_bug526789.js @@ -0,0 +1,248 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService); + var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); + var expiry = (Date.now() + 1000) * 1000; + + cm.removeAll(); + + // Allow all cookies. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + // test that variants of 'baz.com' get normalized appropriately, but that + // malformed hosts are rejected + cm.add("baz.com", "/", "foo", "bar", false, false, true, expiry, {}); + do_check_eq(cm.countCookiesFromHost("baz.com"), 1); + do_check_eq(cm.countCookiesFromHost("BAZ.com"), 1); + do_check_eq(cm.countCookiesFromHost(".baz.com"), 1); + do_check_eq(cm.countCookiesFromHost("baz.com."), 0); + do_check_eq(cm.countCookiesFromHost(".baz.com."), 0); + do_check_throws(function() { + cm.countCookiesFromHost("baz.com.."); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.countCookiesFromHost("baz..com"); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.countCookiesFromHost("..baz.com"); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + cm.remove("BAZ.com.", "foo", "/", false, {}); + do_check_eq(cm.countCookiesFromHost("baz.com"), 1); + cm.remove("baz.com", "foo", "/", false, {}); + do_check_eq(cm.countCookiesFromHost("baz.com"), 0); + + // Test that 'baz.com' and 'baz.com.' are treated differently + cm.add("baz.com.", "/", "foo", "bar", false, false, true, expiry, {}); + do_check_eq(cm.countCookiesFromHost("baz.com"), 0); + do_check_eq(cm.countCookiesFromHost("BAZ.com"), 0); + do_check_eq(cm.countCookiesFromHost(".baz.com"), 0); + do_check_eq(cm.countCookiesFromHost("baz.com."), 1); + do_check_eq(cm.countCookiesFromHost(".baz.com."), 1); + cm.remove("baz.com", "foo", "/", false, {}); + do_check_eq(cm.countCookiesFromHost("baz.com."), 1); + cm.remove("baz.com.", "foo", "/", false, {}); + do_check_eq(cm.countCookiesFromHost("baz.com."), 0); + + // test that domain cookies are illegal for IP addresses, aliases such as + // 'localhost', and eTLD's such as 'co.uk' + cm.add("192.168.0.1", "/", "foo", "bar", false, false, true, expiry, {}); + do_check_eq(cm.countCookiesFromHost("192.168.0.1"), 1); + do_check_eq(cm.countCookiesFromHost("192.168.0.1."), 0); + do_check_throws(function() { + cm.countCookiesFromHost(".192.168.0.1"); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.countCookiesFromHost(".192.168.0.1."); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + cm.add("localhost", "/", "foo", "bar", false, false, true, expiry, {}); + do_check_eq(cm.countCookiesFromHost("localhost"), 1); + do_check_eq(cm.countCookiesFromHost("localhost."), 0); + do_check_throws(function() { + cm.countCookiesFromHost(".localhost"); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.countCookiesFromHost(".localhost."); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + cm.add("co.uk", "/", "foo", "bar", false, false, true, expiry, {}); + do_check_eq(cm.countCookiesFromHost("co.uk"), 1); + do_check_eq(cm.countCookiesFromHost("co.uk."), 0); + do_check_throws(function() { + cm.countCookiesFromHost(".co.uk"); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.countCookiesFromHost(".co.uk."); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + cm.removeAll(); + + // test that setting an empty or '.' http:// host results in a no-op + var uri = NetUtil.newURI("http://baz.com/"); + var emptyuri = NetUtil.newURI("http:///"); + var doturi = NetUtil.newURI("http://./"); + do_check_eq(uri.asciiHost, "baz.com"); + do_check_eq(emptyuri.asciiHost, ""); + do_check_eq(doturi.asciiHost, "."); + cs.setCookieString(emptyuri, null, "foo2=bar", null); + do_check_eq(getCookieCount(), 0); + cs.setCookieString(doturi, null, "foo3=bar", null); + do_check_eq(getCookieCount(), 0); + cs.setCookieString(uri, null, "foo=bar", null); + do_check_eq(getCookieCount(), 1); + + do_check_eq(cs.getCookieString(uri, null), "foo=bar"); + do_check_eq(cs.getCookieString(emptyuri, null), null); + do_check_eq(cs.getCookieString(doturi, null), null); + + do_check_eq(cm.countCookiesFromHost(""), 0); + do_check_throws(function() { + cm.countCookiesFromHost("."); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.countCookiesFromHost(".."); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + var e = cm.getCookiesFromHost("", {}); + do_check_false(e.hasMoreElements()); + do_check_throws(function() { + cm.getCookiesFromHost(".", {}); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.getCookiesFromHost("..", {}); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + e = cm.getCookiesFromHost("baz.com", {}); + do_check_true(e.hasMoreElements()); + do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).name, "foo"); + do_check_false(e.hasMoreElements()); + e = cm.getCookiesFromHost("", {}); + do_check_false(e.hasMoreElements()); + do_check_throws(function() { + cm.getCookiesFromHost(".", {}); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function() { + cm.getCookiesFromHost("..", {}); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + cm.removeAll(); + + // test that an empty file:// host works + emptyuri = NetUtil.newURI("file:///"); + do_check_eq(emptyuri.asciiHost, ""); + do_check_eq(NetUtil.newURI("file://./").asciiHost, ""); + do_check_eq(NetUtil.newURI("file://foo.bar/").asciiHost, ""); + cs.setCookieString(emptyuri, null, "foo2=bar", null); + do_check_eq(getCookieCount(), 1); + cs.setCookieString(emptyuri, null, "foo3=bar; domain=", null); + do_check_eq(getCookieCount(), 2); + cs.setCookieString(emptyuri, null, "foo4=bar; domain=.", null); + do_check_eq(getCookieCount(), 2); + cs.setCookieString(emptyuri, null, "foo5=bar; domain=bar.com", null); + do_check_eq(getCookieCount(), 2); + + do_check_eq(cs.getCookieString(emptyuri, null), "foo2=bar; foo3=bar"); + + do_check_eq(cm.countCookiesFromHost("baz.com"), 0); + do_check_eq(cm.countCookiesFromHost(""), 2); + do_check_throws(function() { + cm.countCookiesFromHost("."); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + e = cm.getCookiesFromHost("baz.com", {}); + do_check_false(e.hasMoreElements()); + e = cm.getCookiesFromHost("", {}); + do_check_true(e.hasMoreElements()); + e.getNext(); + do_check_true(e.hasMoreElements()); + e.getNext(); + do_check_false(e.hasMoreElements()); + do_check_throws(function() { + cm.getCookiesFromHost(".", {}); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + cm.removeAll(); + + // test that an empty host to add() or remove() works, + // but a host of '.' doesn't + cm.add("", "/", "foo2", "bar", false, false, true, expiry, {}); + do_check_eq(getCookieCount(), 1); + do_check_throws(function() { + cm.add(".", "/", "foo3", "bar", false, false, true, expiry, {}); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_eq(getCookieCount(), 1); + + cm.remove("", "foo2", "/", false, {}); + do_check_eq(getCookieCount(), 0); + do_check_throws(function() { + cm.remove(".", "foo3", "/", false, {}); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + // test that the 'domain' attribute accepts a leading dot for IP addresses, + // aliases such as 'localhost', and eTLD's such as 'co.uk'; but that the + // resulting cookie is for the exact host only. + testDomainCookie("http://192.168.0.1/", "192.168.0.1"); + testDomainCookie("http://localhost/", "localhost"); + testDomainCookie("http://co.uk/", "co.uk"); + + // Test that trailing dots are treated differently for purposes of the + // 'domain' attribute when using setCookieString. + testTrailingDotCookie("http://localhost", "localhost"); + testTrailingDotCookie("http://foo.com", "foo.com"); + + cm.removeAll(); +} + +function getCookieCount() { + var count = 0; + var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); + var enumerator = cm.enumerator; + while (enumerator.hasMoreElements()) { + if (!(enumerator.getNext() instanceof Ci.nsICookie2)) + throw new Error("not a cookie"); + ++count; + } + return count; +} + +function testDomainCookie(uriString, domain) { + var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService); + var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); + + cm.removeAll(); + + var uri = NetUtil.newURI(uriString); + cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null); + var e = cm.getCookiesFromHost(domain, {}); + do_check_true(e.hasMoreElements()); + do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).host, domain); + cm.removeAll(); + + cs.setCookieString(uri, null, "foo=bar; domain=." + domain, null); + e = cm.getCookiesFromHost(domain, {}); + do_check_true(e.hasMoreElements()); + do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).host, domain); + cm.removeAll(); +} + +function testTrailingDotCookie(uriString, domain) { + var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService); + var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); + + cm.removeAll(); + + var uri = NetUtil.newURI(uriString); + cs.setCookieString(uri, null, "foo=bar; domain=" + domain + ".", null); + do_check_eq(cm.countCookiesFromHost(domain), 0); + do_check_eq(cm.countCookiesFromHost(domain + "."), 0); + cm.removeAll(); + + uri = NetUtil.newURI(uriString + "."); + cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null); + do_check_eq(cm.countCookiesFromHost(domain), 0); + do_check_eq(cm.countCookiesFromHost(domain + "."), 0); + cm.removeAll(); +} + diff --git a/extensions/cookie/test/unit/test_bug650522.js b/extensions/cookie/test/unit/test_bug650522.js new file mode 100644 index 000000000..1d99cb233 --- /dev/null +++ b/extensions/cookie/test/unit/test_bug650522.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +function run_test() { + var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService); + var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); + var expiry = (Date.now() + 1000) * 1000; + + // Test our handling of host names with a single character at the beginning + // followed by a dot. + cm.add("e.mail.com", "/", "foo", "bar", false, false, true, expiry, {}); + do_check_eq(cm.countCookiesFromHost("e.mail.com"), 1); + do_check_eq(cs.getCookieString(NetUtil.newURI("http://e.mail.com"), null), "foo=bar"); +} diff --git a/extensions/cookie/test/unit/test_bug667087.js b/extensions/cookie/test/unit/test_bug667087.js new file mode 100644 index 000000000..2400dea51 --- /dev/null +++ b/extensions/cookie/test/unit/test_bug667087.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +function run_test() { + var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService); + var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); + var expiry = (Date.now() + 1000) * 1000; + + // Test our handling of host names with a single character consisting only + // of a single character + cm.add("a", "/", "foo", "bar", false, false, true, expiry, {}); + do_check_eq(cm.countCookiesFromHost("a"), 1); + do_check_eq(cs.getCookieString(NetUtil.newURI("http://a"), null), "foo=bar"); +} diff --git a/extensions/cookie/test/unit/test_cookies_async_failure.js b/extensions/cookie/test/unit/test_cookies_async_failure.js new file mode 100644 index 000000000..628553a4e --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_async_failure.js @@ -0,0 +1,600 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test the various ways opening a cookie database can fail in an asynchronous +// (i.e. after synchronous initialization) manner, and that the database is +// renamed and recreated under each circumstance. These circumstances are, in no +// particular order: +// +// 1) A write operation failing after the database has been read in. +// 2) Asynchronous read failure due to a corrupt database. +// 3) Synchronous read failure due to a corrupt database, when reading: +// a) a single base domain; +// b) the entire database. +// 4) Asynchronous read failure, followed by another failure during INSERT but +// before the database closes for rebuilding. (The additional error should be +// ignored.) +// 5) Asynchronous read failure, followed by an INSERT failure during rebuild. +// This should result in an abort of the database rebuild; the partially- +// built database should be moved to 'cookies.sqlite.bak-rebuild'. + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + do_run_generator(test_generator); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + this.profile = do_get_profile(); + + // Allow all cookies. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + // Get the cookie file and the backup file. + do_check_false(do_get_cookie_file(profile).exists()); + do_check_false(do_get_backup_file(profile).exists()); + + // Create a cookie object for testing. + this.now = Date.now() * 1000; + this.futureExpiry = Math.round(this.now / 1e6 + 1000); + this.cookie = new Cookie("oh", "hai", "bar.com", "/", this.futureExpiry, + this.now, this.now, false, false, false); + + this.sub_generator = run_test_1(test_generator); + sub_generator.next(); + yield; + + this.sub_generator = run_test_2(test_generator); + sub_generator.next(); + yield; + + this.sub_generator = run_test_3(test_generator); + sub_generator.next(); + yield; + + this.sub_generator = run_test_4(test_generator); + sub_generator.next(); + yield; + + this.sub_generator = run_test_5(test_generator); + sub_generator.next(); + yield; + + finish_test(); + return; +} + +function do_get_backup_file(profile) +{ + let file = profile.clone(); + file.append("cookies.sqlite.bak"); + return file; +} + +function do_get_rebuild_backup_file(profile) +{ + let file = profile.clone(); + file.append("cookies.sqlite.bak-rebuild"); + return file; +} + +function do_corrupt_db(file) +{ + // Sanity check: the database size should be larger than 450k, since we've + // written about 460k of data. If it's not, let's make it obvious now. + let size = file.fileSize; + do_check_true(size > 450e3); + + // Corrupt the database by writing bad data to the end of the file. We + // assume that the important metadata -- table structure etc -- is stored + // elsewhere, and that doing this will not cause synchronous failure when + // initializing the database connection. This is totally empirical -- + // overwriting between 1k and 100k of live data seems to work. (Note that the + // database file will be larger than the actual content requires, since the + // cookie service uses a large growth increment. So we calculate the offset + // based on the expected size of the content, not just the file size.) + let ostream = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + ostream.init(file, 2, -1, 0); + let sstream = ostream.QueryInterface(Ci.nsISeekableStream); + let n = size - 450e3 + 20e3; + sstream.seek(Ci.nsISeekableStream.NS_SEEK_SET, size - n); + for (let i = 0; i < n; ++i) { + ostream.write("a", 1); + } + ostream.flush(); + ostream.close(); + + do_check_eq(file.clone().fileSize, size); + return size; +} + +function run_test_1(generator) +{ + // Load the profile and populate it. + let uri = NetUtil.newURI("http://foo.com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Open a database connection now, before we load the profile and begin + // asynchronous write operations. In order to tell when the async delete + // statement has completed, we do something tricky: open a schema 2 connection + // and add a cookie with null baseDomain. We can then wait until we see it + // deleted in the new database. + let db2 = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + db2.db.executeSimpleSQL("INSERT INTO moz_cookies (baseDomain) VALUES (NULL)"); + db2.close(); + let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 4); + do_check_eq(do_count_cookies_in_db(db.db), 2); + + // Load the profile, and wait for async read completion... + do_load_profile(sub_generator); + yield; + + // ... and the DELETE statement to finish. + while (do_count_cookies_in_db(db.db) == 2) { + do_execute_soon(function() { + do_run_generator(sub_generator); + }); + yield; + } + do_check_eq(do_count_cookies_in_db(db.db), 1); + + // Insert a row. + db.insertCookie(cookie); + db.close(); + + // Attempt to insert a cookie with the same (name, host, path) triplet. + Services.cookiemgr.add(cookie.host, cookie.path, cookie.name, "hallo", + cookie.isSecure, cookie.isHttpOnly, cookie.isSession, cookie.expiry, {}); + + // Check that the cookie service accepted the new cookie. + do_check_eq(Services.cookiemgr.countCookiesFromHost(cookie.host), 1); + + // Wait for the cookie service to rename the old database and rebuild. + new _observer(sub_generator, "cookie-db-rebuilding"); + yield; + do_execute_soon(function() { do_run_generator(sub_generator); }); + yield; + + // At this point, the cookies should still be in memory. + do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost(cookie.host), 1); + do_check_eq(do_count_cookies(), 2); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Check that the original database was renamed, and that it contains the + // original cookie. + do_check_true(do_get_backup_file(profile).exists()); + let backupdb = Services.storage.openDatabase(do_get_backup_file(profile)); + do_check_eq(do_count_cookies_in_db(backupdb, "foo.com"), 1); + backupdb.close(); + + // Load the profile, and check that it contains the new cookie. + do_load_profile(); + + do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 1); + let enumerator = Services.cookiemgr.getCookiesFromHost(cookie.host, {}); + do_check_true(enumerator.hasMoreElements()); + let dbcookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + do_check_eq(dbcookie.value, "hallo"); + do_check_false(enumerator.hasMoreElements()); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Clean up. + do_get_cookie_file(profile).remove(false); + do_get_backup_file(profile).remove(false); + do_check_false(do_get_cookie_file(profile).exists()); + do_check_false(do_get_backup_file(profile).exists()); + do_run_generator(generator); +} + +function run_test_2(generator) +{ + // Load the profile and populate it. + do_load_profile(); + for (let i = 0; i < 3000; ++i) { + let uri = NetUtil.newURI("http://" + i + ".com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + } + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Corrupt the database file. + let size = do_corrupt_db(do_get_cookie_file(profile)); + + // Load the profile. + do_load_profile(); + + // At this point, the database connection should be open. Ensure that it + // succeeded. + do_check_false(do_get_backup_file(profile).exists()); + + // Synchronously read in the first cookie. This will cause it to go into the + // cookie table, whereupon it will be written out during database rebuild. + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + + // Wait for the asynchronous read to choke, at which point the backup file + // will be created and the database rebuilt. + new _observer(sub_generator, "cookie-db-rebuilding"); + yield; + do_execute_soon(function() { do_run_generator(sub_generator); }); + yield; + + // At this point, the cookies should still be in memory. + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + do_check_eq(do_count_cookies(), 1); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Check that the original database was renamed. + do_check_true(do_get_backup_file(profile).exists()); + do_check_eq(do_get_backup_file(profile).fileSize, size); + let db = Services.storage.openDatabase(do_get_cookie_file(profile)); + do_check_eq(do_count_cookies_in_db(db, "0.com"), 1); + db.close(); + + // Load the profile, and check that it contains the new cookie. + do_load_profile(); + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + do_check_eq(do_count_cookies(), 1); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Clean up. + do_get_cookie_file(profile).remove(false); + do_get_backup_file(profile).remove(false); + do_check_false(do_get_cookie_file(profile).exists()); + do_check_false(do_get_backup_file(profile).exists()); + do_run_generator(generator); +} + +function run_test_3(generator) +{ + // Set the maximum cookies per base domain limit to a large value, so that + // corrupting the database is easier. + Services.prefs.setIntPref("network.cookie.maxPerHost", 3000); + + // Load the profile and populate it. + do_load_profile(); + for (let i = 0; i < 10; ++i) { + let uri = NetUtil.newURI("http://hither.com/"); + Services.cookies.setCookieString(uri, null, "oh" + i + "=hai; max-age=1000", + null); + } + for (let i = 10; i < 3000; ++i) { + let uri = NetUtil.newURI("http://haithur.com/"); + Services.cookies.setCookieString(uri, null, "oh" + i + "=hai; max-age=1000", + null); + } + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Corrupt the database file. + let size = do_corrupt_db(do_get_cookie_file(profile)); + + // Load the profile. + do_load_profile(); + + // At this point, the database connection should be open. Ensure that it + // succeeded. + do_check_false(do_get_backup_file(profile).exists()); + + // Synchronously read in the cookies for our two domains. The first should + // succeed, but the second should fail midway through, resulting in none of + // those cookies being present. + do_check_eq(Services.cookiemgr.countCookiesFromHost("hither.com"), 10); + do_check_eq(Services.cookiemgr.countCookiesFromHost("haithur.com"), 0); + + // Wait for the backup file to be created and the database rebuilt. + do_check_false(do_get_backup_file(profile).exists()); + new _observer(sub_generator, "cookie-db-rebuilding"); + yield; + do_execute_soon(function() { do_run_generator(sub_generator); }); + yield; + + // Close the profile. + do_close_profile(sub_generator); + yield; + let db = Services.storage.openDatabase(do_get_cookie_file(profile)); + do_check_eq(do_count_cookies_in_db(db, "hither.com"), 10); + do_check_eq(do_count_cookies_in_db(db), 10); + db.close(); + + // Check that the original database was renamed. + do_check_true(do_get_backup_file(profile).exists()); + do_check_eq(do_get_backup_file(profile).fileSize, size); + + // Rename it back, and try loading the entire database synchronously. + do_get_backup_file(profile).moveTo(null, "cookies.sqlite"); + do_load_profile(); + + // At this point, the database connection should be open. Ensure that it + // succeeded. + do_check_false(do_get_backup_file(profile).exists()); + + // Synchronously read in everything. + do_check_eq(do_count_cookies(), 0); + + // Wait for the backup file to be created and the database rebuilt. + do_check_false(do_get_backup_file(profile).exists()); + new _observer(sub_generator, "cookie-db-rebuilding"); + yield; + do_execute_soon(function() { do_run_generator(sub_generator); }); + yield; + + // Close the profile. + do_close_profile(sub_generator); + yield; + db = Services.storage.openDatabase(do_get_cookie_file(profile)); + do_check_eq(do_count_cookies_in_db(db), 0); + db.close(); + + // Check that the original database was renamed. + do_check_true(do_get_backup_file(profile).exists()); + do_check_eq(do_get_backup_file(profile).fileSize, size); + + // Clean up. + do_get_cookie_file(profile).remove(false); + do_get_backup_file(profile).remove(false); + do_check_false(do_get_cookie_file(profile).exists()); + do_check_false(do_get_backup_file(profile).exists()); + do_run_generator(generator); +} + +function run_test_4(generator) +{ + // Load the profile and populate it. + do_load_profile(); + for (let i = 0; i < 3000; ++i) { + let uri = NetUtil.newURI("http://" + i + ".com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + } + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Corrupt the database file. + let size = do_corrupt_db(do_get_cookie_file(profile)); + + // Load the profile. + do_load_profile(); + + // At this point, the database connection should be open. Ensure that it + // succeeded. + do_check_false(do_get_backup_file(profile).exists()); + + // Synchronously read in the first cookie. This will cause it to go into the + // cookie table, whereupon it will be written out during database rebuild. + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + + // Queue up an INSERT for the same base domain. This should also go into + // memory and be written out during database rebuild. + let uri = NetUtil.newURI("http://0.com/"); + Services.cookies.setCookieString(uri, null, "oh2=hai; max-age=1000", null); + + // Wait for the asynchronous read to choke and the insert to fail shortly + // thereafter, at which point the backup file will be created and the database + // rebuilt. + new _observer(sub_generator, "cookie-db-rebuilding"); + yield; + do_execute_soon(function() { do_run_generator(sub_generator); }); + yield; + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Check that the original database was renamed. + do_check_true(do_get_backup_file(profile).exists()); + do_check_eq(do_get_backup_file(profile).fileSize, size); + let db = Services.storage.openDatabase(do_get_cookie_file(profile)); + do_check_eq(do_count_cookies_in_db(db, "0.com"), 2); + db.close(); + + // Load the profile, and check that it contains the new cookie. + do_load_profile(); + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 2); + do_check_eq(do_count_cookies(), 2); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Clean up. + do_get_cookie_file(profile).remove(false); + do_get_backup_file(profile).remove(false); + do_check_false(do_get_cookie_file(profile).exists()); + do_check_false(do_get_backup_file(profile).exists()); + do_run_generator(generator); +} + +function run_test_4(generator) +{ + // Load the profile and populate it. + do_load_profile(); + for (let i = 0; i < 3000; ++i) { + let uri = NetUtil.newURI("http://" + i + ".com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + } + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Corrupt the database file. + let size = do_corrupt_db(do_get_cookie_file(profile)); + + // Load the profile. + do_load_profile(); + + // At this point, the database connection should be open. Ensure that it + // succeeded. + do_check_false(do_get_backup_file(profile).exists()); + + // Synchronously read in the first cookie. This will cause it to go into the + // cookie table, whereupon it will be written out during database rebuild. + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + + // Queue up an INSERT for the same base domain. This should also go into + // memory and be written out during database rebuild. + let uri = NetUtil.newURI("http://0.com/"); + Services.cookies.setCookieString(uri, null, "oh2=hai; max-age=1000", null); + + // Wait for the asynchronous read to choke and the insert to fail shortly + // thereafter, at which point the backup file will be created and the database + // rebuilt. + new _observer(sub_generator, "cookie-db-rebuilding"); + yield; + do_execute_soon(function() { do_run_generator(sub_generator); }); + yield; + + // At this point, the cookies should still be in memory. + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 2); + do_check_eq(do_count_cookies(), 2); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Check that the original database was renamed. + do_check_true(do_get_backup_file(profile).exists()); + do_check_eq(do_get_backup_file(profile).fileSize, size); + let db = Services.storage.openDatabase(do_get_cookie_file(profile)); + do_check_eq(do_count_cookies_in_db(db, "0.com"), 2); + db.close(); + + // Load the profile, and check that it contains the new cookie. + do_load_profile(); + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 2); + do_check_eq(do_count_cookies(), 2); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Clean up. + do_get_cookie_file(profile).remove(false); + do_get_backup_file(profile).remove(false); + do_check_false(do_get_cookie_file(profile).exists()); + do_check_false(do_get_backup_file(profile).exists()); + do_run_generator(generator); +} + +function run_test_5(generator) +{ + // Load the profile and populate it. + do_load_profile(); + let uri = NetUtil.newURI("http://bar.com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; path=/; max-age=1000", + null); + for (let i = 0; i < 3000; ++i) { + let uri = NetUtil.newURI("http://" + i + ".com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + } + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Corrupt the database file. + let size = do_corrupt_db(do_get_cookie_file(profile)); + + // Load the profile. + do_load_profile(); + + // At this point, the database connection should be open. Ensure that it + // succeeded. + do_check_false(do_get_backup_file(profile).exists()); + + // Synchronously read in the first two cookies. This will cause them to go + // into the cookie table, whereupon it will be written out during database + // rebuild. + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + + // Wait for the asynchronous read to choke, at which point the backup file + // will be created and a new connection opened. + new _observer(sub_generator, "cookie-db-rebuilding"); + yield; + + // At this point, the cookies should still be in memory. (Note that these + // calls are re-entrant into the cookie service, but it's OK!) + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + do_check_eq(do_count_cookies(), 2); + do_check_true(do_get_backup_file(profile).exists()); + do_check_eq(do_get_backup_file(profile).fileSize, size); + do_check_false(do_get_rebuild_backup_file(profile).exists()); + + // Open a database connection, and write a row that will trigger a constraint + // violation. + let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 4); + db.insertCookie(cookie); + do_check_eq(do_count_cookies_in_db(db.db, "bar.com"), 1); + do_check_eq(do_count_cookies_in_db(db.db), 1); + db.close(); + + // Wait for the rebuild to bail and the database to be closed. + new _observer(sub_generator, "cookie-db-closed"); + yield; + + // Check that the original backup and the database itself are gone. + do_check_true(do_get_rebuild_backup_file(profile).exists()); + do_check_true(do_get_backup_file(profile).exists()); + do_check_eq(do_get_backup_file(profile).fileSize, size); + do_check_false(do_get_cookie_file(profile).exists()); + + // Check that the rebuild backup has the original bar.com cookie, and possibly + // a 0.com cookie depending on whether it got written out first or second. + db = new CookieDatabaseConnection(do_get_rebuild_backup_file(profile), 4); + do_check_eq(do_count_cookies_in_db(db.db, "bar.com"), 1); + let count = do_count_cookies_in_db(db.db); + do_check_true(count == 1 || + count == 2 && do_count_cookies_in_db(db.db, "0.com") == 1); + db.close(); + + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1); + do_check_eq(do_count_cookies(), 2); + + // Close the profile. We do not need to wait for completion, because the + // database has already been closed. + do_close_profile(); + + // Clean up. + do_get_backup_file(profile).remove(false); + do_get_rebuild_backup_file(profile).remove(false); + do_check_false(do_get_cookie_file(profile).exists()); + do_check_false(do_get_backup_file(profile).exists()); + do_check_false(do_get_rebuild_backup_file(profile).exists()); + do_run_generator(generator); +} + diff --git a/extensions/cookie/test/unit/test_cookies_persistence.js b/extensions/cookie/test/unit/test_cookies_persistence.js new file mode 100644 index 000000000..d6de81b72 --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_persistence.js @@ -0,0 +1,78 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// test for cookie persistence across sessions, for the cases: +// 1) network.cookie.lifetimePolicy = 0 (expire naturally) +// 2) network.cookie.lifetimePolicy = 2 (expire at end of session) + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + // Create URIs and channels pointing to foo.com and bar.com. + // We will use these to put foo.com into first and third party contexts. + var spec1 = "http://foo.com/foo.html"; + var spec2 = "http://bar.com/bar.html"; + var uri1 = NetUtil.newURI(spec1); + var uri2 = NetUtil.newURI(spec2); + var channel1 = NetUtil.newChannel({uri: uri1, loadUsingSystemPrincipal: true}); + var channel2 = NetUtil.newChannel({uri: uri2, loadUsingSystemPrincipal: true}); + + // Force the channel URI to be used when determining the originating URI of + // the channel. + var httpchannel1 = channel1.QueryInterface(Ci.nsIHttpChannelInternal); + var httpchannel2 = channel1.QueryInterface(Ci.nsIHttpChannelInternal); + httpchannel1.forceAllowThirdPartyCookie = true; + httpchannel2.forceAllowThirdPartyCookie = true; + + // test with cookies enabled, and third party cookies persistent. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref("network.cookie.thirdparty.sessionOnly", false); + do_set_cookies(uri1, channel1, false, [1, 2, 3, 4]); + do_set_cookies(uri2, channel2, true, [1, 2, 3, 4]); + + // fake a profile change + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 4); + do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0); + + // Again, but don't wait for the async close to complete. This should always + // work, since we blocked on close above and haven't kicked off any writes + // since then. + do_close_profile(); + do_load_profile(); + do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 4); + do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0); + + // test with cookies set to session-only + Services.prefs.setIntPref("network.cookie.lifetimePolicy", 2); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel1, false, [1, 2, 3, 4]); + do_set_cookies(uri2, channel2, true, [1, 2, 3, 4]); + + // fake a profile change + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 0); + do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0); + + finish_test(); +} + diff --git a/extensions/cookie/test/unit/test_cookies_privatebrowsing.js b/extensions/cookie/test/unit/test_cookies_privatebrowsing.js new file mode 100644 index 000000000..ab35f8ef7 --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_privatebrowsing.js @@ -0,0 +1,115 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test private browsing mode. + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + do_run_generator(test_generator); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function make_channel(url) { + return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}) + .QueryInterface(Ci.nsIHttpChannel); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + // Test with cookies enabled. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + // Create URIs pointing to foo.com and bar.com. + let uri1 = NetUtil.newURI("http://foo.com/foo.html"); + let uri2 = NetUtil.newURI("http://bar.com/bar.html"); + + // Set a cookie for host 1. + Services.cookies.setCookieString(uri1, null, "oh=hai; max-age=1000", null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1); + + // Enter private browsing mode, set a cookie for host 2, and check the counts. + var chan1 = make_channel(uri1.spec); + chan1.QueryInterface(Ci.nsIPrivateBrowsingChannel); + chan1.setPrivate(true); + + var chan2 = make_channel(uri2.spec); + chan2.QueryInterface(Ci.nsIPrivateBrowsingChannel); + chan2.setPrivate(true); + + Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2); + do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null); + do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai"); + + // Remove cookies and check counts. + Services.obs.notifyObservers(null, "last-pb-context-exited", null); + do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null); + do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), null); + + Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2); + do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai"); + + // Leave private browsing mode and check counts. + Services.obs.notifyObservers(null, "last-pb-context-exited", null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri2.host), 0); + + // Fake a profile change. + do_close_profile(test_generator); + yield; + do_load_profile(); + + // Check that the right cookie persisted. + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri2.host), 0); + + // Enter private browsing mode, set a cookie for host 2, and check the counts. + do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null); + do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), null); + Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2); + do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai"); + + // Fake a profile change. + do_close_profile(test_generator); + yield; + do_load_profile(); + + // We're still in private browsing mode, but should have a new session. + // Check counts. + do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null); + do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), null); + + // Leave private browsing mode and check counts. + Services.obs.notifyObservers(null, "last-pb-context-exited", null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri2.host), 0); + + // Enter private browsing mode. + + // Fake a profile change, but wait for async read completion. + do_close_profile(test_generator); + yield; + do_load_profile(test_generator); + yield; + + // We're still in private browsing mode, but should have a new session. + // Check counts. + do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null); + do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), null); + + // Leave private browsing mode and check counts. + Services.obs.notifyObservers(null, "last-pb-context-exited", null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri2.host), 0); + + finish_test(); +} diff --git a/extensions/cookie/test/unit/test_cookies_profile_close.js b/extensions/cookie/test/unit/test_cookies_profile_close.js new file mode 100644 index 000000000..bae6e3a59 --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_profile_close.js @@ -0,0 +1,92 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that the cookie APIs behave sanely after 'profile-before-change'. + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + // Allow all cookies. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + // Start the cookieservice. + Services.cookies; + + // Set a cookie. + let uri = NetUtil.newURI("http://foo.com"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + let enumerator = Services.cookiemgr.enumerator; + do_check_true(enumerator.hasMoreElements()); + let cookie = enumerator.getNext(); + do_check_false(enumerator.hasMoreElements()); + + // Fire 'profile-before-change'. + do_close_profile(); + + // Check that the APIs behave appropriately. + do_check_eq(Services.cookies.getCookieString(uri, null), null); + do_check_eq(Services.cookies.getCookieStringFromHttp(uri, null, null), null); + Services.cookies.setCookieString(uri, null, "oh2=hai", null); + Services.cookies.setCookieStringFromHttp(uri, null, null, "oh3=hai", null, null); + do_check_eq(Services.cookies.getCookieString(uri, null), null); + + do_check_throws(function() { + Services.cookiemgr.removeAll(); + }, Cr.NS_ERROR_NOT_AVAILABLE); + + do_check_throws(function() { + Services.cookiemgr.enumerator; + }, Cr.NS_ERROR_NOT_AVAILABLE); + + do_check_throws(function() { + Services.cookiemgr.add("foo.com", "", "oh4", "hai", false, false, false, 0, {}); + }, Cr.NS_ERROR_NOT_AVAILABLE); + + do_check_throws(function() { + Services.cookiemgr.remove("foo.com", "", "oh4", false, {}); + }, Cr.NS_ERROR_NOT_AVAILABLE); + + do_check_throws(function() { + let file = profile.clone(); + file.append("cookies.txt"); + Services.cookiemgr.importCookies(file); + }, Cr.NS_ERROR_NOT_AVAILABLE); + + do_check_throws(function() { + Services.cookiemgr.cookieExists(cookie); + }, Cr.NS_ERROR_NOT_AVAILABLE); + + do_check_throws(function() { + Services.cookies.countCookiesFromHost("foo.com"); + }, Cr.NS_ERROR_NOT_AVAILABLE); + + do_check_throws(function() { + Services.cookies.getCookiesFromHost("foo.com", {}); + }, Cr.NS_ERROR_NOT_AVAILABLE); + + // Wait for the database to finish closing. + new _observer(test_generator, "cookie-db-closed"); + yield; + + // Load the profile and check that the API is available. + do_load_profile(); + do_check_true(Services.cookiemgr.cookieExists(cookie)); + + finish_test(); +} + diff --git a/extensions/cookie/test/unit/test_cookies_read.js b/extensions/cookie/test/unit/test_cookies_read.js new file mode 100644 index 000000000..b389ad8cc --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_read.js @@ -0,0 +1,122 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// test cookie database asynchronous read operation. + +var test_generator = do_run_test(); + +var CMAX = 1000; // # of cookies to create + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + // Allow all cookies. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + // Start the cookieservice, to force creation of a database. + Services.cookies; + + // Open a database connection now, after synchronous initialization has + // completed. We may not be able to open one later once asynchronous writing + // begins. + do_check_true(do_get_cookie_file(profile).exists()); + let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 4); + + for (let i = 0; i < CMAX; ++i) { + let uri = NetUtil.newURI("http://" + i + ".com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + } + + do_check_eq(do_count_cookies(), CMAX); + + // Wait until all CMAX cookies have been written out to the database. + while (do_count_cookies_in_db(db.db) < CMAX) { + do_execute_soon(function() { + do_run_generator(test_generator); + }); + yield; + } + + // Check the WAL file size. We set it to 16 pages of 32k, which means it + // should be around 500k. + let file = db.db.databaseFile; + do_check_true(file.exists()); + do_check_true(file.fileSize < 1e6); + db.close(); + + // fake a profile change + do_close_profile(test_generator); + yield; + do_load_profile(); + + // test a few random cookies + do_check_eq(Services.cookiemgr.countCookiesFromHost("999.com"), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost("abc.com"), 0); + do_check_eq(Services.cookiemgr.countCookiesFromHost("100.com"), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost("400.com"), 1); + do_check_eq(Services.cookiemgr.countCookiesFromHost("xyz.com"), 0); + + // force synchronous load of everything + do_check_eq(do_count_cookies(), CMAX); + + // check that everything's precisely correct + for (let i = 0; i < CMAX; ++i) { + let host = i.toString() + ".com"; + do_check_eq(Services.cookiemgr.countCookiesFromHost(host), 1); + } + + // reload again, to make sure the additions were written correctly + do_close_profile(test_generator); + yield; + do_load_profile(); + + // remove some of the cookies, in both reverse and forward order + for (let i = 100; i-- > 0; ) { + let host = i.toString() + ".com"; + Services.cookiemgr.remove(host, "oh", "/", false, {}); + } + for (let i = CMAX - 100; i < CMAX; ++i) { + let host = i.toString() + ".com"; + Services.cookiemgr.remove(host, "oh", "/", false, {}); + } + + // check the count + do_check_eq(do_count_cookies(), CMAX - 200); + + // reload again, to make sure the removals were written correctly + do_close_profile(test_generator); + yield; + do_load_profile(); + + // check the count + do_check_eq(do_count_cookies(), CMAX - 200); + + // reload again, but wait for async read completion + do_close_profile(test_generator); + yield; + do_load_profile(test_generator); + yield; + + // check that everything's precisely correct + do_check_eq(do_count_cookies(), CMAX - 200); + for (let i = 100; i < CMAX - 100; ++i) { + let host = i.toString() + ".com"; + do_check_eq(Services.cookiemgr.countCookiesFromHost(host), 1); + } + + finish_test(); +} + diff --git a/extensions/cookie/test/unit/test_cookies_sync_failure.js b/extensions/cookie/test/unit/test_cookies_sync_failure.js new file mode 100644 index 000000000..2de1de628 --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_sync_failure.js @@ -0,0 +1,286 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test the various ways opening a cookie database can fail in a synchronous +// (i.e. immediate) manner, and that the database is renamed and recreated +// under each circumstance. These circumstances are, in no particular order: +// +// 1) A corrupt database, such that opening the connection fails. +// 2) The 'moz_cookies' table doesn't exist. +// 3) Not all of the expected columns exist, and statement creation fails when: +// a) The schema version is larger than the current version. +// b) The schema version is less than or equal to the current version. +// 4) Migration fails. This will have different modes depending on the initial +// version: +// a) Schema 1: the 'lastAccessed' column already exists. +// b) Schema 2: the 'baseDomain' column already exists; or 'baseDomain' +// cannot be computed for a particular host. +// c) Schema 3: the 'creationTime' column already exists; or the +// 'moz_uniqueid' index already exists. + +var COOKIE_DATABASE_SCHEMA_CURRENT = 7; + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + do_run_generator(test_generator); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + this.profile = do_get_profile(); + + // Allow all cookies. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + // Get the cookie file and the backup file. + this.cookieFile = profile.clone(); + cookieFile.append("cookies.sqlite"); + this.backupFile = profile.clone(); + backupFile.append("cookies.sqlite.bak"); + do_check_false(cookieFile.exists()); + do_check_false(backupFile.exists()); + + // Create a cookie object for testing. + this.now = Date.now() * 1000; + this.futureExpiry = Math.round(this.now / 1e6 + 1000); + this.cookie = new Cookie("oh", "hai", "bar.com", "/", this.futureExpiry, + this.now, this.now, false, false, false); + + this.sub_generator = run_test_1(test_generator); + sub_generator.next(); + yield; + + this.sub_generator = run_test_2(test_generator); + sub_generator.next(); + yield; + + this.sub_generator = run_test_3(test_generator, 99); + sub_generator.next(); + yield; + + this.sub_generator = run_test_3(test_generator, COOKIE_DATABASE_SCHEMA_CURRENT); + sub_generator.next(); + yield; + + this.sub_generator = run_test_3(test_generator, 4); + sub_generator.next(); + yield; + + this.sub_generator = run_test_3(test_generator, 3); + sub_generator.next(); + yield; + + this.sub_generator = run_test_4_exists(test_generator, 1, + "ALTER TABLE moz_cookies ADD lastAccessed INTEGER"); + sub_generator.next(); + yield; + + this.sub_generator = run_test_4_exists(test_generator, 2, + "ALTER TABLE moz_cookies ADD baseDomain TEXT"); + sub_generator.next(); + yield; + + this.sub_generator = run_test_4_baseDomain(test_generator); + sub_generator.next(); + yield; + + this.sub_generator = run_test_4_exists(test_generator, 3, + "ALTER TABLE moz_cookies ADD creationTime INTEGER"); + sub_generator.next(); + yield; + + this.sub_generator = run_test_4_exists(test_generator, 3, + "CREATE UNIQUE INDEX moz_uniqueid ON moz_cookies (name, host, path)"); + sub_generator.next(); + yield; + + finish_test(); + return; +} + +const garbage = "hello thar!"; + +function create_garbage_file(file) +{ + // Create an empty database file. + file.create(Ci.nsIFile.NORMAL_FILE_TYPE, -1); + do_check_true(file.exists()); + do_check_eq(file.fileSize, 0); + + // Write some garbage to it. + let ostream = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + ostream.init(file, -1, -1, 0); + ostream.write(garbage, garbage.length); + ostream.flush(); + ostream.close(); + + file = file.clone(); // Windows maintains a stat cache. It's lame. + do_check_eq(file.fileSize, garbage.length); +} + +function check_garbage_file(file) +{ + do_check_true(file.exists()); + do_check_eq(file.fileSize, garbage.length); + file.remove(false); + do_check_false(file.exists()); +} + +function run_test_1(generator) +{ + // Create a garbage database file. + create_garbage_file(cookieFile); + + // Load the profile and populate it. + let uri = NetUtil.newURI("http://foo.com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + + // Fake a profile change. + do_close_profile(sub_generator); + yield; + do_load_profile(); + + // Check that the new database contains the cookie, and the old file was + // renamed. + do_check_eq(do_count_cookies(), 1); + check_garbage_file(backupFile); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Clean up. + cookieFile.remove(false); + do_check_false(cookieFile.exists()); + do_run_generator(generator); +} + +function run_test_2(generator) +{ + // Load the profile and populate it. + do_load_profile(); + let uri = NetUtil.newURI("http://foo.com/"); + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + + // Fake a profile change. + do_close_profile(sub_generator); + yield; + + // Drop the table. + let db = Services.storage.openDatabase(cookieFile); + db.executeSimpleSQL("DROP TABLE moz_cookies"); + db.close(); + + // Load the profile and check that the table is recreated in-place. + do_load_profile(); + do_check_eq(do_count_cookies(), 0); + do_check_false(backupFile.exists()); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Clean up. + cookieFile.remove(false); + do_check_false(cookieFile.exists()); + do_run_generator(generator); +} + +function run_test_3(generator, schema) +{ + // Manually create a schema 2 database, populate it, and set the schema + // version to the desired number. + let schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + schema2db.insertCookie(cookie); + schema2db.db.schemaVersion = schema; + schema2db.close(); + + // Load the profile and check that the column existence test fails. + do_load_profile(); + do_check_eq(do_count_cookies(), 0); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Check that the schema version has been reset. + let db = Services.storage.openDatabase(cookieFile); + do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); + db.close(); + + // Clean up. + cookieFile.remove(false); + do_check_false(cookieFile.exists()); + do_run_generator(generator); +} + +function run_test_4_exists(generator, schema, stmt) +{ + // Manually create a database, populate it, and add the desired column. + let db = new CookieDatabaseConnection(do_get_cookie_file(profile), schema); + db.insertCookie(cookie); + db.db.executeSimpleSQL(stmt); + db.close(); + + // Load the profile and check that migration fails. + do_load_profile(); + do_check_eq(do_count_cookies(), 0); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Check that the schema version has been reset and the backup file exists. + db = Services.storage.openDatabase(cookieFile); + do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); + db.close(); + do_check_true(backupFile.exists()); + + // Clean up. + cookieFile.remove(false); + backupFile.remove(false); + do_check_false(cookieFile.exists()); + do_check_false(backupFile.exists()); + do_run_generator(generator); +} + +function run_test_4_baseDomain(generator) +{ + // Manually create a database and populate it with a bad host. + let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + let badCookie = new Cookie("oh", "hai", ".", "/", this.futureExpiry, this.now, + this.now, false, false, false); + db.insertCookie(badCookie); + db.close(); + + // Load the profile and check that migration fails. + do_load_profile(); + do_check_eq(do_count_cookies(), 0); + + // Close the profile. + do_close_profile(sub_generator); + yield; + + // Check that the schema version has been reset and the backup file exists. + db = Services.storage.openDatabase(cookieFile); + do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); + db.close(); + do_check_true(backupFile.exists()); + + // Clean up. + cookieFile.remove(false); + backupFile.remove(false); + do_check_false(cookieFile.exists()); + do_check_false(backupFile.exists()); + do_run_generator(generator); +} diff --git a/extensions/cookie/test/unit/test_cookies_thirdparty.js b/extensions/cookie/test/unit/test_cookies_thirdparty.js new file mode 100644 index 000000000..a39f807f2 --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_thirdparty.js @@ -0,0 +1,147 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// test third party cookie blocking, for the cases: +// 1) with null channel +// 2) with channel, but with no docshell parent + +function run_test() { + // Create URIs and channels pointing to foo.com and bar.com. + // We will use these to put foo.com into first and third party contexts. + var spec1 = "http://foo.com/foo.html"; + var spec2 = "http://bar.com/bar.html"; + var uri1 = NetUtil.newURI(spec1); + var uri2 = NetUtil.newURI(spec2); + var channel1 = NetUtil.newChannel({uri: uri1, loadUsingSystemPrincipal: true}); + var channel2 = NetUtil.newChannel({uri: uri2, loadUsingSystemPrincipal: true}); + + // test with cookies enabled + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + do_set_cookies(uri1, channel1, true, [1, 2, 3, 4]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [1, 2, 3, 4]); + Services.cookies.removeAll(); + + // test with third party cookies blocked + Services.prefs.setIntPref("network.cookie.cookieBehavior", 1); + do_set_cookies(uri1, channel1, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + + // Force the channel URI to be used when determining the originating URI of + // the channel. + var httpchannel1 = channel1.QueryInterface(Ci.nsIHttpChannelInternal); + var httpchannel2 = channel2.QueryInterface(Ci.nsIHttpChannelInternal); + httpchannel1.forceAllowThirdPartyCookie = true; + httpchannel2.forceAllowThirdPartyCookie = true; + + // test with cookies enabled + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + do_set_cookies(uri1, channel1, true, [1, 2, 3, 4]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [1, 2, 3, 4]); + Services.cookies.removeAll(); + + // test with third party cookies blocked + Services.prefs.setIntPref("network.cookie.cookieBehavior", 1); + do_set_cookies(uri1, channel1, true, [0, 1, 1, 2]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + + // test with third party cookies limited + Services.prefs.setIntPref("network.cookie.cookieBehavior", 3); + do_set_cookies(uri1, channel1, true, [0, 1, 2, 3]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + do_set_single_http_cookie(uri1, channel1, 1); + do_set_cookies(uri1, channel2, true, [2, 3, 4, 5]); + Services.cookies.removeAll(); + + // Test per-site 3rd party cookie blocking with cookies enabled + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + var kPermissionType = "cookie"; + var ALLOW_FIRST_PARTY_ONLY = 9; + // ALLOW_FIRST_PARTY_ONLY overrides + Services.perms.add(uri1, kPermissionType, ALLOW_FIRST_PARTY_ONLY); + do_set_cookies(uri1, channel1, true, [0, 1, 1, 2]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + + // Test per-site 3rd party cookie blocking with 3rd party cookies disabled + Services.prefs.setIntPref("network.cookie.cookieBehavior", 1); + do_set_cookies(uri1, channel1, true, [0, 1, 1, 2]); + Services.cookies.removeAll(); + // No preference has been set for uri2, but it should act as if + // ALLOW_FIRST_PARTY_ONLY has been set + do_set_cookies(uri2, channel2, true, [0, 1, 1, 2]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + + // Test per-site 3rd party cookie blocking with 3rd party cookies limited + Services.prefs.setIntPref("network.cookie.cookieBehavior", 3); + do_set_cookies(uri1, channel1, true, [0, 1, 1, 2]); + Services.cookies.removeAll(); + // No preference has been set for uri2, but it should act as if + // LIMIT_THIRD_PARTY has been set + do_set_cookies(uri2, channel2, true, [0, 1, 2, 3]); + Services.cookies.removeAll(); + do_set_single_http_cookie(uri2, channel2, 1); + do_set_cookies(uri2, channel2, true, [2, 3, 4, 5]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + do_set_single_http_cookie(uri1, channel1, 1); + do_set_cookies(uri1, channel2, true, [1, 1, 1, 1]); + Services.cookies.removeAll(); + + // Test per-site 3rd party cookie limiting with cookies enabled + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + var kPermissionType = "cookie"; + var LIMIT_THIRD_PARTY = 10; + // LIMIT_THIRD_PARTY overrides + Services.perms.add(uri1, kPermissionType, LIMIT_THIRD_PARTY); + do_set_cookies(uri1, channel1, true, [0, 1, 2, 3]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + do_set_single_http_cookie(uri1, channel1, 1); + do_set_cookies(uri1, channel2, true, [2, 3, 4, 5]); + Services.cookies.removeAll(); + + // Test per-site 3rd party cookie limiting with 3rd party cookies disabled + Services.prefs.setIntPref("network.cookie.cookieBehavior", 1); + do_set_cookies(uri1, channel1, true, [0, 1, 2, 3]); + Services.cookies.removeAll(); + // No preference has been set for uri2, but it should act as if + // ALLOW_FIRST_PARTY_ONLY has been set + do_set_cookies(uri2, channel2, true, [0, 1, 1, 2]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + do_set_single_http_cookie(uri1, channel1, 1); + do_set_cookies(uri1, channel2, true, [2, 3, 4, 5]); + Services.cookies.removeAll(); + + // Test per-site 3rd party cookie limiting with 3rd party cookies limited + Services.prefs.setIntPref("network.cookie.cookieBehavior", 3); + do_set_cookies(uri1, channel1, true, [0, 1, 2, 3]); + Services.cookies.removeAll(); + // No preference has been set for uri2, but it should act as if + // LIMIT_THIRD_PARTY has been set + do_set_cookies(uri2, channel2, true, [0, 1, 2, 3]); + Services.cookies.removeAll(); + do_set_single_http_cookie(uri2, channel2, 1); + do_set_cookies(uri2, channel2, true, [2, 3, 4, 5]); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, true, [0, 0, 0, 0]); + Services.cookies.removeAll(); + do_set_single_http_cookie(uri1, channel1, 1); + do_set_cookies(uri1, channel2, true, [2, 3, 4, 5]); + Services.cookies.removeAll(); +} + diff --git a/extensions/cookie/test/unit/test_cookies_thirdparty_session.js b/extensions/cookie/test/unit/test_cookies_thirdparty_session.js new file mode 100644 index 000000000..36e5fb11a --- /dev/null +++ b/extensions/cookie/test/unit/test_cookies_thirdparty_session.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// test third party persistence across sessions, for the cases: +// 1) network.cookie.thirdparty.sessionOnly = false +// 2) network.cookie.thirdparty.sessionOnly = true + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + // Create URIs and channels pointing to foo.com and bar.com. + // We will use these to put foo.com into first and third party contexts. + var spec1 = "http://foo.com/foo.html"; + var spec2 = "http://bar.com/bar.html"; + var uri1 = NetUtil.newURI(spec1); + var uri2 = NetUtil.newURI(spec2); + var channel1 = NetUtil.newChannel({uri: uri1, loadUsingSystemPrincipal: true}); + var channel2 = NetUtil.newChannel({uri: uri2, loadUsingSystemPrincipal: true}); + + // Force the channel URI to be used when determining the originating URI of + // the channel. + var httpchannel1 = channel1.QueryInterface(Ci.nsIHttpChannelInternal); + var httpchannel2 = channel2.QueryInterface(Ci.nsIHttpChannelInternal); + httpchannel1.forceAllowThirdPartyCookie = true; + httpchannel2.forceAllowThirdPartyCookie = true; + + // test with cookies enabled, and third party cookies persistent. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref("network.cookie.thirdparty.sessionOnly", false); + do_set_cookies(uri1, channel2, false, [1, 2, 3, 4]); + do_set_cookies(uri2, channel1, true, [1, 2, 3, 4]); + + // fake a profile change + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 4); + do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0); + + // test with third party cookies for session only. + Services.prefs.setBoolPref("network.cookie.thirdparty.sessionOnly", true); + Services.cookies.removeAll(); + do_set_cookies(uri1, channel2, false, [1, 2, 3, 4]); + do_set_cookies(uri2, channel1, true, [1, 2, 3, 4]); + + // fake a profile change + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 0); + do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0); + + finish_test(); +} diff --git a/extensions/cookie/test/unit/test_domain_eviction.js b/extensions/cookie/test/unit/test_domain_eviction.js new file mode 100644 index 000000000..349f6d77e --- /dev/null +++ b/extensions/cookie/test/unit/test_domain_eviction.js @@ -0,0 +1,153 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that domain eviction occurs when the cookies per base domain limit is +// reached, and that expired cookies are evicted before live cookies. + +var test_generator = do_run_test(); + +function run_test() +{ + do_test_pending(); + do_run_generator(test_generator); +} + +function continue_test() +{ + do_run_generator(test_generator); +} + +function do_run_test() +{ + // Set the base domain limit to 50 so we have a known value. + Services.prefs.setIntPref("network.cookie.maxPerHost", 50); + + let futureExpiry = Math.floor(Date.now() / 1000 + 1000); + + // test eviction under the 50 cookies per base domain limit. this means + // that cookies for foo.com and bar.foo.com should count toward this limit, + // while cookies for baz.com should not. there are several tests we perform + // to make sure the base domain logic is working correctly. + + // 1) simplest case: set 100 cookies for "foo.bar" and make sure 50 survive. + setCookies("foo.bar", 100, futureExpiry); + do_check_eq(countCookies("foo.bar", "foo.bar"), 50); + + // 2) set cookies for different subdomains of "foo.baz", and an unrelated + // domain, and make sure all 50 within the "foo.baz" base domain are counted. + setCookies("foo.baz", 10, futureExpiry); + setCookies(".foo.baz", 10, futureExpiry); + setCookies("bar.foo.baz", 10, futureExpiry); + setCookies("baz.bar.foo.baz", 10, futureExpiry); + setCookies("unrelated.domain", 50, futureExpiry); + do_check_eq(countCookies("foo.baz", "baz.bar.foo.baz"), 40); + setCookies("foo.baz", 20, futureExpiry); + do_check_eq(countCookies("foo.baz", "baz.bar.foo.baz"), 50); + + // 3) ensure cookies are evicted by order of lastAccessed time, if the + // limit on cookies per base domain is reached. + setCookies("horse.radish", 10, futureExpiry); + + // Wait a while, to make sure the first batch of cookies is older than + // the second (timer resolution varies on different platforms). + do_timeout(100, continue_test); + yield; + + setCookies("tasty.horse.radish", 50, futureExpiry); + do_check_eq(countCookies("horse.radish", "horse.radish"), 50); + + let enumerator = Services.cookiemgr.enumerator; + while (enumerator.hasMoreElements()) { + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + + if (cookie.host == "horse.radish") + do_throw("cookies not evicted by lastAccessed order"); + } + + // Test that expired cookies for a domain are evicted before live ones. + let shortExpiry = Math.floor(Date.now() / 1000 + 2); + setCookies("captchart.com", 49, futureExpiry); + Services.cookiemgr.add("captchart.com", "", "test100", "eviction", + false, false, false, shortExpiry, {}); + do_timeout(2100, continue_test); + yield; + + do_check_eq(countCookies("captchart.com", "captchart.com"), 50); + Services.cookiemgr.add("captchart.com", "", "test200", "eviction", + false, false, false, futureExpiry, {}); + do_check_eq(countCookies("captchart.com", "captchart.com"), 50); + + enumerator = Services.cookiemgr.getCookiesFromHost("captchart.com", {}); + while (enumerator.hasMoreElements()) { + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + do_check_true(cookie.expiry == futureExpiry); + } + + do_finish_generator_test(test_generator); +} + +// set 'aNumber' cookies with host 'aHost', with distinct names. +function +setCookies(aHost, aNumber, aExpiry) +{ + for (let i = 0; i < aNumber; ++i) + Services.cookiemgr.add(aHost, "", "test" + i, "eviction", + false, false, false, aExpiry, {}); +} + +// count how many cookies are within domain 'aBaseDomain', using three +// independent interface methods on nsICookieManager2: +// 1) 'enumerator', an enumerator of all cookies; +// 2) 'countCookiesFromHost', which returns the number of cookies within the +// base domain of 'aHost', +// 3) 'getCookiesFromHost', which returns an enumerator of 2). +function +countCookies(aBaseDomain, aHost) +{ + let enumerator = Services.cookiemgr.enumerator; + + // count how many cookies are within domain 'aBaseDomain' using the cookie + // enumerator. + let cookies = []; + while (enumerator.hasMoreElements()) { + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + + if (cookie.host.length >= aBaseDomain.length && + cookie.host.slice(cookie.host.length - aBaseDomain.length) == aBaseDomain) + cookies.push(cookie); + } + + // confirm the count using countCookiesFromHost and getCookiesFromHost. + let result = cookies.length; + do_check_eq(Services.cookiemgr.countCookiesFromHost(aBaseDomain), + cookies.length); + do_check_eq(Services.cookiemgr.countCookiesFromHost(aHost), cookies.length); + + enumerator = Services.cookiemgr.getCookiesFromHost(aHost, {}); + while (enumerator.hasMoreElements()) { + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + + if (cookie.host.length >= aBaseDomain.length && + cookie.host.slice(cookie.host.length - aBaseDomain.length) == aBaseDomain) { + let found = false; + for (let i = 0; i < cookies.length; ++i) { + if (cookies[i].host == cookie.host && cookies[i].name == cookie.name) { + found = true; + cookies.splice(i, 1); + break; + } + } + + if (!found) + do_throw("cookie " + cookie.name + " not found in master enumerator"); + + } else { + do_throw("cookie host " + cookie.host + " not within domain " + aBaseDomain); + } + } + + do_check_eq(cookies.length, 0); + + return result; +} + diff --git a/extensions/cookie/test/unit/test_eviction.js b/extensions/cookie/test/unit/test_eviction.js new file mode 100644 index 000000000..7b1550208 --- /dev/null +++ b/extensions/cookie/test/unit/test_eviction.js @@ -0,0 +1,249 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +var test_generator = do_run_test(); + +function run_test() +{ + do_test_pending(); + do_run_generator(test_generator); +} + +function continue_test() +{ + do_run_generator(test_generator); +} + +function repeat_test() +{ + // The test is probably going to fail because setting a batch of cookies took + // a significant fraction of 'gPurgeAge'. Compensate by rerunning the + // test with a larger purge age. + do_check_true(gPurgeAge < 64); + gPurgeAge *= 2; + gShortExpiry *= 2; + + do_execute_soon(function() { + test_generator.close(); + test_generator = do_run_test(); + do_run_generator(test_generator); + }); +} + +// Purge threshold, in seconds. +var gPurgeAge = 1; + +// Short expiry age, in seconds. +var gShortExpiry = 2; + +// Required delay to ensure a purge occurs, in milliseconds. This must be at +// least gPurgeAge + 10%, and includes a little fuzz to account for timer +// resolution and possible differences between PR_Now() and Date.now(). +function get_purge_delay() +{ + return gPurgeAge * 1100 + 100; +} + +// Required delay to ensure a cookie set with an expiry time 'gShortExpiry' into +// the future will have expired. +function get_expiry_delay() +{ + return gShortExpiry * 1000 + 100; +} + +function do_run_test() +{ + // Set up a profile. + let profile = do_get_profile(); + + // twiddle prefs to convenient values for this test + Services.prefs.setIntPref("network.cookie.purgeAge", gPurgeAge); + Services.prefs.setIntPref("network.cookie.maxNumber", 100); + + let expiry = Date.now() / 1000 + 1000; + + // eviction is performed based on two limits: when the total number of cookies + // exceeds maxNumber + 10% (110), and when cookies are older than purgeAge + // (1 second). purging is done when both conditions are satisfied, and only + // those cookies are purged. + + // we test the following cases of eviction: + // 1) excess and age are satisfied, but only some of the excess are old enough + // to be purged. + Services.cookiemgr.removeAll(); + if (!set_cookies(0, 5, expiry)) { + repeat_test(); + return; + } + // Sleep a while, to make sure the first batch of cookies is older than + // the second (timer resolution varies on different platforms). + do_timeout(get_purge_delay(), continue_test); + yield; + if (!set_cookies(5, 111, expiry)) { + repeat_test(); + return; + } + + // Fake a profile change, to ensure eviction affects the database correctly. + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_true(check_remaining_cookies(111, 5, 106)); + + // 2) excess and age are satisfied, and all of the excess are old enough + // to be purged. + Services.cookiemgr.removeAll(); + if (!set_cookies(0, 10, expiry)) { + repeat_test(); + return; + } + do_timeout(get_purge_delay(), continue_test); + yield; + if (!set_cookies(10, 111, expiry)) { + repeat_test(); + return; + } + + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_true(check_remaining_cookies(111, 10, 101)); + + // 3) excess and age are satisfied, and more than the excess are old enough + // to be purged. + Services.cookiemgr.removeAll(); + if (!set_cookies(0, 50, expiry)) { + repeat_test(); + return; + } + do_timeout(get_purge_delay(), continue_test); + yield; + if (!set_cookies(50, 111, expiry)) { + repeat_test(); + return; + } + + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_true(check_remaining_cookies(111, 50, 101)); + + // 4) excess but not age are satisfied. + Services.cookiemgr.removeAll(); + if (!set_cookies(0, 120, expiry)) { + repeat_test(); + return; + } + + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_true(check_remaining_cookies(120, 0, 120)); + + // 5) age but not excess are satisfied. + Services.cookiemgr.removeAll(); + if (!set_cookies(0, 20, expiry)) { + repeat_test(); + return; + } + do_timeout(get_purge_delay(), continue_test); + yield; + if (!set_cookies(20, 110, expiry)) { + repeat_test(); + return; + } + + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_true(check_remaining_cookies(110, 20, 110)); + + // 6) Excess and age are satisfied, but the cookie limit can be satisfied by + // purging expired cookies. + Services.cookiemgr.removeAll(); + let shortExpiry = Math.floor(Date.now() / 1000) + gShortExpiry; + if (!set_cookies(0, 20, shortExpiry)) { + repeat_test(); + return; + } + do_timeout(get_expiry_delay(), continue_test); + yield; + if (!set_cookies(20, 110, expiry)) { + repeat_test(); + return; + } + do_timeout(get_purge_delay(), continue_test); + yield; + if (!set_cookies(110, 111, expiry)) { + repeat_test(); + return; + } + + do_close_profile(test_generator); + yield; + do_load_profile(); + do_check_true(check_remaining_cookies(111, 20, 91)); + + do_finish_generator_test(test_generator); +} + +// Set 'end - begin' total cookies, with consecutively increasing hosts numbered +// 'begin' to 'end'. +function set_cookies(begin, end, expiry) +{ + do_check_true(begin != end); + + let beginTime; + for (let i = begin; i < end; ++i) { + let host = "eviction." + i + ".tests"; + Services.cookiemgr.add(host, "", "test", "eviction", false, false, false, + expiry, {}); + + if (i == begin) + beginTime = get_creationTime(i); + } + + let endTime = get_creationTime(end - 1); + do_check_true(begin == end - 1 || endTime > beginTime); + if (endTime - beginTime > gPurgeAge * 1000000) { + // Setting cookies took an amount of time very close to the purge threshold. + // Retry the test with a larger threshold. + return false; + } + + return true; +} + +function get_creationTime(i) +{ + let host = "eviction." + i + ".tests"; + let enumerator = Services.cookiemgr.getCookiesFromHost(host, {}); + do_check_true(enumerator.hasMoreElements()); + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + return cookie.creationTime; +} + +// Test that 'aNumberToExpect' cookies remain after purging is complete, and +// that the cookies that remain consist of the set expected given the number of +// of older and newer cookies -- eviction should occur by order of lastAccessed +// time, if both the limit on total cookies (maxNumber + 10%) and the purge age +// + 10% are exceeded. +function check_remaining_cookies(aNumberTotal, aNumberOld, aNumberToExpect) { + var enumerator = Services.cookiemgr.enumerator; + + let i = 0; + while (enumerator.hasMoreElements()) { + var cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + ++i; + + if (aNumberTotal != aNumberToExpect) { + // make sure the cookie is one of the batch we expect was purged. + var hostNumber = new Number(cookie.rawHost.split(".")[1]); + if (hostNumber < (aNumberOld - aNumberToExpect)) break; + } + } + + return i == aNumberToExpect; +} diff --git a/extensions/cookie/test/unit/test_permmanager_cleardata.js b/extensions/cookie/test/unit/test_permmanager_cleardata.js new file mode 100644 index 000000000..faa2579f5 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_cleardata.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var pm; + +// Create a principal based on the { origin, originAttributes }. +function createPrincipal(aOrigin, aOriginAttributes) +{ + return Services.scriptSecurityManager.createCodebasePrincipal(NetUtil.newURI(aOrigin), aOriginAttributes); +} + +// Return the data required by 'clear-origin-attributes-data' notification. +function getData(aPattern) +{ + return JSON.stringify(aPattern); +} + +// Use aEntries to create principals, add permissions to them and check that they have them. +// Then, it is notifying 'clear-origin-attributes-data' with the given aData and check if the permissions +// of principals[i] matches the permission in aResults[i]. +function test(aEntries, aData, aResults) +{ + let principals = []; + + for (entry of aEntries) { + principals.push(createPrincipal(entry.origin, entry.originAttributes)); + } + + for (principal of principals) { + do_check_eq(pm.testPermissionFromPrincipal(principal, "test/clear-origin"), pm.UNKNOWN_ACTION); + pm.addFromPrincipal(principal, "test/clear-origin", pm.ALLOW_ACTION, pm.EXPIRE_NEVER, 0); + do_check_eq(pm.testPermissionFromPrincipal(principal, "test/clear-origin"), pm.ALLOW_ACTION); + } + + Services.obs.notifyObservers(null, 'clear-origin-attributes-data', aData); + + var length = aEntries.length; + for (let i=0; i { + let got = findCapabilityViaDB(origin, type); + if (got == expected) { + // the do_check_eq() below will succeed - which is what we want. + do_check_eq(got, expected, "The database has the expected value"); + deferred.resolve(); + return; + } + // value isn't correct - see if we've retried enough + if (count++ == max) { + // the do_check_eq() below will fail - which is what we want. + do_check_eq(got, expected, "The database wasn't updated with the expected value"); + deferred.resolve(); + return; + } + // we can retry... + do_timeout(100, do_check); + } + do_check(); + return deferred.promise; +} + +// use the DB to find the requested permission. Returns the permission +// value (ie, the "capability" in nsIPermission parlance) or null if it can't +// be found. +function findCapabilityViaDB(origin = TEST_ORIGIN, type = TEST_PERMISSION) { + let principal = Services.scriptSecurityManager.createCodebasePrincipal(origin, {}); + let originStr = principal.origin; + + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); + file.append("permissions.sqlite"); + + let storage = Cc["@mozilla.org/storage/service;1"] + .getService(Ci.mozIStorageService); + + let connection = storage.openDatabase(file); + + let query = connection.createStatement( + "SELECT permission FROM moz_perms WHERE origin = :origin AND type = :type"); + query.bindByName("origin", originStr); + query.bindByName("type", type); + + if (!query.executeStep()) { + // no row + return null; + } + let result = query.getInt32(0); + if (query.executeStep()) { + // this is bad - we never expect more than 1 row here. + do_throw("More than 1 row found!") + } + return result; +} diff --git a/extensions/cookie/test/unit/test_permmanager_expiration.js b/extensions/cookie/test/unit/test_permmanager_expiration.js new file mode 100644 index 000000000..7ab8e88ae --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_expiration.js @@ -0,0 +1,82 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that permissions with specific expiry times behave as expected. + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function continue_test() +{ + do_run_generator(test_generator); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + let pm = Services.perms; + let permURI = NetUtil.newURI("http://example.com"); + let principal = Services.scriptSecurityManager.createCodebasePrincipal(permURI, {}); + + let now = Number(Date.now()); + + // add a permission with *now* expiration + pm.addFromPrincipal(principal, "test/expiration-perm-exp", 1, pm.EXPIRE_TIME, now); + pm.addFromPrincipal(principal, "test/expiration-session-exp", 1, pm.EXPIRE_SESSION, now); + + // add a permission with future expiration (100 milliseconds) + pm.addFromPrincipal(principal, "test/expiration-perm-exp2", 1, pm.EXPIRE_TIME, now + 100); + pm.addFromPrincipal(principal, "test/expiration-session-exp2", 1, pm.EXPIRE_SESSION, now + 100); + + // add a permission with future expiration (1000 seconds) + pm.addFromPrincipal(principal, "test/expiration-perm-exp3", 1, pm.EXPIRE_TIME, now + 1e6); + pm.addFromPrincipal(principal, "test/expiration-session-exp3", 1, pm.EXPIRE_SESSION, now + 1e6); + + // add a permission without expiration + pm.addFromPrincipal(principal, "test/expiration-perm-nexp", 1, pm.EXPIRE_NEVER, 0); + + // add a permission for renewal + pm.addFromPrincipal(principal, "test/expiration-perm-renewable", 1, pm.EXPIRE_TIME, now + 100); + pm.addFromPrincipal(principal, "test/expiration-session-renewable", 1, pm.EXPIRE_SESSION, now + 100); + + // And immediately renew them with longer timeouts + pm.updateExpireTime(principal, "test/expiration-perm-renewable", true, now + 100, now + 1e6); + pm.updateExpireTime(principal, "test/expiration-session-renewable", true, now + 1e6, now + 100); + + // check that the second two haven't expired yet + do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp3")); + do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp3")); + do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-nexp")); + do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-renewable")); + do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-session-renewable")); + + // ... and the first one has + do_timeout(10, continue_test); + yield; + do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp")); + do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp")); + + // ... and that the short-term one will + do_timeout(200, continue_test); + yield; + do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp2")); + do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp2")); + + // Check that .getPermission returns a matching result + do_check_null(pm.getPermissionObject(principal, "test/expiration-perm-exp", false)); + do_check_null(pm.getPermissionObject(principal, "test/expiration-session-exp", false)); + do_check_null(pm.getPermissionObject(principal, "test/expiration-perm-exp2", false)); + do_check_null(pm.getPermissionObject(principal, "test/expiration-session-exp2", false)); + + // Check that the renewable permissions actually got renewed + do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-renewable")); + do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-session-renewable")); + + do_finish_generator_test(test_generator); +} + diff --git a/extensions/cookie/test/unit/test_permmanager_getAllForURI.js b/extensions/cookie/test/unit/test_permmanager_getAllForURI.js new file mode 100644 index 000000000..7fec41826 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_getAllForURI.js @@ -0,0 +1,78 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function check_enumerator(uri, permissions) { + let pm = Cc["@mozilla.org/permissionmanager;1"] + .getService(Ci.nsIPermissionManager); + + let enumerator = pm.getAllForURI(uri); + for ([type, capability] of permissions) { + let perm = enumerator.getNext(); + do_check_true(perm != null); + do_check_true(perm.principal.URI.equals(uri)); + do_check_eq(perm.type, type); + do_check_eq(perm.capability, capability); + do_check_eq(perm.expireType, pm.EXPIRE_NEVER); + } + do_check_false(enumerator.hasMoreElements()); +} + +function run_test() { + let pm = Cc["@mozilla.org/permissionmanager;1"] + .getService(Ci.nsIPermissionManager); + + let uri = NetUtil.newURI("http://example.com"); + let sub = NetUtil.newURI("http://sub.example.com"); + + check_enumerator(uri, [ ]); + + pm.add(uri, "test/getallforuri", pm.ALLOW_ACTION); + check_enumerator(uri, [ + [ "test/getallforuri", pm.ALLOW_ACTION ] + ]); + + // check that uris are matched exactly + check_enumerator(sub, [ ]); + + pm.add(sub, "test/getallforuri", pm.PROMPT_ACTION); + pm.add(sub, "test/getallforuri2", pm.DENY_ACTION); + + check_enumerator(sub, [ + [ "test/getallforuri", pm.PROMPT_ACTION ], + [ "test/getallforuri2", pm.DENY_ACTION ] + ]); + + // check that the original uri list has not changed + check_enumerator(uri, [ + [ "test/getallforuri", pm.ALLOW_ACTION ] + ]); + + // check that UNKNOWN_ACTION permissions are ignored + pm.add(uri, "test/getallforuri2", pm.UNKNOWN_ACTION); + pm.add(uri, "test/getallforuri3", pm.DENY_ACTION); + + check_enumerator(uri, [ + [ "test/getallforuri", pm.ALLOW_ACTION ], + [ "test/getallforuri3", pm.DENY_ACTION ] + ]); + + // check that permission updates are reflected + pm.add(uri, "test/getallforuri", pm.PROMPT_ACTION); + + check_enumerator(uri, [ + [ "test/getallforuri", pm.PROMPT_ACTION ], + [ "test/getallforuri3", pm.DENY_ACTION ] + ]); + + // check that permission removals are reflected + pm.remove(uri, "test/getallforuri"); + + check_enumerator(uri, [ + [ "test/getallforuri3", pm.DENY_ACTION ] + ]); + + pm.removeAll(); + check_enumerator(uri, [ ]); + check_enumerator(sub, [ ]); +} + diff --git a/extensions/cookie/test/unit/test_permmanager_getPermissionObject.js b/extensions/cookie/test/unit/test_permmanager_getPermissionObject.js new file mode 100644 index 000000000..d01b51923 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_getPermissionObject.js @@ -0,0 +1,95 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function getPrincipalFromURI(aURI) { + let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + let uri = NetUtil.newURI(aURI); + return ssm.createCodebasePrincipal(uri, {}); +} + +function getSystemPrincipal() { + return Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager) + .getSystemPrincipal(); +} + +function run_test() { + var pm = Cc["@mozilla.org/permissionmanager;1"]. + getService(Ci.nsIPermissionManager); + + do_check_null(pm.getPermissionObject(getSystemPrincipal(), "test/pobject", false)); + + let principal = getPrincipalFromURI("http://example.com"); + let subPrincipal = getPrincipalFromURI("http://sub.example.com"); + let subSubPrincipal = getPrincipalFromURI("http://sub.sub.example.com"); + + do_check_null(pm.getPermissionObject(principal, "test/pobject", false)); + do_check_null(pm.getPermissionObject(principal, "test/pobject", true)); + + pm.addFromPrincipal(principal, "test/pobject", pm.ALLOW_ACTION); + var rootPerm = pm.getPermissionObject(principal, "test/pobject", false); + do_check_true(rootPerm != null); + do_check_eq(rootPerm.principal.origin, "http://example.com"); + do_check_eq(rootPerm.type, "test/pobject"); + do_check_eq(rootPerm.capability, pm.ALLOW_ACTION); + do_check_eq(rootPerm.expireType, pm.EXPIRE_NEVER); + + var rootPerm2 = pm.getPermissionObject(principal, "test/pobject", true); + do_check_true(rootPerm != null); + do_check_eq(rootPerm.principal.origin, "http://example.com"); + + var subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true); + do_check_null(subPerm); + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false); + do_check_true(subPerm != null); + do_check_eq(subPerm.principal.origin, "http://example.com"); + do_check_eq(subPerm.type, "test/pobject"); + do_check_eq(subPerm.capability, pm.ALLOW_ACTION); + + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true); + do_check_null(subPerm); + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false); + do_check_true(subPerm != null); + do_check_eq(subPerm.principal.origin, "http://example.com"); + + pm.addFromPrincipal(principal, "test/pobject", pm.DENY_ACTION, pm.EXPIRE_SESSION); + + // make sure permission objects are not dynamic + do_check_eq(rootPerm.capability, pm.ALLOW_ACTION); + + // but do update on change + rootPerm = pm.getPermissionObject(principal, "test/pobject", true); + do_check_eq(rootPerm.capability, pm.DENY_ACTION); + do_check_eq(rootPerm.expireType, pm.EXPIRE_SESSION); + + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false); + do_check_eq(subPerm.principal.origin, "http://example.com"); + do_check_eq(subPerm.capability, pm.DENY_ACTION); + do_check_eq(subPerm.expireType, pm.EXPIRE_SESSION); + + pm.addFromPrincipal(subPrincipal, "test/pobject", pm.PROMPT_ACTION); + rootPerm = pm.getPermissionObject(principal, "test/pobject", true); + do_check_eq(rootPerm.principal.origin, "http://example.com"); + do_check_eq(rootPerm.capability, pm.DENY_ACTION); + + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true); + do_check_eq(subPerm.principal.origin, "http://sub.example.com"); + do_check_eq(subPerm.capability, pm.PROMPT_ACTION); + + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false); + do_check_eq(subPerm.principal.origin, "http://sub.example.com"); + do_check_eq(subPerm.capability, pm.PROMPT_ACTION); + + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true); + do_check_null(subPerm); + + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false); + do_check_eq(subPerm.principal.origin, "http://sub.example.com"); + do_check_eq(subPerm.capability, pm.PROMPT_ACTION); + + pm.removeFromPrincipal(principal, "test/pobject"); + + rootPerm = pm.getPermissionObject(principal, "test/pobject", true); + do_check_null(rootPerm); +} diff --git a/extensions/cookie/test/unit/test_permmanager_idn.js b/extensions/cookie/test/unit/test_permmanager_idn.js new file mode 100644 index 000000000..72fc06bba --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_idn.js @@ -0,0 +1,49 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function getPrincipalFromDomain(aDomain) { + let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + let uri = NetUtil.newURI("http://" + aDomain); + return ssm.createCodebasePrincipal(uri, {}); +} + +function run_test() { + let profile = do_get_profile(); + let pm = Services.perms; + let perm = 'test-idn'; + + // We create three principal linked to IDN. + // One with just a domain, one with a subdomain and one with the TLD + // containing a UTF-8 character. + let mainDomainPrincipal = getPrincipalFromDomain("fôû.com"); + let subDomainPrincipal = getPrincipalFromDomain("fôô.bàr.com"); + let tldPrincipal = getPrincipalFromDomain("fôû.bàr.côm"); + + // We add those to the permission manager. + pm.addFromPrincipal(mainDomainPrincipal, perm, pm.ALLOW_ACTION, 0, 0); + pm.addFromPrincipal(subDomainPrincipal, perm, pm.ALLOW_ACTION, 0, 0); + pm.addFromPrincipal(tldPrincipal, perm, pm.ALLOW_ACTION, 0, 0); + + // They should obviously be there now.. + do_check_eq(pm.testPermissionFromPrincipal(mainDomainPrincipal, perm), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(subDomainPrincipal, perm), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(tldPrincipal, perm), pm.ALLOW_ACTION); + + // We do the same thing with the puny-encoded versions of the IDN. + let punyMainDomainPrincipal = getPrincipalFromDomain('xn--f-xgav.com'); + let punySubDomainPrincipal = getPrincipalFromDomain('xn--f-xgaa.xn--br-jia.com'); + let punyTldPrincipal = getPrincipalFromDomain('xn--f-xgav.xn--br-jia.xn--cm-8ja'); + + // Those principals should have the permission granted too. + do_check_eq(pm.testPermissionFromPrincipal(punyMainDomainPrincipal, perm), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(punySubDomainPrincipal, perm), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(punyTldPrincipal, perm), pm.ALLOW_ACTION); + + // However, those two principals shouldn't be allowed because they are like + // the IDN but without the UT8-8 characters. + let witnessPrincipal = getPrincipalFromDomain("foo.com"); + do_check_eq(pm.testPermissionFromPrincipal(witnessPrincipal, perm), pm.UNKNOWN_ACTION); + witnessPrincipal = getPrincipalFromDomain("foo.bar.com"); + do_check_eq(pm.testPermissionFromPrincipal(witnessPrincipal, perm), pm.UNKNOWN_ACTION); +} diff --git a/extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js b/extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js new file mode 100644 index 000000000..8d36a9667 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js @@ -0,0 +1,142 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var DEBUG_TEST = false; + +function run_test() { + // Setup a profile directory. + var dir = do_get_profile(); + // Get the db file. + var file = dir.clone(); + file.append("permissions.sqlite"); + + var storage = Cc["@mozilla.org/storage/service;1"] + .getService(Ci.mozIStorageService); + + // Create database. + var connection = storage.openDatabase(file); + // The file should now exist. + do_check_true(file.exists()); + + connection.schemaVersion = 3; + connection.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")"); + + // Now we can inject garbadge in the database. + var garbadge = [ + // Regular entry. + { host: '42', type: '0', permission: 1, expireType: 0, expireTime: 0, + appId: 0, isInBrowserElement: 0 }, + + // Special values in host (some being invalid). + { host: 'scheme:file', type: '1', permission: 0, expireType: 0, + expireTime: 0, appId: 0, isInBrowserElement: 0 }, + { host: '192.168.0.1', type: '2', permission: 0, expireType: 0, + expireTime: 0, appId: 0, isInBrowserElement: 0 }, + { host: '2001:0db8:0000:0000:0000:ff00:0042:8329', type: '3', permission: 0, + expireType: 0, expireTime: 0, appId: 0, isInBrowserElement: 0 }, + { host: '::1', type: '4', permission: 0, expireType: 0, expireTime: 0, + appId: 0, isInBrowserElement: 0 }, + + // Permission is UNKNOWN_ACTION. + { host: '42', type: '5', permission: Ci.nsIPermissionManager.UNKNOWN_ACTION, + expireType: 0, expireTime: 0, appId: 0, isInBrowserElement: 0 }, + + // Permission is out of range. + { host: '42', type: '6', permission: 100, expireType: 0, expireTime: 0, + appId: 0, isInBrowserElement: 0 }, + { host: '42', type: '7', permission: -100, expireType: 0, expireTime: 0, + appId: 0, isInBrowserElement: 0 }, + + // ExpireType is out of range. + { host: '42', type: '8', permission: 1, expireType: -100, expireTime: 0, + appId: 0, isInBrowserElement: 0 }, + { host: '42', type: '9', permission: 1, expireType: 100, expireTime: 0, + appId: 0, isInBrowserElement: 0 }, + + // ExpireTime is at 0 with ExpireType = Time. + { host: '42', type: '10', permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_TIME, expireTime: 0, appId: 0, + isInBrowserElement: 0 }, + + // ExpireTime has a value with ExpireType != Time + { host: '42', type: '11', permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, expireTime: 1000, + appId: 0, isInBrowserElement: 0 }, + { host: '42', type: '12', permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_NEVER, expireTime: 1000, + appId: 0, isInBrowserElement: 0 }, + + // ExpireTime is negative. + { host: '42', type: '13', permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_TIME, expireTime: -1, + appId: 0, isInBrowserElement: 0 }, + + // AppId is negative. + { host: '42', type: '14', permission: 1, expireType: 0, expireTime: 0, + appId: -1, isInBrowserElement: 0 }, + + // IsInBrowserElement is negative or higher than 1. + { host: '42', type: '15', permission: 1, expireType: 0, expireTime: 0, + appId: 0, isInBrowserElement: -1 }, + { host: '42', type: '16', permission: 1, expireType: 0, expireTime: 0, + appId: 0, isInBrowserElement: 10 }, + + // This insertion should be the last one. It is used to make sure we always + // load it regardless of the previous entries validities. + { host: 'example.org', type: 'test-load-invalid-entries', + permission: Ci.nsIPermissionManager.ALLOW_ACTION, expireType: 0, + expireTime: 0, appId: 0, isInBrowserElement: 0 }, + ]; + + for (var i=0; i 0, "we found at least 1 record that was migrated"); + + // This permission should always be there. + let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + let uri = NetUtil.newURI("http://example.org"); + let principal = ssm.createCodebasePrincipal(uri, {}); + do_check_eq(pm.testPermissionFromPrincipal(principal, 'test-load-invalid-entries'), Ci.nsIPermissionManager.ALLOW_ACTION); +} diff --git a/extensions/cookie/test/unit/test_permmanager_local_files.js b/extensions/cookie/test/unit/test_permmanager_local_files.js new file mode 100644 index 000000000..b9c803f5c --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_local_files.js @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that permissions work for file:// URIs (aka local files). + +function getPrincipalFromURIString(uriStr) +{ + let uri = NetUtil.newURI(uriStr); + return Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); +} + +function run_test() { + let pm = Services.perms; + + // If we add a permission to a file:// URI, the test should return true. + let principal = getPrincipalFromURIString("file:///foo/bar"); + pm.addFromPrincipal(principal, "test/local-files", pm.ALLOW_ACTION, 0, 0); + do_check_eq(pm.testPermissionFromPrincipal(principal, "test/local-files"), pm.ALLOW_ACTION); + + // Another file:// URI should have the same permission. + let witnessPrincipal = getPrincipalFromURIString("file:///bar/foo"); + do_check_eq(pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), pm.UNKNOWN_ACTION); + + // Giving "file:///" a permission shouldn't give it to all file:// URIs. + let rootPrincipal = getPrincipalFromURIString("file:///"); + pm.addFromPrincipal(rootPrincipal, "test/local-files", pm.ALLOW_ACTION, 0, 0); + do_check_eq(pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), pm.UNKNOWN_ACTION); + + // Giving "file://" a permission shouldn't give it to all file:// URIs. + let schemeRootPrincipal = getPrincipalFromURIString("file://"); + pm.addFromPrincipal(schemeRootPrincipal, "test/local-files", pm.ALLOW_ACTION, 0, 0); + do_check_eq(pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), pm.UNKNOWN_ACTION); + + // Giving 'node' a permission shouldn't give it to its 'children'. + let fileInDirPrincipal = getPrincipalFromURIString("file:///foo/bar/foobar.txt"); + do_check_eq(pm.testPermissionFromPrincipal(fileInDirPrincipal, "test/local-files"), pm.UNKNOWN_ACTION); + + // Revert "file:///foo/bar" permission and check that it has been correctly taken into account. + pm.removeFromPrincipal(principal, "test/local-files"); + do_check_eq(pm.testPermissionFromPrincipal(principal, "test/local-files"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(fileInDirPrincipal, "test/local-files"), pm.UNKNOWN_ACTION); +} diff --git a/extensions/cookie/test/unit/test_permmanager_matches.js b/extensions/cookie/test/unit/test_permmanager_matches.js new file mode 100644 index 000000000..c15288890 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_matches.js @@ -0,0 +1,183 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function matches_always(perm, principals) { + principals.forEach((principal) => { + do_check_true(perm.matches(principal, true), "perm: " + perm.principal.origin + ", princ: " + principal.origin); + do_check_true(perm.matches(principal, false), "perm: " + perm.principal.origin + ", princ: " + principal.origin); + }); +} + +function matches_weak(perm, principals) { + principals.forEach((principal) => { + do_check_false(perm.matches(principal, true), "perm: " + perm.principal.origin + ", princ: " + principal.origin); + do_check_true(perm.matches(principal, false), "perm: " + perm.principal.origin + ", princ: " + principal.origin); + }); +} + +function matches_never(perm, principals) { + principals.forEach((principal) => { + do_check_false(perm.matches(principal, true), "perm: " + perm.principal.origin + ", princ: " + principal.origin); + do_check_false(perm.matches(principal, false), "perm: " + perm.principal.origin + ", princ: " + principal.origin); + }); +} + +function run_test() { + // initialize the permission manager service + let pm = Cc["@mozilla.org/permissionmanager;1"]. + getService(Ci.nsIPermissionManager); + + let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + + // Add some permissions + let uri0 = NetUtil.newURI("http://google.com/search?q=foo#hashtag", null, null); + let uri1 = NetUtil.newURI("http://hangouts.google.com/subdir", null, null); + let uri2 = NetUtil.newURI("http://google.org/", null, null); + let uri3 = NetUtil.newURI("https://google.com/some/random/subdirectory", null, null); + let uri4 = NetUtil.newURI("https://hangouts.google.com/#!/hangout", null, null); + let uri5 = NetUtil.newURI("http://google.com:8096/", null, null); + + let uri0_n_n = secMan.createCodebasePrincipal(uri0, {}); + let uri1_n_n = secMan.createCodebasePrincipal(uri1, {}); + let uri2_n_n = secMan.createCodebasePrincipal(uri2, {}); + let uri3_n_n = secMan.createCodebasePrincipal(uri3, {}); + let uri4_n_n = secMan.createCodebasePrincipal(uri4, {}); + let uri5_n_n = secMan.createCodebasePrincipal(uri5, {}); + + let attrs = {appId: 1000}; + let uri0_1000_n = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_1000_n = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_1000_n = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_1000_n = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_1000_n = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_1000_n = secMan.createCodebasePrincipal(uri5, attrs); + + attrs = {appId: 1000, inIsolatedMozBrowser: true}; + let uri0_1000_y = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_1000_y = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_1000_y = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_1000_y = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_1000_y = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_1000_y = secMan.createCodebasePrincipal(uri5, attrs); + + attrs = {appId: 2000}; + let uri0_2000_n = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_2000_n = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_2000_n = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_2000_n = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_2000_n = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_2000_n = secMan.createCodebasePrincipal(uri5, attrs); + + attrs = {appId: 2000, inIsolatedMozBrowser: true}; + let uri0_2000_y = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_2000_y = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_2000_y = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_2000_y = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_2000_y = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_2000_y = secMan.createCodebasePrincipal(uri5, attrs); + + attrs = {userContextId: 1}; + let uri0_1 = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_1 = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_1 = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_1 = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_1 = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_1 = secMan.createCodebasePrincipal(uri5, attrs); + + attrs = {firstPartyDomain: "cnn.com"}; + let uri0_cnn = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_cnn = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_cnn = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_cnn = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_cnn = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_cnn = secMan.createCodebasePrincipal(uri5, attrs); + + pm.addFromPrincipal(uri0_n_n, "test/matches", pm.ALLOW_ACTION); + let perm_n_n = pm.getPermissionObject(uri0_n_n, "test/matches", true); + pm.addFromPrincipal(uri0_1000_n, "test/matches", pm.ALLOW_ACTION); + let perm_1000_n = pm.getPermissionObject(uri0_1000_n, "test/matches", true); + pm.addFromPrincipal(uri0_1000_y, "test/matches", pm.ALLOW_ACTION); + let perm_1000_y = pm.getPermissionObject(uri0_1000_y, "test/matches", true); + pm.addFromPrincipal(uri0_2000_n, "test/matches", pm.ALLOW_ACTION); + let perm_2000_n = pm.getPermissionObject(uri0_2000_n, "test/matches", true); + pm.addFromPrincipal(uri0_2000_y, "test/matches", pm.ALLOW_ACTION); + let perm_2000_y = pm.getPermissionObject(uri0_2000_y, "test/matches", true); + pm.addFromPrincipal(uri0_1, "test/matches", pm.ALLOW_ACTION); + let perm_1 = pm.getPermissionObject(uri0_n_n, "test/matches", true); + pm.addFromPrincipal(uri0_cnn, "test/matches", pm.ALLOW_ACTION); + let perm_cnn = pm.getPermissionObject(uri0_n_n, "test/matches", true); + + matches_always(perm_n_n, [uri0_n_n, uri0_1, uri0_cnn]); + matches_weak(perm_n_n, [uri1_n_n, uri1_1, uri1_cnn]); + matches_never(perm_n_n, [uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri2_1, uri3_1, uri4_1, uri5_1, + uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_1000_n, [uri0_1000_n]); + matches_weak(perm_1000_n, [uri1_1000_n]); + matches_never(perm_1000_n, [uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_1000_y, [uri0_1000_y]); + matches_weak(perm_1000_y, [uri1_1000_y]); + matches_never(perm_1000_y, [uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_2000_n, [uri0_2000_n]); + matches_weak(perm_2000_n, [uri1_2000_n]); + matches_never(perm_2000_n, [uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_2000_y, [uri0_2000_y]); + matches_weak(perm_2000_y, [uri1_2000_y]); + matches_never(perm_2000_y, [uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_1, [uri0_n_n, uri0_1, uri0_cnn]); + matches_weak(perm_1, [uri1_n_n, uri1_1, uri1_cnn]); + matches_never(perm_1, [uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri2_1, uri3_1, uri4_1, uri5_1, + uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_cnn, [uri0_n_n, uri0_1, uri0_cnn]); + matches_weak(perm_cnn, [uri1_n_n, uri1_1, uri1_cnn]); + matches_never(perm_cnn, [uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri2_1, uri3_1, uri4_1, uri5_1, + uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + // Clean up! + pm.removeAll(); +} diff --git a/extensions/cookie/test/unit/test_permmanager_matchesuri.js b/extensions/cookie/test/unit/test_permmanager_matchesuri.js new file mode 100644 index 000000000..88578166c --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_matchesuri.js @@ -0,0 +1,150 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function matches_always(perm, uris) { + uris.forEach((uri) => { + do_check_true(perm.matchesURI(uri, true), "perm: " + perm.principal.origin + ", URI: " + uri.spec); + do_check_true(perm.matchesURI(uri, false), "perm: " + perm.principal.origin + ", URI: " + uri.spec); + }); +} + +function matches_weak(perm, uris) { + uris.forEach((uri) => { + do_check_false(perm.matchesURI(uri, true), "perm: " + perm.principal.origin + ", URI: " + uri.spec); + do_check_true(perm.matchesURI(uri, false), "perm: " + perm.principal.origin + ", URI: " + uri.spec); + }); +} + +function matches_never(perm, uris) { + uris.forEach((uri) => { + do_check_false(perm.matchesURI(uri, true), "perm: " + perm.principal.origin + ", URI: " + uri.spec); + do_check_false(perm.matchesURI(uri, false), "perm: " + perm.principal.origin + ", URI: " + uri.spec); + }); +} + +function mk_permission(uri, isAppPermission = false) { + let pm = Cc["@mozilla.org/permissionmanager;1"]. + getService(Ci.nsIPermissionManager); + + let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + + // Get the permission from the principal! + let attrs = {appId: 1000}; + let principal = + secMan.createCodebasePrincipal(uri, isAppPermission ? attrs : {}); + + pm.addFromPrincipal(principal, "test/matchesuri", pm.ALLOW_ACTION); + let permission = pm.getPermissionObject(principal, "test/matchesuri", true); + + return permission; +} + +function run_test() { + // initialize the permission manager service + let pm = Cc["@mozilla.org/permissionmanager;1"]. + getService(Ci.nsIPermissionManager); + + let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + + let fileprefix = "file:///"; + if (Services.appinfo.OS == "WINNT") { + // Windows rejects files if they don't have a drive. See Bug 1180870 + fileprefix += "c:/"; + } + + // Add some permissions + let uri0 = NetUtil.newURI("http://google.com:9091/just/a/path", null, null); + let uri1 = NetUtil.newURI("http://hangouts.google.com:9091/some/path", null, null); + let uri2 = NetUtil.newURI("http://google.com:9091/", null, null); + let uri3 = NetUtil.newURI("http://google.org:9091/", null, null); + let uri4 = NetUtil.newURI("http://deeper.hangouts.google.com:9091/", null, null); + let uri5 = NetUtil.newURI("https://google.com/just/a/path", null, null); + let uri6 = NetUtil.newURI("https://hangouts.google.com", null, null); + let uri7 = NetUtil.newURI("https://google.com/", null, null); + + let fileuri1 = NetUtil.newURI(fileprefix + "a/file/path", null, null); + let fileuri2 = NetUtil.newURI(fileprefix + "a/file/path/deeper", null, null); + let fileuri3 = NetUtil.newURI(fileprefix + "a/file/otherpath", null, null); + + { + let perm = mk_permission(uri0); + matches_always(perm, [uri0, uri2]); + matches_weak(perm, [uri1, uri4]); + matches_never(perm, [uri3, uri5, uri6, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri1); + matches_always(perm, [uri1]); + matches_weak(perm, [uri4]); + matches_never(perm, [uri0, uri2, uri3, uri5, uri6, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri2); + matches_always(perm, [uri0, uri2]); + matches_weak(perm, [uri1, uri4]); + matches_never(perm, [uri3, uri5, uri6, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri3); + matches_always(perm, [uri3]); + matches_weak(perm, []); + matches_never(perm, [uri1, uri2, uri4, uri5, uri6, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri4); + matches_always(perm, [uri4]); + matches_weak(perm, []); + matches_never(perm, [uri1, uri2, uri3, uri5, uri6, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri5); + matches_always(perm, [uri5, uri7]); + matches_weak(perm, [uri6]); + matches_never(perm, [uri0, uri1, uri2, uri3, uri4, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri6); + matches_always(perm, [uri6]); + matches_weak(perm, []); + matches_never(perm, [uri0, uri1, uri2, uri3, uri4, uri5, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri7); + matches_always(perm, [uri5, uri7]); + matches_weak(perm, [uri6]); + matches_never(perm, [uri0, uri1, uri2, uri3, uri4, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(fileuri1); + matches_always(perm, [fileuri1]); + matches_weak(perm, []); + matches_never(perm, [uri0, uri1, uri2, uri3, uri4, uri5, uri6, uri7, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(fileuri2); + matches_always(perm, [fileuri2]); + matches_weak(perm, []); + matches_never(perm, [uri0, uri1, uri2, uri3, uri4, uri5, uri6, uri7, fileuri1, fileuri3]); + } + + { + let perm = mk_permission(fileuri3); + matches_always(perm, [fileuri3]); + matches_weak(perm, []); + matches_never(perm, [uri0, uri1, uri2, uri3, uri4, uri5, uri6, uri7, fileuri1, fileuri2]); + } + + // Clean up! + pm.removeAll(); +} diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_4-7.js b/extensions/cookie/test/unit/test_permmanager_migrate_4-7.js new file mode 100644 index 000000000..4749422da --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_4-7.js @@ -0,0 +1,207 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm"); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 4; + + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")"); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")"); + + let id = 0; + + function insertHost(host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + stmtInsert.execute(); + + return { + id: thisId, + host: host, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime, + appId: appId, + isInBrowserElement: isInBrowserElement + }; + } + + // Add some rows to the database + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", "B", 1, 0, 0, 0, 0, false), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // The http:// entries under foo.com won't be inserted, as there are history entries for foo.com, + // and http://foo.com or a subdomain are never visited. + // ["http://foo.com", "A", 1, 0, 0], + // ["http://foo.com^appId=1000", "A", 1, 0, 0], + // ["http://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + // + // Because we search for port/scheme combinations under eTLD+1, we should not have http:// entries + // for subdomains of foo.com either + // ["http://sub.foo.com", "B", 1, 0, 0], + // ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^appId=1000", "A", 1, 0, 0], + ["https://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^appId=1000", "B", 1, 0, 0], + ["https://bar.ca^appId=1000", "B", 1, 0, 0], + ["http://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Because we put ftp://some.subdomain.of.foo.com:8000/some/subdirectory in the history, we should + // also have these entries + ["ftp://foo.com:8000", "A", 1, 0, 0], + ["ftp://foo.com:8000", "C", 1, 0, 0], + ["ftp://foo.com:8000^appId=1000", "A", 1, 0, 0], + ["ftp://foo.com:8000^appId=2000&inBrowser=1", "A", 1, 0, 0], + + // In addition, because we search for port/scheme combinations under eTLD+1, we should have the + // following entries + ["ftp://sub.foo.com:8000", "B", 1, 0, 0], + ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], + ]; + + let found = expected.map((it) => 0); + + // Add some places to the places database + yield PlacesTestUtils.addVisits(Services.io.newURI("https://foo.com/some/other/subdirectory", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory", null, null)); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_false(db.tableExists("moz_hosts_is_backup")); + do_check_false(db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), 0); + + db.close(); + } +}); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js b/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js new file mode 100644 index 000000000..38646660a --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js @@ -0,0 +1,226 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +/* + * Prevent the nsINavHistoryService from being avaliable for the migration + */ + +var CONTRACT_ID = "@mozilla.org/browser/nav-history-service;1"; +var factory = { + createInstance: function() { + throw new Error("There is no history service"); + }, + lockFactory: function() { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]) +}; + +var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID(); + +var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); +var oldClassID = registrar.contractIDToCID(CONTRACT_ID); +var oldFactory = Components.manager.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory); +registrar.unregisterFactory(oldClassID, oldFactory); +registrar.registerFactory(newClassID, "", CONTRACT_ID, factory); + +function cleanupFactory() { + registrar.unregisterFactory(newClassID, factory); + registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory); +} + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +/* + * Done nsINavHistoryService code + */ + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + // Make sure that we can't resolve the nsINavHistoryService + try { + Cc['@mozilla.org/browser/nav-history-service;1'].getService(Ci.nsINavHistoryService); + do_check_true(false, "There shouldn't have been a nsINavHistoryService"); + } catch (e) { + do_check_true(true, "There wasn't a nsINavHistoryService"); + } + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 4; + + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")"); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")"); + + let id = 0; + + function insertHost(host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + stmtInsert.execute(); + + return { + id: thisId, + host: host, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime, + appId: appId, + isInBrowserElement: isInBrowserElement + }; + } + + // Add some rows to the database + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("263.123.555.676", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", "B", 1, 0, 0, 0, 0, false), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + ["http://foo.com", "A", 1, 0, 0], + ["http://foo.com", "C", 1, 0, 0], + ["http://foo.com^appId=1000", "A", 1, 0, 0], + ["http://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + ["http://sub.foo.com", "B", 1, 0, 0], + ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^appId=1000", "A", 1, 0, 0], + ["https://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^appId=1000", "B", 1, 0, 0], + ["https://bar.ca^appId=1000", "B", 1, 0, 0], + ["http://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://263.123.555.676", "A", 1, 0, 0], + ["https://263.123.555.676", "A", 1, 0, 0], + ]; + + let found = expected.map((it) => 0); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_false(db.tableExists("moz_hosts_is_backup")); + do_check_false(db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), 0); + + db.close(); + } + + cleanupFactory(); +}); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js b/extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js new file mode 100644 index 000000000..4d38d72e8 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js @@ -0,0 +1,284 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm"); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 5; + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")"); + + let stmt5Insert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")"); + + /* + * V4 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts_v4 (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")"); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts_v4 (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")"); + + let id = 0; + + function insertOrigin(origin, type, permission, expireType, expireTime, modificationTime) { + let thisId = id++; + + stmt5Insert.bindByName("id", thisId); + stmt5Insert.bindByName("origin", origin); + stmt5Insert.bindByName("type", type); + stmt5Insert.bindByName("permission", permission); + stmt5Insert.bindByName("expireType", expireType); + stmt5Insert.bindByName("expireTime", expireTime); + stmt5Insert.bindByName("modificationTime", modificationTime); + + stmt5Insert.execute(); + + return { + id: thisId, + origin: origin, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime + }; + } + + function insertHost(host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + stmtInsert.execute(); + + return { + id: thisId, + host: host, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime, + appId: appId, + isInBrowserElement: isInBrowserElement + }; + } + + let created5 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + ]; + + // Add some rows to the database + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", "B", 1, 0, 0, 0, 0, false), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // The http:// entries under foo.com won't be inserted, as there are history entries for foo.com, + // and http://foo.com or a subdomain are never visited. + // ["http://foo.com", "A", 1, 0, 0], + // ["http://foo.com^appId=1000", "A", 1, 0, 0], + // ["http://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + // + // Because we search for port/scheme combinations under eTLD+1, we should not have http:// entries + // for subdomains of foo.com either + // ["http://sub.foo.com", "B", 1, 0, 0], + // ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^appId=1000", "A", 1, 0, 0], + ["https://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^appId=1000", "B", 1, 0, 0], + ["https://bar.ca^appId=1000", "B", 1, 0, 0], + ["http://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Because we put ftp://some.subdomain.of.foo.com:8000/some/subdirectory in the history, we should + // also have these entries + ["ftp://foo.com:8000", "A", 1, 0, 0], + ["ftp://foo.com:8000", "C", 1, 0, 0], + ["ftp://foo.com:8000^appId=1000", "A", 1, 0, 0], + ["ftp://foo.com:8000^appId=2000&inBrowser=1", "A", 1, 0, 0], + + // In addition, because we search for port/scheme combinations under eTLD+1, we should have the + // following entries + ["ftp://sub.foo.com:8000", "B", 1, 0, 0], + ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], + ]; + + let found = expected.map((it) => 0); + + // Add some places to the places database + yield PlacesTestUtils.addVisits(Services.io.newURI("https://foo.com/some/other/subdirectory", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory", null, null)); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_false(db.tableExists("moz_hosts_is_backup")); + do_check_true(db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), 0); + + // Check that the moz_perms_v6 table contains the backup of the entry we created + let mozPermsV6Stmt = db.createStatement("SELECT " + + "origin, type, permission, expireType, expireTime, modificationTime " + + "FROM moz_perms_v6 WHERE id = :id"); + + // Check that the moz_hosts table still contains the correct values. + created5.forEach((it) => { + mozPermsV6Stmt.reset(); + mozPermsV6Stmt.bindByName("id", it.id); + mozPermsV6Stmt.executeStep(); + do_check_eq(mozPermsV6Stmt.getUTF8String(0), it.origin); + do_check_eq(mozPermsV6Stmt.getUTF8String(1), it.type); + do_check_eq(mozPermsV6Stmt.getInt64(2), it.permission); + do_check_eq(mozPermsV6Stmt.getInt64(3), it.expireType); + do_check_eq(mozPermsV6Stmt.getInt64(4), it.expireTime); + do_check_eq(mozPermsV6Stmt.getInt64(5), it.modificationTime); + }); + + // Check that there are the right number of values + let mozPermsV6Count = db.createStatement("SELECT count(*) FROM moz_perms_v6"); + mozPermsV6Count.executeStep(); + do_check_eq(mozPermsV6Count.getInt64(0), created5.length); + + db.close(); + } +}); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js b/extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js new file mode 100644 index 000000000..0e5820d2b --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js @@ -0,0 +1,168 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm"); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 5; + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")"); + + let stmt5Insert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")"); + + let id = 0; + + function insertOrigin(origin, type, permission, expireType, expireTime, modificationTime) { + let thisId = id++; + + stmt5Insert.bindByName("id", thisId); + stmt5Insert.bindByName("origin", origin); + stmt5Insert.bindByName("type", type); + stmt5Insert.bindByName("permission", permission); + stmt5Insert.bindByName("expireType", expireType); + stmt5Insert.bindByName("expireTime", expireTime); + stmt5Insert.bindByName("modificationTime", modificationTime); + + stmt5Insert.execute(); + + return { + id: thisId, + host: origin, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime + }; + } + + let created5 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + + insertOrigin("http://127.0.0.1", "B", 2, 0, 0, 0), + insertOrigin("http://localhost", "B", 2, 0, 0, 0), + ]; + + let created4 = []; // Didn't create any v4 entries, so the DB should be empty + + // CLose the db connection + stmt5Insert.finalize(); + db.close(); + stmt5Insert = null; + db = null; + + let expected = [ + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0], + + ["http://127.0.0.1", "B", 2, 0, 0, 0], + ["http://localhost", "B", 2, 0, 0, 0], + ]; + + let found = expected.map((it) => 0); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_false(db.tableExists("moz_hosts_is_backup")); + do_check_false(db.tableExists("moz_perms_v6")); + + let mozHostsStmt = db.createStatement("SELECT " + + "host, type, permission, expireType, expireTime, " + + "modificationTime, appId, isInBrowserElement " + + "FROM moz_hosts WHERE id = :id"); + + // Check that the moz_hosts table still contains the correct values. + created4.forEach((it) => { + mozHostsStmt.reset(); + mozHostsStmt.bindByName("id", it.id); + mozHostsStmt.executeStep(); + do_check_eq(mozHostsStmt.getUTF8String(0), it.host); + do_check_eq(mozHostsStmt.getUTF8String(1), it.type); + do_check_eq(mozHostsStmt.getInt64(2), it.permission); + do_check_eq(mozHostsStmt.getInt64(3), it.expireType); + do_check_eq(mozHostsStmt.getInt64(4), it.expireTime); + do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime); + do_check_eq(mozHostsStmt.getInt64(6), it.appId); + do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement); + }); + + // Check that there are the right number of values + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), created4.length); + + db.close(); + } +}); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js b/extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js new file mode 100644 index 000000000..aa634c7eb --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js @@ -0,0 +1,284 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm"); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 6; + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")"); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")"); + + /* + * V4 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")"); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")"); + + let id = 0; + + function insertOrigin(origin, type, permission, expireType, expireTime, modificationTime) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + stmt6Insert.execute(); + + return { + id: thisId, + origin: origin, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime + }; + } + + function insertHost(host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + stmtInsert.execute(); + + return { + id: thisId, + host: host, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime, + appId: appId, + isInBrowserElement: isInBrowserElement + }; + } + + let created6 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + ]; + + // Add some rows to the database + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", "B", 1, 0, 0, 0, 0, false), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // The http:// entries under foo.com won't be inserted, as there are history entries for foo.com, + // and http://foo.com or a subdomain are never visited. + // ["http://foo.com", "A", 1, 0, 0], + // ["http://foo.com^appId=1000", "A", 1, 0, 0], + // ["http://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + // + // Because we search for port/scheme combinations under eTLD+1, we should not have http:// entries + // for subdomains of foo.com either + // ["http://sub.foo.com", "B", 1, 0, 0], + // ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^appId=1000", "A", 1, 0, 0], + ["https://foo.com^appId=2000&inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^appId=1000", "B", 1, 0, 0], + ["https://bar.ca^appId=1000", "B", 1, 0, 0], + ["http://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Because we put ftp://some.subdomain.of.foo.com:8000/some/subdirectory in the history, we should + // also have these entries + ["ftp://foo.com:8000", "A", 1, 0, 0], + ["ftp://foo.com:8000", "C", 1, 0, 0], + ["ftp://foo.com:8000^appId=1000", "A", 1, 0, 0], + ["ftp://foo.com:8000^appId=2000&inBrowser=1", "A", 1, 0, 0], + + // In addition, because we search for port/scheme combinations under eTLD+1, we should have the + // following entries + ["ftp://sub.foo.com:8000", "B", 1, 0, 0], + ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], + ]; + + let found = expected.map((it) => 0); + + // Add some places to the places database + yield PlacesTestUtils.addVisits(Services.io.newURI("https://foo.com/some/other/subdirectory", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory", null, null)); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_false(db.tableExists("moz_hosts_is_backup")); + do_check_true(db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), 0); + + // Check that the moz_perms_v6 table contains the backup of the entry we created + let mozPermsV6Stmt = db.createStatement("SELECT " + + "origin, type, permission, expireType, expireTime, modificationTime " + + "FROM moz_perms_v6 WHERE id = :id"); + + // Check that the moz_hosts table still contains the correct values. + created6.forEach((it) => { + mozPermsV6Stmt.reset(); + mozPermsV6Stmt.bindByName("id", it.id); + mozPermsV6Stmt.executeStep(); + do_check_eq(mozPermsV6Stmt.getUTF8String(0), it.origin); + do_check_eq(mozPermsV6Stmt.getUTF8String(1), it.type); + do_check_eq(mozPermsV6Stmt.getInt64(2), it.permission); + do_check_eq(mozPermsV6Stmt.getInt64(3), it.expireType); + do_check_eq(mozPermsV6Stmt.getInt64(4), it.expireTime); + do_check_eq(mozPermsV6Stmt.getInt64(5), it.modificationTime); + }); + + // Check that there are the right number of values + let mozPermsV6Count = db.createStatement("SELECT count(*) FROM moz_perms_v6"); + mozPermsV6Count.executeStep(); + do_check_eq(mozPermsV6Count.getInt64(0), created6.length); + + db.close(); + } +}); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_6-7b.js b/extensions/cookie/test/unit/test_permmanager_migrate_6-7b.js new file mode 100644 index 000000000..7b138ff29 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_6-7b.js @@ -0,0 +1,162 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm"); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 6; + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")"); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")"); + + let id = 0; + + function insertOrigin(origin, type, permission, expireType, expireTime, modificationTime) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + stmt6Insert.execute(); + + return { + id: thisId, + host: origin, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime + }; + } + + let created6 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + ]; + + let created4 = []; // Didn't create any v4 entries, so the DB should be empty + + // CLose the db connection + stmt6Insert.finalize(); + db.close(); + stmt6Insert = null; + db = null; + + let expected = [ + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0] + ]; + + let found = expected.map((it) => 0); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_false(db.tableExists("moz_hosts_is_backup")); + do_check_false(db.tableExists("moz_perms_v6")); + + let mozHostsStmt = db.createStatement("SELECT " + + "host, type, permission, expireType, expireTime, " + + "modificationTime, appId, isInBrowserElement " + + "FROM moz_hosts WHERE id = :id"); + + // Check that the moz_hosts table still contains the correct values. + created4.forEach((it) => { + mozHostsStmt.reset(); + mozHostsStmt.bindByName("id", it.id); + mozHostsStmt.executeStep(); + do_check_eq(mozHostsStmt.getUTF8String(0), it.host); + do_check_eq(mozHostsStmt.getUTF8String(1), it.type); + do_check_eq(mozHostsStmt.getInt64(2), it.permission); + do_check_eq(mozHostsStmt.getInt64(3), it.expireType); + do_check_eq(mozHostsStmt.getInt64(4), it.expireTime); + do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime); + do_check_eq(mozHostsStmt.getInt64(6), it.appId); + do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement); + }); + + // Check that there are the right number of values + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), created4.length); + + db.close(); + } +}); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_7-8.js b/extensions/cookie/test/unit/test_permmanager_migrate_7-8.js new file mode 100644 index 000000000..56d5e2347 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_7-8.js @@ -0,0 +1,246 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm"); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 7; + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")"); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")"); + + /* + * V4 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")"); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")"); + + /* + * The v4 table is a backup + */ + db.executeSimpleSQL("CREATE TABLE moz_hosts_is_backup (dummy INTEGER PRIMARY KEY)"); + + let id = 0; + + function insertOrigin(origin, type, permission, expireType, expireTime, modificationTime) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + stmt6Insert.execute(); + + return { + id: thisId, + origin: origin, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime + }; + } + + function insertHost(host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + stmtInsert.execute(); + + return { + id: thisId, + host: host, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime, + appId: appId, + isInBrowserElement: isInBrowserElement + }; + } + + let created7 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + insertOrigin("https://192.0.2.235", "A", 2, 0, 0), + ]; + + // Add some rows to the database + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + // Although ipv6 addresses are written with [] around the IP address, + // the .host property doesn't contain these []s, which means that we + // write it like this + insertHost("2001:db8::ff00:42:8329", "C", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", "B", 1, 0, 0, 0, 0, false), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // We should have kept the previously migrated entries + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["https://localhost:8080", "A", 1, 0, 0], + ["ftp://127.0.0.1:8080", "A", 1, 0, 0], + + ["http://[2001:db8::ff00:42:8329]", "C", 1, 0, 0], + ["https://[2001:db8::ff00:42:8329]", "C", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + + // There should only be one entry of this type in the database + ["https://192.0.2.235", "A", 2, 0, 0], + ]; + + let found = expected.map((it) => 0); + + // Add some places to the places database + yield PlacesTestUtils.addVisits(Services.io.newURI("https://foo.com/some/other/subdirectory", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://127.0.0.1:8080", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("https://localhost:8080", null, null)); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_false(db.tableExists("moz_hosts_is_backup")); + do_check_false(db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), 0); + + // Check that there are the right number of values in the permissions database + let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms"); + mozPermsCount.executeStep(); + do_check_eq(mozPermsCount.getInt64(0), expected.length); + + db.close(); + } +}); diff --git a/extensions/cookie/test/unit/test_permmanager_notifications.js b/extensions/cookie/test/unit/test_permmanager_notifications.js new file mode 100644 index 000000000..5708fe8ec --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_notifications.js @@ -0,0 +1,140 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that the permissionmanager 'added', 'changed', 'deleted', and 'cleared' +// notifications behave as expected. + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function continue_test() +{ + do_run_generator(test_generator); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + let pm = Services.perms; + let now = Number(Date.now()); + let permType = "test/expiration-perm"; + let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + let uri = NetUtil.newURI("http://example.com"); + let principal = ssm.createCodebasePrincipal(uri, {}); + + let observer = new permission_observer(test_generator, now, permType); + Services.obs.addObserver(observer, "perm-changed", false); + + // Add a permission, to test the 'add' notification. Note that we use + // do_execute_soon() so that we can use our generator to continue the test + // where we left off. + do_execute_soon(function() { + pm.addFromPrincipal(principal, permType, pm.ALLOW_ACTION, pm.EXPIRE_TIME, now + 100000); + }); + yield; + + // Alter a permission, to test the 'changed' notification. + do_execute_soon(function() { + pm.addFromPrincipal(principal, permType, pm.ALLOW_ACTION, pm.EXPIRE_TIME, now + 200000); + }); + yield; + + // Remove a permission, to test the 'deleted' notification. + do_execute_soon(function() { + pm.removeFromPrincipal(principal, permType); + }); + yield; + + // Clear permissions, to test the 'cleared' notification. + do_execute_soon(function() { + pm.removeAll(); + }); + yield; + + Services.obs.removeObserver(observer, "perm-changed"); + do_check_eq(observer.adds, 1); + do_check_eq(observer.changes, 1); + do_check_eq(observer.deletes, 1); + do_check_true(observer.cleared); + + do_finish_generator_test(test_generator); +} + +function permission_observer(generator, now, type) { + // Set up our observer object. + this.generator = generator; + this.pm = Services.perms; + this.now = now; + this.type = type; + this.adds = 0; + this.changes = 0; + this.deletes = 0; + this.cleared = false; +} + +permission_observer.prototype = { + observe: function(subject, topic, data) { + do_check_eq(topic, "perm-changed"); + + // "deleted" means a permission was deleted. aPermission is the deleted permission. + // "added" means a permission was added. aPermission is the added permission. + // "changed" means a permission was altered. aPermission is the new permission. + // "cleared" means the entire permission list was cleared. aPermission is null. + if (data == "added") { + var perm = subject.QueryInterface(Ci.nsIPermission); + this.adds++; + switch (this.adds) { + case 1: + do_check_eq(this.type, perm.type); + do_check_eq(this.pm.EXPIRE_TIME, perm.expireType); + do_check_eq(this.now + 100000, perm.expireTime); + break; + default: + do_throw("too many add notifications posted."); + } + + } else if (data == "changed") { + let perm = subject.QueryInterface(Ci.nsIPermission); + this.changes++; + switch (this.changes) { + case 1: + do_check_eq(this.type, perm.type); + do_check_eq(this.pm.EXPIRE_TIME, perm.expireType); + do_check_eq(this.now + 200000, perm.expireTime); + break; + default: + do_throw("too many change notifications posted."); + } + + } else if (data == "deleted") { + var perm = subject.QueryInterface(Ci.nsIPermission); + this.deletes++; + switch (this.deletes) { + case 1: + do_check_eq(this.type, perm.type); + break; + default: + do_throw("too many delete notifications posted."); + } + + } else if (data == "cleared") { + // only clear once: at the end + do_check_false(this.cleared); + do_check_eq(do_count_enumerator(Services.perms.enumerator), 0); + this.cleared = true; + + } else { + do_throw("unexpected data '" + data + "'!"); + } + + // Continue the test. + do_run_generator(this.generator); + }, +}; + diff --git a/extensions/cookie/test/unit/test_permmanager_removeall.js b/extensions/cookie/test/unit/test_permmanager_removeall.js new file mode 100644 index 000000000..54294a915 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_removeall.js @@ -0,0 +1,36 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + // setup a profile directory + var dir = do_get_profile(); + + // initialize the permission manager service + var pm = Cc["@mozilla.org/permissionmanager;1"]. + getService(Ci.nsIPermissionManager); + + // get the db file + var file = dir.clone(); + file.append("permissions.sqlite"); + do_check_true(file.exists()); + + // corrupt the file + var ostream = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + ostream.init(file, 0x02, 0o666, 0); + var conv = Cc["@mozilla.org/intl/converter-output-stream;1"]. + createInstance(Ci.nsIConverterOutputStream); + conv.init(ostream, "UTF-8", 0, 0); + for (var i = 0; i < file.fileSize; ++i) + conv.writeString("a"); + conv.close(); + + // prepare an empty hostperm.1 file so that it can be used for importing + var hostperm = dir.clone(); + hostperm.append("hostperm.1"); + ostream.init(hostperm, 0x02 | 0x08, 0o666, 0); + ostream.close(); + + // remove all should not throw + pm.removeAll(); +} diff --git a/extensions/cookie/test/unit/test_permmanager_removeforapp.js b/extensions/cookie/test/unit/test_permmanager_removeforapp.js new file mode 100644 index 000000000..152409de2 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_removeforapp.js @@ -0,0 +1,99 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + // initialize the permission manager service + let ssm = Services.scriptSecurityManager; + let pm = Services.perms; + + function mkPrin(uri, appId, inIsolatedMozBrowser) { + return ssm.createCodebasePrincipal(Services.io.newURI(uri, null, null), + {appId: appId, inIsolatedMozBrowser: inIsolatedMozBrowser}); + } + + function checkPerms(perms) { + perms.forEach((perm) => { + // Look up the expected permission + do_check_eq(pm.getPermissionObject(mkPrin(perm[0], perm[1], perm[2]), + perm[3], true).capability, + perm[4], "Permission is expected in the permission database"); + }); + + // Count the entries + let count = 0; + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { enumerator.getNext(); count++; } + + do_check_eq(count, perms.length, "There should be the right number of permissions in the DB"); + } + + checkPerms([]); + + let permissions = [ + ['http://google.com', 1001, false, 'a', 1], + ['http://google.com', 1001, false, 'b', 1], + ['http://mozilla.com', 1001, false, 'b', 1], + ['http://mozilla.com', 1001, false, 'a', 1], + + ['http://google.com', 1001, true, 'a', 1], + ['http://google.com', 1001, true, 'b', 1], + ['http://mozilla.com', 1001, true, 'b', 1], + ['http://mozilla.com', 1001, true, 'a', 1], + + ['http://google.com', 1011, false, 'a', 1], + ['http://google.com', 1011, false, 'b', 1], + ['http://mozilla.com', 1011, false, 'b', 1], + ['http://mozilla.com', 1011, false, 'a', 1], + ]; + + permissions.forEach((perm) => { + pm.addFromPrincipal(mkPrin(perm[0], perm[1], perm[2]), perm[3], perm[4]); + }); + + checkPerms(permissions); + + let remove_false_perms = [ + ['http://google.com', 1011, false, 'a', 1], + ['http://google.com', 1011, false, 'b', 1], + ['http://mozilla.com', 1011, false, 'b', 1], + ['http://mozilla.com', 1011, false, 'a', 1], + ]; + + let attrs = { appId: 1001 }; + pm.removePermissionsWithAttributes(JSON.stringify(attrs)); + checkPerms(remove_false_perms); + + let restore = [ + ['http://google.com', 1001, false, 'a', 1], + ['http://google.com', 1001, false, 'b', 1], + ['http://mozilla.com', 1001, false, 'b', 1], + ['http://mozilla.com', 1001, false, 'a', 1], + + ['http://google.com', 1001, true, 'a', 1], + ['http://google.com', 1001, true, 'b', 1], + ['http://mozilla.com', 1001, true, 'b', 1], + ['http://mozilla.com', 1001, true, 'a', 1], + ]; + + restore.forEach((perm) => { + pm.addFromPrincipal(mkPrin(perm[0], perm[1], perm[2]), perm[3], perm[4]); + }); + checkPerms(permissions); + + let remove_true_perms = [ + ['http://google.com', 1001, false, 'a', 1], + ['http://google.com', 1001, false, 'b', 1], + ['http://mozilla.com', 1001, false, 'b', 1], + ['http://mozilla.com', 1001, false, 'a', 1], + + ['http://google.com', 1011, false, 'a', 1], + ['http://google.com', 1011, false, 'b', 1], + ['http://mozilla.com', 1011, false, 'b', 1], + ['http://mozilla.com', 1011, false, 'a', 1], + ]; + + attrs = { appId: 1001, + inIsolatedMozBrowser: true }; + pm.removePermissionsWithAttributes(JSON.stringify(attrs)); + checkPerms(remove_true_perms); +} diff --git a/extensions/cookie/test/unit/test_permmanager_removepermission.js b/extensions/cookie/test/unit/test_permmanager_removepermission.js new file mode 100644 index 000000000..e8f5817e2 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_removepermission.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + // initialize the permission manager service + let pm = Cc["@mozilla.org/permissionmanager;1"]. + getService(Ci.nsIPermissionManager); + + do_check_eq(perm_count(), 0); + + // add some permissions + let uri = NetUtil.newURI("http://amazon.com:8080/foobarbaz", null, null); + let uri2 = NetUtil.newURI("http://google.com:2048/quxx", null, null); + + pm.add(uri, "apple", 0); + pm.add(uri, "apple", 3); + pm.add(uri, "pear", 3); + pm.add(uri, "pear", 1); + pm.add(uri, "cucumber", 1); + pm.add(uri, "cucumber", 1); + pm.add(uri, "cucumber", 1); + + pm.add(uri2, "apple", 2); + pm.add(uri2, "pear", 0); + pm.add(uri2, "pear", 2); + + // Make sure that removePermission doesn't remove more than one permission each time + do_check_eq(perm_count(), 5); + + remove_one_by_type("apple"); + do_check_eq(perm_count(), 4); + + remove_one_by_type("apple"); + do_check_eq(perm_count(), 3); + + remove_one_by_type("pear"); + do_check_eq(perm_count(), 2); + + remove_one_by_type("cucumber"); + do_check_eq(perm_count(), 1); + + remove_one_by_type("pear"); + do_check_eq(perm_count(), 0); + + + function perm_count() { + let enumerator = pm.enumerator; + let count = 0; + while (enumerator.hasMoreElements()) { + count++; + enumerator.getNext(); + } + + return count; + } + + function remove_one_by_type(type) { + let enumerator = pm.enumerator; + while (enumerator.hasMoreElements()) { + let it = enumerator.getNext().QueryInterface(Ci.nsIPermission); + if (it.type == type) { + pm.removePermission(it); + break; + } + } + } +} diff --git a/extensions/cookie/test/unit/test_permmanager_removesince.js b/extensions/cookie/test/unit/test_permmanager_removesince.js new file mode 100644 index 000000000..719f7f6f6 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_removesince.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that removing permissions since a specified time behaves as expected. + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function continue_test() +{ + do_run_generator(test_generator); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + let pm = Services.perms; + + // to help with testing edge-cases, we will arrange for .removeAllSince to + // remove *all* permissions from one principal and one permission from another. + let permURI1 = NetUtil.newURI("http://example.com"); + let principal1 = Services.scriptSecurityManager.createCodebasePrincipal(permURI1, {}); + + let permURI2 = NetUtil.newURI("http://example.org"); + let principal2 = Services.scriptSecurityManager.createCodebasePrincipal(permURI2, {}); + + // add a permission now - this isn't going to be removed. + pm.addFromPrincipal(principal1, "test/remove-since", 1); + + // sleep briefly, then record the time - we'll remove all since then. + do_timeout(20, continue_test); + yield; + + let since = Number(Date.now()); + + // *sob* - on Windows at least, the now recorded by nsPermissionManager.cpp + // might be a couple of ms *earlier* than what JS sees. So another sleep + // to ensure our |since| is greater than the time of the permissions we + // are now adding. Sadly this means we'll never be able to test when since + // exactly equals the modTime, but there you go... + do_timeout(20, continue_test); + yield; + + // add another item - this second one should get nuked. + pm.addFromPrincipal(principal1, "test/remove-since-2", 1); + + // add 2 items for the second principal - both will be removed. + pm.addFromPrincipal(principal2, "test/remove-since", 1); + pm.addFromPrincipal(principal2, "test/remove-since-2", 1); + + // do the removal. + pm.removeAllSince(since); + + // principal1 - the first one should remain. + do_check_eq(1, pm.testPermissionFromPrincipal(principal1, "test/remove-since")); + // but the second should have been removed. + do_check_eq(0, pm.testPermissionFromPrincipal(principal1, "test/remove-since-2")); + + // principal2 - both should have been removed. + do_check_eq(0, pm.testPermissionFromPrincipal(principal2, "test/remove-since")); + do_check_eq(0, pm.testPermissionFromPrincipal(principal2, "test/remove-since-2")); + + do_finish_generator_test(test_generator); +} diff --git a/extensions/cookie/test/unit/test_permmanager_subdomains.js b/extensions/cookie/test/unit/test_permmanager_subdomains.js new file mode 100644 index 000000000..4e78e4d46 --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_subdomains.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function getPrincipalFromURI(aURI) { + let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + let uri = NetUtil.newURI(aURI); + return ssm.createCodebasePrincipal(uri, {}); +} + +function run_test() { + var pm = Cc["@mozilla.org/permissionmanager;1"]. + getService(Ci.nsIPermissionManager); + + // Adds a permission to a sub-domain. Checks if it is working. + let sub1Principal = getPrincipalFromURI("http://sub1.example.com"); + pm.addFromPrincipal(sub1Principal, "test/subdomains", pm.ALLOW_ACTION, 0, 0); + do_check_eq(pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), pm.ALLOW_ACTION); + + // A sub-sub-domain should get the permission. + let subsubPrincipal = getPrincipalFromURI("http://sub.sub1.example.com"); + do_check_eq(pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), pm.ALLOW_ACTION); + + // Another sub-domain shouldn't get the permission. + let sub2Principal = getPrincipalFromURI("http://sub2.example.com"); + do_check_eq(pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), pm.UNKNOWN_ACTION); + + // Remove current permissions. + pm.removeFromPrincipal(sub1Principal, "test/subdomains"); + do_check_eq(pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), pm.UNKNOWN_ACTION); + + // Adding the permission to the main domain. Checks if it is working. + let mainPrincipal = getPrincipalFromURI("http://example.com"); + pm.addFromPrincipal(mainPrincipal, "test/subdomains", pm.ALLOW_ACTION, 0, 0); + do_check_eq(pm.testPermissionFromPrincipal(mainPrincipal, "test/subdomains"), pm.ALLOW_ACTION); + + // All sub-domains should have the permission now. + do_check_eq(pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), pm.ALLOW_ACTION); + + // Remove current permissions. + pm.removeFromPrincipal(mainPrincipal, "test/subdomains"); + do_check_eq(pm.testPermissionFromPrincipal(mainPrincipal, "test/subdomains"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), pm.UNKNOWN_ACTION); + + // A sanity check that the previous implementation wasn't passing... + let crazyPrincipal = getPrincipalFromURI("http://com"); + pm.addFromPrincipal(crazyPrincipal, "test/subdomains", pm.ALLOW_ACTION, 0, 0); + do_check_eq(pm.testPermissionFromPrincipal(crazyPrincipal, "test/subdomains"), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(mainPrincipal, "test/subdomains"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), pm.UNKNOWN_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), pm.UNKNOWN_ACTION); +} diff --git a/extensions/cookie/test/unit/test_schema_2_migration.js b/extensions/cookie/test/unit/test_schema_2_migration.js new file mode 100644 index 000000000..7dc5e823c --- /dev/null +++ b/extensions/cookie/test/unit/test_schema_2_migration.js @@ -0,0 +1,207 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test cookie database migration from version 2 (Gecko 1.9.3) to the current +// version, presently 4 (Gecko 2.0). + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + // Create a schema 2 database. + let schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + + let now = Date.now() * 1000; + let futureExpiry = Math.round(now / 1e6 + 1000); + let pastExpiry = Math.round(now / 1e6 - 1000); + + // Populate it, with: + // 1) Unexpired, unique cookies. + for (let i = 0; i < 20; ++i) { + let cookie = new Cookie("oh" + i, "hai", "foo.com", "/", + futureExpiry, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + + // 2) Expired, unique cookies. + for (let i = 20; i < 40; ++i) { + let cookie = new Cookie("oh" + i, "hai", "bar.com", "/", + pastExpiry, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + + // 3) Many copies of the same cookie, some of which have expired and + // some of which have not. + for (let i = 40; i < 45; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + futureExpiry + i, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + for (let i = 45; i < 50; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + pastExpiry - i, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + for (let i = 50; i < 55; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + futureExpiry - i, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + for (let i = 55; i < 60; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + pastExpiry + i, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + + // Close it. + schema2db.close(); + schema2db = null; + + // Load the database, forcing migration to the current schema version. Then + // test the expected set of cookies: + // 1) All unexpired, unique cookies exist. + do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 20); + + // 2) All expired, unique cookies exist. + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 20); + + // 3) Only one cookie remains, and it's the one with the highest expiration + // time. + do_check_eq(Services.cookiemgr.countCookiesFromHost("baz.com"), 1); + let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com", {}); + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + do_check_eq(cookie.expiry, futureExpiry + 44); + + do_close_profile(test_generator); + yield; + + // Open the database so we can execute some more schema 2 statements on it. + schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + + // Populate it with more cookies. + for (let i = 60; i < 80; ++i) { + let cookie = new Cookie("oh" + i, "hai", "foo.com", "/", + futureExpiry, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + for (let i = 80; i < 100; ++i) { + let cookie = new Cookie("oh" + i, "hai", "cat.com", "/", + futureExpiry, now, now + i, false, false, false); + + schema2db.insertCookie(cookie); + } + + // Attempt to add a cookie with the same (name, host, path) values as another + // cookie. This should succeed since we have a REPLACE clause for conflict on + // the unique index. + cookie = new Cookie("oh", "hai", "baz.com", "/", + futureExpiry, now, now + 100, false, false, false); + + schema2db.insertCookie(cookie); + + // Check that there is, indeed, a singular cookie for baz.com. + do_check_eq(do_count_cookies_in_db(schema2db.db, "baz.com"), 1); + + // Close it. + schema2db.close(); + schema2db = null; + + // Back up the database, so we can test both asynchronous and synchronous + // loading separately. + let file = do_get_cookie_file(profile); + let copy = profile.clone(); + copy.append("cookies.sqlite.copy"); + file.copyTo(null, copy.leafName); + + // Load the database asynchronously, forcing a purge of the newly-added + // cookies. (Their baseDomain column will be NULL.) + do_load_profile(test_generator); + yield; + + // Test the expected set of cookies. + do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 20); + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 20); + do_check_eq(Services.cookiemgr.countCookiesFromHost("baz.com"), 0); + do_check_eq(Services.cookiemgr.countCookiesFromHost("cat.com"), 0); + + do_close_profile(test_generator); + yield; + + // Open the database and prove that they were deleted. + schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + do_check_eq(do_count_cookies_in_db(schema2db.db), 40); + do_check_eq(do_count_cookies_in_db(schema2db.db, "foo.com"), 20); + do_check_eq(do_count_cookies_in_db(schema2db.db, "bar.com"), 20); + schema2db.close(); + + // Copy the database back. + file.remove(false); + copy.copyTo(null, file.leafName); + + // Load the database host-at-a-time. + do_load_profile(); + + // Test the expected set of cookies. + do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 20); + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 20); + do_check_eq(Services.cookiemgr.countCookiesFromHost("baz.com"), 0); + do_check_eq(Services.cookiemgr.countCookiesFromHost("cat.com"), 0); + + do_close_profile(test_generator); + yield; + + // Open the database and prove that they were deleted. + schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + do_check_eq(do_count_cookies_in_db(schema2db.db), 40); + do_check_eq(do_count_cookies_in_db(schema2db.db, "foo.com"), 20); + do_check_eq(do_count_cookies_in_db(schema2db.db, "bar.com"), 20); + schema2db.close(); + + // Copy the database back. + file.remove(false); + copy.copyTo(null, file.leafName); + + // Load the database synchronously, in its entirety. + do_load_profile(); + do_check_eq(do_count_cookies(), 40); + + // Test the expected set of cookies. + do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 20); + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 20); + do_check_eq(Services.cookiemgr.countCookiesFromHost("baz.com"), 0); + do_check_eq(Services.cookiemgr.countCookiesFromHost("cat.com"), 0); + + do_close_profile(test_generator); + yield; + + // Open the database and prove that they were deleted. + schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); + do_check_eq(do_count_cookies_in_db(schema2db.db), 40); + do_check_eq(do_count_cookies_in_db(schema2db.db, "foo.com"), 20); + do_check_eq(do_count_cookies_in_db(schema2db.db, "bar.com"), 20); + schema2db.close(); + + finish_test(); +} + diff --git a/extensions/cookie/test/unit/test_schema_3_migration.js b/extensions/cookie/test/unit/test_schema_3_migration.js new file mode 100644 index 000000000..40a23f7e4 --- /dev/null +++ b/extensions/cookie/test/unit/test_schema_3_migration.js @@ -0,0 +1,125 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test cookie database migration from version 3 (prerelease Gecko 2.0) to the +// current version, presently 4 (Gecko 2.0). + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function finish_test() { + do_execute_soon(function() { + test_generator.close(); + do_test_finished(); + }); +} + +function do_run_test() { + // Set up a profile. + let profile = do_get_profile(); + + // Create a schema 3 database. + let schema3db = new CookieDatabaseConnection(do_get_cookie_file(profile), 3); + + let now = Date.now() * 1000; + let futureExpiry = Math.round(now / 1e6 + 1000); + let pastExpiry = Math.round(now / 1e6 - 1000); + + // Populate it, with: + // 1) Unexpired, unique cookies. + for (let i = 0; i < 20; ++i) { + let cookie = new Cookie("oh" + i, "hai", "foo.com", "/", + futureExpiry, now, now + i, false, false, false); + + schema3db.insertCookie(cookie); + } + + // 2) Expired, unique cookies. + for (let i = 20; i < 40; ++i) { + let cookie = new Cookie("oh" + i, "hai", "bar.com", "/", + pastExpiry, now, now + i, false, false, false); + + schema3db.insertCookie(cookie); + } + + // 3) Many copies of the same cookie, some of which have expired and + // some of which have not. + for (let i = 40; i < 45; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + futureExpiry + i, now, now + i, false, false, false); + + schema3db.insertCookie(cookie); + } + for (let i = 45; i < 50; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + pastExpiry - i, now, now + i, false, false, false); + + schema3db.insertCookie(cookie); + } + for (let i = 50; i < 55; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + futureExpiry - i, now, now + i, false, false, false); + + schema3db.insertCookie(cookie); + } + for (let i = 55; i < 60; ++i) { + let cookie = new Cookie("oh", "hai", "baz.com", "/", + pastExpiry + i, now, now + i, false, false, false); + + schema3db.insertCookie(cookie); + } + + // Close it. + schema3db.close(); + schema3db = null; + + // Load the database, forcing migration to the current schema version. Then + // test the expected set of cookies: + // 1) All unexpired, unique cookies exist. + do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 20); + + // 2) All expired, unique cookies exist. + do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 20); + + // 3) Only one cookie remains, and it's the one with the highest expiration + // time. + do_check_eq(Services.cookiemgr.countCookiesFromHost("baz.com"), 1); + let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com", {}); + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + do_check_eq(cookie.expiry, futureExpiry + 44); + + do_close_profile(test_generator); + yield; + + // Open the database so we can execute some more schema 3 statements on it. + schema3db = new CookieDatabaseConnection(do_get_cookie_file(profile), 3); + + // Populate it with more cookies. + for (let i = 60; i < 80; ++i) { + let cookie = new Cookie("oh" + i, "hai", "cat.com", "/", + futureExpiry, now, now + i, false, false, false); + + schema3db.insertCookie(cookie); + } + + // Close it. + schema3db.close(); + schema3db = null; + + // Load the database. The cookies added immediately prior will have a NULL + // creationTime column. + do_load_profile(); + + // Test the expected set of cookies. + do_check_eq(Services.cookiemgr.countCookiesFromHost("cat.com"), 20); + enumerator = Services.cookiemgr.getCookiesFromHost("cat.com", {}); + cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + do_check_eq(cookie.creationTime, 0); + + finish_test(); +} + diff --git a/extensions/cookie/test/unit/xpcshell.ini b/extensions/cookie/test/unit/xpcshell.ini new file mode 100644 index 000000000..e20d0142c --- /dev/null +++ b/extensions/cookie/test/unit/xpcshell.ini @@ -0,0 +1,48 @@ +[DEFAULT] +head = head_cookies.js +tail = +skip-if = toolkit == 'android' +support-files = + cookieprompt.js + cookieprompt.manifest + +[test_bug526789.js] +[test_bug650522.js] +[test_bug667087.js] +[test_cookies_async_failure.js] +[test_cookies_persistence.js] +skip-if = true # Bug 863738 +[test_cookies_privatebrowsing.js] +[test_cookies_profile_close.js] +[test_cookies_read.js] +[test_cookies_sync_failure.js] +[test_cookies_thirdparty.js] +[test_cookies_thirdparty_session.js] +[test_domain_eviction.js] +[test_eviction.js] +[test_permmanager_defaults.js] +[test_permmanager_expiration.js] +[test_permmanager_getAllForURI.js] +[test_permmanager_getPermissionObject.js] +[test_permmanager_notifications.js] +[test_permmanager_removeall.js] +[test_permmanager_removesince.js] +[test_permmanager_removeforapp.js] +[test_permmanager_load_invalid_entries.js] +skip-if = debug == true +[test_permmanager_idn.js] +[test_permmanager_subdomains.js] +[test_permmanager_local_files.js] +[test_permmanager_cleardata.js] +[test_schema_2_migration.js] +[test_schema_3_migration.js] +[test_permmanager_removepermission.js] +[test_permmanager_matchesuri.js] +[test_permmanager_matches.js] +[test_permmanager_migrate_4-7.js] +[test_permmanager_migrate_5-7a.js] +[test_permmanager_migrate_5-7b.js] +[test_permmanager_migrate_6-7a.js] +[test_permmanager_migrate_6-7b.js] +[test_permmanager_migrate_4-7_no_history.js] +[test_permmanager_migrate_7-8.js] diff --git a/extensions/cookie/test/unit_ipc/test_child.js b/extensions/cookie/test/unit_ipc/test_child.js new file mode 100644 index 000000000..40a48d8b8 --- /dev/null +++ b/extensions/cookie/test/unit_ipc/test_child.js @@ -0,0 +1,59 @@ +var Ci = Components.interfaces; +var Cc = Components.classes; +var Cr = Components.results; + +var gIoService = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + +function isParentProcess() { + let appInfo = Cc["@mozilla.org/xre/app-info;1"]; + return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT); +} + +function getPrincipalForURI(aURI) { + var uri = gIoService.newURI(aURI, null, null); + var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + return ssm.createCodebasePrincipal(uri, {}); +} + +function run_test() { + if (!isParentProcess()) { + const Ci = Components.interfaces; + const Cc = Components.classes; + + var mM = Cc["@mozilla.org/childprocessmessagemanager;1"]. + getService(Ci.nsISyncMessageSender); + + var messageListener = { + receiveMessage: function(aMessage) { + switch(aMessage.name) { + case "TESTING:Stage2A": + // Permissions created after the child is present + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.org"), "cookie1"), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.com"), "cookie2"), pm.DENY_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.net"), "cookie3"), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://firefox.org"), "cookie1"), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://firefox.com"), "cookie2"), pm.DENY_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://firefox.net"), "cookie3"), pm.ALLOW_ACTION); + + mM.sendAsyncMessage("TESTING:Stage3"); + break; + + } + return true; + }, + }; + + mM.addMessageListener("TESTING:Stage2A", messageListener); + + // Permissions created before the child is present + var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.org"), "cookie1"), pm.ALLOW_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.com"), "cookie2"), pm.DENY_ACTION); + do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.net"), "cookie3"), pm.ALLOW_ACTION); + + mM.sendAsyncMessage("TESTING:Stage2"); + } +} + diff --git a/extensions/cookie/test/unit_ipc/test_parent.js b/extensions/cookie/test/unit_ipc/test_parent.js new file mode 100644 index 000000000..5423dd594 --- /dev/null +++ b/extensions/cookie/test/unit_ipc/test_parent.js @@ -0,0 +1,59 @@ +var Ci = Components.interfaces; +var Cc = Components.classes; +var Cr = Components.results; + +var gIoService = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + +function isParentProcess() { + let appInfo = Cc["@mozilla.org/xre/app-info;1"]; + return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT); +} + +function getPrincipalForURI(aURI) { + var uri = gIoService.newURI(aURI, null, null); + var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + return ssm.createCodebasePrincipal(uri, {}); +} + +function run_test() { + if (isParentProcess()) { + var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); + + // Permissions created before the child is present + pm.addFromPrincipal(getPrincipalForURI("http://mozilla.org"), "cookie1", pm.ALLOW_ACTION, pm.EXPIRE_NEVER, 0); + pm.addFromPrincipal(getPrincipalForURI("http://mozilla.com"), "cookie2", pm.DENY_ACTION, pm.EXPIRE_SESSION, 0); + pm.addFromPrincipal(getPrincipalForURI("http://mozilla.net"), "cookie3", pm.ALLOW_ACTION, pm.EXPIRE_TIME, Date.now() + 1000*60*60*24); + + var mM = Cc["@mozilla.org/parentprocessmessagemanager;1"]. + getService(Ci.nsIMessageBroadcaster); + + var messageListener = { + receiveMessage: function(aMessage) { + switch(aMessage.name) { + case "TESTING:Stage2": + // Permissions created after the child is present + pm.addFromPrincipal(getPrincipalForURI("http://firefox.org"), "cookie1", pm.ALLOW_ACTION, pm.EXPIRE_NEVER, 0); + pm.addFromPrincipal(getPrincipalForURI("http://firefox.com"), "cookie2", pm.DENY_ACTION, pm.EXPIRE_SESSION, 0); + pm.addFromPrincipal(getPrincipalForURI("http://firefox.net"), "cookie3", pm.ALLOW_ACTION, pm.EXPIRE_TIME, Date.now() + 1000*60*60*24); + mM.broadcastAsyncMessage("TESTING:Stage2A"); + break; + + case "TESTING:Stage3": + do_test_finished(); + break; + } + return true; + }, + }; + + mM.addMessageListener("TESTING:Stage2", messageListener); + mM.addMessageListener("TESTING:Stage3", messageListener); + + do_test_pending(); + do_load_child_test_harness(); + run_test_in_child("test_child.js"); + } +} + diff --git a/extensions/cookie/test/unit_ipc/xpcshell.ini b/extensions/cookie/test/unit_ipc/xpcshell.ini new file mode 100644 index 000000000..5640ea0e3 --- /dev/null +++ b/extensions/cookie/test/unit_ipc/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +head = +tail = +skip-if = toolkit == 'android' + +[test_child.js] +[test_parent.js] diff --git a/extensions/gio/moz.build b/extensions/gio/moz.build new file mode 100644 index 000000000..94828f809 --- /dev/null +++ b/extensions/gio/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + 'nsGIOProtocolHandler.cpp', +] + +FINAL_LIBRARY = 'xul' + +CXXFLAGS += CONFIG['MOZ_GIO_CFLAGS'] diff --git a/extensions/gio/nsGIOProtocolHandler.cpp b/extensions/gio/nsGIOProtocolHandler.cpp new file mode 100644 index 000000000..a378e8700 --- /dev/null +++ b/extensions/gio/nsGIOProtocolHandler.cpp @@ -0,0 +1,1131 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This code is based on original Mozilla gnome-vfs extension. It implements + * input stream provided by GVFS/GIO. +*/ +#include "mozilla/ModuleUtils.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIObserver.h" +#include "nsThreadUtils.h" +#include "nsProxyRelease.h" +#include "nsIStringBundle.h" +#include "nsIStandardURL.h" +#include "nsMimeTypes.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsServiceManagerUtils.h" +#include "nsIURI.h" +#include "nsIAuthPrompt.h" +#include "nsIChannel.h" +#include "nsIInputStream.h" +#include "nsIProtocolHandler.h" +#include "nsNullPrincipal.h" +#include "mozilla/Monitor.h" +#include "plstr.h" +#include "prtime.h" +#include +#include + +#define MOZ_GIO_SCHEME "moz-gio" +#define MOZ_GIO_SUPPORTED_PROTOCOLS "network.gio.supported-protocols" + +//----------------------------------------------------------------------------- + +// NSPR_LOG_MODULES=gio:5 +static mozilla::LazyLogModule sGIOLog("gio"); +#define LOG(args) MOZ_LOG(sGIOLog, mozilla::LogLevel::Debug, args) + + +//----------------------------------------------------------------------------- +static nsresult +MapGIOResult(gint code) +{ + switch (code) + { + case G_IO_ERROR_NOT_FOUND: return NS_ERROR_FILE_NOT_FOUND; // shows error + case G_IO_ERROR_INVALID_ARGUMENT: return NS_ERROR_INVALID_ARG; + case G_IO_ERROR_NOT_SUPPORTED: return NS_ERROR_NOT_AVAILABLE; + case G_IO_ERROR_NO_SPACE: return NS_ERROR_FILE_NO_DEVICE_SPACE; + case G_IO_ERROR_READ_ONLY: return NS_ERROR_FILE_READ_ONLY; + case G_IO_ERROR_PERMISSION_DENIED: return NS_ERROR_FILE_ACCESS_DENIED; // wrong password/login + case G_IO_ERROR_CLOSED: return NS_BASE_STREAM_CLOSED; // was EOF + case G_IO_ERROR_NOT_DIRECTORY: return NS_ERROR_FILE_NOT_DIRECTORY; + case G_IO_ERROR_PENDING: return NS_ERROR_IN_PROGRESS; + case G_IO_ERROR_EXISTS: return NS_ERROR_FILE_ALREADY_EXISTS; + case G_IO_ERROR_IS_DIRECTORY: return NS_ERROR_FILE_IS_DIRECTORY; + case G_IO_ERROR_NOT_MOUNTED: return NS_ERROR_NOT_CONNECTED; // shows error + case G_IO_ERROR_HOST_NOT_FOUND: return NS_ERROR_UNKNOWN_HOST; // shows error + case G_IO_ERROR_CANCELLED: return NS_ERROR_ABORT; + case G_IO_ERROR_NOT_EMPTY: return NS_ERROR_FILE_DIR_NOT_EMPTY; + case G_IO_ERROR_FILENAME_TOO_LONG: return NS_ERROR_FILE_NAME_TOO_LONG; + case G_IO_ERROR_INVALID_FILENAME: return NS_ERROR_FILE_INVALID_PATH; + case G_IO_ERROR_TIMED_OUT: return NS_ERROR_NET_TIMEOUT; // shows error + case G_IO_ERROR_WOULD_BLOCK: return NS_BASE_STREAM_WOULD_BLOCK; + case G_IO_ERROR_FAILED_HANDLED: return NS_ERROR_ABORT; // Cancel on login dialog + +/* unhandled: + G_IO_ERROR_NOT_REGULAR_FILE, + G_IO_ERROR_NOT_SYMBOLIC_LINK, + G_IO_ERROR_NOT_MOUNTABLE_FILE, + G_IO_ERROR_TOO_MANY_LINKS, + G_IO_ERROR_ALREADY_MOUNTED, + G_IO_ERROR_CANT_CREATE_BACKUP, + G_IO_ERROR_WRONG_ETAG, + G_IO_ERROR_WOULD_RECURSE, + G_IO_ERROR_BUSY, + G_IO_ERROR_WOULD_MERGE, + G_IO_ERROR_TOO_MANY_OPEN_FILES +*/ + // Make GCC happy + default: + return NS_ERROR_FAILURE; + } + + return NS_ERROR_FAILURE; +} + +static nsresult +MapGIOResult(GError *result) +{ + if (!result) + return NS_OK; + else + return MapGIOResult(result->code); +} +/** Return values for mount operation. + * These enums are used as mount operation return values. + */ +typedef enum { + MOUNT_OPERATION_IN_PROGRESS, /** \enum operation in progress */ + MOUNT_OPERATION_SUCCESS, /** \enum operation successful */ + MOUNT_OPERATION_FAILED /** \enum operation not successful */ +} MountOperationResult; +//----------------------------------------------------------------------------- +/** + * Sort function compares according to file type (directory/file) + * and alphabethical order + * @param a pointer to GFileInfo object to compare + * @param b pointer to GFileInfo object to compare + * @return -1 when first object should be before the second, 0 when equal, + * +1 when second object should be before the first + */ +static gint +FileInfoComparator(gconstpointer a, gconstpointer b) +{ + GFileInfo *ia = ( GFileInfo *) a; + GFileInfo *ib = ( GFileInfo *) b; + if (g_file_info_get_file_type(ia) == G_FILE_TYPE_DIRECTORY + && g_file_info_get_file_type(ib) != G_FILE_TYPE_DIRECTORY) + return -1; + if (g_file_info_get_file_type(ib) == G_FILE_TYPE_DIRECTORY + && g_file_info_get_file_type(ia) != G_FILE_TYPE_DIRECTORY) + return 1; + + return strcasecmp(g_file_info_get_name(ia), g_file_info_get_name(ib)); +} + +/* Declaration of mount callback functions */ +static void mount_enclosing_volume_finished (GObject *source_object, + GAsyncResult *res, + gpointer user_data); +static void mount_operation_ask_password (GMountOperation *mount_op, + const char *message, + const char *default_user, + const char *default_domain, + GAskPasswordFlags flags, + gpointer user_data); +//----------------------------------------------------------------------------- + +class nsGIOInputStream final : public nsIInputStream +{ + ~nsGIOInputStream() { Close(); } + + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + + explicit nsGIOInputStream(const nsCString &uriSpec) + : mSpec(uriSpec) + , mChannel(nullptr) + , mHandle(nullptr) + , mStream(nullptr) + , mBytesRemaining(UINT64_MAX) + , mStatus(NS_OK) + , mDirList(nullptr) + , mDirListPtr(nullptr) + , mDirBufCursor(0) + , mDirOpen(false) + , mMonitorMountInProgress("GIOInputStream::MountFinished") { } + + void SetChannel(nsIChannel *channel) + { + // We need to hold an owning reference to our channel. This is done + // so we can access the channel's notification callbacks to acquire + // a reference to a nsIAuthPrompt if we need to handle an interactive + // mount operation. + // + // However, the channel can only be accessed on the main thread, so + // we have to be very careful with ownership. Moreover, it doesn't + // support threadsafe addref/release, so proxying is the answer. + // + // Also, it's important to note that this likely creates a reference + // cycle since the channel likely owns this stream. This reference + // cycle is broken in our Close method. + + NS_ADDREF(mChannel = channel); + } + void SetMountResult(MountOperationResult result, gint error_code); + private: + nsresult DoOpen(); + nsresult DoRead(char *aBuf, uint32_t aCount, uint32_t *aCountRead); + nsresult SetContentTypeOfChannel(const char *contentType); + nsresult MountVolume(); + nsresult DoOpenDirectory(); + nsresult DoOpenFile(GFileInfo *info); + nsCString mSpec; + nsIChannel *mChannel; // manually refcounted + GFile *mHandle; + GFileInputStream *mStream; + uint64_t mBytesRemaining; + nsresult mStatus; + GList *mDirList; + GList *mDirListPtr; + nsCString mDirBuf; + uint32_t mDirBufCursor; + bool mDirOpen; + MountOperationResult mMountRes; + mozilla::Monitor mMonitorMountInProgress; + gint mMountErrorCode; +}; +/** + * Set result of mount operation and notify monitor waiting for results. + * This method is called in main thread as long as it is used only + * in mount_enclosing_volume_finished function. + * @param result Result of mount operation + */ +void +nsGIOInputStream::SetMountResult(MountOperationResult result, gint error_code) +{ + mozilla::MonitorAutoLock mon(mMonitorMountInProgress); + mMountRes = result; + mMountErrorCode = error_code; + mon.Notify(); +} + +/** + * Start mount operation and wait in loop until it is finished. This method is + * called from thread which is trying to read from location. + */ +nsresult +nsGIOInputStream::MountVolume() { + GMountOperation* mount_op = g_mount_operation_new(); + g_signal_connect (mount_op, "ask-password", + G_CALLBACK (mount_operation_ask_password), mChannel); + mMountRes = MOUNT_OPERATION_IN_PROGRESS; + /* g_file_mount_enclosing_volume uses a dbus request to mount the volume. + Callback mount_enclosing_volume_finished is called in main thread + (not this thread on which this method is called). */ + g_file_mount_enclosing_volume(mHandle, + G_MOUNT_MOUNT_NONE, + mount_op, + nullptr, + mount_enclosing_volume_finished, + this); + mozilla::MonitorAutoLock mon(mMonitorMountInProgress); + /* Waiting for finish of mount operation thread */ + while (mMountRes == MOUNT_OPERATION_IN_PROGRESS) + mon.Wait(); + + g_object_unref(mount_op); + + if (mMountRes == MOUNT_OPERATION_FAILED) { + return MapGIOResult(mMountErrorCode); + } else { + return NS_OK; + } +} + +/** + * Create list of infos about objects in opened directory + * Return: NS_OK when list obtained, otherwise error code according + * to failed operation. + */ +nsresult +nsGIOInputStream::DoOpenDirectory() +{ + GError *error = nullptr; + + GFileEnumerator *f_enum = g_file_enumerate_children(mHandle, + "standard::*,time::*", + G_FILE_QUERY_INFO_NONE, + nullptr, + &error); + if (!f_enum) { + nsresult rv = MapGIOResult(error); + g_warning("Cannot read from directory: %s", error->message); + g_error_free(error); + return rv; + } + // fill list of file infos + GFileInfo *info = g_file_enumerator_next_file(f_enum, nullptr, &error); + while (info) { + mDirList = g_list_append(mDirList, info); + info = g_file_enumerator_next_file(f_enum, nullptr, &error); + } + g_object_unref(f_enum); + if (error) { + g_warning("Error reading directory content: %s", error->message); + nsresult rv = MapGIOResult(error); + g_error_free(error); + return rv; + } + mDirOpen = true; + + // Sort list of file infos by using FileInfoComparator function + mDirList = g_list_sort(mDirList, FileInfoComparator); + mDirListPtr = mDirList; + + // Write base URL (make sure it ends with a '/') + mDirBuf.AppendLiteral("300: "); + mDirBuf.Append(mSpec); + if (mSpec.get()[mSpec.Length() - 1] != '/') + mDirBuf.Append('/'); + mDirBuf.Append('\n'); + + // Write column names + mDirBuf.AppendLiteral("200: filename content-length last-modified file-type\n"); + + // Write charset (assume UTF-8) + // XXX is this correct? + mDirBuf.AppendLiteral("301: UTF-8\n"); + SetContentTypeOfChannel(APPLICATION_HTTP_INDEX_FORMAT); + return NS_OK; +} + +/** + * Create file stream and set mime type for channel + * @param info file info used to determine mime type + * @return NS_OK when file stream created successfuly, error code otherwise + */ +nsresult +nsGIOInputStream::DoOpenFile(GFileInfo *info) +{ + GError *error = nullptr; + + mStream = g_file_read(mHandle, nullptr, &error); + if (!mStream) { + nsresult rv = MapGIOResult(error); + g_warning("Cannot read from file: %s", error->message); + g_error_free(error); + return rv; + } + + const char * content_type = g_file_info_get_content_type(info); + if (content_type) { + char *mime_type = g_content_type_get_mime_type(content_type); + if (mime_type) { + if (strcmp(mime_type, APPLICATION_OCTET_STREAM) != 0) { + SetContentTypeOfChannel(mime_type); + } + g_free(mime_type); + } + } else { + g_warning("Missing content type."); + } + + mBytesRemaining = g_file_info_get_size(info); + // Update the content length attribute on the channel. We do this + // synchronously without proxying. This hack is not as bad as it looks! + mChannel->SetContentLength(mBytesRemaining); + + return NS_OK; +} + +/** + * Start file open operation, mount volume when needed and according to file type + * create file output stream or read directory content. + * @return NS_OK when file or directory opened successfully, error code otherwise + */ +nsresult +nsGIOInputStream::DoOpen() +{ + nsresult rv; + GError *error = nullptr; + + NS_ASSERTION(mHandle == nullptr, "already open"); + + mHandle = g_file_new_for_uri( mSpec.get() ); + + GFileInfo *info = g_file_query_info(mHandle, + "standard::*", + G_FILE_QUERY_INFO_NONE, + nullptr, + &error); + + if (error) { + if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED) { + // location is not yet mounted, try to mount + g_error_free(error); + if (NS_IsMainThread()) + return NS_ERROR_NOT_CONNECTED; + error = nullptr; + rv = MountVolume(); + if (rv != NS_OK) { + return rv; + } + // get info again + info = g_file_query_info(mHandle, + "standard::*", + G_FILE_QUERY_INFO_NONE, + nullptr, + &error); + // second try to get file info from remote files after media mount + if (!info) { + g_warning("Unable to get file info: %s", error->message); + rv = MapGIOResult(error); + g_error_free(error); + return rv; + } + } else { + g_warning("Unable to get file info: %s", error->message); + rv = MapGIOResult(error); + g_error_free(error); + return rv; + } + } + // Get file type to handle directories and file differently + GFileType f_type = g_file_info_get_file_type(info); + if (f_type == G_FILE_TYPE_DIRECTORY) { + // directory + rv = DoOpenDirectory(); + } else if (f_type != G_FILE_TYPE_UNKNOWN) { + // file + rv = DoOpenFile(info); + } else { + g_warning("Unable to get file type."); + rv = NS_ERROR_FILE_NOT_FOUND; + } + if (info) + g_object_unref(info); + return rv; +} + +/** + * Read content of file or create file list from directory + * @param aBuf read destination buffer + * @param aCount length of destination buffer + * @param aCountRead number of read characters + * @return NS_OK when read successfully, NS_BASE_STREAM_CLOSED when end of file, + * error code otherwise + */ +nsresult +nsGIOInputStream::DoRead(char *aBuf, uint32_t aCount, uint32_t *aCountRead) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + if (mStream) { + // file read + GError *error = nullptr; + uint32_t bytes_read = g_input_stream_read(G_INPUT_STREAM(mStream), + aBuf, + aCount, + nullptr, + &error); + if (error) { + rv = MapGIOResult(error); + *aCountRead = 0; + g_warning("Cannot read from file: %s", error->message); + g_error_free(error); + return rv; + } + *aCountRead = bytes_read; + mBytesRemaining -= *aCountRead; + return NS_OK; + } + else if (mDirOpen) { + // directory read + while (aCount && rv != NS_BASE_STREAM_CLOSED) + { + // Copy data out of our buffer + uint32_t bufLen = mDirBuf.Length() - mDirBufCursor; + if (bufLen) + { + uint32_t n = std::min(bufLen, aCount); + memcpy(aBuf, mDirBuf.get() + mDirBufCursor, n); + *aCountRead += n; + aBuf += n; + aCount -= n; + mDirBufCursor += n; + } + + if (!mDirListPtr) // Are we at the end of the directory list? + { + rv = NS_BASE_STREAM_CLOSED; + } + else if (aCount) // Do we need more data? + { + GFileInfo *info = (GFileInfo *) mDirListPtr->data; + + // Prune '.' and '..' from directory listing. + const char * fname = g_file_info_get_name(info); + if (fname && fname[0] == '.' && + (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0'))) + { + mDirListPtr = mDirListPtr->next; + continue; + } + + mDirBuf.AssignLiteral("201: "); + + // The "filename" field + nsCString escName; + nsCOMPtr nu = do_GetService(NS_NETUTIL_CONTRACTID); + if (nu && fname) { + nu->EscapeString(nsDependentCString(fname), + nsINetUtil::ESCAPE_URL_PATH, escName); + + mDirBuf.Append(escName); + mDirBuf.Append(' '); + } + + // The "content-length" field + // XXX truncates size from 64-bit to 32-bit + mDirBuf.AppendInt(int32_t(g_file_info_get_size(info))); + mDirBuf.Append(' '); + + // The "last-modified" field + // + // NSPR promises: PRTime is compatible with time_t + // we just need to convert from seconds to microseconds + GTimeVal gtime; + g_file_info_get_modification_time(info, >ime); + + PRExplodedTime tm; + PRTime pt = ((PRTime) gtime.tv_sec) * 1000000; + PR_ExplodeTime(pt, PR_GMTParameters, &tm); + { + char buf[64]; + PR_FormatTimeUSEnglish(buf, sizeof(buf), + "%a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ", &tm); + mDirBuf.Append(buf); + } + + // The "file-type" field + switch (g_file_info_get_file_type(info)) + { + case G_FILE_TYPE_REGULAR: + mDirBuf.AppendLiteral("FILE "); + break; + case G_FILE_TYPE_DIRECTORY: + mDirBuf.AppendLiteral("DIRECTORY "); + break; + case G_FILE_TYPE_SYMBOLIC_LINK: + mDirBuf.AppendLiteral("SYMBOLIC-LINK "); + break; + default: + break; + } + mDirBuf.Append('\n'); + + mDirBufCursor = 0; + mDirListPtr = mDirListPtr->next; + } + } + } + return rv; +} + +/** + * This class is used to implement SetContentTypeOfChannel. + */ +class nsGIOSetContentTypeEvent : public mozilla::Runnable +{ + public: + nsGIOSetContentTypeEvent(nsIChannel *channel, const char *contentType) + : mChannel(channel), mContentType(contentType) + { + // stash channel reference in mChannel. no AddRef here! see note + // in SetContentTypeOfchannel. + } + + NS_IMETHOD Run() override + { + mChannel->SetContentType(mContentType); + return NS_OK; + } + + private: + nsIChannel *mChannel; + nsCString mContentType; +}; + +nsresult +nsGIOInputStream::SetContentTypeOfChannel(const char *contentType) +{ + // We need to proxy this call over to the main thread. We post an + // asynchronous event in this case so that we don't delay reading data, and + // we know that this is safe to do since the channel's reference will be + // released asynchronously as well. We trust the ordering of the main + // thread's event queue to protect us against memory corruption. + + nsresult rv; + nsCOMPtr ev = + new nsGIOSetContentTypeEvent(mChannel, contentType); + if (!ev) + { + rv = NS_ERROR_OUT_OF_MEMORY; + } + else + { + rv = NS_DispatchToMainThread(ev); + } + return rv; +} + +NS_IMPL_ISUPPORTS(nsGIOInputStream, nsIInputStream) + +/** + * Free all used memory and close stream. + */ +NS_IMETHODIMP +nsGIOInputStream::Close() +{ + if (mStream) + { + g_object_unref(mStream); + mStream = nullptr; + } + + if (mHandle) + { + g_object_unref(mHandle); + mHandle = nullptr; + } + + if (mDirList) + { + // Destroy the list of GIOFileInfo objects... + g_list_foreach(mDirList, (GFunc) g_object_unref, nullptr); + g_list_free(mDirList); + mDirList = nullptr; + mDirListPtr = nullptr; + } + + if (mChannel) { + NS_ReleaseOnMainThread(dont_AddRef(mChannel)); + + mChannel = nullptr; + } + + mSpec.Truncate(); // free memory + + // Prevent future reads from re-opening the handle. + if (NS_SUCCEEDED(mStatus)) + mStatus = NS_BASE_STREAM_CLOSED; + + return NS_OK; +} + +/** + * Return number of remaining bytes available on input + * @param aResult remaining bytes + */ +NS_IMETHODIMP +nsGIOInputStream::Available(uint64_t *aResult) +{ + if (NS_FAILED(mStatus)) + return mStatus; + + *aResult = mBytesRemaining; + + return NS_OK; +} + +/** + * Trying to read from stream. When location is not available it tries to mount it. + * @param aBuf buffer to put read data + * @param aCount length of aBuf + * @param aCountRead number of bytes actually read + */ +NS_IMETHODIMP +nsGIOInputStream::Read(char *aBuf, + uint32_t aCount, + uint32_t *aCountRead) +{ + *aCountRead = 0; + // Check if file is already opened, otherwise open it + if (!mStream && !mDirOpen && mStatus == NS_OK) { + mStatus = DoOpen(); + if (NS_FAILED(mStatus)) { + return mStatus; + } + } + + mStatus = DoRead(aBuf, aCount, aCountRead); + // Check if all data has been read + if (mStatus == NS_BASE_STREAM_CLOSED) + return NS_OK; + + // Check whenever any error appears while reading + return mStatus; +} + +NS_IMETHODIMP +nsGIOInputStream::ReadSegments(nsWriteSegmentFun aWriter, + void *aClosure, + uint32_t aCount, + uint32_t *aResult) +{ + // There is no way to implement this using GnomeVFS, but fortunately + // that doesn't matter. Because we are a blocking input stream, Necko + // isn't going to call our ReadSegments method. + NS_NOTREACHED("nsGIOInputStream::ReadSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsGIOInputStream::IsNonBlocking(bool *aResult) +{ + *aResult = false; + return NS_OK; +} + +//----------------------------------------------------------------------------- + +/** + * Called when finishing mount operation. Result of operation is set in + * nsGIOInputStream. This function is called in main thread as an async request + * typically from dbus. + * @param source_object GFile object which requested the mount + * @param res result object + * @param user_data pointer to nsGIOInputStream + */ +static void +mount_enclosing_volume_finished (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = nullptr; + + nsGIOInputStream* istream = static_cast(user_data); + + g_file_mount_enclosing_volume_finish(G_FILE (source_object), res, &error); + + if (error) { + g_warning("Mount failed: %s %d", error->message, error->code); + istream->SetMountResult(MOUNT_OPERATION_FAILED, error->code); + g_error_free(error); + } else { + istream->SetMountResult(MOUNT_OPERATION_SUCCESS, 0); + } +} + +/** + * This function is called when username or password are requested from user. + * This function is called in main thread as async request from dbus. + * @param mount_op mount operation + * @param message message to show to user + * @param default_user preffered user + * @param default_domain domain name + * @param flags what type of information is required + * @param user_data nsIChannel + */ +static void +mount_operation_ask_password (GMountOperation *mount_op, + const char *message, + const char *default_user, + const char *default_domain, + GAskPasswordFlags flags, + gpointer user_data) +{ + nsIChannel *channel = (nsIChannel *) user_data; + if (!channel) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + // We can't handle request for domain + if (flags & G_ASK_PASSWORD_NEED_DOMAIN) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + + nsCOMPtr prompt; + NS_QueryNotificationCallbacks(channel, prompt); + + // If no auth prompt, then give up. We could failover to using the + // WindowWatcher service, but that might defeat a consumer's purposeful + // attempt to disable authentication (for whatever reason). + if (!prompt) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + // Parse out the host and port... + nsCOMPtr uri; + channel->GetURI(getter_AddRefs(uri)); + if (!uri) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + + nsAutoCString scheme, hostPort; + uri->GetScheme(scheme); + uri->GetHostPort(hostPort); + + // It doesn't make sense for either of these strings to be empty. What kind + // of funky URI is this? + if (scheme.IsEmpty() || hostPort.IsEmpty()) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + // Construct the single signon key. Altering the value of this key will + // cause people's remembered passwords to be forgotten. Think carefully + // before changing the way this key is constructed. + nsAutoString key, realm; + + NS_ConvertUTF8toUTF16 dispHost(scheme); + dispHost.AppendLiteral("://"); + dispHost.Append(NS_ConvertUTF8toUTF16(hostPort)); + + key = dispHost; + if (*default_domain != '\0') + { + // We assume the realm string is ASCII. That might be a bogus assumption, + // but we have no idea what encoding GnomeVFS is using, so for now we'll + // limit ourselves to ISO-Latin-1. XXX What is a better solution? + realm.Append('"'); + realm.Append(NS_ConvertASCIItoUTF16(default_domain)); + realm.Append('"'); + key.Append(' '); + key.Append(realm); + } + // Construct the message string... + // + // We use Necko's string bundle here. This code really should be encapsulated + // behind some Necko API, after all this code is based closely on the code in + // nsHttpChannel.cpp. + nsCOMPtr bundleSvc = + do_GetService(NS_STRINGBUNDLE_CONTRACTID); + if (!bundleSvc) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + nsCOMPtr bundle; + bundleSvc->CreateBundle("chrome://global/locale/commonDialogs.properties", + getter_AddRefs(bundle)); + if (!bundle) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + nsAutoString nsmessage; + + if (flags & G_ASK_PASSWORD_NEED_PASSWORD) { + if (flags & G_ASK_PASSWORD_NEED_USERNAME) { + if (!realm.IsEmpty()) { + const char16_t *strings[] = { realm.get(), dispHost.get() }; + bundle->FormatStringFromName(u"EnterLoginForRealm3", + strings, 2, getter_Copies(nsmessage)); + } else { + const char16_t *strings[] = { dispHost.get() }; + bundle->FormatStringFromName(u"EnterUserPasswordFor2", + strings, 1, getter_Copies(nsmessage)); + } + } else { + NS_ConvertUTF8toUTF16 userName(default_user); + const char16_t *strings[] = { userName.get(), dispHost.get() }; + bundle->FormatStringFromName(u"EnterPasswordFor", + strings, 2, getter_Copies(nsmessage)); + } + } else { + g_warning("Unknown mount operation request (flags: %x)", flags); + } + + if (nsmessage.IsEmpty()) { + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + return; + } + // Prompt the user... + nsresult rv; + bool retval = false; + char16_t *user = nullptr, *pass = nullptr; + if (default_user) { + // user will be freed by PromptUsernameAndPassword + user = ToNewUnicode(NS_ConvertUTF8toUTF16(default_user)); + } + if (flags & G_ASK_PASSWORD_NEED_USERNAME) { + rv = prompt->PromptUsernameAndPassword(nullptr, nsmessage.get(), + key.get(), + nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, + &user, &pass, &retval); + } else { + rv = prompt->PromptPassword(nullptr, nsmessage.get(), + key.get(), + nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, + &pass, &retval); + } + if (NS_FAILED(rv) || !retval) { // was || user == '\0' || pass == '\0' + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); + free(user); + free(pass); + return; + } + /* GIO should accept UTF8 */ + g_mount_operation_set_username(mount_op, NS_ConvertUTF16toUTF8(user).get()); + g_mount_operation_set_password(mount_op, NS_ConvertUTF16toUTF8(pass).get()); + free(user); + free(pass); + g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_HANDLED); +} + +//----------------------------------------------------------------------------- + +class nsGIOProtocolHandler final : public nsIProtocolHandler + , public nsIObserver +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPROTOCOLHANDLER + NS_DECL_NSIOBSERVER + + nsresult Init(); + + private: + ~nsGIOProtocolHandler() {} + + void InitSupportedProtocolsPref(nsIPrefBranch *prefs); + bool IsSupportedProtocol(const nsCString &spec); + + nsCString mSupportedProtocols; +}; + +NS_IMPL_ISUPPORTS(nsGIOProtocolHandler, nsIProtocolHandler, nsIObserver) + +nsresult +nsGIOProtocolHandler::Init() +{ + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) + { + InitSupportedProtocolsPref(prefs); + prefs->AddObserver(MOZ_GIO_SUPPORTED_PROTOCOLS, this, false); + } + + return NS_OK; +} + +void +nsGIOProtocolHandler::InitSupportedProtocolsPref(nsIPrefBranch *prefs) +{ + // Get user preferences to determine which protocol is supported. + // Gvfs/GIO has a set of supported protocols like obex, network, archive, + // computer, dav, cdda, gphoto2, trash, etc. Some of these seems to be + // irrelevant to process by browser. By default accept only smb and sftp + // protocols so far. + nsresult rv = prefs->GetCharPref(MOZ_GIO_SUPPORTED_PROTOCOLS, + getter_Copies(mSupportedProtocols)); + if (NS_SUCCEEDED(rv)) { + mSupportedProtocols.StripWhitespace(); + ToLowerCase(mSupportedProtocols); + } + else + mSupportedProtocols.AssignLiteral("smb:,sftp:"); // use defaults + + LOG(("gio: supported protocols \"%s\"\n", mSupportedProtocols.get())); +} + +bool +nsGIOProtocolHandler::IsSupportedProtocol(const nsCString &aSpec) +{ + const char *specString = aSpec.get(); + const char *colon = strchr(specString, ':'); + if (!colon) + return false; + + uint32_t length = colon - specString + 1; + + // + ':' + nsCString scheme(specString, length); + + char *found = PL_strcasestr(mSupportedProtocols.get(), scheme.get()); + if (!found) + return false; + + if (found[length] != ',' && found[length] != '\0') + return false; + + return true; +} + +NS_IMETHODIMP +nsGIOProtocolHandler::GetScheme(nsACString &aScheme) +{ + aScheme.Assign(MOZ_GIO_SCHEME); + return NS_OK; +} + +NS_IMETHODIMP +nsGIOProtocolHandler::GetDefaultPort(int32_t *aDefaultPort) +{ + *aDefaultPort = -1; + return NS_OK; +} + +NS_IMETHODIMP +nsGIOProtocolHandler::GetProtocolFlags(uint32_t *aProtocolFlags) +{ + // Is URI_STD true of all GnomeVFS URI types? + *aProtocolFlags = URI_STD | URI_DANGEROUS_TO_LOAD; + return NS_OK; +} + +NS_IMETHODIMP +nsGIOProtocolHandler::NewURI(const nsACString &aSpec, + const char *aOriginCharset, + nsIURI *aBaseURI, + nsIURI **aResult) +{ + const nsCString flatSpec(aSpec); + LOG(("gio: NewURI [spec=%s]\n", flatSpec.get())); + + if (!aBaseURI) + { + // XXX Is it good to support all GIO protocols? + if (!IsSupportedProtocol(flatSpec)) + return NS_ERROR_UNKNOWN_PROTOCOL; + + int32_t colon_location = flatSpec.FindChar(':'); + if (colon_location <= 0) + return NS_ERROR_UNKNOWN_PROTOCOL; + + // Verify that GIO supports this URI scheme. + bool uri_scheme_supported = false; + + GVfs *gvfs = g_vfs_get_default(); + + if (!gvfs) { + g_warning("Cannot get GVfs object."); + return NS_ERROR_UNKNOWN_PROTOCOL; + } + + const gchar* const * uri_schemes = g_vfs_get_supported_uri_schemes(gvfs); + + while (*uri_schemes != nullptr) { + // While flatSpec ends with ':' the uri_scheme does not. Therefore do not + // compare last character. + if (StringHead(flatSpec, colon_location).Equals(*uri_schemes)) { + uri_scheme_supported = true; + break; + } + uri_schemes++; + } + + if (!uri_scheme_supported) { + return NS_ERROR_UNKNOWN_PROTOCOL; + } + } + + nsresult rv; + nsCOMPtr url = + do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, flatSpec, + aOriginCharset, aBaseURI); + if (NS_SUCCEEDED(rv)) + rv = CallQueryInterface(url, aResult); + return rv; + +} + +NS_IMETHODIMP +nsGIOProtocolHandler::NewChannel2(nsIURI* aURI, + nsILoadInfo* aLoadInfo, + nsIChannel** aResult) +{ + NS_ENSURE_ARG_POINTER(aURI); + nsresult rv; + + nsAutoCString spec; + rv = aURI->GetSpec(spec); + if (NS_FAILED(rv)) + return rv; + + RefPtr stream = new nsGIOInputStream(spec); + if (!stream) { + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = NS_NewInputStreamChannelInternal(aResult, + aURI, + stream, + NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE), + EmptyCString(), // aContentCharset + aLoadInfo); + if (NS_SUCCEEDED(rv)) { + stream->SetChannel(*aResult); + } + return rv; +} + +NS_IMETHODIMP +nsGIOProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **aResult) +{ + return NewChannel2(aURI, nullptr, aResult); +} + +NS_IMETHODIMP +nsGIOProtocolHandler::AllowPort(int32_t aPort, + const char *aScheme, + bool *aResult) +{ + // Don't override anything. + *aResult = false; + return NS_OK; +} + +NS_IMETHODIMP +nsGIOProtocolHandler::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + if (strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) { + nsCOMPtr prefs = do_QueryInterface(aSubject); + InitSupportedProtocolsPref(prefs); + } + return NS_OK; +} + +//----------------------------------------------------------------------------- + +#define NS_GIOPROTOCOLHANDLER_CID \ +{ /* ee706783-3af8-4d19-9e84-e2ebfe213480 */ \ + 0xee706783, \ + 0x3af8, \ + 0x4d19, \ + {0x9e, 0x84, 0xe2, 0xeb, 0xfe, 0x21, 0x34, 0x80} \ +} + +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGIOProtocolHandler, Init) +NS_DEFINE_NAMED_CID(NS_GIOPROTOCOLHANDLER_CID); + +static const mozilla::Module::CIDEntry kVFSCIDs[] = { + { &kNS_GIOPROTOCOLHANDLER_CID, false, nullptr, nsGIOProtocolHandlerConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kVFSContracts[] = { + { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX MOZ_GIO_SCHEME, &kNS_GIOPROTOCOLHANDLER_CID }, + { nullptr } +}; + +static const mozilla::Module kVFSModule = { + mozilla::Module::kVersion, + kVFSCIDs, + kVFSContracts +}; + +NSMODULE_DEFN(nsGIOModule) = &kVFSModule; diff --git a/extensions/moz.build b/extensions/moz.build new file mode 100644 index 000000000..39cdb8765 --- /dev/null +++ b/extensions/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += CONFIG['MOZ_EXTENSIONS'] diff --git a/extensions/moz.configure b/extensions/moz.configure new file mode 100644 index 000000000..568f361a5 --- /dev/null +++ b/extensions/moz.configure @@ -0,0 +1,5 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/extensions/permissions/moz.build b/extensions/permissions/moz.build new file mode 100644 index 000000000..401f01848 --- /dev/null +++ b/extensions/permissions/moz.build @@ -0,0 +1,12 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'nsContentBlocker.cpp', + 'nsModuleFactory.cpp', +] + +FINAL_LIBRARY = 'xul' diff --git a/extensions/permissions/nsContentBlocker.cpp b/extensions/permissions/nsContentBlocker.cpp new file mode 100644 index 000000000..cc2162b70 --- /dev/null +++ b/extensions/permissions/nsContentBlocker.cpp @@ -0,0 +1,377 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsContentBlocker.h" +#include "nsIContent.h" +#include "nsIURI.h" +#include "nsIServiceManager.h" +#include "nsIDocShellTreeItem.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIDocShell.h" +#include "nsString.h" +#include "nsContentPolicyUtils.h" +#include "nsIObjectLoadingContent.h" +#include "mozilla/ArrayUtils.h" +#include "nsContentUtils.h" + +// Possible behavior pref values +// Those map to the nsIPermissionManager values where possible +#define BEHAVIOR_ACCEPT nsIPermissionManager::ALLOW_ACTION +#define BEHAVIOR_REJECT nsIPermissionManager::DENY_ACTION +#define BEHAVIOR_NOFOREIGN 3 + +// From nsIContentPolicy +static const char *kTypeString[] = { + "other", + "script", + "image", + "stylesheet", + "object", + "document", + "subdocument", + "refresh", + "xbl", + "ping", + "xmlhttprequest", + "objectsubrequest", + "dtd", + "font", + "media", + "websocket", + "csp_report", + "xslt", + "beacon", + "fetch", + "image", + "manifest", + "", // TYPE_INTERNAL_SCRIPT + "", // TYPE_INTERNAL_WORKER + "", // TYPE_INTERNAL_SHARED_WORKER + "", // TYPE_INTERNAL_EMBED + "", // TYPE_INTERNAL_OBJECT + "", // TYPE_INTERNAL_FRAME + "", // TYPE_INTERNAL_IFRAME + "", // TYPE_INTERNAL_AUDIO + "", // TYPE_INTERNAL_VIDEO + "", // TYPE_INTERNAL_TRACK + "", // TYPE_INTERNAL_XMLHTTPREQUEST + "", // TYPE_INTERNAL_EVENTSOURCE + "", // TYPE_INTERNAL_SERVICE_WORKER +}; + +#define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString) +uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES]; + +NS_IMPL_ISUPPORTS(nsContentBlocker, + nsIContentPolicy, + nsIObserver, + nsISupportsWeakReference) + +nsContentBlocker::nsContentBlocker() +{ + memset(mBehaviorPref, BEHAVIOR_ACCEPT, NUMBER_OF_TYPES); +} + +nsresult +nsContentBlocker::Init() +{ + nsresult rv; + mPermissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr prefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr prefBranch; + rv = prefService->GetBranch("permissions.default.", getter_AddRefs(prefBranch)); + NS_ENSURE_SUCCESS(rv, rv); + + // Migrate old image blocker pref + nsCOMPtr oldPrefBranch; + oldPrefBranch = do_QueryInterface(prefService); + int32_t oldPref; + rv = oldPrefBranch->GetIntPref("network.image.imageBehavior", &oldPref); + if (NS_SUCCEEDED(rv) && oldPref) { + int32_t newPref; + switch (oldPref) { + default: + newPref = BEHAVIOR_ACCEPT; + break; + case 1: + newPref = BEHAVIOR_NOFOREIGN; + break; + case 2: + newPref = BEHAVIOR_REJECT; + break; + } + prefBranch->SetIntPref("image", newPref); + oldPrefBranch->ClearUserPref("network.image.imageBehavior"); + } + + + // The branch is not a copy of the prefservice, but a new object, because + // it is a non-default branch. Adding obeservers to it will only work if + // we make sure that the object doesn't die. So, keep a reference to it. + mPrefBranchInternal = do_QueryInterface(prefBranch, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mPrefBranchInternal->AddObserver("", this, true); + PrefChanged(prefBranch, nullptr); + + return rv; +} + +#undef LIMIT +#define LIMIT(x, low, high, default) ((x) >= (low) && (x) <= (high) ? (x) : (default)) + +void +nsContentBlocker::PrefChanged(nsIPrefBranch *aPrefBranch, + const char *aPref) +{ + int32_t val; + +#define PREF_CHANGED(_P) (!aPref || !strcmp(aPref, _P)) + + for(uint32_t i = 0; i < NUMBER_OF_TYPES; ++i) { + if (*kTypeString[i] && + PREF_CHANGED(kTypeString[i]) && + NS_SUCCEEDED(aPrefBranch->GetIntPref(kTypeString[i], &val))) + mBehaviorPref[i] = LIMIT(val, 1, 3, 1); + } + +} + +// nsIContentPolicy Implementation +NS_IMETHODIMP +nsContentBlocker::ShouldLoad(uint32_t aContentType, + nsIURI *aContentLocation, + nsIURI *aRequestingLocation, + nsISupports *aRequestingContext, + const nsACString &aMimeGuess, + nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, + int16_t *aDecision) +{ + MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), + "We should only see external content policy types here."); + + *aDecision = nsIContentPolicy::ACCEPT; + nsresult rv; + + // Ony support NUMBER_OF_TYPES content types. that all there is at the + // moment, but you never know... + if (aContentType > NUMBER_OF_TYPES) + return NS_OK; + + // we can't do anything without this + if (!aContentLocation) + return NS_OK; + + // The final type of an object tag may mutate before it reaches + // shouldProcess, so we cannot make any sane blocking decisions here + if (aContentType == nsIContentPolicy::TYPE_OBJECT) + return NS_OK; + + // we only want to check http, https, ftp + // for chrome:// and resources and others, no need to check. + nsAutoCString scheme; + aContentLocation->GetScheme(scheme); + if (!scheme.LowerCaseEqualsLiteral("ftp") && + !scheme.LowerCaseEqualsLiteral("http") && + !scheme.LowerCaseEqualsLiteral("https")) + return NS_OK; + + bool shouldLoad, fromPrefs; + rv = TestPermission(aContentLocation, aRequestingLocation, aContentType, + &shouldLoad, &fromPrefs); + NS_ENSURE_SUCCESS(rv, rv); + if (!shouldLoad) { + if (fromPrefs) { + *aDecision = nsIContentPolicy::REJECT_TYPE; + } else { + *aDecision = nsIContentPolicy::REJECT_SERVER; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsContentBlocker::ShouldProcess(uint32_t aContentType, + nsIURI *aContentLocation, + nsIURI *aRequestingLocation, + nsISupports *aRequestingContext, + const nsACString &aMimeGuess, + nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, + int16_t *aDecision) +{ + MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), + "We should only see external content policy types here."); + + // For loads where aRequestingContext is chrome, we should just + // accept. Those are most likely toplevel loads in windows, and + // chrome generally knows what it's doing anyway. + nsCOMPtr item = + do_QueryInterface(NS_CP_GetDocShellFromContext(aRequestingContext)); + + if (item && item->ItemType() == nsIDocShellTreeItem::typeChrome) { + *aDecision = nsIContentPolicy::ACCEPT; + return NS_OK; + } + + // For objects, we only check policy in shouldProcess, as the final type isn't + // determined until the channel is open -- We don't want to block images in + // object tags because plugins are disallowed. + // NOTE that this bypasses the aContentLocation checks in ShouldLoad - this is + // intentional, as aContentLocation may be null for plugins that load by type + // (e.g. java) + if (aContentType == nsIContentPolicy::TYPE_OBJECT) { + *aDecision = nsIContentPolicy::ACCEPT; + + bool shouldLoad, fromPrefs; + nsresult rv = TestPermission(aContentLocation, aRequestingLocation, + aContentType, &shouldLoad, &fromPrefs); + NS_ENSURE_SUCCESS(rv, rv); + if (!shouldLoad) { + if (fromPrefs) { + *aDecision = nsIContentPolicy::REJECT_TYPE; + } else { + *aDecision = nsIContentPolicy::REJECT_SERVER; + } + } + return NS_OK; + } + + // This isn't a load from chrome or an object tag - Just do a ShouldLoad() + // check -- we want the same answer here + return ShouldLoad(aContentType, aContentLocation, aRequestingLocation, + aRequestingContext, aMimeGuess, aExtra, aRequestPrincipal, + aDecision); +} + +nsresult +nsContentBlocker::TestPermission(nsIURI *aCurrentURI, + nsIURI *aFirstURI, + int32_t aContentType, + bool *aPermission, + bool *aFromPrefs) +{ + *aFromPrefs = false; + + if (!*kTypeString[aContentType - 1]) { + // Disallow internal content policy types, they should not be used here. + *aPermission = false; + return NS_OK; + } + + // This default will also get used if there is an unknown value in the + // permission list, or if the permission manager returns unknown values. + *aPermission = true; + + // check the permission list first; if we find an entry, it overrides + // default prefs. + // Don't forget the aContentType ranges from 1..8, while the + // array is indexed 0..7 + uint32_t permission; + nsresult rv = mPermissionManager->TestPermission(aCurrentURI, + kTypeString[aContentType - 1], + &permission); + NS_ENSURE_SUCCESS(rv, rv); + + // If there is nothing on the list, use the default. + if (!permission) { + permission = mBehaviorPref[aContentType - 1]; + *aFromPrefs = true; + } + + // Use the fact that the nsIPermissionManager values map to + // the BEHAVIOR_* values above. + switch (permission) { + case BEHAVIOR_ACCEPT: + *aPermission = true; + break; + case BEHAVIOR_REJECT: + *aPermission = false; + break; + + case BEHAVIOR_NOFOREIGN: + // Third party checking + + // Need a requesting uri for third party checks to work. + if (!aFirstURI) + return NS_OK; + + bool trustedSource = false; + rv = aFirstURI->SchemeIs("chrome", &trustedSource); + NS_ENSURE_SUCCESS(rv,rv); + if (!trustedSource) { + rv = aFirstURI->SchemeIs("resource", &trustedSource); + NS_ENSURE_SUCCESS(rv,rv); + } + if (trustedSource) + return NS_OK; + + // compare tails of names checking to see if they have a common domain + // we do this by comparing the tails of both names where each tail + // includes at least one dot + + // A more generic method somewhere would be nice + + nsAutoCString currentHost; + rv = aCurrentURI->GetAsciiHost(currentHost); + NS_ENSURE_SUCCESS(rv, rv); + + // Search for two dots, starting at the end. + // If there are no two dots found, ++dot will turn to zero, + // that will return the entire string. + int32_t dot = currentHost.RFindChar('.'); + dot = currentHost.RFindChar('.', dot-1); + ++dot; + + // Get the domain, ie the last part of the host (www.domain.com -> domain.com) + // This will break on co.uk + const nsCSubstring &tail = + Substring(currentHost, dot, currentHost.Length() - dot); + + nsAutoCString firstHost; + rv = aFirstURI->GetAsciiHost(firstHost); + NS_ENSURE_SUCCESS(rv, rv); + + // If the tail is longer then the whole firstHost, it will never match + if (firstHost.Length() < tail.Length()) { + *aPermission = false; + return NS_OK; + } + + // Get the last part of the firstUri with the same length as |tail| + const nsCSubstring &firstTail = + Substring(firstHost, firstHost.Length() - tail.Length(), tail.Length()); + + // Check that both tails are the same, and that just before the tail in + // |firstUri| there is a dot. That means both url are in the same domain + if ((firstHost.Length() > tail.Length() && + firstHost.CharAt(firstHost.Length() - tail.Length() - 1) != '.') || + !tail.Equals(firstTail)) { + *aPermission = false; + } + break; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsContentBlocker::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + NS_ASSERTION(!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic), + "unexpected topic - we only deal with pref changes!"); + + if (mPrefBranchInternal) + PrefChanged(mPrefBranchInternal, NS_LossyConvertUTF16toASCII(aData).get()); + return NS_OK; +} diff --git a/extensions/permissions/nsContentBlocker.h b/extensions/permissions/nsContentBlocker.h new file mode 100644 index 000000000..880300952 --- /dev/null +++ b/extensions/permissions/nsContentBlocker.h @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef nsContentBlocker_h__ +#define nsContentBlocker_h__ + +#include "nsIContentPolicy.h" +#include "nsIObserver.h" +#include "nsWeakReference.h" +#include "nsIPermissionManager.h" +#include "nsIPrefBranch.h" +#include "mozilla/Attributes.h" + +class nsIPrefBranch; + +//////////////////////////////////////////////////////////////////////////////// + +class nsContentBlocker final : public nsIContentPolicy, + public nsIObserver, + public nsSupportsWeakReference +{ +public: + + // nsISupports + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPOLICY + NS_DECL_NSIOBSERVER + + nsContentBlocker(); + nsresult Init(); + +private: + ~nsContentBlocker() {} + + void PrefChanged(nsIPrefBranch *, const char *); + nsresult TestPermission(nsIURI *aCurrentURI, + nsIURI *aFirstURI, + int32_t aContentType, + bool *aPermission, + bool *aFromPrefs); + + nsCOMPtr mPermissionManager; + nsCOMPtr mPrefBranchInternal; + static uint8_t mBehaviorPref[]; +}; + +#define NS_CONTENTBLOCKER_CID \ +{ 0x4ca6b67b, 0x5cc7, 0x4e71, \ + { 0xa9, 0x8a, 0x97, 0xaf, 0x1c, 0x13, 0x48, 0x62 } } + +#define NS_CONTENTBLOCKER_CONTRACTID "@mozilla.org/permissions/contentblocker;1" + +#endif /* nsContentBlocker_h__ */ diff --git a/extensions/permissions/nsModuleFactory.cpp b/extensions/permissions/nsModuleFactory.cpp new file mode 100644 index 000000000..a8917c463 --- /dev/null +++ b/extensions/permissions/nsModuleFactory.cpp @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ModuleUtils.h" +#include "nsIServiceManager.h" +#include "nsContentBlocker.h" +#include "nsXPIDLString.h" + +// Define the constructor function for the objects +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsContentBlocker, Init) + +NS_DEFINE_NAMED_CID(NS_CONTENTBLOCKER_CID); + +static const mozilla::Module::CIDEntry kPermissionsCIDs[] = { + { &kNS_CONTENTBLOCKER_CID, false, nullptr, nsContentBlockerConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kPermissionsContracts[] = { + { NS_CONTENTBLOCKER_CONTRACTID, &kNS_CONTENTBLOCKER_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kPermissionsCategories[] = { + { "content-policy", NS_CONTENTBLOCKER_CONTRACTID, NS_CONTENTBLOCKER_CONTRACTID }, + { nullptr } +}; + +static const mozilla::Module kPermissionsModule = { + mozilla::Module::kVersion, + kPermissionsCIDs, + kPermissionsContracts, + kPermissionsCategories +}; + +NSMODULE_DEFN(nsPermissionsModule) = &kPermissionsModule; diff --git a/extensions/pref/autoconfig/moz.build b/extensions/pref/autoconfig/moz.build new file mode 100644 index 000000000..632913a1c --- /dev/null +++ b/extensions/pref/autoconfig/moz.build @@ -0,0 +1,9 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['public', 'src'] + +XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini'] diff --git a/extensions/pref/autoconfig/public/moz.build b/extensions/pref/autoconfig/public/moz.build new file mode 100644 index 000000000..467f0c475 --- /dev/null +++ b/extensions/pref/autoconfig/public/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +XPIDL_SOURCES += [ + 'nsIAutoConfig.idl', + 'nsIReadConfig.idl', +] + +XPIDL_MODULE = 'autoconfig' + diff --git a/extensions/pref/autoconfig/public/nsIAutoConfig.idl b/extensions/pref/autoconfig/public/nsIAutoConfig.idl new file mode 100644 index 000000000..e76dc0614 --- /dev/null +++ b/extensions/pref/autoconfig/public/nsIAutoConfig.idl @@ -0,0 +1,26 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + + +%{C++ + +#define NS_AUTOCONFIG_CID\ + { 0xe036c738,\ + 0x1dd1,\ + 0x11b2,\ + { 0x93, 0x92, 0x9d, 0x94, 0xaa, 0x74, 0xb0, 0xc5 }\ + } + +#define NS_AUTOCONFIG_CONTRACTID \ + "@mozilla.org/autoconfiguration;1" + +%} + +[uuid (80DB54AE-13F2-11d5-BE44-00108335A220)] +interface nsIAutoConfig : nsISupports { + attribute string configURL; +}; diff --git a/extensions/pref/autoconfig/public/nsIReadConfig.idl b/extensions/pref/autoconfig/public/nsIReadConfig.idl new file mode 100644 index 000000000..e00c06e52 --- /dev/null +++ b/extensions/pref/autoconfig/public/nsIReadConfig.idl @@ -0,0 +1,24 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +%{C++ + +#define NS_READCONFIG_CID\ + { 0xba5bc4c6,\ + 0x1dd1, \ + 0x11b2, \ + { 0xbb, 0x89, 0xb8, 0x44, 0xc6, 0xec, 0x03, 0x39 }\ + } + +#define NS_READCONFIG_CONTRACTID \ + "@mozilla.org/readconfig;1" + +%} + +[uuid (ba5bc4c6-1dd1-11b2-bb89-b844c6ec0339)] +interface nsIReadConfig : nsISupports { +}; diff --git a/extensions/pref/autoconfig/src/moz.build b/extensions/pref/autoconfig/src/moz.build new file mode 100644 index 000000000..3417269f0 --- /dev/null +++ b/extensions/pref/autoconfig/src/moz.build @@ -0,0 +1,18 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'nsAutoConfig.cpp', + 'nsConfigFactory.cpp', + 'nsJSConfigTriggers.cpp', + 'nsReadConfig.cpp', +] + +FINAL_LIBRARY = 'xul' + +FINAL_TARGET_FILES.defaults.autoconfig += [ + 'prefcalls.js', +] diff --git a/extensions/pref/autoconfig/src/nsAutoConfig.cpp b/extensions/pref/autoconfig/src/nsAutoConfig.cpp new file mode 100644 index 000000000..08f406093 --- /dev/null +++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp @@ -0,0 +1,532 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsAutoConfig.h" +#include "nsIURI.h" +#include "nsIHttpChannel.h" +#include "nsIFileStreams.h" +#include "nsThreadUtils.h" +#include "nsAppDirectoryServiceDefs.h" +#include "prmem.h" +#include "nsIObserverService.h" +#include "nsLiteralString.h" +#include "nsIPromptService.h" +#include "nsIServiceManager.h" +#include "nsIStringBundle.h" +#include "nsContentUtils.h" +#include "nsCRT.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nspr.h" +#include + +#include "mozilla/Logging.h" + +using mozilla::LogLevel; + +mozilla::LazyLogModule MCD("MCD"); + +extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length, + const char *filename, + bool bGlobalContext, + bool bCallbacks, + bool skipFirstLine); + +// nsISupports Implementation + +NS_IMPL_ISUPPORTS(nsAutoConfig, nsIAutoConfig, nsITimerCallback, nsIStreamListener, nsIObserver, nsIRequestObserver, nsISupportsWeakReference) + +nsAutoConfig::nsAutoConfig() +{ +} + +nsresult nsAutoConfig::Init() +{ + // member initializers and constructor code + + nsresult rv; + mLoaded = false; + + // Registering the object as an observer to the profile-after-change topic + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_FAILED(rv)) + return rv; + + rv = observerService->AddObserver(this,"profile-after-change", true); + + return rv; +} + +nsAutoConfig::~nsAutoConfig() +{ +} + +// attribute string configURL +NS_IMETHODIMP nsAutoConfig::GetConfigURL(char **aConfigURL) +{ + if (!aConfigURL) + return NS_ERROR_NULL_POINTER; + + if (mConfigURL.IsEmpty()) { + *aConfigURL = nullptr; + return NS_OK; + } + + *aConfigURL = ToNewCString(mConfigURL); + if (!*aConfigURL) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} +NS_IMETHODIMP nsAutoConfig::SetConfigURL(const char *aConfigURL) +{ + if (!aConfigURL) + return NS_ERROR_NULL_POINTER; + mConfigURL.Assign(aConfigURL); + return NS_OK; +} + +NS_IMETHODIMP +nsAutoConfig::OnStartRequest(nsIRequest *request, nsISupports *context) +{ + return NS_OK; +} + + +NS_IMETHODIMP +nsAutoConfig::OnDataAvailable(nsIRequest *request, + nsISupports *context, + nsIInputStream *aIStream, + uint64_t aSourceOffset, + uint32_t aLength) +{ + uint32_t amt, size; + nsresult rv; + char buf[1024]; + + while (aLength) { + size = std::min(aLength, sizeof(buf)); + rv = aIStream->Read(buf, size, &amt); + if (NS_FAILED(rv)) + return rv; + mBuf.Append(buf, amt); + aLength -= amt; + } + return NS_OK; +} + + +NS_IMETHODIMP +nsAutoConfig::OnStopRequest(nsIRequest *request, nsISupports *context, + nsresult aStatus) +{ + nsresult rv; + + // If the request is failed, go read the failover.jsc file + if (NS_FAILED(aStatus)) { + MOZ_LOG(MCD, LogLevel::Debug, ("mcd request failed with status %x\n", aStatus)); + return readOfflineFile(); + } + + // Checking for the http response, if failure go read the failover file. + nsCOMPtr pHTTPCon(do_QueryInterface(request)); + if (pHTTPCon) { + uint32_t httpStatus; + pHTTPCon->GetResponseStatus(&httpStatus); + if (httpStatus != 200) + { + MOZ_LOG(MCD, LogLevel::Debug, ("mcd http request failed with status %x\n", httpStatus)); + return readOfflineFile(); + } + } + + // Send the autoconfig.jsc to javascript engine. + + rv = EvaluateAdminConfigScript(mBuf.get(), mBuf.Length(), + nullptr, false,true, false); + if (NS_SUCCEEDED(rv)) { + + // Write the autoconfig.jsc to failover.jsc (cached copy) + rv = writeFailoverFile(); + + if (NS_FAILED(rv)) + NS_WARNING("Error writing failover.jsc file"); + + // Releasing the lock to allow the main thread to start execution + mLoaded = true; + + return NS_OK; + } + // there is an error in parsing of the autoconfig file. + NS_WARNING("Error reading autoconfig.jsc from the network, reading the offline version"); + return readOfflineFile(); +} + +// Notify method as a TimerCallBack function +NS_IMETHODIMP nsAutoConfig::Notify(nsITimer *timer) +{ + downloadAutoConfig(); + return NS_OK; +} + +/* Observe() is called twice: once at the instantiation time and other + after the profile is set. It doesn't do anything but return NS_OK during the + creation time. Second time it calls downloadAutoConfig(). +*/ + +NS_IMETHODIMP nsAutoConfig::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *someData) +{ + nsresult rv = NS_OK; + if (!nsCRT::strcmp(aTopic, "profile-after-change")) { + + // We will be calling downloadAutoConfig even if there is no profile + // name. Nothing will be passed as a parameter to the URL and the + // default case will be picked up by the script. + + rv = downloadAutoConfig(); + + } + + return rv; +} + +nsresult nsAutoConfig::downloadAutoConfig() +{ + nsresult rv; + nsAutoCString emailAddr; + nsXPIDLCString urlName; + static bool firstTime = true; + + if (mConfigURL.IsEmpty()) { + MOZ_LOG(MCD, LogLevel::Debug, ("global config url is empty - did you set autoadmin.global_config_url?\n")); + NS_WARNING("AutoConfig called without global_config_url"); + return NS_OK; + } + + // If there is an email address appended as an argument to the ConfigURL + // in the previous read, we need to remove it when timer kicks in and + // downloads the autoconfig file again. + // If necessary, the email address will be added again as an argument. + int32_t index = mConfigURL.RFindChar((char16_t)'?'); + if (index != -1) + mConfigURL.Truncate(index); + + // Clean up the previous read, the new read is going to use the same buffer + if (!mBuf.IsEmpty()) + mBuf.Truncate(0); + + // Get the preferences branch and save it to the member variable + if (!mPrefBranch) { + nsCOMPtr prefs = + do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = prefs->GetBranch(nullptr,getter_AddRefs(mPrefBranch)); + if (NS_FAILED(rv)) + return rv; + } + + // Check to see if the network is online/offline + nsCOMPtr ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + bool offline; + rv = ios->GetOffline(&offline); + if (NS_FAILED(rv)) + return rv; + + if (offline) { + bool offlineFailover; + rv = mPrefBranch->GetBoolPref("autoadmin.offline_failover", + &offlineFailover); + // Read the failover.jsc if the network is offline and the pref says so + if (NS_SUCCEEDED(rv) && offlineFailover) + return readOfflineFile(); + } + + /* Append user's identity at the end of the URL if the pref says so. + First we are checking for the user's email address but if it is not + available in the case where the client is used without messenger, user's + profile name will be used as an unique identifier + */ + bool appendMail; + rv = mPrefBranch->GetBoolPref("autoadmin.append_emailaddr", &appendMail); + if (NS_SUCCEEDED(rv) && appendMail) { + rv = getEmailAddr(emailAddr); + if (NS_SUCCEEDED(rv) && emailAddr.get()) { + /* Adding the unique identifier at the end of autoconfig URL. + In this case the autoconfig URL is a script and + emailAddr as passed as an argument + */ + mConfigURL.Append('?'); + mConfigURL.Append(emailAddr); + } + } + + // create a new url + nsCOMPtr url; + nsCOMPtr channel; + + rv = NS_NewURI(getter_AddRefs(url), mConfigURL.get(), nullptr, nullptr); + if (NS_FAILED(rv)) + { + MOZ_LOG(MCD, LogLevel::Debug, ("failed to create URL - is autoadmin.global_config_url valid? - %s\n", mConfigURL.get())); + return rv; + } + + MOZ_LOG(MCD, LogLevel::Debug, ("running MCD url %s\n", mConfigURL.get())); + // open a channel for the url + rv = NS_NewChannel(getter_AddRefs(channel), + url, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, + nsIContentPolicy::TYPE_OTHER, + nullptr, // loadGroup + nullptr, // aCallbacks + nsIRequest::INHIBIT_PERSISTENT_CACHING | + nsIRequest::LOAD_BYPASS_CACHE); + + if (NS_FAILED(rv)) + return rv; + + rv = channel->AsyncOpen2(this); + if (NS_FAILED(rv)) { + readOfflineFile(); + return rv; + } + + // Set a repeating timer if the pref is set. + // This is to be done only once. + // Also We are having the event queue processing only for the startup + // It is not needed with the repeating timer. + if (firstTime) { + firstTime = false; + + // Getting the current thread. If we start an AsyncOpen, the thread + // needs to wait before the reading of autoconfig is done + + nsCOMPtr thread = do_GetCurrentThread(); + NS_ENSURE_STATE(thread); + + /* process events until we're finished. AutoConfig.jsc reading needs + to be finished before the browser starts loading up + We are waiting for the mLoaded which will be set through + onStopRequest or readOfflineFile methods + There is a possibility of deadlock so we need to make sure + that mLoaded will be set to true in any case (success/failure) + */ + + while (!mLoaded) + NS_ENSURE_STATE(NS_ProcessNextEvent(thread)); + + int32_t minutes; + rv = mPrefBranch->GetIntPref("autoadmin.refresh_interval", + &minutes); + if (NS_SUCCEEDED(rv) && minutes > 0) { + // Create a new timer and pass this nsAutoConfig + // object as a timer callback. + mTimer = do_CreateInstance("@mozilla.org/timer;1",&rv); + if (NS_FAILED(rv)) + return rv; + rv = mTimer->InitWithCallback(this, minutes * 60 * 1000, + nsITimer::TYPE_REPEATING_SLACK); + if (NS_FAILED(rv)) + return rv; + } + } //first_time + + return NS_OK; +} // nsPref::downloadAutoConfig() + + + +nsresult nsAutoConfig::readOfflineFile() +{ + nsresult rv; + + /* Releasing the lock to allow main thread to start + execution. At this point we do not need to stall + the thread since all network activities are done. + */ + mLoaded = true; + + bool failCache; + rv = mPrefBranch->GetBoolPref("autoadmin.failover_to_cached", &failCache); + if (NS_SUCCEEDED(rv) && !failCache) { + // disable network connections and return. + + nsCOMPtr ios = + do_GetService(NS_IOSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + bool offline; + rv = ios->GetOffline(&offline); + if (NS_FAILED(rv)) + return rv; + + if (!offline) { + rv = ios->SetOffline(true); + if (NS_FAILED(rv)) + return rv; + } + + // lock the "network.online" prference so user cannot toggle back to + // online mode. + rv = mPrefBranch->SetBoolPref("network.online", false); + if (NS_FAILED(rv)) + return rv; + + mPrefBranch->LockPref("network.online"); + return NS_OK; + } + + /* faiover_to_cached is set to true so + Open the file and read the content. + execute the javascript file + */ + + nsCOMPtr failoverFile; + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(failoverFile)); + if (NS_FAILED(rv)) + return rv; + + failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc")); + rv = evaluateLocalFile(failoverFile); + if (NS_FAILED(rv)) + NS_WARNING("Couldn't open failover.jsc, going back to default prefs"); + return NS_OK; +} + +nsresult nsAutoConfig::evaluateLocalFile(nsIFile *file) +{ + nsresult rv; + nsCOMPtr inStr; + + rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file); + if (NS_FAILED(rv)) + return rv; + + int64_t fileSize; + file->GetFileSize(&fileSize); + uint32_t fs = fileSize; // Converting 64 bit structure to unsigned int + char *buf = (char *)PR_Malloc(fs * sizeof(char)); + if (!buf) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t amt = 0; + rv = inStr->Read(buf, fs, &amt); + if (NS_SUCCEEDED(rv)) { + EvaluateAdminConfigScript(buf, fs, nullptr, false, + true, false); + } + inStr->Close(); + PR_Free(buf); + return rv; +} + +nsresult nsAutoConfig::writeFailoverFile() +{ + nsresult rv; + nsCOMPtr failoverFile; + nsCOMPtr outStr; + uint32_t amt; + + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(failoverFile)); + if (NS_FAILED(rv)) + return rv; + + failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc")); + + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStr), failoverFile); + if (NS_FAILED(rv)) + return rv; + rv = outStr->Write(mBuf.get(),mBuf.Length(),&amt); + outStr->Close(); + return rv; +} + +nsresult nsAutoConfig::getEmailAddr(nsACString & emailAddr) +{ + + nsresult rv; + nsXPIDLCString prefValue; + + /* Getting an email address through set of three preferences: + First getting a default account with + "mail.accountmanager.defaultaccount" + second getting an associated id with the default account + Third getting an email address with id + */ + + rv = mPrefBranch->GetCharPref("mail.accountmanager.defaultaccount", + getter_Copies(prefValue)); + if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty()) { + emailAddr = NS_LITERAL_CSTRING("mail.account.") + + prefValue + NS_LITERAL_CSTRING(".identities"); + rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(), + getter_Copies(prefValue)); + if (NS_FAILED(rv) || prefValue.IsEmpty()) + return PromptForEMailAddress(emailAddr); + int32_t commandIndex = prefValue.FindChar(','); + if (commandIndex != kNotFound) + prefValue.Truncate(commandIndex); + emailAddr = NS_LITERAL_CSTRING("mail.identity.") + + prefValue + NS_LITERAL_CSTRING(".useremail"); + rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(), + getter_Copies(prefValue)); + if (NS_FAILED(rv) || prefValue.IsEmpty()) + return PromptForEMailAddress(emailAddr); + emailAddr = prefValue; + } + else { + // look for 4.x pref in case we just migrated. + rv = mPrefBranch->GetCharPref("mail.identity.useremail", + getter_Copies(prefValue)); + if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty()) + emailAddr = prefValue; + else + PromptForEMailAddress(emailAddr); + } + + return NS_OK; +} + +nsresult nsAutoConfig::PromptForEMailAddress(nsACString &emailAddress) +{ + nsresult rv; + nsCOMPtr promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr bundle; + rv = bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties", + getter_AddRefs(bundle)); + NS_ENSURE_SUCCESS(rv, rv); + + nsXPIDLString title; + rv = bundle->GetStringFromName(u"emailPromptTitle", getter_Copies(title)); + NS_ENSURE_SUCCESS(rv, rv); + + nsXPIDLString err; + rv = bundle->GetStringFromName(u"emailPromptMsg", getter_Copies(err)); + NS_ENSURE_SUCCESS(rv, rv); + bool check = false; + nsXPIDLString emailResult; + bool success; + rv = promptService->Prompt(nullptr, title.get(), err.get(), getter_Copies(emailResult), nullptr, &check, &success); + if (!success) + return NS_ERROR_FAILURE; + NS_ENSURE_SUCCESS(rv, rv); + LossyCopyUTF16toASCII(emailResult, emailAddress); + return NS_OK; +} diff --git a/extensions/pref/autoconfig/src/nsAutoConfig.h b/extensions/pref/autoconfig/src/nsAutoConfig.h new file mode 100644 index 000000000..d805ad184 --- /dev/null +++ b/extensions/pref/autoconfig/src/nsAutoConfig.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAutoConfig_h +#define nsAutoConfig_h + +#include "nsIAutoConfig.h" +#include "nsITimer.h" +#include "nsIFile.h" +#include "nsIObserver.h" +#include "nsIStreamListener.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsWeakReference.h" +#include "nsString.h" + +class nsAutoConfig : public nsIAutoConfig, + public nsITimerCallback, + public nsIStreamListener, + public nsIObserver, + public nsSupportsWeakReference + +{ + public: + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIAUTOCONFIG + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIOBSERVER + NS_DECL_NSITIMERCALLBACK + + nsAutoConfig(); + nsresult Init(); + + protected: + + virtual ~nsAutoConfig(); + nsresult downloadAutoConfig(); + nsresult readOfflineFile(); + nsresult evaluateLocalFile(nsIFile *file); + nsresult writeFailoverFile(); + nsresult getEmailAddr(nsACString & emailAddr); + nsresult PromptForEMailAddress(nsACString &emailAddress); + nsCString mBuf; + nsCOMPtr mPrefBranch; + bool mLoaded; + nsCOMPtr mTimer; + nsCString mConfigURL; +}; + +#endif diff --git a/extensions/pref/autoconfig/src/nsConfigFactory.cpp b/extensions/pref/autoconfig/src/nsConfigFactory.cpp new file mode 100644 index 000000000..89f886b2a --- /dev/null +++ b/extensions/pref/autoconfig/src/nsConfigFactory.cpp @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ModuleUtils.h" +#include "nsAutoConfig.h" +#include "nsReadConfig.h" +#include "nsIAppStartupNotifier.h" + +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAutoConfig, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsReadConfig, Init) + +NS_DEFINE_NAMED_CID(NS_AUTOCONFIG_CID); +NS_DEFINE_NAMED_CID(NS_READCONFIG_CID); + +static const mozilla::Module::CIDEntry kAutoConfigCIDs[] = { + { &kNS_AUTOCONFIG_CID, false, nullptr, nsAutoConfigConstructor }, + { &kNS_READCONFIG_CID, false, nullptr, nsReadConfigConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kAutoConfigContracts[] = { + { NS_AUTOCONFIG_CONTRACTID, &kNS_AUTOCONFIG_CID }, + { NS_READCONFIG_CONTRACTID, &kNS_READCONFIG_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kAutoConfigCategories[] = { + { "pref-config-startup", "ReadConfig Module", NS_READCONFIG_CONTRACTID }, + { nullptr } +}; + +static const mozilla::Module kAutoConfigModule = { + mozilla::Module::kVersion, + kAutoConfigCIDs, + kAutoConfigContracts, + kAutoConfigCategories +}; + +NSMODULE_DEFN(nsAutoConfigModule) = &kAutoConfigModule; diff --git a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp new file mode 100644 index 000000000..87f2bef20 --- /dev/null +++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jsapi.h" +#include "nsIXPConnect.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include "nsString.h" +#include "nsIPrefService.h" +#include "nspr.h" +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "nsContentUtils.h" +#include "nsIScriptSecurityManager.h" +#include "nsJSPrincipals.h" +#include "nsIScriptError.h" +#include "jswrapper.h" + +extern mozilla::LazyLogModule MCD; +using mozilla::AutoSafeJSContext; +using mozilla::dom::AutoJSAPI; + +//***************************************************************************** + +static JS::PersistentRooted autoconfigSb; + +nsresult CentralizedAdminPrefManagerInit() +{ + nsresult rv; + + // If the sandbox is already created, no need to create it again. + if (autoconfigSb.initialized()) + return NS_OK; + + // Grab XPConnect. + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID(), &rv); + if (NS_FAILED(rv)) { + return rv; + } + + // Grab the system principal. + nsCOMPtr principal; + nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(principal)); + + + // Create a sandbox. + AutoSafeJSContext cx; + JS::Rooted sandbox(cx); + rv = xpc->CreateSandbox(cx, principal, sandbox.address()); + NS_ENSURE_SUCCESS(rv, rv); + + // Unwrap, store and root the sandbox. + NS_ENSURE_STATE(sandbox); + autoconfigSb.init(cx, js::UncheckedUnwrap(sandbox)); + + return NS_OK; +} + +nsresult CentralizedAdminPrefManagerFinish() +{ + if (autoconfigSb.initialized()) { + AutoSafeJSContext cx; + autoconfigSb.reset(); + JS_MaybeGC(cx); + } + return NS_OK; +} + +nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length, + const char *filename, bool bGlobalContext, + bool bCallbacks, bool skipFirstLine) +{ + nsresult rv = NS_OK; + + if (skipFirstLine) { + /* In order to protect the privacy of the JavaScript preferences file + * from loading by the browser, we make the first line unparseable + * by JavaScript. We must skip that line here before executing + * the JavaScript code. + */ + unsigned int i = 0; + while (i < length) { + char c = js_buffer[i++]; + if (c == '\r') { + if (js_buffer[i] == '\n') + i++; + break; + } + if (c == '\n') + break; + } + + length -= i; + js_buffer += i; + } + + // Grab XPConnect. + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID(), &rv); + if (NS_FAILED(rv)) { + return rv; + } + + AutoJSAPI jsapi; + if (!jsapi.Init(autoconfigSb)) { + return NS_ERROR_UNEXPECTED; + } + JSContext* cx = jsapi.cx(); + + nsAutoCString script(js_buffer, length); + JS::RootedValue v(cx); + + nsString convertedScript; + bool isUTF8 = IsUTF8(script); + if (isUTF8) { + convertedScript = NS_ConvertUTF8toUTF16(script); + } else { + nsContentUtils::ReportToConsoleNonLocalized( + NS_LITERAL_STRING("Your AutoConfig file is ASCII. Please convert it to UTF-8."), + nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("autoconfig"), + nullptr); + /* If the length is 0, the conversion failed. Fallback to ASCII */ + convertedScript = NS_ConvertASCIItoUTF16(script); + } + JS::Rooted value(cx, JS::BooleanValue(isUTF8)); + if (!JS_DefineProperty(cx, autoconfigSb, "gIsUTF8", value, JSPROP_ENUMERATE)) { + return NS_ERROR_UNEXPECTED; + } + rv = xpc->EvalInSandboxObject(convertedScript, filename, cx, + autoconfigSb, JSVERSION_LATEST, &v); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + diff --git a/extensions/pref/autoconfig/src/nsReadConfig.cpp b/extensions/pref/autoconfig/src/nsReadConfig.cpp new file mode 100644 index 000000000..6f17deaf1 --- /dev/null +++ b/extensions/pref/autoconfig/src/nsReadConfig.cpp @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsReadConfig.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsIAppStartup.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIAutoConfig.h" +#include "nsIComponentManager.h" +#include "nsIFile.h" +#include "nsIObserverService.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsIPromptService.h" +#include "nsIServiceManager.h" +#include "nsIStringBundle.h" +#include "nsToolkitCompsCID.h" +#include "nsXPIDLString.h" +#include "nsNetUtil.h" +#include "prmem.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nspr.h" +#include "nsXULAppAPI.h" +#include "nsContentUtils.h" + +extern mozilla::LazyLogModule MCD; + +extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length, + const char *filename, + bool bGlobalContext, + bool bCallbacks, + bool skipFirstLine); +extern nsresult CentralizedAdminPrefManagerInit(); +extern nsresult CentralizedAdminPrefManagerFinish(); + + +static void DisplayError(void) +{ + nsresult rv; + + nsCOMPtr promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1"); + if (!promptService) + return; + + nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID); + if (!bundleService) + return; + + nsCOMPtr bundle; + bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties", + getter_AddRefs(bundle)); + if (!bundle) + return; + + nsXPIDLString title; + rv = bundle->GetStringFromName(u"readConfigTitle", getter_Copies(title)); + if (NS_FAILED(rv)) + return; + + nsXPIDLString err; + rv = bundle->GetStringFromName(u"readConfigMsg", getter_Copies(err)); + if (NS_FAILED(rv)) + return; + + promptService->Alert(nullptr, title.get(), err.get()); +} + +// nsISupports Implementation + +NS_IMPL_ISUPPORTS(nsReadConfig, nsIReadConfig, nsIObserver) + +nsReadConfig::nsReadConfig() : + mRead(false) +{ +} + +nsresult nsReadConfig::Init() +{ + nsresult rv; + + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + + if (observerService) { + rv = observerService->AddObserver(this, NS_PREFSERVICE_READ_TOPIC_ID, false); + } + return(rv); +} + +nsReadConfig::~nsReadConfig() +{ + CentralizedAdminPrefManagerFinish(); +} + +NS_IMETHODIMP nsReadConfig::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) +{ + nsresult rv = NS_OK; + + if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) { + rv = readConfigFile(); + if (NS_FAILED(rv)) { + DisplayError(); + + nsCOMPtr appStartup = + do_GetService(NS_APPSTARTUP_CONTRACTID); + if (appStartup) + appStartup->Quit(nsIAppStartup::eAttemptQuit); + } + } + return rv; +} + + +nsresult nsReadConfig::readConfigFile() +{ + nsresult rv = NS_OK; + nsXPIDLCString lockFileName; + nsXPIDLCString lockVendor; + uint32_t fileNameLen = 0; + + nsCOMPtr defaultPrefBranch; + nsCOMPtr prefService = + do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = prefService->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch)); + if (NS_FAILED(rv)) + return rv; + + // This preference is set in the all.js or all-ns.js (depending whether + // running mozilla or netscp6) + + rv = defaultPrefBranch->GetCharPref("general.config.filename", + getter_Copies(lockFileName)); + + + MOZ_LOG(MCD, LogLevel::Debug, ("general.config.filename = %s\n", lockFileName.get())); + if (NS_FAILED(rv)) + return rv; + + // This needs to be read only once. + // + if (!mRead) { + // Initiate the new JS Context for Preference management + + rv = CentralizedAdminPrefManagerInit(); + if (NS_FAILED(rv)) + return rv; + + // Open and evaluate function calls to set/lock/unlock prefs + rv = openAndEvaluateJSFile("prefcalls.js", 0, false, false); + if (NS_FAILED(rv)) + return rv; + + mRead = true; + } + // If the lockFileName is nullptr return ok, because no lockFile will be used + + + // Once the config file is read, we should check that the vendor name + // is consistent By checking for the vendor name after reading the config + // file we allow for the preference to be set (and locked) by the creator + // of the cfg file meaning the file can not be renamed (successfully). + + nsCOMPtr prefBranch; + rv = prefService->GetBranch(nullptr, getter_AddRefs(prefBranch)); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t obscureValue = 0; + (void) defaultPrefBranch->GetIntPref("general.config.obscure_value", &obscureValue); + MOZ_LOG(MCD, LogLevel::Debug, ("evaluating .cfg file %s with obscureValue %d\n", lockFileName.get(), obscureValue)); + rv = openAndEvaluateJSFile(lockFileName.get(), obscureValue, true, true); + if (NS_FAILED(rv)) + { + MOZ_LOG(MCD, LogLevel::Debug, ("error evaluating .cfg file %s %x\n", lockFileName.get(), rv)); + return rv; + } + + rv = prefBranch->GetCharPref("general.config.filename", + getter_Copies(lockFileName)); + if (NS_FAILED(rv)) + // There is NO REASON we should ever get here. This is POST reading + // of the config file. + return NS_ERROR_FAILURE; + + + rv = prefBranch->GetCharPref("general.config.vendor", + getter_Copies(lockVendor)); + // If vendor is not nullptr, do this check + if (NS_SUCCEEDED(rv)) { + + fileNameLen = strlen(lockFileName); + + // lockVendor and lockFileName should be the same with the addtion of + // .cfg to the filename by checking this post reading of the cfg file + // this value can be set within the cfg file adding a level of security. + + if (PL_strncmp(lockFileName, lockVendor, fileNameLen - 4) != 0) + return NS_ERROR_FAILURE; + } + + // get the value of the autoconfig url + nsXPIDLCString urlName; + rv = prefBranch->GetCharPref("autoadmin.global_config_url", + getter_Copies(urlName)); + if (NS_SUCCEEDED(rv) && !urlName.IsEmpty()) { + + // Instantiating nsAutoConfig object if the pref is present + mAutoConfig = do_CreateInstance(NS_AUTOCONFIG_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_OUT_OF_MEMORY; + + rv = mAutoConfig->SetConfigURL(urlName); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + } + + return NS_OK; +} // ReadConfigFile + + +nsresult nsReadConfig::openAndEvaluateJSFile(const char *aFileName, int32_t obscureValue, + bool isEncoded, + bool isBinDir) +{ + nsresult rv; + + nsCOMPtr inStr; + if (isBinDir) { + nsCOMPtr jsFile; + rv = NS_GetSpecialDirectory(NS_GRE_DIR, + getter_AddRefs(jsFile)); + if (NS_FAILED(rv)) + return rv; + + rv = jsFile->AppendNative(nsDependentCString(aFileName)); + if (NS_FAILED(rv)) + return rv; + + rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile); + if (NS_FAILED(rv)) + return rv; + + } else { + nsAutoCString location("resource://gre/defaults/autoconfig/"); + location += aFileName; + + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), location); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr channel; + rv = NS_NewChannel(getter_AddRefs(channel), + uri, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, + nsIContentPolicy::TYPE_OTHER); + NS_ENSURE_SUCCESS(rv, rv); + + rv = channel->Open2(getter_AddRefs(inStr)); + NS_ENSURE_SUCCESS(rv, rv); + } + + uint64_t fs64; + uint32_t amt = 0; + rv = inStr->Available(&fs64); + if (NS_FAILED(rv)) + return rv; + // PR_Malloc dones't support over 4GB + if (fs64 > UINT32_MAX) + return NS_ERROR_FILE_TOO_BIG; + uint32_t fs = (uint32_t)fs64; + + char *buf = (char *)PR_Malloc(fs * sizeof(char)); + if (!buf) + return NS_ERROR_OUT_OF_MEMORY; + + rv = inStr->Read(buf, (uint32_t)fs, &amt); + NS_ASSERTION((amt == fs), "failed to read the entire configuration file!!"); + if (NS_SUCCEEDED(rv)) { + if (obscureValue > 0) { + + // Unobscure file by subtracting some value from every char. + for (uint32_t i = 0; i < amt; i++) + buf[i] -= obscureValue; + } + rv = EvaluateAdminConfigScript(buf, amt, aFileName, + false, true, + isEncoded ? true:false); + } + inStr->Close(); + PR_Free(buf); + + return rv; +} diff --git a/extensions/pref/autoconfig/src/nsReadConfig.h b/extensions/pref/autoconfig/src/nsReadConfig.h new file mode 100644 index 000000000..66aa9e5f0 --- /dev/null +++ b/extensions/pref/autoconfig/src/nsReadConfig.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsReadConfig_h +#define nsReadConfig_h + +#include "nsCOMPtr.h" +#include "nsIReadConfig.h" +#include "nsIAutoConfig.h" +#include "nsIObserver.h" + + +class nsReadConfig : public nsIReadConfig, + public nsIObserver +{ + + public: + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIREADCONFIG + NS_DECL_NSIOBSERVER + + nsReadConfig(); + + nsresult Init(); + + protected: + + virtual ~nsReadConfig(); + + nsresult readConfigFile(); + nsresult openAndEvaluateJSFile(const char *aFileName, int32_t obscureValue, + bool isEncoded, bool isBinDir); + bool mRead; +private: + nsCOMPtr mAutoConfig; +}; + +#endif diff --git a/extensions/pref/autoconfig/src/prefcalls.js b/extensions/pref/autoconfig/src/prefcalls.js new file mode 100644 index 000000000..d0bbd538e --- /dev/null +++ b/extensions/pref/autoconfig/src/prefcalls.js @@ -0,0 +1,230 @@ +/* -*- tab-width: 4; indent-tabs-mode: nil; js-indent-level: 4 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const nsILDAPURL = Components.interfaces.nsILDAPURL; +const LDAPURLContractID = "@mozilla.org/network/ldap-url;1"; +const nsILDAPSyncQuery = Components.interfaces.nsILDAPSyncQuery; +const LDAPSyncQueryContractID = "@mozilla.org/ldapsyncquery;1"; +const nsIPrefService = Components.interfaces.nsIPrefService; +const PrefServiceContractID = "@mozilla.org/preferences-service;1"; + +var gVersion; +var gIsUTF8; + +function getPrefBranch() { + + var prefService = Components.classes[PrefServiceContractID] + .getService(nsIPrefService); + return prefService.getBranch(null); +} + +function pref(prefName, value) { + + try { + var prefBranch = getPrefBranch(); + + if (typeof value == "string") { + if (gIsUTF8) { + const nsISupportsString = Components.interfaces.nsISupportsString; + let string = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + string.data = value; + prefBranch.setComplexValue(prefName, nsISupportsString, string); + return; + } + prefBranch.setCharPref(prefName, value); + } + else if (typeof value == "number") { + prefBranch.setIntPref(prefName, value); + } + else if (typeof value == "boolean") { + prefBranch.setBoolPref(prefName, value); + } + } + catch(e) { + displayError("pref", e); + } +} + +function defaultPref(prefName, value) { + + try { + var prefService = Components.classes[PrefServiceContractID] + .getService(nsIPrefService); + var prefBranch = prefService.getDefaultBranch(null); + if (typeof value == "string") { + if (gIsUTF8) { + const nsISupportsString = Components.interfaces.nsISupportsString; + let string = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + string.data = value; + prefBranch.setComplexValue(prefName, nsISupportsString, string); + return; + } + prefBranch.setCharPref(prefName, value); + } + else if (typeof value == "number") { + prefBranch.setIntPref(prefName, value); + } + else if (typeof value == "boolean") { + prefBranch.setBoolPref(prefName, value); + } + } + catch(e) { + displayError("defaultPref", e); + } +} + +function lockPref(prefName, value) { + + try { + var prefBranch = getPrefBranch(); + + if (prefBranch.prefIsLocked(prefName)) + prefBranch.unlockPref(prefName); + + defaultPref(prefName, value); + + prefBranch.lockPref(prefName); + } + catch(e) { + displayError("lockPref", e); + } +} + +function unlockPref(prefName) { + + try { + + var prefBranch = getPrefBranch(); + prefBranch.unlockPref(prefName); + } + catch(e) { + displayError("unlockPref", e); + } +} + +function getPref(prefName) { + + try { + var prefBranch = getPrefBranch(); + + switch (prefBranch.getPrefType(prefName)) { + + case prefBranch.PREF_STRING: + if (gIsUTF8) { + const nsISupportsString = Components.interfaces.nsISupportsString; + let string = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + return prefBranch.getComplexValue(prefName, nsISupportsString).data; + } + return prefBranch.getCharPref(prefName); + + case prefBranch.PREF_INT: + return prefBranch.getIntPref(prefName); + + case prefBranch.PREF_BOOL: + return prefBranch.getBoolPref(prefName); + default: + return null; + } + } + catch(e) { + displayError("getPref", e); + } +} + +function clearPref(prefName) { + + try { + var prefBranch = getPrefBranch(); + prefBranch.clearUserPref(prefName); + } + catch(e) { + } + +} + +function setLDAPVersion(version) { + gVersion = version; +} + + +function getLDAPAttributes(host, base, filter, attribs, isSecure) { + + try { + var urlSpec = "ldap" + (isSecure ? "s" : "") + "://" + host + (isSecure ? ":636" : "") + "/" + base + "?" + attribs + "?sub?" + + filter; + + var url = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService) + .newURI(urlSpec, null, null) + .QueryInterface(Components.interfaces.nsILDAPURL); + + var ldapquery = Components.classes[LDAPSyncQueryContractID] + .createInstance(nsILDAPSyncQuery); + // default to LDAP v3 + if (!gVersion) + gVersion = Components.interfaces.nsILDAPConnection.VERSION3 + // user supplied method + processLDAPValues(ldapquery.getQueryResults(url, gVersion)); + } + catch(e) { + displayError("getLDAPAttibutes", e); + } +} + +function getLDAPValue(str, key) { + + try { + if (str == null || key == null) + return null; + + var search_key = "\n" + key + "="; + + var start_pos = str.indexOf(search_key); + if (start_pos == -1) + return null; + + start_pos += search_key.length; + + var end_pos = str.indexOf("\n", start_pos); + if (end_pos == -1) + end_pos = str.length; + + return str.substring(start_pos, end_pos); + } + catch(e) { + displayError("getLDAPValue", e); + } +} + +function displayError(funcname, message) { + + try { + var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] + .getService(Components.interfaces.nsIPromptService); + var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"] + .getService(Components.interfaces.nsIStringBundleService) + .createBundle("chrome://autoconfig/locale/autoconfig.properties"); + + var title = bundle.GetStringFromName("autoConfigTitle"); + var msg = bundle.formatStringFromName("autoConfigMsg", [funcname], 1); + promptService.alert(null, title, msg + " " + message); + } + catch(e) { } +} + +function getenv(name) { + try { + var environment = Components.classes["@mozilla.org/process/environment;1"]. + getService(Components.interfaces.nsIEnvironment); + return environment.get(name); + } + catch(e) { + displayError("getEnvironment", e); + } +} + diff --git a/extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg b/extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg new file mode 100644 index 000000000..6b96c65fd --- /dev/null +++ b/extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg @@ -0,0 +1,6 @@ +// # don't remove this comment! (the first line is ignored by Mozilla) +// +lockPref("_test.string.ASCII", "ASCII"); +lockPref("_test.string.non-ASCII", "日本語"); +lockPref("_test.string.getPref", getPref("_test.string.non-ASCII")); +lockPref("_test.string.gIsUTF8", String(this.gIsUTF8)); diff --git a/extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg b/extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg new file mode 100644 index 000000000..eec789942 --- /dev/null +++ b/extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg @@ -0,0 +1,6 @@ +// # don't remove this comment! (the first line is ignored by Mozilla) + +lockPref("_test.string.ASCII", "UTF-8"); +lockPref("_test.string.non-ASCII", "日本語"); +lockPref("_test.string.getPref", getPref("_test.string.non-ASCII")); +lockPref("_test.string.gIsUTF8", String(this.gIsUTF8)); diff --git a/extensions/pref/autoconfig/test/unit/autoconfig.js b/extensions/pref/autoconfig/test/unit/autoconfig.js new file mode 100644 index 000000000..f831d95b6 --- /dev/null +++ b/extensions/pref/autoconfig/test/unit/autoconfig.js @@ -0,0 +1,4 @@ +pref("general.config.filename", "autoconfig.cfg"); +pref("general.config.vendor", "autoconfig"); +pref("general.config.obscure_value", 0); + diff --git a/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js b/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js new file mode 100644 index 000000000..a42bc1219 --- /dev/null +++ b/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js @@ -0,0 +1,97 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var {classes: Cc, interfaces: Ci, results: Cr} = Components; + +function run_test() { + let dirSvc = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties); + let obsvc = Cc['@mozilla.org/observer-service;1']. + getService(Ci.nsIObserverService); + let ps = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService); + let defaultPrefs = ps.getDefaultBranch(null); + let prefs = ps.getBranch(null); + + let greD = dirSvc.get("GreD", Ci.nsIFile); + let defaultPrefD = dirSvc.get("PrfDef", Ci.nsIFile); + let testDir = do_get_cwd(); + + try { + let autoConfigJS = testDir.clone(); + autoConfigJS.append("autoconfig.js"); + autoConfigJS.copyTo(defaultPrefD, "autoconfig.js"); + + // Make sure nsReadConfig is initialized. + Cc["@mozilla.org/readconfig;1"].getService(Ci.nsISupports); + ps.resetPrefs(); + + var tests = [{ + filename: "autoconfig-utf8.cfg", + prefs: { + "_test.string.ASCII": "UTF-8", + "_test.string.non-ASCII": "日本語", + "_test.string.getPref": "日本語", + "_test.string.gIsUTF8": "true" + } + }, { + filename: "autoconfig-latin1.cfg", + prefs: { + "_test.string.ASCII": "ASCII", + "_test.string.non-ASCII": "日本語", + "_test.string.getPref": "日本語", + "_test.string.gIsUTF8": "false", + } + }]; + + function testAutoConfig(test) { + // Make sure pref values are unset. + for (let prefName in test.prefs) { + do_check_eq(Ci.nsIPrefBranch.PREF_INVALID, prefs.getPrefType(prefName)); + } + + let autoConfigCfg = testDir.clone(); + autoConfigCfg.append(test.filename); + autoConfigCfg.copyTo(greD, "autoconfig.cfg"); + + obsvc.notifyObservers(ps, "prefservice:before-read-userprefs", null); + + for (let prefName in test.prefs) { + do_check_eq(test.prefs[prefName], + prefs.getComplexValue(prefName, Ci.nsISupportsString).data); + } + + ps.resetPrefs(); + // Make sure pref values are reset. + for (let prefName in test.prefs) { + do_check_eq(Ci.nsIPrefBranch.PREF_INVALID, prefs.getPrefType(prefName)); + } + } + + tests.forEach(testAutoConfig); + + } finally { + try { + let autoConfigJS = defaultPrefD.clone(); + autoConfigJS.append("autoconfig.js"); + autoConfigJS.remove(false); + } catch (e) { + if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) { + throw e; + } + } + + try { + let autoConfigCfg = greD.clone(); + autoConfigCfg.append("autoconfig.cfg"); + autoConfigCfg.remove(false); + } catch (e) { + if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) { + throw e; + } + } + + ps.resetPrefs(); + } +} + diff --git a/extensions/pref/autoconfig/test/unit/xpcshell.ini b/extensions/pref/autoconfig/test/unit/xpcshell.ini new file mode 100644 index 000000000..4806363e5 --- /dev/null +++ b/extensions/pref/autoconfig/test/unit/xpcshell.ini @@ -0,0 +1,10 @@ +[DEFAULT] +head = +tail = +skip-if = toolkit == 'android' +support-files = + autoconfig-latin1.cfg + autoconfig-utf8.cfg + autoconfig.js + +[test_autoconfig_nonascii.js] diff --git a/extensions/pref/moz.build b/extensions/pref/moz.build new file mode 100644 index 000000000..ed5958b04 --- /dev/null +++ b/extensions/pref/moz.build @@ -0,0 +1,8 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +DIRS += ['autoconfig'] diff --git a/extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl b/extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl new file mode 100644 index 000000000..7fd918364 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PContent; + +namespace mozilla { + +sync protocol PRemoteSpellcheckEngine { + manager PContent; + +parent: + async __delete__(); + + sync Check(nsString aWord) returns (bool aIsMisspelled); + + sync CheckAndSuggest(nsString aWord) returns (bool aIsMisspelled, nsString[] aSuggestions); + + sync SetDictionary(nsString aDictionary) returns (bool success); +}; + +} // namespace mozilla diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp new file mode 100644 index 000000000..dadfb2963 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemoteSpellCheckEngineChild.h" + +namespace mozilla { + +RemoteSpellcheckEngineChild::RemoteSpellcheckEngineChild(mozSpellChecker *aOwner) + : mOwner(aOwner) +{ +} + +RemoteSpellcheckEngineChild::~RemoteSpellcheckEngineChild() +{ + // null out the owner's SpellcheckEngineChild to prevent state corruption + // during shutdown + mOwner->DeleteRemoteEngine(); +} + +} //namespace mozilla diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h new file mode 100644 index 000000000..2cc40ce1f --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef RemoteSpellcheckEngineChild_h_ +#define RemoteSpellcheckEngineChild_h_ + +#include "mozilla/PRemoteSpellcheckEngineChild.h" +#include "mozSpellChecker.h" + +class mozSpellChecker; + +namespace mozilla { + +class RemoteSpellcheckEngineChild : public mozilla::PRemoteSpellcheckEngineChild +{ +public: + explicit RemoteSpellcheckEngineChild(mozSpellChecker *aOwner); + virtual ~RemoteSpellcheckEngineChild(); + +private: + mozSpellChecker *mOwner; +}; + +} //namespace mozilla + +#endif // RemoteSpellcheckEngineChild_h_ diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp new file mode 100644 index 000000000..ce20b4e19 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp @@ -0,0 +1,63 @@ +/* vim: set ts=2 sw=2 sts=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemoteSpellCheckEngineParent.h" +#include "nsISpellChecker.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla { + +RemoteSpellcheckEngineParent::RemoteSpellcheckEngineParent() +{ + mSpellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID); +} + +RemoteSpellcheckEngineParent::~RemoteSpellcheckEngineParent() +{ +} + +bool +RemoteSpellcheckEngineParent::RecvSetDictionary( + const nsString& aDictionary, + bool* success) +{ + nsresult rv = mSpellChecker->SetCurrentDictionary(aDictionary); + *success = NS_SUCCEEDED(rv); + return true; +} + +bool +RemoteSpellcheckEngineParent::RecvCheck( + const nsString& aWord, + bool* aIsMisspelled) +{ + nsresult rv = mSpellChecker->CheckWord(aWord, aIsMisspelled, nullptr); + + // If CheckWord failed, we can't tell whether the word is correctly spelled. + if (NS_FAILED(rv)) + *aIsMisspelled = false; + return true; +} + +bool +RemoteSpellcheckEngineParent::RecvCheckAndSuggest( + const nsString& aWord, + bool* aIsMisspelled, + InfallibleTArray* aSuggestions) +{ + nsresult rv = mSpellChecker->CheckWord(aWord, aIsMisspelled, aSuggestions); + if (NS_FAILED(rv)) { + aSuggestions->Clear(); + *aIsMisspelled = false; + } + return true; +} + +void +RemoteSpellcheckEngineParent::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +} // namespace mozilla diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h new file mode 100644 index 000000000..c0bb51139 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef RemoteSpellcheckEngineParent_h_ +#define RemoteSpellcheckEngineParent_h_ + +#include "mozilla/PRemoteSpellcheckEngineParent.h" +#include "nsCOMPtr.h" + +class nsISpellChecker; + +namespace mozilla { + +class RemoteSpellcheckEngineParent : public PRemoteSpellcheckEngineParent +{ +public: + RemoteSpellcheckEngineParent(); + + virtual ~RemoteSpellcheckEngineParent(); + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + virtual bool RecvSetDictionary(const nsString& aDictionary, + bool* success) override; + + virtual bool RecvCheck(const nsString& aWord, bool* aIsMisspelled) override; + + virtual bool RecvCheckAndSuggest(const nsString& aWord, + bool* aIsMisspelled, + InfallibleTArray* aSuggestions) + override; + +private: + nsCOMPtr mSpellChecker; +}; + +} // namespace mozilla + +#endif diff --git a/extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h b/extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h new file mode 100644 index 000000000..729e66b8e --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h @@ -0,0 +1,58 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developers + * are Copyright (C) 2011 the Initial Developers. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#ifndef alloc_hooks_h__ +#define alloc_hooks_h__ + +/** + * This file is force-included in hunspell code. Its purpose is to add memory + * reporting to hunspell without modifying its code, in order to ease future + * upgrades. + * + * This file is force-included through mozilla-config.h which is generated + * during the configure step. + * + * Currently, the memory allocated using operator new/new[] is not being + * tracked, but that's OK, since almost all of the memory used by Hunspell is + * allocated using C memory allocation functions. + */ + +#include "mozilla/mozalloc.h" +#include "mozHunspellAllocator.h" + +#define malloc(size) HunspellAllocator::CountingMalloc(size) +#define calloc(count, size) HunspellAllocator::CountingCalloc(count, size) +#define free(ptr) HunspellAllocator::CountingFree(ptr) +#define realloc(ptr, size) HunspellAllocator::CountingRealloc(ptr, size) + +#endif diff --git a/extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h b/extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h new file mode 100644 index 000000000..a841567b9 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef fopen_hooks_h__ +#define fopen_hooks_h__ + +/** + * This file is force-included in hunspell code. Its purpose is to add + * readahead to fopen() calls in hunspell without modifying its code, in order + * to ease future upgrades. + * + * This file is force-included through mozilla-config.h which is generated + * during the configure step. + */ + +#include "mozilla/FileUtils.h" +#include +#include + +#if defined(XP_WIN) +#include "nsNativeCharsetUtils.h" +#include "nsString.h" + +#include +#include +// Hunspell defines a function named near. Windef.h #defines near. +#undef near +// mozHunspell defines a function named RemoveDirectory. +#undef RemoveDirectory +#endif /* defined(XP_WIN) */ + +inline FILE* +hunspell_fopen_readahead(const char* filename, const char* mode) +{ + if (!filename || !mode) { + return nullptr; + } + // Fall back to libc's fopen for modes not supported by ReadAheadFile + if (!strchr(mode, 'r') || strchr(mode, '+')) { + return fopen(filename, mode); + } + int fd = -1; +#if defined(XP_WIN) + // filename is obtained via the nsIFile::nativePath attribute, so + // it is using the Windows ANSI code page, NOT UTF-8! + nsAutoString utf16Filename; + nsresult rv = NS_CopyNativeToUnicode(nsDependentCString(filename), + utf16Filename); + if (NS_FAILED(rv)) { + return nullptr; + } + HANDLE handle = INVALID_HANDLE_VALUE; + mozilla::ReadAheadFile(utf16Filename.get(), 0, SIZE_MAX, &handle); + if (handle == INVALID_HANDLE_VALUE) { + return nullptr; + } + int flags = _O_RDONLY; + // MSVC CRT's _open_osfhandle only supports adding _O_TEXT, not _O_BINARY + if (strchr(mode, 't')) { + // Force translated mode + flags |= _O_TEXT; + } + // Import the Win32 fd into the CRT + fd = _open_osfhandle((intptr_t)handle, flags); + if (fd < 0) { + CloseHandle(handle); + return nullptr; + } +#else + mozilla::ReadAheadFile(filename, 0, SIZE_MAX, &fd); + if (fd < 0) { + return nullptr; + } +#endif /* defined(XP_WIN) */ + + FILE* file = fdopen(fd, mode); + if (!file) { + close(fd); + } + return file; +} + +#define fopen(filename, mode) hunspell_fopen_readahead(filename, mode) + +#endif /* fopen_hooks_h__ */ + diff --git a/extensions/spellcheck/hunspell/glue/moz.build b/extensions/spellcheck/hunspell/glue/moz.build new file mode 100644 index 000000000..1e1d9711a --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/moz.build @@ -0,0 +1,39 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + 'mozHunspell.cpp', + 'mozHunspellDirProvider.cpp', + 'RemoteSpellCheckEngineChild.cpp', + 'RemoteSpellCheckEngineParent.cpp', +] + +FINAL_LIBRARY = 'xul' + +if CONFIG['MOZ_SYSTEM_HUNSPELL']: + CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS'] +else: + LOCAL_INCLUDES += ['../src'] + +LOCAL_INCLUDES += [ + '/dom/base', + '/extensions/spellcheck/src', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +IPDL_SOURCES = [ + 'PRemoteSpellcheckEngine.ipdl', +] + +EXPORTS.mozilla += [ + 'RemoteSpellCheckEngineChild.h', + 'RemoteSpellCheckEngineParent.h', +] + +# This variable is referenced in configure.in. Make sure to change that file +# too if you need to change this variable. +DEFINES['HUNSPELL_STATIC'] = True diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp new file mode 100644 index 000000000..87ffbc661 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp @@ -0,0 +1,623 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca) + * David Einstein (deinst@world.std.com) + * Michiel van Leeuwen (mvl@exedo.nl) + * Caolan McNamara (cmc@openoffice.org) + * László Németh (nemethl@gyorsposta.hu) + * Davide Prina + * Giuseppe Modugno + * Gianluca Turconi + * Simon Brouwer + * Noll Janos + * Biro Arpad + * Goldman Eleonora + * Sarlos Tamas + * Bencsath Boldizsar + * Halacsy Peter + * Dvornik Laszlo + * Gefferth Andras + * Nagy Viktor + * Varga Daniel + * Chris Halls + * Rene Engelhard + * Bram Moolenaar + * Dafydd Jones + * Harri Pitkanen + * Andras Timar + * Tor Lillqvist + * Jesper Kristensen (mail@jesperkristensen.dk) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#include "mozHunspell.h" +#include "nsReadableUtils.h" +#include "nsXPIDLString.h" +#include "nsIObserverService.h" +#include "nsISimpleEnumerator.h" +#include "nsIDirectoryEnumerator.h" +#include "nsIFile.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "mozISpellI18NManager.h" +#include "nsUnicharUtilCIID.h" +#include "nsUnicharUtils.h" +#include "nsCRT.h" +#include "mozInlineSpellChecker.h" +#include "mozilla/Services.h" +#include +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "mozilla/dom/EncodingUtils.h" +#include "mozilla/dom/ContentParent.h" + +using mozilla::dom::ContentParent; +using mozilla::dom::EncodingUtils; + +NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell) +NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell) + +NS_INTERFACE_MAP_BEGIN(mozHunspell) + NS_INTERFACE_MAP_ENTRY(mozISpellCheckingEngine) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellCheckingEngine) + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozHunspell) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION(mozHunspell, + mPersonalDictionary, + mEncoder, + mDecoder) + +template<> mozilla::Atomic mozilla::CountingAllocatorBase::sAmount(0); + +mozHunspell::mozHunspell() + : mHunspell(nullptr) +{ +#ifdef DEBUG + // There must be only one instance of this class: it reports memory based on + // a single static count in HunspellAllocator. + static bool hasRun = false; + MOZ_ASSERT(!hasRun); + hasRun = true; +#endif +} + +nsresult +mozHunspell::Init() +{ + LoadDictionaryList(false); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, "profile-do-change", true); + obs->AddObserver(this, "profile-after-change", true); + } + + mozilla::RegisterWeakMemoryReporter(this); + + return NS_OK; +} + +mozHunspell::~mozHunspell() +{ + mozilla::UnregisterWeakMemoryReporter(this); + + mPersonalDictionary = nullptr; + delete mHunspell; +} + +NS_IMETHODIMP mozHunspell::GetDictionary(char16_t **aDictionary) +{ + NS_ENSURE_ARG_POINTER(aDictionary); + + *aDictionary = ToNewUnicode(mDictionary); + return *aDictionary ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/* set the Dictionary. + * This also Loads the dictionary and initializes the converter using the dictionaries converter + */ +NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary) +{ + NS_ENSURE_ARG_POINTER(aDictionary); + + if (nsDependentString(aDictionary).IsEmpty()) { + delete mHunspell; + mHunspell = nullptr; + mDictionary.Truncate(); + mAffixFileName.Truncate(); + mLanguage.Truncate(); + mDecoder = nullptr; + mEncoder = nullptr; + + return NS_OK; + } + + nsIFile* affFile = mDictionaries.GetWeak(nsDependentString(aDictionary)); + if (!affFile) + return NS_ERROR_FILE_NOT_FOUND; + + nsAutoCString dictFileName, affFileName; + + // XXX This isn't really good. nsIFile->NativePath isn't safe for all + // character sets on Windows. + // A better way would be to QI to nsIFile, and get a filehandle + // from there. Only problem is that hunspell wants a path + + nsresult rv = affFile->GetNativePath(affFileName); + NS_ENSURE_SUCCESS(rv, rv); + + if (mAffixFileName.Equals(affFileName.get())) + return NS_OK; + + dictFileName = affFileName; + int32_t dotPos = dictFileName.RFindChar('.'); + if (dotPos == -1) + return NS_ERROR_FAILURE; + + dictFileName.SetLength(dotPos); + dictFileName.AppendLiteral(".dic"); + + // SetDictionary can be called multiple times, so we might have a + // valid mHunspell instance which needs cleaned up. + delete mHunspell; + + mDictionary = aDictionary; + mAffixFileName = affFileName; + + mHunspell = new Hunspell(affFileName.get(), + dictFileName.get()); + if (!mHunspell) + return NS_ERROR_OUT_OF_MEMORY; + + nsDependentCString label(mHunspell->get_dic_encoding()); + nsAutoCString encoding; + if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) { + return NS_ERROR_UCONV_NOCONV; + } + mEncoder = EncodingUtils::EncoderForEncoding(encoding); + mDecoder = EncodingUtils::DecoderForEncoding(encoding); + + if (mEncoder) + mEncoder->SetOutputErrorBehavior(mEncoder->kOnError_Signal, nullptr, '?'); + + int32_t pos = mDictionary.FindChar('-'); + if (pos == -1) + pos = mDictionary.FindChar('_'); + + if (pos == -1) + mLanguage.Assign(mDictionary); + else + mLanguage = Substring(mDictionary, 0, pos); + + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetLanguage(char16_t **aLanguage) +{ + NS_ENSURE_ARG_POINTER(aLanguage); + + if (mDictionary.IsEmpty()) + return NS_ERROR_NOT_INITIALIZED; + + *aLanguage = ToNewUnicode(mLanguage); + return *aLanguage ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP mozHunspell::GetProvidesPersonalDictionary(bool *aProvidesPersonalDictionary) +{ + NS_ENSURE_ARG_POINTER(aProvidesPersonalDictionary); + + *aProvidesPersonalDictionary = false; + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetProvidesWordUtils(bool *aProvidesWordUtils) +{ + NS_ENSURE_ARG_POINTER(aProvidesWordUtils); + + *aProvidesWordUtils = false; + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetName(char16_t * *aName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP mozHunspell::GetCopyright(char16_t * *aCopyright) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP mozHunspell::GetPersonalDictionary(mozIPersonalDictionary * *aPersonalDictionary) +{ + *aPersonalDictionary = mPersonalDictionary; + NS_IF_ADDREF(*aPersonalDictionary); + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::SetPersonalDictionary(mozIPersonalDictionary * aPersonalDictionary) +{ + mPersonalDictionary = aPersonalDictionary; + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetDictionaryList(char16_t ***aDictionaries, + uint32_t *aCount) +{ + if (!aDictionaries || !aCount) + return NS_ERROR_NULL_POINTER; + + uint32_t count = 0; + char16_t** dicts = + (char16_t**) moz_xmalloc(sizeof(char16_t*) * mDictionaries.Count()); + + for (auto iter = mDictionaries.Iter(); !iter.Done(); iter.Next()) { + dicts[count] = ToNewUnicode(iter.Key()); + if (!dicts[count]) { + while (count) { + --count; + free(dicts[count]); + } + free(dicts); + return NS_ERROR_OUT_OF_MEMORY; + } + + ++count; + } + + *aDictionaries = dicts; + *aCount = count; + + return NS_OK; +} + +void +mozHunspell::LoadDictionaryList(bool aNotifyChildProcesses) +{ + mDictionaries.Clear(); + + nsresult rv; + + nsCOMPtr dirSvc = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + if (!dirSvc) + return; + + // find built in dictionaries, or dictionaries specified in + // spellchecker.dictionary_path in prefs + nsCOMPtr dictDir; + + // check preferences first + nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if (prefs) { + nsCString extDictPath; + rv = prefs->GetCharPref("spellchecker.dictionary_path", getter_Copies(extDictPath)); + if (NS_SUCCEEDED(rv)) { + // set the spellchecker.dictionary_path + rv = NS_NewNativeLocalFile(extDictPath, true, getter_AddRefs(dictDir)); + } + } + if (!dictDir) { + // spellcheck.dictionary_path not found, set internal path + rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY, + NS_GET_IID(nsIFile), getter_AddRefs(dictDir)); + } + if (dictDir) { + LoadDictionariesFromDir(dictDir); + } + else { + // try to load gredir/dictionaries + nsCOMPtr greDir; + rv = dirSvc->Get(NS_GRE_DIR, + NS_GET_IID(nsIFile), getter_AddRefs(greDir)); + if (NS_SUCCEEDED(rv)) { + greDir->AppendNative(NS_LITERAL_CSTRING("dictionaries")); + LoadDictionariesFromDir(greDir); + } + + // try to load appdir/dictionaries only if different than gredir + nsCOMPtr appDir; + rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), getter_AddRefs(appDir)); + bool equals; + if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) { + appDir->AppendNative(NS_LITERAL_CSTRING("dictionaries")); + LoadDictionariesFromDir(appDir); + } + } + + // find dictionaries in DICPATH + char* dicEnv = PR_GetEnv("DICPATH"); + if (dicEnv) { + // do a two-pass dance so dictionaries are loaded right-to-left as preference + nsTArray> dirs; + nsAutoCString env(dicEnv); // assume dicEnv is UTF-8 + + char* currPath = nullptr; + char* nextPaths = env.BeginWriting(); + while ((currPath = NS_strtok(":", &nextPaths))) { + nsCOMPtr dir; + rv = NS_NewNativeLocalFile(nsCString(currPath), true, getter_AddRefs(dir)); + if (NS_SUCCEEDED(rv)) { + dirs.AppendElement(dir); + } + } + + // load them in reverse order so they override each other properly + for (int32_t i = dirs.Length() - 1; i >= 0; i--) { + LoadDictionariesFromDir(dirs[i]); + } + } + + // find dictionaries from extensions requiring restart + nsCOMPtr dictDirs; + rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY_LIST, + NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dictDirs)); + if (NS_FAILED(rv)) + return; + + bool hasMore; + while (NS_SUCCEEDED(dictDirs->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr elem; + dictDirs->GetNext(getter_AddRefs(elem)); + + dictDir = do_QueryInterface(elem); + if (dictDir) + LoadDictionariesFromDir(dictDir); + } + + // find dictionaries from restartless extensions + for (int32_t i = 0; i < mDynamicDirectories.Count(); i++) { + LoadDictionariesFromDir(mDynamicDirectories[i]); + } + + // Now we have finished updating the list of dictionaries, update the current + // dictionary and any editors which may use it. + mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking(); + + if (aNotifyChildProcesses) { + ContentParent::NotifyUpdatedDictionaries(); + } + + // Check if the current dictionary is still available. + // If not, try to replace it with another dictionary of the same language. + if (!mDictionary.IsEmpty()) { + rv = SetDictionary(mDictionary.get()); + if (NS_SUCCEEDED(rv)) + return; + } + + // If the current dictionary has gone, and we don't have a good replacement, + // set no current dictionary. + if (!mDictionary.IsEmpty()) { + SetDictionary(EmptyString().get()); + } +} + +NS_IMETHODIMP +mozHunspell::LoadDictionariesFromDir(nsIFile* aDir) +{ + nsresult rv; + + bool check = false; + rv = aDir->Exists(&check); + if (NS_FAILED(rv) || !check) + return NS_ERROR_UNEXPECTED; + + rv = aDir->IsDirectory(&check); + if (NS_FAILED(rv) || !check) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr e; + rv = aDir->GetDirectoryEntries(getter_AddRefs(e)); + if (NS_FAILED(rv)) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr files(do_QueryInterface(e)); + if (!files) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr file; + while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file) { + nsAutoString leafName; + file->GetLeafName(leafName); + if (!StringEndsWith(leafName, NS_LITERAL_STRING(".dic"))) + continue; + + nsAutoString dict(leafName); + dict.SetLength(dict.Length() - 4); // magic length of ".dic" + + // check for the presence of the .aff file + leafName = dict; + leafName.AppendLiteral(".aff"); + file->SetLeafName(leafName); + rv = file->Exists(&check); + if (NS_FAILED(rv) || !check) + continue; + +#ifdef DEBUG_bsmedberg + printf("Adding dictionary: %s\n", NS_ConvertUTF16toUTF8(dict).get()); +#endif + + // Replace '_' separator with '-' + dict.ReplaceChar("_", '-'); + + mDictionaries.Put(dict, file); + } + + return NS_OK; +} + +nsresult mozHunspell::ConvertCharset(const char16_t* aStr, char ** aDst) +{ + NS_ENSURE_ARG_POINTER(aDst); + NS_ENSURE_TRUE(mEncoder, NS_ERROR_NULL_POINTER); + + int32_t outLength; + int32_t inLength = NS_strlen(aStr); + nsresult rv = mEncoder->GetMaxLength(aStr, inLength, &outLength); + NS_ENSURE_SUCCESS(rv, rv); + + *aDst = (char *) moz_xmalloc(sizeof(char) * (outLength+1)); + NS_ENSURE_TRUE(*aDst, NS_ERROR_OUT_OF_MEMORY); + + rv = mEncoder->Convert(aStr, &inLength, *aDst, &outLength); + if (NS_SUCCEEDED(rv)) + (*aDst)[outLength] = '\0'; + + return rv; +} + +NS_IMETHODIMP +mozHunspell::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) +{ + MOZ_COLLECT_REPORT( + "explicit/spell-check", KIND_HEAP, UNITS_BYTES, + HunspellAllocator::MemoryAllocated(), + "Memory used by the spell-checking engine."); + + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::Check(const char16_t *aWord, bool *aResult) +{ + NS_ENSURE_ARG_POINTER(aWord); + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE); + + nsXPIDLCString charsetWord; + nsresult rv = ConvertCharset(aWord, getter_Copies(charsetWord)); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = !!mHunspell->spell(charsetWord); + + + if (!*aResult && mPersonalDictionary) + rv = mPersonalDictionary->Check(aWord, mLanguage.get(), aResult); + + return rv; +} + +NS_IMETHODIMP mozHunspell::Suggest(const char16_t *aWord, char16_t ***aSuggestions, uint32_t *aSuggestionCount) +{ + NS_ENSURE_ARG_POINTER(aSuggestions); + NS_ENSURE_ARG_POINTER(aSuggestionCount); + NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE); + + nsresult rv; + *aSuggestionCount = 0; + + nsXPIDLCString charsetWord; + rv = ConvertCharset(aWord, getter_Copies(charsetWord)); + NS_ENSURE_SUCCESS(rv, rv); + + char ** wlst; + *aSuggestionCount = mHunspell->suggest(&wlst, charsetWord); + + if (*aSuggestionCount) { + *aSuggestions = (char16_t **)moz_xmalloc(*aSuggestionCount * sizeof(char16_t *)); + if (*aSuggestions) { + uint32_t index = 0; + for (index = 0; index < *aSuggestionCount && NS_SUCCEEDED(rv); ++index) { + // Convert the suggestion to utf16 + int32_t inLength = strlen(wlst[index]); + int32_t outLength; + rv = mDecoder->GetMaxLength(wlst[index], inLength, &outLength); + if (NS_SUCCEEDED(rv)) + { + (*aSuggestions)[index] = (char16_t *) moz_xmalloc(sizeof(char16_t) * (outLength+1)); + if ((*aSuggestions)[index]) + { + rv = mDecoder->Convert(wlst[index], &inLength, (*aSuggestions)[index], &outLength); + if (NS_SUCCEEDED(rv)) + (*aSuggestions)[index][outLength] = 0; + } + else + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + + if (NS_FAILED(rv)) + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(index, *aSuggestions); // free the char16_t strings up to the point at which the error occurred + } + else // if (*aSuggestions) + rv = NS_ERROR_OUT_OF_MEMORY; + } + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aSuggestionCount, wlst); + return rv; +} + +NS_IMETHODIMP +mozHunspell::Observe(nsISupports* aSubj, const char *aTopic, + const char16_t *aData) +{ + NS_ASSERTION(!strcmp(aTopic, "profile-do-change") + || !strcmp(aTopic, "profile-after-change"), + "Unexpected observer topic"); + + LoadDictionaryList(false); + + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::AddDirectory(nsIFile *aDir) +{ + mDynamicDirectories.AppendObject(aDir); + LoadDictionaryList(true); + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir) +{ + mDynamicDirectories.RemoveObject(aDir); + LoadDictionaryList(true); + +#ifdef MOZ_THUNDERBIRD + /* + * This notification is needed for Thunderbird. Thunderbird derives the dictionary + * from the document's "lang" attribute. If a dictionary is removed, + * we need to change the "lang" attribute. + */ + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(nullptr, + SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION, + nullptr); + } +#endif + return NS_OK; +} diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.h b/extensions/spellcheck/hunspell/glue/mozHunspell.h new file mode 100644 index 000000000..01ef741aa --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspell.h @@ -0,0 +1,125 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca) + * David Einstein (deinst@world.std.com) + * Michiel van Leeuwen (mvl@exedo.nl) + * Caolan McNamara (cmc@openoffice.org) + * László Németh (nemethl@gyorsposta.hu) + * Davide Prina + * Giuseppe Modugno + * Gianluca Turconi + * Simon Brouwer + * Noll Janos + * Biro Arpad + * Goldman Eleonora + * Sarlos Tamas + * Bencsath Boldizsar + * Halacsy Peter + * Dvornik Laszlo + * Gefferth Andras + * Nagy Viktor + * Varga Daniel + * Chris Halls + * Rene Engelhard + * Bram Moolenaar + * Dafydd Jones + * Harri Pitkanen + * Andras Timar + * Tor Lillqvist + * Jesper Kristensen (mail@jesperkristensen.dk) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#ifndef mozHunspell_h__ +#define mozHunspell_h__ + +#include +#include "mozISpellCheckingEngine.h" +#include "mozIPersonalDictionary.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsIMemoryReporter.h" +#include "nsIObserver.h" +#include "nsIUnicodeEncoder.h" +#include "nsIUnicodeDecoder.h" +#include "nsInterfaceHashtable.h" +#include "nsWeakReference.h" +#include "nsCycleCollectionParticipant.h" +#include "mozHunspellAllocator.h" + +#define MOZ_HUNSPELL_CONTRACTID "@mozilla.org/spellchecker/engine;1" +#define MOZ_HUNSPELL_CID \ +/* 56c778e4-1bee-45f3-a689-886692a97fe7 */ \ +{ 0x56c778e4, 0x1bee, 0x45f3, \ + { 0xa6, 0x89, 0x88, 0x66, 0x92, 0xa9, 0x7f, 0xe7 } } + +class mozHunspell final : public mozISpellCheckingEngine, + public nsIObserver, + public nsSupportsWeakReference, + public nsIMemoryReporter +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_MOZISPELLCHECKINGENGINE + NS_DECL_NSIOBSERVER + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozHunspell, mozISpellCheckingEngine) + + mozHunspell(); + + nsresult Init(); + + void LoadDictionaryList(bool aNotifyChildProcesses); + + // helper method for converting a word to the charset of the dictionary + nsresult ConvertCharset(const char16_t* aStr, char ** aDst); + + NS_DECL_NSIMEMORYREPORTER + +protected: + virtual ~mozHunspell(); + + nsCOMPtr mPersonalDictionary; + nsCOMPtr mEncoder; + nsCOMPtr mDecoder; + + // Hashtable matches dictionary name to .aff file + nsInterfaceHashtable mDictionaries; + nsString mDictionary; + nsString mLanguage; + nsCString mAffixFileName; + + // dynamic dirs used to search for dictionaries + nsCOMArray mDynamicDirectories; + + Hunspell *mHunspell; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h b/extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h new file mode 100644 index 000000000..219d4a5dd --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozHunspellAllocator_h__ +#define mozHunspellAllocator_h__ + +#include "mozilla/CountingAllocatorBase.h" + +class HunspellAllocator : public mozilla::CountingAllocatorBase +{ +}; + +#endif diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp new file mode 100644 index 000000000..00758b0c3 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp @@ -0,0 +1,140 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Benjamin Smedberg (benjamin@smedbergs.us) (Original Code) + * László Németh (nemethl@gyorsposta.hu) + * Ryan VanderMeulen (ryanvm@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#include "mozHunspellDirProvider.h" +#include "nsXULAppAPI.h" +#include "nsString.h" + +#include "mozISpellCheckingEngine.h" +#include "nsICategoryManager.h" + +NS_IMPL_ISUPPORTS(mozHunspellDirProvider, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2) + +NS_IMETHODIMP +mozHunspellDirProvider::GetFile(const char *aKey, bool *aPersist, + nsIFile* *aResult) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +mozHunspellDirProvider::GetFiles(const char *aKey, + nsISimpleEnumerator* *aResult) +{ + if (strcmp(aKey, DICTIONARY_SEARCH_DIRECTORY_LIST) != 0) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr dirSvc = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + if (!dirSvc) + return NS_ERROR_FAILURE; + + nsCOMPtr list; + nsresult rv = dirSvc->Get(XRE_EXTENSIONS_DIR_LIST, + NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(list)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr e = new AppendingEnumerator(list); + if (!e) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = nullptr; + e.swap(*aResult); + return NS_SUCCESS_AGGREGATE_RESULT; +} + +NS_IMPL_ISUPPORTS(mozHunspellDirProvider::AppendingEnumerator, + nsISimpleEnumerator) + +NS_IMETHODIMP +mozHunspellDirProvider::AppendingEnumerator::HasMoreElements(bool *aResult) +{ + *aResult = mNext ? true : false; + return NS_OK; +} + +NS_IMETHODIMP +mozHunspellDirProvider::AppendingEnumerator::GetNext(nsISupports* *aResult) +{ + if (aResult) + NS_ADDREF(*aResult = mNext); + + mNext = nullptr; + + nsresult rv; + + // Ignore all errors + + bool more; + while (NS_SUCCEEDED(mBase->HasMoreElements(&more)) && more) { + nsCOMPtr nextbasesupp; + mBase->GetNext(getter_AddRefs(nextbasesupp)); + + nsCOMPtr nextbase(do_QueryInterface(nextbasesupp)); + if (!nextbase) + continue; + + nextbase->Clone(getter_AddRefs(mNext)); + if (!mNext) + continue; + + mNext->AppendNative(NS_LITERAL_CSTRING("dictionaries")); + + bool exists; + rv = mNext->Exists(&exists); + if (NS_SUCCEEDED(rv) && exists) + break; + + mNext = nullptr; + } + + return NS_OK; +} + +mozHunspellDirProvider::AppendingEnumerator::AppendingEnumerator + (nsISimpleEnumerator* aBase) : + mBase(aBase) +{ + // Initialize mNext to begin + GetNext(nullptr); +} + +char const *const +mozHunspellDirProvider::kContractID = "@mozilla.org/spellcheck/dir-provider;1"; diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h new file mode 100644 index 000000000..60ab23be8 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h @@ -0,0 +1,77 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Benjamin Smedberg (benjamin@smedbergs.us) (Original Code) + * László Németh (nemethl@gyorsposta.hu) + * Ryan VanderMeulen (ryanvm@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#ifndef mozHunspellDirProvider_h__ +#define mozHunspellDirProvider_h__ + +#include "nsIDirectoryService.h" +#include "nsIFile.h" +#include "nsISimpleEnumerator.h" +#include "mozilla/Attributes.h" + +class mozHunspellDirProvider final : + public nsIDirectoryServiceProvider2 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + + static char const *const kContractID; + +private: + ~mozHunspellDirProvider() {} + + class AppendingEnumerator final : public nsISimpleEnumerator + { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + explicit AppendingEnumerator(nsISimpleEnumerator* aBase); + + private: + ~AppendingEnumerator() {} + + nsCOMPtr mBase; + nsCOMPtr mNext; + }; +}; + +#define HUNSPELLDIRPROVIDER_CID \ +{ 0x64d6174c, 0x1496, 0x4ffd, \ + { 0x87, 0xf2, 0xda, 0x26, 0x70, 0xf8, 0x89, 0x34 } } + +#endif // mozHunspellDirProvider diff --git a/extensions/spellcheck/hunspell/moz.build b/extensions/spellcheck/hunspell/moz.build new file mode 100644 index 000000000..61955e506 --- /dev/null +++ b/extensions/spellcheck/hunspell/moz.build @@ -0,0 +1,12 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['glue'] +if not CONFIG['MOZ_SYSTEM_HUNSPELL']: + DIRS += ['src'] + +if CONFIG['ENABLE_TESTS']: + XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] diff --git a/extensions/spellcheck/hunspell/src/README b/extensions/spellcheck/hunspell/src/README new file mode 100644 index 000000000..b97a112fd --- /dev/null +++ b/extensions/spellcheck/hunspell/src/README @@ -0,0 +1,21 @@ +Hunspell spell checker and morphological analyser library + +Documentation, tests, examples: http://hunspell.github.io/ + +Author of Hunspell: +László Németh (nemethl (at) gyorsposta.hu) + +Hunspell based on OpenOffice.org's Myspell. MySpell's author: +Kevin Hendricks (kevin.hendricks (at) sympatico.ca) + +License: GPL 2.0/LGPL 2.1/MPL 1.1 tri-license + +The contents of this library may be used under the terms of +the GNU General Public License Version 2 or later (the "GPL"), or +the GNU Lesser General Public License Version 2.1 or later (the "LGPL", +see http://gnu.org/copyleft/lesser.html) or the Mozilla Public License +Version 1.1 or later (the "MPL", see http://mozilla.org/MPL/MPL-1.1.html). + +Software distributed under these licenses is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the licences +for the specific language governing rights and limitations under the licenses. diff --git a/extensions/spellcheck/hunspell/src/README.mozilla b/extensions/spellcheck/hunspell/src/README.mozilla new file mode 100644 index 000000000..79a9f54d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/README.mozilla @@ -0,0 +1,2 @@ +Hunspell Version: 1.4.1 +Additional Patches: See patches directory. diff --git a/extensions/spellcheck/hunspell/src/affentry.cxx b/extensions/spellcheck/hunspell/src/affentry.cxx new file mode 100644 index 000000000..bd2827436 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affentry.cxx @@ -0,0 +1,1068 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "affentry.hxx" +#include "csutil.hxx" + +PfxEntry::PfxEntry(AffixMgr* pmgr, affentry* dp) + // register affix manager + : pmyMgr(pmgr), + next(NULL), + nexteq(NULL), + nextne(NULL), + flgnxt(NULL) { + // set up its initial values + aflag = dp->aflag; // flag + strip = dp->strip; // string to strip + appnd = dp->appnd; // string to append + numconds = dp->numconds; // length of the condition + opts = dp->opts; // cross product flag + // then copy over all of the conditions + if (opts & aeLONGCOND) { + memcpy(c.conds, dp->c.l.conds1, MAXCONDLEN_1); + c.l.conds2 = dp->c.l.conds2; + } else + memcpy(c.conds, dp->c.conds, MAXCONDLEN); + morphcode = dp->morphcode; + contclass = dp->contclass; + contclasslen = dp->contclasslen; +} + +PfxEntry::~PfxEntry() { + aflag = 0; + pmyMgr = NULL; + if (opts & aeLONGCOND) + free(c.l.conds2); + if (morphcode && !(opts & aeALIASM)) + free(morphcode); + if (contclass && !(opts & aeALIASF)) + free(contclass); +} + +// add prefix to this word assuming conditions hold +char* PfxEntry::add(const char* word, size_t len) { + if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) && + (len >= numconds) && test_condition(word) && + (!strip.size() || (strncmp(word, strip.c_str(), strip.size()) == 0))) { + /* we have a match so add prefix */ + std::string tword(appnd); + tword.append(word + strip.size()); + return mystrdup(tword.c_str()); + } + return NULL; +} + +inline char* PfxEntry::nextchar(char* p) { + if (p) { + p++; + if (opts & aeLONGCOND) { + // jump to the 2nd part of the condition + if (p == c.conds + MAXCONDLEN_1) + return c.l.conds2; + // end of the MAXCONDLEN length condition + } else if (p == c.conds + MAXCONDLEN) + return NULL; + return *p ? p : NULL; + } + return NULL; +} + +inline int PfxEntry::test_condition(const char* st) { + const char* pos = NULL; // group with pos input position + bool neg = false; // complementer + bool ingroup = false; // character in the group + if (numconds == 0) + return 1; + char* p = c.conds; + while (1) { + switch (*p) { + case '\0': + return 1; + case '[': { + neg = false; + ingroup = false; + p = nextchar(p); + pos = st; + break; + } + case '^': { + p = nextchar(p); + neg = true; + break; + } + case ']': { + if ((neg && ingroup) || (!neg && !ingroup)) + return 0; + pos = NULL; + p = nextchar(p); + // skip the next character + if (!ingroup && *st) + for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++) + ; + if (*st == '\0' && p) + return 0; // word <= condition + break; + } + case '.': + if (!pos) { // dots are not metacharacters in groups: [.] + p = nextchar(p); + // skip the next character + for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++) + ; + if (*st == '\0' && p) + return 0; // word <= condition + break; + } + /* FALLTHROUGH */ + default: { + if (*st == *p) { + st++; + p = nextchar(p); + if ((opts & aeUTF8) && (*(st - 1) & 0x80)) { // multibyte + while (p && (*p & 0xc0) == 0x80) { // character + if (*p != *st) { + if (!pos) + return 0; + st = pos; + break; + } + p = nextchar(p); + st++; + } + if (pos && st != pos) { + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + } + } else if (pos) { + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + } + } else if (pos) { // group + p = nextchar(p); + } else + return 0; + } + } + if (!p) + return 1; + } +} + +// check if this prefix entry matches +struct hentry* PfxEntry::checkword(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* he; // hash entry of root word or NULL + + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if (tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + tmpl += strip.size(); + if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) { + do { + if (TESTAFF(he->astr, aflag, he->alen) && + // forbid single prefixes with needaffix flag + !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) && + // needflag + ((!needflag) || TESTAFF(he->astr, needflag, he->alen) || + (contclass && TESTAFF(contclass, needflag, contclasslen)))) + return he; + he = he->next_homonym; // check homonyms + } while (he); + } + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // ross checked combined with a suffix + + // if ((opts & aeXPRODUCT) && in_compound) { + if ((opts & aeXPRODUCT)) { + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, aeXPRODUCT, this, + NULL, 0, NULL, FLAG_NULL, needflag, + in_compound); + if (he) + return he; + } + } + } + return NULL; +} + +// check if this prefix entry matches +struct hentry* PfxEntry::check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* he; // hash entry of root word or NULL + + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + tmpl += strip.size(); + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // cross checked combined with a suffix + + if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { + he = pmyMgr->suffix_check_twosfx(tmpword.c_str(), tmpl, aeXPRODUCT, this, + needflag); + if (he) + return he; + } + } + } + return NULL; +} + +// check if this prefix entry matches +char* PfxEntry::check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + tmpl += strip.size(); + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // ross checked combined with a suffix + + if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { + return pmyMgr->suffix_check_twosfx_morph(tmpword.c_str(), tmpl, + aeXPRODUCT, + this, needflag); + } + } + } + return NULL; +} + +// check if this prefix entry matches +char* PfxEntry::check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* he; // hash entry of root word or NULL + char* st; + + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + std::string result; + + tmpl += strip.size(); + if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) { + do { + if (TESTAFF(he->astr, aflag, he->alen) && + // forbid single prefixes with needaffix flag + !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) && + // needflag + ((!needflag) || TESTAFF(he->astr, needflag, he->alen) || + (contclass && TESTAFF(contclass, needflag, contclasslen)))) { + if (morphcode) { + result.append(" "); + result.append(morphcode); + } else + result.append(getKey()); + if (!HENTRY_FIND(he, MORPH_STEM)) { + result.append(" "); + result.append(MORPH_STEM); + result.append(HENTRY_WORD(he)); + } + // store the pointer of the hash entry + if (HENTRY_DATA(he)) { + result.append(" "); + result.append(HENTRY_DATA2(he)); + } else { + // return with debug information + char* flag = pmyMgr->encode_flag(getFlag()); + result.append(" "); + result.append(MORPH_FLAG); + result.append(flag); + free(flag); + } + result.append("\n"); + } + he = he->next_homonym; + } while (he); + } + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // ross checked combined with a suffix + + if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { + st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this, + FLAG_NULL, needflag); + if (st) { + result.append(st); + free(st); + } + } + + if (!result.empty()) + return mystrdup(result.c_str()); + } + } + + return NULL; +} + +SfxEntry::SfxEntry(AffixMgr* pmgr, affentry* dp) + : pmyMgr(pmgr) // register affix manager + , + next(NULL), + nexteq(NULL), + nextne(NULL), + flgnxt(NULL), + l_morph(NULL), + r_morph(NULL), + eq_morph(NULL) { + // set up its initial values + aflag = dp->aflag; // char flag + strip = dp->strip; // string to strip + appnd = dp->appnd; // string to append + numconds = dp->numconds; // length of the condition + opts = dp->opts; // cross product flag + + // then copy over all of the conditions + if (opts & aeLONGCOND) { + memcpy(c.l.conds1, dp->c.l.conds1, MAXCONDLEN_1); + c.l.conds2 = dp->c.l.conds2; + } else + memcpy(c.conds, dp->c.conds, MAXCONDLEN); + rappnd = appnd; + reverseword(rappnd); + morphcode = dp->morphcode; + contclass = dp->contclass; + contclasslen = dp->contclasslen; +} + +SfxEntry::~SfxEntry() { + aflag = 0; + pmyMgr = NULL; + if (opts & aeLONGCOND) + free(c.l.conds2); + if (morphcode && !(opts & aeALIASM)) + free(morphcode); + if (contclass && !(opts & aeALIASF)) + free(contclass); +} + +// add suffix to this word assuming conditions hold +char* SfxEntry::add(const char* word, size_t len) { + /* make sure all conditions match */ + if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) && + (len >= numconds) && test_condition(word + len, word) && + (!strip.size() || + (strcmp(word + len - strip.size(), strip.c_str()) == 0))) { + std::string tword(word); + /* we have a match so add suffix */ + tword.replace(len - strip.size(), std::string::npos, appnd); + return mystrdup(tword.c_str()); + } + return NULL; +} + +inline char* SfxEntry::nextchar(char* p) { + if (p) { + p++; + if (opts & aeLONGCOND) { + // jump to the 2nd part of the condition + if (p == c.l.conds1 + MAXCONDLEN_1) + return c.l.conds2; + // end of the MAXCONDLEN length condition + } else if (p == c.conds + MAXCONDLEN) + return NULL; + return *p ? p : NULL; + } + return NULL; +} + +inline int SfxEntry::test_condition(const char* st, const char* beg) { + const char* pos = NULL; // group with pos input position + bool neg = false; // complementer + bool ingroup = false; // character in the group + if (numconds == 0) + return 1; + char* p = c.conds; + st--; + int i = 1; + while (1) { + switch (*p) { + case '\0': + return 1; + case '[': + p = nextchar(p); + pos = st; + break; + case '^': + p = nextchar(p); + neg = true; + break; + case ']': + if (!neg && !ingroup) + return 0; + i++; + // skip the next character + if (!ingroup) { + for (; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; st--) + ; + st--; + } + pos = NULL; + neg = false; + ingroup = false; + p = nextchar(p); + if (st < beg && p) + return 0; // word <= condition + break; + case '.': + if (!pos) { + // dots are not metacharacters in groups: [.] + p = nextchar(p); + // skip the next character + for (st--; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; + st--) + ; + if (st < beg) { // word <= condition + if (p) + return 0; + else + return 1; + } + if ((opts & aeUTF8) && (*st & 0x80)) { // head of the UTF-8 character + st--; + if (st < beg) { // word <= condition + if (p) + return 0; + else + return 1; + } + } + break; + } + /* FALLTHROUGH */ + default: { + if (*st == *p) { + p = nextchar(p); + if ((opts & aeUTF8) && (*st & 0x80)) { + st--; + while (p && (st >= beg)) { + if (*p != *st) { + if (!pos) + return 0; + st = pos; + break; + } + // first byte of the UTF-8 multibyte character + if ((*p & 0xc0) != 0x80) + break; + p = nextchar(p); + st--; + } + if (pos && st != pos) { + if (neg) + return 0; + else if (i == numconds) + return 1; + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + st--; + } + if (p && *p != ']') + p = nextchar(p); + } else if (pos) { + if (neg) + return 0; + else if (i == numconds) + return 1; + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + // if (p && *p != ']') p = nextchar(p); + st--; + } + if (!pos) { + i++; + st--; + } + if (st < beg && p && *p != ']') + return 0; // word <= condition + } else if (pos) { // group + p = nextchar(p); + } else + return 0; + } + } + if (!p) + return 1; + } +} + +// see if this suffix is present in the word +struct hentry* SfxEntry::checkword(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass, + const FLAG needflag, + const FLAG badflag) { + struct hentry* he; // hash entry pointer + PfxEntry* ep = ppfx; + + // if this suffix is being cross checked with a prefix + // but it does not support cross products skip it + + if (((optflags & aeXPRODUCT) != 0) && ((opts & aeXPRODUCT) == 0)) + return NULL; + + // upon entry suffix is 0 length or already matches the end of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + // the second condition is not enough for UTF-8 strings + // it checked in test_condition() + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing suffix and adding + // back any characters that would have been stripped or + // or null terminating the shorter string + + std::string tmpstring(word, tmpl); + if (strip.size()) { + tmpstring.append(strip); + } + + const char* tmpword = tmpstring.c_str(); + const char* endword = tmpword + tmpstring.size(); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(endword, tmpword)) { +#ifdef SZOSZABLYA_POSSIBLE_ROOTS + fprintf(stdout, "%s %s %c\n", word, tmpword, aflag); +#endif + if ((he = pmyMgr->lookup(tmpword)) != NULL) { + do { + // check conditional suffix (enabled by prefix) + if ((TESTAFF(he->astr, aflag, he->alen) || + (ep && ep->getCont() && + TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && + (((optflags & aeXPRODUCT) == 0) || + (ep && TESTAFF(he->astr, ep->getFlag(), he->alen)) || + // enabled by prefix + ((contclass) && + (ep && TESTAFF(contclass, ep->getFlag(), contclasslen)))) && + // handle cont. class + ((!cclass) || + ((contclass) && TESTAFF(contclass, cclass, contclasslen))) && + // check only in compound homonyms (bad flags) + (!badflag || !TESTAFF(he->astr, badflag, he->alen)) && + // handle required flag + ((!needflag) || + (TESTAFF(he->astr, needflag, he->alen) || + ((contclass) && TESTAFF(contclass, needflag, contclasslen))))) + return he; + he = he->next_homonym; // check homonyms + } while (he); + + // obsolote stemming code (used only by the + // experimental SuffixMgr:suggest_pos_stems) + // store resulting root in wlst + } else if (wlst && (*ns < maxSug)) { + int cwrd = 1; + for (int k = 0; k < *ns; k++) + if (strcmp(tmpword, wlst[k]) == 0) { + cwrd = 0; + break; + } + if (cwrd) { + wlst[*ns] = mystrdup(tmpword); + if (wlst[*ns] == NULL) { + for (int j = 0; j < *ns; j++) + free(wlst[j]); + *ns = -1; + return NULL; + } + (*ns)++; + } + } + } + } + return NULL; +} + +// see if two-level suffix is present in the word +struct hentry* SfxEntry::check_twosfx(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag) { + struct hentry* he; // hash entry pointer + PfxEntry* ep = ppfx; + + // if this suffix is being cross checked with a prefix + // but it does not support cross products skip it + + if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0) + return NULL; + + // upon entry suffix is 0 length or already matches the end of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing suffix and adding + // back any characters that would have been stripped or + // or null terminating the shorter string + + std::string tmpword(word); + tmpword.resize(tmpl); + tmpword.append(strip); + tmpl += strip.size(); + + const char* beg = tmpword.c_str(); + const char* end = beg + tmpl; + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then recall suffix_check + + if (test_condition(end, beg)) { + if (ppfx) { + // handle conditional suffix + if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL, + (FLAG)aflag, needflag); + else + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, optflags, ppfx, NULL, 0, + NULL, (FLAG)aflag, needflag); + } else { + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL, + (FLAG)aflag, needflag); + } + if (he) + return he; + } + } + return NULL; +} + +// see if two-level suffix is present in the word +char* SfxEntry::check_twosfx_morph(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag) { + PfxEntry* ep = ppfx; + char* st; + + char result[MAXLNLEN]; + + *result = '\0'; + + // if this suffix is being cross checked with a prefix + // but it does not support cross products skip it + + if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0) + return NULL; + + // upon entry suffix is 0 length or already matches the end of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing suffix and adding + // back any characters that would have been stripped or + // or null terminating the shorter string + + std::string tmpword(word); + tmpword.resize(tmpl); + tmpword.append(strip); + tmpl += strip.size(); + + const char* beg = tmpword.c_str(); + const char* end = beg + tmpl; + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then recall suffix_check + + if (test_condition(end, beg)) { + if (ppfx) { + // handle conditional suffix + if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) { + st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, + needflag); + if (st) { + if (ppfx->getMorph()) { + mystrcat(result, ppfx->getMorph(), MAXLNLEN); + mystrcat(result, " ", MAXLNLEN); + } + mystrcat(result, st, MAXLNLEN); + free(st); + mychomp(result); + } + } else { + st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, optflags, ppfx, aflag, + needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + mychomp(result); + } + } + } else { + st = + pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + mychomp(result); + } + } + if (*result) + return mystrdup(result); + } + } + return NULL; +} + +// get next homonym with same affix +struct hentry* SfxEntry::get_next_homonym(struct hentry* he, + int optflags, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag) { + PfxEntry* ep = ppfx; + FLAG eFlag = ep ? ep->getFlag() : FLAG_NULL; + + while (he->next_homonym) { + he = he->next_homonym; + if ((TESTAFF(he->astr, aflag, he->alen) || + (ep && ep->getCont() && + TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && + ((optflags & aeXPRODUCT) == 0 || TESTAFF(he->astr, eFlag, he->alen) || + // handle conditional suffix + ((contclass) && TESTAFF(contclass, eFlag, contclasslen))) && + // handle cont. class + ((!cclass) || + ((contclass) && TESTAFF(contclass, cclass, contclasslen))) && + // handle required flag + ((!needflag) || + (TESTAFF(he->astr, needflag, he->alen) || + ((contclass) && TESTAFF(contclass, needflag, contclasslen))))) + return he; + } + return NULL; +} + +#if 0 + +Appendix: Understanding Affix Code + + +An affix is either a prefix or a suffix attached to root words to make +other words. + +Basically a Prefix or a Suffix is set of AffEntry objects +which store information about the prefix or suffix along +with supporting routines to check if a word has a particular +prefix or suffix or a combination. + +The structure affentry is defined as follows: + +struct affentry +{ + unsigned short aflag; // ID used to represent the affix + std::string strip; // string to strip before adding affix + std::string appnd; // the affix string to add + char numconds; // the number of conditions that must be met + char opts; // flag: aeXPRODUCT- combine both prefix and suffix + char conds[SETSIZE]; // array which encodes the conditions to be met +}; + + +Here is a suffix borrowed from the en_US.aff file. This file +is whitespace delimited. + +SFX D Y 4 +SFX D 0 e d +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +This information can be interpreted as follows: + +In the first line has 4 fields + +Field +----- +1 SFX - indicates this is a suffix +2 D - is the name of the character flag which represents this suffix +3 Y - indicates it can be combined with prefixes (cross product) +4 4 - indicates that sequence of 4 affentry structures are needed to + properly store the affix information + +The remaining lines describe the unique information for the 4 SfxEntry +objects that make up this affix. Each line can be interpreted +as follows: (note fields 1 and 2 are as a check against line 1 info) + +Field +----- +1 SFX - indicates this is a suffix +2 D - is the name of the character flag for this affix +3 y - the string of chars to strip off before adding affix + (a 0 here indicates the NULL string) +4 ied - the string of affix characters to add +5 [^aeiou]y - the conditions which must be met before the affix + can be applied + +Field 5 is interesting. Since this is a suffix, field 5 tells us that +there are 2 conditions that must be met. The first condition is that +the next to the last character in the word must *NOT* be any of the +following "a", "e", "i", "o" or "u". The second condition is that +the last character of the word must end in "y". + +So how can we encode this information concisely and be able to +test for both conditions in a fast manner? The answer is found +but studying the wonderful ispell code of Geoff Kuenning, et.al. +(now available under a normal BSD license). + +If we set up a conds array of 256 bytes indexed (0 to 255) and access it +using a character (cast to an unsigned char) of a string, we have 8 bits +of information we can store about that character. Specifically we +could use each bit to say if that character is allowed in any of the +last (or first for prefixes) 8 characters of the word. + +Basically, each character at one end of the word (up to the number +of conditions) is used to index into the conds array and the resulting +value found there says whether the that character is valid for a +specific character position in the word. + +For prefixes, it does this by setting bit 0 if that char is valid +in the first position, bit 1 if valid in the second position, and so on. + +If a bit is not set, then that char is not valid for that postion in the +word. + +If working with suffixes bit 0 is used for the character closest +to the front, bit 1 for the next character towards the end, ..., +with bit numconds-1 representing the last char at the end of the string. + +Note: since entries in the conds[] are 8 bits, only 8 conditions +(read that only 8 character positions) can be examined at one +end of a word (the beginning for prefixes and the end for suffixes. + +So to make this clearer, lets encode the conds array values for the +first two affentries for the suffix D described earlier. + + + For the first affentry: + numconds = 1 (only examine the last character) + + conds['e'] = (1 << 0) (the word must end in an E) + all others are all 0 + + For the second affentry: + numconds = 2 (only examine the last two characters) + + conds[X] = conds[X] | (1 << 0) (aeiou are not allowed) + where X is all characters *but* a, e, i, o, or u + + + conds['y'] = (1 << 1) (the last char must be a y) + all other bits for all other entries in the conds array are zero + +#endif diff --git a/extensions/spellcheck/hunspell/src/affentry.hxx b/extensions/spellcheck/hunspell/src/affentry.hxx new file mode 100644 index 000000000..6311d83ff --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affentry.hxx @@ -0,0 +1,232 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AFFIX_HXX_ +#define _AFFIX_HXX_ + +#include "hunvisapi.h" + +#include "atypes.hxx" +#include "baseaffix.hxx" +#include "affixmgr.hxx" + +/* A Prefix Entry */ + +class LIBHUNSPELL_DLL_EXPORTED PfxEntry : protected AffEntry { + private: + PfxEntry(const PfxEntry&); + PfxEntry& operator=(const PfxEntry&); + + private: + AffixMgr* pmyMgr; + + PfxEntry* next; + PfxEntry* nexteq; + PfxEntry* nextne; + PfxEntry* flgnxt; + + public: + PfxEntry(AffixMgr* pmgr, affentry* dp); + ~PfxEntry(); + + inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); } + struct hentry* checkword(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + struct hentry* check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + char* check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + char* check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + inline FLAG getFlag() { return aflag; } + inline const char* getKey() { return appnd.c_str(); } + char* add(const char* word, size_t len); + + inline short getKeyLen() { return appnd.size(); } + + inline const char* getMorph() { return morphcode; } + + inline const unsigned short* getCont() { return contclass; } + inline short getContLen() { return contclasslen; } + + inline PfxEntry* getNext() { return next; } + inline PfxEntry* getNextNE() { return nextne; } + inline PfxEntry* getNextEQ() { return nexteq; } + inline PfxEntry* getFlgNxt() { return flgnxt; } + + inline void setNext(PfxEntry* ptr) { next = ptr; } + inline void setNextNE(PfxEntry* ptr) { nextne = ptr; } + inline void setNextEQ(PfxEntry* ptr) { nexteq = ptr; } + inline void setFlgNxt(PfxEntry* ptr) { flgnxt = ptr; } + + inline char* nextchar(char* p); + inline int test_condition(const char* st); +}; + +/* A Suffix Entry */ + +class LIBHUNSPELL_DLL_EXPORTED SfxEntry : protected AffEntry { + private: + SfxEntry(const SfxEntry&); + SfxEntry& operator=(const SfxEntry&); + + private: + AffixMgr* pmyMgr; + std::string rappnd; + + SfxEntry* next; + SfxEntry* nexteq; + SfxEntry* nextne; + SfxEntry* flgnxt; + + SfxEntry* l_morph; + SfxEntry* r_morph; + SfxEntry* eq_morph; + + public: + SfxEntry(AffixMgr* pmgr, affentry* dp); + ~SfxEntry(); + + inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); } + struct hentry* checkword(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass = FLAG_NULL, + const FLAG needflag = FLAG_NULL, + const FLAG badflag = FLAG_NULL); + + struct hentry* check_twosfx(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + char* check_twosfx_morph(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + struct hentry* get_next_homonym(struct hentry* he); + struct hentry* get_next_homonym(struct hentry* word, + int optflags, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag); + + inline FLAG getFlag() { return aflag; } + inline const char* getKey() { return rappnd.c_str(); } + char* add(const char* word, size_t len); + + inline const char* getMorph() { return morphcode; } + + inline const unsigned short* getCont() { return contclass; } + inline short getContLen() { return contclasslen; } + inline const char* getAffix() { return appnd.c_str(); } + + inline short getKeyLen() { return appnd.size(); } + + inline SfxEntry* getNext() { return next; } + inline SfxEntry* getNextNE() { return nextne; } + inline SfxEntry* getNextEQ() { return nexteq; } + + inline SfxEntry* getLM() { return l_morph; } + inline SfxEntry* getRM() { return r_morph; } + inline SfxEntry* getEQM() { return eq_morph; } + inline SfxEntry* getFlgNxt() { return flgnxt; } + + inline void setNext(SfxEntry* ptr) { next = ptr; } + inline void setNextNE(SfxEntry* ptr) { nextne = ptr; } + inline void setNextEQ(SfxEntry* ptr) { nexteq = ptr; } + inline void setFlgNxt(SfxEntry* ptr) { flgnxt = ptr; } + + inline char* nextchar(char* p); + inline int test_condition(const char* st, const char* begin); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/affixmgr.cxx b/extensions/spellcheck/hunspell/src/affixmgr.cxx new file mode 100644 index 000000000..d6bb67798 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affixmgr.cxx @@ -0,0 +1,5117 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "affixmgr.hxx" +#include "affentry.hxx" +#include "langnum.hxx" + +#include "csutil.hxx" + +AffixMgr::AffixMgr(const char* affpath, + HashMgr** ptr, + int* md, + const char* key) { + // register hash manager and load affix data from aff file + pHMgr = ptr[0]; + alldic = ptr; + maxdic = md; + keystring = NULL; + trystring = NULL; + encoding = NULL; + csconv = NULL; + utf8 = 0; + complexprefixes = 0; + maptable = NULL; + nummap = 0; + breaktable = NULL; + numbreak = -1; + reptable = NULL; + numrep = 0; + iconvtable = NULL; + oconvtable = NULL; + checkcpdtable = NULL; + // allow simplified compound forms (see 3rd field of CHECKCOMPOUNDPATTERN) + simplifiedcpd = 0; + numcheckcpd = 0; + defcpdtable = NULL; + numdefcpd = 0; + phone = NULL; + compoundflag = FLAG_NULL; // permits word in compound forms + compoundbegin = FLAG_NULL; // may be first word in compound forms + compoundmiddle = FLAG_NULL; // may be middle word in compound forms + compoundend = FLAG_NULL; // may be last word in compound forms + compoundroot = FLAG_NULL; // compound word signing flag + compoundpermitflag = FLAG_NULL; // compound permitting flag for suffixed word + compoundforbidflag = FLAG_NULL; // compound fordidden flag for suffixed word + compoundmoresuffixes = 0; // allow more suffixes within compound words + checkcompounddup = 0; // forbid double words in compounds + checkcompoundrep = 0; // forbid bad compounds (may be non compound word with + // a REP substitution) + checkcompoundcase = + 0; // forbid upper and lowercase combinations at word bounds + checkcompoundtriple = 0; // forbid compounds with triple letters + simplifiedtriple = 0; // allow simplified triple letters in compounds + // (Schiff+fahrt -> Schiffahrt) + forbiddenword = FORBIDDENWORD; // forbidden word signing flag + nosuggest = FLAG_NULL; // don't suggest words signed with NOSUGGEST flag + nongramsuggest = FLAG_NULL; + lang = NULL; // language + langnum = 0; // language code (see http://l10n.openoffice.org/languages.html) + needaffix = FLAG_NULL; // forbidden root, allowed only with suffixes + cpdwordmax = -1; // default: unlimited wordcount in compound words + cpdmin = -1; // undefined + cpdmaxsyllable = 0; // default: unlimited syllablecount in compound words + cpdvowels = NULL; // vowels (for calculating of Hungarian compounding limit, + // O(n) search! XXX) + cpdvowels_utf16 = + NULL; // vowels for UTF-8 encoding (bsearch instead of O(n) search) + cpdvowels_utf16_len = 0; // vowels + pfxappnd = NULL; // previous prefix for counting syllables of the prefix BUG + sfxappnd = NULL; // previous suffix for counting syllables of the suffix BUG + sfxextra = 0; // modifier for syllable count of sfxappnd BUG + cpdsyllablenum = NULL; // syllable count incrementing flag + checknum = 0; // checking numbers, and word with numbers + wordchars = NULL; // letters + spec. word characters + ignorechars = NULL; // letters + spec. word characters + version = NULL; // affix and dictionary file version string + havecontclass = 0; // flags of possible continuing classes (double affix) + // LEMMA_PRESENT: not put root into the morphological output. Lemma presents + // in morhological description in dictionary file. It's often combined with + // PSEUDOROOT. + lemma_present = FLAG_NULL; + circumfix = FLAG_NULL; + onlyincompound = FLAG_NULL; + maxngramsugs = -1; // undefined + maxdiff = -1; // undefined + onlymaxdiff = 0; + maxcpdsugs = -1; // undefined + nosplitsugs = 0; + sugswithdots = 0; + keepcase = 0; + forceucase = 0; + warn = 0; + forbidwarn = 0; + checksharps = 0; + substandard = FLAG_NULL; + fullstrip = 0; + + sfx = NULL; + pfx = NULL; + + for (int i = 0; i < SETSIZE; i++) { + pStart[i] = NULL; + sStart[i] = NULL; + pFlag[i] = NULL; + sFlag[i] = NULL; + } + + for (int j = 0; j < CONTSIZE; j++) { + contclasses[j] = 0; + } + + if (parse_file(affpath, key)) { + HUNSPELL_WARNING(stderr, "Failure loading aff file %s\n", affpath); + } + + if (cpdmin == -1) + cpdmin = MINCPDLEN; +} + +AffixMgr::~AffixMgr() { + // pass through linked prefix entries and clean up + for (int i = 0; i < SETSIZE; i++) { + pFlag[i] = NULL; + PfxEntry* ptr = pStart[i]; + PfxEntry* nptr = NULL; + while (ptr) { + nptr = ptr->getNext(); + delete (ptr); + ptr = nptr; + nptr = NULL; + } + } + + // pass through linked suffix entries and clean up + for (int j = 0; j < SETSIZE; j++) { + sFlag[j] = NULL; + SfxEntry* ptr = sStart[j]; + SfxEntry* nptr = NULL; + while (ptr) { + nptr = ptr->getNext(); + delete (ptr); + ptr = nptr; + nptr = NULL; + } + sStart[j] = NULL; + } + + if (keystring) + free(keystring); + keystring = NULL; + if (trystring) + free(trystring); + trystring = NULL; + if (encoding) + free(encoding); + encoding = NULL; + if (maptable) { + for (int j = 0; j < nummap; j++) { + for (int k = 0; k < maptable[j].len; k++) { + if (maptable[j].set[k]) + free(maptable[j].set[k]); + } + free(maptable[j].set); + maptable[j].set = NULL; + maptable[j].len = 0; + } + free(maptable); + maptable = NULL; + } + nummap = 0; + if (breaktable) { + for (int j = 0; j < numbreak; j++) { + if (breaktable[j]) + free(breaktable[j]); + breaktable[j] = NULL; + } + free(breaktable); + breaktable = NULL; + } + numbreak = 0; + if (reptable) { + for (int j = 0; j < numrep; j++) { + free(reptable[j].pattern); + free(reptable[j].pattern2); + } + free(reptable); + reptable = NULL; + } + if (iconvtable) + delete iconvtable; + if (oconvtable) + delete oconvtable; + if (phone && phone->rules) { + for (int j = 0; j < phone->num + 1; j++) { + free(phone->rules[j * 2]); + free(phone->rules[j * 2 + 1]); + } + free(phone->rules); + free(phone); + phone = NULL; + } + + if (defcpdtable) { + for (int j = 0; j < numdefcpd; j++) { + free(defcpdtable[j].def); + defcpdtable[j].def = NULL; + } + free(defcpdtable); + defcpdtable = NULL; + } + numrep = 0; + if (checkcpdtable) { + for (int j = 0; j < numcheckcpd; j++) { + free(checkcpdtable[j].pattern); + free(checkcpdtable[j].pattern2); + free(checkcpdtable[j].pattern3); + checkcpdtable[j].pattern = NULL; + checkcpdtable[j].pattern2 = NULL; + checkcpdtable[j].pattern3 = NULL; + } + free(checkcpdtable); + checkcpdtable = NULL; + } + numcheckcpd = 0; + FREE_FLAG(compoundflag); + FREE_FLAG(compoundbegin); + FREE_FLAG(compoundmiddle); + FREE_FLAG(compoundend); + FREE_FLAG(compoundpermitflag); + FREE_FLAG(compoundforbidflag); + FREE_FLAG(compoundroot); + FREE_FLAG(forbiddenword); + FREE_FLAG(nosuggest); + FREE_FLAG(nongramsuggest); + FREE_FLAG(needaffix); + FREE_FLAG(lemma_present); + FREE_FLAG(circumfix); + FREE_FLAG(onlyincompound); + + cpdwordmax = 0; + pHMgr = NULL; + cpdmin = 0; + cpdmaxsyllable = 0; + if (cpdvowels) + free(cpdvowels); + if (cpdvowels_utf16) + free(cpdvowels_utf16); + if (cpdsyllablenum) + free(cpdsyllablenum); + free_utf_tbl(); + if (lang) + free(lang); + if (wordchars) + free(wordchars); + if (ignorechars) + free(ignorechars); + if (version) + free(version); + checknum = 0; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +void AffixMgr::finishFileMgr(FileMgr* afflst) { + delete afflst; + + // convert affix trees to sorted list + process_pfx_tree_to_list(); + process_sfx_tree_to_list(); +} + +// read in aff file and build up prefix and suffix entry objects +int AffixMgr::parse_file(const char* affpath, const char* key) { + char* line; // io buffers + char ft; // affix type + + // checking flag duplication + char dupflags[CONTSIZE]; + char dupflags_ini = 1; + + // first line indicator for removing byte order mark + int firstline = 1; + + // open the affix file + FileMgr* afflst = new FileMgr(affpath, key); + if (!afflst) { + HUNSPELL_WARNING( + stderr, "error: could not open affix description file %s\n", affpath); + return 1; + } + + // step one is to parse the affix file building up the internal + // affix data structures + + // read in each line ignoring any that do not + // start with a known line type indicator + while ((line = afflst->getline()) != NULL) { + mychomp(line); + + /* remove byte order mark */ + if (firstline) { + firstline = 0; + // Affix file begins with byte order mark: possible incompatibility with + // old Hunspell versions + if (strncmp(line, "\xEF\xBB\xBF", 3) == 0) { + memmove(line, line + 3, strlen(line + 3) + 1); + } + } + + /* parse in the keyboard string */ + if (strncmp(line, "KEY", 3) == 0) { + if (parse_string(line, &keystring, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the try string */ + if (strncmp(line, "TRY", 3) == 0) { + if (parse_string(line, &trystring, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the name of the character set used by the .dict and .aff */ + if (strncmp(line, "SET", 3) == 0) { + if (parse_string(line, &encoding, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + if (strcmp(encoding, "UTF-8") == 0) { + utf8 = 1; +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT + if (initialize_utf_tbl()) { + finishFileMgr(afflst); + return 1; + } +#endif +#endif + } + } + + /* parse COMPLEXPREFIXES for agglutinative languages with right-to-left + * writing system */ + if (strncmp(line, "COMPLEXPREFIXES", 15) == 0) + complexprefixes = 1; + + /* parse in the flag used by the controlled compound words */ + if (strncmp(line, "COMPOUNDFLAG", 12) == 0) { + if (parse_flag(line, &compoundflag, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound words */ + if (strncmp(line, "COMPOUNDBEGIN", 13) == 0) { + if (complexprefixes) { + if (parse_flag(line, &compoundend, afflst)) { + finishFileMgr(afflst); + return 1; + } + } else { + if (parse_flag(line, &compoundbegin, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + } + + /* parse in the flag used by compound words */ + if (strncmp(line, "COMPOUNDMIDDLE", 14) == 0) { + if (parse_flag(line, &compoundmiddle, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + /* parse in the flag used by compound words */ + if (strncmp(line, "COMPOUNDEND", 11) == 0) { + if (complexprefixes) { + if (parse_flag(line, &compoundbegin, afflst)) { + finishFileMgr(afflst); + return 1; + } + } else { + if (parse_flag(line, &compoundend, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + } + + /* parse in the data used by compound_check() method */ + if (strncmp(line, "COMPOUNDWORDMAX", 15) == 0) { + if (parse_num(line, &cpdwordmax, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag sign compounds in dictionary */ + if (strncmp(line, "COMPOUNDROOT", 12) == 0) { + if (parse_flag(line, &compoundroot, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound_check() method */ + if (strncmp(line, "COMPOUNDPERMITFLAG", 18) == 0) { + if (parse_flag(line, &compoundpermitflag, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound_check() method */ + if (strncmp(line, "COMPOUNDFORBIDFLAG", 18) == 0) { + if (parse_flag(line, &compoundforbidflag, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "COMPOUNDMORESUFFIXES", 20) == 0) { + compoundmoresuffixes = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDDUP", 16) == 0) { + checkcompounddup = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDREP", 16) == 0) { + checkcompoundrep = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDTRIPLE", 19) == 0) { + checkcompoundtriple = 1; + } + + if (strncmp(line, "SIMPLIFIEDTRIPLE", 16) == 0) { + simplifiedtriple = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDCASE", 17) == 0) { + checkcompoundcase = 1; + } + + if (strncmp(line, "NOSUGGEST", 9) == 0) { + if (parse_flag(line, &nosuggest, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "NONGRAMSUGGEST", 14) == 0) { + if (parse_flag(line, &nongramsuggest, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by forbidden words */ + if (strncmp(line, "FORBIDDENWORD", 13) == 0) { + if (parse_flag(line, &forbiddenword, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by forbidden words */ + if (strncmp(line, "LEMMA_PRESENT", 13) == 0) { + if (parse_flag(line, &lemma_present, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by circumfixes */ + if (strncmp(line, "CIRCUMFIX", 9) == 0) { + if (parse_flag(line, &circumfix, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by fogemorphemes */ + if (strncmp(line, "ONLYINCOMPOUND", 14) == 0) { + if (parse_flag(line, &onlyincompound, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `needaffixs' */ + if (strncmp(line, "PSEUDOROOT", 10) == 0) { + if (parse_flag(line, &needaffix, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `needaffixs' */ + if (strncmp(line, "NEEDAFFIX", 9) == 0) { + if (parse_flag(line, &needaffix, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the minimal length for words in compounds */ + if (strncmp(line, "COMPOUNDMIN", 11) == 0) { + if (parse_num(line, &cpdmin, afflst)) { + finishFileMgr(afflst); + return 1; + } + if (cpdmin < 1) + cpdmin = 1; + } + + /* parse in the max. words and syllables in compounds */ + if (strncmp(line, "COMPOUNDSYLLABLE", 16) == 0) { + if (parse_cpdsyllable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound_check() method */ + if (strncmp(line, "SYLLABLENUM", 11) == 0) { + if (parse_string(line, &cpdsyllablenum, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by the controlled compound words */ + if (strncmp(line, "CHECKNUM", 8) == 0) { + checknum = 1; + } + + /* parse in the extra word characters */ + if (strncmp(line, "WORDCHARS", 9) == 0) { + if (!parse_array(line, &wordchars, wordchars_utf16, + utf8, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the ignored characters (for example, Arabic optional diacretics + * charachters */ + if (strncmp(line, "IGNORE", 6) == 0) { + if (!parse_array(line, &ignorechars, ignorechars_utf16, + utf8, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the typical fault correcting table */ + if (strncmp(line, "REP", 3) == 0) { + if (parse_reptable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the input conversion table */ + if (strncmp(line, "ICONV", 5) == 0) { + if (parse_convtable(line, afflst, &iconvtable, "ICONV")) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the input conversion table */ + if (strncmp(line, "OCONV", 5) == 0) { + if (parse_convtable(line, afflst, &oconvtable, "OCONV")) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the phonetic translation table */ + if (strncmp(line, "PHONE", 5) == 0) { + if (parse_phonetable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the checkcompoundpattern table */ + if (strncmp(line, "CHECKCOMPOUNDPATTERN", 20) == 0) { + if (parse_checkcpdtable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the defcompound table */ + if (strncmp(line, "COMPOUNDRULE", 12) == 0) { + if (parse_defcpdtable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the related character map table */ + if (strncmp(line, "MAP", 3) == 0) { + if (parse_maptable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the word breakpoints table */ + if (strncmp(line, "BREAK", 5) == 0) { + if (parse_breaktable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the language for language specific codes */ + if (strncmp(line, "LANG", 4) == 0) { + if (parse_string(line, &lang, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + langnum = get_lang_num(lang); + } + + if (strncmp(line, "VERSION", 7) == 0) { + for (line = line + 7; *line == ' ' || *line == '\t'; line++) + ; + version = mystrdup(line); + } + + if (strncmp(line, "MAXNGRAMSUGS", 12) == 0) { + if (parse_num(line, &maxngramsugs, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "ONLYMAXDIFF", 11) == 0) + onlymaxdiff = 1; + + if (strncmp(line, "MAXDIFF", 7) == 0) { + if (parse_num(line, &maxdiff, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "MAXCPDSUGS", 10) == 0) { + if (parse_num(line, &maxcpdsugs, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "NOSPLITSUGS", 11) == 0) { + nosplitsugs = 1; + } + + if (strncmp(line, "FULLSTRIP", 9) == 0) { + fullstrip = 1; + } + + if (strncmp(line, "SUGSWITHDOTS", 12) == 0) { + sugswithdots = 1; + } + + /* parse in the flag used by forbidden words */ + if (strncmp(line, "KEEPCASE", 8) == 0) { + if (parse_flag(line, &keepcase, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `forceucase' */ + if (strncmp(line, "FORCEUCASE", 10) == 0) { + if (parse_flag(line, &forceucase, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `warn' */ + if (strncmp(line, "WARN", 4) == 0) { + if (parse_flag(line, &warn, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "FORBIDWARN", 10) == 0) { + forbidwarn = 1; + } + + /* parse in the flag used by the affix generator */ + if (strncmp(line, "SUBSTANDARD", 11) == 0) { + if (parse_flag(line, &substandard, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "CHECKSHARPS", 11) == 0) { + checksharps = 1; + } + + /* parse this affix: P - prefix, S - suffix */ + ft = ' '; + if (strncmp(line, "PFX", 3) == 0) + ft = complexprefixes ? 'S' : 'P'; + if (strncmp(line, "SFX", 3) == 0) + ft = complexprefixes ? 'P' : 'S'; + if (ft != ' ') { + if (dupflags_ini) { + memset(dupflags, 0, sizeof(dupflags)); + dupflags_ini = 0; + } + if (parse_affix(line, ft, afflst, dupflags)) { + finishFileMgr(afflst); + return 1; + } + } + } + + finishFileMgr(afflst); + // affix trees are sorted now + + // now we can speed up performance greatly taking advantage of the + // relationship between the affixes and the idea of "subsets". + + // View each prefix as a potential leading subset of another and view + // each suffix (reversed) as a potential trailing subset of another. + + // To illustrate this relationship if we know the prefix "ab" is found in the + // word to examine, only prefixes that "ab" is a leading subset of need be + // examined. + // Furthermore is "ab" is not present then none of the prefixes that "ab" is + // is a subset need be examined. + // The same argument goes for suffix string that are reversed. + + // Then to top this off why not examine the first char of the word to quickly + // limit the set of prefixes to examine (i.e. the prefixes to examine must + // be leading supersets of the first character of the word (if they exist) + + // To take advantage of this "subset" relationship, we need to add two links + // from entry. One to take next if the current prefix is found (call it + // nexteq) + // and one to take next if the current prefix is not found (call it nextne). + + // Since we have built ordered lists, all that remains is to properly + // initialize + // the nextne and nexteq pointers that relate them + + process_pfx_order(); + process_sfx_order(); + + /* get encoding for CHECKCOMPOUNDCASE */ + if (!utf8) { + char* enc = get_encoding(); + csconv = get_current_cs(enc); + free(enc); + enc = NULL; + + std::string expw; + if (wordchars) { + expw.assign(wordchars); + free(wordchars); + } + + for (int i = 0; i <= 255; i++) { + if ((csconv[i].cupper != csconv[i].clower) && + (expw.find((char)i) == std::string::npos)) { + expw.push_back((char)i); + } + } + + wordchars = mystrdup(expw.c_str()); + } + + // default BREAK definition + if (numbreak == -1) { + breaktable = (char**)malloc(sizeof(char*) * 3); + if (!breaktable) + return 1; + breaktable[0] = mystrdup("-"); + breaktable[1] = mystrdup("^-"); + breaktable[2] = mystrdup("-$"); + if (breaktable[0] && breaktable[1] && breaktable[2]) + numbreak = 3; + } + return 0; +} + +// we want to be able to quickly access prefix information +// both by prefix flag, and sorted by prefix string itself +// so we need to set up two indexes + +int AffixMgr::build_pfxtree(PfxEntry* pfxptr) { + PfxEntry* ptr; + PfxEntry* pptr; + PfxEntry* ep = pfxptr; + + // get the right starting points + const char* key = ep->getKey(); + const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF); + + // first index by flag which must exist + ptr = pFlag[flg]; + ep->setFlgNxt(ptr); + pFlag[flg] = ep; + + // handle the special case of null affix string + if (strlen(key) == 0) { + // always inset them at head of list at element 0 + ptr = pStart[0]; + ep->setNext(ptr); + pStart[0] = ep; + return 0; + } + + // now handle the normal case + ep->setNextEQ(NULL); + ep->setNextNE(NULL); + + unsigned char sp = *((const unsigned char*)key); + ptr = pStart[sp]; + + // handle the first insert + if (!ptr) { + pStart[sp] = ep; + return 0; + } + + // otherwise use binary tree insertion so that a sorted + // list can easily be generated later + pptr = NULL; + for (;;) { + pptr = ptr; + if (strcmp(ep->getKey(), ptr->getKey()) <= 0) { + ptr = ptr->getNextEQ(); + if (!ptr) { + pptr->setNextEQ(ep); + break; + } + } else { + ptr = ptr->getNextNE(); + if (!ptr) { + pptr->setNextNE(ep); + break; + } + } + } + return 0; +} + +// we want to be able to quickly access suffix information +// both by suffix flag, and sorted by the reverse of the +// suffix string itself; so we need to set up two indexes +int AffixMgr::build_sfxtree(SfxEntry* sfxptr) { + SfxEntry* ptr; + SfxEntry* pptr; + SfxEntry* ep = sfxptr; + + /* get the right starting point */ + const char* key = ep->getKey(); + const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF); + + // first index by flag which must exist + ptr = sFlag[flg]; + ep->setFlgNxt(ptr); + sFlag[flg] = ep; + + // next index by affix string + + // handle the special case of null affix string + if (strlen(key) == 0) { + // always inset them at head of list at element 0 + ptr = sStart[0]; + ep->setNext(ptr); + sStart[0] = ep; + return 0; + } + + // now handle the normal case + ep->setNextEQ(NULL); + ep->setNextNE(NULL); + + unsigned char sp = *((const unsigned char*)key); + ptr = sStart[sp]; + + // handle the first insert + if (!ptr) { + sStart[sp] = ep; + return 0; + } + + // otherwise use binary tree insertion so that a sorted + // list can easily be generated later + pptr = NULL; + for (;;) { + pptr = ptr; + if (strcmp(ep->getKey(), ptr->getKey()) <= 0) { + ptr = ptr->getNextEQ(); + if (!ptr) { + pptr->setNextEQ(ep); + break; + } + } else { + ptr = ptr->getNextNE(); + if (!ptr) { + pptr->setNextNE(ep); + break; + } + } + } + return 0; +} + +// convert from binary tree to sorted list +int AffixMgr::process_pfx_tree_to_list() { + for (int i = 1; i < SETSIZE; i++) { + pStart[i] = process_pfx_in_order(pStart[i], NULL); + } + return 0; +} + +PfxEntry* AffixMgr::process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr) { + if (ptr) { + nptr = process_pfx_in_order(ptr->getNextNE(), nptr); + ptr->setNext(nptr); + nptr = process_pfx_in_order(ptr->getNextEQ(), ptr); + } + return nptr; +} + +// convert from binary tree to sorted list +int AffixMgr::process_sfx_tree_to_list() { + for (int i = 1; i < SETSIZE; i++) { + sStart[i] = process_sfx_in_order(sStart[i], NULL); + } + return 0; +} + +SfxEntry* AffixMgr::process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr) { + if (ptr) { + nptr = process_sfx_in_order(ptr->getNextNE(), nptr); + ptr->setNext(nptr); + nptr = process_sfx_in_order(ptr->getNextEQ(), ptr); + } + return nptr; +} + +// reinitialize the PfxEntry links NextEQ and NextNE to speed searching +// using the idea of leading subsets this time +int AffixMgr::process_pfx_order() { + PfxEntry* ptr; + + // loop through each prefix list starting point + for (int i = 1; i < SETSIZE; i++) { + ptr = pStart[i]; + + // look through the remainder of the list + // and find next entry with affix that + // the current one is not a subset of + // mark that as destination for NextNE + // use next in list that you are a subset + // of as NextEQ + + for (; ptr != NULL; ptr = ptr->getNext()) { + PfxEntry* nptr = ptr->getNext(); + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + } + ptr->setNextNE(nptr); + ptr->setNextEQ(NULL); + if ((ptr->getNext()) && + isSubset(ptr->getKey(), (ptr->getNext())->getKey())) + ptr->setNextEQ(ptr->getNext()); + } + + // now clean up by adding smart search termination strings: + // if you are already a superset of the previous prefix + // but not a subset of the next, search can end here + // so set NextNE properly + + ptr = pStart[i]; + for (; ptr != NULL; ptr = ptr->getNext()) { + PfxEntry* nptr = ptr->getNext(); + PfxEntry* mptr = NULL; + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + mptr = nptr; + } + if (mptr) + mptr->setNextNE(NULL); + } + } + return 0; +} + +// initialize the SfxEntry links NextEQ and NextNE to speed searching +// using the idea of leading subsets this time +int AffixMgr::process_sfx_order() { + SfxEntry* ptr; + + // loop through each prefix list starting point + for (int i = 1; i < SETSIZE; i++) { + ptr = sStart[i]; + + // look through the remainder of the list + // and find next entry with affix that + // the current one is not a subset of + // mark that as destination for NextNE + // use next in list that you are a subset + // of as NextEQ + + for (; ptr != NULL; ptr = ptr->getNext()) { + SfxEntry* nptr = ptr->getNext(); + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + } + ptr->setNextNE(nptr); + ptr->setNextEQ(NULL); + if ((ptr->getNext()) && + isSubset(ptr->getKey(), (ptr->getNext())->getKey())) + ptr->setNextEQ(ptr->getNext()); + } + + // now clean up by adding smart search termination strings: + // if you are already a superset of the previous suffix + // but not a subset of the next, search can end here + // so set NextNE properly + + ptr = sStart[i]; + for (; ptr != NULL; ptr = ptr->getNext()) { + SfxEntry* nptr = ptr->getNext(); + SfxEntry* mptr = NULL; + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + mptr = nptr; + } + if (mptr) + mptr->setNextNE(NULL); + } + } + return 0; +} + +// add flags to the result for dictionary debugging +void AffixMgr::debugflag(char* result, unsigned short flag) { + char* st = encode_flag(flag); + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_FLAG, MAXLNLEN); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } +} + +// add flags to the result for dictionary debugging +std::string& AffixMgr::debugflag(std::string& result, unsigned short flag) { + char* st = encode_flag(flag); + result.append(" "); + result.append(MORPH_FLAG); + if (st) { + result.append(st); + free(st); + } + return result; +} + +// calculate the character length of the condition +int AffixMgr::condlen(const char* st) { + int l = 0; + bool group = false; + for (; *st; st++) { + if (*st == '[') { + group = true; + l++; + } else if (*st == ']') + group = false; + else if (!group && (!utf8 || (!(*st & 0x80) || ((*st & 0xc0) == 0x80)))) + l++; + } + return l; +} + +int AffixMgr::encodeit(affentry& entry, const char* cs) { + if (strcmp(cs, ".") != 0) { + entry.numconds = (char)condlen(cs); + // coverity[buffer_size_warning] - deliberate use of lack of end of conds + // padded by strncpy as long condition flag + strncpy(entry.c.conds, cs, MAXCONDLEN); + if (entry.c.conds[MAXCONDLEN - 1] && cs[MAXCONDLEN]) { + entry.opts += aeLONGCOND; + entry.c.l.conds2 = mystrdup(cs + MAXCONDLEN_1); + if (!entry.c.l.conds2) + return 1; + } + } else { + entry.numconds = 0; + entry.c.conds[0] = '\0'; + } + return 0; +} + +// return 1 if s1 is a leading subset of s2 (dots are for infixes) +inline int AffixMgr::isSubset(const char* s1, const char* s2) { + while (((*s1 == *s2) || (*s1 == '.')) && (*s1 != '\0')) { + s1++; + s2++; + } + return (*s1 == '\0'); +} + +// check word for prefixes +struct hentry* AffixMgr::prefix_check(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* rv = NULL; + + pfx = NULL; + pfxappnd = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + while (pe) { + if ( + // fogemorpheme + ((in_compound != IN_CPD_NOT) || + !(pe->getCont() && + (TESTAFF(pe->getCont(), onlyincompound, pe->getContLen())))) && + // permit prefixes in compounds + ((in_compound != IN_CPD_END) || + (pe->getCont() && + (TESTAFF(pe->getCont(), compoundpermitflag, pe->getContLen()))))) { + // check prefix + rv = pe->checkword(word, len, in_compound, needflag); + if (rv) { + pfx = pe; // BUG: pfx not stateless + return rv; + } + } + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + if ( + // fogemorpheme + ((in_compound != IN_CPD_NOT) || + !(pptr->getCont() && + (TESTAFF(pptr->getCont(), onlyincompound, pptr->getContLen())))) && + // permit prefixes in compounds + ((in_compound != IN_CPD_END) || + (pptr->getCont() && (TESTAFF(pptr->getCont(), compoundpermitflag, + pptr->getContLen()))))) { + // check prefix + rv = pptr->checkword(word, len, in_compound, needflag); + if (rv) { + pfx = pptr; // BUG: pfx not stateless + return rv; + } + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + return NULL; +} + +// check word for prefixes +struct hentry* AffixMgr::prefix_check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* rv = NULL; + + pfx = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + + while (pe) { + rv = pe->check_twosfx(word, len, in_compound, needflag); + if (rv) + return rv; + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + rv = pptr->check_twosfx(word, len, in_compound, needflag); + if (rv) { + pfx = pptr; + return rv; + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + return NULL; +} + +// check word for prefixes +char* AffixMgr::prefix_check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + + char result[MAXLNLEN]; + result[0] = '\0'; + + pfx = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + while (pe) { + char* st = pe->check_morph(word, len, in_compound, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + // if (rv) return rv; + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + char* st = pptr->check_morph(word, len, in_compound, needflag); + if (st) { + // fogemorpheme + if ((in_compound != IN_CPD_NOT) || + !((pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound, + pptr->getContLen()))))) { + mystrcat(result, st, MAXLNLEN); + pfx = pptr; + } + free(st); + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + if (*result) + return mystrdup(result); + return NULL; +} + +// check word for prefixes +char* AffixMgr::prefix_check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + char result[MAXLNLEN]; + result[0] = '\0'; + + pfx = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + while (pe) { + char* st = pe->check_twosfx_morph(word, len, in_compound, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + char* st = pptr->check_twosfx_morph(word, len, in_compound, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + pfx = pptr; + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + if (*result) + return mystrdup(result); + return NULL; +} + +// Is word a non compound with a REP substitution (see checkcompoundrep)? +int AffixMgr::cpdrep_check(const char* word, int wl) { + + if ((wl < 2) || !numrep) + return 0; + + for (int i = 0; i < numrep; i++) { + const char* r = word; + int lenp = strlen(reptable[i].pattern); + // search every occurence of the pattern in the word + while ((r = strstr(r, reptable[i].pattern)) != NULL) { + std::string candidate(word); + candidate.replace(r - word, lenp, reptable[i].pattern2); + if (candidate_check(candidate.c_str(), candidate.size())) + return 1; + r++; // search for the next letter + } + } + return 0; +} + +// forbid compoundings when there are special patterns at word bound +int AffixMgr::cpdpat_check(const char* word, + int pos, + hentry* r1, + hentry* r2, + const char /*affixed*/) { + int len; + for (int i = 0; i < numcheckcpd; i++) { + if (isSubset(checkcpdtable[i].pattern2, word + pos) && + (!r1 || !checkcpdtable[i].cond || + (r1->astr && TESTAFF(r1->astr, checkcpdtable[i].cond, r1->alen))) && + (!r2 || !checkcpdtable[i].cond2 || + (r2->astr && TESTAFF(r2->astr, checkcpdtable[i].cond2, r2->alen))) && + // zero length pattern => only TESTAFF + // zero pattern (0/flag) => unmodified stem (zero affixes allowed) + (!*(checkcpdtable[i].pattern) || + ((*(checkcpdtable[i].pattern) == '0' && r1->blen <= pos && + strncmp(word + pos - r1->blen, r1->word, r1->blen) == 0) || + (*(checkcpdtable[i].pattern) != '0' && + ((len = strlen(checkcpdtable[i].pattern)) != 0) && + strncmp(word + pos - len, checkcpdtable[i].pattern, len) == 0)))) { + return 1; + } + } + return 0; +} + +// forbid compounding with neighbouring upper and lower case characters at word +// bounds +int AffixMgr::cpdcase_check(const char* word, int pos) { + if (utf8) { + const char* p; + for (p = word + pos - 1; (*p & 0xc0) == 0x80; p--) + ; + std::string pair(p); + std::vector pair_u; + u8_u16(pair_u, pair); + unsigned short a = pair_u.size() > 1 ? ((pair_u[1].h << 8) + pair_u[1].l) : 0; + unsigned short b = !pair_u.empty() ? ((pair_u[0].h << 8) + pair_u[0].l) : 0; + if (((unicodetoupper(a, langnum) == a) || + (unicodetoupper(b, langnum) == b)) && + (a != '-') && (b != '-')) + return 1; + } else { + unsigned char a = *(word + pos - 1); + unsigned char b = *(word + pos); + if ((csconv[a].ccase || csconv[b].ccase) && (a != '-') && (b != '-')) + return 1; + } + return 0; +} + +struct metachar_data { + signed short btpp; // metacharacter (*, ?) position for backtracking + signed short btwp; // word position for metacharacters + int btnum; // number of matched characters in metacharacter +}; + +// check compound patterns +int AffixMgr::defcpd_check(hentry*** words, + short wnum, + hentry* rv, + hentry** def, + char all) { + int w = 0; + + if (!*words) { + w = 1; + *words = def; + } + + if (!*words) { + return 0; + } + + std::vector btinfo(1); + + short bt = 0; + int i, j; + + (*words)[wnum] = rv; + + // has the last word COMPOUNDRULE flag? + if (rv->alen == 0) { + (*words)[wnum] = NULL; + if (w) + *words = NULL; + return 0; + } + int ok = 0; + for (i = 0; i < numdefcpd; i++) { + for (j = 0; j < defcpdtable[i].len; j++) { + if (defcpdtable[i].def[j] != '*' && defcpdtable[i].def[j] != '?' && + TESTAFF(rv->astr, defcpdtable[i].def[j], rv->alen)) { + ok = 1; + break; + } + } + } + if (ok == 0) { + (*words)[wnum] = NULL; + if (w) + *words = NULL; + return 0; + } + + for (i = 0; i < numdefcpd; i++) { + signed short pp = 0; // pattern position + signed short wp = 0; // "words" position + int ok2; + ok = 1; + ok2 = 1; + do { + while ((pp < defcpdtable[i].len) && (wp <= wnum)) { + if (((pp + 1) < defcpdtable[i].len) && + ((defcpdtable[i].def[pp + 1] == '*') || + (defcpdtable[i].def[pp + 1] == '?'))) { + int wend = (defcpdtable[i].def[pp + 1] == '?') ? wp : wnum; + ok2 = 1; + pp += 2; + btinfo[bt].btpp = pp; + btinfo[bt].btwp = wp; + while (wp <= wend) { + if (!(*words)[wp]->alen || + !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp - 2], + (*words)[wp]->alen)) { + ok2 = 0; + break; + } + wp++; + } + if (wp <= wnum) + ok2 = 0; + btinfo[bt].btnum = wp - btinfo[bt].btwp; + if (btinfo[bt].btnum > 0) { + ++bt; + btinfo.resize(bt+1); + } + if (ok2) + break; + } else { + ok2 = 1; + if (!(*words)[wp] || !(*words)[wp]->alen || + !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp], + (*words)[wp]->alen)) { + ok = 0; + break; + } + pp++; + wp++; + if ((defcpdtable[i].len == pp) && !(wp > wnum)) + ok = 0; + } + } + if (ok && ok2) { + int r = pp; + while ((defcpdtable[i].len > r) && ((r + 1) < defcpdtable[i].len) && + ((defcpdtable[i].def[r + 1] == '*') || + (defcpdtable[i].def[r + 1] == '?'))) + r += 2; + if (defcpdtable[i].len <= r) + return 1; + } + // backtrack + if (bt) + do { + ok = 1; + btinfo[bt - 1].btnum--; + pp = btinfo[bt - 1].btpp; + wp = btinfo[bt - 1].btwp + (signed short)btinfo[bt - 1].btnum; + } while ((btinfo[bt - 1].btnum < 0) && --bt); + } while (bt); + + if (ok && ok2 && (!all || (defcpdtable[i].len <= pp))) + return 1; + + // check zero ending + while (ok && ok2 && (defcpdtable[i].len > pp) && + ((pp + 1) < defcpdtable[i].len) && + ((defcpdtable[i].def[pp + 1] == '*') || + (defcpdtable[i].def[pp + 1] == '?'))) + pp += 2; + if (ok && ok2 && (defcpdtable[i].len <= pp)) + return 1; + } + (*words)[wnum] = NULL; + if (w) + *words = NULL; + return 0; +} + +inline int AffixMgr::candidate_check(const char* word, int len) { + struct hentry* rv = NULL; + + rv = lookup(word); + if (rv) + return 1; + + // rv = prefix_check(word,len,1); + // if (rv) return 1; + + rv = affix_check(word, len); + if (rv) + return 1; + return 0; +} + +// calculate number of syllable for compound-checking +short AffixMgr::get_syllable(const std::string& word) { + if (cpdmaxsyllable == 0) + return 0; + + short num = 0; + + if (!utf8) { + for (size_t i = 0; i < word.size(); ++i) { + if (strchr(cpdvowels, word[i])) + num++; + } + } else if (cpdvowels_utf16) { + std::vector w; + int i = u8_u16(w, word); + for (; i > 0; i--) { + if (std::binary_search(cpdvowels_utf16, + cpdvowels_utf16 + cpdvowels_utf16_len, + w[i - 1])) { + ++num; + } + } + } + return num; +} + +void AffixMgr::setcminmax(int* cmin, int* cmax, const char* word, int len) { + if (utf8) { + int i; + for (*cmin = 0, i = 0; (i < cpdmin) && *cmin < len; i++) { + for ((*cmin)++; *cmin < len && (word[*cmin] & 0xc0) == 0x80; (*cmin)++) + ; + } + for (*cmax = len, i = 0; (i < (cpdmin - 1)) && *cmax >= 0; i++) { + for ((*cmax)--; *cmax >= 0 && (word[*cmax] & 0xc0) == 0x80; (*cmax)--) + ; + } + } else { + *cmin = cpdmin; + *cmax = len - cpdmin + 1; + } +} + +// check if compound word is correctly spelled +// hu_mov_rule = spec. Hungarian rule (XXX) +struct hentry* AffixMgr::compound_check(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words = NULL, + hentry** rwords = NULL, + char hu_mov_rule = 0, + char is_sug = 0, + int* info = NULL) { + int i; + short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; + struct hentry* rv = NULL; + struct hentry* rv_first; + std::string st; + char ch = '\0'; + int cmin; + int cmax; + int striple = 0; + int scpd = 0; + int soldi = 0; + int oldcmin = 0; + int oldcmax = 0; + int oldlen = 0; + int checkedstriple = 0; + int onlycpdrule; + char affixed = 0; + hentry** oldwords = words; + + int checked_prefix; + + setcminmax(&cmin, &cmax, word, len); + + st.assign(word); + + for (i = cmin; i < cmax; i++) { + // go to end of the UTF-8 character + if (utf8) { + for (; (st[i] & 0xc0) == 0x80; i++) + ; + if (i >= cmax) + return NULL; + } + + words = oldwords; + onlycpdrule = (words) ? 1 : 0; + + do { // onlycpdrule loop + + oldnumsyllable = numsyllable; + oldwordnum = wordnum; + checked_prefix = 0; + + do { // simplified checkcompoundpattern loop + + if (scpd > 0) { + for (; scpd <= numcheckcpd && + (!checkcpdtable[scpd - 1].pattern3 || + strncmp(word + i, checkcpdtable[scpd - 1].pattern3, + strlen(checkcpdtable[scpd - 1].pattern3)) != 0); + scpd++) + ; + + if (scpd > numcheckcpd) + break; // break simplified checkcompoundpattern loop + st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern); + soldi = i; + i += strlen(checkcpdtable[scpd - 1].pattern); + st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern2); + st.replace(i + strlen(checkcpdtable[scpd - 1].pattern2), std::string::npos, + word + soldi + strlen(checkcpdtable[scpd - 1].pattern3)); + + oldlen = len; + len += strlen(checkcpdtable[scpd - 1].pattern) + + strlen(checkcpdtable[scpd - 1].pattern2) - + strlen(checkcpdtable[scpd - 1].pattern3); + oldcmin = cmin; + oldcmax = cmax; + setcminmax(&cmin, &cmax, st.c_str(), len); + + cmax = len - cpdmin + 1; + } + + ch = st[i]; + st[i] = '\0'; + + sfx = NULL; + pfx = NULL; + + // FIRST WORD + + affixed = 1; + rv = lookup(st.c_str()); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && !hu_mov_rule && + ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundbegin && !wordnum && !onlycpdrule && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + (compoundmiddle && wordnum && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) || + (numdefcpd && onlycpdrule && + ((!words && !wordnum && + defcpd_check(&words, wnum, rv, rwords, 0)) || + (words && + defcpd_check(&words, wnum, rv, rwords, 0))))) || + (scpd != 0 && checkcpdtable[scpd - 1].cond != FLAG_NULL && + !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)))) { + rv = rv->next_homonym; + } + + if (rv) + affixed = 0; + + if (!rv) { + if (onlycpdrule) + break; + if (compoundflag && + !(rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundflag))) { + if (((rv = suffix_check( + st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundflag, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) && + !hu_mov_rule && sfx->getCont() && + ((compoundforbidflag && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())) || + (compoundend && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = NULL; + } + } + + if (rv || + (((wordnum == 0) && compoundbegin && + ((rv = suffix_check( + st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundbegin, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundbegin))) || // twofold suffixes + compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundbegin)))) || + ((wordnum > 0) && compoundmiddle && + ((rv = suffix_check( + st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundmiddle, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundmiddle))) || // twofold suffixes + compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundmiddle)))))) + checked_prefix = 1; + // else check forbiddenwords and needaffix + } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, needaffix, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && + TESTAFF(rv->astr, nosuggest, rv->alen)))) { + st[i] = ch; + // continue; + break; + } + + // check non_compound flag in suffix and prefix + if ((rv) && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())))) { + rv = NULL; + } + + // check compoundend flag in suffix and prefix + if ((rv) && !checked_prefix && compoundend && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundend, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = NULL; + } + + // check compoundmiddle flag in suffix and prefix + if ((rv) && !checked_prefix && (wordnum == 0) && compoundmiddle && + !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundmiddle, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundmiddle, sfx->getContLen())))) { + rv = NULL; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) { + return NULL; + } + + // increment word number, if the second root has a compoundroot flag + if ((rv) && compoundroot && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // first word is acceptable in compound words? + if (((rv) && + (checked_prefix || (words && words[wnum]) || + (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + ((oldwordnum == 0) && compoundbegin && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + ((oldwordnum > 0) && compoundmiddle && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) // || + // (numdefcpd && ) + + // LANG_hu section: spec. Hungarian rule + || ((langnum == LANG_hu) && hu_mov_rule && + (TESTAFF( + rv->astr, 'F', + rv->alen) || // XXX hardwired Hungarian dictionary codes + TESTAFF(rv->astr, 'G', rv->alen) || + TESTAFF(rv->astr, 'H', rv->alen))) + // END of LANG_hu section + ) && + ( + // test CHECKCOMPOUNDPATTERN conditions + scpd == 0 || checkcpdtable[scpd - 1].cond == FLAG_NULL || + TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)) && + !((checkcompoundtriple && scpd == 0 && + !words && // test triple letters + (word[i - 1] == word[i]) && + (((i > 1) && (word[i - 1] == word[i - 2])) || + ((word[i - 1] == word[i + 1])) // may be word[i+1] == '\0' + )) || + (checkcompoundcase && scpd == 0 && !words && + cpdcase_check(word, i)))) + // LANG_hu section: spec. Hungarian rule + || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && + (rv = affix_check(st.c_str(), i)) && + (sfx && sfx->getCont() && + ( // XXX hardwired Hungarian dic. codes + TESTAFF(sfx->getCont(), (unsigned short)'x', + sfx->getContLen()) || + TESTAFF( + sfx->getCont(), (unsigned short)'%', + sfx->getContLen()))))) { // first word is ok condition + + // LANG_hu section: spec. Hungarian rule + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(st.substr(i)); + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + } + // END of LANG_hu section + + // NEXT WORD(S) + rv_first = rv; + st[i] = ch; + + do { // striple loop + + // check simplifiedtriple + if (simplifiedtriple) { + if (striple) { + checkedstriple = 1; + i--; // check "fahrt" instead of "ahrt" in "Schiffahrt" + } else if (i > 2 && *(word + i - 1) == *(word + i - 2)) + striple = 1; + } + + rv = lookup(st.c_str() + i); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && + ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && !words && + TESTAFF(rv->astr, compoundend, rv->alen)) || + (numdefcpd && words && + defcpd_check(&words, wnum + 1, rv, NULL, 1))) || + (scpd != 0 && checkcpdtable[scpd - 1].cond2 != FLAG_NULL && + !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, + rv->alen)))) { + rv = rv->next_homonym; + } + + // check FORCEUCASE + if (rv && forceucase && (rv) && + (TESTAFF(rv->astr, forceucase, rv->alen)) && + !(info && *info & SPELL_ORIGCAP)) + rv = NULL; + + if (rv && words && words[wnum + 1]) + return rv_first; + + oldnumsyllable2 = numsyllable; + oldwordnum2 = wordnum; + + // LANG_hu section: spec. Hungarian rule, XXX hardwired dictionary + // code + if ((rv) && (langnum == LANG_hu) && + (TESTAFF(rv->astr, 'I', rv->alen)) && + !(TESTAFF(rv->astr, 'J', rv->alen))) { + numsyllable--; + } + // END of LANG_hu section + + // increment word number, if the second root has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && + TESTAFF(rv->astr, nosuggest, rv->alen)))) + return NULL; + + // second word is acceptable, as a root? + // hungarian conventions: compounding is acceptable, + // when compound forms consist of 2 words, or if more, + // then the syllable number of root words must be 6, or lesser. + + if ((rv) && + ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && + (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->clen)) <= + cpdmaxsyllable))) && + ( + // test CHECKCOMPOUNDPATTERN + !numcheckcpd || scpd != 0 || + !cpdpat_check(word, i, rv_first, rv, 0)) && + ((!checkcompounddup || (rv != rv_first))) + // test CHECKCOMPOUNDPATTERN conditions + && + (scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL || + TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) { + // forbid compound word, if it is a non compound word with typical + // fault + if (checkcompoundrep && cpdrep_check(word, len)) + return NULL; + return rv_first; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word has prefix or/and suffix + sfx = NULL; + sfxflag = FLAG_NULL; + rv = (compoundflag && !onlycpdrule) + ? affix_check((word + i), strlen(word + i), compoundflag, + IN_CPD_END) + : NULL; + if (!rv && compoundend && !onlycpdrule) { + sfx = NULL; + pfx = NULL; + rv = affix_check((word + i), strlen(word + i), compoundend, + IN_CPD_END); + } + + if (!rv && numdefcpd && words) { + rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END); + if (rv && defcpd_check(&words, wnum + 1, rv, NULL, 1)) + return rv_first; + rv = NULL; + } + + // test CHECKCOMPOUNDPATTERN conditions (allowed forms) + if (rv && + !(scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL || + TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) + rv = NULL; + + // test CHECKCOMPOUNDPATTERN conditions (forbidden compounds) + if (rv && numcheckcpd && scpd == 0 && + cpdpat_check(word, i, rv_first, rv, affixed)) + rv = NULL; + + // check non_compound flag in suffix and prefix + if ((rv) && ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, + pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())))) { + rv = NULL; + } + + // check FORCEUCASE + if (rv && forceucase && (rv) && + (TESTAFF(rv->astr, forceucase, rv->alen)) && + !(info && *info & SPELL_ORIGCAP)) + rv = NULL; + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && + TESTAFF(rv->astr, nosuggest, rv->alen)))) + return NULL; + + // pfxappnd = prefix of word+i, or NULL + // calculate syllable number of prefix. + // hungarian convention: when syllable number of prefix is more, + // than 1, the prefix+word counts as two words. + + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(word + i); + + // - affix syllable num. + // XXX only second suffix (inflections, not derivations) + if (sfxappnd) { + std::string tmp(sfxappnd); + reverseword(tmp); + numsyllable -= get_syllable(tmp) + sfxextra; + } + + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + + // increment syllable num, if last word has a SYLLABLENUM flag + // and the suffix is beginning `s' + + if (cpdsyllablenum) { + switch (sfxflag) { + case 'c': { + numsyllable += 2; + break; + } + case 'J': { + numsyllable += 1; + break; + } + case 'I': { + if (rv && TESTAFF(rv->astr, 'J', rv->alen)) + numsyllable += 1; + break; + } + } + } + } + + // increment word number, if the second word has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // second word is acceptable, as a word with prefix or/and suffix? + // hungarian conventions: compounding is acceptable, + // when compound forms consist 2 word, otherwise + // the syllable number of root words is 6, or lesser. + if ((rv) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) && + ((!checkcompounddup || (rv != rv_first)))) { + // forbid compound word, if it is a non compound word with typical + // fault + if (checkcompoundrep && cpdrep_check(word, len)) + return NULL; + return rv_first; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word is a compound word (recursive call) + if (wordnum < maxwordnum) { + rv = compound_check(st.c_str() + i, strlen(st.c_str() + i), wordnum + 1, + numsyllable, maxwordnum, wnum + 1, words, rwords, 0, + is_sug, info); + + if (rv && numcheckcpd && + ((scpd == 0 && + cpdpat_check(word, i, rv_first, rv, affixed)) || + (scpd != 0 && + !cpdpat_check(word, i, rv_first, rv, affixed)))) + rv = NULL; + } else { + rv = NULL; + } + if (rv) { + // forbid compound word, if it is a non compound word with typical + // fault + if (checkcompoundrep || forbiddenword) { + struct hentry* rv2 = NULL; + + if (checkcompoundrep && cpdrep_check(word, len)) + return NULL; + + // check first part + if (strncmp(rv->word, word + i, rv->blen) == 0) { + char r = st[i + rv->blen]; + st[i + rv->blen] = '\0'; + + if (checkcompoundrep && cpdrep_check(st.c_str(), i + rv->blen)) { + st[ + i + rv->blen] = r; + continue; + } + + if (forbiddenword) { + rv2 = lookup(word); + if (!rv2) + rv2 = affix_check(word, len); + if (rv2 && rv2->astr && + TESTAFF(rv2->astr, forbiddenword, rv2->alen) && + (strncmp(rv2->word, st.c_str(), i + rv->blen) == 0)) { + return NULL; + } + } + st[i + rv->blen] = r; + } + } + return rv_first; + } + } while (striple && !checkedstriple); // end of striple loop + + if (checkedstriple) { + i++; + checkedstriple = 0; + striple = 0; + } + + } // first word is ok condition + + if (soldi != 0) { + i = soldi; + soldi = 0; + len = oldlen; + cmin = oldcmin; + cmax = oldcmax; + } + scpd++; + + } while (!onlycpdrule && simplifiedcpd && + scpd <= numcheckcpd); // end of simplifiedcpd loop + + scpd = 0; + wordnum = oldwordnum; + numsyllable = oldnumsyllable; + + if (soldi != 0) { + i = soldi; + st.assign(word); // XXX add more optim. + soldi = 0; + } else + st[i] = ch; + + } while (numdefcpd && oldwordnum == 0 && + onlycpdrule++ < 1); // end of onlycpd loop + } + + return NULL; +} + +// check if compound word is correctly spelled +// hu_mov_rule = spec. Hungarian rule (XXX) +int AffixMgr::compound_check_morph(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words, + hentry** rwords, + char hu_mov_rule = 0, + char** result = NULL, + char* partresult = NULL) { + int i; + short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; + int ok = 0; + + struct hentry* rv = NULL; + struct hentry* rv_first; + std::string st; + char ch; + + int checked_prefix; + char presult[MAXLNLEN]; + + int cmin; + int cmax; + + int onlycpdrule; + char affixed = 0; + hentry** oldwords = words; + + setcminmax(&cmin, &cmax, word, len); + + st.assign(word); + + for (i = cmin; i < cmax; i++) { + // go to end of the UTF-8 character + if (utf8) { + for (; (st[i] & 0xc0) == 0x80; i++) + ; + if (i >= cmax) + return 0; + } + + words = oldwords; + onlycpdrule = (words) ? 1 : 0; + + do { // onlycpdrule loop + + oldnumsyllable = numsyllable; + oldwordnum = wordnum; + checked_prefix = 0; + + ch = st[i]; + st[i] = '\0'; + sfx = NULL; + + // FIRST WORD + + affixed = 1; + + *presult = '\0'; + if (partresult) + mystrcat(presult, partresult, MAXLNLEN); + + rv = lookup(st.c_str()); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && !hu_mov_rule && + ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundbegin && !wordnum && !onlycpdrule && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + (compoundmiddle && wordnum && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) || + (numdefcpd && onlycpdrule && + ((!words && !wordnum && + defcpd_check(&words, wnum, rv, rwords, 0)) || + (words && + defcpd_check(&words, wnum, rv, rwords, 0))))))) { + rv = rv->next_homonym; + } + + if (rv) + affixed = 0; + + if (rv) { + sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_PART, st.c_str()); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_STEM, + st.c_str()); + } + // store the pointer of the hash entry + // sprintf(presult + strlen(presult), "%c%s%p", MSEP_FLD, + // MORPH_HENTRY, rv); + if (HENTRY_DATA(rv)) { + sprintf(presult + strlen(presult), "%c%s", MSEP_FLD, + HENTRY_DATA2(rv)); + } + } + + if (!rv) { + if (onlycpdrule && strlen(*result) > MAXLNLEN / 10) + break; + if (compoundflag && + !(rv = + prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundflag))) { + if (((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, + compoundflag, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) && + !hu_mov_rule && sfx->getCont() && + ((compoundforbidflag && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())) || + (compoundend && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = NULL; + } + } + + if (rv || + (((wordnum == 0) && compoundbegin && + ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, + compoundbegin, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundbegin))) || // twofold suffix+compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundbegin)))) || + ((wordnum > 0) && compoundmiddle && + ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, + compoundmiddle, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundmiddle))) || // twofold suffix+compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundmiddle)))))) { + // char * p = prefix_check_morph(st, i, 0, compound); + char* p = NULL; + if (compoundflag) + p = affix_check_morph(st.c_str(), i, compoundflag); + if (!p || (*p == '\0')) { + if (p) + free(p); + p = NULL; + if ((wordnum == 0) && compoundbegin) { + p = affix_check_morph(st.c_str(), i, compoundbegin); + } else if ((wordnum > 0) && compoundmiddle) { + p = affix_check_morph(st.c_str(), i, compoundmiddle); + } + } + if (p && (*p != '\0')) { + sprintf(presult + strlen(presult), "%c%s%s%s", MSEP_FLD, MORPH_PART, + st.c_str(), line_uniq_app(&p, MSEP_REC)); + } + if (p) + free(p); + checked_prefix = 1; + } + // else check forbiddenwords + } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + TESTAFF(rv->astr, needaffix, rv->alen))) { + st[i] = ch; + continue; + } + + // check non_compound flag in suffix and prefix + if ((rv) && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())))) { + continue; + } + + // check compoundend flag in suffix and prefix + if ((rv) && !checked_prefix && compoundend && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundend, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + continue; + } + + // check compoundmiddle flag in suffix and prefix + if ((rv) && !checked_prefix && (wordnum == 0) && compoundmiddle && + !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundmiddle, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundmiddle, sfx->getContLen())))) { + rv = NULL; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) + continue; + + // increment word number, if the second root has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // first word is acceptable in compound words? + if (((rv) && + (checked_prefix || (words && words[wnum]) || + (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + ((oldwordnum == 0) && compoundbegin && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + ((oldwordnum > 0) && compoundmiddle && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) + // LANG_hu section: spec. Hungarian rule + || ((langnum == LANG_hu) && // hu_mov_rule + hu_mov_rule && (TESTAFF(rv->astr, 'F', rv->alen) || + TESTAFF(rv->astr, 'G', rv->alen) || + TESTAFF(rv->astr, 'H', rv->alen))) + // END of LANG_hu section + ) && + !((checkcompoundtriple && !words && // test triple letters + (word[i - 1] == word[i]) && + (((i > 1) && (word[i - 1] == word[i - 2])) || + ((word[i - 1] == word[i + 1])) // may be word[i+1] == '\0' + )) || + ( + // test CHECKCOMPOUNDPATTERN + numcheckcpd && !words && + cpdpat_check(word, i, rv, NULL, affixed)) || + (checkcompoundcase && !words && cpdcase_check(word, i)))) + // LANG_hu section: spec. Hungarian rule + || + ((!rv) && (langnum == LANG_hu) && hu_mov_rule && + (rv = affix_check(st.c_str(), i)) && + (sfx && sfx->getCont() && + (TESTAFF(sfx->getCont(), (unsigned short)'x', sfx->getContLen()) || + TESTAFF(sfx->getCont(), (unsigned short)'%', sfx->getContLen())))) + // END of LANG_hu section + ) { + // LANG_hu section: spec. Hungarian rule + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(st.substr(i)); + + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + } + // END of LANG_hu section + + // NEXT WORD(S) + rv_first = rv; + rv = lookup((word + i)); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && !words && + TESTAFF(rv->astr, compoundend, rv->alen)) || + (numdefcpd && words && + defcpd_check(&words, wnum + 1, rv, NULL, 1))))) { + rv = rv->next_homonym; + } + + if (rv && words && words[wnum + 1]) { + mystrcat(*result, presult, MAXLNLEN); + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_PART, MAXLNLEN); + mystrcat(*result, word + i, MAXLNLEN); + if (complexprefixes && HENTRY_DATA(rv)) + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_STEM, MAXLNLEN); + mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(*result + strlen(*result), " %s%p", + // MORPH_HENTRY, rv); + if (!complexprefixes && HENTRY_DATA(rv)) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + } + mystrcat(*result, "\n", MAXLNLEN); + return 0; + } + + oldnumsyllable2 = numsyllable; + oldwordnum2 = wordnum; + + // LANG_hu section: spec. Hungarian rule + if ((rv) && (langnum == LANG_hu) && + (TESTAFF(rv->astr, 'I', rv->alen)) && + !(TESTAFF(rv->astr, 'J', rv->alen))) { + numsyllable--; + } + // END of LANG_hu section + // increment word number, if the second root has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) { + st[i] = ch; + continue; + } + + // second word is acceptable, as a root? + // hungarian conventions: compounding is acceptable, + // when compound forms consist of 2 words, or if more, + // then the syllable number of root words must be 6, or lesser. + if ((rv) && + ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && + (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->blen)) <= + cpdmaxsyllable))) && + ((!checkcompounddup || (rv != rv_first)))) { + // bad compound word + mystrcat(*result, presult, MAXLNLEN); + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_PART, MAXLNLEN); + mystrcat(*result, word + i, MAXLNLEN); + + if (HENTRY_DATA(rv)) { + if (complexprefixes) + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_STEM, MAXLNLEN); + mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(*result + strlen(*result), " + // %s%p", MORPH_HENTRY, rv); + if (!complexprefixes) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + } + } + mystrcat(*result, "\n", MAXLNLEN); + ok = 1; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word has prefix or/and suffix + sfx = NULL; + sfxflag = FLAG_NULL; + + if (compoundflag && !onlycpdrule) + rv = affix_check((word + i), strlen(word + i), compoundflag); + else + rv = NULL; + + if (!rv && compoundend && !onlycpdrule) { + sfx = NULL; + pfx = NULL; + rv = affix_check((word + i), strlen(word + i), compoundend); + } + + if (!rv && numdefcpd && words) { + rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END); + if (rv && words && defcpd_check(&words, wnum + 1, rv, NULL, 1)) { + char* m = NULL; + if (compoundflag) + m = affix_check_morph((word + i), strlen(word + i), compoundflag); + if ((!m || *m == '\0') && compoundend) { + if (m) + free(m); + m = affix_check_morph((word + i), strlen(word + i), compoundend); + } + mystrcat(*result, presult, MAXLNLEN); + if (m || (*m != '\0')) { + char m2[MAXLNLEN]; + sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i, + line_uniq_app(&m, MSEP_REC)); + mystrcat(*result, m2, MAXLNLEN); + } + if (m) + free(m); + mystrcat(*result, "\n", MAXLNLEN); + ok = 1; + } + } + + // check non_compound flag in suffix and prefix + if ((rv) && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())))) { + rv = NULL; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen)) && + (!TESTAFF(rv->astr, needaffix, rv->alen))) { + st[i] = ch; + continue; + } + + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(word + i); + + // - affix syllable num. + // XXX only second suffix (inflections, not derivations) + if (sfxappnd) { + std::string tmp(sfxappnd); + reverseword(tmp); + numsyllable -= get_syllable(tmp) + sfxextra; + } + + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + + // increment syllable num, if last word has a SYLLABLENUM flag + // and the suffix is beginning `s' + + if (cpdsyllablenum) { + switch (sfxflag) { + case 'c': { + numsyllable += 2; + break; + } + case 'J': { + numsyllable += 1; + break; + } + case 'I': { + if (rv && TESTAFF(rv->astr, 'J', rv->alen)) + numsyllable += 1; + break; + } + } + } + } + + // increment word number, if the second word has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + // second word is acceptable, as a word with prefix or/and suffix? + // hungarian conventions: compounding is acceptable, + // when compound forms consist 2 word, otherwise + // the syllable number of root words is 6, or lesser. + if ((rv) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) && + ((!checkcompounddup || (rv != rv_first)))) { + char* m = NULL; + if (compoundflag) + m = affix_check_morph((word + i), strlen(word + i), compoundflag); + if ((!m || *m == '\0') && compoundend) { + if (m) + free(m); + m = affix_check_morph((word + i), strlen(word + i), compoundend); + } + mystrcat(*result, presult, MAXLNLEN); + if (m && (*m != '\0')) { + char m2[MAXLNLEN]; + sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i, + line_uniq_app(&m, MSEP_REC)); + mystrcat(*result, m2, MAXLNLEN); + } + if (m) + free(m); + if (strlen(*result) + 1 < MAXLNLEN) + sprintf(*result + strlen(*result), "%c", MSEP_REC); + ok = 1; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word is a compound word (recursive call) + if ((wordnum < maxwordnum) && (ok == 0)) { + compound_check_morph((word + i), strlen(word + i), wordnum + 1, + numsyllable, maxwordnum, wnum + 1, words, rwords, 0, + result, presult); + } else { + rv = NULL; + } + } + st[i] = ch; + wordnum = oldwordnum; + numsyllable = oldnumsyllable; + + } while (numdefcpd && oldwordnum == 0 && + onlycpdrule++ < 1); // end of onlycpd loop + } + return 0; +} + + +// return 1 if s1 (reversed) is a leading subset of end of s2 +/* inline int AffixMgr::isRevSubset(const char * s1, const char * end_of_s2, int + len) + { + while ((len > 0) && *s1 && (*s1 == *end_of_s2)) { + s1++; + end_of_s2--; + len--; + } + return (*s1 == '\0'); + } + */ + +inline int AffixMgr::isRevSubset(const char* s1, + const char* end_of_s2, + int len) { + while ((len > 0) && (*s1 != '\0') && ((*s1 == *end_of_s2) || (*s1 == '.'))) { + s1++; + end_of_s2--; + len--; + } + return (*s1 == '\0'); +} + +// check word for suffixes + +struct hentry* AffixMgr::suffix_check(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass, + const FLAG needflag, + char in_compound) { + struct hentry* rv = NULL; + PfxEntry* ep = ppfx; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + + while (se) { + if (!cclass || se->getCont()) { + // suffixes are not allowed in beginning of compounds + if ((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (se->getCont() && compoundpermitflag && + TESTAFF(se->getCont(), compoundpermitflag, se->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!se->getCont() || + !(TESTAFF(se->getCont(), circumfix, se->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (se->getCont() && + (TESTAFF(se->getCont(), circumfix, se->getContLen()))))) && + // fogemorpheme + (in_compound || + !(se->getCont() && + (TESTAFF(se->getCont(), onlyincompound, se->getContLen())))) && + // needaffix on prefix or first suffix + (cclass || + !(se->getCont() && + TESTAFF(se->getCont(), needaffix, se->getContLen())) || + (ppfx && + !((ep->getCont()) && + TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) { + rv = se->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns, + (FLAG)cclass, needflag, + (in_compound ? 0 : onlyincompound)); + if (rv) { + sfx = se; // BUG: sfx not stateless + return rv; + } + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + // suffixes are not allowed in beginning of compounds + if ((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (sptr->getCont() && compoundpermitflag && + TESTAFF(sptr->getCont(), compoundpermitflag, + sptr->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!sptr->getCont() || + !(TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (sptr->getCont() && + (TESTAFF(sptr->getCont(), circumfix, sptr->getContLen()))))) && + // fogemorpheme + (in_compound || + !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, + sptr->getContLen()))))) && + // needaffix on prefix or first suffix + (cclass || + !(sptr->getCont() && + TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) || + (ppfx && + !((ep->getCont()) && + TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) + if (in_compound != IN_CPD_END || ppfx || + !(sptr->getCont() && + TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))) { + rv = sptr->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns, + cclass, needflag, + (in_compound ? 0 : onlyincompound)); + if (rv) { + sfx = sptr; // BUG: sfx not stateless + sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless + if (!sptr->getCont()) + sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless + // LANG_hu section: spec. Hungarian rule + else if (langnum == LANG_hu && sptr->getKeyLen() && + sptr->getKey()[0] == 'i' && sptr->getKey()[1] != 'y' && + sptr->getKey()[1] != 't') { + sfxextra = 1; + } + // END of LANG_hu section + return rv; + } + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + return NULL; +} + +// check word for two-level suffixes + +struct hentry* AffixMgr::suffix_check_twosfx(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag) { + struct hentry* rv = NULL; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + while (se) { + if (contclasses[se->getFlag()]) { + rv = se->check_twosfx(word, len, sfxopts, ppfx, needflag); + if (rv) + return rv; + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + if (contclasses[sptr->getFlag()]) { + rv = sptr->check_twosfx(word, len, sfxopts, ppfx, needflag); + if (rv) { + sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless + if (!sptr->getCont()) + sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless + return rv; + } + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + return NULL; +} + +char* AffixMgr::suffix_check_twosfx_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag) { + std::string result; + std::string result2; + std::string result3; + + char* st; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + while (se) { + if (contclasses[se->getFlag()]) { + st = se->check_twosfx_morph(word, len, sfxopts, ppfx, needflag); + if (st) { + if (ppfx) { + if (ppfx->getMorph()) { + result.append(ppfx->getMorph()); + result.append(" "); + } else + debugflag(result, ppfx->getFlag()); + } + result.append(st); + free(st); + if (se->getMorph()) { + result.append(" "); + result.append(se->getMorph()); + } else + debugflag(result, se->getFlag()); + result.append("\n"); + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + if (contclasses[sptr->getFlag()]) { + st = sptr->check_twosfx_morph(word, len, sfxopts, ppfx, needflag); + if (st) { + sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless + if (!sptr->getCont()) + sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless + result2.assign(st); + free(st); + + result3.clear(); + + if (sptr->getMorph()) { + result3.append(" "); + result3.append(sptr->getMorph()); + } else + debugflag(result3, sptr->getFlag()); + strlinecat(result2, result3); + result2.append("\n"); + result.append(result2); + } + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + if (!result.empty()) + return mystrdup(result.c_str()); + + return NULL; +} + +char* AffixMgr::suffix_check_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag, + char in_compound) { + char result[MAXLNLEN]; + + struct hentry* rv = NULL; + + result[0] = '\0'; + + PfxEntry* ep = ppfx; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + while (se) { + if (!cclass || se->getCont()) { + // suffixes are not allowed in beginning of compounds + if (((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (se->getCont() && compoundpermitflag && + TESTAFF(se->getCont(), compoundpermitflag, se->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!se->getCont() || + !(TESTAFF(se->getCont(), circumfix, se->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (se->getCont() && + (TESTAFF(se->getCont(), circumfix, se->getContLen()))))) && + // fogemorpheme + (in_compound || + !((se->getCont() && + (TESTAFF(se->getCont(), onlyincompound, se->getContLen()))))) && + // needaffix on prefix or first suffix + (cclass || + !(se->getCont() && + TESTAFF(se->getCont(), needaffix, se->getContLen())) || + (ppfx && + !((ep->getCont()) && + TESTAFF(ep->getCont(), needaffix, ep->getContLen())))))) + rv = se->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass, + needflag); + while (rv) { + if (ppfx) { + if (ppfx->getMorph()) { + mystrcat(result, ppfx->getMorph(), MAXLNLEN); + mystrcat(result, " ", MAXLNLEN); + } else + debugflag(result, ppfx->getFlag()); + } + if (complexprefixes && HENTRY_DATA(rv)) + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_STEM, MAXLNLEN); + mystrcat(result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(result + strlen(result), " %s%p", MORPH_HENTRY, + // rv); + + if (!complexprefixes && HENTRY_DATA(rv)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + } + if (se->getMorph()) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, se->getMorph(), MAXLNLEN); + } else + debugflag(result, se->getFlag()); + mystrcat(result, "\n", MAXLNLEN); + rv = se->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag); + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + // suffixes are not allowed in beginning of compounds + if (((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (sptr->getCont() && compoundpermitflag && + TESTAFF(sptr->getCont(), compoundpermitflag, + sptr->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!sptr->getCont() || + !(TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (sptr->getCont() && + (TESTAFF(sptr->getCont(), circumfix, sptr->getContLen()))))) && + // fogemorpheme + (in_compound || + !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, + sptr->getContLen()))))) && + // needaffix on first suffix + (cclass || + !(sptr->getCont() && + TESTAFF(sptr->getCont(), needaffix, sptr->getContLen()))))) + rv = sptr->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass, + needflag); + while (rv) { + if (ppfx) { + if (ppfx->getMorph()) { + mystrcat(result, ppfx->getMorph(), MAXLNLEN); + mystrcat(result, " ", MAXLNLEN); + } else + debugflag(result, ppfx->getFlag()); + } + if (complexprefixes && HENTRY_DATA(rv)) + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_STEM, MAXLNLEN); + mystrcat(result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(result + strlen(result), " %s%p", + // MORPH_HENTRY, rv); + + if (!complexprefixes && HENTRY_DATA(rv)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + } + + if (sptr->getMorph()) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, sptr->getMorph(), MAXLNLEN); + } else + debugflag(result, sptr->getFlag()); + mystrcat(result, "\n", MAXLNLEN); + rv = sptr->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag); + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + if (*result) + return mystrdup(result); + return NULL; +} + +// check if word with affixes is correctly spelled +struct hentry* AffixMgr::affix_check(const char* word, + int len, + const FLAG needflag, + char in_compound) { + struct hentry* rv = NULL; + + // check all prefixes (also crossed with suffixes if allowed) + rv = prefix_check(word, len, in_compound, needflag); + if (rv) + return rv; + + // if still not found check all suffixes + rv = suffix_check(word, len, 0, NULL, NULL, 0, NULL, FLAG_NULL, needflag, + in_compound); + + if (havecontclass) { + sfx = NULL; + pfx = NULL; + + if (rv) + return rv; + // if still not found check all two-level suffixes + rv = suffix_check_twosfx(word, len, 0, NULL, needflag); + + if (rv) + return rv; + // if still not found check all two-level suffixes + rv = prefix_check_twosfx(word, len, IN_CPD_NOT, needflag); + } + + return rv; +} + +// check if word with affixes is correctly spelled +char* AffixMgr::affix_check_morph(const char* word, + int len, + const FLAG needflag, + char in_compound) { + char result[MAXLNLEN]; + char* st = NULL; + + *result = '\0'; + + // check all prefixes (also crossed with suffixes if allowed) + st = prefix_check_morph(word, len, in_compound); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + // if still not found check all suffixes + st = suffix_check_morph(word, len, 0, NULL, '\0', needflag, in_compound); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + if (havecontclass) { + sfx = NULL; + pfx = NULL; + // if still not found check all two-level suffixes + st = suffix_check_twosfx_morph(word, len, 0, NULL, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + // if still not found check all two-level suffixes + st = prefix_check_twosfx_morph(word, len, IN_CPD_NOT, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + } + + return mystrdup(result); +} + +char* AffixMgr::morphgen(const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* morph, + const char* targetmorph, + int level) { + // handle suffixes + if (!morph) + return NULL; + + // check substandard flag + if (TESTAFF(ap, substandard, al)) + return NULL; + + if (morphcmp(morph, targetmorph) == 0) + return mystrdup(ts); + + size_t stemmorphcatpos; + std::string mymorph; + + // use input suffix fields, if exist + if (strstr(morph, MORPH_INFL_SFX) || strstr(morph, MORPH_DERI_SFX)) { + mymorph.assign(morph); + mymorph.append(" "); + stemmorphcatpos = mymorph.size(); + } else { + stemmorphcatpos = std::string::npos; + } + + for (int i = 0; i < al; i++) { + const unsigned char c = (unsigned char)(ap[i] & 0x00FF); + SfxEntry* sptr = sFlag[c]; + while (sptr) { + if (sptr->getFlag() == ap[i] && sptr->getMorph() && + ((sptr->getContLen() == 0) || + // don't generate forms with substandard affixes + !TESTAFF(sptr->getCont(), substandard, sptr->getContLen()))) { + const char* stemmorph; + if (stemmorphcatpos != std::string::npos) { + mymorph.replace(stemmorphcatpos, std::string::npos, sptr->getMorph()); + stemmorph = mymorph.c_str(); + } else { + stemmorph = sptr->getMorph(); + } + + int cmp = morphcmp(stemmorph, targetmorph); + + if (cmp == 0) { + char* newword = sptr->add(ts, wl); + if (newword) { + hentry* check = pHMgr->lookup(newword); // XXX extra dic + if (!check || !check->astr || + !(TESTAFF(check->astr, forbiddenword, check->alen) || + TESTAFF(check->astr, ONLYUPCASEFLAG, check->alen))) { + return newword; + } + free(newword); + } + } + + // recursive call for secondary suffixes + if ((level == 0) && (cmp == 1) && (sptr->getContLen() > 0) && + // (get_sfxcount(stemmorph) < targetcount) && + !TESTAFF(sptr->getCont(), substandard, sptr->getContLen())) { + char* newword = sptr->add(ts, wl); + if (newword) { + char* newword2 = + morphgen(newword, strlen(newword), sptr->getCont(), + sptr->getContLen(), stemmorph, targetmorph, 1); + + if (newword2) { + free(newword); + return newword2; + } + free(newword); + newword = NULL; + } + } + } + sptr = sptr->getFlgNxt(); + } + } + return NULL; +} + +int AffixMgr::expand_rootword(struct guessword* wlst, + int maxn, + const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* bad, + int badl, + const char* phon) { + int nh = 0; + // first add root word to list + if ((nh < maxn) && + !(al && ((needaffix && TESTAFF(ap, needaffix, al)) || + (onlyincompound && TESTAFF(ap, onlyincompound, al))))) { + wlst[nh].word = mystrdup(ts); + if (!wlst[nh].word) + return 0; + wlst[nh].allow = (1 == 0); + wlst[nh].orig = NULL; + nh++; + // add special phonetic version + if (phon && (nh < maxn)) { + wlst[nh].word = mystrdup(phon); + if (!wlst[nh].word) + return nh - 1; + wlst[nh].allow = (1 == 0); + wlst[nh].orig = mystrdup(ts); + if (!wlst[nh].orig) + return nh - 1; + nh++; + } + } + + // handle suffixes + for (int i = 0; i < al; i++) { + const unsigned char c = (unsigned char)(ap[i] & 0x00FF); + SfxEntry* sptr = sFlag[c]; + while (sptr) { + if ((sptr->getFlag() == ap[i]) && + (!sptr->getKeyLen() || + ((badl > sptr->getKeyLen()) && + (strcmp(sptr->getAffix(), bad + badl - sptr->getKeyLen()) == 0))) && + // check needaffix flag + !(sptr->getCont() && + ((needaffix && + TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) || + (circumfix && + TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())) || + (onlyincompound && + TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) { + char* newword = sptr->add(ts, wl); + if (newword) { + if (nh < maxn) { + wlst[nh].word = newword; + wlst[nh].allow = sptr->allowCross(); + wlst[nh].orig = NULL; + nh++; + // add special phonetic version + if (phon && (nh < maxn)) { + std::string prefix(phon); + std::string key(sptr->getKey()); + reverseword(key); + prefix.append(key); + wlst[nh].word = mystrdup(prefix.c_str()); + if (!wlst[nh].word) + return nh - 1; + wlst[nh].allow = (1 == 0); + wlst[nh].orig = mystrdup(newword); + if (!wlst[nh].orig) + return nh - 1; + nh++; + } + } else { + free(newword); + } + } + } + sptr = sptr->getFlgNxt(); + } + } + + int n = nh; + + // handle cross products of prefixes and suffixes + for (int j = 1; j < n; j++) + if (wlst[j].allow) { + for (int k = 0; k < al; k++) { + const unsigned char c = (unsigned char)(ap[k] & 0x00FF); + PfxEntry* cptr = pFlag[c]; + while (cptr) { + if ((cptr->getFlag() == ap[k]) && cptr->allowCross() && + (!cptr->getKeyLen() || + ((badl > cptr->getKeyLen()) && + (strncmp(cptr->getKey(), bad, cptr->getKeyLen()) == 0)))) { + int l1 = strlen(wlst[j].word); + char* newword = cptr->add(wlst[j].word, l1); + if (newword) { + if (nh < maxn) { + wlst[nh].word = newword; + wlst[nh].allow = cptr->allowCross(); + wlst[nh].orig = NULL; + nh++; + } else { + free(newword); + } + } + } + cptr = cptr->getFlgNxt(); + } + } + } + + // now handle pure prefixes + for (int m = 0; m < al; m++) { + const unsigned char c = (unsigned char)(ap[m] & 0x00FF); + PfxEntry* ptr = pFlag[c]; + while (ptr) { + if ((ptr->getFlag() == ap[m]) && + (!ptr->getKeyLen() || + ((badl > ptr->getKeyLen()) && + (strncmp(ptr->getKey(), bad, ptr->getKeyLen()) == 0))) && + // check needaffix flag + !(ptr->getCont() && + ((needaffix && + TESTAFF(ptr->getCont(), needaffix, ptr->getContLen())) || + (circumfix && + TESTAFF(ptr->getCont(), circumfix, ptr->getContLen())) || + (onlyincompound && + TESTAFF(ptr->getCont(), onlyincompound, ptr->getContLen()))))) { + char* newword = ptr->add(ts, wl); + if (newword) { + if (nh < maxn) { + wlst[nh].word = newword; + wlst[nh].allow = ptr->allowCross(); + wlst[nh].orig = NULL; + nh++; + } else { + free(newword); + } + } + } + ptr = ptr->getFlgNxt(); + } + } + + return nh; +} + +// return length of replacing table +int AffixMgr::get_numrep() const { + return numrep; +} + +// return replacing table +struct replentry* AffixMgr::get_reptable() const { + if (!reptable) + return NULL; + return reptable; +} + +// return iconv table +RepList* AffixMgr::get_iconvtable() const { + if (!iconvtable) + return NULL; + return iconvtable; +} + +// return oconv table +RepList* AffixMgr::get_oconvtable() const { + if (!oconvtable) + return NULL; + return oconvtable; +} + +// return replacing table +struct phonetable* AffixMgr::get_phonetable() const { + if (!phone) + return NULL; + return phone; +} + +// return length of character map table +int AffixMgr::get_nummap() const { + return nummap; +} + +// return character map table +struct mapentry* AffixMgr::get_maptable() const { + if (!maptable) + return NULL; + return maptable; +} + +// return length of word break table +int AffixMgr::get_numbreak() const { + return numbreak; +} + +// return character map table +char** AffixMgr::get_breaktable() const { + if (!breaktable) + return NULL; + return breaktable; +} + +// return text encoding of dictionary +char* AffixMgr::get_encoding() { + if (!encoding) + encoding = mystrdup(SPELL_ENCODING); + return mystrdup(encoding); +} + +// return text encoding of dictionary +int AffixMgr::get_langnum() const { + return langnum; +} + +// return double prefix option +int AffixMgr::get_complexprefixes() const { + return complexprefixes; +} + +// return FULLSTRIP option +int AffixMgr::get_fullstrip() const { + return fullstrip; +} + +FLAG AffixMgr::get_keepcase() const { + return keepcase; +} + +FLAG AffixMgr::get_forceucase() const { + return forceucase; +} + +FLAG AffixMgr::get_warn() const { + return warn; +} + +int AffixMgr::get_forbidwarn() const { + return forbidwarn; +} + +int AffixMgr::get_checksharps() const { + return checksharps; +} + +char* AffixMgr::encode_flag(unsigned short aflag) const { + return pHMgr->encode_flag(aflag); +} + +// return the preferred ignore string for suggestions +char* AffixMgr::get_ignore() const { + if (!ignorechars) + return NULL; + return ignorechars; +} + +// return the preferred ignore string for suggestions +const std::vector& AffixMgr::get_ignore_utf16() const { + return ignorechars_utf16; +} + +// return the keyboard string for suggestions +char* AffixMgr::get_key_string() { + if (!keystring) + keystring = mystrdup(SPELL_KEYSTRING); + return mystrdup(keystring); +} + +// return the preferred try string for suggestions +char* AffixMgr::get_try_string() const { + if (!trystring) + return NULL; + return mystrdup(trystring); +} + +// return the preferred try string for suggestions +const char* AffixMgr::get_wordchars() const { + return wordchars; +} + +const std::vector& AffixMgr::get_wordchars_utf16() const { + return wordchars_utf16; +} + +// is there compounding? +int AffixMgr::get_compound() const { + return compoundflag || compoundbegin || numdefcpd; +} + +// return the compound words control flag +FLAG AffixMgr::get_compoundflag() const { + return compoundflag; +} + +// return the forbidden words control flag +FLAG AffixMgr::get_forbiddenword() const { + return forbiddenword; +} + +// return the forbidden words control flag +FLAG AffixMgr::get_nosuggest() const { + return nosuggest; +} + +// return the forbidden words control flag +FLAG AffixMgr::get_nongramsuggest() const { + return nongramsuggest; +} + +// return the forbidden words flag modify flag +FLAG AffixMgr::get_needaffix() const { + return needaffix; +} + +// return the onlyincompound flag +FLAG AffixMgr::get_onlyincompound() const { + return onlyincompound; +} + +// return the compound word signal flag +FLAG AffixMgr::get_compoundroot() const { + return compoundroot; +} + +// return the compound begin signal flag +FLAG AffixMgr::get_compoundbegin() const { + return compoundbegin; +} + +// return the value of checknum +int AffixMgr::get_checknum() const { + return checknum; +} + +// return the value of prefix +const char* AffixMgr::get_prefix() const { + if (pfx) + return pfx->getKey(); + return NULL; +} + +// return the value of suffix +const char* AffixMgr::get_suffix() const { + return sfxappnd; +} + +// return the value of suffix +const char* AffixMgr::get_version() const { + return version; +} + +// return lemma_present flag +FLAG AffixMgr::get_lemma_present() const { + return lemma_present; +} + +// utility method to look up root words in hash table +struct hentry* AffixMgr::lookup(const char* word) { + int i; + struct hentry* he = NULL; + for (i = 0; i < *maxdic && !he; i++) { + he = (alldic[i])->lookup(word); + } + return he; +} + +// return the value of suffix +int AffixMgr::have_contclass() const { + return havecontclass; +} + +// return utf8 +int AffixMgr::get_utf8() const { + return utf8; +} + +int AffixMgr::get_maxngramsugs(void) const { + return maxngramsugs; +} + +int AffixMgr::get_maxcpdsugs(void) const { + return maxcpdsugs; +} + +int AffixMgr::get_maxdiff(void) const { + return maxdiff; +} + +int AffixMgr::get_onlymaxdiff(void) const { + return onlymaxdiff; +} + +// return nosplitsugs +int AffixMgr::get_nosplitsugs(void) const { + return nosplitsugs; +} + +// return sugswithdots +int AffixMgr::get_sugswithdots(void) const { + return sugswithdots; +} + +/* parse flag */ +int AffixMgr::parse_flag(char* line, unsigned short* out, FileMgr* af) { + char* s = NULL; + if (*out != FLAG_NULL && !(*out >= DEFAULTFLAGS)) { + HUNSPELL_WARNING( + stderr, + "error: line %d: multiple definitions of an affix file parameter\n", + af->getlinenum()); + return 1; + } + if (parse_string(line, &s, af->getlinenum())) + return 1; + *out = pHMgr->decode_flag(s); + free(s); + return 0; +} + +/* parse num */ +int AffixMgr::parse_num(char* line, int* out, FileMgr* af) { + char* s = NULL; + if (*out != -1) { + HUNSPELL_WARNING( + stderr, + "error: line %d: multiple definitions of an affix file parameter\n", + af->getlinenum()); + return 1; + } + if (parse_string(line, &s, af->getlinenum())) + return 1; + *out = atoi(s); + free(s); + return 0; +} + +/* parse in the max syllablecount of compound words and */ +int AffixMgr::parse_cpdsyllable(char* line, FileMgr* af) { + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + cpdmaxsyllable = atoi(piece); + np++; + break; + } + case 2: { + if (!utf8) { + cpdvowels = mystrdup(piece); + } else { + std::vector w; + u8_u16(w, piece); + if (!w.empty()) { + std::sort(w.begin(), w.end()); + cpdvowels_utf16 = (w_char*)malloc(w.size() * sizeof(w_char)); + if (!cpdvowels_utf16) + return 1; + memcpy(cpdvowels_utf16, &w[0], w.size()); + } + cpdvowels_utf16_len = w.size(); + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np < 2) { + HUNSPELL_WARNING(stderr, + "error: line %d: missing compoundsyllable information\n", + af->getlinenum()); + return 1; + } + if (np == 2) + cpdvowels = mystrdup("aeiouAEIOU"); + return 0; +} + +/* parse in the typical fault correcting table */ +int AffixMgr::parse_reptable(char* line, FileMgr* af) { + if (numrep != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numrep = atoi(piece); + if (numrep < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", + af->getlinenum()); + return 1; + } + reptable = (replentry*)malloc(numrep * sizeof(struct replentry)); + if (!reptable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numrep lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numrep; j++) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + reptable[j].pattern = NULL; + reptable[j].pattern2 = NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "REP", 3) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numrep = 0; + return 1; + } + break; + } + case 1: { + if (*piece == '^') + reptable[j].start = true; + else + reptable[j].start = false; + reptable[j].pattern = + mystrrep(mystrdup(piece + int(reptable[j].start)), "_", " "); + int lr = strlen(reptable[j].pattern) - 1; + if (reptable[j].pattern[lr] == '$') { + reptable[j].end = true; + reptable[j].pattern[lr] = '\0'; + } else + reptable[j].end = false; + break; + } + case 2: { + reptable[j].pattern2 = mystrrep(mystrdup(piece), "_", " "); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if ((!(reptable[j].pattern)) || (!(reptable[j].pattern2))) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numrep = 0; + return 1; + } + } + return 0; +} + +/* parse in the typical fault correcting table */ +int AffixMgr::parse_convtable(char* line, + FileMgr* af, + RepList** rl, + const char* keyword) { + if (*rl) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + int numrl = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numrl = atoi(piece); + if (numrl < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", + af->getlinenum()); + return 1; + } + *rl = new RepList(numrl); + if (!*rl) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the num lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numrl; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + char* pattern = NULL; + char* pattern2 = NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, keyword, strlen(keyword)) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + delete *rl; + *rl = NULL; + return 1; + } + break; + } + case 1: { + pattern = mystrrep(mystrdup(piece), "_", " "); + break; + } + case 2: { + pattern2 = mystrrep(mystrdup(piece), "_", " "); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!pattern || !pattern2) { + if (pattern) + free(pattern); + if (pattern2) + free(pattern2); + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + (*rl)->add(pattern, pattern2); + } + return 0; +} + +/* parse in the typical fault correcting table */ +int AffixMgr::parse_phonetable(char* line, FileMgr* af) { + if (phone) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + phone = (phonetable*)malloc(sizeof(struct phonetable)); + if (!phone) + return 1; + phone->num = atoi(piece); + phone->rules = NULL; + phone->utf8 = (char)utf8; + if (phone->num < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + phone->rules = (char**)malloc(2 * (phone->num + 1) * sizeof(char*)); + if (!phone->rules) { + free(phone); + phone = NULL; + return 1; + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the phone->num lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < phone->num; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + phone->rules[j * 2] = NULL; + phone->rules[j * 2 + 1] = NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "PHONE", 5) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + phone->num = 0; + return 1; + } + break; + } + case 1: { + phone->rules[j * 2] = mystrrep(mystrdup(piece), "_", ""); + break; + } + case 2: { + phone->rules[j * 2 + 1] = mystrrep(mystrdup(piece), "_", ""); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if ((!(phone->rules[j * 2])) || (!(phone->rules[j * 2 + 1]))) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + phone->num = 0; + return 1; + } + } + phone->rules[phone->num * 2] = mystrdup(""); + phone->rules[phone->num * 2 + 1] = mystrdup(""); + init_phonet_hash(*phone); + return 0; +} + +/* parse in the checkcompoundpattern table */ +int AffixMgr::parse_checkcpdtable(char* line, FileMgr* af) { + if (numcheckcpd != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numcheckcpd = atoi(piece); + if (numcheckcpd < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + checkcpdtable = + (patentry*)malloc(numcheckcpd * sizeof(struct patentry)); + if (!checkcpdtable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numcheckcpd lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numcheckcpd; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + checkcpdtable[j].pattern = NULL; + checkcpdtable[j].pattern2 = NULL; + checkcpdtable[j].pattern3 = NULL; + checkcpdtable[j].cond = FLAG_NULL; + checkcpdtable[j].cond2 = FLAG_NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "CHECKCOMPOUNDPATTERN", 20) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numcheckcpd = 0; + return 1; + } + break; + } + case 1: { + checkcpdtable[j].pattern = mystrdup(piece); + char* p = strchr(checkcpdtable[j].pattern, '/'); + if (p) { + *p = '\0'; + checkcpdtable[j].cond = pHMgr->decode_flag(p + 1); + } + break; + } + case 2: { + checkcpdtable[j].pattern2 = mystrdup(piece); + char* p = strchr(checkcpdtable[j].pattern2, '/'); + if (p) { + *p = '\0'; + checkcpdtable[j].cond2 = pHMgr->decode_flag(p + 1); + } + break; + } + case 3: { + checkcpdtable[j].pattern3 = mystrdup(piece); + simplifiedcpd = 1; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if ((!(checkcpdtable[j].pattern)) || (!(checkcpdtable[j].pattern2))) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numcheckcpd = 0; + return 1; + } + } + return 0; +} + +/* parse in the compound rule table */ +int AffixMgr::parse_defcpdtable(char* line, FileMgr* af) { + if (numdefcpd != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numdefcpd = atoi(piece); + if (numdefcpd < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + defcpdtable = (flagentry*)malloc(numdefcpd * sizeof(flagentry)); + if (!defcpdtable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numdefcpd lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numdefcpd; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + defcpdtable[j].def = NULL; + defcpdtable[j].len = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "COMPOUNDRULE", 12) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numdefcpd = 0; + return 1; + } + break; + } + case 1: { // handle parenthesized flags + if (strchr(piece, '(')) { + defcpdtable[j].def = (FLAG*)malloc(strlen(piece) * sizeof(FLAG)); + defcpdtable[j].len = 0; + int end = 0; + FLAG* conv; + while (!end) { + char* par = piece + 1; + while (*par != '(' && *par != ')' && *par != '\0') + par++; + if (*par == '\0') + end = 1; + else + *par = '\0'; + if (*piece == '(') + piece++; + if (*piece == '*' || *piece == '?') { + defcpdtable[j].def[defcpdtable[j].len++] = (FLAG)*piece; + } else if (*piece != '\0') { + int l = pHMgr->decode_flags(&conv, piece, af); + for (int k = 0; k < l; k++) + defcpdtable[j].def[defcpdtable[j].len++] = conv[k]; + free(conv); + } + piece = par + 1; + } + } else { + defcpdtable[j].len = + pHMgr->decode_flags(&(defcpdtable[j].def), piece, af); + } + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!defcpdtable[j].len) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numdefcpd = 0; + return 1; + } + } + return 0; +} + +/* parse in the character map table */ +int AffixMgr::parse_maptable(char* line, FileMgr* af) { + if (nummap != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + nummap = atoi(piece); + if (nummap < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + maptable = (mapentry*)malloc(nummap * sizeof(struct mapentry)); + if (!maptable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the nummap lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < nummap; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + maptable[j].set = NULL; + maptable[j].len = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "MAP", 3) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + nummap = 0; + return 1; + } + break; + } + case 1: { + int setn = 0; + maptable[j].len = strlen(piece); + maptable[j].set = (char**)malloc(maptable[j].len * sizeof(char*)); + if (!maptable[j].set) + return 1; + for (int k = 0; k < maptable[j].len; k++) { + int chl = 1; + int chb = k; + if (piece[k] == '(') { + char* parpos = strchr(piece + k, ')'); + if (parpos != NULL) { + chb = k + 1; + chl = (int)(parpos - piece) - k - 1; + k = k + chl + 1; + } + } else { + if (utf8 && (piece[k] & 0xc0) == 0xc0) { + for (k++; utf8 && (piece[k] & 0xc0) == 0x80; k++) + ; + chl = k - chb; + k--; + } + } + maptable[j].set[setn] = (char*)malloc(chl + 1); + if (!maptable[j].set[setn]) + return 1; + strncpy(maptable[j].set[setn], piece + chb, chl); + maptable[j].set[setn][chl] = '\0'; + setn++; + } + maptable[j].len = setn; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!maptable[j].set || !maptable[j].len) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + nummap = 0; + return 1; + } + } + return 0; +} + +/* parse in the word breakpoint table */ +int AffixMgr::parse_breaktable(char* line, FileMgr* af) { + if (numbreak > -1) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numbreak = atoi(piece); + if (numbreak < 0) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + if (numbreak == 0) + return 0; + breaktable = (char**)malloc(numbreak * sizeof(char*)); + if (!breaktable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numbreak lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numbreak; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "BREAK", 5) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numbreak = 0; + return 1; + } + break; + } + case 1: { + breaktable[j] = mystrdup(piece); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!breaktable) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numbreak = 0; + return 1; + } + } + return 0; +} + +void AffixMgr::reverse_condition(std::string& piece) { + if (piece.empty()) + return; + + int neg = 0; + for (std::string::reverse_iterator k = piece.rbegin(); k != piece.rend(); ++k) { + switch (*k) { + case '[': { + if (neg) + *(k - 1) = '['; + else + *k = ']'; + break; + } + case ']': { + *k = '['; + if (neg) + *(k - 1) = '^'; + neg = 0; + break; + } + case '^': { + if (*(k - 1) == ']') + neg = 1; + else + *(k - 1) = *k; + break; + } + default: { + if (neg) + *(k - 1) = *k; + } + } + } +} + +int AffixMgr::parse_affix(char* line, + const char at, + FileMgr* af, + char* dupflags) { + int numents = 0; // number of affentry structures to parse + + unsigned short aflag = 0; // affix char identifier + + char ff = 0; + std::vector affentries; + + char* tp = line; + char* nl = line; + char* piece; + int i = 0; + +// checking lines with bad syntax +#ifdef DEBUG + int basefieldnum = 0; +#endif + + // split affix header line into pieces + + int np = 0; + + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + // piece 1 - is type of affix + case 0: { + np++; + break; + } + + // piece 2 - is affix char + case 1: { + np++; + aflag = pHMgr->decode_flag(piece); + if (((at == 'S') && (dupflags[aflag] & dupSFX)) || + ((at == 'P') && (dupflags[aflag] & dupPFX))) { + HUNSPELL_WARNING( + stderr, + "error: line %d: multiple definitions of an affix flag\n", + af->getlinenum()); + // return 1; XXX permissive mode for bad dictionaries + } + dupflags[aflag] += (char)((at == 'S') ? dupSFX : dupPFX); + break; + } + // piece 3 - is cross product indicator + case 2: { + np++; + if (*piece == 'Y') + ff = aeXPRODUCT; + break; + } + + // piece 4 - is number of affentries + case 3: { + np++; + numents = atoi(piece); + if ((numents <= 0) || ((std::numeric_limits::max() / + sizeof(struct affentry)) < static_cast(numents))) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + free(err); + } + return 1; + } + affentries.resize(numents); + affentries[0].opts = ff; + if (utf8) + affentries[0].opts += aeUTF8; + if (pHMgr->is_aliasf()) + affentries[0].opts += aeALIASF; + if (pHMgr->is_aliasm()) + affentries[0].opts += aeALIASM; + affentries[0].aflag = aflag; + } + + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + // check to make sure we parsed enough pieces + if (np != 4) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + free(err); + } + return 1; + } + + // now parse numents affentries for this affix + std::vector::iterator start = affentries.begin(); + std::vector::iterator end = affentries.end(); + for (std::vector::iterator entry = start; entry != end; ++entry) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + np = 0; + + // split line into pieces + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + // piece 1 - is type + case 0: { + np++; + if (entry != start) + entry->opts = start->opts & + (char)(aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM); + break; + } + + // piece 2 - is affix char + case 1: { + np++; + if (pHMgr->decode_flag(piece) != aflag) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, + "error: line %d: affix %s is corrupt\n", + af->getlinenum(), err); + free(err); + } + return 1; + } + + if (entry != start) + entry->aflag = start->aflag; + break; + } + + // piece 3 - is string to strip or 0 for null + case 2: { + np++; + entry->strip = piece; + if (complexprefixes) { + if (utf8) + reverseword_utf(entry->strip); + else + reverseword(entry->strip); + } + if (entry->strip.compare("0") == 0) { + entry->strip.clear(); + } + break; + } + + // piece 4 - is affix string or 0 for null + case 3: { + char* dash; + entry->morphcode = NULL; + entry->contclass = NULL; + entry->contclasslen = 0; + np++; + dash = strchr(piece, '/'); + if (dash) { + *dash = '\0'; + + entry->appnd = piece; + + if (ignorechars) { + if (utf8) { + remove_ignored_chars_utf(entry->appnd, ignorechars_utf16); + } else { + remove_ignored_chars(entry->appnd, ignorechars); + } + } + + if (complexprefixes) { + if (utf8) + reverseword_utf(entry->appnd); + else + reverseword(entry->appnd); + } + + if (pHMgr->is_aliasf()) { + int index = atoi(dash + 1); + entry->contclasslen = (unsigned short)pHMgr->get_aliasf( + index, &(entry->contclass), af); + if (!entry->contclasslen) + HUNSPELL_WARNING(stderr, + "error: bad affix flag alias: \"%s\"\n", + dash + 1); + } else { + entry->contclasslen = (unsigned short)pHMgr->decode_flags( + &(entry->contclass), dash + 1, af); + std::sort(entry->contclass, entry->contclass + entry->contclasslen); + } + *dash = '/'; + + havecontclass = 1; + for (unsigned short _i = 0; _i < entry->contclasslen; _i++) { + contclasses[(entry->contclass)[_i]] = 1; + } + } else { + entry->appnd = piece; + + if (ignorechars) { + if (utf8) { + remove_ignored_chars_utf(entry->appnd, ignorechars_utf16); + } else { + remove_ignored_chars(entry->appnd, ignorechars); + } + } + + if (complexprefixes) { + if (utf8) + reverseword_utf(entry->appnd); + else + reverseword(entry->appnd); + } + } + + if (entry->appnd.compare("0") == 0) { + entry->appnd.clear(); + } + break; + } + + // piece 5 - is the conditions descriptions + case 4: { + std::string chunk(piece); + np++; + if (complexprefixes) { + if (utf8) + reverseword_utf(chunk); + else + reverseword(chunk); + reverse_condition(chunk); + } + if (!entry->strip.empty() && chunk != "." && + redundant_condition(at, entry->strip.c_str(), entry->strip.size(), chunk.c_str(), + af->getlinenum())) + chunk = "."; + if (at == 'S') { + reverseword(chunk); + reverse_condition(chunk); + } + if (encodeit(*entry, chunk.c_str())) + return 1; + break; + } + + case 5: { + std::string chunk(piece); + np++; + if (pHMgr->is_aliasm()) { + int index = atoi(chunk.c_str()); + entry->morphcode = pHMgr->get_aliasm(index); + } else { + if (complexprefixes) { // XXX - fix me for morph. gen. + if (utf8) + reverseword_utf(chunk); + else + reverseword(chunk); + } + // add the remaining of the line + if (*tp) { + *(tp - 1) = ' '; + chunk.push_back(' '); + chunk.append(tp); + } + entry->morphcode = mystrdup(chunk.c_str()); + if (!entry->morphcode) + return 1; + } + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + // check to make sure we parsed enough pieces + if (np < 4) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, "error: line %d: affix %s is corrupt\n", + af->getlinenum(), err); + free(err); + } + return 1; + } + +#ifdef DEBUG + // detect unnecessary fields, excepting comments + if (basefieldnum) { + int fieldnum = + !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6); + if (fieldnum != basefieldnum) + HUNSPELL_WARNING(stderr, "warning: line %d: bad field number\n", + af->getlinenum()); + } else { + basefieldnum = + !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6); + } +#endif + } + + // now create SfxEntry or PfxEntry objects and use links to + // build an ordered (sorted by affix string) list + for (std::vector::iterator entry = start; entry != end; ++entry) { + if (at == 'P') { + PfxEntry* pfxptr = new PfxEntry(this, &(*entry)); + build_pfxtree(pfxptr); + } else { + SfxEntry* sfxptr = new SfxEntry(this, &(*entry)); + build_sfxtree(sfxptr); + } + } + return 0; +} + +int AffixMgr::redundant_condition(char ft, + const char* strip, + int stripl, + const char* cond, + int linenum) { + int condl = strlen(cond); + int i; + int j; + int neg; + int in; + if (ft == 'P') { // prefix + if (strncmp(strip, cond, condl) == 0) + return 1; + if (utf8) { + } else { + for (i = 0, j = 0; (i < stripl) && (j < condl); i++, j++) { + if (cond[j] != '[') { + if (cond[j] != strip[i]) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } else { + neg = (cond[j + 1] == '^') ? 1 : 0; + in = 0; + do { + j++; + if (strip[i] == cond[j]) + in = 1; + } while ((j < (condl - 1)) && (cond[j] != ']')); + if (j == (condl - 1) && (cond[j] != ']')) { + HUNSPELL_WARNING(stderr, + "error: line %d: missing ] in condition:\n%s\n", + linenum, cond); + return 0; + } + if ((!neg && !in) || (neg && in)) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } + } + if (j >= condl) + return 1; + } + } else { // suffix + if ((stripl >= condl) && strcmp(strip + stripl - condl, cond) == 0) + return 1; + if (utf8) { + } else { + for (i = stripl - 1, j = condl - 1; (i >= 0) && (j >= 0); i--, j--) { + if (cond[j] != ']') { + if (cond[j] != strip[i]) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } else { + in = 0; + do { + j--; + if (strip[i] == cond[j]) + in = 1; + } while ((j > 0) && (cond[j] != '[')); + if ((j == 0) && (cond[j] != '[')) { + HUNSPELL_WARNING(stderr, + "error: line: %d: missing ] in condition:\n%s\n", + linenum, cond); + return 0; + } + neg = (cond[j + 1] == '^') ? 1 : 0; + if ((!neg && !in) || (neg && in)) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } + } + if (j < 0) + return 1; + } + } + return 0; +} + +int AffixMgr::get_suffix_words(short unsigned* suff, + int len, + const char* root_word, + char** slst) { + int suff_words_cnt = 0; + short unsigned* start_ptr = suff; + for (int j = 0; j < SETSIZE; j++) { + SfxEntry* ptr = sStart[j]; + while (ptr) { + suff = start_ptr; + for (int i = 0; i < len; i++) { + if ((*suff) == ptr->getFlag()) { + std::string nw(root_word); + nw.append(ptr->getAffix()); + hentry* ht = ptr->checkword(nw.c_str(), nw.size(), 0, NULL, NULL, 0, + NULL, 0, 0, 0); + if (ht) { + slst[suff_words_cnt++] = mystrdup(nw.c_str()); + } + } + suff++; + } + ptr = ptr->getNext(); + } + } + return suff_words_cnt; +} diff --git a/extensions/spellcheck/hunspell/src/affixmgr.hxx b/extensions/spellcheck/hunspell/src/affixmgr.hxx new file mode 100644 index 000000000..d70e85338 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affixmgr.hxx @@ -0,0 +1,390 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AFFIXMGR_HXX_ +#define _AFFIXMGR_HXX_ + +#include "hunvisapi.h" + +#include + +#include + +#include "atypes.hxx" +#include "baseaffix.hxx" +#include "hashmgr.hxx" +#include "phonet.hxx" +#include "replist.hxx" + +// check flag duplication +#define dupSFX (1 << 0) +#define dupPFX (1 << 1) + +class PfxEntry; +class SfxEntry; + +class LIBHUNSPELL_DLL_EXPORTED AffixMgr { + PfxEntry* pStart[SETSIZE]; + SfxEntry* sStart[SETSIZE]; + PfxEntry* pFlag[SETSIZE]; + SfxEntry* sFlag[SETSIZE]; + HashMgr* pHMgr; + HashMgr** alldic; + int* maxdic; + char* keystring; + char* trystring; + char* encoding; + struct cs_info* csconv; + int utf8; + int complexprefixes; + FLAG compoundflag; + FLAG compoundbegin; + FLAG compoundmiddle; + FLAG compoundend; + FLAG compoundroot; + FLAG compoundforbidflag; + FLAG compoundpermitflag; + int compoundmoresuffixes; + int checkcompounddup; + int checkcompoundrep; + int checkcompoundcase; + int checkcompoundtriple; + int simplifiedtriple; + FLAG forbiddenword; + FLAG nosuggest; + FLAG nongramsuggest; + FLAG needaffix; + int cpdmin; + int numrep; + replentry* reptable; + RepList* iconvtable; + RepList* oconvtable; + int nummap; + mapentry* maptable; + int numbreak; + char** breaktable; + int numcheckcpd; + patentry* checkcpdtable; + int simplifiedcpd; + int numdefcpd; + flagentry* defcpdtable; + phonetable* phone; + int maxngramsugs; + int maxcpdsugs; + int maxdiff; + int onlymaxdiff; + int nosplitsugs; + int sugswithdots; + int cpdwordmax; + int cpdmaxsyllable; + char* cpdvowels; + w_char* cpdvowels_utf16; + int cpdvowels_utf16_len; + char* cpdsyllablenum; + const char* pfxappnd; // BUG: not stateless + const char* sfxappnd; // BUG: not stateless + int sfxextra; // BUG: not stateless + FLAG sfxflag; // BUG: not stateless + char* derived; // BUG: not stateless + SfxEntry* sfx; // BUG: not stateless + PfxEntry* pfx; // BUG: not stateless + int checknum; + char* wordchars; + std::vector wordchars_utf16; + char* ignorechars; + std::vector ignorechars_utf16; + char* version; + char* lang; + int langnum; + FLAG lemma_present; + FLAG circumfix; + FLAG onlyincompound; + FLAG keepcase; + FLAG forceucase; + FLAG warn; + int forbidwarn; + FLAG substandard; + int checksharps; + int fullstrip; + + int havecontclass; // boolean variable + char contclasses[CONTSIZE]; // flags of possible continuing classes (twofold + // affix) + + public: + AffixMgr(const char* affpath, HashMgr** ptr, int* md, const char* key = NULL); + ~AffixMgr(); + struct hentry* affix_check(const char* word, + int len, + const unsigned short needflag = (unsigned short)0, + char in_compound = IN_CPD_NOT); + struct hentry* prefix_check(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + inline int isSubset(const char* s1, const char* s2); + struct hentry* prefix_check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + inline int isRevSubset(const char* s1, const char* end_of_s2, int len); + struct hentry* suffix_check(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass = FLAG_NULL, + const FLAG needflag = FLAG_NULL, + char in_compound = IN_CPD_NOT); + struct hentry* suffix_check_twosfx(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + char* affix_check_morph(const char* word, + int len, + const FLAG needflag = FLAG_NULL, + char in_compound = IN_CPD_NOT); + char* prefix_check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + char* suffix_check_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG cclass = FLAG_NULL, + const FLAG needflag = FLAG_NULL, + char in_compound = IN_CPD_NOT); + + char* prefix_check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + char* suffix_check_twosfx_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + char* morphgen(const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* morph, + const char* targetmorph, + int level); + + int expand_rootword(struct guessword* wlst, + int maxn, + const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* bad, + int, + const char*); + + short get_syllable(const std::string& word); + int cpdrep_check(const char* word, int len); + int cpdpat_check(const char* word, + int len, + hentry* r1, + hentry* r2, + const char affixed); + int defcpd_check(hentry*** words, + short wnum, + hentry* rv, + hentry** rwords, + char all); + int cpdcase_check(const char* word, int len); + inline int candidate_check(const char* word, int len); + void setcminmax(int* cmin, int* cmax, const char* word, int len); + struct hentry* compound_check(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words, + hentry** rwords, + char hu_mov_rule, + char is_sug, + int* info); + + int compound_check_morph(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words, + hentry** rwords, + char hu_mov_rule, + char** result, + char* partresult); + + int get_suffix_words(short unsigned* suff, + int len, + const char* root_word, + char** slst); + + struct hentry* lookup(const char* word); + int get_numrep() const; + struct replentry* get_reptable() const; + RepList* get_iconvtable() const; + RepList* get_oconvtable() const; + struct phonetable* get_phonetable() const; + int get_nummap() const; + struct mapentry* get_maptable() const; + int get_numbreak() const; + char** get_breaktable() const; + char* get_encoding(); + int get_langnum() const; + char* get_key_string(); + char* get_try_string() const; + const char* get_wordchars() const; + const std::vector& get_wordchars_utf16() const; + char* get_ignore() const; + const std::vector& get_ignore_utf16() const; + int get_compound() const; + FLAG get_compoundflag() const; + FLAG get_compoundbegin() const; + FLAG get_forbiddenword() const; + FLAG get_nosuggest() const; + FLAG get_nongramsuggest() const; + FLAG get_needaffix() const; + FLAG get_onlyincompound() const; + FLAG get_compoundroot() const; + FLAG get_lemma_present() const; + int get_checknum() const; + const char* get_prefix() const; + const char* get_suffix() const; + const char* get_derived() const; + const char* get_version() const; + int have_contclass() const; + int get_utf8() const; + int get_complexprefixes() const; + char* get_suffixed(char) const; + int get_maxngramsugs() const; + int get_maxcpdsugs() const; + int get_maxdiff() const; + int get_onlymaxdiff() const; + int get_nosplitsugs() const; + int get_sugswithdots(void) const; + FLAG get_keepcase(void) const; + FLAG get_forceucase(void) const; + FLAG get_warn(void) const; + int get_forbidwarn(void) const; + int get_checksharps(void) const; + char* encode_flag(unsigned short aflag) const; + int get_fullstrip() const; + + private: + int parse_file(const char* affpath, const char* key); + int parse_flag(char* line, unsigned short* out, FileMgr* af); + int parse_num(char* line, int* out, FileMgr* af); + int parse_cpdsyllable(char* line, FileMgr* af); + int parse_reptable(char* line, FileMgr* af); + int parse_convtable(char* line, + FileMgr* af, + RepList** rl, + const char* keyword); + int parse_phonetable(char* line, FileMgr* af); + int parse_maptable(char* line, FileMgr* af); + int parse_breaktable(char* line, FileMgr* af); + int parse_checkcpdtable(char* line, FileMgr* af); + int parse_defcpdtable(char* line, FileMgr* af); + int parse_affix(char* line, const char at, FileMgr* af, char* dupflags); + + void reverse_condition(std::string&); + void debugflag(char* result, unsigned short flag); + std::string& debugflag(std::string& result, unsigned short flag); + int condlen(const char*); + int encodeit(affentry& entry, const char* cs); + int build_pfxtree(PfxEntry* pfxptr); + int build_sfxtree(SfxEntry* sfxptr); + int process_pfx_order(); + int process_sfx_order(); + PfxEntry* process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr); + SfxEntry* process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr); + int process_pfx_tree_to_list(); + int process_sfx_tree_to_list(); + int redundant_condition(char, const char* strip, int stripl, const char* cond, int); + void finishFileMgr(FileMgr* afflst); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/atypes.hxx b/extensions/spellcheck/hunspell/src/atypes.hxx new file mode 100644 index 000000000..60826af20 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/atypes.hxx @@ -0,0 +1,145 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _ATYPES_HXX_ +#define _ATYPES_HXX_ + +#ifndef HUNSPELL_WARNING +#include +#ifdef HUNSPELL_WARNING_ON +#define HUNSPELL_WARNING fprintf +#else +// empty inline function to switch off warnings (instead of the C99 standard +// variadic macros) +static inline void HUNSPELL_WARNING(FILE*, const char*, ...) {} +#endif +#endif + +// HUNSTEM def. +#define HUNSTEM + +#include "hashmgr.hxx" +#include "w_char.hxx" +#include +#include + +#define SETSIZE 256 +#define CONTSIZE 65536 + +// affentry options +#define aeXPRODUCT (1 << 0) +#define aeUTF8 (1 << 1) +#define aeALIASF (1 << 2) +#define aeALIASM (1 << 3) +#define aeLONGCOND (1 << 4) + +// compound options +#define IN_CPD_NOT 0 +#define IN_CPD_BEGIN 1 +#define IN_CPD_END 2 +#define IN_CPD_OTHER 3 + +// info options +#define SPELL_COMPOUND (1 << 0) +#define SPELL_FORBIDDEN (1 << 1) +#define SPELL_ALLCAP (1 << 2) +#define SPELL_NOCAP (1 << 3) +#define SPELL_INITCAP (1 << 4) +#define SPELL_ORIGCAP (1 << 5) +#define SPELL_WARN (1 << 6) + +#define MAXLNLEN 8192 + +#define MINCPDLEN 3 +#define MAXCOMPOUND 10 +#define MAXCONDLEN 20 +#define MAXCONDLEN_1 (MAXCONDLEN - sizeof(char*)) + +#define MAXACC 1000 + +#define FLAG unsigned short +#define FLAG_NULL 0x00 +#define FREE_FLAG(a) a = 0 + +#define TESTAFF(a, b, c) (std::binary_search(a, a + c, b)) + +struct affentry { + std::string strip; + std::string appnd; + char numconds; + char opts; + unsigned short aflag; + unsigned short* contclass; + short contclasslen; + union { + char conds[MAXCONDLEN]; + struct { + char conds1[MAXCONDLEN_1]; + char* conds2; + } l; + } c; + char* morphcode; +}; + +struct guessword { + char* word; + bool allow; + char* orig; +}; + +struct mapentry { + char** set; + int len; +}; + +struct flagentry { + FLAG* def; + int len; +}; + +struct patentry { + char* pattern; + char* pattern2; + char* pattern3; + FLAG cond; + FLAG cond2; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/baseaffix.hxx b/extensions/spellcheck/hunspell/src/baseaffix.hxx new file mode 100644 index 000000000..59256e92f --- /dev/null +++ b/extensions/spellcheck/hunspell/src/baseaffix.hxx @@ -0,0 +1,77 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _BASEAFF_HXX_ +#define _BASEAFF_HXX_ + +#include "hunvisapi.h" +#include + +class LIBHUNSPELL_DLL_EXPORTED AffEntry { + private: + AffEntry(const AffEntry&); + AffEntry& operator=(const AffEntry&); + + protected: + AffEntry() + : numconds(0), + opts(0), + aflag(0), + morphcode(0), + contclass(NULL), + contclasslen(0) {} + std::string appnd; + std::string strip; + unsigned char numconds; + char opts; + unsigned short aflag; + union { + char conds[MAXCONDLEN]; + struct { + char conds1[MAXCONDLEN_1]; + char* conds2; + } l; + } c; + char* morphcode; + unsigned short* contclass; + short contclasslen; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/csutil.cxx b/extensions/spellcheck/hunspell/src/csutil.cxx new file mode 100644 index 000000000..1948e4a3b --- /dev/null +++ b/extensions/spellcheck/hunspell/src/csutil.cxx @@ -0,0 +1,2850 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "csutil.hxx" +#include "atypes.hxx" +#include "langnum.hxx" + +// Unicode character encoding information +struct unicode_info { + unsigned short c; + unsigned short cupper; + unsigned short clower; +}; + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef OPENOFFICEORG +#include +#else +#ifndef MOZILLA_CLIENT +#include "utf_info.cxx" +#define UTF_LST_LEN (sizeof(utf_lst) / (sizeof(unicode_info))) +#endif +#endif + +#ifdef MOZILLA_CLIENT +#include "nsCOMPtr.h" +#include "nsIUnicodeEncoder.h" +#include "nsIUnicodeDecoder.h" +#include "nsUnicharUtils.h" +#include "mozilla/dom/EncodingUtils.h" + +using mozilla::dom::EncodingUtils; +#endif + +struct unicode_info2 { + char cletter; + unsigned short cupper; + unsigned short clower; +}; + +static struct unicode_info2* utf_tbl = NULL; +static int utf_tbl_count = + 0; // utf_tbl can be used by multiple Hunspell instances + +FILE* myfopen(const char* path, const char* mode) { +#ifdef _WIN32 +#define WIN32_LONG_PATH_PREFIX "\\\\?\\" + if (strncmp(path, WIN32_LONG_PATH_PREFIX, 4) == 0) { + int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + wchar_t* buff = (wchar_t*)malloc(len * sizeof(wchar_t)); + wchar_t* buff2 = (wchar_t*)malloc(len * sizeof(wchar_t)); + FILE* f = NULL; + if (buff && buff2) { + MultiByteToWideChar(CP_UTF8, 0, path, -1, buff, len); + if (_wfullpath(buff2, buff, len) != NULL) { + f = _wfopen(buff2, (strcmp(mode, "r") == 0) ? L"r" : L"rb"); + } + free(buff); + free(buff2); + } + return f; + } +#endif + return fopen(path, mode); +} + +std::string& u16_u8(std::string& dest, const std::vector& src) { + dest.clear(); + std::vector::const_iterator u2 = src.begin(); + std::vector::const_iterator u2_max = src.end(); + while (u2 < u2_max) { + signed char u8; + if (u2->h) { // > 0xFF + // XXX 4-byte haven't implemented yet. + if (u2->h >= 0x08) { // >= 0x800 (3-byte UTF-8 character) + u8 = 0xe0 + (u2->h >> 4); + dest.push_back(u8); + u8 = 0x80 + ((u2->h & 0xf) << 2) + (u2->l >> 6); + dest.push_back(u8); + u8 = 0x80 + (u2->l & 0x3f); + dest.push_back(u8); + } else { // < 0x800 (2-byte UTF-8 character) + u8 = 0xc0 + (u2->h << 2) + (u2->l >> 6); + dest.push_back(u8); + u8 = 0x80 + (u2->l & 0x3f); + dest.push_back(u8); + } + } else { // <= 0xFF + if (u2->l & 0x80) { // >0x80 (2-byte UTF-8 character) + u8 = 0xc0 + (u2->l >> 6); + dest.push_back(u8); + u8 = 0x80 + (u2->l & 0x3f); + dest.push_back(u8); + } else { // < 0x80 (1-byte UTF-8 character) + u8 = u2->l; + dest.push_back(u8); + } + } + ++u2; + } + return dest; +} + +int u8_u16(std::vector& dest, const std::string& src) { + dest.clear(); + std::string::const_iterator u8 = src.begin(); + std::string::const_iterator u8_max = src.end(); + + while (u8 < u8_max) { + w_char u2; + switch ((*u8) & 0xf0) { + case 0x00: + case 0x10: + case 0x20: + case 0x30: + case 0x40: + case 0x50: + case 0x60: + case 0x70: { + u2.h = 0; + u2.l = *u8; + break; + } + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Unexpected continuation bytes " + "in %ld. character position\n%s\n", + static_cast(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + break; + } + case 0xc0: + case 0xd0: { // 2-byte UTF-8 codes + if ((*(u8 + 1) & 0xc0) == 0x80) { + u2.h = (*u8 & 0x1f) >> 2; + u2.l = (*u8 << 6) + (*(u8 + 1) & 0x3f); + ++u8; + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing continuation byte in " + "%ld. character position:\n%s\n", + static_cast(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + } + break; + } + case 0xe0: { // 3-byte UTF-8 codes + if ((*(u8 + 1) & 0xc0) == 0x80) { + u2.h = ((*u8 & 0x0f) << 4) + ((*(u8 + 1) & 0x3f) >> 2); + ++u8; + if ((*(u8 + 1) & 0xc0) == 0x80) { + u2.l = (static_cast(*u8) << 6) + (*(u8 + 1) & 0x3f); + ++u8; + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing continuation byte " + "in %ld. character position:\n%s\n", + static_cast(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + } + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing continuation byte in " + "%ld. character position:\n%s\n", + static_cast(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + } + break; + } + case 0xf0: { // 4 or more byte UTF-8 codes + HUNSPELL_WARNING(stderr, + "This UTF-8 encoding can't convert to UTF-16:\n%s\n", + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + dest.push_back(u2); + return -1; + } + } + dest.push_back(u2); + ++u8; + } + + return dest.size(); +} + +// strip strings into token based on single char delimiter +// acts like strsep() but only uses a delim char and not +// a delim string +// default delimiter: white space characters + +char* mystrsep(char** stringp, const char delim) { + char* mp = *stringp; + if (*mp != '\0') { + char* dp; + if (delim) { + dp = strchr(mp, delim); + } else { + // don't use isspace() here, the string can be in some random charset + // that's way different than the locale's + for (dp = mp; (*dp && *dp != ' ' && *dp != '\t'); dp++) + ; + if (!*dp) + dp = NULL; + } + if (dp) { + *stringp = dp + 1; + *dp = '\0'; + } else { + *stringp = mp + strlen(mp); + } + return mp; + } + return NULL; +} + +// replaces strdup with ansi version +char* mystrdup(const char* s) { + char* d = NULL; + if (s) { + size_t sl = strlen(s) + 1; + d = (char*)malloc(sl); + if (d) { + memcpy(d, s, sl); + } else { + HUNSPELL_WARNING(stderr, "Can't allocate memory.\n"); + } + } + return d; +} + +// strcat for limited length destination string +char* mystrcat(char* dest, const char* st, int max) { + int len; + int len2; + if (dest == NULL || st == NULL) + return dest; + len = strlen(dest); + len2 = strlen(st); + if (len + len2 + 1 > max) + return dest; + strcpy(dest + len, st); + return dest; +} + +// remove cross-platform text line end characters +void mychomp(char* s) { + size_t k = strlen(s); + if ((k > 0) && ((*(s + k - 1) == '\r') || (*(s + k - 1) == '\n'))) + *(s + k - 1) = '\0'; + if ((k > 1) && (*(s + k - 2) == '\r')) + *(s + k - 2) = '\0'; +} + +// break text to lines +// return number of lines +int line_tok(const char* text, char*** lines, char breakchar) { + int linenum = 0; + if (!text) { + return linenum; + } + char* dup = mystrdup(text); + char* p = strchr(dup, breakchar); + while (p) { + linenum++; + *p = '\0'; + p++; + p = strchr(p, breakchar); + } + linenum++; + *lines = (char**)malloc(linenum * sizeof(char*)); + if (!(*lines)) { + free(dup); + return 0; + } + + p = dup; + int l = 0; + for (int i = 0; i < linenum; i++) { + if (*p != '\0') { + (*lines)[l] = mystrdup(p); + if (!(*lines)[l]) { + for (i = 0; i < l; i++) + free((*lines)[i]); + free(dup); + return 0; + } + l++; + } + p += strlen(p) + 1; + } + free(dup); + if (!l) { + free(*lines); + *lines = NULL; + } + return l; +} + +// uniq line in place +char* line_uniq(char* text, char breakchar) { + char** lines; + int linenum = line_tok(text, &lines, breakchar); + int i; + strcpy(text, lines[0]); + for (i = 1; i < linenum; i++) { + int dup = 0; + for (int j = 0; j < i; j++) { + if (strcmp(lines[i], lines[j]) == 0) { + dup = 1; + break; + } + } + if (!dup) { + if ((i > 1) || (*(lines[0]) != '\0')) { + sprintf(text + strlen(text), "%c", breakchar); + } + strcat(text, lines[i]); + } + } + for (i = 0; i < linenum; i++) { + free(lines[i]); + } + free(lines); + return text; +} + +// uniq and boundary for compound analysis: "1\n\2\n\1" -> " ( \1 | \2 ) " +char* line_uniq_app(char** text, char breakchar) { + if (!strchr(*text, breakchar)) { + return *text; + } + + char** lines; + int i; + int linenum = line_tok(*text, &lines, breakchar); + int dup = 0; + for (i = 0; i < linenum; i++) { + for (int j = 0; j < (i - 1); j++) { + if (strcmp(lines[i], lines[j]) == 0) { + *(lines[i]) = '\0'; + dup++; + break; + } + } + } + if ((linenum - dup) == 1) { + strcpy(*text, lines[0]); + freelist(&lines, linenum); + return *text; + } + char* newtext = (char*)malloc(strlen(*text) + 2 * linenum + 3 + 1); + if (newtext) { + free(*text); + *text = newtext; + } else { + freelist(&lines, linenum); + return *text; + } + strcpy(*text, " ( "); + for (i = 0; i < linenum; i++) + if (*(lines[i])) { + sprintf(*text + strlen(*text), "%s%s", lines[i], " | "); + } + (*text)[strlen(*text) - 2] = ')'; // " ) " + freelist(&lines, linenum); + return *text; +} + +// append s to ends of every lines in text +std::string& strlinecat(std::string& str, const std::string& apd) { + size_t pos = 0; + while ((pos = str.find('\n', pos)) != std::string::npos) { + str.insert(pos, apd); + pos += apd.length() + 1; + } + str.append(apd); + return str; +} + +// morphcmp(): compare MORPH_DERI_SFX, MORPH_INFL_SFX and MORPH_TERM_SFX fields +// in the first line of the inputs +// return 0, if inputs equal +// return 1, if inputs may equal with a secondary suffix +// otherwise return -1 +int morphcmp(const char* s, const char* t) { + int se = 0; + int te = 0; + const char* sl; + const char* tl; + const char* olds; + const char* oldt; + if (!s || !t) + return 1; + olds = s; + sl = strchr(s, '\n'); + s = strstr(s, MORPH_DERI_SFX); + if (!s || (sl && sl < s)) + s = strstr(olds, MORPH_INFL_SFX); + if (!s || (sl && sl < s)) { + s = strstr(olds, MORPH_TERM_SFX); + olds = NULL; + } + oldt = t; + tl = strchr(t, '\n'); + t = strstr(t, MORPH_DERI_SFX); + if (!t || (tl && tl < t)) + t = strstr(oldt, MORPH_INFL_SFX); + if (!t || (tl && tl < t)) { + t = strstr(oldt, MORPH_TERM_SFX); + oldt = NULL; + } + while (s && t && (!sl || sl > s) && (!tl || tl > t)) { + s += MORPH_TAG_LEN; + t += MORPH_TAG_LEN; + se = 0; + te = 0; + while ((*s == *t) && !se && !te) { + s++; + t++; + switch (*s) { + case ' ': + case '\n': + case '\t': + case '\0': + se = 1; + } + switch (*t) { + case ' ': + case '\n': + case '\t': + case '\0': + te = 1; + } + } + if (!se || !te) { + // not terminal suffix difference + if (olds) + return -1; + return 1; + } + olds = s; + s = strstr(s, MORPH_DERI_SFX); + if (!s || (sl && sl < s)) + s = strstr(olds, MORPH_INFL_SFX); + if (!s || (sl && sl < s)) { + s = strstr(olds, MORPH_TERM_SFX); + olds = NULL; + } + oldt = t; + t = strstr(t, MORPH_DERI_SFX); + if (!t || (tl && tl < t)) + t = strstr(oldt, MORPH_INFL_SFX); + if (!t || (tl && tl < t)) { + t = strstr(oldt, MORPH_TERM_SFX); + oldt = NULL; + } + } + if (!s && !t && se && te) + return 0; + return 1; +} + +int get_sfxcount(const char* morph) { + if (!morph || !*morph) + return 0; + int n = 0; + const char* old = morph; + morph = strstr(morph, MORPH_DERI_SFX); + if (!morph) + morph = strstr(old, MORPH_INFL_SFX); + if (!morph) + morph = strstr(old, MORPH_TERM_SFX); + while (morph) { + n++; + old = morph; + morph = strstr(morph + 1, MORPH_DERI_SFX); + if (!morph) + morph = strstr(old + 1, MORPH_INFL_SFX); + if (!morph) + morph = strstr(old + 1, MORPH_TERM_SFX); + } + return n; +} + +int fieldlen(const char* r) { + int n = 0; + while (r && *r != ' ' && *r != '\t' && *r != '\0' && *r != '\n') { + r++; + n++; + } + return n; +} + +bool copy_field(std::string& dest, + const std::string& morph, + const std::string& var) { + if (morph.empty()) + return false; + size_t pos = morph.find(var); + if (pos == std::string::npos) + return false; + dest.clear(); + std::string beg(morph.substr(pos + MORPH_TAG_LEN, std::string::npos)); + + for (size_t i = 0; i < beg.size(); ++i) { + const char c(beg[i]); + if (c == ' ' || c == '\t' || c == '\n') + break; + dest.push_back(c); + } + + return true; +} + +std::string& mystrrep(std::string& str, + const std::string& search, + const std::string& replace) { + size_t pos = 0; + while ((pos = str.find(search, pos)) != std::string::npos) { + str.replace(pos, search.length(), replace); + pos += replace.length(); + } + return str; +} + +char* mystrrep(char* word, const char* pat, const char* rep) { + char* pos = strstr(word, pat); + if (pos) { + int replen = strlen(rep); + int patlen = strlen(pat); + while (pos) { + if (replen < patlen) { + char* end = word + strlen(word); + char* next = pos + replen; + char* prev = pos + strlen(pat); + for (; prev < end;* next = *prev, prev++, next++) + ; + *next = '\0'; + } else if (replen > patlen) { + char* end = pos + patlen; + char* next = word + strlen(word) + replen - patlen; + char* prev = next - replen + patlen; + for (; prev >= end;* next = *prev, prev--, next--) + ; + } + strncpy(pos, rep, replen); + pos = strstr(word, pat); + } + } + return word; +} + +// reverse word +size_t reverseword(std::string& word) { + std::reverse(word.begin(), word.end()); + return word.size(); +} + +// reverse word +size_t reverseword_utf(std::string& word) { + std::vector w; + u8_u16(w, word); + std::reverse(w.begin(), w.end()); + u16_u8(word, w); + return w.size(); +} + +int uniqlist(char** list, int n) { + int i; + if (n < 2) + return n; + for (i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (list[j] && list[i] && (strcmp(list[j], list[i]) == 0)) { + free(list[i]); + list[i] = NULL; + break; + } + } + } + int m = 1; + for (i = 1; i < n; i++) + if (list[i]) { + list[m] = list[i]; + m++; + } + return m; +} + +void freelist(char*** list, int n) { + if (list && *list) { + for (int i = 0; i < n; i++) + free((*list)[i]); + free(*list); + *list = NULL; + } +} + +namespace { +unsigned char cupper(const struct cs_info* csconv, int nIndex) { + if (nIndex < 0 || nIndex > 255) + return nIndex; + return csconv[nIndex].cupper; +} + +unsigned char clower(const struct cs_info* csconv, int nIndex) { + if (nIndex < 0 || nIndex > 255) + return nIndex; + return csconv[nIndex].clower; +} + +unsigned char ccase(const struct cs_info* csconv, int nIndex) { + if (nIndex < 0 || nIndex > 255) + return nIndex; + return csconv[nIndex].ccase; +} +} + +w_char upper_utf(w_char u, int langnum) { + unsigned short idx = (u.h << 8) + u.l; + if (idx != unicodetoupper(idx, langnum)) { + u.h = (unsigned char)(unicodetoupper(idx, langnum) >> 8); + u.l = (unsigned char)(unicodetoupper(idx, langnum) & 0x00FF); + } + return u; +} + +w_char lower_utf(w_char u, int langnum) { + unsigned short idx = (u.h << 8) + u.l; + if (idx != unicodetolower(idx, langnum)) { + u.h = (unsigned char)(unicodetolower(idx, langnum) >> 8); + u.l = (unsigned char)(unicodetolower(idx, langnum) & 0x00FF); + } + return u; +} + +// convert std::string to all caps +std::string& mkallcap(std::string& s, const struct cs_info* csconv) { + for (std::string::iterator aI = s.begin(), aEnd = s.end(); aI != aEnd; ++aI) { + *aI = cupper(csconv, static_cast(*aI)); + } + return s; +} + +// convert std::string to all little +std::string& mkallsmall(std::string& s, const struct cs_info* csconv) { + for (std::string::iterator aI = s.begin(), aEnd = s.end(); aI != aEnd; ++aI) { + *aI = clower(csconv, static_cast(*aI)); + } + return s; +} + +std::vector& mkallsmall_utf(std::vector& u, + int langnum) { + for (size_t i = 0; i < u.size(); ++i) { + unsigned short idx = (u[i].h << 8) + u[i].l; + if (idx != unicodetolower(idx, langnum)) { + u[i].h = (unsigned char)(unicodetolower(idx, langnum) >> 8); + u[i].l = (unsigned char)(unicodetolower(idx, langnum) & 0x00FF); + } + } + return u; +} + +std::vector& mkallcap_utf(std::vector& u, int langnum) { + for (size_t i = 0; i < u.size(); i++) { + unsigned short idx = (u[i].h << 8) + u[i].l; + if (idx != unicodetoupper(idx, langnum)) { + u[i].h = (unsigned char)(unicodetoupper(idx, langnum) >> 8); + u[i].l = (unsigned char)(unicodetoupper(idx, langnum) & 0x00FF); + } + } + return u; +} + +std::string& mkinitcap(std::string& s, const struct cs_info* csconv) { + if (!s.empty()) { + s[0] = cupper(csconv, static_cast(s[0])); + } + return s; +} + +std::vector& mkinitcap_utf(std::vector& u, int langnum) { + if (!u.empty()) { + unsigned short idx = (u[0].h << 8) + u[0].l; + if (idx != unicodetoupper(idx, langnum)) { + u[0].h = (unsigned char)(unicodetoupper(idx, langnum) >> 8); + u[0].l = (unsigned char)(unicodetoupper(idx, langnum) & 0x00FF); + } + } + return u; +} + +std::string& mkinitsmall(std::string& s, const struct cs_info* csconv) { + if (!s.empty()) { + s[0] = clower(csconv, static_cast(s[0])); + } + return s; +} + +std::vector& mkinitsmall_utf(std::vector& u, int langnum) { + if (!u.empty()) { + unsigned short idx = (u[0].h << 8) + u[0].l; + if (idx != unicodetolower(idx, langnum)) { + u[0].h = (unsigned char)(unicodetolower(idx, langnum) >> 8); + u[0].l = (unsigned char)(unicodetolower(idx, langnum) & 0x00FF); + } + } + return u; +} + +// conversion function for protected memory +void store_pointer(char* dest, char* source) { + memcpy(dest, &source, sizeof(char*)); +} + +// conversion function for protected memory +char* get_stored_pointer(const char* s) { + char* p; + memcpy(&p, s, sizeof(char*)); + return p; +} + +#ifndef MOZILLA_CLIENT + +// these are simple character mappings for the +// encodings supported +// supplying isupper, tolower, and toupper + +static struct cs_info iso1_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso2_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x01, 0xb3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x01, 0xb5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x01, 0xb9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x01, 0xbe, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xa3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xa5}, {0x00, 0xb6, 0xa6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xa9}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xae}, {0x00, 0xbf, 0xaf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso3_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x01, 0x69, 0xa9}, {0x01, 0xba, 0xaa}, + {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xa6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0x49}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xaf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x00, 0xd0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso4_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x01, 0xb3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x01, 0xb5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x01, 0xb9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x01, 0xbe, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xa3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xa5}, {0x00, 0xb6, 0xa6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xa9}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xae}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso5_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xf1, 0xa1}, + {0x01, 0xf2, 0xa2}, {0x01, 0xf3, 0xa3}, {0x01, 0xf4, 0xa4}, + {0x01, 0xf5, 0xa5}, {0x01, 0xf6, 0xa6}, {0x01, 0xf7, 0xa7}, + {0x01, 0xf8, 0xa8}, {0x01, 0xf9, 0xa9}, {0x01, 0xfa, 0xaa}, + {0x01, 0xfb, 0xab}, {0x01, 0xfc, 0xac}, {0x00, 0xad, 0xad}, + {0x01, 0xfe, 0xae}, {0x01, 0xff, 0xaf}, {0x01, 0xd0, 0xb0}, + {0x01, 0xd1, 0xb1}, {0x01, 0xd2, 0xb2}, {0x01, 0xd3, 0xb3}, + {0x01, 0xd4, 0xb4}, {0x01, 0xd5, 0xb5}, {0x01, 0xd6, 0xb6}, + {0x01, 0xd7, 0xb7}, {0x01, 0xd8, 0xb8}, {0x01, 0xd9, 0xb9}, + {0x01, 0xda, 0xba}, {0x01, 0xdb, 0xbb}, {0x01, 0xdc, 0xbc}, + {0x01, 0xdd, 0xbd}, {0x01, 0xde, 0xbe}, {0x01, 0xdf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x00, 0xd0, 0xb0}, {0x00, 0xd1, 0xb1}, + {0x00, 0xd2, 0xb2}, {0x00, 0xd3, 0xb3}, {0x00, 0xd4, 0xb4}, + {0x00, 0xd5, 0xb5}, {0x00, 0xd6, 0xb6}, {0x00, 0xd7, 0xb7}, + {0x00, 0xd8, 0xb8}, {0x00, 0xd9, 0xb9}, {0x00, 0xda, 0xba}, + {0x00, 0xdb, 0xbb}, {0x00, 0xdc, 0xbc}, {0x00, 0xdd, 0xbd}, + {0x00, 0xde, 0xbe}, {0x00, 0xdf, 0xbf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xa1}, {0x00, 0xf2, 0xa2}, + {0x00, 0xf3, 0xa3}, {0x00, 0xf4, 0xa4}, {0x00, 0xf5, 0xa5}, + {0x00, 0xf6, 0xa6}, {0x00, 0xf7, 0xa7}, {0x00, 0xf8, 0xa8}, + {0x00, 0xf9, 0xa9}, {0x00, 0xfa, 0xaa}, {0x00, 0xfb, 0xab}, + {0x00, 0xfc, 0xac}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xae}, + {0x00, 0xff, 0xaf}}; + +static struct cs_info iso6_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso7_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x01, 0xdc, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x01, 0xdd, 0xb8}, {0x01, 0xde, 0xb9}, + {0x01, 0xdf, 0xba}, {0x00, 0xbb, 0xbb}, {0x01, 0xfc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x01, 0xfd, 0xbe}, {0x01, 0xfe, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x00, 0xdc, 0xb6}, {0x00, 0xdd, 0xb8}, + {0x00, 0xde, 0xb9}, {0x00, 0xdf, 0xba}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd3}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xbc}, {0x00, 0xfd, 0xbe}, {0x00, 0xfe, 0xbf}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso8_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso9_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0xfd, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0xdd}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0x69, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0x49}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso10_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info koi8r_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xb3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x01, 0xa3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xe0}, {0x00, 0xc1, 0xe1}, {0x00, 0xc2, 0xe2}, + {0x00, 0xc3, 0xe3}, {0x00, 0xc4, 0xe4}, {0x00, 0xc5, 0xe5}, + {0x00, 0xc6, 0xe6}, {0x00, 0xc7, 0xe7}, {0x00, 0xc8, 0xe8}, + {0x00, 0xc9, 0xe9}, {0x00, 0xca, 0xea}, {0x00, 0xcb, 0xeb}, + {0x00, 0xcc, 0xec}, {0x00, 0xcd, 0xed}, {0x00, 0xce, 0xee}, + {0x00, 0xcf, 0xef}, {0x00, 0xd0, 0xf0}, {0x00, 0xd1, 0xf1}, + {0x00, 0xd2, 0xf2}, {0x00, 0xd3, 0xf3}, {0x00, 0xd4, 0xf4}, + {0x00, 0xd5, 0xf5}, {0x00, 0xd6, 0xf6}, {0x00, 0xd7, 0xf7}, + {0x00, 0xd8, 0xf8}, {0x00, 0xd9, 0xf9}, {0x00, 0xda, 0xfa}, + {0x00, 0xdb, 0xfb}, {0x00, 0xdc, 0xfc}, {0x00, 0xdd, 0xfd}, + {0x00, 0xde, 0xfe}, {0x00, 0xdf, 0xff}, {0x01, 0xc0, 0xe0}, + {0x01, 0xc1, 0xe1}, {0x01, 0xc2, 0xe2}, {0x01, 0xc3, 0xe3}, + {0x01, 0xc4, 0xe4}, {0x01, 0xc5, 0xe5}, {0x01, 0xc6, 0xe6}, + {0x01, 0xc7, 0xe7}, {0x01, 0xc8, 0xe8}, {0x01, 0xc9, 0xe9}, + {0x01, 0xca, 0xea}, {0x01, 0xcb, 0xeb}, {0x01, 0xcc, 0xec}, + {0x01, 0xcd, 0xed}, {0x01, 0xce, 0xee}, {0x01, 0xcf, 0xef}, + {0x01, 0xd0, 0xf0}, {0x01, 0xd1, 0xf1}, {0x01, 0xd2, 0xf2}, + {0x01, 0xd3, 0xf3}, {0x01, 0xd4, 0xf4}, {0x01, 0xd5, 0xf5}, + {0x01, 0xd6, 0xf6}, {0x01, 0xd7, 0xf7}, {0x01, 0xd8, 0xf8}, + {0x01, 0xd9, 0xf9}, {0x01, 0xda, 0xfa}, {0x01, 0xdb, 0xfb}, + {0x01, 0xdc, 0xfc}, {0x01, 0xdd, 0xfd}, {0x01, 0xde, 0xfe}, + {0x01, 0xdf, 0xff}}; + +static struct cs_info koi8u_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xb3}, {0x00, 0xa4, 0xb4}, /* ie */ + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xb6}, /* i */ + {0x00, 0xa7, 0xb7}, /* ii */ + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xbd}, /* g'' */ + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x01, 0xa3, 0xb3}, + {0x00, 0xb4, 0xb4}, /* IE */ + {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, /* I */ + {0x00, 0xb7, 0xb7}, /* II */ + {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, + {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, + {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xe0}, + {0x00, 0xc1, 0xe1}, {0x00, 0xc2, 0xe2}, {0x00, 0xc3, 0xe3}, + {0x00, 0xc4, 0xe4}, {0x00, 0xc5, 0xe5}, {0x00, 0xc6, 0xe6}, + {0x00, 0xc7, 0xe7}, {0x00, 0xc8, 0xe8}, {0x00, 0xc9, 0xe9}, + {0x00, 0xca, 0xea}, {0x00, 0xcb, 0xeb}, {0x00, 0xcc, 0xec}, + {0x00, 0xcd, 0xed}, {0x00, 0xce, 0xee}, {0x00, 0xcf, 0xef}, + {0x00, 0xd0, 0xf0}, {0x00, 0xd1, 0xf1}, {0x00, 0xd2, 0xf2}, + {0x00, 0xd3, 0xf3}, {0x00, 0xd4, 0xf4}, {0x00, 0xd5, 0xf5}, + {0x00, 0xd6, 0xf6}, {0x00, 0xd7, 0xf7}, {0x00, 0xd8, 0xf8}, + {0x00, 0xd9, 0xf9}, {0x00, 0xda, 0xfa}, {0x00, 0xdb, 0xfb}, + {0x00, 0xdc, 0xfc}, {0x00, 0xdd, 0xfd}, {0x00, 0xde, 0xfe}, + {0x00, 0xdf, 0xff}, {0x01, 0xc0, 0xe0}, {0x01, 0xc1, 0xe1}, + {0x01, 0xc2, 0xe2}, {0x01, 0xc3, 0xe3}, {0x01, 0xc4, 0xe4}, + {0x01, 0xc5, 0xe5}, {0x01, 0xc6, 0xe6}, {0x01, 0xc7, 0xe7}, + {0x01, 0xc8, 0xe8}, {0x01, 0xc9, 0xe9}, {0x01, 0xca, 0xea}, + {0x01, 0xcb, 0xeb}, {0x01, 0xcc, 0xec}, {0x01, 0xcd, 0xed}, + {0x01, 0xce, 0xee}, {0x01, 0xcf, 0xef}, {0x01, 0xd0, 0xf0}, + {0x01, 0xd1, 0xf1}, {0x01, 0xd2, 0xf2}, {0x01, 0xd3, 0xf3}, + {0x01, 0xd4, 0xf4}, {0x01, 0xd5, 0xf5}, {0x01, 0xd6, 0xf6}, + {0x01, 0xd7, 0xf7}, {0x01, 0xd8, 0xf8}, {0x01, 0xd9, 0xf9}, + {0x01, 0xda, 0xfa}, {0x01, 0xdb, 0xfb}, {0x01, 0xdc, 0xfc}, + {0x01, 0xdd, 0xfd}, {0x01, 0xde, 0xfe}, {0x01, 0xdf, 0xff}}; + +static struct cs_info cp1251_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x01, 0x90, 0x80}, + {0x01, 0x83, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x81}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x01, 0x9a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x01, 0x9c, 0x8c}, + {0x01, 0x9d, 0x8d}, {0x01, 0x9e, 0x8e}, {0x01, 0x9f, 0x8f}, + {0x00, 0x90, 0x80}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x8a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x8c}, {0x00, 0x9d, 0x8d}, {0x00, 0x9e, 0x8e}, + {0x00, 0x9f, 0x8f}, {0x00, 0xa0, 0xa0}, {0x01, 0xa2, 0xa1}, + {0x00, 0xa2, 0xa1}, {0x01, 0xbc, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x01, 0xb4, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x01, 0xb8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x01, 0xb3, 0xb2}, {0x00, 0xb3, 0xb2}, + {0x00, 0xb4, 0xa5}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xa8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xa3}, + {0x01, 0xbe, 0xbd}, {0x00, 0xbe, 0xbd}, {0x00, 0xbf, 0xaf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x01, 0xff, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xdf}}; + +static struct cs_info iso13_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0A, 0x0A}, {0x00, 0x0B, 0x0B}, + {0x00, 0x0C, 0x0C}, {0x00, 0x0D, 0x0D}, {0x00, 0x0E, 0x0E}, + {0x00, 0x0F, 0x0F}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1A, 0x1A}, + {0x00, 0x1B, 0x1B}, {0x00, 0x1C, 0x1C}, {0x00, 0x1D, 0x1D}, + {0x00, 0x1E, 0x1E}, {0x00, 0x1F, 0x1F}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2A, 0x2A}, {0x00, 0x2B, 0x2B}, {0x00, 0x2C, 0x2C}, + {0x00, 0x2D, 0x2D}, {0x00, 0x2E, 0x2E}, {0x00, 0x2F, 0x2F}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3A, 0x3A}, {0x00, 0x3B, 0x3B}, + {0x00, 0x3C, 0x3C}, {0x00, 0x3D, 0x3D}, {0x00, 0x3E, 0x3E}, + {0x00, 0x3F, 0x3F}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6A, 0x4A}, + {0x01, 0x6B, 0x4B}, {0x01, 0x6C, 0x4C}, {0x01, 0x6D, 0x4D}, + {0x01, 0x6E, 0x4E}, {0x01, 0x6F, 0x4F}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7A, 0x5A}, {0x00, 0x5B, 0x5B}, {0x00, 0x5C, 0x5C}, + {0x00, 0x5D, 0x5D}, {0x00, 0x5E, 0x5E}, {0x00, 0x5F, 0x5F}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6A, 0x4A}, {0x00, 0x6B, 0x4B}, + {0x00, 0x6C, 0x4C}, {0x00, 0x6D, 0x4D}, {0x00, 0x6E, 0x4E}, + {0x00, 0x6F, 0x4F}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7A, 0x5A}, + {0x00, 0x7B, 0x7B}, {0x00, 0x7C, 0x7C}, {0x00, 0x7D, 0x7D}, + {0x00, 0x7E, 0x7E}, {0x00, 0x7F, 0x7F}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8A, 0x8A}, {0x00, 0x8B, 0x8B}, {0x00, 0x8C, 0x8C}, + {0x00, 0x8D, 0x8D}, {0x00, 0x8E, 0x8E}, {0x00, 0x8F, 0x8F}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9A, 0x9A}, {0x00, 0x9B, 0x9B}, + {0x00, 0x9C, 0x9C}, {0x00, 0x9D, 0x9D}, {0x00, 0x9E, 0x9E}, + {0x00, 0x9F, 0x9F}, {0x00, 0xA0, 0xA0}, {0x00, 0xA1, 0xA1}, + {0x00, 0xA2, 0xA2}, {0x00, 0xA3, 0xA3}, {0x00, 0xA4, 0xA4}, + {0x00, 0xA5, 0xA5}, {0x00, 0xA6, 0xA6}, {0x00, 0xA7, 0xA7}, + {0x01, 0xB8, 0xA8}, {0x00, 0xA9, 0xA9}, {0x01, 0xBA, 0xAA}, + {0x00, 0xAB, 0xAB}, {0x00, 0xAC, 0xAC}, {0x00, 0xAD, 0xAD}, + {0x00, 0xAE, 0xAE}, {0x01, 0xBF, 0xAF}, {0x00, 0xB0, 0xB0}, + {0x00, 0xB1, 0xB1}, {0x00, 0xB2, 0xB2}, {0x00, 0xB3, 0xB3}, + {0x00, 0xB4, 0xB4}, {0x00, 0xB5, 0xB5}, {0x00, 0xB6, 0xB6}, + {0x00, 0xB7, 0xB7}, {0x00, 0xB8, 0xA8}, {0x00, 0xB9, 0xB9}, + {0x00, 0xBA, 0xAA}, {0x00, 0xBB, 0xBB}, {0x00, 0xBC, 0xBC}, + {0x00, 0xBD, 0xBD}, {0x00, 0xBE, 0xBE}, {0x00, 0xBF, 0xAF}, + {0x01, 0xE0, 0xC0}, {0x01, 0xE1, 0xC1}, {0x01, 0xE2, 0xC2}, + {0x01, 0xE3, 0xC3}, {0x01, 0xE4, 0xC4}, {0x01, 0xE5, 0xC5}, + {0x01, 0xE6, 0xC6}, {0x01, 0xE7, 0xC7}, {0x01, 0xE8, 0xC8}, + {0x01, 0xE9, 0xC9}, {0x01, 0xEA, 0xCA}, {0x01, 0xEB, 0xCB}, + {0x01, 0xEC, 0xCC}, {0x01, 0xED, 0xCD}, {0x01, 0xEE, 0xCE}, + {0x01, 0xEF, 0xCF}, {0x01, 0xF0, 0xD0}, {0x01, 0xF1, 0xD1}, + {0x01, 0xF2, 0xD2}, {0x01, 0xF3, 0xD3}, {0x01, 0xF4, 0xD4}, + {0x01, 0xF5, 0xD5}, {0x01, 0xF6, 0xD6}, {0x00, 0xD7, 0xD7}, + {0x01, 0xF8, 0xD8}, {0x01, 0xF9, 0xD9}, {0x01, 0xFA, 0xDA}, + {0x01, 0xFB, 0xDB}, {0x01, 0xFC, 0xDC}, {0x01, 0xFD, 0xDD}, + {0x01, 0xFE, 0xDE}, {0x00, 0xDF, 0xDF}, {0x00, 0xE0, 0xC0}, + {0x00, 0xE1, 0xC1}, {0x00, 0xE2, 0xC2}, {0x00, 0xE3, 0xC3}, + {0x00, 0xE4, 0xC4}, {0x00, 0xE5, 0xC5}, {0x00, 0xE6, 0xC6}, + {0x00, 0xE7, 0xC7}, {0x00, 0xE8, 0xC8}, {0x00, 0xE9, 0xC9}, + {0x00, 0xEA, 0xCA}, {0x00, 0xEB, 0xCB}, {0x00, 0xEC, 0xCC}, + {0x00, 0xED, 0xCD}, {0x00, 0xEE, 0xCE}, {0x00, 0xEF, 0xCF}, + {0x00, 0xF0, 0xD0}, {0x00, 0xF1, 0xD1}, {0x00, 0xF2, 0xD2}, + {0x00, 0xF3, 0xD3}, {0x00, 0xF4, 0xD4}, {0x00, 0xF5, 0xD5}, + {0x00, 0xF6, 0xD6}, {0x00, 0xF7, 0xF7}, {0x00, 0xF8, 0xD8}, + {0x00, 0xF9, 0xD9}, {0x00, 0xFA, 0xDA}, {0x00, 0xFB, 0xDB}, + {0x00, 0xFC, 0xDC}, {0x00, 0xFD, 0xDD}, {0x00, 0xFE, 0xDE}, + {0x00, 0xFF, 0xFF}}; + +static struct cs_info iso14_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xa2, 0xa1}, + {0x00, 0xa2, 0xa1}, {0x00, 0xa3, 0xa3}, {0x01, 0xa5, 0xa4}, + {0x00, 0xa5, 0xa4}, {0x01, 0xa6, 0xab}, {0x00, 0xa7, 0xa7}, + {0x01, 0xb8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x00, 0xab, 0xa6}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x01, 0xff, 0xaf}, {0x01, 0xb1, 0xb0}, + {0x00, 0xb1, 0xb0}, {0x01, 0xb3, 0xb2}, {0x00, 0xb3, 0xb2}, + {0x01, 0xb5, 0xb4}, {0x00, 0xb5, 0xb4}, {0x00, 0xb6, 0xb6}, + {0x01, 0xb9, 0xb7}, {0x00, 0xb8, 0xa8}, {0x00, 0xb9, 0xb6}, + {0x00, 0xba, 0xaa}, {0x01, 0xbf, 0xbb}, {0x00, 0xbc, 0xac}, + {0x01, 0xbe, 0xbd}, {0x00, 0xbe, 0xbd}, {0x00, 0xbf, 0xbb}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso15_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x01, 0xa8, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa6}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x01, 0xb8, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb4}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x01, 0xbd, 0xbc}, + {0x00, 0xbd, 0xbc}, {0x01, 0xff, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xbe}}; + +static struct cs_info iscii_devanagari_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info tis620_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +struct enc_entry { + const char* enc_name; + struct cs_info* cs_table; +}; + +static struct enc_entry encds[] = { + {"iso88591", iso1_tbl}, // ISO-8859-1 + {"iso88592", iso2_tbl}, // ISO-8859-2 + {"iso88593", iso3_tbl}, // ISO-8859-3 + {"iso88594", iso4_tbl}, // ISO-8859-4 + {"iso88595", iso5_tbl}, // ISO-8859-5 + {"iso88596", iso6_tbl}, // ISO-8859-6 + {"iso88597", iso7_tbl}, // ISO-8859-7 + {"iso88598", iso8_tbl}, // ISO-8859-8 + {"iso88599", iso9_tbl}, // ISO-8859-9 + {"iso885910", iso10_tbl}, // ISO-8859-10 + {"tis620", tis620_tbl}, // TIS-620/ISO-8859-11 + {"tis6202533", tis620_tbl}, // TIS-620/ISO-8859-11 + {"iso885911", tis620_tbl}, // TIS-620/ISO-8859-11 + {"iso885913", iso13_tbl}, // ISO-8859-13 + {"iso885914", iso14_tbl}, // ISO-8859-14 + {"iso885915", iso15_tbl}, // ISO-8859-15 + {"koi8r", koi8r_tbl}, // KOI8-R + {"koi8u", koi8u_tbl}, // KOI8-U + {"cp1251", cp1251_tbl}, // CP-1251 + {"microsoftcp1251", cp1251_tbl}, // microsoft-cp1251 + {"xisciias", iscii_devanagari_tbl}, // x-iscii-as + {"isciidevanagari", iscii_devanagari_tbl} // ISCII-DEVANAGARI +}; + +/* map to lower case and remove non alphanumeric chars */ +static void toAsciiLowerAndRemoveNonAlphanumeric(const char* pName, + char* pBuf) { + while (*pName) { + /* A-Z */ + if ((*pName >= 0x41) && (*pName <= 0x5A)) { + *pBuf = (*pName) + 0x20; /* toAsciiLower */ + pBuf++; + } + /* a-z, 0-9 */ + else if (((*pName >= 0x61) && (*pName <= 0x7A)) || + ((*pName >= 0x30) && (*pName <= 0x39))) { + *pBuf = *pName; + pBuf++; + } + + pName++; + } + + *pBuf = '\0'; +} + +struct cs_info* get_current_cs(const char* es) { + char* normalized_encoding = new char[strlen(es) + 1]; + toAsciiLowerAndRemoveNonAlphanumeric(es, normalized_encoding); + + struct cs_info* ccs = NULL; + int n = sizeof(encds) / sizeof(encds[0]); + for (int i = 0; i < n; i++) { + if (strcmp(normalized_encoding, encds[i].enc_name) == 0) { + ccs = encds[i].cs_table; + break; + } + } + + delete[] normalized_encoding; + + if (!ccs) { + HUNSPELL_WARNING(stderr, + "error: unknown encoding %s: using %s as fallback\n", es, + encds[0].enc_name); + ccs = encds[0].cs_table; + } + + return ccs; +} +#else +// XXX This function was rewritten for mozilla. Instead of storing the +// conversion tables static in this file, create them when needed +// with help the mozilla backend. +struct cs_info* get_current_cs(const char* es) { + struct cs_info* ccs = new cs_info[256]; + // Initialze the array with dummy data so that we wouldn't need + // to return null in case of failures. + for (int i = 0; i <= 0xff; ++i) { + ccs[i].ccase = false; + ccs[i].clower = i; + ccs[i].cupper = i; + } + + nsCOMPtr encoder; + nsCOMPtr decoder; + + nsresult rv; + + nsAutoCString label(es); + nsAutoCString encoding; + if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) { + return ccs; + } + encoder = EncodingUtils::EncoderForEncoding(encoding); + decoder = EncodingUtils::DecoderForEncoding(encoding); + encoder->SetOutputErrorBehavior(encoder->kOnError_Signal, nullptr, '?'); + decoder->SetInputErrorBehavior(decoder->kOnError_Signal); + + for (unsigned int i = 0; i <= 0xff; ++i) { + bool success = false; + // We want to find the upper/lowercase equivalents of each byte + // in this 1-byte character encoding. Call our encoding/decoding + // APIs separately for each byte since they may reject some of the + // bytes, and we want to handle errors separately for each byte. + char lower, upper; + do { + if (i == 0) + break; + const char source = char(i); + char16_t uni, uniCased; + int32_t charLength = 1, uniLength = 1; + + rv = decoder->Convert(&source, &charLength, &uni, &uniLength); + // Explicitly check NS_OK because we don't want to allow + // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. + if (rv != NS_OK || charLength != 1 || uniLength != 1) + break; + uniCased = ToLowerCase(uni); + rv = encoder->Convert(&uniCased, &uniLength, &lower, &charLength); + // Explicitly check NS_OK because we don't want to allow + // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. + if (rv != NS_OK || charLength != 1 || uniLength != 1) + break; + + uniCased = ToUpperCase(uni); + rv = encoder->Convert(&uniCased, &uniLength, &upper, &charLength); + // Explicitly check NS_OK because we don't want to allow + // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. + if (rv != NS_OK || charLength != 1 || uniLength != 1) + break; + + success = true; + } while (0); + + if (success) { + ccs[i].cupper = upper; + ccs[i].clower = lower; + } else { + ccs[i].cupper = i; + ccs[i].clower = i; + } + + if (ccs[i].clower != (unsigned char)i) + ccs[i].ccase = true; + else + ccs[i].ccase = false; + } + + return ccs; +} +#endif + +// primitive isalpha() replacement for tokenization +char* get_casechars(const char* enc) { + struct cs_info* csconv = get_current_cs(enc); + char expw[MAXLNLEN]; + char* p = expw; + for (int i = 0; i <= 255; i++) { + if (cupper(csconv, i) != clower(csconv, i)) { + *p = static_cast(i); + p++; + } + } + *p = '\0'; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif + return mystrdup(expw); +} + +// language to encoding default map + +struct lang_map { + const char* lang; + int num; +}; + +static struct lang_map lang2enc[] = + {{"ar", LANG_ar}, {"az", LANG_az}, + {"az_AZ", LANG_az}, // for back-compatibility + {"bg", LANG_bg}, {"ca", LANG_ca}, + {"cs", LANG_cs}, {"da", LANG_da}, + {"de", LANG_de}, {"el", LANG_el}, + {"en", LANG_en}, {"es", LANG_es}, + {"eu", LANG_eu}, {"gl", LANG_gl}, + {"fr", LANG_fr}, {"hr", LANG_hr}, + {"hu", LANG_hu}, {"hu_HU", LANG_hu}, // for back-compatibility + {"it", LANG_it}, {"la", LANG_la}, + {"lv", LANG_lv}, {"nl", LANG_nl}, + {"pl", LANG_pl}, {"pt", LANG_pt}, + {"sv", LANG_sv}, {"tr", LANG_tr}, + {"tr_TR", LANG_tr}, // for back-compatibility + {"ru", LANG_ru}, {"uk", LANG_uk}}; + +int get_lang_num(const char* lang) { + int n = sizeof(lang2enc) / sizeof(lang2enc[0]); + for (int i = 0; i < n; i++) { + if (strcmp(lang, lang2enc[i].lang) == 0) { + return lang2enc[i].num; + } + } + return LANG_xx; +} + +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT +int initialize_utf_tbl() { + utf_tbl_count++; + if (utf_tbl) + return 0; + utf_tbl = (unicode_info2*)malloc(CONTSIZE * sizeof(unicode_info2)); + if (utf_tbl) { + size_t j; + for (j = 0; j < CONTSIZE; j++) { + utf_tbl[j].cletter = 0; + utf_tbl[j].clower = (unsigned short)j; + utf_tbl[j].cupper = (unsigned short)j; + } + for (j = 0; j < UTF_LST_LEN; j++) { + utf_tbl[utf_lst[j].c].cletter = 1; + utf_tbl[utf_lst[j].c].clower = utf_lst[j].clower; + utf_tbl[utf_lst[j].c].cupper = utf_lst[j].cupper; + } + } else + return 1; + return 0; +} +#endif +#endif + +void free_utf_tbl() { + if (utf_tbl_count > 0) + utf_tbl_count--; + if (utf_tbl && (utf_tbl_count == 0)) { + free(utf_tbl); + utf_tbl = NULL; + } +} + +unsigned short unicodetoupper(unsigned short c, int langnum) { + // In Azeri and Turkish, I and i dictinct letters: + // There are a dotless lower case i pair of upper `I', + // and an upper I with dot pair of lower `i'. + if (c == 0x0069 && ((langnum == LANG_az) || (langnum == LANG_tr))) + return 0x0130; +#ifdef OPENOFFICEORG + return static_cast(u_toupper(c)); +#else +#ifdef MOZILLA_CLIENT + return ToUpperCase((char16_t)c); +#else + return (utf_tbl) ? utf_tbl[c].cupper : c; +#endif +#endif +} + +unsigned short unicodetolower(unsigned short c, int langnum) { + // In Azeri and Turkish, I and i dictinct letters: + // There are a dotless lower case i pair of upper `I', + // and an upper I with dot pair of lower `i'. + if (c == 0x0049 && ((langnum == LANG_az) || (langnum == LANG_tr))) + return 0x0131; +#ifdef OPENOFFICEORG + return static_cast(u_tolower(c)); +#else +#ifdef MOZILLA_CLIENT + return ToLowerCase((char16_t)c); +#else + return (utf_tbl) ? utf_tbl[c].clower : c; +#endif +#endif +} + +int unicodeisalpha(unsigned short c) { +#ifdef OPENOFFICEORG + return u_isalpha(c); +#else + return (utf_tbl) ? utf_tbl[c].cletter : 0; +#endif +} + +/* get type of capitalization */ +int get_captype(const std::string& word, cs_info* csconv) { + // now determine the capitalization type of the first nl letters + size_t ncap = 0; + size_t nneutral = 0; + size_t firstcap = 0; + if (csconv == NULL) + return NOCAP; + for (std::string::const_iterator q = word.begin(); q != word.end(); ++q) { + unsigned char nIndex = static_cast(*q); + if (ccase(csconv, nIndex)) + ncap++; + if (cupper(csconv, nIndex) == clower(csconv, nIndex)) + nneutral++; + } + if (ncap) { + unsigned char nIndex = static_cast(word[0]); + firstcap = csconv[nIndex].ccase; + } + + // now finally set the captype + if (ncap == 0) { + return NOCAP; + } else if ((ncap == 1) && firstcap) { + return INITCAP; + } else if ((ncap == word.size()) || ((ncap + nneutral) == word.size())) { + return ALLCAP; + } else if ((ncap > 1) && firstcap) { + return HUHINITCAP; + } + return HUHCAP; +} + +int get_captype_utf8(const std::vector& word, int langnum) { + // now determine the capitalization type of the first nl letters + size_t ncap = 0; + size_t nneutral = 0; + size_t firstcap = 0; + for (size_t i = 0; i < word.size(); ++i) { + unsigned short idx = (word[i].h << 8) + word[i].l; + if (idx != unicodetolower(idx, langnum)) + ncap++; + if (unicodetoupper(idx, langnum) == unicodetolower(idx, langnum)) + nneutral++; + } + if (ncap) { + unsigned short idx = (word[0].h << 8) + word[0].l; + firstcap = (idx != unicodetolower(idx, langnum)); + } + + // now finally set the captype + if (ncap == 0) { + return NOCAP; + } else if ((ncap == 1) && firstcap) { + return INITCAP; + } else if ((ncap == word.size()) || ((ncap + nneutral) == word.size())) { + return ALLCAP; + } else if ((ncap > 1) && firstcap) { + return HUHINITCAP; + } + return HUHCAP; +} + +// strip all ignored characters in the string +size_t remove_ignored_chars_utf(std::string& word, + const std::vector& ignored_chars) { + std::vector w; + std::vector w2; + u8_u16(w, word); + + for (size_t i = 0; i < w.size(); ++i) { + if (!std::binary_search(ignored_chars.begin(), + ignored_chars.end(), + w[i])) { + w2.push_back(w[i]); + } + } + + u16_u8(word, w2); + return w2.size(); +} + +namespace { +class is_any_of { + public: + is_any_of(const std::string& in) : chars(in) {} + + bool operator()(char c) { return chars.find(c) != std::string::npos; } + + private: + std::string chars; +}; +} + +// strip all ignored characters in the string +size_t remove_ignored_chars(std::string& word, + const std::string& ignored_chars) { + word.erase( + std::remove_if(word.begin(), word.end(), is_any_of(ignored_chars)), + word.end()); + return word.size(); +} + +int parse_string(char* line, char** out, int ln) { + char* tp = line; + char* piece; + int i = 0; + int np = 0; + if (*out) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions\n", ln); + return 1; + } + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + *out = mystrdup(piece); + if (!*out) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + // free(piece); + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", ln); + return 1; + } + return 0; +} + +bool parse_array(char* line, + char** out, + std::vector& out_utf16, + int utf8, + int ln) { + if (parse_string(line, out, ln)) + return false; + if (utf8) { + u8_u16(out_utf16, *out); + std::sort(out_utf16.begin(), out_utf16.end()); + } + return true; +} diff --git a/extensions/spellcheck/hunspell/src/csutil.hxx b/extensions/spellcheck/hunspell/src/csutil.hxx new file mode 100644 index 000000000..ce7091df5 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/csutil.hxx @@ -0,0 +1,325 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __CSUTILHXX__ +#define __CSUTILHXX__ + +#include "hunvisapi.h" + +// First some base level utility routines + +#include +#include +#include +#include "w_char.hxx" +#include "htypes.hxx" + +#ifdef MOZILLA_CLIENT +#include "nscore.h" // for mozalloc headers +#endif + +// casing +#define NOCAP 0 +#define INITCAP 1 +#define ALLCAP 2 +#define HUHCAP 3 +#define HUHINITCAP 4 + +// default encoding and keystring +#define SPELL_ENCODING "ISO8859-1" +#define SPELL_KEYSTRING "qwertyuiop|asdfghjkl|zxcvbnm" + +// default morphological fields +#define MORPH_STEM "st:" +#define MORPH_ALLOMORPH "al:" +#define MORPH_POS "po:" +#define MORPH_DERI_PFX "dp:" +#define MORPH_INFL_PFX "ip:" +#define MORPH_TERM_PFX "tp:" +#define MORPH_DERI_SFX "ds:" +#define MORPH_INFL_SFX "is:" +#define MORPH_TERM_SFX "ts:" +#define MORPH_SURF_PFX "sp:" +#define MORPH_FREQ "fr:" +#define MORPH_PHON "ph:" +#define MORPH_HYPH "hy:" +#define MORPH_PART "pa:" +#define MORPH_FLAG "fl:" +#define MORPH_HENTRY "_H:" +#define MORPH_TAG_LEN strlen(MORPH_STEM) + +#define MSEP_FLD ' ' +#define MSEP_REC '\n' +#define MSEP_ALT '\v' + +// default flags +#define DEFAULTFLAGS 65510 +#define FORBIDDENWORD 65510 +#define ONLYUPCASEFLAG 65511 + +// fopen or optional _wfopen to fix long pathname problem of WIN32 +LIBHUNSPELL_DLL_EXPORTED FILE* myfopen(const char* path, const char* mode); + +// convert UTF-16 characters to UTF-8 +LIBHUNSPELL_DLL_EXPORTED std::string& u16_u8(std::string& dest, + const std::vector& src); + +// convert UTF-8 characters to UTF-16 +LIBHUNSPELL_DLL_EXPORTED int u8_u16(std::vector& dest, + const std::string& src); + +// remove end of line char(s) +LIBHUNSPELL_DLL_EXPORTED void mychomp(char* s); + +// duplicate string +LIBHUNSPELL_DLL_EXPORTED char* mystrdup(const char* s); + +// strcat for limited length destination string +LIBHUNSPELL_DLL_EXPORTED char* mystrcat(char* dest, const char* st, int max); + +// parse into tokens with char delimiter +LIBHUNSPELL_DLL_EXPORTED char* mystrsep(char** sptr, const char delim); + +// replace pat by rep in word and return word +LIBHUNSPELL_DLL_EXPORTED char* mystrrep(char* word, + const char* pat, + const char* rep); +LIBHUNSPELL_DLL_EXPORTED std::string& mystrrep(std::string& str, + const std::string& search, + const std::string& replace); + +// append s to ends of every lines in text +LIBHUNSPELL_DLL_EXPORTED std::string& strlinecat(std::string& str, + const std::string& apd); + +// tokenize into lines with new line +LIBHUNSPELL_DLL_EXPORTED int line_tok(const char* text, + char*** lines, + char breakchar); + +// tokenize into lines with new line and uniq in place +LIBHUNSPELL_DLL_EXPORTED char* line_uniq(char* text, char breakchar); +LIBHUNSPELL_DLL_EXPORTED char* line_uniq_app(char** text, char breakchar); + +// reverse word +LIBHUNSPELL_DLL_EXPORTED size_t reverseword(std::string& word); + +// reverse word +LIBHUNSPELL_DLL_EXPORTED size_t reverseword_utf(std::string&); + +// remove duplicates +LIBHUNSPELL_DLL_EXPORTED int uniqlist(char** list, int n); + +// free character array list +LIBHUNSPELL_DLL_EXPORTED void freelist(char*** list, int n); + +// character encoding information +struct cs_info { + unsigned char ccase; + unsigned char clower; + unsigned char cupper; +}; + +LIBHUNSPELL_DLL_EXPORTED int initialize_utf_tbl(); +LIBHUNSPELL_DLL_EXPORTED void free_utf_tbl(); +LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetoupper(unsigned short c, + int langnum); +LIBHUNSPELL_DLL_EXPORTED w_char upper_utf(w_char u, int langnum); +LIBHUNSPELL_DLL_EXPORTED w_char lower_utf(w_char u, int langnum); +LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetolower(unsigned short c, + int langnum); +LIBHUNSPELL_DLL_EXPORTED int unicodeisalpha(unsigned short c); + +LIBHUNSPELL_DLL_EXPORTED struct cs_info* get_current_cs(const char* es); + +// get language identifiers of language codes +LIBHUNSPELL_DLL_EXPORTED int get_lang_num(const char* lang); + +// get characters of the given 8bit encoding with lower- and uppercase forms +LIBHUNSPELL_DLL_EXPORTED char* get_casechars(const char* enc); + +// convert std::string to all caps +LIBHUNSPELL_DLL_EXPORTED std::string& mkallcap(std::string& s, + const struct cs_info* csconv); + +// convert null terminated string to all little +LIBHUNSPELL_DLL_EXPORTED std::string& mkallsmall(std::string& s, + const struct cs_info* csconv); + +// convert first letter of string to little +LIBHUNSPELL_DLL_EXPORTED std::string& mkinitsmall(std::string& s, + const struct cs_info* csconv); + +// convert first letter of string to capital +LIBHUNSPELL_DLL_EXPORTED std::string& mkinitcap(std::string& s, + const struct cs_info* csconv); + +// convert first letter of UTF-8 string to capital +LIBHUNSPELL_DLL_EXPORTED std::vector& +mkinitcap_utf(std::vector& u, int langnum); + +// convert UTF-8 string to little +LIBHUNSPELL_DLL_EXPORTED std::vector& +mkallsmall_utf(std::vector& u, int langnum); + +// convert first letter of UTF-8 string to little +LIBHUNSPELL_DLL_EXPORTED std::vector& +mkinitsmall_utf(std::vector& u, int langnum); + +// convert UTF-8 string to capital +LIBHUNSPELL_DLL_EXPORTED std::vector& +mkallcap_utf(std::vector& u, int langnum); + +// get type of capitalization +LIBHUNSPELL_DLL_EXPORTED int get_captype(const std::string& q, cs_info*); + +// get type of capitalization (UTF-8) +LIBHUNSPELL_DLL_EXPORTED int get_captype_utf8(const std::vector& q, int langnum); + +// strip all ignored characters in the string +LIBHUNSPELL_DLL_EXPORTED size_t remove_ignored_chars_utf( + std::string& word, + const std::vector& ignored_chars); + +// strip all ignored characters in the string +LIBHUNSPELL_DLL_EXPORTED size_t remove_ignored_chars( + std::string& word, + const std::string& ignored_chars); + +LIBHUNSPELL_DLL_EXPORTED int parse_string(char* line, char** out, int ln); + +LIBHUNSPELL_DLL_EXPORTED bool parse_array(char* line, + char** out, + std::vector& out_utf16, + int utf8, + int ln); + +LIBHUNSPELL_DLL_EXPORTED int fieldlen(const char* r); + +LIBHUNSPELL_DLL_EXPORTED bool copy_field(std::string& dest, + const std::string& morph, + const std::string& var); + +LIBHUNSPELL_DLL_EXPORTED int morphcmp(const char* s, const char* t); + +LIBHUNSPELL_DLL_EXPORTED int get_sfxcount(const char* morph); + +// conversion function for protected memory +LIBHUNSPELL_DLL_EXPORTED void store_pointer(char* dest, char* source); + +// conversion function for protected memory +LIBHUNSPELL_DLL_EXPORTED char* get_stored_pointer(const char* s); + +// hash entry macros +LIBHUNSPELL_DLL_EXPORTED inline char* HENTRY_DATA(struct hentry* h) { + char* ret; + if (!h->var) + ret = NULL; + else if (h->var & H_OPT_ALIASM) + ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); + else + ret = HENTRY_WORD(h) + h->blen + 1; + return ret; +} + +LIBHUNSPELL_DLL_EXPORTED inline const char* HENTRY_DATA( + const struct hentry* h) { + const char* ret; + if (!h->var) + ret = NULL; + else if (h->var & H_OPT_ALIASM) + ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); + else + ret = HENTRY_WORD(h) + h->blen + 1; + return ret; +} + +// NULL-free version for warning-free OOo build +LIBHUNSPELL_DLL_EXPORTED inline const char* HENTRY_DATA2( + const struct hentry* h) { + const char* ret; + if (!h->var) + ret = ""; + else if (h->var & H_OPT_ALIASM) + ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); + else + ret = HENTRY_WORD(h) + h->blen + 1; + return ret; +} + +LIBHUNSPELL_DLL_EXPORTED inline char* HENTRY_FIND(struct hentry* h, + const char* p) { + return (HENTRY_DATA(h) ? strstr(HENTRY_DATA(h), p) : NULL); +} + +#endif diff --git a/extensions/spellcheck/hunspell/src/filemgr.cxx b/extensions/spellcheck/hunspell/src/filemgr.cxx new file mode 100644 index 000000000..2218bc79e --- /dev/null +++ b/extensions/spellcheck/hunspell/src/filemgr.cxx @@ -0,0 +1,120 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "filemgr.hxx" +#include "csutil.hxx" + +int FileMgr::fail(const char* err, const char* par) { + fprintf(stderr, err, par); + return -1; +} + +FileMgr::FileMgr(const char* file, const char* key) : hin(NULL), linenum(0) { + in[0] = '\0'; + + fin = myfopen(file, "r"); + if (!fin) { + // check hzipped file + std::string st(file); + st.append(HZIP_EXTENSION); + hin = new Hunzip(st.c_str(), key); + } + if (!fin && !hin) + fail(MSG_OPEN, file); +} + +FileMgr::~FileMgr() { + if (fin) + fclose(fin); + if (hin) + delete hin; +} + +char* FileMgr::getline() { + const char* l; + linenum++; + if (fin) + return fgets(in, BUFSIZE - 1, fin); + if (hin && ((l = hin->getline()) != NULL)) + return strcpy(in, l); + linenum--; + return NULL; +} + +int FileMgr::getlinenum() { + return linenum; +} diff --git a/extensions/spellcheck/hunspell/src/filemgr.hxx b/extensions/spellcheck/hunspell/src/filemgr.hxx new file mode 100644 index 000000000..8b69931dd --- /dev/null +++ b/extensions/spellcheck/hunspell/src/filemgr.hxx @@ -0,0 +1,101 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* file manager class - read lines of files [filename] OR [filename.hz] */ +#ifndef _FILEMGR_HXX_ +#define _FILEMGR_HXX_ + +#include "hunvisapi.h" + +#include "hunzip.hxx" +#include + +class LIBHUNSPELL_DLL_EXPORTED FileMgr { + private: + FileMgr(const FileMgr&); + FileMgr& operator=(const FileMgr&); + + protected: + FILE* fin; + Hunzip* hin; + char in[BUFSIZE + 50]; // input buffer + int fail(const char* err, const char* par); + int linenum; + + public: + FileMgr(const char* filename, const char* key = NULL); + ~FileMgr(); + char* getline(); + int getlinenum(); +}; +#endif diff --git a/extensions/spellcheck/hunspell/src/hashmgr.cxx b/extensions/spellcheck/hunspell/src/hashmgr.cxx new file mode 100644 index 000000000..c3cd95420 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hashmgr.cxx @@ -0,0 +1,1147 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "hashmgr.hxx" +#include "csutil.hxx" +#include "atypes.hxx" + +// build a hash table from a munched word list + +HashMgr::HashMgr(const char* tpath, const char* apath, const char* key) + : tablesize(0), + tableptr(NULL), + flag_mode(FLAG_CHAR), + complexprefixes(0), + utf8(0), + forbiddenword(FORBIDDENWORD) // forbidden word signing flag + , + numaliasf(0), + aliasf(NULL), + aliasflen(0), + numaliasm(0), + aliasm(NULL) { + langnum = 0; + lang = NULL; + enc = NULL; + csconv = 0; + ignorechars = NULL; + load_config(apath, key); + int ec = load_tables(tpath, key); + if (ec) { + /* error condition - what should we do here */ + HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n", ec); + if (tableptr) { + free(tableptr); + tableptr = NULL; + } + tablesize = 0; + } +} + +HashMgr::~HashMgr() { + if (tableptr) { + // now pass through hash table freeing up everything + // go through column by column of the table + for (int i = 0; i < tablesize; i++) { + struct hentry* pt = tableptr[i]; + struct hentry* nt = NULL; + while (pt) { + nt = pt->next; + if (pt->astr && + (!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen))) + free(pt->astr); + free(pt); + pt = nt; + } + } + free(tableptr); + } + tablesize = 0; + + if (aliasf) { + for (int j = 0; j < (numaliasf); j++) + free(aliasf[j]); + free(aliasf); + aliasf = NULL; + if (aliasflen) { + free(aliasflen); + aliasflen = NULL; + } + } + if (aliasm) { + for (int j = 0; j < (numaliasm); j++) + free(aliasm[j]); + free(aliasm); + aliasm = NULL; + } + +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT + if (utf8) + free_utf_tbl(); +#endif +#endif + + if (enc) + free(enc); + if (lang) + free(lang); + + if (ignorechars) + free(ignorechars); + +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +// lookup a root word in the hashtable + +struct hentry* HashMgr::lookup(const char* word) const { + struct hentry* dp; + if (tableptr) { + dp = tableptr[hash(word)]; + if (!dp) + return NULL; + for (; dp != NULL; dp = dp->next) { + if (strcmp(word, dp->word) == 0) + return dp; + } + } + return NULL; +} + +// add a word to the hash table (private) +int HashMgr::add_word(const char* word, + int wbl, + int wcl, + unsigned short* aff, + int al, + const char* desc, + bool onlyupcase) { + + std::string *word_copy = NULL; + std::string *desc_copy = NULL; + if (ignorechars || complexprefixes) { + word_copy = new std::string(word, wbl); + + if (ignorechars != NULL) { + if (utf8) { + wcl = remove_ignored_chars_utf(*word_copy, ignorechars_utf16); + } else { + remove_ignored_chars(*word_copy, ignorechars); + } + } + + if (complexprefixes) { + if (utf8) + wcl = reverseword_utf(*word_copy); + else + reverseword(*word_copy); + + if (desc && !aliasm) { + desc_copy = new std::string(desc); + + if (complexprefixes) { + if (utf8) + reverseword_utf(*desc_copy); + else + reverseword(*desc_copy); + } + desc = desc_copy->c_str(); + } + } + + wbl = word_copy->size(); + word = word_copy->c_str(); + } + + bool upcasehomonym = false; + int descl = desc ? (aliasm ? sizeof(char*) : strlen(desc) + 1) : 0; + // variable-length hash record with word and optional fields + struct hentry* hp = + (struct hentry*)malloc(sizeof(struct hentry) + wbl + descl); + if (!hp) { + delete desc_copy; + delete word_copy; + return 1; + } + + char* hpw = hp->word; + strcpy(hpw, word); + + int i = hash(hpw); + + hp->blen = (unsigned char)wbl; + hp->clen = (unsigned char)wcl; + hp->alen = (short)al; + hp->astr = aff; + hp->next = NULL; + hp->next_homonym = NULL; + + // store the description string or its pointer + if (desc) { + hp->var = H_OPT; + if (aliasm) { + hp->var += H_OPT_ALIASM; + store_pointer(hpw + wbl + 1, get_aliasm(atoi(desc))); + } else { + strcpy(hpw + wbl + 1, desc); + } + if (strstr(HENTRY_DATA(hp), MORPH_PHON)) + hp->var += H_OPT_PHON; + } else + hp->var = 0; + + struct hentry* dp = tableptr[i]; + if (!dp) { + tableptr[i] = hp; + delete desc_copy; + delete word_copy; + return 0; + } + while (dp->next != NULL) { + if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) { + // remove hidden onlyupcase homonym + if (!onlyupcase) { + if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { + free(dp->astr); + dp->astr = hp->astr; + dp->alen = hp->alen; + free(hp); + delete desc_copy; + delete word_copy; + return 0; + } else { + dp->next_homonym = hp; + } + } else { + upcasehomonym = true; + } + } + dp = dp->next; + } + if (strcmp(hp->word, dp->word) == 0) { + // remove hidden onlyupcase homonym + if (!onlyupcase) { + if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { + free(dp->astr); + dp->astr = hp->astr; + dp->alen = hp->alen; + free(hp); + delete desc_copy; + delete word_copy; + return 0; + } else { + dp->next_homonym = hp; + } + } else { + upcasehomonym = true; + } + } + if (!upcasehomonym) { + dp->next = hp; + } else { + // remove hidden onlyupcase homonym + if (hp->astr) + free(hp->astr); + free(hp); + } + + delete desc_copy; + delete word_copy; + return 0; +} + +int HashMgr::add_hidden_capitalized_word(const std::string& word, + int wcl, + unsigned short* flags, + int flagslen, + char* dp, + int captype) { + if (flags == NULL) + flagslen = 0; + + // add inner capitalized forms to handle the following allcap forms: + // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG + // Allcaps with suffixes: CIA's -> CIA'S + if (((captype == HUHCAP) || (captype == HUHINITCAP) || + ((captype == ALLCAP) && (flagslen != 0))) && + !((flagslen != 0) && TESTAFF(flags, forbiddenword, flagslen))) { + unsigned short* flags2 = + (unsigned short*)malloc(sizeof(unsigned short) * (flagslen + 1)); + if (!flags2) + return 1; + if (flagslen) + memcpy(flags2, flags, flagslen * sizeof(unsigned short)); + flags2[flagslen] = ONLYUPCASEFLAG; + if (utf8) { + std::string st; + std::vector w; + u8_u16(w, word); + mkallsmall_utf(w, langnum); + mkinitcap_utf(w, langnum); + u16_u8(st, w); + return add_word(st.c_str(), st.size(), wcl, flags2, flagslen + 1, dp, true); + } else { + std::string new_word(word); + mkallsmall(new_word, csconv); + mkinitcap(new_word, csconv); + int ret = add_word(new_word.c_str(), new_word.size(), wcl, flags2, flagslen + 1, dp, true); + return ret; + } + } + return 0; +} + +// detect captype and modify word length for UTF-8 encoding +int HashMgr::get_clen_and_captype(const std::string& word, int* captype) { + int len; + if (utf8) { + std::vector dest_utf; + len = u8_u16(dest_utf, word); + *captype = get_captype_utf8(dest_utf, langnum); + } else { + len = word.size(); + *captype = get_captype(word, csconv); + } + return len; +} + +// remove word (personal dictionary function for standalone applications) +int HashMgr::remove(const char* word) { + struct hentry* dp = lookup(word); + while (dp) { + if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) { + unsigned short* flags = + (unsigned short*)malloc(sizeof(unsigned short) * (dp->alen + 1)); + if (!flags) + return 1; + for (int i = 0; i < dp->alen; i++) + flags[i] = dp->astr[i]; + flags[dp->alen] = forbiddenword; + dp->astr = flags; + dp->alen++; + std::sort(flags, flags + dp->alen); + } + dp = dp->next_homonym; + } + return 0; +} + +/* remove forbidden flag to add a personal word to the hash */ +int HashMgr::remove_forbidden_flag(const std::string& word) { + struct hentry* dp = lookup(word.c_str()); + if (!dp) + return 1; + while (dp) { + if (dp->astr && TESTAFF(dp->astr, forbiddenword, dp->alen)) { + if (dp->alen == 1) + dp->alen = 0; // XXX forbidden words of personal dic. + else { + unsigned short* flags2 = + (unsigned short*)malloc(sizeof(unsigned short) * (dp->alen - 1)); + if (!flags2) + return 1; + int i, j = 0; + for (i = 0; i < dp->alen; i++) { + if (dp->astr[i] != forbiddenword) + flags2[j++] = dp->astr[i]; + } + dp->alen--; + dp->astr = flags2; // XXX allowed forbidden words + } + } + dp = dp->next_homonym; + } + return 0; +} + +// add a custom dic. word to the hash table (public) +int HashMgr::add(const std::string& word) { + unsigned short* flags = NULL; + int al = 0; + if (remove_forbidden_flag(word)) { + int captype; + int wbl = word.size(); + int wcl = get_clen_and_captype(word, &captype); + add_word(word.c_str(), wbl, wcl, flags, al, NULL, false); + return add_hidden_capitalized_word(word, wcl, flags, al, NULL, + captype); + } + return 0; +} + +int HashMgr::add_with_affix(const char* word, const char* example) { + // detect captype and modify word length for UTF-8 encoding + struct hentry* dp = lookup(example); + remove_forbidden_flag(word); + if (dp && dp->astr) { + int captype; + int wbl = strlen(word); + int wcl = get_clen_and_captype(word, &captype); + if (aliasf) { + add_word(word, wbl, wcl, dp->astr, dp->alen, NULL, false); + } else { + unsigned short* flags = + (unsigned short*)malloc(dp->alen * sizeof(unsigned short)); + if (flags) { + memcpy((void*)flags, (void*)dp->astr, + dp->alen * sizeof(unsigned short)); + add_word(word, wbl, wcl, flags, dp->alen, NULL, false); + } else + return 1; + } + return add_hidden_capitalized_word(word, wcl, dp->astr, + dp->alen, NULL, captype); + } + return 1; +} + +// walk the hash table entry by entry - null at end +// initialize: col=-1; hp = NULL; hp = walk_hashtable(&col, hp); +struct hentry* HashMgr::walk_hashtable(int& col, struct hentry* hp) const { + if (hp && hp->next != NULL) + return hp->next; + for (col++; col < tablesize; col++) { + if (tableptr[col]) + return tableptr[col]; + } + // null at end and reset to start + col = -1; + return NULL; +} + +// load a munched word list and build a hash table on the fly +int HashMgr::load_tables(const char* tpath, const char* key) { + int al; + char* ap; + char* dp; + char* dp2; + unsigned short* flags; + char* ts; + + // open dictionary file + FileMgr* dict = new FileMgr(tpath, key); + if (dict == NULL) + return 1; + + // first read the first line of file to get hash table size */ + if ((ts = dict->getline()) == NULL) { + HUNSPELL_WARNING(stderr, "error: empty dic file %s\n", tpath); + delete dict; + return 2; + } + mychomp(ts); + + /* remove byte order mark */ + if (strncmp(ts, "\xEF\xBB\xBF", 3) == 0) { + memmove(ts, ts + 3, strlen(ts + 3) + 1); + // warning: dic file begins with byte order mark: possible incompatibility + // with old Hunspell versions + } + + tablesize = atoi(ts); + + int nExtra = 5 + USERWORD; + + if (tablesize <= 0 || + (tablesize >= (std::numeric_limits::max() - 1 - nExtra) / + int(sizeof(struct hentry*)))) { + HUNSPELL_WARNING( + stderr, "error: line 1: missing or bad word count in the dic file\n"); + delete dict; + return 4; + } + tablesize += nExtra; + if ((tablesize % 2) == 0) + tablesize++; + + // allocate the hash table + tableptr = (struct hentry**)calloc(tablesize, sizeof(struct hentry*)); + if (!tableptr) { + delete dict; + return 3; + } + + // loop through all words on much list and add to hash + // table and create word and affix strings + + while ((ts = dict->getline()) != NULL) { + mychomp(ts); + // split each line into word and morphological description + dp = ts; + while ((dp = strchr(dp, ':')) != NULL) { + if ((dp > ts + 3) && (*(dp - 3) == ' ' || *(dp - 3) == '\t')) { + for (dp -= 4; dp >= ts && (*dp == ' ' || *dp == '\t'); dp--) + ; + if (dp < ts) { // missing word + dp = NULL; + } else { + *(dp + 1) = '\0'; + dp = dp + 2; + } + break; + } + dp++; + } + + // tabulator is the old morphological field separator + dp2 = strchr(ts, '\t'); + if (dp2 && (!dp || dp2 < dp)) { + *dp2 = '\0'; + dp = dp2 + 1; + } + + // split each line into word and affix char strings + // "\/" signs slash in words (not affix separator) + // "/" at beginning of the line is word character (not affix separator) + ap = strchr(ts, '/'); + while (ap) { + if (ap == ts) { + ap++; + continue; + } else if (*(ap - 1) != '\\') + break; + // replace "\/" with "/" + for (char *sp = ap - 1; *sp; *sp = *(sp + 1), sp++) + ; + ap = strchr(ap, '/'); + } + + if (ap) { + *ap = '\0'; + if (aliasf) { + int index = atoi(ap + 1); + al = get_aliasf(index, &flags, dict); + if (!al) { + HUNSPELL_WARNING(stderr, "error: line %d: bad flag vector alias\n", + dict->getlinenum()); + *ap = '\0'; + } + } else { + al = decode_flags(&flags, ap + 1, dict); + if (al == -1) { + HUNSPELL_WARNING(stderr, "Can't allocate memory.\n"); + delete dict; + return 6; + } + std::sort(flags, flags + al); + } + } else { + al = 0; + ap = NULL; + flags = NULL; + } + + int captype; + int wbl = strlen(ts); + int wcl = get_clen_and_captype(ts, &captype); + // add the word and its index plus its capitalized form optionally + if (add_word(ts, wbl, wcl, flags, al, dp, false) || + add_hidden_capitalized_word(ts, wcl, flags, al, dp, captype)) { + delete dict; + return 5; + } + } + + delete dict; + return 0; +} + +// the hash function is a simple load and rotate +// algorithm borrowed +int HashMgr::hash(const char* word) const { + unsigned long hv = 0; + for (int i = 0; i < 4 && *word != 0; i++) + hv = (hv << 8) | (*word++); + while (*word != 0) { + ROTATE(hv, ROTATE_LEN); + hv ^= (*word++); + } + return (unsigned long)hv % tablesize; +} + +int HashMgr::decode_flags(unsigned short** result, char* flags, FileMgr* af) { + int len; + if (*flags == '\0') { + *result = NULL; + return 0; + } + switch (flag_mode) { + case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz) + len = strlen(flags); + if (len % 2 == 1) + HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", + af->getlinenum()); + len /= 2; + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + for (int i = 0; i < len; i++) { + (*result)[i] = (((unsigned short)flags[i * 2]) << 8) + + (unsigned short)flags[i * 2 + 1]; + } + break; + } + case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 + // 23 233) + int i; + len = 1; + char* src = flags; + unsigned short* dest; + char* p; + for (p = flags; *p; p++) { + if (*p == ',') + len++; + } + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + dest = *result; + for (p = flags; *p; p++) { + if (*p == ',') { + i = atoi(src); + if (i >= DEFAULTFLAGS) + HUNSPELL_WARNING( + stderr, "error: line %d: flag id %d is too large (max: %d)\n", + af->getlinenum(), i, DEFAULTFLAGS - 1); + *dest = (unsigned short)i; + if (*dest == 0) + HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", + af->getlinenum()); + src = p + 1; + dest++; + } + } + i = atoi(src); + if (i >= DEFAULTFLAGS) + HUNSPELL_WARNING(stderr, + "error: line %d: flag id %d is too large (max: %d)\n", + af->getlinenum(), i, DEFAULTFLAGS - 1); + *dest = (unsigned short)i; + if (*dest == 0) + HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", + af->getlinenum()); + break; + } + case FLAG_UNI: { // UTF-8 characters + std::vector w; + u8_u16(w, flags); + len = w.size(); + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + memcpy(*result, &w[0], len * sizeof(short)); + break; + } + default: { // Ispell's one-character flags (erfg -> e r f g) + unsigned short* dest; + len = strlen(flags); + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + dest = *result; + for (unsigned char* p = (unsigned char*)flags; *p; p++) { + *dest = (unsigned short)*p; + dest++; + } + } + } + return len; +} + +unsigned short HashMgr::decode_flag(const char* f) { + unsigned short s = 0; + int i; + switch (flag_mode) { + case FLAG_LONG: + s = ((unsigned short)f[0] << 8) + (unsigned short)f[1]; + break; + case FLAG_NUM: + i = atoi(f); + if (i >= DEFAULTFLAGS) + HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", + i, DEFAULTFLAGS - 1); + s = (unsigned short)i; + break; + case FLAG_UNI: { + std::vector w; + u8_u16(w, f); + if (!w.empty()) + memcpy(&s, &w[0], 1 * sizeof(short)); + break; + } + default: + s = (unsigned short)*((unsigned char*)f); + } + if (s == 0) + HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); + return s; +} + +char* HashMgr::encode_flag(unsigned short f) { + if (f == 0) + return mystrdup("(NULL)"); + std::string ch; + if (flag_mode == FLAG_LONG) { + ch.push_back((unsigned char)(f >> 8)); + ch.push_back((unsigned char)(f - ((f >> 8) << 8))); + } else if (flag_mode == FLAG_NUM) { + std::ostringstream stream; + stream << f; + ch = stream.str(); + } else if (flag_mode == FLAG_UNI) { + const w_char* w_c = (const w_char*)&f; + std::vector w(w_c, w_c + 1); + u16_u8(ch, w); + } else { + ch.push_back((unsigned char)(f)); + } + return mystrdup(ch.c_str()); +} + +// read in aff file and set flag mode +int HashMgr::load_config(const char* affpath, const char* key) { + char* line; // io buffers + int firstline = 1; + + // open the affix file + FileMgr* afflst = new FileMgr(affpath, key); + if (!afflst) { + HUNSPELL_WARNING( + stderr, "Error - could not open affix description file %s\n", affpath); + return 1; + } + + // read in each line ignoring any that do not + // start with a known line type indicator + + while ((line = afflst->getline()) != NULL) { + mychomp(line); + + /* remove byte order mark */ + if (firstline) { + firstline = 0; + if (strncmp(line, "\xEF\xBB\xBF", 3) == 0) + memmove(line, line + 3, strlen(line + 3) + 1); + } + + /* parse in the try string */ + if ((strncmp(line, "FLAG", 4) == 0) && isspace(line[4])) { + if (flag_mode != FLAG_CHAR) { + HUNSPELL_WARNING(stderr, + "error: line %d: multiple definitions of the FLAG " + "affix file parameter\n", + afflst->getlinenum()); + } + if (strstr(line, "long")) + flag_mode = FLAG_LONG; + if (strstr(line, "num")) + flag_mode = FLAG_NUM; + if (strstr(line, "UTF-8")) + flag_mode = FLAG_UNI; + if (flag_mode == FLAG_CHAR) { + HUNSPELL_WARNING( + stderr, + "error: line %d: FLAG needs `num', `long' or `UTF-8' parameter\n", + afflst->getlinenum()); + } + } + if (strncmp(line, "FORBIDDENWORD", 13) == 0) { + char* st = NULL; + if (parse_string(line, &st, afflst->getlinenum())) { + delete afflst; + return 1; + } + forbiddenword = decode_flag(st); + free(st); + } + if (strncmp(line, "SET", 3) == 0) { + if (parse_string(line, &enc, afflst->getlinenum())) { + delete afflst; + return 1; + } + if (strcmp(enc, "UTF-8") == 0) { + utf8 = 1; +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT + initialize_utf_tbl(); +#endif +#endif + } else + csconv = get_current_cs(enc); + } + if (strncmp(line, "LANG", 4) == 0) { + if (parse_string(line, &lang, afflst->getlinenum())) { + delete afflst; + return 1; + } + langnum = get_lang_num(lang); + } + + /* parse in the ignored characters (for example, Arabic optional diacritics + * characters */ + if (strncmp(line, "IGNORE", 6) == 0) { + if (!parse_array(line, &ignorechars, ignorechars_utf16, + utf8, afflst->getlinenum())) { + delete afflst; + return 1; + } + } + + if ((strncmp(line, "AF", 2) == 0) && isspace(line[2])) { + if (parse_aliasf(line, afflst)) { + delete afflst; + return 1; + } + } + + if ((strncmp(line, "AM", 2) == 0) && isspace(line[2])) { + if (parse_aliasm(line, afflst)) { + delete afflst; + return 1; + } + } + + if (strncmp(line, "COMPLEXPREFIXES", 15) == 0) + complexprefixes = 1; + if (((strncmp(line, "SFX", 3) == 0) || (strncmp(line, "PFX", 3) == 0)) && + isspace(line[3])) + break; + } + if (csconv == NULL) + csconv = get_current_cs(SPELL_ENCODING); + delete afflst; + return 0; +} + +/* parse in the ALIAS table */ +int HashMgr::parse_aliasf(char* line, FileMgr* af) { + if (numaliasf != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numaliasf = atoi(piece); + if (numaliasf < 1) { + numaliasf = 0; + aliasf = NULL; + aliasflen = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + aliasf = + (unsigned short**)malloc(numaliasf * sizeof(unsigned short*)); + aliasflen = + (unsigned short*)malloc(numaliasf * sizeof(unsigned short)); + if (!aliasf || !aliasflen) { + numaliasf = 0; + if (aliasf) + free(aliasf); + if (aliasflen) + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + return 1; + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + numaliasf = 0; + free(aliasf); + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numaliasf lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numaliasf; j++) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + aliasf[j] = NULL; + aliasflen[j] = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "AF", 2) != 0) { + numaliasf = 0; + free(aliasf); + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + break; + } + case 1: { + aliasflen[j] = + (unsigned short)decode_flags(&(aliasf[j]), piece, af); + std::sort(aliasf[j], aliasf[j] + aliasflen[j]); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!aliasf[j]) { + free(aliasf); + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + numaliasf = 0; + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + } + return 0; +} + +int HashMgr::is_aliasf() { + return (aliasf != NULL); +} + +int HashMgr::get_aliasf(int index, unsigned short** fvec, FileMgr* af) { + if ((index > 0) && (index <= numaliasf)) { + *fvec = aliasf[index - 1]; + return aliasflen[index - 1]; + } + HUNSPELL_WARNING(stderr, "error: line %d: bad flag alias index: %d\n", + af->getlinenum(), index); + *fvec = NULL; + return 0; +} + +/* parse morph alias definitions */ +int HashMgr::parse_aliasm(char* line, FileMgr* af) { + if (numaliasm != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numaliasm = atoi(piece); + if (numaliasm < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + aliasm = (char**)malloc(numaliasm * sizeof(char*)); + if (!aliasm) { + numaliasm = 0; + return 1; + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + numaliasm = 0; + free(aliasm); + aliasm = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numaliasm lines to read in the remainder of the table */ + char* nl = line; + for (int j = 0; j < numaliasm; j++) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + aliasm[j] = NULL; + piece = mystrsep(&tp, ' '); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "AM", 2) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numaliasm = 0; + free(aliasm); + aliasm = NULL; + return 1; + } + break; + } + case 1: { + // add the remaining of the line + if (*tp) { + *(tp - 1) = ' '; + tp = tp + strlen(tp); + } + std::string chunk(piece); + if (complexprefixes) { + if (utf8) + reverseword_utf(chunk); + else + reverseword(chunk); + } + aliasm[j] = mystrdup(chunk.c_str()); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, ' '); + } + if (!aliasm[j]) { + numaliasm = 0; + free(aliasm); + aliasm = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + } + return 0; +} + +int HashMgr::is_aliasm() { + return (aliasm != NULL); +} + +char* HashMgr::get_aliasm(int index) { + if ((index > 0) && (index <= numaliasm)) + return aliasm[index - 1]; + HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index); + return NULL; +} diff --git a/extensions/spellcheck/hunspell/src/hashmgr.hxx b/extensions/spellcheck/hunspell/src/hashmgr.hxx new file mode 100644 index 000000000..95b06b13f --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hashmgr.hxx @@ -0,0 +1,149 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _HASHMGR_HXX_ +#define _HASHMGR_HXX_ + +#include "hunvisapi.h" + +#include +#include +#include + +#include "htypes.hxx" +#include "filemgr.hxx" +#include "w_char.hxx" + +enum flag { FLAG_CHAR, FLAG_LONG, FLAG_NUM, FLAG_UNI }; + +class LIBHUNSPELL_DLL_EXPORTED HashMgr { + int tablesize; + struct hentry** tableptr; + flag flag_mode; + int complexprefixes; + int utf8; + unsigned short forbiddenword; + int langnum; + char* enc; + char* lang; + struct cs_info* csconv; + char* ignorechars; + std::vector ignorechars_utf16; + int numaliasf; // flag vector `compression' with aliases + unsigned short** aliasf; + unsigned short* aliasflen; + int numaliasm; // morphological desciption `compression' with aliases + char** aliasm; + + public: + HashMgr(const char* tpath, const char* apath, const char* key = NULL); + ~HashMgr(); + + struct hentry* lookup(const char*) const; + int hash(const char*) const; + struct hentry* walk_hashtable(int& col, struct hentry* hp) const; + + int add(const std::string& word); + int add_with_affix(const char* word, const char* pattern); + int remove(const char* word); + int decode_flags(unsigned short** result, char* flags, FileMgr* af); + unsigned short decode_flag(const char* flag); + char* encode_flag(unsigned short flag); + int is_aliasf(); + int get_aliasf(int index, unsigned short** fvec, FileMgr* af); + int is_aliasm(); + char* get_aliasm(int index); + + private: + int get_clen_and_captype(const std::string& word, int* captype); + int load_tables(const char* tpath, const char* key); + int add_word(const char* word, + int wbl, + int wcl, + unsigned short* ap, + int al, + const char* desc, + bool onlyupcase); + int load_config(const char* affpath, const char* key); + int parse_aliasf(char* line, FileMgr* af); + int add_hidden_capitalized_word(const std::string& word, + int wcl, + unsigned short* flags, + int al, + char* dp, + int captype); + int parse_aliasm(char* line, FileMgr* af); + int remove_forbidden_flag(const std::string& word); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/htypes.hxx b/extensions/spellcheck/hunspell/src/htypes.hxx new file mode 100644 index 000000000..d24439441 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/htypes.hxx @@ -0,0 +1,71 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _HTYPES_HXX_ +#define _HTYPES_HXX_ + +#define ROTATE_LEN 5 + +#define ROTATE(v, q) \ + (v) = ((v) << (q)) | (((v) >> (32 - q)) & ((1 << (q)) - 1)); + +// hentry options +#define H_OPT (1 << 0) +#define H_OPT_ALIASM (1 << 1) +#define H_OPT_PHON (1 << 2) + +// see also csutil.hxx +#define HENTRY_WORD(h) &(h->word[0]) + +// approx. number of user defined words +#define USERWORD 1000 + +struct hentry { + unsigned char blen; // word length in bytes + unsigned char clen; // word length in characters (different for UTF-8 enc.) + short alen; // length of affix flag vector + unsigned short* astr; // affix flag vector + struct hentry* next; // next word with same hash code + struct hentry* next_homonym; // next homonym word (with same hash code) + char var; // variable fields (only for special pronounciation yet) + char word[1]; // variable-length word (8-bit or UTF-8 encoding) +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunspell.cxx b/extensions/spellcheck/hunspell/src/hunspell.cxx new file mode 100644 index 000000000..7ff1e2bcf --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunspell.cxx @@ -0,0 +1,1895 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "hunspell.hxx" +#include "hunspell.h" +#ifndef MOZILLA_CLIENT +#include "config.h" +#endif +#include "csutil.hxx" + +#include +#include + +#define MAXWORDLEN 100 +#define MAXWORDUTF8LEN (MAXWORDLEN * 3) + +Hunspell::Hunspell(const char* affpath, const char* dpath, const char* key) { + encoding = NULL; + csconv = NULL; + utf8 = 0; + complexprefixes = 0; + affixpath = mystrdup(affpath); + maxdic = 0; + + /* first set up the hash manager */ + pHMgr[0] = new HashMgr(dpath, affpath, key); + if (pHMgr[0]) + maxdic = 1; + + /* next set up the affix manager */ + /* it needs access to the hash manager lookup methods */ + pAMgr = new AffixMgr(affpath, pHMgr, &maxdic, key); + + /* get the preferred try string and the dictionary */ + /* encoding from the Affix Manager for that dictionary */ + char* try_string = pAMgr->get_try_string(); + encoding = pAMgr->get_encoding(); + langnum = pAMgr->get_langnum(); + utf8 = pAMgr->get_utf8(); + if (!utf8) + csconv = get_current_cs(encoding); + complexprefixes = pAMgr->get_complexprefixes(); + wordbreak = pAMgr->get_breaktable(); + + /* and finally set up the suggestion manager */ + pSMgr = new SuggestMgr(try_string, MAXSUGGESTION, pAMgr); + if (try_string) + free(try_string); +} + +Hunspell::~Hunspell() { + delete pSMgr; + delete pAMgr; + for (int i = 0; i < maxdic; i++) + delete pHMgr[i]; + maxdic = 0; + pSMgr = NULL; + pAMgr = NULL; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif + csconv = NULL; + if (encoding) + free(encoding); + encoding = NULL; + if (affixpath) + free(affixpath); + affixpath = NULL; +} + +// load extra dictionaries +int Hunspell::add_dic(const char* dpath, const char* key) { + if (maxdic == MAXDIC || !affixpath) + return 1; + pHMgr[maxdic] = new HashMgr(dpath, affixpath, key); + if (pHMgr[maxdic]) + maxdic++; + else + return 1; + return 0; +} + +// make a copy of src at destination while removing all leading +// blanks and removing any trailing periods after recording +// their presence with the abbreviation flag +// also since already going through character by character, +// set the capitalization type +// return the length of the "cleaned" (and UTF-8 encoded) word + +size_t Hunspell::cleanword2(std::string& dest, + std::vector& dest_utf, + const char* src, + int* nc, + int* pcaptype, + size_t* pabbrev) { + dest.clear(); + dest_utf.clear(); + + const char* q = src; + + // first skip over any leading blanks + while ((*q != '\0') && (*q == ' ')) + q++; + + // now strip off any trailing periods (recording their presence) + *pabbrev = 0; + int nl = strlen(q); + while ((nl > 0) && (*(q + nl - 1) == '.')) { + nl--; + (*pabbrev)++; + } + + // if no characters are left it can't be capitalized + if (nl <= 0) { + *pcaptype = NOCAP; + return 0; + } + + dest.append(q, nl); + nl = dest.size(); + if (utf8) { + *nc = u8_u16(dest_utf, dest); + *pcaptype = get_captype_utf8(dest_utf, langnum); + } else { + *pcaptype = get_captype(dest, csconv); + *nc = nl; + } + return nl; +} + +void Hunspell::cleanword(std::string& dest, + const char* src, + int* pcaptype, + int* pabbrev) { + dest.clear(); + const unsigned char* q = (const unsigned char*)src; + int firstcap = 0; + + // first skip over any leading blanks + while ((*q != '\0') && (*q == ' ')) + q++; + + // now strip off any trailing periods (recording their presence) + *pabbrev = 0; + int nl = strlen((const char*)q); + while ((nl > 0) && (*(q + nl - 1) == '.')) { + nl--; + (*pabbrev)++; + } + + // if no characters are left it can't be capitalized + if (nl <= 0) { + *pcaptype = NOCAP; + return; + } + + // now determine the capitalization type of the first nl letters + int ncap = 0; + int nneutral = 0; + int nc = 0; + + if (!utf8) { + while (nl > 0) { + nc++; + if (csconv[(*q)].ccase) + ncap++; + if (csconv[(*q)].cupper == csconv[(*q)].clower) + nneutral++; + dest.push_back(*q++); + nl--; + } + // remember to terminate the destination string + firstcap = csconv[static_cast(dest[0])].ccase; + } else { + std::vector t; + u8_u16(t, src); + for (size_t i = 0; i < t.size(); ++i) { + unsigned short idx = (t[i].h << 8) + t[i].l; + unsigned short low = unicodetolower(idx, langnum); + if (idx != low) + ncap++; + if (unicodetoupper(idx, langnum) == low) + nneutral++; + } + u16_u8(dest, t); + if (ncap) { + unsigned short idx = (t[0].h << 8) + t[0].l; + firstcap = (idx != unicodetolower(idx, langnum)); + } + } + + // now finally set the captype + if (ncap == 0) { + *pcaptype = NOCAP; + } else if ((ncap == 1) && firstcap) { + *pcaptype = INITCAP; + } else if ((ncap == nc) || ((ncap + nneutral) == nc)) { + *pcaptype = ALLCAP; + } else if ((ncap > 1) && firstcap) { + *pcaptype = HUHINITCAP; + } else { + *pcaptype = HUHCAP; + } +} + +void Hunspell::mkallcap(std::string& u8) { + if (utf8) { + std::vector u16; + u8_u16(u16, u8); + ::mkallcap_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkallcap(u8, csconv); + } +} + +int Hunspell::mkallsmall2(std::string& u8, std::vector& u16) { + if (utf8) { + ::mkallsmall_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkallsmall(u8, csconv); + } + return u8.size(); +} + +// convert UTF-8 sharp S codes to latin 1 +std::string Hunspell::sharps_u8_l1(const std::string& source) { + std::string dest(source); + mystrrep(dest, "\xC3\x9F", "\xDF"); + return dest; +} + +// recursive search for right ss - sharp s permutations +hentry* Hunspell::spellsharps(std::string& base, + size_t n_pos, + int n, + int repnum, + int* info, + char** root) { + size_t pos = base.find("ss", n_pos); + if (pos != std::string::npos && (n < MAXSHARPS)) { + base[pos] = '\xC3'; + base[pos + 1] = '\x9F'; + hentry* h = spellsharps(base, pos + 2, n + 1, repnum + 1, info, root); + if (h) + return h; + base[pos] = 's'; + base[pos + 1] = 's'; + h = spellsharps(base, pos + 2, n + 1, repnum, info, root); + if (h) + return h; + } else if (repnum > 0) { + if (utf8) + return checkword(base.c_str(), info, root); + std::string tmp(sharps_u8_l1(base)); + return checkword(tmp.c_str(), info, root); + } + return NULL; +} + +int Hunspell::is_keepcase(const hentry* rv) { + return pAMgr && rv->astr && pAMgr->get_keepcase() && + TESTAFF(rv->astr, pAMgr->get_keepcase(), rv->alen); +} + +/* insert a word to the beginning of the suggestion array and return ns */ +int Hunspell::insert_sug(char*** slst, const char* word, int ns) { + if (!*slst) + return ns; + char* dup = mystrdup(word); + if (!dup) + return ns; + if (ns == MAXSUGGESTION) { + ns--; + free((*slst)[ns]); + } + for (int k = ns; k > 0; k--) + (*slst)[k] = (*slst)[k - 1]; + (*slst)[0] = dup; + return ns + 1; +} + +int Hunspell::spell(const char* word, int* info, char** root) { + struct hentry* rv = NULL; + + int info2 = 0; + if (!info) + info = &info2; + else + *info = 0; + + // Hunspell supports XML input of the simplified API (see manual) + if (strcmp(word, SPELL_XML) == 0) + return 1; + int nc = strlen(word); + if (utf8) { + if (nc >= MAXWORDUTF8LEN) + return 0; + } else { + if (nc >= MAXWORDLEN) + return 0; + } + int captype = NOCAP; + size_t abbv = 0; + size_t wl = 0; + + std::string scw; + std::vector sunicw; + + // input conversion + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + { + std::string wspace; + + int convstatus = rl ? rl->conv(word, wspace) : 0; + if (convstatus < 0) + return 0; + else if (convstatus > 0) + wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv); + else + wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv); + } + +#ifdef MOZILLA_CLIENT + // accept the abbreviated words without dots + // workaround for the incomplete tokenization of Mozilla + abbv = 1; +#endif + + if (wl == 0 || maxdic == 0) + return 1; + if (root) + *root = NULL; + + // allow numbers with dots, dashes and commas (but forbid double separators: + // "..", "--" etc.) + enum { NBEGIN, NNUM, NSEP }; + int nstate = NBEGIN; + size_t i; + + for (i = 0; (i < wl); i++) { + if ((scw[i] <= '9') && (scw[i] >= '0')) { + nstate = NNUM; + } else if ((scw[i] == ',') || (scw[i] == '.') || (scw[i] == '-')) { + if ((nstate == NSEP) || (i == 0)) + break; + nstate = NSEP; + } else + break; + } + if ((i == wl) && (nstate == NNUM)) + return 1; + + switch (captype) { + case HUHCAP: + /* FALLTHROUGH */ + case HUHINITCAP: + *info += SPELL_ORIGCAP; + /* FALLTHROUGH */ + case NOCAP: + rv = checkword(scw.c_str(), info, root); + if ((abbv) && !(rv)) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + rv = checkword(u8buffer.c_str(), info, root); + } + break; + case ALLCAP: { + *info += SPELL_ORIGCAP; + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + if (abbv) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + rv = checkword(u8buffer.c_str(), info, root); + if (rv) + break; + } + // Spec. prefix handling for Catalan, French, Italian: + // prefixes separated by apostrophe (SANT'ELIA -> Sant'+Elia). + size_t apos = pAMgr ? scw.find('\'') : std::string::npos; + if (apos != std::string::npos) { + mkallsmall2(scw, sunicw); + //conversion may result in string with different len to pre-mkallsmall2 + //so re-scan + if (apos != std::string::npos && apos < scw.size() - 1) { + std::string part1 = scw.substr(0, apos+1); + std::string part2 = scw.substr(apos+1); + if (utf8) { + std::vector part1u, part2u; + u8_u16(part1u, part1); + u8_u16(part2u, part2); + mkinitcap2(part2, part2u); + scw = part1 + part2; + sunicw = part1u; + sunicw.insert(sunicw.end(), part2u.begin(), part2u.end()); + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + } else { + mkinitcap2(part2, sunicw); + scw = part1 + part2; + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + } + mkinitcap2(scw, sunicw); + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + } + } + if (pAMgr && pAMgr->get_checksharps() && scw.find("SS") != std::string::npos) { + + mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + rv = spellsharps(u8buffer, 0, 0, 0, info, root); + if (!rv) { + mkinitcap2(scw, sunicw); + rv = spellsharps(scw, 0, 0, 0, info, root); + } + if ((abbv) && !(rv)) { + u8buffer.push_back('.'); + rv = spellsharps(u8buffer, 0, 0, 0, info, root); + if (!rv) { + u8buffer = std::string(scw); + u8buffer.push_back('.'); + rv = spellsharps(u8buffer, 0, 0, 0, info, root); + } + } + if (rv) + break; + } + } + case INITCAP: { + + *info += SPELL_ORIGCAP; + mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + mkinitcap2(scw, sunicw); + if (captype == INITCAP) + *info += SPELL_INITCAP; + rv = checkword(scw.c_str(), info, root); + if (captype == INITCAP) + *info -= SPELL_INITCAP; + // forbid bad capitalization + // (for example, ijs -> Ijs instead of IJs in Dutch) + // use explicit forms in dic: Ijs/F (F = FORBIDDENWORD flag) + if (*info & SPELL_FORBIDDEN) { + rv = NULL; + break; + } + if (rv && is_keepcase(rv) && (captype == ALLCAP)) + rv = NULL; + if (rv) + break; + + rv = checkword(u8buffer.c_str(), info, root); + if (abbv && !rv) { + u8buffer.push_back('.'); + rv = checkword(u8buffer.c_str(), info, root); + if (!rv) { + u8buffer = scw; + u8buffer.push_back('.'); + if (captype == INITCAP) + *info += SPELL_INITCAP; + rv = checkword(u8buffer.c_str(), info, root); + if (captype == INITCAP) + *info -= SPELL_INITCAP; + if (rv && is_keepcase(rv) && (captype == ALLCAP)) + rv = NULL; + break; + } + } + if (rv && is_keepcase(rv) && + ((captype == ALLCAP) || + // if CHECKSHARPS: KEEPCASE words with \xDF are allowed + // in INITCAP form, too. + !(pAMgr->get_checksharps() && + ((utf8 && u8buffer.find("\xC3\x9F") != std::string::npos) || + (!utf8 && u8buffer.find('\xDF') != std::string::npos))))) + rv = NULL; + break; + } + } + + if (rv) { + if (pAMgr && pAMgr->get_warn() && rv->astr && + TESTAFF(rv->astr, pAMgr->get_warn(), rv->alen)) { + *info += SPELL_WARN; + if (pAMgr->get_forbidwarn()) + return 0; + return HUNSPELL_OK_WARN; + } + return HUNSPELL_OK; + } + + // recursive breaking at break points + if (wordbreak) { + + int nbr = 0; + wl = scw.size(); + int numbreak = pAMgr ? pAMgr->get_numbreak() : 0; + + // calculate break points for recursion limit + for (int j = 0; j < numbreak; j++) { + size_t len = strlen(wordbreak[j]); + size_t pos = 0; + while ((pos = scw.find(wordbreak[j], pos, len)) != std::string::npos) { + ++nbr; + pos += len; + } + } + if (nbr >= 10) + return 0; + + // check boundary patterns (^begin and end$) + for (int j = 0; j < numbreak; j++) { + size_t plen = strlen(wordbreak[j]); + if (plen == 1 || plen > wl) + continue; + + if (wordbreak[j][0] == '^' && + scw.compare(0, plen - 1, wordbreak[j] + 1, plen -1) == 0 && spell(scw.c_str() + plen - 1)) + return 1; + + if (wordbreak[j][plen - 1] == '$' && + scw.compare(wl - plen + 1, plen - 1, wordbreak[j], plen - 1) == 0) { + char r = scw[wl - plen + 1]; + scw[wl - plen + 1] = '\0'; + if (spell(scw.c_str())) + return 1; + scw[wl - plen + 1] = r; + } + } + + // other patterns + for (int j = 0; j < numbreak; j++) { + size_t plen = strlen(wordbreak[j]); + size_t found = scw.find(wordbreak[j]); + if ((found > 0) && (found < wl - plen)) { + if (!spell(scw.c_str() + found + plen)) + continue; + char r = scw[found]; + scw[found] = '\0'; + // examine 2 sides of the break point + if (spell(scw.c_str())) + return 1; + scw[found] = r; + + // LANG_hu: spec. dash rule + if (langnum == LANG_hu && strcmp(wordbreak[j], "-") == 0) { + r = scw[found + 1]; + scw[found + 1] = '\0'; + if (spell(scw.c_str())) + return 1; // check the first part with dash + scw[found + 1] = r; + } + // end of LANG specific region + } + } + } + + return 0; +} + +struct hentry* Hunspell::checkword(const char* w, int* info, char** root) { + struct hentry* he = NULL; + bool usebuffer = false; + int len, i; + std::string w2; + const char* word; + + char* ignoredchars = pAMgr ? pAMgr->get_ignore() : NULL; + if (ignoredchars != NULL) { + w2.assign(w); + if (utf8) { + const std::vector& ignoredchars_utf16 = + pAMgr->get_ignore_utf16(); + remove_ignored_chars_utf(w2, ignoredchars_utf16); + } else { + remove_ignored_chars(w2, ignoredchars); + } + word = w2.c_str(); + usebuffer = true; + } else + word = w; + + len = strlen(word); + + if (!len) + return NULL; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + if (!usebuffer) { + w2.assign(word); + usebuffer = true; + } + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + } + + if (usebuffer) { + word = w2.c_str(); + } + + // look word in hash table + for (i = 0; (i < maxdic) && !he; i++) { + he = (pHMgr[i])->lookup(word); + + // check forbidden and onlyincompound words + if ((he) && (he->astr) && (pAMgr) && + TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) { + if (info) + *info += SPELL_FORBIDDEN; + // LANG_hu section: set dash information for suggestions + if (langnum == LANG_hu) { + if (pAMgr->get_compoundflag() && + TESTAFF(he->astr, pAMgr->get_compoundflag(), he->alen)) { + if (info) + *info += SPELL_COMPOUND; + } + } + return NULL; + } + + // he = next not needaffix, onlyincompound homonym or onlyupcase word + while (he && (he->astr) && pAMgr && + ((pAMgr->get_needaffix() && + TESTAFF(he->astr, pAMgr->get_needaffix(), he->alen)) || + (pAMgr->get_onlyincompound() && + TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) || + (info && (*info & SPELL_INITCAP) && + TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen)))) + he = he->next_homonym; + } + + // check with affixes + if (!he && pAMgr) { + // try stripping off affixes */ + he = pAMgr->affix_check(word, len, 0); + + // check compound restriction and onlyupcase + if (he && he->astr && + ((pAMgr->get_onlyincompound() && + TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) || + (info && (*info & SPELL_INITCAP) && + TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen)))) { + he = NULL; + } + + if (he) { + if ((he->astr) && (pAMgr) && + TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) { + if (info) + *info += SPELL_FORBIDDEN; + return NULL; + } + if (root) { + std::string word_root(he->word); + if (complexprefixes) { + if (utf8) + reverseword_utf(word_root); + else + reverseword(word_root); + } + *root = mystrdup(word_root.c_str()); + } + // try check compound word + } else if (pAMgr->get_compound()) { + struct hentry* rwords[100]; // buffer for COMPOUND pattern checking + he = pAMgr->compound_check(word, len, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 0, info); + // LANG_hu section: `moving rule' with last dash + if ((!he) && (langnum == LANG_hu) && (word[len - 1] == '-')) { + char* dup = mystrdup(word); + if (!dup) + return NULL; + dup[len - 1] = '\0'; + he = pAMgr->compound_check(dup, len - 1, -5, 0, 100, 0, NULL, (hentry**)&rwords, 1, 0, + info); + free(dup); + } + // end of LANG specific region + if (he) { + if (root) { + std::string word_root(he->word); + if (complexprefixes) { + if (utf8) + reverseword_utf(word_root); + else + reverseword(word_root); + } + *root = mystrdup(word_root.c_str()); + } + if (info) + *info += SPELL_COMPOUND; + } + } + } + + return he; +} + +int Hunspell::suggest(char*** slst, const char* word) { + int onlycmpdsug = 0; + if (!pSMgr || maxdic == 0) + return 0; + *slst = NULL; + // process XML input of the simplified API (see manual) + if (strncmp(word, SPELL_XML, sizeof(SPELL_XML) - 3) == 0) { + return spellml(slst, word); + } + int nc = strlen(word); + if (utf8) { + if (nc >= MAXWORDUTF8LEN) + return 0; + } else { + if (nc >= MAXWORDLEN) + return 0; + } + int captype = NOCAP; + size_t abbv = 0; + size_t wl = 0; + + std::string scw; + std::vector sunicw; + + // input conversion + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + { + std::string wspace; + + int convstatus = rl ? rl->conv(word, wspace) : 0; + if (convstatus < 0) + return 0; + else if (convstatus > 0) + wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv); + else + wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv); + + if (wl == 0) + return 0; + } + + int ns = 0; + int capwords = 0; + + // check capitalized form for FORCEUCASE + if (pAMgr && captype == NOCAP && pAMgr->get_forceucase()) { + int info = SPELL_ORIGCAP; + if (checkword(scw.c_str(), &info, NULL)) { + std::string form(scw); + mkinitcap(form); + + char** wlst = (char**)malloc(MAXSUGGESTION * sizeof(char*)); + if (wlst == NULL) + return -1; + *slst = wlst; + wlst[0] = mystrdup(form.c_str()); + for (int i = 1; i < MAXSUGGESTION; ++i) { + wlst[i] = NULL; + } + + return 1; + } + } + + switch (captype) { + case NOCAP: { + ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug); + break; + } + + case INITCAP: { + capwords = 1; + ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug); + if (ns == -1) + break; + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + break; + } + case HUHINITCAP: + capwords = 1; + case HUHCAP: { + ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug); + if (ns != -1) { + // something.The -> something. The + size_t dot_pos = scw.find('.'); + if (dot_pos != std::string::npos) { + std::string postdot = scw.substr(dot_pos + 1); + int captype_; + if (utf8) { + std::vector postdotu; + u8_u16(postdotu, postdot); + captype_ = get_captype_utf8(postdotu, langnum); + } else { + captype_ = get_captype(postdot, csconv); + } + if (captype_ == INITCAP) { + std::string str(scw); + str.insert(dot_pos + 1, 1, ' '); + ns = insert_sug(slst, str.c_str(), ns); + } + } + + std::string wspace; + + if (captype == HUHINITCAP) { + // TheOpenOffice.org -> The OpenOffice.org + wspace = scw; + mkinitsmall2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + } + wspace = scw; + mkallsmall2(wspace, sunicw); + if (spell(wspace.c_str())) + ns = insert_sug(slst, wspace.c_str(), ns); + int prevns = ns; + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + if (captype == HUHINITCAP) { + mkinitcap2(wspace, sunicw); + if (spell(wspace.c_str())) + ns = insert_sug(slst, wspace.c_str(), ns); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + } + // aNew -> "a New" (instead of "a new") + for (int j = prevns; j < ns; j++) { + char* space = strchr((*slst)[j], ' '); + if (space) { + size_t slen = strlen(space + 1); + // different case after space (need capitalisation) + if ((slen < wl) && strcmp(scw.c_str() + wl - slen, space + 1)) { + std::string first((*slst)[j], space + 1); + std::string second(space + 1); + std::vector w; + if (utf8) + u8_u16(w, second); + mkinitcap2(second, w); + // set as first suggestion + char* r = (*slst)[j]; + for (int k = j; k > 0; k--) + (*slst)[k] = (*slst)[k - 1]; + free(r); + (*slst)[0] = mystrdup((first + second).c_str()); + } + } + } + } + break; + } + + case ALLCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + if (ns == -1) + break; + if (pAMgr && pAMgr->get_keepcase() && spell(wspace.c_str())) + ns = insert_sug(slst, wspace.c_str(), ns); + mkinitcap2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + for (int j = 0; j < ns; j++) { + std::string form((*slst)[j]); + mkallcap(form); + + if (pAMgr && pAMgr->get_checksharps()) { + if (utf8) { + mystrrep(form, "\xC3\x9F", "SS"); + } else { + mystrrep(form, "\xDF", "SS"); + } + } + + free((*slst)[j]); + (*slst)[j] = mystrdup(form.c_str()); + + } + break; + } + } + + // LANG_hu section: replace '-' with ' ' in Hungarian + if (langnum == LANG_hu) { + for (int j = 0; j < ns; j++) { + char* pos = strchr((*slst)[j], '-'); + if (pos) { + int info; + *pos = '\0'; + std::string w((*slst)[j]); + w.append(pos + 1); + (void)spell(w.c_str(), &info, NULL); + if ((info & SPELL_COMPOUND) && (info & SPELL_FORBIDDEN)) { + *pos = ' '; + } else + *pos = '-'; + } + } + } + // END OF LANG_hu section + + // try ngram approach since found nothing or only compound words + if (pAMgr && (ns == 0 || onlycmpdsug) && (pAMgr->get_maxngramsugs() != 0) && + (*slst)) { + switch (captype) { + case NOCAP: { + ns = pSMgr->ngsuggest(*slst, scw.c_str(), ns, pHMgr, maxdic); + break; + } + case HUHINITCAP: + capwords = 1; + case HUHCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic); + break; + } + case INITCAP: { + capwords = 1; + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic); + break; + } + case ALLCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + int oldns = ns; + ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic); + for (int j = oldns; j < ns; j++) { + std::string form((*slst)[j]); + mkallcap(form); + free((*slst)[j]); + (*slst)[j] = mystrdup(form.c_str()); + } + break; + } + } + } + + // try dash suggestion (Afo-American -> Afro-American) + size_t dash_pos = scw.find('-'); + if (dash_pos != std::string::npos) { + int nodashsug = 1; + for (int j = 0; j < ns && nodashsug == 1; j++) { + if (strchr((*slst)[j], '-')) + nodashsug = 0; + } + + size_t prev_pos = 0; + bool last = false; + + while (nodashsug && !last) { + if (dash_pos == scw.size()) + last = 1; + std::string chunk = scw.substr(prev_pos, dash_pos - prev_pos); + if (!spell(chunk.c_str())) { + char** nlst = NULL; + int nn = suggest(&nlst, chunk.c_str()); + for (int j = nn - 1; j >= 0; j--) { + std::string wspace = scw.substr(0, prev_pos); + wspace.append(nlst[j]); + if (!last) { + wspace.append("-"); + wspace.append(scw.substr(dash_pos + 1)); + } + ns = insert_sug(slst, wspace.c_str(), ns); + free(nlst[j]); + } + if (nlst != NULL) + free(nlst); + nodashsug = 0; + } + if (!last) { + prev_pos = dash_pos + 1; + dash_pos = scw.find('-', prev_pos); + } + if (dash_pos == std::string::npos) + dash_pos = scw.size(); + } + } + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + for (int j = 0; j < ns; j++) { + std::string root((*slst)[j]); + free((*slst)[j]); + if (utf8) + reverseword_utf(root); + else + reverseword(root); + (*slst)[j] = mystrdup(root.c_str()); + } + } + + // capitalize + if (capwords) + for (int j = 0; j < ns; j++) { + std::string form((*slst)[j]); + free((*slst)[j]); + mkinitcap(form); + (*slst)[j] = mystrdup(form.c_str()); + } + + // expand suggestions with dot(s) + if (abbv && pAMgr && pAMgr->get_sugswithdots()) { + for (int j = 0; j < ns; j++) { + (*slst)[j] = (char*)realloc((*slst)[j], strlen((*slst)[j]) + 1 + abbv); + strcat((*slst)[j], word + strlen(word) - abbv); + } + } + + // remove bad capitalized and forbidden forms + if (pAMgr && (pAMgr->get_keepcase() || pAMgr->get_forbiddenword())) { + switch (captype) { + case INITCAP: + case ALLCAP: { + int l = 0; + for (int j = 0; j < ns; j++) { + if (!strchr((*slst)[j], ' ') && !spell((*slst)[j])) { + std::string s; + std::vector w; + if (utf8) { + u8_u16(w, (*slst)[j]); + } else { + s = (*slst)[j]; + } + mkallsmall2(s, w); + free((*slst)[j]); + if (spell(s.c_str())) { + (*slst)[l] = mystrdup(s.c_str()); + if ((*slst)[l]) + l++; + } else { + mkinitcap2(s, w); + if (spell(s.c_str())) { + (*slst)[l] = mystrdup(s.c_str()); + if ((*slst)[l]) + l++; + } + } + } else { + (*slst)[l] = (*slst)[j]; + l++; + } + } + ns = l; + } + } + } + + // remove duplications + int l = 0; + for (int j = 0; j < ns; j++) { + (*slst)[l] = (*slst)[j]; + for (int k = 0; k < l; k++) { + if (strcmp((*slst)[k], (*slst)[j]) == 0) { + free((*slst)[j]); + l--; + break; + } + } + l++; + } + ns = l; + + // output conversion + rl = (pAMgr) ? pAMgr->get_oconvtable() : NULL; + for (int j = 0; rl && j < ns; j++) { + std::string wspace; + if (rl->conv((*slst)[j], wspace) > 0) { + free((*slst)[j]); + (*slst)[j] = mystrdup(wspace.c_str()); + } + } + + // if suggestions removed by nosuggest, onlyincompound parameters + if (l == 0 && *slst) { + free(*slst); + *slst = NULL; + } + return l; +} + +void Hunspell::free_list(char*** slst, int n) { + freelist(slst, n); +} + +char* Hunspell::get_dic_encoding() { + return encoding; +} + +int Hunspell::stem(char*** slst, char** desc, int n) { + + std::string result2; + *slst = NULL; + if (n == 0) + return 0; + for (int i = 0; i < n; i++) { + + std::string result; + + // add compound word parts (except the last one) + char* s = (char*)desc[i]; + char* part = strstr(s, MORPH_PART); + if (part) { + char* nextpart = strstr(part + 1, MORPH_PART); + while (nextpart) { + std::string field; + copy_field(field, part, MORPH_PART); + result.append(field); + part = nextpart; + nextpart = strstr(part + 1, MORPH_PART); + } + s = part; + } + + char** pl; + std::string tok(s); + size_t alt = 0; + while ((alt = tok.find(" | ", alt)) != std::string::npos) { + tok[alt + 1] = MSEP_ALT; + } + int pln = line_tok(tok.c_str(), &pl, MSEP_ALT); + for (int k = 0; k < pln; k++) { + // add derivational suffixes + if (strstr(pl[k], MORPH_DERI_SFX)) { + // remove inflectional suffixes + char* is = strstr(pl[k], MORPH_INFL_SFX); + if (is) + *is = '\0'; + char* sg = pSMgr->suggest_gen(&(pl[k]), 1, pl[k]); + if (sg) { + char** gen; + int genl = line_tok(sg, &gen, MSEP_REC); + free(sg); + for (int j = 0; j < genl; j++) { + result2.push_back(MSEP_REC); + result2.append(result); + result2.append(gen[j]); + } + freelist(&gen, genl); + } + } else { + result2.push_back(MSEP_REC); + result2.append(result); + if (strstr(pl[k], MORPH_SURF_PFX)) { + std::string field; + copy_field(field, pl[k], MORPH_SURF_PFX); + result2.append(field); + } + std::string field; + copy_field(field, pl[k], MORPH_STEM); + result2.append(field); + } + } + freelist(&pl, pln); + } + int sln = line_tok(result2.c_str(), slst, MSEP_REC); + return uniqlist(*slst, sln); +} + +int Hunspell::stem(char*** slst, const char* word) { + char** pl; + int pln = analyze(&pl, word); + int pln2 = stem(slst, pl, pln); + freelist(&pl, pln); + return pln2; +} + +const char* Hunspell::get_wordchars() { + return pAMgr->get_wordchars(); +} + +const std::vector& Hunspell::get_wordchars_utf16() { + return pAMgr->get_wordchars_utf16(); +} + +void Hunspell::mkinitcap(std::string& u8) { + if (utf8) { + std::vector u16; + u8_u16(u16, u8); + ::mkinitcap_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkinitcap(u8, csconv); + } +} + +int Hunspell::mkinitcap2(std::string& u8, std::vector& u16) { + if (utf8) { + ::mkinitcap_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkinitcap(u8, csconv); + } + return u8.size(); +} + +int Hunspell::mkinitsmall2(std::string& u8, std::vector& u16) { + if (utf8) { + ::mkinitsmall_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkinitsmall(u8, csconv); + } + return u8.size(); +} + +int Hunspell::add(const char* word) { + if (pHMgr[0]) + return (pHMgr[0])->add(word); + return 0; +} + +int Hunspell::add_with_affix(const char* word, const char* example) { + if (pHMgr[0]) + return (pHMgr[0])->add_with_affix(word, example); + return 0; +} + +int Hunspell::remove(const char* word) { + if (pHMgr[0]) + return (pHMgr[0])->remove(word); + return 0; +} + +const char* Hunspell::get_version() { + return pAMgr->get_version(); +} + +struct cs_info* Hunspell::get_csconv() { + return csconv; +} + +void Hunspell::cat_result(std::string& result, char* st) { + if (st) { + if (!result.empty()) + result.append("\n"); + result.append(st); + free(st); + } +} + +int Hunspell::analyze(char*** slst, const char* word) { + *slst = NULL; + if (!pSMgr || maxdic == 0) + return 0; + int nc = strlen(word); + if (utf8) { + if (nc >= MAXWORDUTF8LEN) + return 0; + } else { + if (nc >= MAXWORDLEN) + return 0; + } + int captype = NOCAP; + size_t abbv = 0; + size_t wl = 0; + + std::string scw; + std::vector sunicw; + + // input conversion + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + { + std::string wspace; + + int convstatus = rl ? rl->conv(word, wspace) : 0; + if (convstatus < 0) + return 0; + else if (convstatus > 0) + wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv); + else + wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv); + } + + if (wl == 0) { + if (abbv) { + scw.clear(); + for (wl = 0; wl < abbv; wl++) + scw.push_back('.'); + abbv = 0; + } else + return 0; + } + + std::string result; + + size_t n = 0; + size_t n2 = 0; + size_t n3 = 0; + + // test numbers + // LANG_hu section: set dash information for suggestions + if (langnum == LANG_hu) { + while ((n < wl) && (((scw[n] <= '9') && (scw[n] >= '0')) || + (((scw[n] == '.') || (scw[n] == ',')) && (n > 0)))) { + n++; + if ((scw[n] == '.') || (scw[n] == ',')) { + if (((n2 == 0) && (n > 3)) || + ((n2 > 0) && ((scw[n - 1] == '.') || (scw[n - 1] == ',')))) + break; + n2++; + n3 = n; + } + } + + if ((n == wl) && (n3 > 0) && (n - n3 > 3)) + return 0; + if ((n == wl) || ((n > 0) && ((scw[n] == '%') || (scw[n] == '\xB0')) && + checkword(scw.c_str() + n, NULL, NULL))) { + result.append(scw); + result.resize(n - 1); + if (n == wl) + cat_result(result, pSMgr->suggest_morph(scw.c_str() + n - 1)); + else { + char sign = scw[n]; + scw[n] = '\0'; + cat_result(result, pSMgr->suggest_morph(scw.c_str() + n - 1)); + result.push_back('+'); // XXX SPEC. MORPHCODE + scw[n] = sign; + cat_result(result, pSMgr->suggest_morph(scw.c_str() + n)); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } + // END OF LANG_hu section + + switch (captype) { + case HUHCAP: + case HUHINITCAP: + case NOCAP: { + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + break; + } + case INITCAP: { + wl = mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + mkinitcap2(scw, sunicw); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + + u8buffer = scw; + u8buffer.push_back('.'); + + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + break; + } + case ALLCAP: { + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + mkinitcap2(scw, sunicw); + + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + + u8buffer = scw; + u8buffer.push_back('.'); + + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + break; + } + } + + if (!result.empty()) { + // word reversing wrapper for complex prefixes + if (complexprefixes) { + if (utf8) + reverseword_utf(result); + else + reverseword(result); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + + // compound word with dash (HU) I18n + // LANG_hu section: set dash information for suggestions + + size_t dash_pos = langnum == LANG_hu ? scw.find('-') : std::string::npos; + int nresult = 0; + if (dash_pos != std::string::npos) { + std::string part1 = scw.substr(0, dash_pos); + std::string part2 = scw.substr(dash_pos+1); + + // examine 2 sides of the dash + if (part2.empty()) { // base word ending with dash + if (spell(part1.c_str())) { + char* p = pSMgr->suggest_morph(part1.c_str()); + if (p) { + int ret = line_tok(p, slst, MSEP_REC); + free(p); + return ret; + } + } + } else if (part2.size() == 1 && part2[0] == 'e') { // XXX (HU) -e hat. + if (spell(part1.c_str()) && (spell("-e"))) { + char* st = pSMgr->suggest_morph(part1.c_str()); + if (st) { + result.append(st); + free(st); + } + result.push_back('+'); // XXX spec. separator in MORPHCODE + st = pSMgr->suggest_morph("-e"); + if (st) { + result.append(st); + free(st); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } else { + // first word ending with dash: word- XXX ??? + part1.push_back(' '); + nresult = spell(part1.c_str()); + part1.erase(part1.size() - 1); + if (nresult && spell(part2.c_str()) && + ((part2.size() > 1) || ((part2[0] > '0') && (part2[0] < '9')))) { + char* st = pSMgr->suggest_morph(part1.c_str()); + if (st) { + result.append(st); + free(st); + result.push_back('+'); // XXX spec. separator in MORPHCODE + } + st = pSMgr->suggest_morph(part2.c_str()); + if (st) { + result.append(st); + free(st); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } + // affixed number in correct word + if (nresult && (dash_pos > 0) && + (((scw[dash_pos - 1] <= '9') && (scw[dash_pos - 1] >= '0')) || + (scw[dash_pos - 1] == '.'))) { + n = 1; + if (scw[dash_pos - n] == '.') + n++; + // search first not a number character to left from dash + while ((dash_pos >= n) && ((scw[dash_pos - n] == '0') || (n < 3)) && + (n < 6)) { + n++; + } + if (dash_pos < n) + n--; + // numbers: valami1000000-hoz + // examine 100000-hoz, 10000-hoz 1000-hoz, 10-hoz, + // 56-hoz, 6-hoz + for (; n >= 1; n--) { + if (scw[dash_pos - n] < '0' || scw[dash_pos - n] > '9') { + continue; + } + std::string chunk = scw.substr(dash_pos - n); + if (checkword(chunk.c_str(), NULL, NULL)) { + result.append(chunk); + char* st = pSMgr->suggest_morph(chunk.c_str()); + if (st) { + result.append(st); + free(st); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } + } + } + return 0; +} + +int Hunspell::generate(char*** slst, const char* word, char** pl, int pln) { + *slst = NULL; + if (!pSMgr || !pln) + return 0; + char** pl2; + int pl2n = analyze(&pl2, word); + int captype = NOCAP; + int abbv = 0; + std::string cw; + cleanword(cw, word, &captype, &abbv); + std::string result; + + for (int i = 0; i < pln; i++) { + cat_result(result, pSMgr->suggest_gen(pl2, pl2n, pl[i])); + } + freelist(&pl2, pl2n); + + if (!result.empty()) { + // allcap + if (captype == ALLCAP) + mkallcap(result); + + // line split + int linenum = line_tok(result.c_str(), slst, MSEP_REC); + + // capitalize + if (captype == INITCAP || captype == HUHINITCAP) { + for (int j = 0; j < linenum; j++) { + std::string form((*slst)[j]); + free((*slst)[j]); + mkinitcap(form); + (*slst)[j] = mystrdup(form.c_str()); + } + } + + // temporary filtering of prefix related errors (eg. + // generate("undrinkable", "eats") --> "undrinkables" and "*undrinks") + + int r = 0; + for (int j = 0; j < linenum; j++) { + if (!spell((*slst)[j])) { + free((*slst)[j]); + (*slst)[j] = NULL; + } else { + if (r < j) + (*slst)[r] = (*slst)[j]; + r++; + } + } + if (r > 0) + return r; + free(*slst); + *slst = NULL; + } + return 0; +} + +int Hunspell::generate(char*** slst, const char* word, const char* pattern) { + char** pl; + int pln = analyze(&pl, pattern); + int n = generate(slst, word, pl, pln); + freelist(&pl, pln); + return uniqlist(*slst, n); +} + +// minimal XML parser functions +std::string Hunspell::get_xml_par(const char* par) { + std::string dest; + if (!par) + return dest; + char end = *par; + if (end == '>') + end = '<'; + else if (end != '\'' && end != '"') + return 0; // bad XML + for (par++; *par != '\0' && *par != end; ++par) { + dest.push_back(*par); + } + mystrrep(dest, "<", "<"); + mystrrep(dest, "&", "&"); + return dest; +} + +int Hunspell::get_langnum() const { + return langnum; +} + +int Hunspell::input_conv(const char* word, char* dest, size_t destsize) { + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + return (rl && rl->conv(word, dest, destsize) > 0); +} + +// return the beginning of the element (attr == NULL) or the attribute +const char* Hunspell::get_xml_pos(const char* s, const char* attr) { + const char* end = strchr(s, '>'); + const char* p = s; + if (attr == NULL) + return end; + do { + p = strstr(p, attr); + if (!p || p >= end) + return 0; + } while (*(p - 1) != ' ' && *(p - 1) != '\n'); + return p + strlen(attr); +} + +int Hunspell::check_xml_par(const char* q, + const char* attr, + const char* value) { + std::string cw = get_xml_par(get_xml_pos(q, attr)); + if (cw == value) + return 1; + return 0; +} + +int Hunspell::get_xml_list(char*** slst, const char* list, const char* tag) { + if (!list) + return 0; + int n = 0; + const char* p; + for (p = list; ((p = strstr(p, tag)) != NULL); p++) + n++; + if (n == 0) + return 0; + *slst = (char**)malloc(sizeof(char*) * n); + if (!*slst) + return 0; + for (p = list, n = 0; ((p = strstr(p, tag)) != NULL); p++, n++) { + std::string cw = get_xml_par(p + strlen(tag) - 1); + if (cw.empty()) { + break; + } + (*slst)[n] = mystrdup(cw.c_str()); + } + return n; +} + +int Hunspell::spellml(char*** slst, const char* word) { + const char* q = strstr(word, "'); + if (!q2) + return 0; // bad XML input + q2 = strstr(q2, "')); + if (!cw.empty()) + n = analyze(slst, cw.c_str()); + if (n == 0) + return 0; + // convert the result to ana1ana2 format + std::string r; + r.append(""); + for (int i = 0; i < n; i++) { + r.append(""); + + std::string entry((*slst)[i]); + free((*slst)[i]); + mystrrep(entry, "\t", " "); + mystrrep(entry, "&", "&"); + mystrrep(entry, "<", "<"); + r.append(entry); + + r.append(""); + } + r.append(""); + (*slst)[0] = mystrdup(r.c_str()); + return 1; + } else if (check_xml_par(q, "type=", "stem")) { + std::string cw = get_xml_par(strchr(q2, '>')); + if (!cw.empty()) + return stem(slst, cw.c_str()); + } else if (check_xml_par(q, "type=", "generate")) { + std::string cw = get_xml_par(strchr(q2, '>')); + if (cw.empty()) + return 0; + const char* q3 = strstr(q2 + 1, "')); + if (!cw2.empty()) { + return generate(slst, cw.c_str(), cw2.c_str()); + } + } else { + if ((q2 = strstr(q2 + 1, "'), ""); + if (n != 0) { + int n2 = generate(slst, cw.c_str(), slst2, n); + freelist(&slst2, n); + return uniqlist(*slst, n2); + } + freelist(&slst2, n); + } + } + } + return 0; +} + +Hunhandle* Hunspell_create(const char* affpath, const char* dpath) { + return (Hunhandle*)(new Hunspell(affpath, dpath)); +} + +Hunhandle* Hunspell_create_key(const char* affpath, + const char* dpath, + const char* key) { + return (Hunhandle*)(new Hunspell(affpath, dpath, key)); +} + +void Hunspell_destroy(Hunhandle* pHunspell) { + delete (Hunspell*)(pHunspell); +} + +int Hunspell_add_dic(Hunhandle* pHunspell, const char* dpath) { + return ((Hunspell*)pHunspell)->add_dic(dpath); +} + +int Hunspell_spell(Hunhandle* pHunspell, const char* word) { + return ((Hunspell*)pHunspell)->spell(word); +} + +char* Hunspell_get_dic_encoding(Hunhandle* pHunspell) { + return ((Hunspell*)pHunspell)->get_dic_encoding(); +} + +int Hunspell_suggest(Hunhandle* pHunspell, char*** slst, const char* word) { + return ((Hunspell*)pHunspell)->suggest(slst, word); +} + +int Hunspell_analyze(Hunhandle* pHunspell, char*** slst, const char* word) { + return ((Hunspell*)pHunspell)->analyze(slst, word); +} + +int Hunspell_stem(Hunhandle* pHunspell, char*** slst, const char* word) { + return ((Hunspell*)pHunspell)->stem(slst, word); +} + +int Hunspell_stem2(Hunhandle* pHunspell, char*** slst, char** desc, int n) { + return ((Hunspell*)pHunspell)->stem(slst, desc, n); +} + +int Hunspell_generate(Hunhandle* pHunspell, + char*** slst, + const char* word, + const char* word2) { + return ((Hunspell*)pHunspell)->generate(slst, word, word2); +} + +int Hunspell_generate2(Hunhandle* pHunspell, + char*** slst, + const char* word, + char** desc, + int n) { + return ((Hunspell*)pHunspell)->generate(slst, word, desc, n); +} + +/* functions for run-time modification of the dictionary */ + +/* add word to the run-time dictionary */ + +int Hunspell_add(Hunhandle* pHunspell, const char* word) { + return ((Hunspell*)pHunspell)->add(word); +} + +/* add word to the run-time dictionary with affix flags of + * the example (a dictionary word): Hunspell will recognize + * affixed forms of the new word, too. + */ + +int Hunspell_add_with_affix(Hunhandle* pHunspell, + const char* word, + const char* example) { + return ((Hunspell*)pHunspell)->add_with_affix(word, example); +} + +/* remove word from the run-time dictionary */ + +int Hunspell_remove(Hunhandle* pHunspell, const char* word) { + return ((Hunspell*)pHunspell)->remove(word); +} + +void Hunspell_free_list(Hunhandle*, char*** slst, int n) { + freelist(slst, n); +} + +int Hunspell::suffix_suggest(char*** slst, const char* root_word) { + struct hentry* he = NULL; + int len; + std::string w2; + const char* word; + char* ignoredchars = pAMgr->get_ignore(); + if (ignoredchars != NULL) { + w2.assign(root_word); + if (utf8) { + const std::vector& ignoredchars_utf16 = + pAMgr->get_ignore_utf16(); + remove_ignored_chars_utf(w2, ignoredchars_utf16); + } else { + remove_ignored_chars(w2, ignoredchars); + } + word = w2.c_str(); + } else + word = root_word; + + len = strlen(word); + + if (!len) + return 0; + + char** wlst = (char**)malloc(MAXSUGGESTION * sizeof(char*)); + if (wlst == NULL) + return -1; + *slst = wlst; + for (int i = 0; i < MAXSUGGESTION; i++) { + wlst[i] = NULL; + } + + for (int i = 0; (i < maxdic) && !he; i++) { + he = (pHMgr[i])->lookup(word); + } + if (he) { + return pAMgr->get_suffix_words(he->astr, he->alen, root_word, *slst); + } + return 0; +} diff --git a/extensions/spellcheck/hunspell/src/hunspell.h b/extensions/spellcheck/hunspell/src/hunspell.h new file mode 100644 index 000000000..726bbe207 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunspell.h @@ -0,0 +1,162 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MYSPELLMGR_H_ +#define _MYSPELLMGR_H_ + +#include "hunvisapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Hunhandle Hunhandle; + +LIBHUNSPELL_DLL_EXPORTED Hunhandle* Hunspell_create(const char* affpath, + const char* dpath); + +LIBHUNSPELL_DLL_EXPORTED Hunhandle* Hunspell_create_key(const char* affpath, + const char* dpath, + const char* key); + +LIBHUNSPELL_DLL_EXPORTED void Hunspell_destroy(Hunhandle* pHunspell); + +/* load extra dictionaries (only dic files) + * output: 0 = additional dictionary slots available, 1 = slots are now full*/ +LIBHUNSPELL_DLL_EXPORTED int Hunspell_add_dic(Hunhandle* pHunspell, + const char* dpath); + +/* spell(word) - spellcheck word + * output: 0 = bad word, not 0 = good word + */ +LIBHUNSPELL_DLL_EXPORTED int Hunspell_spell(Hunhandle* pHunspell, const char*); + +LIBHUNSPELL_DLL_EXPORTED char* Hunspell_get_dic_encoding(Hunhandle* pHunspell); + +/* suggest(suggestions, word) - search suggestions + * input: pointer to an array of strings pointer and the (bad) word + * array of strings pointer (here *slst) may not be initialized + * output: number of suggestions in string array, and suggestions in + * a newly allocated array of strings (*slts will be NULL when number + * of suggestion equals 0.) + */ +LIBHUNSPELL_DLL_EXPORTED int Hunspell_suggest(Hunhandle* pHunspell, + char*** slst, + const char* word); + +/* morphological functions */ + +/* analyze(result, word) - morphological analysis of the word */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_analyze(Hunhandle* pHunspell, + char*** slst, + const char* word); + +/* stem(result, word) - stemmer function */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_stem(Hunhandle* pHunspell, + char*** slst, + const char* word); + +/* stem(result, analysis, n) - get stems from a morph. analysis + * example: + * char ** result, result2; + * int n1 = Hunspell_analyze(result, "words"); + * int n2 = Hunspell_stem2(result2, result, n1); + */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_stem2(Hunhandle* pHunspell, + char*** slst, + char** desc, + int n); + +/* generate(result, word, word2) - morphological generation by example(s) */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_generate(Hunhandle* pHunspell, + char*** slst, + const char* word, + const char* word2); + +/* generate(result, word, desc, n) - generation by morph. description(s) + * example: + * char ** result; + * char * affix = "is:plural"; // description depends from dictionaries, too + * int n = Hunspell_generate2(result, "word", &affix, 1); + * for (int i = 0; i < n; i++) printf("%s\n", result[i]); + */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_generate2(Hunhandle* pHunspell, + char*** slst, + const char* word, + char** desc, + int n); + +/* functions for run-time modification of the dictionary */ + +/* add word to the run-time dictionary */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_add(Hunhandle* pHunspell, + const char* word); + +/* add word to the run-time dictionary with affix flags of + * the example (a dictionary word): Hunspell will recognize + * affixed forms of the new word, too. + */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_add_with_affix(Hunhandle* pHunspell, + const char* word, + const char* example); + +/* remove word from the run-time dictionary */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_remove(Hunhandle* pHunspell, + const char* word); + +/* free suggestion lists */ + +LIBHUNSPELL_DLL_EXPORTED void Hunspell_free_list(Hunhandle* pHunspell, + char*** slst, + int n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunspell.hxx b/extensions/spellcheck/hunspell/src/hunspell.hxx new file mode 100644 index 000000000..401475309 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunspell.hxx @@ -0,0 +1,258 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hunvisapi.h" + +#include "hashmgr.hxx" +#include "affixmgr.hxx" +#include "suggestmgr.hxx" +#include "langnum.hxx" +#include + +#define SPELL_XML "" + +#define MAXDIC 20 +#define MAXSUGGESTION 15 +#define MAXSHARPS 5 + +#define HUNSPELL_OK (1 << 0) +#define HUNSPELL_OK_WARN (1 << 1) + +#ifndef _MYSPELLMGR_HXX_ +#define _MYSPELLMGR_HXX_ + +class LIBHUNSPELL_DLL_EXPORTED Hunspell { + private: + Hunspell(const Hunspell&); + Hunspell& operator=(const Hunspell&); + + private: + AffixMgr* pAMgr; + HashMgr* pHMgr[MAXDIC]; + int maxdic; + SuggestMgr* pSMgr; + char* affixpath; + char* encoding; + struct cs_info* csconv; + int langnum; + int utf8; + int complexprefixes; + char** wordbreak; + + public: + /* Hunspell(aff, dic) - constructor of Hunspell class + * input: path of affix file and dictionary file + * + * In WIN32 environment, use UTF-8 encoded paths started with the long path + * prefix \\\\?\\ to handle system-independent character encoding and very + * long path names (without the long path prefix Hunspell will use fopen() + * with system-dependent character encoding instead of _wfopen()). + */ + + Hunspell(const char* affpath, const char* dpath, const char* key = NULL); + ~Hunspell(); + + /* load extra dictionaries (only dic files) */ + int add_dic(const char* dpath, const char* key = NULL); + + /* spell(word) - spellcheck word + * output: 0 = bad word, not 0 = good word + * + * plus output: + * info: information bit array, fields: + * SPELL_COMPOUND = a compound word + * SPELL_FORBIDDEN = an explicit forbidden word + * root: root (stem), when input is a word with affix(es) + */ + + int spell(const char* word, int* info = NULL, char** root = NULL); + + /* suggest(suggestions, word) - search suggestions + * input: pointer to an array of strings pointer and the (bad) word + * array of strings pointer (here *slst) may not be initialized + * output: number of suggestions in string array, and suggestions in + * a newly allocated array of strings (*slts will be NULL when number + * of suggestion equals 0.) + */ + + int suggest(char*** slst, const char* word); + + /* Suggest words from suffix rules + * suffix_suggest(suggestions, root_word) + * input: pointer to an array of strings pointer and the word + * array of strings pointer (here *slst) may not be initialized + * output: number of suggestions in string array, and suggestions in + * a newly allocated array of strings (*slts will be NULL when number + * of suggestion equals 0.) + */ + int suffix_suggest(char*** slst, const char* root_word); + + /* deallocate suggestion lists */ + + void free_list(char*** slst, int n); + + char* get_dic_encoding(); + + /* morphological functions */ + + /* analyze(result, word) - morphological analysis of the word */ + + int analyze(char*** slst, const char* word); + + /* stem(result, word) - stemmer function */ + + int stem(char*** slst, const char* word); + + /* stem(result, analysis, n) - get stems from a morph. analysis + * example: + * char ** result, result2; + * int n1 = analyze(&result, "words"); + * int n2 = stem(&result2, result, n1); + */ + + int stem(char*** slst, char** morph, int n); + + /* generate(result, word, word2) - morphological generation by example(s) */ + + int generate(char*** slst, const char* word, const char* word2); + + /* generate(result, word, desc, n) - generation by morph. description(s) + * example: + * char ** result; + * char * affix = "is:plural"; // description depends from dictionaries, too + * int n = generate(&result, "word", &affix, 1); + * for (int i = 0; i < n; i++) printf("%s\n", result[i]); + */ + + int generate(char*** slst, const char* word, char** desc, int n); + + /* functions for run-time modification of the dictionary */ + + /* add word to the run-time dictionary */ + + int add(const char* word); + + /* add word to the run-time dictionary with affix flags of + * the example (a dictionary word): Hunspell will recognize + * affixed forms of the new word, too. + */ + + int add_with_affix(const char* word, const char* example); + + /* remove word from the run-time dictionary */ + + int remove(const char* word); + + /* other */ + + /* get extra word characters definied in affix file for tokenization */ + const char* get_wordchars(); + const std::vector& get_wordchars_utf16(); + + struct cs_info* get_csconv(); + const char* get_version(); + + int get_langnum() const; + + /* need for putdic */ + int input_conv(const char* word, char* dest, size_t destsize); + + private: + void cleanword(std::string& dest, const char*, int* pcaptype, int* pabbrev); + size_t cleanword2(std::string& dest, + std::vector& dest_u, + const char*, + int* w_len, + int* pcaptype, + size_t* pabbrev); + void mkinitcap(std::string& u8); + int mkinitcap2(std::string& u8, std::vector& u16); + int mkinitsmall2(std::string& u8, std::vector& u16); + void mkallcap(std::string& u8); + int mkallsmall2(std::string& u8, std::vector& u16); + struct hentry* checkword(const char*, int* info, char** root); + std::string sharps_u8_l1(const std::string& source); + hentry* + spellsharps(std::string& base, size_t start_pos, int, int, int* info, char** root); + int is_keepcase(const hentry* rv); + int insert_sug(char*** slst, const char* word, int ns); + void cat_result(std::string& result, char* st); + char* stem_description(const char* desc); + int spellml(char*** slst, const char* word); + std::string get_xml_par(const char* par); + const char* get_xml_pos(const char* s, const char* attr); + int get_xml_list(char*** slst, const char* list, const char* tag); + int check_xml_par(const char* q, const char* attr, const char* value); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunvisapi.h b/extensions/spellcheck/hunspell/src/hunvisapi.h new file mode 100644 index 000000000..503c20f66 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunvisapi.h @@ -0,0 +1,18 @@ +#ifndef _HUNSPELL_VISIBILITY_H_ +#define _HUNSPELL_VISIBILITY_H_ + +#if defined(HUNSPELL_STATIC) +# define LIBHUNSPELL_DLL_EXPORTED +#elif defined(_MSC_VER) +# if defined(BUILDING_LIBHUNSPELL) +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllexport) +# else +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBHUNSPELL) && 1 +# define LIBHUNSPELL_DLL_EXPORTED __attribute__((__visibility__("default"))) +#else +# define LIBHUNSPELL_DLL_EXPORTED +#endif + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunzip.cxx b/extensions/spellcheck/hunspell/src/hunzip.cxx new file mode 100644 index 000000000..b2788a105 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunzip.cxx @@ -0,0 +1,263 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include + +#include "hunzip.hxx" +#include "csutil.hxx" + +#define CODELEN 65536 +#define BASEBITREC 5000 + +#define UNCOMPRESSED '\002' +#define MAGIC "hz0" +#define MAGIC_ENCRYPT "hz1" +#define MAGICLEN (sizeof(MAGIC) - 1) + +int Hunzip::fail(const char* err, const char* par) { + fprintf(stderr, err, par); + return -1; +} + +Hunzip::Hunzip(const char* file, const char* key) + : fin(NULL), bufsiz(0), lastbit(0), inc(0), inbits(0), outc(0), dec(NULL) { + in[0] = out[0] = line[0] = '\0'; + filename = mystrdup(file); + if (getcode(key) == -1) + bufsiz = -1; + else + bufsiz = getbuf(); +} + +int Hunzip::getcode(const char* key) { + unsigned char c[2]; + int i, j, n, p; + int allocatedbit = BASEBITREC; + const char* enc = key; + + if (!filename) + return -1; + + fin = myfopen(filename, "rb"); + if (!fin) + return -1; + + // read magic number + if ((fread(in, 1, 3, fin) < MAGICLEN) || + !(strncmp(MAGIC, in, MAGICLEN) == 0 || + strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0)) { + return fail(MSG_FORMAT, filename); + } + + // check encryption + if (strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0) { + unsigned char cs; + if (!key) + return fail(MSG_KEY, filename); + if (fread(&c, 1, 1, fin) < 1) + return fail(MSG_FORMAT, filename); + for (cs = 0; *enc; enc++) + cs ^= *enc; + if (cs != c[0]) + return fail(MSG_KEY, filename); + enc = key; + } else + key = NULL; + + // read record count + if (fread(&c, 1, 2, fin) < 2) + return fail(MSG_FORMAT, filename); + + if (key) { + c[0] ^= *enc; + if (*(++enc) == '\0') + enc = key; + c[1] ^= *enc; + } + + n = ((int)c[0] << 8) + c[1]; + dec = (struct bit*)malloc(BASEBITREC * sizeof(struct bit)); + if (!dec) + return fail(MSG_MEMORY, filename); + dec[0].v[0] = 0; + dec[0].v[1] = 0; + + // read codes + for (i = 0; i < n; i++) { + unsigned char l; + if (fread(c, 1, 2, fin) < 2) + return fail(MSG_FORMAT, filename); + if (key) { + if (*(++enc) == '\0') + enc = key; + c[0] ^= *enc; + if (*(++enc) == '\0') + enc = key; + c[1] ^= *enc; + } + if (fread(&l, 1, 1, fin) < 1) + return fail(MSG_FORMAT, filename); + if (key) { + if (*(++enc) == '\0') + enc = key; + l ^= *enc; + } + if (fread(in, 1, l / 8 + 1, fin) < (size_t)l / 8 + 1) + return fail(MSG_FORMAT, filename); + if (key) + for (j = 0; j <= l / 8; j++) { + if (*(++enc) == '\0') + enc = key; + in[j] ^= *enc; + } + p = 0; + for (j = 0; j < l; j++) { + int b = (in[j / 8] & (1 << (7 - (j % 8)))) ? 1 : 0; + int oldp = p; + p = dec[p].v[b]; + if (p == 0) { + lastbit++; + if (lastbit == allocatedbit) { + allocatedbit += BASEBITREC; + dec = (struct bit*)realloc(dec, allocatedbit * sizeof(struct bit)); + } + dec[lastbit].v[0] = 0; + dec[lastbit].v[1] = 0; + dec[oldp].v[b] = lastbit; + p = lastbit; + } + } + dec[p].c[0] = c[0]; + dec[p].c[1] = c[1]; + } + return 0; +} + +Hunzip::~Hunzip() { + if (dec) + free(dec); + if (fin) + fclose(fin); + if (filename) + free(filename); +} + +int Hunzip::getbuf() { + int p = 0; + int o = 0; + do { + if (inc == 0) + inbits = fread(in, 1, BUFSIZE, fin) * 8; + for (; inc < inbits; inc++) { + int b = (in[inc / 8] & (1 << (7 - (inc % 8)))) ? 1 : 0; + int oldp = p; + p = dec[p].v[b]; + if (p == 0) { + if (oldp == lastbit) { + fclose(fin); + fin = NULL; + // add last odd byte + if (dec[lastbit].c[0]) + out[o++] = dec[lastbit].c[1]; + return o; + } + out[o++] = dec[oldp].c[0]; + out[o++] = dec[oldp].c[1]; + if (o == BUFSIZE) + return o; + p = dec[p].v[b]; + } + } + inc = 0; + } while (inbits == BUFSIZE * 8); + return fail(MSG_FORMAT, filename); +} + +const char* Hunzip::getline() { + char linebuf[BUFSIZE]; + int l = 0, eol = 0, left = 0, right = 0; + if (bufsiz == -1) + return NULL; + while (l < bufsiz && !eol) { + linebuf[l++] = out[outc]; + switch (out[outc]) { + case '\t': + break; + case 31: { // escape + if (++outc == bufsiz) { + bufsiz = getbuf(); + outc = 0; + } + linebuf[l - 1] = out[outc]; + break; + } + case ' ': + break; + default: + if (((unsigned char)out[outc]) < 47) { + if (out[outc] > 32) { + right = out[outc] - 31; + if (++outc == bufsiz) { + bufsiz = getbuf(); + outc = 0; + } + } + if (out[outc] == 30) + left = 9; + else + left = out[outc]; + linebuf[l - 1] = '\n'; + eol = 1; + } + } + if (++outc == bufsiz) { + outc = 0; + bufsiz = fin ? getbuf() : -1; + } + } + if (right) + strcpy(linebuf + l - 1, line + strlen(line) - right - 1); + else + linebuf[l] = '\0'; + strcpy(line + left, linebuf); + return line; +} diff --git a/extensions/spellcheck/hunspell/src/hunzip.hxx b/extensions/spellcheck/hunspell/src/hunzip.hxx new file mode 100644 index 000000000..5082adddb --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunzip.hxx @@ -0,0 +1,87 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* hunzip: file decompression for sorted dictionaries with optional encryption, + * algorithm: prefix-suffix encoding and 16-bit Huffman encoding */ + +#ifndef _HUNZIP_HXX_ +#define _HUNZIP_HXX_ + +#include "hunvisapi.h" + +#include + +#define BUFSIZE 65536 +#define HZIP_EXTENSION ".hz" + +#define MSG_OPEN "error: %s: cannot open\n" +#define MSG_FORMAT "error: %s: not in hzip format\n" +#define MSG_MEMORY "error: %s: missing memory\n" +#define MSG_KEY "error: %s: missing or bad password\n" + +struct bit { + unsigned char c[2]; + int v[2]; +}; + +class LIBHUNSPELL_DLL_EXPORTED Hunzip { + private: + Hunzip(const Hunzip&); + Hunzip& operator=(const Hunzip&); + + protected: + char* filename; + FILE* fin; + int bufsiz, lastbit, inc, inbits, outc; + struct bit* dec; // code table + char in[BUFSIZE]; // input buffer + char out[BUFSIZE + 1]; // Huffman-decoded buffer + char line[BUFSIZE + 50]; // decoded line + int getcode(const char* key); + int getbuf(); + int fail(const char* err, const char* par); + + public: + Hunzip(const char* filename, const char* key = NULL); + ~Hunzip(); + const char* getline(); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/langnum.hxx b/extensions/spellcheck/hunspell/src/langnum.hxx new file mode 100644 index 000000000..af5c86e4f --- /dev/null +++ b/extensions/spellcheck/hunspell/src/langnum.hxx @@ -0,0 +1,78 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _LANGNUM_HXX_ +#define _LANGNUM_HXX_ + +/* + language numbers for language specific codes + see http://l10n.openoffice.org/languages.html +*/ + +enum { + LANG_ar = 96, + LANG_az = 100, // custom number + LANG_bg = 41, + LANG_ca = 37, + LANG_cs = 42, + LANG_da = 45, + LANG_de = 49, + LANG_el = 30, + LANG_en = 01, + LANG_es = 34, + LANG_eu = 10, + LANG_fr = 02, + LANG_gl = 38, + LANG_hr = 78, + LANG_hu = 36, + LANG_it = 39, + LANG_la = 99, // custom number + LANG_lv = 101, // custom number + LANG_nl = 31, + LANG_pl = 48, + LANG_pt = 03, + LANG_ru = 07, + LANG_sv = 50, + LANG_tr = 90, + LANG_uk = 80, + LANG_xx = 999 +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/license.hunspell b/extensions/spellcheck/hunspell/src/license.hunspell new file mode 100644 index 000000000..dc2ce9c1e --- /dev/null +++ b/extensions/spellcheck/hunspell/src/license.hunspell @@ -0,0 +1,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Laszlo Nemeth (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): + * David Einstein + * Davide Prina + * Giuseppe Modugno + * Gianluca Turconi + * Simon Brouwer + * Noll Janos + * Biro Arpad + * Goldman Eleonora + * Sarlos Tamas + * Bencsath Boldizsar + * Halacsy Peter + * Dvornik Laszlo + * Gefferth Andras + * Nagy Viktor + * Varga Daniel + * Chris Halls + * Rene Engelhard + * Bram Moolenaar + * Dafydd Jones + * Harri Pitkanen + * Andras Timar + * Tor Lillqvist + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_CLIENT +# include "config.h" +#endif diff --git a/extensions/spellcheck/hunspell/src/license.myspell b/extensions/spellcheck/hunspell/src/license.myspell new file mode 100644 index 000000000..2da533075 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/license.myspell @@ -0,0 +1,61 @@ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * NOTE: A special thanks and credit goes to Geoff Kuenning + * the creator of ispell. MySpell's affix algorithms were + * based on those of ispell which should be noted is + * copyright Geoff Kuenning et.al. and now available + * under a BSD style license. For more information on ispell + * and affix compression in general, please see: + * http://www.cs.ucla.edu/ficus-members/geoff/ispell.html + * (the home page for ispell) + * + * An almost complete rewrite of MySpell for use by + * the Mozilla project has been developed by David Einstein + * (Deinst@world.std.com). David and I are now + * working on parallel development tracks to help + * our respective projects (Mozilla and OpenOffice.org + * and we will maintain full affix file and dictionary + * file compatibility and work on merging our versions + * of MySpell back into a single tree. David has been + * a significant help in improving MySpell. + * + * Special thanks also go to La'szlo' Ne'meth + * who is the author of the + * Hungarian dictionary and who developed and contributed + * the code to support compound words in MySpell + * and fixed numerous problems with the encoding + * case conversion tables. + * + */ diff --git a/extensions/spellcheck/hunspell/src/moz.build b/extensions/spellcheck/hunspell/src/moz.build new file mode 100644 index 000000000..017264643 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/moz.build @@ -0,0 +1,38 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'affentry.cxx', + 'affixmgr.cxx', + 'csutil.cxx', + 'filemgr.cxx', + 'hashmgr.cxx', + 'hunspell.cxx', + 'hunzip.cxx', + 'phonet.cxx', + 'replist.cxx', + 'suggestmgr.cxx', +] + +# This variable is referenced in configure.in. Make sure to change that file +# too if you need to change this variable. +DEFINES['HUNSPELL_STATIC'] = True + +FINAL_LIBRARY = 'xul' + +LOCAL_INCLUDES += [ + '../glue', +] + +# We allow warnings for third-party code that can be updated from upstream. +ALLOW_COMPILER_WARNINGS = True + +include('/ipc/chromium/chromium-config.mozbuild') + +if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']: + CXXFLAGS += [ + '-Wno-implicit-fallthrough', + ] diff --git a/extensions/spellcheck/hunspell/src/patches/1322666 b/extensions/spellcheck/hunspell/src/patches/1322666 new file mode 100644 index 000000000..16db1fbe6 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/patches/1322666 @@ -0,0 +1,24 @@ +Bug 1322666 - Change MAXWORDLEN to 100 + +diff --git a/extensions/spellcheck/hunspell/src/hunspell.cxx b/extensions/spellcheck/hunspell/src/hunspell.cxx +--- a/extensions/spellcheck/hunspell/src/hunspell.cxx ++++ b/extensions/spellcheck/hunspell/src/hunspell.cxx +@@ -80,17 +80,17 @@ + #ifndef MOZILLA_CLIENT + #include "config.h" + #endif + #include "csutil.hxx" + + #include + #include + +-#define MAXWORDLEN 176 ++#define MAXWORDLEN 100 + #define MAXWORDUTF8LEN (MAXWORDLEN * 3) + + Hunspell::Hunspell(const char* affpath, const char* dpath, const char* key) { + encoding = NULL; + csconv = NULL; + utf8 = 0; + complexprefixes = 0; + affixpath = mystrdup(affpath); diff --git a/extensions/spellcheck/hunspell/src/phonet.cxx b/extensions/spellcheck/hunspell/src/phonet.cxx new file mode 100644 index 000000000..17350e74a --- /dev/null +++ b/extensions/spellcheck/hunspell/src/phonet.cxx @@ -0,0 +1,274 @@ +/* phonetic.c - generic replacement aglogithms for phonetic transformation + Copyright (C) 2000 Bjoern Jacke + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation; + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; If not, see + . + + Changelog: + + 2000-01-05 Bjoern Jacke + Initial Release insprired by the article about phonetic + transformations out of c't 25/1999 + + 2007-07-26 Bjoern Jacke + Released under MPL/GPL/LGPL tri-license for Hunspell + + 2007-08-23 Laszlo Nemeth + Porting from Aspell to Hunspell using C-like structs +*/ + +#include +#include +#include +#include + +#include "csutil.hxx" +#include "phonet.hxx" + +void init_phonet_hash(phonetable& parms) { + int i, k; + + for (i = 0; i < HASHSIZE; i++) { + parms.hash[i] = -1; + } + + for (i = 0; parms.rules[i][0] != '\0'; i += 2) { + /** set hash value **/ + k = (unsigned char)parms.rules[i][0]; + + if (parms.hash[k] < 0) { + parms.hash[k] = i; + } + } +} + +// like strcpy but safe if the strings overlap +// but only if dest < src +static inline void strmove(char* dest, char* src) { + while (*src) + *dest++ = *src++; + *dest = '\0'; +} + +static int myisalpha(char ch) { + if ((unsigned char)ch < 128) + return isalpha(ch); + return 1; +} + +/* Do phonetic transformation. */ +/* phonetic transcription algorithm */ +/* see: http://aspell.net/man-html/Phonetic-Code.html */ +/* convert string to uppercase before this call */ +std::string phonet(const std::string& inword, phonetable& parms) { + + int i, k = 0, p, z; + int k0, n0, p0 = -333, z0; + char c; + const char* s; + typedef unsigned char uchar; + + size_t len = inword.size(); + if (len > MAXPHONETUTF8LEN) + return std::string(); + char word[MAXPHONETUTF8LEN + 1]; + strncpy(word, inword.c_str(), MAXPHONETUTF8LEN); + word[MAXPHONETUTF8LEN] = '\0'; + + std::string target; + /** check word **/ + i = z = 0; + while ((c = word[i]) != '\0') { + int n = parms.hash[(uchar)c]; + z0 = 0; + + if (n >= 0) { + /** check all rules for the same letter **/ + while (parms.rules[n][0] == c) { + /** check whole string **/ + k = 1; /** number of found letters **/ + p = 5; /** default priority **/ + s = parms.rules[n]; + s++; /** important for (see below) "*(s-1)" **/ + + while (*s != '\0' && word[i + k] == *s && !isdigit((unsigned char)*s) && + strchr("(-<^$", *s) == NULL) { + k++; + s++; + } + if (*s == '(') { + /** check letters in "(..)" **/ + if (myisalpha(word[i + k]) // ...could be implied? + && strchr(s + 1, word[i + k]) != NULL) { + k++; + while (*s != ')') + s++; + s++; + } + } + p0 = (int)*s; + k0 = k; + while (*s == '-' && k > 1) { + k--; + s++; + } + if (*s == '<') + s++; + if (isdigit((unsigned char)*s)) { + /** determine priority **/ + p = *s - '0'; + s++; + } + if (*s == '^' && *(s + 1) == '^') + s++; + + if (*s == '\0' || (*s == '^' && (i == 0 || !myisalpha(word[i - 1])) && + (*(s + 1) != '$' || (!myisalpha(word[i + k0])))) || + (*s == '$' && i > 0 && myisalpha(word[i - 1]) && + (!myisalpha(word[i + k0])))) { + /** search for followup rules, if: **/ + /** parms.followup and k > 1 and NO '-' in searchstring **/ + char c0 = word[i + k - 1]; + n0 = parms.hash[(uchar)c0]; + + // if (parms.followup && k > 1 && n0 >= 0 + if (k > 1 && n0 >= 0 && p0 != (int)'-' && word[i + k] != '\0') { + /** test follow-up rule for "word[i+k]" **/ + while (parms.rules[n0][0] == c0) { + /** check whole string **/ + k0 = k; + p0 = 5; + s = parms.rules[n0]; + s++; + while (*s != '\0' && word[i + k0] == *s && + !isdigit((unsigned char)*s) && + strchr("(-<^$", *s) == NULL) { + k0++; + s++; + } + if (*s == '(') { + /** check letters **/ + if (myisalpha(word[i + k0]) && + strchr(s + 1, word[i + k0]) != NULL) { + k0++; + while (*s != ')' && *s != '\0') + s++; + if (*s == ')') + s++; + } + } + while (*s == '-') { + /** "k0" gets NOT reduced **/ + /** because "if (k0 == k)" **/ + s++; + } + if (*s == '<') + s++; + if (isdigit((unsigned char)*s)) { + p0 = *s - '0'; + s++; + } + + if (*s == '\0' + /** *s == '^' cuts **/ + || (*s == '$' && !myisalpha(word[i + k0]))) { + if (k0 == k) { + /** this is just a piece of the string **/ + n0 += 2; + continue; + } + + if (p0 < p) { + /** priority too low **/ + n0 += 2; + continue; + } + /** rule fits; stop search **/ + break; + } + n0 += 2; + } /** End of "while (parms.rules[n0][0] == c0)" **/ + + if (p0 >= p && parms.rules[n0][0] == c0) { + n += 2; + continue; + } + } /** end of follow-up stuff **/ + + /** replace string **/ + s = parms.rules[n + 1]; + p0 = (parms.rules[n][0] != '\0' && + strchr(parms.rules[n] + 1, '<') != NULL) + ? 1 + : 0; + if (p0 == 1 && z == 0) { + /** rule with '<' is used **/ + if (!target.empty() && *s != '\0' && + (target[target.size()-1] == c || target[target.size()-1] == *s)) { + target.erase(target.size() - 1); + } + z0 = 1; + z = 1; + k0 = 0; + while (*s != '\0' && word[i + k0] != '\0') { + word[i + k0] = *s; + k0++; + s++; + } + if (k > k0) + strmove(&word[0] + i + k0, &word[0] + i + k); + + /** new "actual letter" **/ + c = word[i]; + } else { /** no '<' rule used **/ + i += k - 1; + z = 0; + while (*s != '\0' && *(s + 1) != '\0' && target.size() < len) { + if (target.empty() || target[target.size()-1] != *s) { + target.push_back(*s); + } + s++; + } + /** new "actual letter" **/ + c = *s; + if (parms.rules[n][0] != '\0' && + strstr(parms.rules[n] + 1, "^^") != NULL) { + if (c != '\0') { + target.push_back(c); + } + strmove(&word[0], &word[0] + i + 1); + i = 0; + z0 = 1; + } + } + break; + } /** end of follow-up stuff **/ + n += 2; + } /** end of while (parms.rules[n][0] == c) **/ + } /** end of if (n >= 0) **/ + if (z0 == 0) { + if (k && !p0 && target.size() < len && c != '\0' && + (1 || target.empty() || target[target.size()-1] != c)) { + /** condense only double letters **/ + target.push_back(c); + /// printf("\n setting \n"); + } + + i++; + z = 0; + k = 0; + } + } /** end of while ((c = word[i]) != '\0') **/ + + return target; +} /** end of function "phonet" **/ diff --git a/extensions/spellcheck/hunspell/src/phonet.hxx b/extensions/spellcheck/hunspell/src/phonet.hxx new file mode 100644 index 000000000..eb9fd0c62 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/phonet.hxx @@ -0,0 +1,52 @@ +/* phonetic.c - generic replacement aglogithms for phonetic transformation + Copyright (C) 2000 Bjoern Jacke + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation; + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; If not, see + . + + Changelog: + + 2000-01-05 Bjoern Jacke + Initial Release insprired by the article about phonetic + transformations out of c't 25/1999 + + 2007-07-26 Bjoern Jacke + Released under MPL/GPL/LGPL tri-license for Hunspell + + 2007-08-23 Laszlo Nemeth + Porting from Aspell to Hunspell using C-like structs +*/ + +#ifndef __PHONETHXX__ +#define __PHONETHXX__ + +#define HASHSIZE 256 +#define MAXPHONETLEN 256 +#define MAXPHONETUTF8LEN (MAXPHONETLEN * 4) + +#include "hunvisapi.h" + +struct phonetable { + char utf8; + cs_info* lang; + int num; + char** rules; + int hash[HASHSIZE]; +}; + +LIBHUNSPELL_DLL_EXPORTED void init_phonet_hash(phonetable& parms); + +LIBHUNSPELL_DLL_EXPORTED std::string phonet(const std::string& inword, + phonetable& phone); + +#endif diff --git a/extensions/spellcheck/hunspell/src/replist.cxx b/extensions/spellcheck/hunspell/src/replist.cxx new file mode 100644 index 000000000..b3e6b37d2 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/replist.cxx @@ -0,0 +1,193 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "replist.hxx" +#include "csutil.hxx" + +RepList::RepList(int n) { + dat = (replentry**)malloc(sizeof(replentry*) * n); + if (dat == 0) + size = 0; + else + size = n; + pos = 0; +} + +RepList::~RepList() { + for (int i = 0; i < pos; i++) { + free(dat[i]->pattern); + free(dat[i]->pattern2); + free(dat[i]); + } + free(dat); +} + +int RepList::get_pos() { + return pos; +} + +replentry* RepList::item(int n) { + return dat[n]; +} + +int RepList::near(const char* word) { + int p1 = 0; + int p2 = pos; + while ((p2 - p1) > 1) { + int m = (p1 + p2) / 2; + int c = strcmp(word, dat[m]->pattern); + if (c <= 0) { + if (c < 0) + p2 = m; + else + p1 = p2 = m; + } else + p1 = m; + } + return p1; +} + +int RepList::match(const char* word, int n) { + if (strncmp(word, dat[n]->pattern, strlen(dat[n]->pattern)) == 0) + return strlen(dat[n]->pattern); + return 0; +} + +int RepList::add(char* pat1, char* pat2) { + if (pos >= size || pat1 == NULL || pat2 == NULL) + return 1; + replentry* r = (replentry*)malloc(sizeof(replentry)); + if (r == NULL) + return 1; + r->pattern = mystrrep(pat1, "_", " "); + r->pattern2 = mystrrep(pat2, "_", " "); + r->start = false; + r->end = false; + dat[pos++] = r; + for (int i = pos - 1; i > 0; i--) { + r = dat[i]; + if (strcmp(r->pattern, dat[i - 1]->pattern) < 0) { + dat[i] = dat[i - 1]; + dat[i - 1] = r; + } else + break; + } + return 0; +} + +int RepList::conv(const char* word, char* dest, size_t destsize) { + size_t stl = 0; + int change = 0; + for (size_t i = 0; i < strlen(word); i++) { + int n = near(word + i); + int l = match(word + i, n); + if (l) { + size_t replen = strlen(dat[n]->pattern2); + if (stl + replen >= destsize) + return -1; + strcpy(dest + stl, dat[n]->pattern2); + stl += replen; + i += l - 1; + change = 1; + } else { + if (stl + 1 >= destsize) + return -1; + dest[stl++] = word[i]; + } + } + dest[stl] = '\0'; + return change; +} + +bool RepList::conv(const char* word, std::string& dest) { + dest.clear(); + + bool change = false; + for (size_t i = 0; i < strlen(word); i++) { + int n = near(word + i); + int l = match(word + i, n); + if (l) { + dest.append(dat[n]->pattern2); + i += l - 1; + change = true; + } else { + dest.push_back(word[i]); + } + } + return change; +} diff --git a/extensions/spellcheck/hunspell/src/replist.hxx b/extensions/spellcheck/hunspell/src/replist.hxx new file mode 100644 index 000000000..0c5153625 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/replist.hxx @@ -0,0 +1,107 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* string replacement list class */ +#ifndef _REPLIST_HXX_ +#define _REPLIST_HXX_ + +#include "hunvisapi.h" + +#include "w_char.hxx" + +#include +#include + +class LIBHUNSPELL_DLL_EXPORTED RepList { + private: + RepList(const RepList&); + RepList& operator=(const RepList&); + + protected: + replentry** dat; + int size; + int pos; + + public: + RepList(int n); + ~RepList(); + + int get_pos(); + int add(char* pat1, char* pat2); + replentry* item(int n); + int near(const char* word); + int match(const char* word, int n); + int conv(const char* word, char* dest, size_t destsize); + bool conv(const char* word, std::string& dest); +}; +#endif diff --git a/extensions/spellcheck/hunspell/src/suggestmgr.cxx b/extensions/spellcheck/hunspell/src/suggestmgr.cxx new file mode 100644 index 000000000..17becd758 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/suggestmgr.cxx @@ -0,0 +1,2192 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "suggestmgr.hxx" +#include "htypes.hxx" +#include "csutil.hxx" + +const w_char W_VLINE = {'\0', '|'}; + +SuggestMgr::SuggestMgr(const char* tryme, int maxn, AffixMgr* aptr) { + // register affix manager and check in string of chars to + // try when building candidate suggestions + pAMgr = aptr; + + csconv = NULL; + + ckeyl = 0; + ckey = NULL; + ckey_utf = NULL; + + ctryl = 0; + ctry = NULL; + ctry_utf = NULL; + + utf8 = 0; + langnum = 0; + complexprefixes = 0; + + maxSug = maxn; + nosplitsugs = 0; + maxngramsugs = MAXNGRAMSUGS; + maxcpdsugs = MAXCOMPOUNDSUGS; + + if (pAMgr) { + langnum = pAMgr->get_langnum(); + ckey = pAMgr->get_key_string(); + nosplitsugs = pAMgr->get_nosplitsugs(); + if (pAMgr->get_maxngramsugs() >= 0) + maxngramsugs = pAMgr->get_maxngramsugs(); + utf8 = pAMgr->get_utf8(); + if (pAMgr->get_maxcpdsugs() >= 0) + maxcpdsugs = pAMgr->get_maxcpdsugs(); + if (!utf8) { + char* enc = pAMgr->get_encoding(); + csconv = get_current_cs(enc); + free(enc); + } + complexprefixes = pAMgr->get_complexprefixes(); + } + + if (ckey) { + if (utf8) { + std::vector t; + ckeyl = u8_u16(t, ckey); + ckey_utf = (w_char*)malloc(ckeyl * sizeof(w_char)); + if (ckey_utf) + memcpy(ckey_utf, &t[0], ckeyl * sizeof(w_char)); + else + ckeyl = 0; + } else { + ckeyl = strlen(ckey); + } + } + + if (tryme) { + ctry = mystrdup(tryme); + if (ctry) + ctryl = strlen(ctry); + if (ctry && utf8) { + std::vector t; + ctryl = u8_u16(t, tryme); + ctry_utf = (w_char*)malloc(ctryl * sizeof(w_char)); + if (ctry_utf) + memcpy(ctry_utf, &t[0], ctryl * sizeof(w_char)); + else + ctryl = 0; + } + } +} + +SuggestMgr::~SuggestMgr() { + pAMgr = NULL; + if (ckey) + free(ckey); + ckey = NULL; + if (ckey_utf) + free(ckey_utf); + ckey_utf = NULL; + ckeyl = 0; + if (ctry) + free(ctry); + ctry = NULL; + if (ctry_utf) + free(ctry_utf); + ctry_utf = NULL; + ctryl = 0; + maxSug = 0; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +int SuggestMgr::testsug(char** wlst, + const char* candidate, + int wl, + int ns, + int cpdsuggest, + int* timer, + clock_t* timelimit) { + int cwrd = 1; + if (ns == maxSug) + return maxSug; + for (int k = 0; k < ns; k++) { + if (strcmp(candidate, wlst[k]) == 0) { + cwrd = 0; + break; + } + } + if ((cwrd) && checkword(candidate, wl, cpdsuggest, timer, timelimit)) { + wlst[ns] = mystrdup(candidate); + if (wlst[ns] == NULL) { + for (int j = 0; j < ns; j++) + free(wlst[j]); + return -1; + } + ns++; + } + return ns; +} + +// generate suggestions for a misspelled word +// pass in address of array of char * pointers +// onlycompoundsug: probably bad suggestions (need for ngram sugs, too) + +int SuggestMgr::suggest(char*** slst, + const char* w, + int nsug, + int* onlycompoundsug) { + int nocompoundtwowords = 0; + char** wlst; + std::vector word_utf; + int wl = 0; + int nsugorig = nsug; + std::string w2; + const char* word = w; + int oldSug = 0; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + word = w2.c_str(); + } + + if (*slst) { + wlst = *slst; + } else { + wlst = (char**)malloc(maxSug * sizeof(char*)); + if (wlst == NULL) + return -1; + for (int i = 0; i < maxSug; i++) { + wlst[i] = NULL; + } + } + + if (utf8) { + wl = u8_u16(word_utf, word); + if (wl == -1) { + *slst = wlst; + return nsug; + } + } + + for (int cpdsuggest = 0; (cpdsuggest < 2) && (nocompoundtwowords == 0); + cpdsuggest++) { + // limit compound suggestion + if (cpdsuggest > 0) + oldSug = nsug; + + // suggestions for an uppercase word (html -> HTML) + if ((nsug < maxSug) && (nsug > -1)) { + nsug = (utf8) ? capchars_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : capchars(wlst, word, nsug, cpdsuggest); + } + + // perhaps we made a typical fault of spelling + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = replchars(wlst, word, nsug, cpdsuggest); + } + + // perhaps we made chose the wrong char from a related set + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = mapchars(wlst, word, nsug, cpdsuggest); + } + + // only suggest compound words when no other suggestion + if ((cpdsuggest == 0) && (nsug > nsugorig)) + nocompoundtwowords = 1; + + // did we swap the order of chars by mistake + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? swapchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : swapchar(wlst, word, nsug, cpdsuggest); + } + + // did we swap the order of non adjacent chars by mistake + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? longswapchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : longswapchar(wlst, word, nsug, cpdsuggest); + } + + // did we just hit the wrong key in place of a good char (case and keyboard) + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? badcharkey_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : badcharkey(wlst, word, nsug, cpdsuggest); + } + + // did we add a char that should not be there + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? extrachar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : extrachar(wlst, word, nsug, cpdsuggest); + } + + // did we forgot a char + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? forgotchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : forgotchar(wlst, word, nsug, cpdsuggest); + } + + // did we move a char + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? movechar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : movechar(wlst, word, nsug, cpdsuggest); + } + + // did we just hit the wrong key in place of a good char + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? badchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : badchar(wlst, word, nsug, cpdsuggest); + } + + // did we double two characters + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? doubletwochars_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : doubletwochars(wlst, word, nsug, cpdsuggest); + } + + // perhaps we forgot to hit space and two words ran together + if (!nosplitsugs && (nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = twowords(wlst, word, nsug, cpdsuggest); + } + + } // repeating ``for'' statement compounding support + + if (nsug < 0) { + // we ran out of memory - we should free up as much as possible + for (int i = 0; i < maxSug; i++) + if (wlst[i] != NULL) + free(wlst[i]); + free(wlst); + wlst = NULL; + } + + if (!nocompoundtwowords && (nsug > 0) && onlycompoundsug) + *onlycompoundsug = 1; + + *slst = wlst; + return nsug; +} + +// suggestions for an uppercase word (html -> HTML) +int SuggestMgr::capchars_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector candidate_utf(word, word + wl); + mkallcap_utf(candidate_utf, langnum); + std::string candidate; + u16_u8(candidate, candidate_utf); + return testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); +} + +// suggestions for an uppercase word (html -> HTML) +int SuggestMgr::capchars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + mkallcap(candidate, csconv); + return testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); +} + +// suggestions for when chose the wrong char out of a related set +int SuggestMgr::mapchars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate; + clock_t timelimit; + int timer; + + int wl = strlen(word); + if (wl < 2 || !pAMgr) + return ns; + + int nummap = pAMgr->get_nummap(); + struct mapentry* maptable = pAMgr->get_maptable(); + if (maptable == NULL) + return ns; + + timelimit = clock(); + timer = MINTIMER; + return map_related(word, candidate, 0, wlst, cpdsuggest, ns, + maptable, nummap, &timer, &timelimit); +} + +int SuggestMgr::map_related(const char* word, + std::string& candidate, + int wn, + char** wlst, + int cpdsuggest, + int ns, + const mapentry* maptable, + int nummap, + int* timer, + clock_t* timelimit) { + if (*(word + wn) == '\0') { + int cwrd = 1; + for (int m = 0; m < ns; m++) { + if (candidate == wlst[m]) { + cwrd = 0; + break; + } + } + if ((cwrd) && checkword(candidate.c_str(), candidate.size(), cpdsuggest, timer, timelimit)) { + if (ns < maxSug) { + wlst[ns] = mystrdup(candidate.c_str()); + if (wlst[ns] == NULL) + return -1; + ns++; + } + } + return ns; + } + int in_map = 0; + for (int j = 0; j < nummap; j++) { + for (int k = 0; k < maptable[j].len; k++) { + int len = strlen(maptable[j].set[k]); + if (strncmp(maptable[j].set[k], word + wn, len) == 0) { + in_map = 1; + size_t cn = candidate.size(); + for (int l = 0; l < maptable[j].len; l++) { + candidate.resize(cn); + candidate.append(maptable[j].set[l]); + ns = map_related(word, candidate, wn + len, wlst, + cpdsuggest, ns, maptable, nummap, timer, timelimit); + if (!(*timer)) + return ns; + } + } + } + } + if (!in_map) { + candidate.push_back(*(word + wn)); + ns = map_related(word, candidate, wn + 1, wlst, cpdsuggest, ns, + maptable, nummap, timer, timelimit); + } + return ns; +} + +// suggestions for a typical fault of spelling, that +// differs with more, than 1 letter from the right form. +int SuggestMgr::replchars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate; + int wl = strlen(word); + if (wl < 2 || !pAMgr) + return ns; + int numrep = pAMgr->get_numrep(); + struct replentry* reptable = pAMgr->get_reptable(); + if (reptable == NULL) + return ns; + for (int i = 0; i < numrep; i++) { + const char* r = word; + // search every occurence of the pattern in the word + while ((r = strstr(r, reptable[i].pattern)) != NULL && + (!reptable[i].end || strlen(r) == strlen(reptable[i].pattern)) && + (!reptable[i].start || r == word)) { + candidate.assign(word); + candidate.resize(r - word); + candidate.append(reptable[i].pattern2); + int lenp = strlen(reptable[i].pattern); + candidate.append(r + lenp); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + // check REP suggestions with space + size_t sp = candidate.find(' '); + if (sp != std::string::npos) { + size_t prev = 0; + while (sp != std::string::npos) { + std::string prev_chunk = candidate.substr(prev, sp - prev); + if (checkword(prev_chunk.c_str(), prev_chunk.size(), 0, NULL, NULL)) { + int oldns = ns; + std::string post_chunk = candidate.substr(sp + 1); + ns = testsug(wlst, post_chunk.c_str(), post_chunk.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + if (oldns < ns) { + free(wlst[ns - 1]); + wlst[ns - 1] = mystrdup(candidate.c_str()); + if (!wlst[ns - 1]) + return -1; + } + } + prev = sp + 1; + sp = candidate.find(' ', prev); + } + } + r++; // search for the next letter + } + } + return ns; +} + +// perhaps we doubled two characters (pattern aba -> ababa, for example vacation +// -> vacacation) +int SuggestMgr::doubletwochars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + int state = 0; + int wl = strlen(word); + if (wl < 5 || !pAMgr) + return ns; + for (int i = 2; i < wl; i++) { + if (word[i] == word[i - 2]) { + state++; + if (state == 3) { + std::string candidate(word, word + i - 1); + candidate.insert(candidate.end(), word + i + 1, word + wl); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + state = 0; + } + } else { + state = 0; + } + } + return ns; +} + +// perhaps we doubled two characters (pattern aba -> ababa, for example vacation +// -> vacacation) +int SuggestMgr::doubletwochars_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + int state = 0; + if (wl < 5 || !pAMgr) + return ns; + for (int i = 2; i < wl; i++) { + if (word[i] == word[i - 2]) { + state++; + if (state == 3) { + std::vector candidate_utf(word, word + i - 1); + candidate_utf.insert(candidate_utf.end(), word + i + 1, word + wl); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + state = 0; + } + } else { + state = 0; + } + } + return ns; +} + +// error is wrong char in place of correct one (case and keyboard related +// version) +int SuggestMgr::badcharkey(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + + // swap out each char one by one and try uppercase and neighbor + // keyboard chars in its place to see if that makes a good word + for (size_t i = 0; i < candidate.size(); ++i) { + char tmpc = candidate[i]; + // check with uppercase letters + candidate[i] = csconv[((unsigned char)tmpc)].cupper; + if (tmpc != candidate[i]) { + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + candidate[i] = tmpc; + } + // check neighbor characters in keyboard string + if (!ckey) + continue; + char* loc = strchr(ckey, tmpc); + while (loc) { + if ((loc > ckey) && (*(loc - 1) != '|')) { + candidate[i] = *(loc - 1); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + if ((*(loc + 1) != '|') && (*(loc + 1) != '\0')) { + candidate[i] = *(loc + 1); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + loc = strchr(loc + 1, tmpc); + } + candidate[i] = tmpc; + } + return ns; +} + +// error is wrong char in place of correct one (case and keyboard related +// version) +int SuggestMgr::badcharkey_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::string candidate; + std::vector candidate_utf(word, word + wl); + // swap out each char one by one and try all the tryme + // chars in its place to see if that makes a good word + for (int i = 0; i < wl; i++) { + w_char tmpc = candidate_utf[i]; + // check with uppercase letters + candidate_utf[i] = upper_utf(candidate_utf[i], 1); + if (tmpc != candidate_utf[i]) { + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + candidate_utf[i] = tmpc; + } + // check neighbor characters in keyboard string + if (!ckey) + continue; + w_char* loc = ckey_utf; + while ((loc < (ckey_utf + ckeyl)) && *loc != tmpc) + loc++; + while (loc < (ckey_utf + ckeyl)) { + if ((loc > ckey_utf) && *(loc - 1) != W_VLINE) { + candidate_utf[i] = *(loc - 1); + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + if (((loc + 1) < (ckey_utf + ckeyl)) && (*(loc + 1) != W_VLINE)) { + candidate_utf[i] = *(loc + 1); + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + do { + loc++; + } while ((loc < (ckey_utf + ckeyl)) && *loc != tmpc); + } + candidate_utf[i] = tmpc; + } + return ns; +} + +// error is wrong char in place of correct one +int SuggestMgr::badchar(char** wlst, const char* word, int ns, int cpdsuggest) { + std::string candidate(word); + clock_t timelimit = clock(); + int timer = MINTIMER; + // swap out each char one by one and try all the tryme + // chars in its place to see if that makes a good word + for (int j = 0; j < ctryl; j++) { + for (std::string::reverse_iterator aI = candidate.rbegin(), aEnd = candidate.rend(); aI != aEnd; ++aI) { + char tmpc = *aI; + if (ctry[j] == tmpc) + continue; + *aI = ctry[j]; + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + *aI = tmpc; + } + } + return ns; +} + +// error is wrong char in place of correct one +int SuggestMgr::badchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector candidate_utf(word, word + wl); + std::string candidate; + clock_t timelimit = clock(); + int timer = MINTIMER; + // swap out each char one by one and try all the tryme + // chars in its place to see if that makes a good word + for (int j = 0; j < ctryl; j++) { + for (int i = wl - 1; i >= 0; i--) { + w_char tmpc = candidate_utf[i]; + if (tmpc == ctry_utf[j]) + continue; + candidate_utf[i] = ctry_utf[j]; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, + &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + candidate_utf[i] = tmpc; + } + } + return ns; +} + +// error is word has an extra letter it does not need +int SuggestMgr::extrachar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector candidate_utf(word, word + wl); + if (candidate_utf.size() < 2) + return ns; + // try omitting one char of word at a time + for (size_t i = 0; i < candidate_utf.size(); ++i) { + size_t index = candidate_utf.size() - 1 - i; + w_char tmpc = candidate_utf[index]; + candidate_utf.erase(candidate_utf.begin() + index); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + candidate_utf.insert(candidate_utf.begin() + index, tmpc); + } + return ns; +} + +// error is word has an extra letter it does not need +int SuggestMgr::extrachar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + if (candidate.size() < 2) + return ns; + // try omitting one char of word at a time + for (size_t i = 0; i < candidate.size(); ++i) { + size_t index = candidate.size() - 1 - i; + char tmpc = candidate[index]; + candidate.erase(candidate.begin() + index); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + candidate.insert(candidate.begin() + index, tmpc); + } + return ns; +} + +// error is missing a letter it needs +int SuggestMgr::forgotchar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + clock_t timelimit = clock(); + int timer = MINTIMER; + + // try inserting a tryme character before every letter (and the null + // terminator) + for (int k = 0; k < ctryl; ++k) { + for (size_t i = 0; i <= candidate.size(); ++i) { + size_t index = candidate.size() - i; + candidate.insert(candidate.begin() + index, ctry[k]); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + candidate.erase(candidate.begin() + index); + } + } + return ns; +} + +// error is missing a letter it needs +int SuggestMgr::forgotchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector candidate_utf(word, word + wl); + clock_t timelimit = clock(); + int timer = MINTIMER; + + // try inserting a tryme character at the end of the word and before every + // letter + for (int k = 0; k < ctryl; ++k) { + for (size_t i = 0; i <= candidate_utf.size(); ++i) { + size_t index = candidate_utf.size() - i; + candidate_utf.insert(candidate_utf.begin() + index, ctry_utf[k]); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, + &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + candidate_utf.erase(candidate_utf.begin() + index); + } + } + return ns; +} + +/* error is should have been two words */ +int SuggestMgr::twowords(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + int c1, c2; + int forbidden = 0; + int cwrd; + + int wl = strlen(word); + if (wl < 3) + return ns; + + if (langnum == LANG_hu) + forbidden = check_forbidden(word, wl); + + char* candidate = (char*)malloc(wl + 2); + strcpy(candidate + 1, word); + + // split the string into two pieces after every char + // if both pieces are good words make them a suggestion + for (char* p = candidate + 1; p[1] != '\0'; p++) { + p[-1] = *p; + // go to end of the UTF-8 character + while (utf8 && ((p[1] & 0xc0) == 0x80)) { + *p = p[1]; + p++; + } + if (utf8 && p[1] == '\0') + break; // last UTF-8 character + *p = '\0'; + c1 = checkword(candidate, strlen(candidate), cpdsuggest, NULL, NULL); + if (c1) { + c2 = checkword((p + 1), strlen(p + 1), cpdsuggest, NULL, NULL); + if (c2) { + *p = ' '; + + // spec. Hungarian code (need a better compound word support) + if ((langnum == LANG_hu) && !forbidden && + // if 3 repeating letter, use - instead of space + (((p[-1] == p[1]) && + (((p > candidate + 1) && (p[-1] == p[-2])) || (p[-1] == p[2]))) || + // or multiple compounding, with more, than 6 syllables + ((c1 == 3) && (c2 >= 2)))) + *p = '-'; + + cwrd = 1; + for (int k = 0; k < ns; k++) { + if (strcmp(candidate, wlst[k]) == 0) { + cwrd = 0; + break; + } + } + if (ns < maxSug) { + if (cwrd) { + wlst[ns] = mystrdup(candidate); + if (wlst[ns] == NULL) { + free(candidate); + return -1; + } + ns++; + } + } else { + free(candidate); + return ns; + } + // add two word suggestion with dash, if TRY string contains + // "a" or "-" + // NOTE: cwrd doesn't modified for REP twoword sugg. + if (ctry && (strchr(ctry, 'a') || strchr(ctry, '-')) && + mystrlen(p + 1) > 1 && mystrlen(candidate) - mystrlen(p) > 1) { + *p = '-'; + for (int k = 0; k < ns; k++) { + if (strcmp(candidate, wlst[k]) == 0) { + cwrd = 0; + break; + } + } + if (ns < maxSug) { + if (cwrd) { + wlst[ns] = mystrdup(candidate); + if (wlst[ns] == NULL) { + free(candidate); + return -1; + } + ns++; + } + } else { + free(candidate); + return ns; + } + } + } + } + } + free(candidate); + return ns; +} + +// error is adjacent letter were swapped +int SuggestMgr::swapchar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + if (candidate.size() < 2) + return ns; + + // try swapping adjacent chars one by one + for (size_t i = 0; i < candidate.size() - 1; ++i) { + std::swap(candidate[i], candidate[i+1]); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + std::swap(candidate[i], candidate[i+1]); + } + + // try double swaps for short words + // ahev -> have, owudl -> would + if (candidate.size() == 4 || candidate.size() == 5) { + candidate[0] = word[1]; + candidate[1] = word[0]; + candidate[2] = word[2]; + candidate[candidate.size() - 2] = word[candidate.size() - 1]; + candidate[candidate.size() - 1] = word[candidate.size() - 2]; + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + if (candidate.size() == 5) { + candidate[0] = word[0]; + candidate[1] = word[2]; + candidate[2] = word[1]; + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + } + + return ns; +} + +// error is adjacent letter were swapped +int SuggestMgr::swapchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector candidate_utf(word, word + wl); + if (candidate_utf.size() < 2) + return ns; + + std::string candidate; + // try swapping adjacent chars one by one + for (size_t i = 0; i < candidate_utf.size() - 1; ++i) { + std::swap(candidate_utf[i], candidate_utf[i+1]); + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + std::swap(candidate_utf[i], candidate_utf[i+1]); + } + + // try double swaps for short words + // ahev -> have, owudl -> would, suodn -> sound + if (candidate_utf.size() == 4 || candidate_utf.size() == 5) { + candidate_utf[0] = word[1]; + candidate_utf[1] = word[0]; + candidate_utf[2] = word[2]; + candidate_utf[candidate_utf.size() - 2] = word[candidate_utf.size() - 1]; + candidate_utf[candidate_utf.size() - 1] = word[candidate_utf.size() - 2]; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + if (candidate_utf.size() == 5) { + candidate_utf[0] = word[0]; + candidate_utf[1] = word[2]; + candidate_utf[2] = word[1]; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + } + return ns; +} + +// error is not adjacent letter were swapped +int SuggestMgr::longswapchar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + // try swapping not adjacent chars one by one + for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) { + for (std::string::iterator q = candidate.begin(); q < candidate.end(); ++q) { + if (abs(std::distance(q, p)) > 1) { + std::swap(*p, *q); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + std::swap(*p, *q); + } + } + } + return ns; +} + +// error is adjacent letter were swapped +int SuggestMgr::longswapchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector candidate_utf(word, word + wl); + // try swapping not adjacent chars + for (std::vector::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { + for (std::vector::iterator q = candidate_utf.begin(); q < candidate_utf.end(); ++q) { + if (abs(std::distance(q, p)) > 1) { + std::swap(*p, *q); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + std::swap(*p, *q); + } + } + } + return ns; +} + +// error is a letter was moved +int SuggestMgr::movechar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + if (candidate.size() < 2) + return ns; + + // try moving a char + for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) { + for (std::string::iterator q = p + 1; q < candidate.end() && std::distance(p, q) < 10; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate.size(), candidate.begin()); + } + + for (std::string::reverse_iterator p = candidate.rbegin(), pEnd = candidate.rend() - 1; p != pEnd; ++p) { + for (std::string::reverse_iterator q = p + 1, qEnd = candidate.rend(); q != qEnd && std::distance(p, q) < 10; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate.size(), candidate.begin()); + } + + return ns; +} + +// error is a letter was moved +int SuggestMgr::movechar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector candidate_utf(word, word + wl); + if (candidate_utf.size() < 2) + return ns; + + // try moving a char + for (std::vector::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { + for (std::vector::iterator q = p + 1; q < candidate_utf.end() && std::distance(p, q) < 10; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate_utf.size(), candidate_utf.begin()); + } + + for (std::vector::iterator p = candidate_utf.begin() + candidate_utf.size() - 1; p > candidate_utf.begin(); --p) { + for (std::vector::iterator q = p - 1; q >= candidate_utf.begin() && std::distance(q, p) < 10; --q) { + std::swap(*q, *(q + 1)); + if (std::distance(q, p) < 2) + continue; // omit swap char + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate_utf.size(), candidate_utf.begin()); + } + + return ns; +} + +// generate a set of suggestions for very poorly spelled words +int SuggestMgr::ngsuggest(char** wlst, + const char* w, + int ns, + HashMgr** pHMgr, + int md) { + int i, j; + int lval; + int sc; + int lp, lpphon; + int nonbmp = 0; + + // exhaustively search through all root words + // keeping track of the MAX_ROOTS most similar root words + struct hentry* roots[MAX_ROOTS]; + char* rootsphon[MAX_ROOTS]; + int scores[MAX_ROOTS]; + int scoresphon[MAX_ROOTS]; + for (i = 0; i < MAX_ROOTS; i++) { + roots[i] = NULL; + scores[i] = -100 * i; + rootsphon[i] = NULL; + scoresphon[i] = -100 * i; + } + lp = MAX_ROOTS - 1; + lpphon = MAX_ROOTS - 1; + int low = NGRAM_LOWERING; + + std::string w2; + const char* word = w; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + word = w2.c_str(); + } + + std::vector u8; + int nc = strlen(word); + int n = (utf8) ? u8_u16(u8, word) : nc; + + // set character based ngram suggestion for words with non-BMP Unicode + // characters + if (n == -1) { + utf8 = 0; // XXX not state-free + n = nc; + nonbmp = 1; + low = 0; + } + + struct hentry* hp = NULL; + int col = -1; + phonetable* ph = (pAMgr) ? pAMgr->get_phonetable() : NULL; + std::string target; + std::string candidate; + if (ph) { + if (utf8) { + std::vector _w; + u8_u16(_w, word); + mkallcap_utf(_w, langnum); + u16_u8(candidate, _w); + } else { + candidate.assign(word); + if (!nonbmp) + mkallcap(candidate, csconv); + } + target = phonet(candidate, *ph); // XXX phonet() is 8-bit (nc, not n) + } + + FLAG forbiddenword = pAMgr ? pAMgr->get_forbiddenword() : FLAG_NULL; + FLAG nosuggest = pAMgr ? pAMgr->get_nosuggest() : FLAG_NULL; + FLAG nongramsuggest = pAMgr ? pAMgr->get_nongramsuggest() : FLAG_NULL; + FLAG onlyincompound = pAMgr ? pAMgr->get_onlyincompound() : FLAG_NULL; + + for (i = 0; i < md; i++) { + while (0 != (hp = (pHMgr[i])->walk_hashtable(col, hp))) { + if ((hp->astr) && (pAMgr) && + (TESTAFF(hp->astr, forbiddenword, hp->alen) || + TESTAFF(hp->astr, ONLYUPCASEFLAG, hp->alen) || + TESTAFF(hp->astr, nosuggest, hp->alen) || + TESTAFF(hp->astr, nongramsuggest, hp->alen) || + TESTAFF(hp->astr, onlyincompound, hp->alen))) + continue; + + sc = ngram(3, word, HENTRY_WORD(hp), NGRAM_LONGER_WORSE + low) + + leftcommonsubstring(word, HENTRY_WORD(hp)); + + // check special pronounciation + std::string f; + if ((hp->var & H_OPT_PHON) && + copy_field(f, HENTRY_DATA(hp), MORPH_PHON)) { + int sc2 = ngram(3, word, f, NGRAM_LONGER_WORSE + low) + + +leftcommonsubstring(word, f.c_str()); + if (sc2 > sc) + sc = sc2; + } + + int scphon = -20000; + if (ph && (sc > 2) && (abs(n - (int)hp->clen) <= 3)) { + if (utf8) { + std::vector _w; + u8_u16(_w, HENTRY_WORD(hp)); + mkallcap_utf(_w, langnum); + u16_u8(candidate, _w); + } else { + candidate.assign(HENTRY_WORD(hp)); + mkallcap(candidate, csconv); + } + std::string target2 = phonet(candidate, *ph); + scphon = 2 * ngram(3, target, target2, NGRAM_LONGER_WORSE); + } + + if (sc > scores[lp]) { + scores[lp] = sc; + roots[lp] = hp; + lval = sc; + for (j = 0; j < MAX_ROOTS; j++) + if (scores[j] < lval) { + lp = j; + lval = scores[j]; + } + } + + if (scphon > scoresphon[lpphon]) { + scoresphon[lpphon] = scphon; + rootsphon[lpphon] = HENTRY_WORD(hp); + lval = scphon; + for (j = 0; j < MAX_ROOTS; j++) + if (scoresphon[j] < lval) { + lpphon = j; + lval = scoresphon[j]; + } + } + } + } + + // find minimum threshold for a passable suggestion + // mangle original word three differnt ways + // and score them to generate a minimum acceptable score + int thresh = 0; + for (int sp = 1; sp < 4; sp++) { + if (utf8) { + for (int k = sp; k < n; k += 4) { + u8[k].l = '*'; + u8[k].h = 0; + } + std::string mw; + u16_u8(mw, u8); + thresh = thresh + ngram(n, word, mw, NGRAM_ANY_MISMATCH + low); + } else { + std::string mw(word); + for (int k = sp; k < n; k += 4) + mw[k] = '*'; + thresh = thresh + ngram(n, word, mw, NGRAM_ANY_MISMATCH + low); + } + } + thresh = thresh / 3; + thresh--; + + // now expand affixes on each of these root words and + // and use length adjusted ngram scores to select + // possible suggestions + char* guess[MAX_GUESS]; + char* guessorig[MAX_GUESS]; + int gscore[MAX_GUESS]; + for (i = 0; i < MAX_GUESS; i++) { + guess[i] = NULL; + guessorig[i] = NULL; + gscore[i] = -100 * i; + } + + lp = MAX_GUESS - 1; + + struct guessword* glst; + glst = (struct guessword*)calloc(MAX_WORDS, sizeof(struct guessword)); + if (!glst) { + if (nonbmp) + utf8 = 1; + return ns; + } + + for (i = 0; i < MAX_ROOTS; i++) { + if (roots[i]) { + struct hentry* rp = roots[i]; + + std::string f; + const char *field = NULL; + if ((rp->var & H_OPT_PHON) && copy_field(f, HENTRY_DATA(rp), MORPH_PHON)) + field = f.c_str(); + int nw = pAMgr->expand_rootword( + glst, MAX_WORDS, HENTRY_WORD(rp), rp->blen, rp->astr, rp->alen, word, + nc, field); + + for (int k = 0; k < nw; k++) { + sc = ngram(n, word, glst[k].word, NGRAM_ANY_MISMATCH + low) + + leftcommonsubstring(word, glst[k].word); + + if (sc > thresh) { + if (sc > gscore[lp]) { + if (guess[lp]) { + free(guess[lp]); + if (guessorig[lp]) { + free(guessorig[lp]); + guessorig[lp] = NULL; + } + } + gscore[lp] = sc; + guess[lp] = glst[k].word; + guessorig[lp] = glst[k].orig; + lval = sc; + for (j = 0; j < MAX_GUESS; j++) + if (gscore[j] < lval) { + lp = j; + lval = gscore[j]; + } + } else { + free(glst[k].word); + if (glst[k].orig) + free(glst[k].orig); + } + } else { + free(glst[k].word); + if (glst[k].orig) + free(glst[k].orig); + } + } + } + } + free(glst); + + // now we are done generating guesses + // sort in order of decreasing score + + bubblesort(&guess[0], &guessorig[0], &gscore[0], MAX_GUESS); + if (ph) + bubblesort(&rootsphon[0], NULL, &scoresphon[0], MAX_ROOTS); + + // weight suggestions with a similarity index, based on + // the longest common subsequent algorithm and resort + + int is_swap = 0; + int re = 0; + double fact = 1.0; + if (pAMgr) { + int maxd = pAMgr->get_maxdiff(); + if (maxd >= 0) + fact = (10.0 - maxd) / 5.0; + } + + for (i = 0; i < MAX_GUESS; i++) { + if (guess[i]) { + // lowering guess[i] + std::string gl; + int len; + if (utf8) { + std::vector _w; + len = u8_u16(_w, guess[i]); + mkallsmall_utf(_w, langnum); + u16_u8(gl, _w); + } else { + gl.assign(guess[i]); + if (!nonbmp) + mkallsmall(gl, csconv); + len = strlen(guess[i]); + } + + int _lcs = lcslen(word, gl.c_str()); + + // same characters with different casing + if ((n == len) && (n == _lcs)) { + gscore[i] += 2000; + break; + } + // using 2-gram instead of 3, and other weightening + + re = ngram(2, word, gl, NGRAM_ANY_MISMATCH + low + NGRAM_WEIGHTED) + + ngram(2, gl, word, NGRAM_ANY_MISMATCH + low + NGRAM_WEIGHTED); + + gscore[i] = + // length of longest common subsequent minus length difference + 2 * _lcs - abs((int)(n - len)) + + // weight length of the left common substring + leftcommonsubstring(word, gl.c_str()) + + // weight equal character positions + (!nonbmp && commoncharacterpositions(word, gl.c_str(), &is_swap) + ? 1 + : 0) + + // swap character (not neighboring) + ((is_swap) ? 10 : 0) + + // ngram + ngram(4, word, gl, NGRAM_ANY_MISMATCH + low) + + // weighted ngrams + re + + // different limit for dictionaries with PHONE rules + (ph ? (re < len * fact ? -1000 : 0) + : (re < (n + len) * fact ? -1000 : 0)); + } + } + + bubblesort(&guess[0], &guessorig[0], &gscore[0], MAX_GUESS); + + // phonetic version + if (ph) + for (i = 0; i < MAX_ROOTS; i++) { + if (rootsphon[i]) { + // lowering rootphon[i] + std::string gl; + int len; + if (utf8) { + std::vector _w; + len = u8_u16(_w, rootsphon[i]); + mkallsmall_utf(_w, langnum); + u16_u8(gl, _w); + } else { + gl.assign(rootsphon[i]); + if (!nonbmp) + mkallsmall(gl, csconv); + len = strlen(rootsphon[i]); + } + + // heuristic weigthing of ngram scores + scoresphon[i] += 2 * lcslen(word, gl) - abs((int)(n - len)) + + // weight length of the left common substring + leftcommonsubstring(word, gl.c_str()); + } + } + + if (ph) + bubblesort(&rootsphon[0], NULL, &scoresphon[0], MAX_ROOTS); + + // copy over + int oldns = ns; + + int same = 0; + for (i = 0; i < MAX_GUESS; i++) { + if (guess[i]) { + if ((ns < oldns + maxngramsugs) && (ns < maxSug) && + (!same || (gscore[i] > 1000))) { + int unique = 1; + // leave only excellent suggestions, if exists + if (gscore[i] > 1000) + same = 1; + else if (gscore[i] < -100) { + same = 1; + // keep the best ngram suggestions, unless in ONLYMAXDIFF mode + if (ns > oldns || (pAMgr && pAMgr->get_onlymaxdiff())) { + free(guess[i]); + if (guessorig[i]) + free(guessorig[i]); + continue; + } + } + for (j = 0; j < ns; j++) { + // don't suggest previous suggestions or a previous suggestion with + // prefixes or affixes + if ((!guessorig[i] && strstr(guess[i], wlst[j])) || + (guessorig[i] && strstr(guessorig[i], wlst[j])) || + // check forbidden words + !checkword(guess[i], strlen(guess[i]), 0, NULL, NULL)) { + unique = 0; + break; + } + } + if (unique) { + wlst[ns++] = guess[i]; + if (guessorig[i]) { + free(guess[i]); + wlst[ns - 1] = guessorig[i]; + } + } else { + free(guess[i]); + if (guessorig[i]) + free(guessorig[i]); + } + } else { + free(guess[i]); + if (guessorig[i]) + free(guessorig[i]); + } + } + } + + oldns = ns; + if (ph) + for (i = 0; i < MAX_ROOTS; i++) { + if (rootsphon[i]) { + if ((ns < oldns + MAXPHONSUGS) && (ns < maxSug)) { + int unique = 1; + for (j = 0; j < ns; j++) { + // don't suggest previous suggestions or a previous suggestion with + // prefixes or affixes + if (strstr(rootsphon[i], wlst[j]) || + // check forbidden words + !checkword(rootsphon[i], strlen(rootsphon[i]), 0, NULL, NULL)) { + unique = 0; + break; + } + } + if (unique) { + wlst[ns++] = mystrdup(rootsphon[i]); + if (!wlst[ns - 1]) + return ns - 1; + } + } + } + } + + if (nonbmp) + utf8 = 1; + return ns; +} + +// see if a candidate suggestion is spelled correctly +// needs to check both root words and words with affixes + +// obsolote MySpell-HU modifications: +// return value 2 and 3 marks compounding with hyphen (-) +// `3' marks roots without suffix +int SuggestMgr::checkword(const char* word, + int len, + int cpdsuggest, + int* timer, + clock_t* timelimit) { + struct hentry* rv = NULL; + struct hentry* rv2 = NULL; + int nosuffix = 0; + + // check time limit + if (timer) { + (*timer)--; + if (!(*timer) && timelimit) { + if ((clock() - *timelimit) > TIMELIMIT) + return 0; + *timer = MAXPLUSTIMER; + } + } + + if (pAMgr) { + if (cpdsuggest == 1) { + if (pAMgr->get_compound()) { + struct hentry* rwords[100]; // buffer for COMPOUND pattern checking + rv = pAMgr->compound_check(word, len, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 1, + 0); // EXT + if (rv && + (!(rv2 = pAMgr->lookup(word)) || !rv2->astr || + !(TESTAFF(rv2->astr, pAMgr->get_forbiddenword(), rv2->alen) || + TESTAFF(rv2->astr, pAMgr->get_nosuggest(), rv2->alen)))) + return 3; // XXX obsolote categorisation + only ICONV needs affix + // flag check? + } + return 0; + } + + rv = pAMgr->lookup(word); + + if (rv) { + if ((rv->astr) && + (TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen))) + return 0; + while (rv) { + if (rv->astr && + (TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) { + rv = rv->next_homonym; + } else + break; + } + } else + rv = pAMgr->prefix_check(word, len, + 0); // only prefix, and prefix + suffix XXX + + if (rv) { + nosuffix = 1; + } else { + rv = pAMgr->suffix_check(word, len, 0, NULL, NULL, 0, + NULL); // only suffix + } + + if (!rv && pAMgr->have_contclass()) { + rv = pAMgr->suffix_check_twosfx(word, len, 0, NULL, FLAG_NULL); + if (!rv) + rv = pAMgr->prefix_check_twosfx(word, len, 1, FLAG_NULL); + } + + // check forbidden words + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) + return 0; + + if (rv) { // XXX obsolote + if ((pAMgr->get_compoundflag()) && + TESTAFF(rv->astr, pAMgr->get_compoundflag(), rv->alen)) + return 2 + nosuffix; + return 1; + } + } + return 0; +} + +int SuggestMgr::check_forbidden(const char* word, int len) { + struct hentry* rv = NULL; + + if (pAMgr) { + rv = pAMgr->lookup(word); + if (rv && rv->astr && + (TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) + rv = NULL; + if (!(pAMgr->prefix_check(word, len, 1))) + rv = pAMgr->suffix_check(word, len, 0, NULL, NULL, 0, + NULL); // prefix+suffix, suffix + // check forbidden words + if ((rv) && (rv->astr) && + TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen)) + return 1; + } + return 0; +} + +char* SuggestMgr::suggest_morph(const char* w) { + char result[MAXLNLEN]; + char* r = (char*)result; + char* st; + + struct hentry* rv = NULL; + + *result = '\0'; + + if (!pAMgr) + return NULL; + + std::string w2; + const char* word = w; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + word = w2.c_str(); + } + + rv = pAMgr->lookup(word); + + while (rv) { + if ((!rv->astr) || + !(TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) { + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_STEM, MAXLNLEN); + mystrcat(result, word, MAXLNLEN); + } + if (HENTRY_DATA(rv)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + } + mystrcat(result, "\n", MAXLNLEN); + } + rv = rv->next_homonym; + } + + st = pAMgr->affix_check_morph(word, strlen(word)); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + if (pAMgr->get_compound() && (*result == '\0')) { + struct hentry* rwords[100]; // buffer for COMPOUND pattern checking + pAMgr->compound_check_morph(word, strlen(word), 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, &r, + NULL); + } + + return (*result) ? mystrdup(line_uniq(result, MSEP_REC)) : NULL; +} + +/* affixation */ +char* SuggestMgr::suggest_hentry_gen(hentry* rv, const char* pattern) { + char result[MAXLNLEN]; + *result = '\0'; + int sfxcount = get_sfxcount(pattern); + + if (get_sfxcount(HENTRY_DATA(rv)) > sfxcount) + return NULL; + + if (HENTRY_DATA(rv)) { + char* aff = pAMgr->morphgen(HENTRY_WORD(rv), rv->blen, rv->astr, rv->alen, + HENTRY_DATA(rv), pattern, 0); + if (aff) { + mystrcat(result, aff, MAXLNLEN); + mystrcat(result, "\n", MAXLNLEN); + free(aff); + } + } + + // check all allomorphs + char allomorph[MAXLNLEN]; + char* p = NULL; + if (HENTRY_DATA(rv)) + p = (char*)strstr(HENTRY_DATA2(rv), MORPH_ALLOMORPH); + while (p) { + struct hentry* rv2 = NULL; + p += MORPH_TAG_LEN; + int plen = fieldlen(p); + strncpy(allomorph, p, plen); + allomorph[plen] = '\0'; + rv2 = pAMgr->lookup(allomorph); + while (rv2) { + // if (HENTRY_DATA(rv2) && get_sfxcount(HENTRY_DATA(rv2)) <= + // sfxcount) { + if (HENTRY_DATA(rv2)) { + char* st = (char*)strstr(HENTRY_DATA2(rv2), MORPH_STEM); + if (st && (strncmp(st + MORPH_TAG_LEN, HENTRY_WORD(rv), + fieldlen(st + MORPH_TAG_LEN)) == 0)) { + char* aff = pAMgr->morphgen(HENTRY_WORD(rv2), rv2->blen, rv2->astr, + rv2->alen, HENTRY_DATA(rv2), pattern, 0); + if (aff) { + mystrcat(result, aff, MAXLNLEN); + mystrcat(result, "\n", MAXLNLEN); + free(aff); + } + } + } + rv2 = rv2->next_homonym; + } + p = strstr(p + plen, MORPH_ALLOMORPH); + } + + return (*result) ? mystrdup(result) : NULL; +} + +char* SuggestMgr::suggest_gen(char** desc, int n, const char* pattern) { + if (n == 0 || !pAMgr) + return NULL; + + std::string result2; + std::string newpattern; + struct hentry* rv = NULL; + + // search affixed forms with and without derivational suffixes + while (1) { + for (int k = 0; k < n; k++) { + std::string result; + + // add compound word parts (except the last one) + char* s = (char*)desc[k]; + char* part = strstr(s, MORPH_PART); + if (part) { + char* nextpart = strstr(part + 1, MORPH_PART); + while (nextpart) { + std::string field; + copy_field(field, part, MORPH_PART); + result.append(field); + part = nextpart; + nextpart = strstr(part + 1, MORPH_PART); + } + s = part; + } + + char** pl; + std::string tok(s); + size_t pos = tok.find(" | "); + while (pos != std::string::npos) { + tok[pos + 1] = MSEP_ALT; + pos = tok.find(" | ", pos); + } + int pln = line_tok(tok.c_str(), &pl, MSEP_ALT); + for (int i = 0; i < pln; i++) { + // remove inflectional and terminal suffixes + char* is = strstr(pl[i], MORPH_INFL_SFX); + if (is) + *is = '\0'; + char* ts = strstr(pl[i], MORPH_TERM_SFX); + while (ts) { + *ts = '_'; + ts = strstr(pl[i], MORPH_TERM_SFX); + } + char* st = strstr(s, MORPH_STEM); + if (st) { + copy_field(tok, st, MORPH_STEM); + rv = pAMgr->lookup(tok.c_str()); + while (rv) { + std::string newpat(pl[i]); + newpat.append(pattern); + char* sg = suggest_hentry_gen(rv, newpat.c_str()); + if (!sg) + sg = suggest_hentry_gen(rv, pattern); + if (sg) { + char** gen; + int genl = line_tok(sg, &gen, MSEP_REC); + free(sg); + sg = NULL; + for (int j = 0; j < genl; j++) { + result2.push_back(MSEP_REC); + result2.append(result); + if (strstr(pl[i], MORPH_SURF_PFX)) { + std::string field; + copy_field(field, pl[i], MORPH_SURF_PFX); + result2.append(field); + } + result2.append(gen[j]); + } + freelist(&gen, genl); + } + rv = rv->next_homonym; + } + } + } + freelist(&pl, pln); + } + + if (!result2.empty() || !strstr(pattern, MORPH_DERI_SFX)) + break; + + newpattern.assign(pattern); + mystrrep(newpattern, MORPH_DERI_SFX, MORPH_TERM_SFX); + pattern = newpattern.c_str(); + } + return (!result2.empty() ? mystrdup(result2.c_str()) : NULL); +} + +// generate an n-gram score comparing s1 and s2 +int SuggestMgr::ngram(int n, + const std::string& s1, + const std::string& s2, + int opt) { + int nscore = 0; + int ns; + int l1; + int l2; + int test = 0; + + if (utf8) { + std::vector su1; + std::vector su2; + l1 = u8_u16(su1, s1); + l2 = u8_u16(su2, s2); + if ((l2 <= 0) || (l1 == -1)) + return 0; + // lowering dictionary word + if (opt & NGRAM_LOWERING) + mkallsmall_utf(su2, langnum); + for (int j = 1; j <= n; j++) { + ns = 0; + for (int i = 0; i <= (l1 - j); i++) { + int k = 0; + for (int l = 0; l <= (l2 - j); l++) { + for (k = 0; k < j; k++) { + w_char& c1 = su1[i + k]; + w_char& c2 = su2[l + k]; + if ((c1.l != c2.l) || (c1.h != c2.h)) + break; + } + if (k == j) { + ns++; + break; + } + } + if (k != j && opt & NGRAM_WEIGHTED) { + ns--; + test++; + if (i == 0 || i == l1 - j) + ns--; // side weight + } + } + nscore = nscore + ns; + if (ns < 2 && !(opt & NGRAM_WEIGHTED)) + break; + } + } else { + l2 = s2.size(); + if (l2 == 0) + return 0; + l1 = s1.size(); + std::string t(s2); + if (opt & NGRAM_LOWERING) + mkallsmall(t, csconv); + for (int j = 1; j <= n; j++) { + ns = 0; + for (int i = 0; i <= (l1 - j); i++) { + std::string temp(s1.substr(i, j)); + if (t.find(temp) != std::string::npos) { + ns++; + } else if (opt & NGRAM_WEIGHTED) { + ns--; + test++; + if (i == 0 || i == l1 - j) + ns--; // side weight + } + } + nscore = nscore + ns; + if (ns < 2 && !(opt & NGRAM_WEIGHTED)) + break; + } + } + + ns = 0; + if (opt & NGRAM_LONGER_WORSE) + ns = (l2 - l1) - 2; + if (opt & NGRAM_ANY_MISMATCH) + ns = abs(l2 - l1) - 2; + ns = (nscore - ((ns > 0) ? ns : 0)); + return ns; +} + +// length of the left common substring of s1 and (decapitalised) s2 +int SuggestMgr::leftcommonsubstring(const char* s1, const char* s2) { + if (utf8) { + std::vector su1; + std::vector su2; + int l1 = u8_u16(su1, s1); + int l2 = u8_u16(su2, s2); + // decapitalize dictionary word + if (complexprefixes) { + if (su1[l1 - 1] == su2[l2 - 1]) + return 1; + } else { + unsigned short idx = su2.empty() ? 0 : (su2[0].h << 8) + su2[0].l; + unsigned short otheridx = su1.empty() ? 0 : (su1[0].h << 8) + su1[0].l; + if (otheridx != idx && (otheridx != unicodetolower(idx, langnum))) + return 0; + int i; + for (i = 1; (i < l1) && (i < l2) && (su1[i].l == su2[i].l) && + (su1[i].h == su2[i].h); + i++) + ; + return i; + } + } else { + if (complexprefixes) { + int l1 = strlen(s1); + int l2 = strlen(s2); + if (l1 <= l2 && s2[l1 - 1] == s2[l2 - 1]) + return 1; + } else if (csconv) { + const char* olds = s1; + // decapitalise dictionary word + if ((*s1 != *s2) && (*s1 != csconv[((unsigned char)*s2)].clower)) + return 0; + do { + s1++; + s2++; + } while ((*s1 == *s2) && (*s1 != '\0')); + return (int)(s1 - olds); + } + } + return 0; +} + +int SuggestMgr::commoncharacterpositions(const char* s1, + const char* s2, + int* is_swap) { + int num = 0; + int diff = 0; + int diffpos[2]; + *is_swap = 0; + if (utf8) { + std::vector su1; + std::vector su2; + int l1 = u8_u16(su1, s1); + int l2 = u8_u16(su2, s2); + + if (l1 <= 0 || l2 <= 0) + return 0; + + // decapitalize dictionary word + if (complexprefixes) { + su2[l2 - 1] = lower_utf(su2[l2 - 1], langnum); + } else { + su2[0] = lower_utf(su2[0], langnum); + } + for (int i = 0; (i < l1) && (i < l2); i++) { + if (su1[i] == su2[i]) { + num++; + } else { + if (diff < 2) + diffpos[diff] = i; + diff++; + } + } + if ((diff == 2) && (l1 == l2) && + (su1[diffpos[0]] == su2[diffpos[1]]) && + (su1[diffpos[1]] == su2[diffpos[0]])) + *is_swap = 1; + } else { + size_t i; + std::string t(s2); + // decapitalize dictionary word + if (complexprefixes) { + size_t l2 = t.size(); + t[l2 - 1] = csconv[(unsigned char)t[l2 - 1]].clower; + } else { + mkallsmall(t, csconv); + } + for (i = 0; (*(s1 + i) != 0) && i < t.size(); i++) { + if (*(s1 + i) == t[i]) { + num++; + } else { + if (diff < 2) + diffpos[diff] = i; + diff++; + } + } + if ((diff == 2) && (*(s1 + i) == 0) && i == t.size() && + (*(s1 + diffpos[0]) == t[diffpos[1]]) && + (*(s1 + diffpos[1]) == t[diffpos[0]])) + *is_swap = 1; + } + return num; +} + +int SuggestMgr::mystrlen(const char* word) { + if (utf8) { + std::vector w; + return u8_u16(w, word); + } else + return strlen(word); +} + +// sort in decreasing order of score +void SuggestMgr::bubblesort(char** rword, char** rword2, int* rsc, int n) { + int m = 1; + while (m < n) { + int j = m; + while (j > 0) { + if (rsc[j - 1] < rsc[j]) { + int sctmp = rsc[j - 1]; + char* wdtmp = rword[j - 1]; + rsc[j - 1] = rsc[j]; + rword[j - 1] = rword[j]; + rsc[j] = sctmp; + rword[j] = wdtmp; + if (rword2) { + wdtmp = rword2[j - 1]; + rword2[j - 1] = rword2[j]; + rword2[j] = wdtmp; + } + j--; + } else + break; + } + m++; + } + return; +} + +// longest common subsequence +void SuggestMgr::lcs(const char* s, + const char* s2, + int* l1, + int* l2, + char** result) { + int n, m; + std::vector su; + std::vector su2; + char* b; + char* c; + int i; + int j; + if (utf8) { + m = u8_u16(su, s); + n = u8_u16(su2, s2); + } else { + m = strlen(s); + n = strlen(s2); + } + c = (char*)malloc((m + 1) * (n + 1)); + b = (char*)malloc((m + 1) * (n + 1)); + if (!c || !b) { + if (c) + free(c); + if (b) + free(b); + *result = NULL; + return; + } + for (i = 1; i <= m; i++) + c[i * (n + 1)] = 0; + for (j = 0; j <= n; j++) + c[j] = 0; + for (i = 1; i <= m; i++) { + for (j = 1; j <= n; j++) { + if (((utf8) && (su[i - 1] == su2[j - 1])) || + ((!utf8) && (s[i - 1] == s2[j - 1]))) { + c[i * (n + 1) + j] = c[(i - 1) * (n + 1) + j - 1] + 1; + b[i * (n + 1) + j] = LCS_UPLEFT; + } else if (c[(i - 1) * (n + 1) + j] >= c[i * (n + 1) + j - 1]) { + c[i * (n + 1) + j] = c[(i - 1) * (n + 1) + j]; + b[i * (n + 1) + j] = LCS_UP; + } else { + c[i * (n + 1) + j] = c[i * (n + 1) + j - 1]; + b[i * (n + 1) + j] = LCS_LEFT; + } + } + } + *result = b; + free(c); + *l1 = m; + *l2 = n; +} + +int SuggestMgr::lcslen(const char* s, const char* s2) { + int m; + int n; + int i; + int j; + char* result; + int len = 0; + lcs(s, s2, &m, &n, &result); + if (!result) + return 0; + i = m; + j = n; + while ((i != 0) && (j != 0)) { + if (result[i * (n + 1) + j] == LCS_UPLEFT) { + len++; + i--; + j--; + } else if (result[i * (n + 1) + j] == LCS_UP) { + i--; + } else + j--; + } + free(result); + return len; +} + +int SuggestMgr::lcslen(const std::string& s, const std::string& s2) { + return lcslen(s.c_str(), s2.c_str()); +} diff --git a/extensions/spellcheck/hunspell/src/suggestmgr.hxx b/extensions/spellcheck/hunspell/src/suggestmgr.hxx new file mode 100644 index 000000000..675d98eb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/suggestmgr.hxx @@ -0,0 +1,198 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SUGGESTMGR_HXX_ +#define _SUGGESTMGR_HXX_ + +#define MAX_ROOTS 100 +#define MAX_WORDS 100 +#define MAX_GUESS 200 +#define MAXNGRAMSUGS 4 +#define MAXPHONSUGS 2 +#define MAXCOMPOUNDSUGS 3 + +// timelimit: max ~1/4 sec (process time on Linux) for a time consuming function +#define TIMELIMIT (CLOCKS_PER_SEC >> 2) +#define MINTIMER 100 +#define MAXPLUSTIMER 100 + +#define NGRAM_LONGER_WORSE (1 << 0) +#define NGRAM_ANY_MISMATCH (1 << 1) +#define NGRAM_LOWERING (1 << 2) +#define NGRAM_WEIGHTED (1 << 3) + +#include "hunvisapi.h" + +#include "atypes.hxx" +#include "affixmgr.hxx" +#include "hashmgr.hxx" +#include "langnum.hxx" +#include + +enum { LCS_UP, LCS_LEFT, LCS_UPLEFT }; + +class LIBHUNSPELL_DLL_EXPORTED SuggestMgr { + private: + SuggestMgr(const SuggestMgr&); + SuggestMgr& operator=(const SuggestMgr&); + + private: + char* ckey; + int ckeyl; + w_char* ckey_utf; + + char* ctry; + int ctryl; + w_char* ctry_utf; + + AffixMgr* pAMgr; + int maxSug; + struct cs_info* csconv; + int utf8; + int langnum; + int nosplitsugs; + int maxngramsugs; + int maxcpdsugs; + int complexprefixes; + + public: + SuggestMgr(const char* tryme, int maxn, AffixMgr* aptr); + ~SuggestMgr(); + + int suggest(char*** slst, const char* word, int nsug, int* onlycmpdsug); + int ngsuggest(char** wlst, const char* word, int ns, HashMgr** pHMgr, int md); + int suggest_auto(char*** slst, const char* word, int nsug); + int suggest_stems(char*** slst, const char* word, int nsug); + int suggest_pos_stems(char*** slst, const char* word, int nsug); + + char* suggest_morph(const char* word); + char* suggest_gen(char** pl, int pln, const char* pattern); + char* suggest_morph_for_spelling_error(const char* word); + + private: + int testsug(char** wlst, + const char* candidate, + int wl, + int ns, + int cpdsuggest, + int* timer, + clock_t* timelimit); + int checkword(const char*, int, int, int*, clock_t*); + int check_forbidden(const char*, int); + + int capchars(char**, const char*, int, int); + int replchars(char**, const char*, int, int); + int doubletwochars(char**, const char*, int, int); + int forgotchar(char**, const char*, int, int); + int swapchar(char**, const char*, int, int); + int longswapchar(char**, const char*, int, int); + int movechar(char**, const char*, int, int); + int extrachar(char**, const char*, int, int); + int badcharkey(char**, const char*, int, int); + int badchar(char**, const char*, int, int); + int twowords(char**, const char*, int, int); + int fixstems(char**, const char*, int); + + int capchars_utf(char**, const w_char*, int wl, int, int); + int doubletwochars_utf(char**, const w_char*, int wl, int, int); + int forgotchar_utf(char**, const w_char*, int wl, int, int); + int extrachar_utf(char**, const w_char*, int wl, int, int); + int badcharkey_utf(char**, const w_char*, int wl, int, int); + int badchar_utf(char**, const w_char*, int wl, int, int); + int swapchar_utf(char**, const w_char*, int wl, int, int); + int longswapchar_utf(char**, const w_char*, int, int, int); + int movechar_utf(char**, const w_char*, int, int, int); + + int mapchars(char**, const char*, int, int); + int map_related(const char*, + std::string&, + int, + char** wlst, + int, + int, + const mapentry*, + int, + int*, + clock_t*); + int ngram(int n, const std::string& s1, const std::string& s2, int opt); + int mystrlen(const char* word); + int leftcommonsubstring(const char* s1, const char* s2); + int commoncharacterpositions(const char* s1, const char* s2, int* is_swap); + void bubblesort(char** rwd, char** rwd2, int* rsc, int n); + void lcs(const char* s, const char* s2, int* l1, int* l2, char** result); + int lcslen(const char* s, const char* s2); + int lcslen(const std::string& s, const std::string& s2); + char* suggest_hentry_gen(hentry* rv, const char* pattern); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/w_char.hxx b/extensions/spellcheck/hunspell/src/w_char.hxx new file mode 100644 index 000000000..336c454f7 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/w_char.hxx @@ -0,0 +1,75 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __WCHARHXX__ +#define __WCHARHXX__ + +#ifndef GCC +struct w_char { +#else +struct __attribute__((packed)) w_char { +#endif + unsigned char l; + unsigned char h; + + friend bool operator<(const w_char a, const w_char b) { + unsigned short a_idx = (a.h << 8) + a.l; + unsigned short b_idx = (b.h << 8) + b.l; + return a_idx < b_idx; + } + + friend bool operator==(const w_char a, const w_char b) { + return (((a).l == (b).l) && ((a).h == (b).h)); + } + + friend bool operator!=(const w_char a, const w_char b) { + return !(a == b);; + } +}; + +// two character arrays +struct replentry { + char* pattern; + char* pattern2; + bool start; + bool end; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.aff new file mode 100644 index 000000000..0a11404fd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.aff @@ -0,0 +1,4 @@ +# capitalized ngram suggestion test data (Unicode version) for +# Sf.net Bug ID 1463589, reported by Frederik Fouvry. +SET UTF-8 +MAXNGRAMSUGS 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.dic new file mode 100644 index 000000000..8cec60603 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.dic @@ -0,0 +1,2 @@ +1 +Kühlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.sug b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.sug new file mode 100644 index 000000000..8a72f1e21 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.sug @@ -0,0 +1,5 @@ +Kühlschrank +Kühlschrank +Kühlschrank +Kühlschrank +Kühlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.wrong new file mode 100644 index 000000000..9de6c63cd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.wrong @@ -0,0 +1,5 @@ +kuhlschrank +kuehlschrank +kühlschrank +Kuhlschrank +Kuehlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.aff b/extensions/spellcheck/hunspell/tests/unit/data/1463589.aff new file mode 100644 index 000000000..8ecf4594e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.aff @@ -0,0 +1,3 @@ +# capitalized ngram suggestion test data for +# Sf.net Bug ID 1463589, reported by Frederik Fouvry. +MAXNGRAMSUGS 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.dic b/extensions/spellcheck/hunspell/tests/unit/data/1463589.dic new file mode 100644 index 000000000..a3caab802 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.dic @@ -0,0 +1,2 @@ +1 +Khlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.sug b/extensions/spellcheck/hunspell/tests/unit/data/1463589.sug new file mode 100644 index 000000000..2961eddd2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.sug @@ -0,0 +1,5 @@ +Khlschrank +Khlschrank +Khlschrank +Khlschrank +Khlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.test b/extensions/spellcheck/hunspell/tests/unit/data/1463589.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1463589.wrong new file mode 100644 index 000000000..0f3f48969 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.wrong @@ -0,0 +1,5 @@ +kuhlschrank +kuehlschrank +khlschrank +Kuhlschrank +Kuehlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.aff b/extensions/spellcheck/hunspell/tests/unit/data/1592880.aff new file mode 100644 index 000000000..0aa064e37 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.aff @@ -0,0 +1,20 @@ +# fix homonym handling for German dictionary project, +# reported by Björn Jacke (sf.net Bug ID 1592880). +SET ISO8859-1 + +SFX N Y 1 +SFX N 0 n . + +SFX S Y 1 +SFX S 0 s . + +SFX P Y 1 +SFX P 0 en . + +SFX Q Y 2 +SFX Q 0 e . +SFX Q 0 en . + +COMPOUNDEND z +COMPOUNDPERMITFLAG c +ONLYINCOMPOUND o diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.dic b/extensions/spellcheck/hunspell/tests/unit/data/1592880.dic new file mode 100644 index 000000000..8b0fef814 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.dic @@ -0,0 +1,4 @@ +3 +weg/Qoz +weg/P +wege diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.good b/extensions/spellcheck/hunspell/tests/unit/data/1592880.good new file mode 100644 index 000000000..aa00a58b1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.good @@ -0,0 +1,3 @@ +weg +wege +wegen diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.test b/extensions/spellcheck/hunspell/tests/unit/data/1592880.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.aff b/extensions/spellcheck/hunspell/tests/unit/data/1695964.aff new file mode 100644 index 000000000..359a25f3a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.aff @@ -0,0 +1,10 @@ +# fix NEEDAFFIX homonym suggestion. +# Sf.net Bug ID 1695964, reported by Björn Jacke. +TRY esianrtolcdugmphbyfvkwESIANRTOLCDUGMPHBYFVKW +MAXNGRAMSUGS 0 +NEEDAFFIX h +SFX S Y 1 +SFX S 0 s . + +SFX e Y 1 +SFX e 0 e . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.dic b/extensions/spellcheck/hunspell/tests/unit/data/1695964.dic new file mode 100644 index 000000000..ff6d110cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.dic @@ -0,0 +1,3 @@ +2 +Mull/he +Mull/S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.sug b/extensions/spellcheck/hunspell/tests/unit/data/1695964.sug new file mode 100644 index 000000000..35aedff7c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.sug @@ -0,0 +1,3 @@ +Mull +Mulle +Mulls diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.test b/extensions/spellcheck/hunspell/tests/unit/data/1695964.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1695964.wrong new file mode 100644 index 000000000..fd13dc8ca --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.wrong @@ -0,0 +1,3 @@ +Mall +Malle +Malls diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.aff b/extensions/spellcheck/hunspell/tests/unit/data/1706659.aff new file mode 100644 index 000000000..66a676efa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.aff @@ -0,0 +1,13 @@ +# test COMPOUNDRULE bug reported by Björn Jacke +SET ISO8859-1 +TRY esijanrtolcdugmphbyfvkwqxz + +SFX A Y 5 +SFX A 0 e . +SFX A 0 er . +SFX A 0 en . +SFX A 0 em . +SFX A 0 es . + +COMPOUNDRULE 1 +COMPOUNDRULE vw diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.dic b/extensions/spellcheck/hunspell/tests/unit/data/1706659.dic new file mode 100644 index 000000000..32d461f7a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.dic @@ -0,0 +1,4 @@ +3 +arbeits/v +scheu/Aw +farbig/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.test b/extensions/spellcheck/hunspell/tests/unit/data/1706659.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1706659.wrong new file mode 100644 index 000000000..799dd3111 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.wrong @@ -0,0 +1,3 @@ +arbeitsfarbig +arbeitsfarbige +arbeitsfarbiger diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.aff b/extensions/spellcheck/hunspell/tests/unit/data/1975530.aff new file mode 100644 index 000000000..0912050d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.aff @@ -0,0 +1,6 @@ +SET UTF-8 +IGNORE ٌٍَُِّْـ + +PFX x N 1 +PFX x أ ت أ[^ي] + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.dic b/extensions/spellcheck/hunspell/tests/unit/data/1975530.dic new file mode 100644 index 000000000..b1b455df5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.dic @@ -0,0 +1,3 @@ +2 +أرى/x +أيار/x diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.good b/extensions/spellcheck/hunspell/tests/unit/data/1975530.good new file mode 100644 index 000000000..89212a57e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.good @@ -0,0 +1,3 @@ +أرى +أيار +ترى diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.test b/extensions/spellcheck/hunspell/tests/unit/data/1975530.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1975530.wrong new file mode 100644 index 000000000..24cb57627 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.wrong @@ -0,0 +1 @@ +تيار diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.aff b/extensions/spellcheck/hunspell/tests/unit/data/2970240.aff new file mode 100644 index 000000000..6ef95161d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.aff @@ -0,0 +1,5 @@ +# test words with three parts +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN le fi +COMPOUNDFLAG c + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.dic b/extensions/spellcheck/hunspell/tests/unit/data/2970240.dic new file mode 100644 index 000000000..f0b630569 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.dic @@ -0,0 +1,4 @@ +3 +first/c +middle/c +last/c diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.good b/extensions/spellcheck/hunspell/tests/unit/data/2970240.good new file mode 100644 index 000000000..a8d3a593b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.good @@ -0,0 +1 @@ +firstmiddlelast diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.test b/extensions/spellcheck/hunspell/tests/unit/data/2970240.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.wrong b/extensions/spellcheck/hunspell/tests/unit/data/2970240.wrong new file mode 100644 index 000000000..32cead611 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.wrong @@ -0,0 +1 @@ +lastmiddlefirst diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.aff b/extensions/spellcheck/hunspell/tests/unit/data/2970242.aff new file mode 100644 index 000000000..909f0fbc3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.aff @@ -0,0 +1,4 @@ +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN /a /b +COMPOUNDFLAG c + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.dic b/extensions/spellcheck/hunspell/tests/unit/data/2970242.dic new file mode 100644 index 000000000..da0d05f92 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.dic @@ -0,0 +1,4 @@ +3 +foo/ac +bar/c +baz/bc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.good b/extensions/spellcheck/hunspell/tests/unit/data/2970242.good new file mode 100644 index 000000000..90ecb182f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.good @@ -0,0 +1,5 @@ +foobar +barfoo +bazfoo +barbaz +bazbar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.test b/extensions/spellcheck/hunspell/tests/unit/data/2970242.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.wrong b/extensions/spellcheck/hunspell/tests/unit/data/2970242.wrong new file mode 100644 index 000000000..9dabfec91 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.wrong @@ -0,0 +1 @@ +foobaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.aff b/extensions/spellcheck/hunspell/tests/unit/data/2999225.aff new file mode 100644 index 000000000..ea9d0b07b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.aff @@ -0,0 +1,6 @@ +COMPOUNDRULE 1 +COMPOUNDRULE ab + +COMPOUNDBEGIN A +COMPOUNDEND B + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.dic b/extensions/spellcheck/hunspell/tests/unit/data/2999225.dic new file mode 100644 index 000000000..249860362 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.dic @@ -0,0 +1,4 @@ +3 +foo/aA +bar/b +baz/B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.good b/extensions/spellcheck/hunspell/tests/unit/data/2999225.good new file mode 100644 index 000000000..865e15452 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.good @@ -0,0 +1,2 @@ +foobar +foobaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.test b/extensions/spellcheck/hunspell/tests/unit/data/2999225.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.aff b/extensions/spellcheck/hunspell/tests/unit/data/IJ.aff new file mode 100644 index 000000000..c817c2e91 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.aff @@ -0,0 +1,8 @@ +# check bad capitalisation of Dutch letter IJ. +TRY i +FORBIDDENWORD * +PFX i N 1 +PFX i ij IJ ij + +REP 1 +REP ij IJ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.dic b/extensions/spellcheck/hunspell/tests/unit/data/IJ.dic new file mode 100644 index 000000000..ecaf91d21 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.dic @@ -0,0 +1,3 @@ +1 +ijs/i +Ijs/* diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.good b/extensions/spellcheck/hunspell/tests/unit/data/IJ.good new file mode 100644 index 000000000..5f888f057 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.good @@ -0,0 +1,2 @@ +ijs +IJs diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.sug b/extensions/spellcheck/hunspell/tests/unit/data/IJ.sug new file mode 100644 index 000000000..582b7956b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.sug @@ -0,0 +1 @@ +IJs, ijs diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.test b/extensions/spellcheck/hunspell/tests/unit/data/IJ.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.wrong b/extensions/spellcheck/hunspell/tests/unit/data/IJ.wrong new file mode 100644 index 000000000..54bbb475a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.wrong @@ -0,0 +1 @@ +Ijs diff --git a/extensions/spellcheck/hunspell/tests/unit/data/Makefile.am b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.am new file mode 100644 index 000000000..8018ccf7b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.am @@ -0,0 +1,693 @@ +## Process this file with automake to create Makefile.in + +SUBDIRS = suggestiontest + +XFAIL_TESTS = @XFAILED@ + +TESTS = \ +affixes.test \ +condition.test \ +condition_utf.test \ +base.test \ +base_utf.test \ +allcaps.test \ +allcaps_utf.test \ +allcaps2.test \ +allcaps3.test \ +keepcase.test \ +i58202.test \ +map.test \ +rep.test \ +sug.test \ +sugutf.test \ +phone.test \ +flag.test \ +flaglong.test \ +flagnum.test \ +flagutf8.test \ +slash.test \ +forbiddenword.test \ +nosuggest.test \ +alias.test \ +alias2.test \ +alias3.test \ +breakdefault.test \ +break.test \ +needaffix.test \ +needaffix2.test \ +needaffix3.test \ +needaffix4.test \ +needaffix5.test \ +circumfix.test \ +fogemorpheme.test \ +onlyincompound.test \ +complexprefixes.test \ +complexprefixes2.test \ +complexprefixesutf.test \ +conditionalprefix.test \ +zeroaffix.test \ +utf8.test \ +utf8_bom.test \ +utf8_bom2.test \ +utf8_nonbmp.test \ +compoundflag.test \ +compoundrule.test \ +compoundrule2.test \ +compoundrule3.test \ +compoundrule4.test \ +compoundrule5.test \ +compoundrule6.test \ +compoundrule7.test \ +compoundrule8.test \ +compoundaffix.test \ +compoundaffix2.test \ +compoundaffix3.test \ +checkcompounddup.test \ +checkcompoundtriple.test \ +simplifiedtriple.test \ +checkcompoundrep.test \ +checkcompoundcase2.test \ +checkcompoundcaseutf.test \ +checkcompoundpattern.test \ +checkcompoundpattern2.test \ +checkcompoundpattern3.test \ +checkcompoundpattern4.test \ +utfcompound.test \ +checksharps.test \ +checksharpsutf.test \ +germancompounding.test \ +germancompoundingold.test \ +i35725.test \ +i53643.test \ +i54633.test \ +i54980.test \ +maputf.test \ +reputf.test \ +ignore.test \ +ignoreutf.test \ +1592880.test \ +1695964.test \ +1463589.test \ +1463589_utf.test \ +IJ.test \ +i68568.test \ +i68568utf.test \ +1706659.test \ +digits_in_words.test \ +colons_in_words.test \ +ngram_utf_fix.test \ +morph.test \ +1975530.test \ +fullstrip.test \ +iconv.test \ +oconv.test \ +encoding.test \ +korean.test \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword2.test \ +opentaal_keepcase.test \ +arabic.test \ +2970240.test \ +2970242.test \ +breakoff.test \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.test \ +2999225.test \ +onlyincompound2.test \ +forceucase.test \ +warn.test + +# infixes.test + +distclean-local: + -rm -rf testSubDir + +EXTRA_DIST = \ +test.sh \ +affixes.aff \ +affixes.dic \ +affixes.good \ +affixes.test \ +condition.aff \ +condition.dic \ +condition.good \ +condition.test \ +condition.wrong \ +condition_utf.aff \ +condition_utf.dic \ +condition_utf.good \ +condition_utf.test \ +condition_utf.wrong \ +base.aff \ +base.dic \ +base.good \ +base.sug \ +base.test \ +base.wrong \ +base_utf.aff \ +base_utf.dic \ +base_utf.good \ +base_utf.sug \ +base_utf.test \ +base_utf.wrong \ +allcaps.aff \ +allcaps.dic \ +allcaps.good \ +allcaps.sug \ +allcaps.test \ +allcaps.wrong \ +allcaps2.aff \ +allcaps2.dic \ +allcaps2.good \ +allcaps2.sug \ +allcaps2.test \ +allcaps2.wrong \ +allcaps3.aff \ +allcaps3.dic \ +allcaps3.good \ +allcaps3.test \ +allcaps3.wrong \ +allcaps_utf.aff \ +allcaps_utf.dic \ +allcaps_utf.good \ +allcaps_utf.sug \ +allcaps_utf.test \ +allcaps_utf.wrong \ +keepcase.aff \ +keepcase.dic \ +keepcase.good \ +keepcase.sug \ +keepcase.test \ +keepcase.wrong \ +map.aff \ +map.dic \ +map.sug \ +map.test \ +map.wrong \ +rep.aff \ +rep.dic \ +rep.sug \ +rep.test \ +rep.wrong \ +sug.aff \ +sug.dic \ +sug.sug \ +sug.test \ +sug.wrong \ +sugutf.aff \ +sugutf.dic \ +sugutf.sug \ +sugutf.test \ +sugutf.wrong \ +phone.aff \ +phone.dic \ +phone.sug \ +phone.test \ +phone.wrong \ +alias.aff \ +alias.dic \ +alias.good \ +alias.test \ +alias2.aff \ +alias2.dic \ +alias2.good \ +alias2.morph \ +alias2.test \ +alias3.aff \ +alias3.dic \ +alias3.good \ +alias3.morph \ +alias3.test \ +break.aff \ +break.dic \ +break.good \ +break.test \ +break.wrong \ +breakdefault.aff \ +breakdefault.dic \ +breakdefault.good \ +breakdefault.sug \ +breakdefault.test \ +breakdefault.wrong \ +circumfix.aff \ +circumfix.dic \ +circumfix.good \ +circumfix.morph \ +circumfix.test \ +circumfix.wrong \ +fogemorpheme.aff \ +fogemorpheme.dic \ +fogemorpheme.good \ +fogemorpheme.test \ +fogemorpheme.wrong \ +onlyincompound.aff \ +onlyincompound.dic \ +onlyincompound.good \ +onlyincompound.sug \ +onlyincompound.test \ +onlyincompound.wrong \ +forbiddenword.aff \ +forbiddenword.dic \ +forbiddenword.good \ +forbiddenword.test \ +forbiddenword.wrong \ +nosuggest.aff \ +nosuggest.dic \ +nosuggest.good \ +nosuggest.sug \ +nosuggest.test \ +nosuggest.wrong \ +germancompounding.aff \ +germancompounding.dic \ +germancompounding.good \ +germancompounding.test \ +germancompounding.wrong \ +germancompoundingold.aff \ +germancompoundingold.dic \ +germancompoundingold.good \ +germancompoundingold.test \ +germancompoundingold.wrong \ +needaffix2.aff \ +needaffix2.dic \ +needaffix2.good \ +needaffix2.morph \ +needaffix2.test \ +needaffix3.aff \ +needaffix3.dic \ +needaffix3.good \ +needaffix3.test \ +needaffix3.wrong \ +needaffix4.aff \ +needaffix4.dic \ +needaffix4.good \ +needaffix4.test \ +needaffix5.aff \ +needaffix5.dic \ +needaffix5.good \ +needaffix5.test \ +needaffix5.wrong \ +needaffix.aff \ +needaffix.dic \ +needaffix.good \ +needaffix.test \ +needaffix.wrong \ +zeroaffix.aff \ +zeroaffix.dic \ +zeroaffix.good \ +zeroaffix.morph \ +zeroaffix.test \ +utf8.aff \ +utf8.dic \ +utf8.good \ +utf8.test \ +utf8_bom.aff \ +utf8_bom.dic \ +utf8_bom.good \ +utf8_bom.test \ +utf8_bom2.aff \ +utf8_bom2.dic \ +utf8_bom2.good \ +utf8_bom2.test \ +utf8_nonbmp.aff \ +utf8_nonbmp.dic \ +utf8_nonbmp.good \ +utf8_nonbmp.sug \ +utf8_nonbmp.test \ +utf8_nonbmp.wrong \ +utfcompound.aff \ +utfcompound.dic \ +utfcompound.good \ +utfcompound.test \ +utfcompound.wrong \ +compoundflag.aff \ +compoundflag.dic \ +compoundflag.good \ +compoundflag.test \ +compoundflag.wrong \ +compoundrule.aff \ +compoundrule.dic \ +compoundrule.good \ +compoundrule.test \ +compoundrule.wrong \ +compoundrule2.aff \ +compoundrule2.dic \ +compoundrule2.good \ +compoundrule2.test \ +compoundrule2.wrong \ +compoundrule3.aff \ +compoundrule3.dic \ +compoundrule3.good \ +compoundrule3.test \ +compoundrule3.wrong \ +compoundrule4.aff \ +compoundrule4.dic \ +compoundrule4.good \ +compoundrule4.test \ +compoundrule4.wrong \ +compoundrule5.aff \ +compoundrule5.dic \ +compoundrule5.good \ +compoundrule5.morph \ +compoundrule5.test \ +compoundrule5.wrong \ +compoundrule6.aff \ +compoundrule6.dic \ +compoundrule6.good \ +compoundrule6.test \ +compoundrule6.wrong \ +compoundrule7.aff \ +compoundrule7.dic \ +compoundrule7.good \ +compoundrule7.test \ +compoundrule7.wrong \ +compoundrule8.aff \ +compoundrule8.dic \ +compoundrule8.good \ +compoundrule8.test \ +compoundrule8.wrong \ +compoundaffix.aff \ +compoundaffix.dic \ +compoundaffix.good \ +compoundaffix.test \ +compoundaffix.wrong \ +compoundaffix2.aff \ +compoundaffix2.dic \ +compoundaffix2.good \ +compoundaffix2.test \ +compoundaffix3.aff \ +compoundaffix3.dic \ +compoundaffix3.good \ +compoundaffix3.test \ +compoundaffix3.wrong \ +checkcompounddup.aff \ +checkcompounddup.dic \ +checkcompounddup.good \ +checkcompounddup.test \ +checkcompounddup.wrong \ +checkcompoundcase.aff \ +checkcompoundcase.dic \ +checkcompoundcase.good \ +checkcompoundcase.test \ +checkcompoundcase.wrong \ +checkcompoundcase2.aff \ +checkcompoundcase2.dic \ +checkcompoundcase2.good \ +checkcompoundcase2.test \ +checkcompoundcase2.wrong \ +checkcompoundcaseutf.aff \ +checkcompoundcaseutf.dic \ +checkcompoundcaseutf.good \ +checkcompoundcaseutf.test \ +checkcompoundcaseutf.wrong \ +checkcompoundrep.aff \ +checkcompoundrep.dic \ +checkcompoundrep.good \ +checkcompoundrep.test \ +checkcompoundrep.wrong \ +checkcompoundtriple.aff \ +checkcompoundtriple.dic \ +checkcompoundtriple.good \ +checkcompoundtriple.test \ +checkcompoundtriple.wrong \ +simplifiedtriple.aff \ +simplifiedtriple.dic \ +simplifiedtriple.good \ +simplifiedtriple.test \ +simplifiedtriple.wrong \ +checkcompoundpattern.aff \ +checkcompoundpattern.dic \ +checkcompoundpattern.good \ +checkcompoundpattern.test \ +checkcompoundpattern.wrong \ +checkcompoundpattern2.aff \ +checkcompoundpattern2.dic \ +checkcompoundpattern2.good \ +checkcompoundpattern2.test \ +checkcompoundpattern2.wrong \ +checkcompoundpattern3.aff \ +checkcompoundpattern3.dic \ +checkcompoundpattern3.good \ +checkcompoundpattern3.test \ +checkcompoundpattern3.wrong \ +checkcompoundpattern4.aff \ +checkcompoundpattern4.dic \ +checkcompoundpattern4.good \ +checkcompoundpattern4.test \ +checkcompoundpattern4.wrong \ +checksharps.aff \ +checksharps.dic \ +checksharps.good \ +checksharps.sug \ +checksharps.test \ +checksharps.wrong \ +checksharpsutf.aff \ +checksharpsutf.dic \ +checksharpsutf.good \ +checksharpsutf.sug \ +checksharpsutf.test \ +checksharpsutf.wrong \ +conditionalprefix.aff \ +conditionalprefix.dic \ +conditionalprefix.good \ +conditionalprefix.morph \ +conditionalprefix.test \ +conditionalprefix.wrong \ +flaglong.aff \ +flaglong.dic \ +flaglong.good \ +flaglong.test \ +flagnum.aff \ +flagnum.dic \ +flagnum.good \ +flagnum.test \ +flag.aff \ +flag.dic \ +flag.good \ +flag.test \ +flagutf8.aff \ +flagutf8.dic \ +flagutf8.good \ +flagutf8.test \ +complexprefixes.aff \ +complexprefixes.dic \ +complexprefixes.good \ +complexprefixes.wrong \ +complexprefixes.test \ +complexprefixes2.aff \ +complexprefixes2.dic \ +complexprefixes2.good \ +complexprefixes2.test \ +complexprefixesutf.aff \ +complexprefixesutf.dic \ +complexprefixesutf.good \ +complexprefixesutf.wrong \ +complexprefixesutf.test \ +i35725.aff \ +i35725.dic \ +i35725.good \ +i35725.sug \ +i35725.test \ +i35725.wrong \ +i53643.aff \ +i53643.dic \ +i53643.good \ +i53643.test \ +i53643.wrong \ +i54633.aff \ +i54633.dic \ +i54633.good \ +i54633.sug \ +i54633.test \ +i54633.wrong \ +i54980.aff \ +i54980.dic \ +i54980.good \ +i54980.test \ +i58202.aff \ +i58202.dic \ +i58202.good \ +i58202.sug \ +i58202.test \ +i58202.wrong \ +maputf.aff \ +maputf.dic \ +maputf.sug \ +maputf.wrong \ +maputf.test \ +reputf.aff \ +reputf.dic \ +reputf.sug \ +reputf.wrong \ +reputf.test \ +slash.aff \ +slash.dic \ +slash.good \ +slash.test \ +ignore.aff \ +ignore.dic \ +ignore.good \ +ignore.test \ +ignoreutf.aff \ +ignoreutf.dic \ +ignoreutf.good \ +ignoreutf.test \ +1592880.aff \ +1592880.dic \ +1592880.good \ +1592880.test \ +1695964.aff \ +1695964.dic \ +1695964.sug \ +1695964.test \ +1695964.wrong \ +1463589.aff \ +1463589.dic \ +1463589.sug \ +1463589.test \ +1463589.wrong \ +1463589_utf.aff \ +1463589_utf.dic \ +1463589_utf.sug \ +1463589_utf.test \ +1463589_utf.wrong \ +IJ.aff \ +IJ.dic \ +IJ.good \ +IJ.sug \ +IJ.test \ +IJ.wrong \ +i68568.aff \ +i68568.dic \ +i68568.test \ +i68568.wrong \ +i68568utf.aff \ +i68568utf.dic \ +i68568utf.test \ +i68568utf.wrong \ +1706659.aff \ +1706659.dic \ +1706659.test \ +1706659.wrong \ +digits_in_words.aff \ +digits_in_words.dic \ +digits_in_words.test \ +digits_in_words.wrong \ +colons_in_words.aff \ +colons_in_words.dic \ +colons_in_words.test \ +ngram_utf_fix.aff \ +ngram_utf_fix.dic \ +ngram_utf_fix.good \ +ngram_utf_fix.sug \ +ngram_utf_fix.test \ +ngram_utf_fix.wrong \ +morph.aff \ +morph.dic \ +morph.good \ +morph.morph \ +morph.test \ +1975530.aff \ +1975530.dic \ +1975530.good \ +1975530.test \ +1975530.wrong \ +fullstrip.aff \ +fullstrip.dic \ +fullstrip.good \ +fullstrip.test \ +iconv.aff \ +iconv.dic \ +iconv.good \ +iconv.test \ +oconv.aff \ +oconv.dic \ +oconv.good \ +oconv.sug \ +oconv.test \ +oconv.wrong \ +encoding.aff \ +encoding.dic \ +encoding.good \ +encoding.test \ +opentaal_forbiddenword1.aff \ +opentaal_forbiddenword1.dic \ +opentaal_forbiddenword1.good \ +opentaal_forbiddenword1.sug \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword1.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_keepcase.aff \ +opentaal_keepcase.dic \ +opentaal_keepcase.good \ +opentaal_keepcase.sug \ +opentaal_keepcase.test \ +opentaal_keepcase.wrong \ +arabic.aff \ +arabic.dic \ +arabic.wrong \ +arabic.test \ +2970240.aff \ +2970240.dic \ +2970240.good \ +2970240.wrong \ +2970240.test \ +2970242.aff \ +2970242.dic \ +2970242.good \ +2970242.wrong \ +2970242.test \ +breakoff.aff \ +breakoff.dic \ +breakoff.good \ +breakoff.wrong \ +breakoff.test \ +opentaal_cpdpat.aff \ +opentaal_cpdpat.dic \ +opentaal_cpdpat.good \ +opentaal_cpdpat.wrong \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.aff \ +opentaal_cpdpat2.dic \ +opentaal_cpdpat2.good \ +opentaal_cpdpat2.wrong \ +opentaal_cpdpat2.test \ +2999225.aff \ +2999225.dic \ +2999225.good \ +2999225.test \ +korean.aff \ +korean.dic \ +korean.good \ +korean.wrong \ +korean.test \ +onlyincompound2.aff \ +onlyincompound2.dic \ +onlyincompound2.good \ +onlyincompound2.test \ +onlyincompound2.wrong \ +forceucase.aff \ +forceucase.dic \ +forceucase.good \ +forceucase.sug \ +forceucase.wrong \ +forceucase.test \ +warn.aff \ +warn.dic \ +warn.good \ +warn.test + +# infixes.aff +# infixes.dic +# infixes.good +# infixes.test diff --git a/extensions/spellcheck/hunspell/tests/unit/data/Makefile.in b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.in new file mode 100644 index 000000000..a27e04875 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.in @@ -0,0 +1,1416 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = tests +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/codeset.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \ + $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \ + $(top_srcdir)/m4/inttypes-pri.m4 \ + $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/visibility.m4 \ + $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ + $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSESLIB = @CURSESLIB@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENCAT = @GENCAT@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC2 = @GLIBC2@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_ASPRINTF = @HAVE_ASPRINTF@ +HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@ +HAVE_SNPRINTF = @HAVE_SNPRINTF@ +HAVE_VISIBILITY = @HAVE_VISIBILITY@ +HAVE_WPRINTF = @HAVE_WPRINTF@ +HUNSPELL_VERSION_MAJOR = @HUNSPELL_VERSION_MAJOR@ +HUNSPELL_VERSION_MINOR = @HUNSPELL_VERSION_MINOR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPTH = @LIBPTH@ +LIBPTH_PREFIX = @LIBPTH_PREFIX@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBC = @LTLIBC@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBPTH = @LTLIBPTH@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +WOE32 = @WOE32@ +WOE32DLL = @WOE32DLL@ +XFAILED = @XFAILED@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = suggestiontest +XFAIL_TESTS = @XFAILED@ +TESTS = \ +affixes.test \ +condition.test \ +condition_utf.test \ +base.test \ +base_utf.test \ +allcaps.test \ +allcaps_utf.test \ +allcaps2.test \ +allcaps3.test \ +keepcase.test \ +i58202.test \ +map.test \ +rep.test \ +sug.test \ +sugutf.test \ +phone.test \ +flag.test \ +flaglong.test \ +flagnum.test \ +flagutf8.test \ +slash.test \ +forbiddenword.test \ +nosuggest.test \ +alias.test \ +alias2.test \ +alias3.test \ +breakdefault.test \ +break.test \ +needaffix.test \ +needaffix2.test \ +needaffix3.test \ +needaffix4.test \ +needaffix5.test \ +circumfix.test \ +fogemorpheme.test \ +onlyincompound.test \ +complexprefixes.test \ +complexprefixes2.test \ +complexprefixesutf.test \ +conditionalprefix.test \ +zeroaffix.test \ +utf8.test \ +utf8_bom.test \ +utf8_bom2.test \ +utf8_nonbmp.test \ +compoundflag.test \ +compoundrule.test \ +compoundrule2.test \ +compoundrule3.test \ +compoundrule4.test \ +compoundrule5.test \ +compoundrule6.test \ +compoundrule7.test \ +compoundrule8.test \ +compoundaffix.test \ +compoundaffix2.test \ +compoundaffix3.test \ +checkcompounddup.test \ +checkcompoundtriple.test \ +simplifiedtriple.test \ +checkcompoundrep.test \ +checkcompoundcase2.test \ +checkcompoundcaseutf.test \ +checkcompoundpattern.test \ +checkcompoundpattern2.test \ +checkcompoundpattern3.test \ +checkcompoundpattern4.test \ +utfcompound.test \ +checksharps.test \ +checksharpsutf.test \ +germancompounding.test \ +germancompoundingold.test \ +i35725.test \ +i53643.test \ +i54633.test \ +i54980.test \ +maputf.test \ +reputf.test \ +ignore.test \ +ignoreutf.test \ +1592880.test \ +1695964.test \ +1463589.test \ +1463589_utf.test \ +IJ.test \ +i68568.test \ +i68568utf.test \ +1706659.test \ +digits_in_words.test \ +colons_in_words.test \ +ngram_utf_fix.test \ +morph.test \ +1975530.test \ +fullstrip.test \ +iconv.test \ +oconv.test \ +encoding.test \ +korean.test \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword2.test \ +opentaal_keepcase.test \ +arabic.test \ +2970240.test \ +2970242.test \ +breakoff.test \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.test \ +2999225.test \ +onlyincompound2.test \ +forceucase.test \ +warn.test + +EXTRA_DIST = \ +test.sh \ +affixes.aff \ +affixes.dic \ +affixes.good \ +affixes.test \ +condition.aff \ +condition.dic \ +condition.good \ +condition.test \ +condition.wrong \ +condition_utf.aff \ +condition_utf.dic \ +condition_utf.good \ +condition_utf.test \ +condition_utf.wrong \ +base.aff \ +base.dic \ +base.good \ +base.sug \ +base.test \ +base.wrong \ +base_utf.aff \ +base_utf.dic \ +base_utf.good \ +base_utf.sug \ +base_utf.test \ +base_utf.wrong \ +allcaps.aff \ +allcaps.dic \ +allcaps.good \ +allcaps.sug \ +allcaps.test \ +allcaps.wrong \ +allcaps2.aff \ +allcaps2.dic \ +allcaps2.good \ +allcaps2.sug \ +allcaps2.test \ +allcaps2.wrong \ +allcaps3.aff \ +allcaps3.dic \ +allcaps3.good \ +allcaps3.test \ +allcaps3.wrong \ +allcaps_utf.aff \ +allcaps_utf.dic \ +allcaps_utf.good \ +allcaps_utf.sug \ +allcaps_utf.test \ +allcaps_utf.wrong \ +keepcase.aff \ +keepcase.dic \ +keepcase.good \ +keepcase.sug \ +keepcase.test \ +keepcase.wrong \ +map.aff \ +map.dic \ +map.sug \ +map.test \ +map.wrong \ +rep.aff \ +rep.dic \ +rep.sug \ +rep.test \ +rep.wrong \ +sug.aff \ +sug.dic \ +sug.sug \ +sug.test \ +sug.wrong \ +sugutf.aff \ +sugutf.dic \ +sugutf.sug \ +sugutf.test \ +sugutf.wrong \ +phone.aff \ +phone.dic \ +phone.sug \ +phone.test \ +phone.wrong \ +alias.aff \ +alias.dic \ +alias.good \ +alias.test \ +alias2.aff \ +alias2.dic \ +alias2.good \ +alias2.morph \ +alias2.test \ +alias3.aff \ +alias3.dic \ +alias3.good \ +alias3.morph \ +alias3.test \ +break.aff \ +break.dic \ +break.good \ +break.test \ +break.wrong \ +breakdefault.aff \ +breakdefault.dic \ +breakdefault.good \ +breakdefault.sug \ +breakdefault.test \ +breakdefault.wrong \ +circumfix.aff \ +circumfix.dic \ +circumfix.good \ +circumfix.morph \ +circumfix.test \ +circumfix.wrong \ +fogemorpheme.aff \ +fogemorpheme.dic \ +fogemorpheme.good \ +fogemorpheme.test \ +fogemorpheme.wrong \ +onlyincompound.aff \ +onlyincompound.dic \ +onlyincompound.good \ +onlyincompound.sug \ +onlyincompound.test \ +onlyincompound.wrong \ +forbiddenword.aff \ +forbiddenword.dic \ +forbiddenword.good \ +forbiddenword.test \ +forbiddenword.wrong \ +nosuggest.aff \ +nosuggest.dic \ +nosuggest.good \ +nosuggest.sug \ +nosuggest.test \ +nosuggest.wrong \ +germancompounding.aff \ +germancompounding.dic \ +germancompounding.good \ +germancompounding.test \ +germancompounding.wrong \ +germancompoundingold.aff \ +germancompoundingold.dic \ +germancompoundingold.good \ +germancompoundingold.test \ +germancompoundingold.wrong \ +needaffix2.aff \ +needaffix2.dic \ +needaffix2.good \ +needaffix2.morph \ +needaffix2.test \ +needaffix3.aff \ +needaffix3.dic \ +needaffix3.good \ +needaffix3.test \ +needaffix3.wrong \ +needaffix4.aff \ +needaffix4.dic \ +needaffix4.good \ +needaffix4.test \ +needaffix5.aff \ +needaffix5.dic \ +needaffix5.good \ +needaffix5.test \ +needaffix5.wrong \ +needaffix.aff \ +needaffix.dic \ +needaffix.good \ +needaffix.test \ +needaffix.wrong \ +zeroaffix.aff \ +zeroaffix.dic \ +zeroaffix.good \ +zeroaffix.morph \ +zeroaffix.test \ +utf8.aff \ +utf8.dic \ +utf8.good \ +utf8.test \ +utf8_bom.aff \ +utf8_bom.dic \ +utf8_bom.good \ +utf8_bom.test \ +utf8_bom2.aff \ +utf8_bom2.dic \ +utf8_bom2.good \ +utf8_bom2.test \ +utf8_nonbmp.aff \ +utf8_nonbmp.dic \ +utf8_nonbmp.good \ +utf8_nonbmp.sug \ +utf8_nonbmp.test \ +utf8_nonbmp.wrong \ +utfcompound.aff \ +utfcompound.dic \ +utfcompound.good \ +utfcompound.test \ +utfcompound.wrong \ +compoundflag.aff \ +compoundflag.dic \ +compoundflag.good \ +compoundflag.test \ +compoundflag.wrong \ +compoundrule.aff \ +compoundrule.dic \ +compoundrule.good \ +compoundrule.test \ +compoundrule.wrong \ +compoundrule2.aff \ +compoundrule2.dic \ +compoundrule2.good \ +compoundrule2.test \ +compoundrule2.wrong \ +compoundrule3.aff \ +compoundrule3.dic \ +compoundrule3.good \ +compoundrule3.test \ +compoundrule3.wrong \ +compoundrule4.aff \ +compoundrule4.dic \ +compoundrule4.good \ +compoundrule4.test \ +compoundrule4.wrong \ +compoundrule5.aff \ +compoundrule5.dic \ +compoundrule5.good \ +compoundrule5.morph \ +compoundrule5.test \ +compoundrule5.wrong \ +compoundrule6.aff \ +compoundrule6.dic \ +compoundrule6.good \ +compoundrule6.test \ +compoundrule6.wrong \ +compoundrule7.aff \ +compoundrule7.dic \ +compoundrule7.good \ +compoundrule7.test \ +compoundrule7.wrong \ +compoundrule8.aff \ +compoundrule8.dic \ +compoundrule8.good \ +compoundrule8.test \ +compoundrule8.wrong \ +compoundaffix.aff \ +compoundaffix.dic \ +compoundaffix.good \ +compoundaffix.test \ +compoundaffix.wrong \ +compoundaffix2.aff \ +compoundaffix2.dic \ +compoundaffix2.good \ +compoundaffix2.test \ +compoundaffix3.aff \ +compoundaffix3.dic \ +compoundaffix3.good \ +compoundaffix3.test \ +compoundaffix3.wrong \ +checkcompounddup.aff \ +checkcompounddup.dic \ +checkcompounddup.good \ +checkcompounddup.test \ +checkcompounddup.wrong \ +checkcompoundcase.aff \ +checkcompoundcase.dic \ +checkcompoundcase.good \ +checkcompoundcase.test \ +checkcompoundcase.wrong \ +checkcompoundcase2.aff \ +checkcompoundcase2.dic \ +checkcompoundcase2.good \ +checkcompoundcase2.test \ +checkcompoundcase2.wrong \ +checkcompoundcaseutf.aff \ +checkcompoundcaseutf.dic \ +checkcompoundcaseutf.good \ +checkcompoundcaseutf.test \ +checkcompoundcaseutf.wrong \ +checkcompoundrep.aff \ +checkcompoundrep.dic \ +checkcompoundrep.good \ +checkcompoundrep.test \ +checkcompoundrep.wrong \ +checkcompoundtriple.aff \ +checkcompoundtriple.dic \ +checkcompoundtriple.good \ +checkcompoundtriple.test \ +checkcompoundtriple.wrong \ +simplifiedtriple.aff \ +simplifiedtriple.dic \ +simplifiedtriple.good \ +simplifiedtriple.test \ +simplifiedtriple.wrong \ +checkcompoundpattern.aff \ +checkcompoundpattern.dic \ +checkcompoundpattern.good \ +checkcompoundpattern.test \ +checkcompoundpattern.wrong \ +checkcompoundpattern2.aff \ +checkcompoundpattern2.dic \ +checkcompoundpattern2.good \ +checkcompoundpattern2.test \ +checkcompoundpattern2.wrong \ +checkcompoundpattern3.aff \ +checkcompoundpattern3.dic \ +checkcompoundpattern3.good \ +checkcompoundpattern3.test \ +checkcompoundpattern3.wrong \ +checkcompoundpattern4.aff \ +checkcompoundpattern4.dic \ +checkcompoundpattern4.good \ +checkcompoundpattern4.test \ +checkcompoundpattern4.wrong \ +checksharps.aff \ +checksharps.dic \ +checksharps.good \ +checksharps.sug \ +checksharps.test \ +checksharps.wrong \ +checksharpsutf.aff \ +checksharpsutf.dic \ +checksharpsutf.good \ +checksharpsutf.sug \ +checksharpsutf.test \ +checksharpsutf.wrong \ +conditionalprefix.aff \ +conditionalprefix.dic \ +conditionalprefix.good \ +conditionalprefix.morph \ +conditionalprefix.test \ +conditionalprefix.wrong \ +flaglong.aff \ +flaglong.dic \ +flaglong.good \ +flaglong.test \ +flagnum.aff \ +flagnum.dic \ +flagnum.good \ +flagnum.test \ +flag.aff \ +flag.dic \ +flag.good \ +flag.test \ +flagutf8.aff \ +flagutf8.dic \ +flagutf8.good \ +flagutf8.test \ +complexprefixes.aff \ +complexprefixes.dic \ +complexprefixes.good \ +complexprefixes.wrong \ +complexprefixes.test \ +complexprefixes2.aff \ +complexprefixes2.dic \ +complexprefixes2.good \ +complexprefixes2.test \ +complexprefixesutf.aff \ +complexprefixesutf.dic \ +complexprefixesutf.good \ +complexprefixesutf.wrong \ +complexprefixesutf.test \ +i35725.aff \ +i35725.dic \ +i35725.good \ +i35725.sug \ +i35725.test \ +i35725.wrong \ +i53643.aff \ +i53643.dic \ +i53643.good \ +i53643.test \ +i53643.wrong \ +i54633.aff \ +i54633.dic \ +i54633.good \ +i54633.sug \ +i54633.test \ +i54633.wrong \ +i54980.aff \ +i54980.dic \ +i54980.good \ +i54980.test \ +i58202.aff \ +i58202.dic \ +i58202.good \ +i58202.sug \ +i58202.test \ +i58202.wrong \ +maputf.aff \ +maputf.dic \ +maputf.sug \ +maputf.wrong \ +maputf.test \ +reputf.aff \ +reputf.dic \ +reputf.sug \ +reputf.wrong \ +reputf.test \ +slash.aff \ +slash.dic \ +slash.good \ +slash.test \ +ignore.aff \ +ignore.dic \ +ignore.good \ +ignore.test \ +ignoreutf.aff \ +ignoreutf.dic \ +ignoreutf.good \ +ignoreutf.test \ +1592880.aff \ +1592880.dic \ +1592880.good \ +1592880.test \ +1695964.aff \ +1695964.dic \ +1695964.sug \ +1695964.test \ +1695964.wrong \ +1463589.aff \ +1463589.dic \ +1463589.sug \ +1463589.test \ +1463589.wrong \ +1463589_utf.aff \ +1463589_utf.dic \ +1463589_utf.sug \ +1463589_utf.test \ +1463589_utf.wrong \ +IJ.aff \ +IJ.dic \ +IJ.good \ +IJ.sug \ +IJ.test \ +IJ.wrong \ +i68568.aff \ +i68568.dic \ +i68568.test \ +i68568.wrong \ +i68568utf.aff \ +i68568utf.dic \ +i68568utf.test \ +i68568utf.wrong \ +1706659.aff \ +1706659.dic \ +1706659.test \ +1706659.wrong \ +digits_in_words.aff \ +digits_in_words.dic \ +digits_in_words.test \ +digits_in_words.wrong \ +colons_in_words.aff \ +colons_in_words.dic \ +colons_in_words.test \ +ngram_utf_fix.aff \ +ngram_utf_fix.dic \ +ngram_utf_fix.good \ +ngram_utf_fix.sug \ +ngram_utf_fix.test \ +ngram_utf_fix.wrong \ +morph.aff \ +morph.dic \ +morph.good \ +morph.morph \ +morph.test \ +1975530.aff \ +1975530.dic \ +1975530.good \ +1975530.test \ +1975530.wrong \ +fullstrip.aff \ +fullstrip.dic \ +fullstrip.good \ +fullstrip.test \ +iconv.aff \ +iconv.dic \ +iconv.good \ +iconv.test \ +oconv.aff \ +oconv.dic \ +oconv.good \ +oconv.sug \ +oconv.test \ +oconv.wrong \ +encoding.aff \ +encoding.dic \ +encoding.good \ +encoding.test \ +opentaal_forbiddenword1.aff \ +opentaal_forbiddenword1.dic \ +opentaal_forbiddenword1.good \ +opentaal_forbiddenword1.sug \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword1.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_keepcase.aff \ +opentaal_keepcase.dic \ +opentaal_keepcase.good \ +opentaal_keepcase.sug \ +opentaal_keepcase.test \ +opentaal_keepcase.wrong \ +arabic.aff \ +arabic.dic \ +arabic.wrong \ +arabic.test \ +2970240.aff \ +2970240.dic \ +2970240.good \ +2970240.wrong \ +2970240.test \ +2970242.aff \ +2970242.dic \ +2970242.good \ +2970242.wrong \ +2970242.test \ +breakoff.aff \ +breakoff.dic \ +breakoff.good \ +breakoff.wrong \ +breakoff.test \ +opentaal_cpdpat.aff \ +opentaal_cpdpat.dic \ +opentaal_cpdpat.good \ +opentaal_cpdpat.wrong \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.aff \ +opentaal_cpdpat2.dic \ +opentaal_cpdpat2.good \ +opentaal_cpdpat2.wrong \ +opentaal_cpdpat2.test \ +2999225.aff \ +2999225.dic \ +2999225.good \ +2999225.test \ +korean.aff \ +korean.dic \ +korean.good \ +korean.wrong \ +korean.test \ +onlyincompound2.aff \ +onlyincompound2.dic \ +onlyincompound2.good \ +onlyincompound2.test \ +onlyincompound2.wrong \ +forceucase.aff \ +forceucase.dic \ +forceucase.good \ +forceucase.sug \ +forceucase.wrong \ +forceucase.test \ +warn.aff \ +warn.dic \ +warn.good \ +warn.test + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-local \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-TESTS check-am clean clean-generic \ + clean-libtool ctags ctags-recursive distclean \ + distclean-generic distclean-libtool distclean-local \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am + + +# infixes.test + +distclean-local: + -rm -rf testSubDir + +# infixes.aff +# infixes.dic +# infixes.good +# infixes.test + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.aff b/extensions/spellcheck/hunspell/tests/unit/data/affixes.aff new file mode 100644 index 000000000..cf3c50021 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.aff @@ -0,0 +1,7 @@ +# simple example for affix compression (see Hunspell(4)) +PFX A Y 1 +PFX A 0 re . + +SFX B Y 2 +SFX B 0 ed [^y] +SFX B y ied y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.dic b/extensions/spellcheck/hunspell/tests/unit/data/affixes.dic new file mode 100644 index 000000000..e228043ef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.dic @@ -0,0 +1,4 @@ +3 +hello +try/B +work/AB diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.good b/extensions/spellcheck/hunspell/tests/unit/data/affixes.good new file mode 100644 index 000000000..20097e8e6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.good @@ -0,0 +1,7 @@ +hello +try +tried +work +worked +rework +reworked diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.test b/extensions/spellcheck/hunspell/tests/unit/data/affixes.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.aff b/extensions/spellcheck/hunspell/tests/unit/data/alias.aff new file mode 100644 index 000000000..3fbce0ac4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.aff @@ -0,0 +1,12 @@ +# aliases for flag vectors (AF) +# AB -> 1 +# A -> 2 +AF 2 +AF AB +AF A + +SFX A Y 1 +SFX A 0 x . + +SFX B Y 1 +SFX B 0 y/2 . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.dic b/extensions/spellcheck/hunspell/tests/unit/data/alias.dic new file mode 100644 index 000000000..e0af3c918 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.dic @@ -0,0 +1,2 @@ +1 +foo/1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.good b/extensions/spellcheck/hunspell/tests/unit/data/alias.good new file mode 100644 index 000000000..71702f231 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.good @@ -0,0 +1,4 @@ +foo +foox +fooy +fooyx diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.test b/extensions/spellcheck/hunspell/tests/unit/data/alias.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.aff b/extensions/spellcheck/hunspell/tests/unit/data/alias2.aff new file mode 100644 index 000000000..66a183833 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.aff @@ -0,0 +1,17 @@ +# aliases for flag vectors (AF) and morphological descriptions (AM) +# AB -> 1 +# A -> 2 +AF 2 +AF AB +AF A + +AM 3 +AM is:affix_x +AM ds:affix_y +AM po:noun xx:other_data + +SFX A Y 1 +SFX A 0 x . 1 + +SFX B Y 1 +SFX B 0 y/2 . 2 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.dic b/extensions/spellcheck/hunspell/tests/unit/data/alias2.dic new file mode 100644 index 000000000..60300acee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.dic @@ -0,0 +1,2 @@ +1 +foo/1 3 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.good b/extensions/spellcheck/hunspell/tests/unit/data/alias2.good new file mode 100644 index 000000000..71702f231 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.good @@ -0,0 +1,4 @@ +foo +foox +fooy +fooyx diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.morph b/extensions/spellcheck/hunspell/tests/unit/data/alias2.morph new file mode 100644 index 000000000..01f983d57 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.morph @@ -0,0 +1,12 @@ +> foo +analyze(foo) = st:foo po:noun xx:other_data +stem(foo) = foo +> foox +analyze(foox) = st:foo po:noun xx:other_data is:affix_x +stem(foox) = foo +> fooy +analyze(fooy) = st:foo po:noun xx:other_data ds:affix_y +stem(fooy) = fooy +> fooyx +analyze(fooyx) = st:foo po:noun xx:other_data ds:affix_y is:affix_x +stem(fooyx) = fooy diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.test b/extensions/spellcheck/hunspell/tests/unit/data/alias2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.aff b/extensions/spellcheck/hunspell/tests/unit/data/alias3.aff new file mode 100644 index 000000000..a32818500 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.aff @@ -0,0 +1,18 @@ +# morph. aliases with complex prefixes +COMPLEXPREFIXES +WORDCHARS _ + +AM 4 +AM affix_1/ +AM affix_2/ +AM /suffix_1 +AM [stem_1] + +PFX A Y 1 +PFX A 0 tek . 1 + +PFX B Y 1 +PFX B 0 met/A . 2 + +SFX C Y 1 +SFX C 0 _test_ . 3 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.dic b/extensions/spellcheck/hunspell/tests/unit/data/alias3.dic new file mode 100644 index 000000000..f22567cbe --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.dic @@ -0,0 +1,2 @@ +1 +ouro/BC 4 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.good b/extensions/spellcheck/hunspell/tests/unit/data/alias3.good new file mode 100644 index 000000000..6bf822826 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.good @@ -0,0 +1,4 @@ +ouro +metouro +tekmetouro +ouro_test_ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.morph b/extensions/spellcheck/hunspell/tests/unit/data/alias3.morph new file mode 100644 index 000000000..33edf5cee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.morph @@ -0,0 +1,8 @@ +> ouro +analyze(ouro) = [stem_1] ouro:ts +> metouro +analyze(metouro) = affix_2/ ouro:ts [stem_1] +> tekmetouro +analyze(tekmetouro) = affix_1/ affix_2/ ouro:ts [stem_1] +> ouro_test_ +analyze(ouro_test_) = [stem_1] ouro:ts /suffix_1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.test b/extensions/spellcheck/hunspell/tests/unit/data/alias3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.aff new file mode 100644 index 000000000..a11762568 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.aff @@ -0,0 +1,6 @@ +SET UTF-8 +WORDCHARS '. + +SFX S N 1 +SFX S 0 's . + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.dic new file mode 100644 index 000000000..7d3cdcc04 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.dic @@ -0,0 +1,3 @@ +2 +OpenOffice.org +UNICEF/S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.good new file mode 100644 index 000000000..3afd877d9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.good @@ -0,0 +1,4 @@ +OpenOffice.org +OPENOFFICE.ORG +UNICEF's +UNICEF'S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.sug b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.sug new file mode 100644 index 000000000..d372ff23d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.sug @@ -0,0 +1,3 @@ +OpenOffice.org +UNICEF +UNICEF's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.wrong new file mode 100644 index 000000000..668194906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.wrong @@ -0,0 +1,3 @@ +Openoffice.org +Unicef +Unicef's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.aff new file mode 100644 index 000000000..57e916bf5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.aff @@ -0,0 +1,5 @@ +# check uppercase forms of allcaps word + affix and words with mixed casing +WORDCHARS '. + +SFX S N 1 +SFX S 0 's . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.dic new file mode 100644 index 000000000..7d3cdcc04 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.dic @@ -0,0 +1,3 @@ +2 +OpenOffice.org +UNICEF/S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.good new file mode 100644 index 000000000..3afd877d9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.good @@ -0,0 +1,4 @@ +OpenOffice.org +OPENOFFICE.ORG +UNICEF's +UNICEF'S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.sug b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.sug new file mode 100644 index 000000000..d372ff23d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.sug @@ -0,0 +1,3 @@ +OpenOffice.org +UNICEF +UNICEF's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.wrong new file mode 100644 index 000000000..668194906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.wrong @@ -0,0 +1,3 @@ +Openoffice.org +Unicef +Unicef's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.aff new file mode 100644 index 000000000..67022d6eb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.aff @@ -0,0 +1,6 @@ +# forbidden all caps words are case sensitive +# iPod -> ipodos ("iPodic" in Hungarian) +FORBIDDENWORD * +SFX s N 1 +SFX s 0 os . + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.dic new file mode 100644 index 000000000..be21bfb40 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.dic @@ -0,0 +1,4 @@ +3 +iPod/s +iPodos/* +ipodos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.good new file mode 100644 index 000000000..5fd2f82ce --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.good @@ -0,0 +1,4 @@ +iPod +IPOD +ipodos +IPODOS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.sug b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.sug new file mode 100644 index 000000000..5c312d7b5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.sug @@ -0,0 +1,2 @@ +iPod +ipodos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.wrong new file mode 100644 index 000000000..010967be6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.wrong @@ -0,0 +1,2 @@ +ipod +iPodos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.aff new file mode 100644 index 000000000..789818e1a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.aff @@ -0,0 +1,10 @@ +# homonym support +WORDCHARS ' + +SFX s N 1 +SFX s 0 s . + +SFX S N 1 +SFX S 0 's . + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.dic new file mode 100644 index 000000000..e903a0fa9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.dic @@ -0,0 +1,7 @@ +4 +UNESCO/S +Unesco/S +Nasa/S +NASA/S +ACTS +act/s diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.good new file mode 100644 index 000000000..b9930a24d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.good @@ -0,0 +1,13 @@ +UNESCO +Unesco +UNESCO's +Unesco's +UNESCO'S +NASA +Nasa +NASA's +Nasa's +NASA'S +ACTS +acts +Acts diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.wrong new file mode 100644 index 000000000..89172b824 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.wrong @@ -0,0 +1,4 @@ +unesco +unesco's +nasa +nasa's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.aff b/extensions/spellcheck/hunspell/tests/unit/data/arabic.aff new file mode 100644 index 000000000..f8dd5cf24 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.aff @@ -0,0 +1,6 @@ +SET UTF-8 +TRY أ +IGNORE ٌٍَُِّْ + +PFX Aa Y 1 +PFX Aa 0 0/X0 أ[^ي] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.dic b/extensions/spellcheck/hunspell/tests/unit/data/arabic.dic new file mode 100644 index 000000000..9a2035def --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.dic @@ -0,0 +1,2 @@ +1 +ب diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.test b/extensions/spellcheck/hunspell/tests/unit/data/arabic.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.wrong b/extensions/spellcheck/hunspell/tests/unit/data/arabic.wrong new file mode 100644 index 000000000..9b566c364 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.wrong @@ -0,0 +1 @@ +ـ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.aff new file mode 100644 index 000000000..493157b30 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.aff @@ -0,0 +1,198 @@ +# OpenOffice.org’s en_US.aff file +# with Unicode apostrophe: ’ + +SET UTF-8 +TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' + +MAXNGRAMSUGS 1 +WORDCHARS .'’ + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 88 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion +McDonalds’sá/w +McDonald’sszá/g3) st:McDonald’s po:noun_prs is:TRANS +McDonald’sszal/g4) st:McDonald’s po:noun_prs is:INSTR +McDonald’ssal/w diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.dic new file mode 100644 index 000000000..b2b536d28 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.dic @@ -0,0 +1,29 @@ +28 +created/U +create/XKVNGADS +imply/GNSDX +natural/PUY +like/USPBY +convey/BDGS +look/GZRDS +text +hello +said +sawyer +NASA +rotten +day +tomorrow +seven +FAQ/SM +can’t +doesn’t +etc +won’t +lip +text +horrifying +speech +suggest +uncreate/V +Hunspell diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.good b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.good new file mode 100644 index 000000000..4c73e42b8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.good @@ -0,0 +1,27 @@ +created +uncreate +uncreated +imply +implied +unnatural +conveyed +sawyer +NASA +FAQs +can’t +doesn’t +won’t +Created +Hello +HELLO +NASA +etc. +etc +HELLO +lip. +text. +NASA. +Text. +TEXT. +Hunspell. +HUNSPELL. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.sug b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.sug new file mode 100644 index 000000000..990b640cf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.sug @@ -0,0 +1,11 @@ +looked, look +text, create +hello +said +rotten day, rotten-day, rotten +tomorrow, rotten +seven +NASA +horrifying +speech, Hunspell +suggest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.wrong new file mode 100644 index 000000000..88a6e2520 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.wrong @@ -0,0 +1,11 @@ +loooked +texxt +hlelo +seid +rottenday +tomorow +seeeven +Nasa +horrorfying +peech +sugesst diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.aff b/extensions/spellcheck/hunspell/tests/unit/data/base.aff new file mode 100644 index 000000000..632f04b96 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.aff @@ -0,0 +1,192 @@ +# OpenOffice.org's en_US.aff file + +SET ISO8859-1 +TRY esianrtolcdugmphbyfvkwz' + +WORDCHARS .' + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 88 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.dic b/extensions/spellcheck/hunspell/tests/unit/data/base.dic new file mode 100644 index 000000000..5d9b8a28b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.dic @@ -0,0 +1,29 @@ +28 +created/U +create/XKVNGADS +imply/GNSDX +natural/PUY +like/USPBY +convey/BDGS +look/GZRDS +text +hello +said +sawyer +NASA +rotten +day +tomorrow +seven +FAQ/SM +can't +doesn't +etc +won't +lip +text +horrifying +speech +suggest +uncreate/V +Hunspell diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.good b/extensions/spellcheck/hunspell/tests/unit/data/base.good new file mode 100644 index 000000000..8e7f88e2b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.good @@ -0,0 +1,27 @@ +created +uncreate +uncreated +imply +implied +unnatural +conveyed +sawyer +NASA +FAQs +can't +doesn't +won't +Created +Hello +HELLO +NASA +etc. +etc +HELLO +lip. +text. +NASA. +Text. +TEXT. +Hunspell. +HUNSPELL. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.sug b/extensions/spellcheck/hunspell/tests/unit/data/base.sug new file mode 100644 index 000000000..553280a6a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.sug @@ -0,0 +1,11 @@ +looked, look +text +hello +said +rotten day, rotten-day, rotten +tomorrow +seven +NASA +horrifying +speech +suggest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.test b/extensions/spellcheck/hunspell/tests/unit/data/base.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.wrong b/extensions/spellcheck/hunspell/tests/unit/data/base.wrong new file mode 100644 index 000000000..88a6e2520 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.wrong @@ -0,0 +1,11 @@ +loooked +texxt +hlelo +seid +rottenday +tomorow +seeeven +Nasa +horrorfying +peech +sugesst diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.aff b/extensions/spellcheck/hunspell/tests/unit/data/break.aff new file mode 100644 index 000000000..47b8f6b7b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.aff @@ -0,0 +1,8 @@ +# word break points test, recursive break at dash and n-dash +SET UTF-8 + +BREAK 2 +BREAK - +BREAK – + +WORDCHARS -– diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.dic b/extensions/spellcheck/hunspell/tests/unit/data/break.dic new file mode 100644 index 000000000..f3d2aa02f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.dic @@ -0,0 +1,4 @@ +3 +foo +bar +fox-bax diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.good b/extensions/spellcheck/hunspell/tests/unit/data/break.good new file mode 100644 index 000000000..5f08bfd2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.good @@ -0,0 +1,7 @@ +foo +bar +fox-bax +foo-bar +foo–bar +foo-bar-foo-bar +foo-bar–foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.test b/extensions/spellcheck/hunspell/tests/unit/data/break.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.wrong b/extensions/spellcheck/hunspell/tests/unit/data/break.wrong new file mode 100644 index 000000000..599ed9f7f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.wrong @@ -0,0 +1,12 @@ +fox +bax +-foo +bar- +fox-bar +foo-bax +foo–bax +fox–bar +foo-bar-fox-bar +foo-bax-foo-bar +foo-bar–fox-bar +foo-bax–foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.aff b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.aff new file mode 100644 index 000000000..a13f464a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.aff @@ -0,0 +1,6 @@ +# default word break at hyphens and n-dashes + +SET UTF-8 +MAXNGRAMSUGS 0 +WORDCHARS - +TRY ot diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.dic b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.dic new file mode 100644 index 000000000..bf2996035 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.dic @@ -0,0 +1,6 @@ +3 +foo +bar +free +scott +scot-free diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.good b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.good new file mode 100644 index 000000000..8d8125457 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.good @@ -0,0 +1,7 @@ +foo +bar +foo- +-foo +scot-free +foo-bar +foo-bar-foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.sug b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.sug new file mode 100644 index 000000000..8bfc69d93 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.sug @@ -0,0 +1,3 @@ +scott +scot-free +foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.test b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.wrong b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.wrong new file mode 100644 index 000000000..c3b203a7f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.wrong @@ -0,0 +1,3 @@ +scot +sco-free +fo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.aff b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.aff new file mode 100644 index 000000000..2e83d3802 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.aff @@ -0,0 +1,7 @@ +# switch off default word break at hyphens and n-dashes by BREAK 0 +SET UTF-8 +MAXNGRAMSUGS 0 +WORDCHARS - +TRY ot + +BREAK 0 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.dic b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.dic new file mode 100644 index 000000000..bf2996035 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.dic @@ -0,0 +1,6 @@ +3 +foo +bar +free +scott +scot-free diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.good b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.good new file mode 100644 index 000000000..854b39efa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.good @@ -0,0 +1,3 @@ +foo +bar +scot-free diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.test b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.wrong b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.wrong new file mode 100644 index 000000000..a6fcf7f1e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.wrong @@ -0,0 +1,5 @@ +foo- +-foo +foo-bar +foo-bar-foo-bar +scot diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.aff new file mode 100644 index 000000000..7ac46eeab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.aff @@ -0,0 +1,3 @@ +# forbid upper case letters at word bounds in compounding +CHECKCOMPOUNDCASE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.dic new file mode 100644 index 000000000..80f65d38f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.dic @@ -0,0 +1,5 @@ +4 +foo/A +Bar/A +BAZ/A +-/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.good new file mode 100644 index 000000000..9cbd79064 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.good @@ -0,0 +1,5 @@ +Barfoo +foo-Bar +foo-BAZ +BAZ-foo +BAZ-Bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.wrong new file mode 100644 index 000000000..0714c22e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.wrong @@ -0,0 +1,3 @@ +fooBar +BAZBar +BAZfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.aff new file mode 100644 index 000000000..fea046b19 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.aff @@ -0,0 +1,3 @@ +# check extended ascii +CHECKCOMPOUNDCASE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.dic new file mode 100644 index 000000000..086de0aed --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.dic @@ -0,0 +1,3 @@ +2 +o/A +o/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.good new file mode 100644 index 000000000..b38fd0c6c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.good @@ -0,0 +1,2 @@ +oo +oo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.wrong new file mode 100644 index 000000000..94786e95b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.wrong @@ -0,0 +1 @@ +oo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.aff new file mode 100644 index 000000000..546f478a5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.aff @@ -0,0 +1,3 @@ +SET UTF-8 +CHECKCOMPOUNDCASE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.dic new file mode 100644 index 000000000..0b7fbc9ac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.dic @@ -0,0 +1,3 @@ +2 +áoó/A +Óoá/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.good new file mode 100644 index 000000000..32ae1353c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.good @@ -0,0 +1,2 @@ +áoóáoó +Óoááoó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.wrong new file mode 100644 index 000000000..07434ccae --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.wrong @@ -0,0 +1 @@ +áoóÓoá diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.aff new file mode 100644 index 000000000..5cd357a5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.aff @@ -0,0 +1,3 @@ +# Forbid compound word with triple letters +CHECKCOMPOUNDDUP +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.dic new file mode 100644 index 000000000..8ac75f4fc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.dic @@ -0,0 +1,3 @@ +2 +foo/A +bar/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.good new file mode 100644 index 000000000..3866f24ca --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.good @@ -0,0 +1,5 @@ +barfoo +foobar +foofoobar +foobarfoo +barfoobarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.wrong new file mode 100644 index 000000000..5e809b3d8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.wrong @@ -0,0 +1,3 @@ +foofoo +foofoofoo +foobarbar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.aff new file mode 100644 index 000000000..dfda51af2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.aff @@ -0,0 +1,5 @@ +# forbid compounds with spec. pattern at word bounds +COMPOUNDFLAG A +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN nny ny +CHECKCOMPOUNDPATTERN ssz sz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.dic new file mode 100644 index 000000000..09300f0bc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.dic @@ -0,0 +1,5 @@ +4 +knny/A +nyels/A +hossz/A +szmts/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.good new file mode 100644 index 000000000..0f99c52d2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.good @@ -0,0 +1,2 @@ +knnyszmts +hossznyels diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.wrong new file mode 100644 index 000000000..5edd11534 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.wrong @@ -0,0 +1,4 @@ +knnynyels +hosszszmts +hosszknnynyels +knnynyelshossz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.aff new file mode 100644 index 000000000..fdf6560b4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.aff @@ -0,0 +1,7 @@ +# forbid compounds with spec. pattern at word bound and allow modificated form +# (for German and Indian languages) +COMPOUNDFLAG A +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN o b z +CHECKCOMPOUNDPATTERN oo ba u +COMPOUNDMIN 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.dic new file mode 100644 index 000000000..8ac75f4fc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.dic @@ -0,0 +1,3 @@ +2 +foo/A +bar/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.good new file mode 100644 index 000000000..eaad4f902 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.good @@ -0,0 +1,3 @@ +barfoo +fozar +fur diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.wrong new file mode 100644 index 000000000..323fae03f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.wrong @@ -0,0 +1 @@ +foobar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.aff new file mode 100644 index 000000000..6c2cfa4aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.aff @@ -0,0 +1,6 @@ +# forbid compounds with spec. pattern at word bound and allow modificated form +# (for Indian languages) +COMPOUNDFLAG A +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN o/X b/Y z +COMPOUNDMIN 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.dic new file mode 100644 index 000000000..6bd1b7fc9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.dic @@ -0,0 +1,5 @@ +4 +foo/A +boo/AX +bar/A +ban/AY diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.good new file mode 100644 index 000000000..6070eff5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.good @@ -0,0 +1,9 @@ +bozan +barfoo +banfoo +banbar +foobar +fooban +foobanbar +boobar +boobarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.wrong new file mode 100644 index 000000000..41d8d3747 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.wrong @@ -0,0 +1,8 @@ +booban +boobanfoo +fozar +fozarfoo +fozan +fozanfoo +bozar +bozarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.aff new file mode 100644 index 000000000..ef2566308 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.aff @@ -0,0 +1,8 @@ +# sandhi in Telugu writing system, based on the Kiran Chittella's example + +COMPOUNDFLAG x +COMPOUNDMIN 1 +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN a/A u/A O +CHECKCOMPOUNDPATTERN u/B u/B u + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.dic new file mode 100644 index 000000000..d245ef019 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.dic @@ -0,0 +1,6 @@ +4 +sUrya/Ax +udayaM/Ax +pEru/Bx +unna/Bx + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.good new file mode 100644 index 000000000..48761b6ee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.good @@ -0,0 +1,2 @@ +sUryOdayaM +pErunna diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.wrong new file mode 100644 index 000000000..a357fec52 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.wrong @@ -0,0 +1,2 @@ +sUryaudayaM +pEruunna diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.aff new file mode 100644 index 000000000..4fb7ff55e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.aff @@ -0,0 +1,8 @@ +// forbid compound word, if it is also a non compound word with a REP fault +// In example: Hungarian `szervz' (szer+vz) compound word is forbidden, because +// this word is also a dictionary word (szerviz) with typical fault (i->) +CHECKCOMPOUNDREP +COMPOUNDFLAG A + +REP 1 +REP i diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.dic new file mode 100644 index 000000000..030bda916 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.dic @@ -0,0 +1,5 @@ +3 +szer/A +vz/A +szerviz +kocsi/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.good new file mode 100644 index 000000000..c95c03c87 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.good @@ -0,0 +1,2 @@ +vzszer +szerkocsi \ No newline at end of file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.wrong new file mode 100644 index 000000000..8c8701d47 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.wrong @@ -0,0 +1,3 @@ +szervz +szervzkocsi +kocsiszervz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.aff new file mode 100644 index 000000000..7159cf55d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.aff @@ -0,0 +1,3 @@ +# Forbid compound word with triple letters +CHECKCOMPOUNDTRIPLE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.dic new file mode 100644 index 000000000..607c489e8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.dic @@ -0,0 +1,5 @@ +4 +foo/A +opera/A +eel/A +bare/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.good new file mode 100644 index 000000000..1293f749a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.good @@ -0,0 +1,6 @@ +operafoo +operaeel +operabare +eelbare +eelfoo +eelopera diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.wrong new file mode 100644 index 000000000..ae2d02b20 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.wrong @@ -0,0 +1,2 @@ +fooopera +bareeel diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.aff b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.aff new file mode 100644 index 000000000..6b22c7390 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.aff @@ -0,0 +1,4 @@ +# test - SS special capitalizing +CHECKSHARPS +WORDCHARS . +KEEPCASE k diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.dic b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.dic new file mode 100644 index 000000000..91d14ab9e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.dic @@ -0,0 +1,7 @@ +6 +mig/k +Aussto +Absto. +Auenabmessung +Prozessionsstrae +Auenmae diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.good b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.good new file mode 100644 index 000000000..e9be8c5c7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.good @@ -0,0 +1,13 @@ +mig +Mig +MSSIG +Aussto +Absto. +Auenabmessung +Prozessionsstrae +Auenmae +AUSSTOSS +ABSTOSS. +AUSSENABMESSUNG +PROZESSIONSSTRASSE +AUSSENMASSE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.sug b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.sug new file mode 100644 index 000000000..52c6a943b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.sug @@ -0,0 +1 @@ +MSSIG, mig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.test b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.wrong new file mode 100644 index 000000000..96eb8aea7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.wrong @@ -0,0 +1 @@ +MIG diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.aff new file mode 100644 index 000000000..86c0fc426 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.aff @@ -0,0 +1,5 @@ +# test - SS special capitalizing in UTF-8 +SET UTF-8 +CHECKSHARPS +WORDCHARS ß. +KEEPCASE k diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.dic new file mode 100644 index 000000000..9cc364eec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.dic @@ -0,0 +1,7 @@ +6 +müßig/k +Ausstoß +Abstoß. +Außenabmessung +Prozessionsstraße +Außenmaße diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.good b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.good new file mode 100644 index 000000000..a61c24319 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.good @@ -0,0 +1,13 @@ +müßig +Müßig +MÜSSIG +Ausstoß +Abstoß. +Außenabmessung +Prozessionsstraße +Außenmaße +AUSSTOSS +ABSTOSS. +AUSSENABMESSUNG +PROZESSIONSSTRASSE +AUSSENMASSE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.sug b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.sug new file mode 100644 index 000000000..ab68568e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.sug @@ -0,0 +1 @@ +MÜSSIG, müßig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.test b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.wrong new file mode 100644 index 000000000..25eb03dce --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.wrong @@ -0,0 +1 @@ +MÜßIG diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.aff b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.aff new file mode 100644 index 000000000..1eecc644b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.aff @@ -0,0 +1,16 @@ +# circumfixes: ~ obligate prefix/suffix combinations +# superlative in Hungarian: leg- (prefix) AND -bb (suffix) + +CIRCUMFIX X + +PFX A Y 1 +PFX A 0 leg/X . + +PFX B Y 1 +PFX B 0 legesleg/X . + +SFX C Y 3 +SFX C 0 obb . is:COMPARATIVE +SFX C 0 obb/AX . is:SUPERLATIVE +SFX C 0 obb/BX . is:SUPERSUPERLATIVE + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.dic b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.dic new file mode 100644 index 000000000..ba96f046d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.dic @@ -0,0 +1,2 @@ +1 +nagy/C po:adj diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.good b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.good new file mode 100644 index 000000000..65049d9f0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.good @@ -0,0 +1,4 @@ +nagy +nagyobb +legnagyobb +legeslegnagyobb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.morph b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.morph new file mode 100644 index 000000000..62e6c5371 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.morph @@ -0,0 +1,12 @@ +> nagy +analyze(nagy) = st:nagy po:adj +stem(nagy) = nagy +> nagyobb +analyze(nagyobb) = st:nagy po:adj is:COMPARATIVE +stem(nagyobb) = nagy +> legnagyobb +analyze(legnagyobb) = fl:A st:nagy po:adj is:SUPERLATIVE +stem(legnagyobb) = nagy +> legeslegnagyobb +analyze(legeslegnagyobb) = fl:B st:nagy po:adj is:SUPERSUPERLATIVE +stem(legeslegnagyobb) = nagy diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.test b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.wrong new file mode 100644 index 000000000..bab8084ee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.wrong @@ -0,0 +1,2 @@ +legnagy +legeslegnagy diff --git a/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.aff b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.aff new file mode 100644 index 000000000..d08022694 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.aff @@ -0,0 +1,3 @@ +# Colons in Finnish and Swedish words. Problem reported by Lars Aronsson. +# Parsing test (src/parsers) +WORDCHARS : diff --git a/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.dic b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.dic new file mode 100644 index 000000000..bfea1ccc7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.dic @@ -0,0 +1,4 @@ +2 +c:a +S:t +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.test b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.aff b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.aff new file mode 100644 index 000000000..7ddb497a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.aff @@ -0,0 +1,9 @@ +# set twofold prefix stripping +# Coptic example by Moheb Mekhaiel +COMPLEXPREFIXES + +PFX A Y 1 +PFX A 0 tek . + +PFX B Y 1 +PFX B 0 met/A . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.dic b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.dic new file mode 100644 index 000000000..2618c7cf4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.dic @@ -0,0 +1,3 @@ +1 +ouro/B + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.good b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.good new file mode 100644 index 000000000..eed87a774 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.good @@ -0,0 +1,3 @@ +ouro +metouro +tekmetouro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.test b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.wrong b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.wrong new file mode 100644 index 000000000..fb1c8b483 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.wrong @@ -0,0 +1,2 @@ +tekouro +mettekouro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.aff b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.aff new file mode 100644 index 000000000..b4fe1dca6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.aff @@ -0,0 +1,12 @@ +# complex prefixes with morphological analysis +COMPLEXPREFIXES +WORDCHARS _ + +PFX A Y 1 +PFX A 0 tek . affix_1/ + +PFX B Y 1 +PFX B 0 met/A . affix_2/ + +SFX C Y 1 +SFX C 0 _test_ . /suffix_1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.dic b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.dic new file mode 100644 index 000000000..7e4baf06c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.dic @@ -0,0 +1,3 @@ +1 +ouro/BC [stem_1] + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.good b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.good new file mode 100644 index 000000000..6bf822826 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.good @@ -0,0 +1,4 @@ +ouro +metouro +tekmetouro +ouro_test_ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.test b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.aff new file mode 100644 index 000000000..3991e9f5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.aff @@ -0,0 +1,12 @@ +# Coptic example by Moheb Mekhaiel +# Encoded with the new Coptic character encoding of Unicode 4.1 +SET UTF-8 + +# set twofold prefix stripping +COMPLEXPREFIXES + +PFX A Y 1 +PFX A 0 ⲧⲉⲕ . + +PFX B Y 1 +PFX B 0 ⲙⲉⲧ/A . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.dic new file mode 100644 index 000000000..bd0eb6df0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.dic @@ -0,0 +1,2 @@ +1 +ⲟⲩⲣⲟ/B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.good b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.good new file mode 100644 index 000000000..7eb956619 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.good @@ -0,0 +1,3 @@ +ⲟⲩⲣⲟ +ⲙⲉⲧⲟⲩⲣⲟ +ⲧⲉⲕⲙⲉⲧⲟⲩⲣⲟ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.test b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.wrong new file mode 100644 index 000000000..d8021fc44 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.wrong @@ -0,0 +1,2 @@ +ⲧⲉⲕⲟⲩⲣⲟ +ⲙⲉⲧⲧⲉⲕⲟⲩⲣⲟ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.aff new file mode 100644 index 000000000..cae5669c2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.aff @@ -0,0 +1,7 @@ +COMPOUNDFLAG X + +PFX P Y 1 +PFX P 0 pre . + +SFX S Y 1 +SFX S 0 suf . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.dic new file mode 100644 index 000000000..eba6b83fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.dic @@ -0,0 +1,3 @@ +2 +foo/XPS +bar/XPS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.good new file mode 100644 index 000000000..af1f0019a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.good @@ -0,0 +1,6 @@ +foo +foofoo +prefoo +foosuf +prefoosuf +prefoobarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.wrong new file mode 100644 index 000000000..b7e4067bc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.wrong @@ -0,0 +1,3 @@ +foosufbar +fooprebarsuf +prefooprebarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.aff new file mode 100644 index 000000000..1cac16e11 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.aff @@ -0,0 +1,8 @@ +COMPOUNDFLAG X +COMPOUNDPERMITFLAG Y + +PFX P Y 1 +PFX P 0 pre/Y . + +SFX S Y 1 +SFX S 0 suf/Y . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.dic new file mode 100644 index 000000000..eba6b83fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.dic @@ -0,0 +1,3 @@ +2 +foo/XPS +bar/XPS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.good new file mode 100644 index 000000000..9f3020da0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.good @@ -0,0 +1,8 @@ +foo +prefoo +foosuf +prefoosuf +prefoobarsuf +foosufbar +fooprebarsuf +prefooprebarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.aff new file mode 100644 index 000000000..98a12b56c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.aff @@ -0,0 +1,8 @@ +COMPOUNDFLAG X +COMPOUNDFORBIDFLAG Z + +PFX P Y 1 +PFX P 0 pre/Z . + +SFX S Y 1 +SFX S 0 suf/Z . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.dic new file mode 100644 index 000000000..eba6b83fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.dic @@ -0,0 +1,3 @@ +2 +foo/XPS +bar/XPS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.good new file mode 100644 index 000000000..76cc08eae --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.good @@ -0,0 +1,5 @@ +foo +foofoo +prefoo +foosuf +prefoosuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.wrong new file mode 100644 index 000000000..d92b90b28 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.wrong @@ -0,0 +1,6 @@ +prefoobarsuf +foosufbar +fooprebar +foosufprebar +fooprebarsuf +prefooprebarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.aff new file mode 100644 index 000000000..bc8369ceb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 3 +COMPOUNDFLAG A + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.dic new file mode 100644 index 000000000..d1ea8e96e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.dic @@ -0,0 +1,5 @@ +4 +foo/A +bar/A +xy/A +yz/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.good new file mode 100644 index 000000000..21cc29f2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.good @@ -0,0 +1,3 @@ +foobar +barfoo +foobarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.wrong new file mode 100644 index 000000000..c185bf150 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.wrong @@ -0,0 +1,4 @@ +xyyz +fooxy +xyfoo +fooxybar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.aff new file mode 100644 index 000000000..09309e0aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 1 +COMPOUNDRULE ABC diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.dic new file mode 100644 index 000000000..b11e8291e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/BC + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.good new file mode 100644 index 000000000..c7a0763bb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.good @@ -0,0 +1,2 @@ +abc +acc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.wrong new file mode 100644 index 000000000..bc151ea02 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.wrong @@ -0,0 +1,39 @@ +ba +aaabaaa +bbaaa +aaaaba +bbbbbaa +aa +aaa +aaaa +ab +aab +aaab +aaaab +abb +aabb +aaabbb +bb +bbb +bbbb +aaab +abcc +abbc +abbcc +aabc +aabcc +aabbc +aabbcc +aaabbbccc +ac +aac +aacc +aaaccc +bc +bcc +bbc +bbcc +bbbccc +cc +ccc +cccccc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.aff new file mode 100644 index 000000000..e4b86a53b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 1 +COMPOUNDRULE A*B*C* diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.dic new file mode 100644 index 000000000..7d07bbc89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/C + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.good new file mode 100644 index 000000000..de743bb06 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.good @@ -0,0 +1,37 @@ +aa +aaa +aaaa +ab +aab +aaab +aaaab +abb +aabb +aaabbb +bb +bbb +bbbb +aaab +abc +abcc +abbc +abbcc +aabc +aabcc +aabbc +aabbcc +aaabbbccc +ac +acc +aac +aacc +aaaccc +bc +bcc +bbc +bbcc +bbbccc +cc +ccc +cccccc +abcc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.wrong new file mode 100644 index 000000000..9e5d38d35 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.wrong @@ -0,0 +1,8 @@ +ba +aaabaaa +bbaaa +aaaaba +bbbbbaa +cba +cab +acb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.aff new file mode 100644 index 000000000..005314586 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 1 +COMPOUNDRULE A?B?C? diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.dic new file mode 100644 index 000000000..7d07bbc89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/C + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.good new file mode 100644 index 000000000..7f518893e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.good @@ -0,0 +1,7 @@ +a +b +c +ab +abc +ac +bc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.wrong new file mode 100644 index 000000000..6bd1d8004 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.wrong @@ -0,0 +1,41 @@ +aa +aaa +aaaa +aab +aaab +aaaab +abb +aabb +aaabbb +bb +bbb +bbbb +aaab +abcc +abbc +abbcc +aabc +aabcc +aabbc +aabbcc +aaabbbccc +acc +aac +aacc +aaaccc +bcc +bbc +bbcc +bbbccc +cc +ccc +cccccc +abcc +ba +aaabaaa +bbaaa +aaaaba +bbbbbaa +cba +cab +acb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.aff new file mode 100644 index 000000000..8a9996cb3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.aff @@ -0,0 +1,7 @@ +# English ordinal numbers +WORDCHARS 0123456789 +COMPOUNDMIN 1 +ONLYINCOMPOUND c +COMPOUNDRULE 2 +COMPOUNDRULE n*1t +COMPOUNDRULE n*mp diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.dic new file mode 100644 index 000000000..ced0735ec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.dic @@ -0,0 +1,24 @@ +22 +0/nm +1/n1 +2/nm +3/nm +4/nm +5/nm +6/nm +7/nm +8/nm +9/nm +0th/pt +1st/p +1th/tc +2nd/p +2th/tc +3rd/p +3th/tc +4th/pt +5th/pt +6th/pt +7th/pt +8th/pt +9th/pt diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.good new file mode 100644 index 000000000..fafe64a5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.good @@ -0,0 +1,29 @@ +1st +2nd +3rd +4th +5th +6th +7th +8th +9th +10th +11th +12th +13th +14th +15th +16th +17th +18th +19th +20th +21st +22nd +23rd +24th +25th +100th +1000th +10001st +10011th diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.test new file mode 100644 index 000000000..52e144cb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.test @@ -0,0 +1,6 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.wrong new file mode 100644 index 000000000..99f28e7cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.wrong @@ -0,0 +1,5 @@ +1th +2th +3th +10001th +10011st diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.aff new file mode 100644 index 000000000..46502460b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.aff @@ -0,0 +1,7 @@ +# number + percent +SET UTF-8 +COMPOUNDMIN 1 +COMPOUNDRULE 2 +COMPOUNDRULE N*%? +COMPOUNDRULE NN*.NN*%? +WORDCHARS 0123456789‰. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.dic new file mode 100644 index 000000000..eeeffdac5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.dic @@ -0,0 +1,14 @@ +13 +0/N po:num +1/N po:num +2/N po:num +3/N po:num +4/N po:num +5/N po:num +6/N po:num +7/N po:num +8/N po:num +9/N po:num +./. po:sign_dot +%/% po:sign_percent +‰/% po:sign_per_mille diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.good new file mode 100644 index 000000000..691fca1fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.good @@ -0,0 +1,7 @@ +10% +0.2% +0.20% +123.4561‰ +10 +0000 +10.25 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.morph b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.morph new file mode 100644 index 000000000..107a80859 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.morph @@ -0,0 +1,21 @@ +> 10% +analyze(10%) = pa:1 st:1 po:num pa:0 st:0 po:num pa:% st:% po:sign_percent +stem(10%) = 10% +> 0.2% +analyze(0.2%) = pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:% st:% po:sign_percent +stem(0.2%) = 0.2% +> 0.20% +analyze(0.20%) = pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:0 st:0 po:num pa:% st:% po:sign_percent +stem(0.20%) = 0.20% +> 123.4561‰ +analyze(123.4561‰) = pa:1 st:1 po:num pa:2 st:2 po:num pa:3 st:3 po:num pa:. st:. po:sign_dot pa:4 st:4 po:num pa:5 st:5 po:num pa:6 st:6 po:num pa:1 st:1 po:num pa:‰ st:‰ po:sign_per_mille +stem(123.4561‰) = 123.4561‰ +> 10 +analyze(10) = pa:1 st:1 po:num pa:0 st:0 po:num +stem(10) = 10 +> 0000 +analyze(0000) = pa:0 st:0 po:num pa:0 st:0 po:num pa:0 st:0 po:num pa:0 st:0 po:num +stem(0000) = 0000 +> 10.25 +analyze(10.25) = pa:1 st:1 po:num pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:5 st:5 po:num +stem(10.25) = 10.25 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.wrong new file mode 100644 index 000000000..ba1fe3290 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.wrong @@ -0,0 +1 @@ +.25 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.aff new file mode 100644 index 000000000..e8a088d5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.aff @@ -0,0 +1,4 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 2 +COMPOUNDRULE A*A +COMPOUNDRULE A*AAB*BBBC*C diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.dic new file mode 100644 index 000000000..7d07bbc89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/C + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.good new file mode 100644 index 000000000..55a8f8bc5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.good @@ -0,0 +1,4 @@ +aa +aaaaaa +aabbbc +aaaaabbbbbbcccccc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.wrong new file mode 100644 index 000000000..48b376dac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.wrong @@ -0,0 +1,4 @@ +abc +abbbbbccccccc +aabbccccccc +aabbbbbbb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.aff new file mode 100644 index 000000000..3ae1fc784 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.aff @@ -0,0 +1,8 @@ +# English ordinal numbers (parenthesized long flags) +FLAG long +WORDCHARS 0123456789 +COMPOUNDMIN 1 +ONLYINCOMPOUND cc +COMPOUNDRULE 2 +COMPOUNDRULE (nn)*(11)(tt) +COMPOUNDRULE (nn)*(mm)(pp) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.dic new file mode 100644 index 000000000..ad4bb4d28 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.dic @@ -0,0 +1,24 @@ +22 +0/nnmm +1/nn11 +2/nnmm +3/nnmm +4/nnmm +5/nnmm +6/nnmm +7/nnmm +8/nnmm +9/nnmm +0th/pptt +1st/pp +1th/ttcc +2nd/pp +2th/ttcc +3rd/pp +3th/ttcc +4th/pptt +5th/pptt +6th/pptt +7th/pptt +8th/pptt +9th/pptt diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.good new file mode 100644 index 000000000..fafe64a5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.good @@ -0,0 +1,29 @@ +1st +2nd +3rd +4th +5th +6th +7th +8th +9th +10th +11th +12th +13th +14th +15th +16th +17th +18th +19th +20th +21st +22nd +23rd +24th +25th +100th +1000th +10001st +10011th diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.test new file mode 100644 index 000000000..52e144cb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.test @@ -0,0 +1,6 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.wrong new file mode 100644 index 000000000..99f28e7cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.wrong @@ -0,0 +1,5 @@ +1th +2th +3th +10001th +10011st diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.aff new file mode 100644 index 000000000..03a423d48 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.aff @@ -0,0 +1,8 @@ +# English ordinal numbers (parenthesized numerical flags) +FLAG num +WORDCHARS 0123456789 +COMPOUNDMIN 1 +ONLYINCOMPOUND 1000 +COMPOUNDRULE 2 +COMPOUNDRULE (1001)*(1002)(2001) +COMPOUNDRULE (1001)*(2002)(2000) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.dic new file mode 100644 index 000000000..e156e95fe --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.dic @@ -0,0 +1,24 @@ +22 +0/1001,2002 +1/1001,1002 +2/1001,2002 +3/1001,2002 +4/1001,2002 +5/1001,2002 +6/1001,2002 +7/1001,2002 +8/1001,2002 +9/1001,2002 +0th/2000,2001 +1st/2000 +1th/2001,1000 +2nd/2000 +2th/2001,1000 +3rd/2000 +3th/2001,1000 +4th/2000,2001 +5th/2000,2001 +6th/2000,2001 +7th/2000,2001 +8th/2000,2001 +9th/2000,2001 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.good new file mode 100644 index 000000000..fafe64a5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.good @@ -0,0 +1,29 @@ +1st +2nd +3rd +4th +5th +6th +7th +8th +9th +10th +11th +12th +13th +14th +15th +16th +17th +18th +19th +20th +21st +22nd +23rd +24th +25th +100th +1000th +10001st +10011th diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.test new file mode 100644 index 000000000..52e144cb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.test @@ -0,0 +1,6 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.wrong new file mode 100644 index 000000000..99f28e7cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.wrong @@ -0,0 +1,5 @@ +1th +2th +3th +10001th +10011st diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.aff new file mode 100644 index 000000000..62a1ce5e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.aff @@ -0,0 +1,42 @@ +SET UTF-8 +WORDCHARS 0123456789 + +SFX S N 18 +SFX S 0 suf1 . +SFX S 0 suf2 ó +SFX S 0 suf3 [áéóú] +SFX S 0 suf4 [^ó] +SFX S 0 suf5 [^áéóú] +SFX S 0 suf6 őó +SFX S 0 suf7 ő[áéóú] +SFX S 0 suf8 ő[^ó] +SFX S 0 suf9 ő[^áéóú] +SFX S 0 suf10 [áéóőú]ó +SFX S 0 suf11 [^ő]ó +SFX S 0 suf12 [^áéóőú]ó +SFX S 0 suf13 [áéőú][^ú] +SFX S 0 suf14 [^ú][áéóú] +SFX S 0 suf15 [áéóú][^áéőú] +SFX S 0 suf16 [^áéóú][^áéőú] +SFX S 0 suf17 [áéóú][bcdfgkmnóprstvz] +SFX S 0 suf18 [áéóú]ó + +PFX P N 18 +PFX P 0 pre1 . +PFX P 0 pre2 ó +PFX P 0 pre3 [áéóú] +PFX P 0 pre4 [^ó] +PFX P 0 pre5 [^áéóú] +PFX P 0 pre6 óő +PFX P 0 pre7 ó[áéőú] +PFX P 0 pre8 ó[^ő] +PFX P 0 pre9 ó[^áéóőú] +PFX P 0 pre10 [áéóőú]ő +PFX P 0 pre11 [^ó]ő +PFX P 0 pre12 [^áéóőú]ő +PFX P 0 pre13 [áéóú][áéőú] +PFX P 0 pre14 [áéóú][^áéóú] +PFX P 0 pre15 [áéóú][^áéőú] +PFX P 0 pre16 [^áéőú][^áéóú] +PFX P 0 pre17 [bcdfgkmnóprstvz][áéóú] +PFX P 0 pre18 ó[áéóú] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.dic new file mode 100644 index 000000000..f03ce4ea2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.dic @@ -0,0 +1,2 @@ +1 +óőó/SP diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.good b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.good new file mode 100644 index 000000000..6c6203737 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.good @@ -0,0 +1,19 @@ +óőó +óőósuf1 +pre1óőó +óőósuf2 +pre2óőó +óőósuf3 +pre3óőó +óőósuf6 +pre6óőó +óőósuf7 +pre7óőó +óőósuf10 +pre10óőó +óőósuf13 +pre13óőó +óőósuf14 +pre14óőó +óőósuf16 +pre16óőó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.wrong new file mode 100644 index 000000000..f1022132c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.wrong @@ -0,0 +1,18 @@ +óőósuf4 +pre4óőó +óőósuf5 +pre5óőó +óőósuf8 +pre8óőó +óőósuf9 +pre9óőó +óőósuf11 +pre11óőó +óőósuf12 +pre12óőó +óőósuf15 +pre15óőó +óőósuf17 +óőósuf18 +pre17óőó +pre18óőó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.aff b/extensions/spellcheck/hunspell/tests/unit/data/condition.aff new file mode 100644 index 000000000..62157421a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.aff @@ -0,0 +1,62 @@ +SET ISO8859-2 +WORDCHARS 0123456789 + +SFX S N 18 +SFX S 0 suf1 . +SFX S 0 suf2 o +SFX S 0 suf3 [aeou] +SFX S 0 suf4 [^o] +SFX S 0 suf5 [^aeou] +SFX S 0 suf6 fo +SFX S 0 suf7 f[aeou] +SFX S 0 suf8 f[^o] +SFX S 0 suf9 f[^aeou] +SFX S 0 suf10 [aefu]o +SFX S 0 suf11 [^f]o +SFX S 0 suf12 [^aefu]o +SFX S 0 suf13 [aefu][^aefu] +SFX S 0 suf14 [^aeou][aeou] +SFX S 0 suf15 [aeou][^aefu] +SFX S 0 suf16 [^aeou][^aefu] +SFX S 0 suf17 [aeou][bcdfgkmnoprstvz] +SFX S 0 suf18 [aeou]o + +SFX Q N 2 +SFX Q 0 ning [^aeio][aeiou]n +SFX Q 0 ing [aeio][aeiou][bcdfgkmnprstvz] + +SFX T N 1 +SFX T y ies .[^aeiou]y + +PFX U N 1 +PFX U 0 un wr. + +SFX Z Y 3 +SFX Z 0 ch [].a +SFX Z 0 m [].a +SFX Z a 0 [].a + +PFX P N 18 +PFX P 0 pre1 . +PFX P 0 pre2 o +PFX P 0 pre3 [aeou] +PFX P 0 pre4 [^o] +PFX P 0 pre5 [^aeou] +PFX P 0 pre6 of +PFX P 0 pre7 o[aefou] +PFX P 0 pre8 o[^f] +PFX P 0 pre9 o[^aefu] +PFX P 0 pre10 [aefu]o +PFX P 0 pre11 [^f]o +PFX P 0 pre12 [^aefou]o +PFX P 0 pre13 [aeou][aefu] +PFX P 0 pre14 [aeou][^aeou] +PFX P 0 pre15 [aeou][^aefu] +PFX P 0 pre16 [^aefu][^aeou] +PFX P 0 pre17 [bcdfgkmnoprstvz][aeou] +PFX P 0 pre18 o[aeou] + + +PFX R N 2 +PFX R 0 gnin n[aeiou][^aeio] +PFX R 0 gni [bcdfgkmnprstvz][aeiou][aeio] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.dic b/extensions/spellcheck/hunspell/tests/unit/data/condition.dic new file mode 100644 index 000000000..40ebd5588 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.dic @@ -0,0 +1,6 @@ +5 +ofo/SP +entertain/Q +nianretne/R +ra/Z +wry/TU diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.good b/extensions/spellcheck/hunspell/tests/unit/data/condition.good new file mode 100644 index 000000000..8fef4a747 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.good @@ -0,0 +1,26 @@ +ofo +ofosuf1 +pre1ofo +ofosuf2 +pre2ofo +ofosuf3 +pre3ofo +ofosuf6 +pre6ofo +ofosuf7 +pre7ofo +ofosuf10 +ofosuf13 +pre13ofo +ofosuf14 +pre14ofo +ofosuf16 +pre16ofo +entertain +entertaining +gninianretne +r +ram +rach +wries +unwry diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.test b/extensions/spellcheck/hunspell/tests/unit/data/condition.test new file mode 100644 index 000000000..c95329532 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-2 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.wrong b/extensions/spellcheck/hunspell/tests/unit/data/condition.wrong new file mode 100644 index 000000000..7b83d828d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.wrong @@ -0,0 +1,21 @@ +ofosuf4 +pre4ofo +ofosuf5 +pre5ofo +ofosuf8 +pre8ofo +ofosuf9 +pre9ofo +ofosuf11 +pre10ofo +pre11ofo +ofosuf12 +pre12ofo +ofosuf15 +pre15ofo +ofosuf17 +pre17ofo +ofosuf18 +pre18ofo +entertainning +gninnianretne diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.aff b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.aff new file mode 100644 index 000000000..e7a9bf749 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.aff @@ -0,0 +1,11 @@ +PFX P Y 1 +PFX P 0 un . ip:un + +SFX S Y 1 +SFX S 0 s . is:PL + +SFX Q Y 1 +SFX Q 0 s . is:3SGV + +SFX R Y 1 +SFX R 0 able/PS . ds:DER_V_ADJ_ABLE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.dic b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.dic new file mode 100644 index 000000000..2f6d45615 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.dic @@ -0,0 +1,3 @@ +2 +drink/RQ po:verb +drink/S po:noun diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.good b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.good new file mode 100644 index 000000000..01438d0eb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.good @@ -0,0 +1,6 @@ +drink +drinks +drinkable +drinkables +undrinkable +undrinkables diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.morph b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.morph new file mode 100644 index 000000000..95d544389 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.morph @@ -0,0 +1,20 @@ +> drink +analyze(drink) = st:drink po:verb +analyze(drink) = st:drink po:noun +stem(drink) = drink +> drinks +analyze(drinks) = st:drink po:verb is:3SGV +analyze(drinks) = st:drink po:noun is:PL +stem(drinks) = drink +> drinkable +analyze(drinkable) = st:drink po:verb ds:DER_V_ADJ_ABLE +stem(drinkable) = drinkable +> drinkables +analyze(drinkables) = st:drink po:verb ds:DER_V_ADJ_ABLE is:PL +stem(drinkables) = drinkable +> undrinkable +analyze(undrinkable) = ip:un st:drink po:verb ds:DER_V_ADJ_ABLE +stem(undrinkable) = drinkable +> undrinkables +analyze(undrinkables) = ip:un st:drink po:verb ds:DER_V_ADJ_ABLE is:PL +stem(undrinkables) = drinkable diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.test b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.wrong new file mode 100644 index 000000000..70262d940 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.wrong @@ -0,0 +1,2 @@ +undrink +undrinks diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.aff b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.aff new file mode 100644 index 000000000..18a42f6fd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.aff @@ -0,0 +1,9 @@ +# Digits in words, handled by COMPOUNDRULE. +# 1-jährig, 2-jährig, 100-jährig etc. +SET UTF-8 +COMPOUNDMIN 1 +# recognize ab, aab, aaab etc. compounds (a=digits, b=-jährig, see dic file) +COMPOUNDRULE 1 +COMPOUNDRULE a*b +ONLYINCOMPOUND c +WORDCHARS 0123456789- diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.dic b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.dic new file mode 100644 index 000000000..deeaece05 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.dic @@ -0,0 +1,12 @@ +11 +0/a +1/a +2/a +3/a +4/a +5/a +6/a +7/a +8/a +9/a +-jährig/bc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.test b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.wrong b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.wrong new file mode 100644 index 000000000..aeaf6ce34 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.wrong @@ -0,0 +1 @@ +-jährig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.aff b/extensions/spellcheck/hunspell/tests/unit/data/encoding.aff new file mode 100644 index 000000000..1f560d262 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.aff @@ -0,0 +1 @@ +SET ISO-8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.dic b/extensions/spellcheck/hunspell/tests/unit/data/encoding.dic new file mode 100644 index 000000000..414f9b8d3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.dic @@ -0,0 +1,3 @@ +2 +cur +uvre diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.good b/extensions/spellcheck/hunspell/tests/unit/data/encoding.good new file mode 100644 index 000000000..fc41c90aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.good @@ -0,0 +1,4 @@ +cur +uvre +CUR +UVRE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.test b/extensions/spellcheck/hunspell/tests/unit/data/encoding.test new file mode 100644 index 000000000..09619572e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.aff b/extensions/spellcheck/hunspell/tests/unit/data/flag.aff new file mode 100644 index 000000000..ac105c11f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.aff @@ -0,0 +1,13 @@ +# base 1-character flags + +SFX A Y 1 +SFX A 0 s/123 . + +SFX 1 Y 1 +SFX 1 0 bar . + +SFX 2 Y 1 +SFX 2 0 baz . + +PFX 3 Y 1 +PFX 3 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.dic b/extensions/spellcheck/hunspell/tests/unit/data/flag.dic new file mode 100644 index 000000000..b1b237106 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.dic @@ -0,0 +1,2 @@ +1 +foo/A3 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.good b/extensions/spellcheck/hunspell/tests/unit/data/flag.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.test b/extensions/spellcheck/hunspell/tests/unit/data/flag.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.aff b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.aff new file mode 100644 index 000000000..437f13b3a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.aff @@ -0,0 +1,14 @@ +# 2-character flags +FLAG long + +SFX zx Y 1 +SFX zx 0 s/g?1G09 . + +SFX g? Y 1 +SFX g? 0 bar . + +SFX 1G Y 1 +SFX 1G 0 baz . + +PFX 09 Y 1 +PFX 09 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.dic b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.dic new file mode 100644 index 000000000..46c601286 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.dic @@ -0,0 +1,2 @@ +1 +foo/zx09 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.good b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.test b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.aff b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.aff new file mode 100644 index 000000000..823cee4cd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.aff @@ -0,0 +1,14 @@ +# numerical flags +FLAG num + +SFX 999 Y 1 +SFX 999 0 s/214,216,54321 . + +SFX 214 Y 1 +SFX 214 0 bar . + +SFX 216 Y 1 +SFX 216 0 baz . + +PFX 54321 Y 1 +PFX 54321 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.dic b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.dic new file mode 100644 index 000000000..927c45f2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.dic @@ -0,0 +1,2 @@ +1 +foo/999,54321 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.good b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.test b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.aff b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.aff new file mode 100644 index 000000000..d0f75c185 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.aff @@ -0,0 +1,15 @@ +# UTF-8 flags +FLAG UTF-8 + +SFX A Y 1 +SFX A 0 s/ÖüÜ . +#SFX A 0 s/ÖüÖÜ . + +SFX Ö Y 1 +SFX Ö 0 bar . + +SFX ü Y 1 +SFX ü 0 baz . + +PFX Ü Y 1 +PFX Ü 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.dic b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.dic new file mode 100644 index 000000000..2944490c9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.dic @@ -0,0 +1,2 @@ +1 +foo/AÜ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.good b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.test b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.aff b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.aff new file mode 100644 index 000000000..56cdabe5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.aff @@ -0,0 +1,12 @@ +# fogemorphemes: special morphemes in compounds +# +# Swedish example: +# gata + kontoret = gatukontoret + +COMPOUNDFLAG X +COMPOUNDBEGIN Y +ONLYINCOMPOUND Z +COMPOUNDPERMITFLAG P + +SFX A Y 1 +SFX A a u/YPZ . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.dic b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.dic new file mode 100644 index 000000000..1b76380d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.dic @@ -0,0 +1,3 @@ +2 +gata/A +kontoret/X diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.good b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.good new file mode 100644 index 000000000..01e77d561 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.good @@ -0,0 +1,3 @@ +gata +kontoret +gatukontoret diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.test b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.wrong b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.wrong new file mode 100644 index 000000000..f920745c7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.wrong @@ -0,0 +1,3 @@ +gatu +gatakontoret +kontoretgatu diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.aff b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.aff new file mode 100644 index 000000000..de7f8ad9a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.aff @@ -0,0 +1,11 @@ +# FORBIDDENWORD flag +# The signed word, and its suffixed forms are all forbidden, +# excepts with root homonyms. +# Useful for forbidding bad suffixed forms or compounds. + + +FORBIDDENWORD X +COMPOUNDFLAG Y + +SFX A Y 1 +SFX A 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.dic b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.dic new file mode 100644 index 000000000..78f2ee3d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.dic @@ -0,0 +1,8 @@ +5 +foo/S [1] +foo/YX [2] +foo/Y [3] +foo/S [4] +bar/YS [5] +bars/X +foos/X diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.good b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.good new file mode 100644 index 000000000..7bd112e9e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.good @@ -0,0 +1,3 @@ +foo +bar + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.test b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.wrong b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.wrong new file mode 100644 index 000000000..5752c1e44 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.wrong @@ -0,0 +1,4 @@ +bars +foos +foobar +barfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.aff b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.aff new file mode 100644 index 000000000..5eebcbdab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.aff @@ -0,0 +1,4 @@ +# force capitalized compound +TRY F +FORCEUCASE A +COMPOUNDFLAG C diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.dic b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.dic new file mode 100644 index 000000000..82fd93b30 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.dic @@ -0,0 +1,4 @@ +3 +foo/C +bar/C +baz/CA diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.good b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.good new file mode 100644 index 000000000..37ecf4957 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.good @@ -0,0 +1,7 @@ +foo +bar +baz +foobar +Foobaz +foobazbar +Foobarbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.sug b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.sug new file mode 100644 index 000000000..6a77cbd06 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.sug @@ -0,0 +1,2 @@ +Foobaz +Foobarbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.test b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.wrong new file mode 100644 index 000000000..1503e42dd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.wrong @@ -0,0 +1,2 @@ +foobaz +foobarbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.aff b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.aff new file mode 100644 index 000000000..d60cb74d7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.aff @@ -0,0 +1,15 @@ +# FULLSTRIP option: Hunspell can strip full words by affix rules +# see OpenOffice.org Issue #80145 +# test data from Davide Prina + +FULLSTRIP + +SET ISO8859-15 +TRY aioertnsclmdpgubzfvhàq'ACMSkBGPLxEyRTVòIODNwFéùèìjUZKHWJYQX + +SFX A Y 3 # verbo andare (verb to go) +SFX A andare vado andare # io vado (I go) +SFX A andare va andare # tu vai (you go) +SFX A are iamo andare # noi andiamo (we go) + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.dic b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.dic new file mode 100644 index 000000000..553113d44 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.dic @@ -0,0 +1,4 @@ +2 +andare/A +riandare/A + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.good b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.good new file mode 100644 index 000000000..1240e71f5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.good @@ -0,0 +1,9 @@ +andare +vado +va +andiamo +riandare +rivado +riva +riandiamo + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.test b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.aff b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.aff new file mode 100644 index 000000000..5ff25872c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.aff @@ -0,0 +1,91 @@ +# German compounding + +# handle special casing of German sharp s + +CHECKSHARPS + +# compound flags + +COMPOUNDBEGIN U +COMPOUNDMIDDLE V +COMPOUNDEND W + +# Prefixes are allowed at the beginning of compounds, +# suffixes are allowed at the end of compounds by default: +# (prefix)?(root)+(affix)? +# Affixes with COMPOUNDPERMITFLAG may be inside of compounds. +COMPOUNDPERMITFLAG P + +# for German fogemorphemes (Fuge-element) +# Hint: ONLYINCOMPOUND is not required everywhere, but the +# checking will be a little faster with it. + +ONLYINCOMPOUND X + +# forbid uppercase characters at compound word bounds +CHECKCOMPOUNDCASE + +# for handling Fuge-elements with dashes (Arbeits-) +# dash will be a special word + +COMPOUNDMIN 1 +WORDCHARS - + +# compound settings and fogemorpheme for `Arbeit' + +SFX A Y 3 +SFX A 0 s/UPX . +SFX A 0 s/VPDX . +SFX A 0 0/WXD . + +SFX B Y 2 +SFX B 0 0/UPX . +SFX B 0 0/VWXDP . + +# a suffix for `Computer' + +SFX C Y 1 +SFX C 0 n/WD . + +# for forbid exceptions (*Arbeitsnehmer) + +FORBIDDENWORD Z + +# dash prefix for compounds with dash (Arbeits-Computer) + +PFX - Y 1 +PFX - 0 -/P . + +# decapitalizing prefix +# circumfix for positioning in compounds + +PFX D Y 29 +PFX D A a/PX A +PFX D /PX +PFX D B b/PX B +PFX D C c/PX C +PFX D D d/PX D +PFX D E e/PX E +PFX D F f/PX F +PFX D G g/PX G +PFX D H h/PX H +PFX D I i/PX I +PFX D J j/PX J +PFX D K k/PX K +PFX D L l/PX L +PFX D M m/PX M +PFX D N n/PX N +PFX D O o/PX O +PFX D /PX +PFX D P p/PX P +PFX D Q q/PX Q +PFX D R r/PX R +PFX D S s/PX S +PFX D T t/PX T +PFX D U u/PX U +PFX D /PX +PFX D V v/PX V +PFX D W w/PX W +PFX D X x/PX X +PFX D Y y/PX Y +PFX D Z z/PX Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.dic b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.dic new file mode 100644 index 000000000..5db6783a4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.dic @@ -0,0 +1,5 @@ +4 +Arbeit/A- +Computer/BC- +-/W +Arbeitsnehmer/Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.good b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.good new file mode 100644 index 000000000..e4945553c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.good @@ -0,0 +1,20 @@ +Computer +Computern +Arbeit +Arbeits- +Computerarbeit +Computerarbeits- +Arbeitscomputer +Computercomputer +Computercomputern +Arbeitscomputern +Computerarbeitscomputer +Computerarbeitscomputern +Arbeitscomputercomputer +Computercomputerarbeit +Arbeitscomputerarbeit +Arbeitsarbeitsarbeit +Computerarbeitsarbeit +Computerarbeits-Computer +Computerarbeits-Computern +Computer-Arbeit diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.test b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.wrong b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.wrong new file mode 100644 index 000000000..c5f2ba115 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.wrong @@ -0,0 +1,50 @@ +computer +computern +arbeit +Arbeits +arbeits +ComputerArbeit +ComputernArbeit +Computernarbeit +ComputerArbeits +Arbeitcomputer +Arbeitcomputern +ArbeitsComputer +ArbeitsComputern +Computerarbeitcomputer +ComputerArbeitcomputer +ComputerArbeitscomputer +Computerarbeitcomputern +ComputerArbeitcomputern +ComputerArbeitscomputern +Arbeitscomputerarbeits +Arbeitscomputernarbeits +Computerarbeits-computer +Arbeitsnehmer +computers +computern +computernarbeit +computernArbeit +computerArbeit +computerArbeits +arbeitcomputer +arbeitsComputer +computerarbeitcomputer +computerArbeitcomputer +computerArbeitscomputer +arbeitscomputerarbeits +computerarbeits-computer +arbeitsnehmer +computernarbeit +computernArbeit +arbeits- +computerarbeit +computerarbeits- +arbeitscomputer +arbeitscomputern +computerarbeitscomputer +computerarbeitscomputern +computerarbeitscomputers +arbeitscomputerarbeit +computerarbeits-Computer +computerarbeits-Computern diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.aff b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.aff new file mode 100644 index 000000000..3e06f0647 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.aff @@ -0,0 +1,96 @@ +# German compounding + +# handle special casing of German sharp s + +CHECKSHARPS + +# compound flags + +COMPOUNDBEGIN U +COMPOUNDMIDDLE V +COMPOUNDEND W + +# Prefixes are allowed at the beginning of compounds, +# suffixes are allowed at the end of compounds by default: +# (prefix)?(root)+(affix)? +# Affixes with COMPOUNDPERMITFLAG may be inside of compounds. +COMPOUNDPERMITFLAG P + +# for German fogemorphemes (Fuge-element) +# Hint: ONLYINCOMPOUND is not required everywhere, but the +# checking will be a little faster with it. + +ONLYINCOMPOUND X + +# for decapitalizing nouns with fogemorphemes + +CIRCUMFIX Y + +# for handling Fuge-elements with dashes (Arbeits-) +# dash will be a special word + +COMPOUNDMIN 1 +WORDCHARS - + +# compound settings and fogemorpheme for `Arbeit' + +SFX A Y 3 +SFX A 0 s/UPX . +SFX A 0 s/VPXDY . +SFX A 0 0/WXDY . + +# compound settings for `Computer' + +SFX B Y 2 +SFX B 0 0/UPX . +SFX B 0 0/VWPXDY . + +# a suffix for `Computer' + +SFX C Y 2 +SFX C 0 n . +SFX C 0 n/WXDY . + +# for forbid exceptions (*Arbeitsnehmer) + +FORBIDDENWORD Z + +# dash prefix for compounds with dash (Arbeits-Computer) + +PFX - Y 2 +PFX - 0 -/PUVW . +PFX - 0 -/PY . + +# decapitalizing prefix +# circumfix for positioning in compounds + +PFX D Y 29 +PFX D A a/PXY A +PFX D /PXY +PFX D B b/PXY B +PFX D C c/PXY C +PFX D D d/PXY D +PFX D E e/PXY E +PFX D F f/PXY F +PFX D G g/PXY G +PFX D H h/PXY H +PFX D I i/PXY I +PFX D J j/PXY J +PFX D K k/PXY K +PFX D L l/PXY L +PFX D M m/PXY M +PFX D N n/PXY N +PFX D O o/PXY O +PFX D /PXY +PFX D P p/PXY P +PFX D Q q/PXY Q +PFX D R r/PXY R +PFX D S s/PXY S +PFX D T t/PXY T +PFX D U u/PXY U +PFX D /PXY +PFX D V v/PXY V +PFX D W w/PXY W +PFX D X x/PXY X +PFX D Y y/PXY Y +PFX D Z z/PXY Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.dic b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.dic new file mode 100644 index 000000000..5db6783a4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.dic @@ -0,0 +1,5 @@ +4 +Arbeit/A- +Computer/BC- +-/W +Arbeitsnehmer/Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.good b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.good new file mode 100644 index 000000000..5357bff16 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.good @@ -0,0 +1,14 @@ +Computer +Computern +Arbeit +Arbeits- +Computerarbeit +Computerarbeits- +Arbeitscomputer +Arbeitscomputern +Computerarbeitscomputer +Computerarbeitscomputern +Arbeitscomputerarbeit +Computerarbeits-Computer +Computerarbeits-Computern +Computer-Arbeit diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.test b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.wrong b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.wrong new file mode 100644 index 000000000..c5f2ba115 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.wrong @@ -0,0 +1,50 @@ +computer +computern +arbeit +Arbeits +arbeits +ComputerArbeit +ComputernArbeit +Computernarbeit +ComputerArbeits +Arbeitcomputer +Arbeitcomputern +ArbeitsComputer +ArbeitsComputern +Computerarbeitcomputer +ComputerArbeitcomputer +ComputerArbeitscomputer +Computerarbeitcomputern +ComputerArbeitcomputern +ComputerArbeitscomputern +Arbeitscomputerarbeits +Arbeitscomputernarbeits +Computerarbeits-computer +Arbeitsnehmer +computers +computern +computernarbeit +computernArbeit +computerArbeit +computerArbeits +arbeitcomputer +arbeitsComputer +computerarbeitcomputer +computerArbeitcomputer +computerArbeitscomputer +arbeitscomputerarbeits +computerarbeits-computer +arbeitsnehmer +computernarbeit +computernArbeit +arbeits- +computerarbeit +computerarbeits- +arbeitscomputer +arbeitscomputern +computerarbeitscomputer +computerarbeitscomputern +computerarbeitscomputers +arbeitscomputerarbeit +computerarbeits-Computer +computerarbeits-Computern diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.aff b/extensions/spellcheck/hunspell/tests/unit/data/i35725.aff new file mode 100644 index 000000000..96755c7ec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.aff @@ -0,0 +1,203 @@ +# Ngram suggestions +# - fix case problem +# - detect character swapping (keep only these suggestions) +# - lesser suggestions +# - weight with common subsequence algorithm +# - suggest uppercased words + +# 2007-02-05: +# now not neighbour character replacements and character movings are +# detected by not ngram suggestions, too. + +# OpenOffice.org's en_US.aff file + +SET ISO8859-1 +TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' + +WORDCHARS ' + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 88 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.dic b/extensions/spellcheck/hunspell/tests/unit/data/i35725.dic new file mode 100644 index 000000000..0c61f0031 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.dic @@ -0,0 +1,15 @@ +15 +endangerment/SM +ferment/FSCM +preferment/SM +impermanent/Y +permanent/YSP +semipermanent/Y +empowerment/MS +supermen +tournament/MS +ornamental/SY +ornament/GSDM +supernatant +pimpernel +UNESCO/M diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.good b/extensions/spellcheck/hunspell/tests/unit/data/i35725.good new file mode 100644 index 000000000..052ba8418 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.good @@ -0,0 +1 @@ +permanent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.sug b/extensions/spellcheck/hunspell/tests/unit/data/i35725.sug new file mode 100644 index 000000000..a8bf1d980 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.sug @@ -0,0 +1,10 @@ +permanent, preferment +permanent, ornament +permanent +Permanent, Preferment +Permanent, Ornament +Permanent +UNESCO +UNESCO +UNESCO's +UNESCO's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.test b/extensions/spellcheck/hunspell/tests/unit/data/i35725.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i35725.wrong new file mode 100644 index 000000000..573e195d8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.wrong @@ -0,0 +1,10 @@ +permenant +pernament +pernemant +Permenant +Pernament +Pernemant +unesco +Unesco +unesco's +Unesco's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.aff b/extensions/spellcheck/hunspell/tests/unit/data/i53643.aff new file mode 100644 index 000000000..9fac6d84c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.aff @@ -0,0 +1,2 @@ +# check numbers with separators +WORDCHARS 0123456789.-, diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.dic b/extensions/spellcheck/hunspell/tests/unit/data/i53643.dic new file mode 100644 index 000000000..aec5d506b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.dic @@ -0,0 +1,2 @@ +1 +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.good b/extensions/spellcheck/hunspell/tests/unit/data/i53643.good new file mode 100644 index 000000000..116333452 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.good @@ -0,0 +1,19 @@ +1 +12 +123 +1234 +12345 +123456 +1234567 +1.1 +1.12 +1.123 +1.1234 +1.12345 +1.123456 +12.1 +123.12 +1234.123 +12345.1234 +123456.12345 +1234567.123456 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.test b/extensions/spellcheck/hunspell/tests/unit/data/i53643.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i53643.wrong new file mode 100644 index 000000000..45c61d298 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.wrong @@ -0,0 +1,4 @@ +1..2 +1,,2 +1.,2 +1,.2 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.aff b/extensions/spellcheck/hunspell/tests/unit/data/i54633.aff new file mode 100644 index 000000000..46281e1c5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.aff @@ -0,0 +1,2 @@ +# Missing capitalized suggestion for capitalized bad words +SET ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.dic b/extensions/spellcheck/hunspell/tests/unit/data/i54633.dic new file mode 100644 index 000000000..e26d6f9c8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.dic @@ -0,0 +1,2 @@ +1 +diter diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.good b/extensions/spellcheck/hunspell/tests/unit/data/i54633.good new file mode 100644 index 000000000..a115f67ed --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.good @@ -0,0 +1,2 @@ +diter +diter diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.sug b/extensions/spellcheck/hunspell/tests/unit/data/i54633.sug new file mode 100644 index 000000000..a115f67ed --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.sug @@ -0,0 +1,2 @@ +diter +diter diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.test b/extensions/spellcheck/hunspell/tests/unit/data/i54633.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i54633.wrong new file mode 100644 index 000000000..579a45dab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.wrong @@ -0,0 +1,2 @@ +editer +Editer diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.aff b/extensions/spellcheck/hunspell/tests/unit/data/i54980.aff new file mode 100644 index 000000000..37cc5c53d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.aff @@ -0,0 +1,2 @@ +# ISO-8859-15 (extended latin-1) support for French, Finnish and EURO symbol +SET ISO8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.dic b/extensions/spellcheck/hunspell/tests/unit/data/i54980.dic new file mode 100644 index 000000000..414f9b8d3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.dic @@ -0,0 +1,3 @@ +2 +cur +uvre diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.good b/extensions/spellcheck/hunspell/tests/unit/data/i54980.good new file mode 100644 index 000000000..fc41c90aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.good @@ -0,0 +1,4 @@ +cur +uvre +CUR +UVRE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.test b/extensions/spellcheck/hunspell/tests/unit/data/i54980.test new file mode 100644 index 000000000..09619572e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.aff b/extensions/spellcheck/hunspell/tests/unit/data/i58202.aff new file mode 100644 index 000000000..11249d4f2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.aff @@ -0,0 +1,4 @@ +# case suggestions +MAXNGRAMSUGS 0 +# capitalise baz->Baz +TRY B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.dic b/extensions/spellcheck/hunspell/tests/unit/data/i58202.dic new file mode 100644 index 000000000..19e1980ba --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.dic @@ -0,0 +1,5 @@ +4 +foo +bar +Baz +Boo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.good b/extensions/spellcheck/hunspell/tests/unit/data/i58202.good new file mode 100644 index 000000000..88a079a55 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.good @@ -0,0 +1,10 @@ +foo +bar +Foo +Bar +Baz +Boo +FOO +BAR +BAZ +BOO diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.sug b/extensions/spellcheck/hunspell/tests/unit/data/i58202.sug new file mode 100644 index 000000000..bc784acef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.sug @@ -0,0 +1,13 @@ +foo, Boo +Bar +Baz +Boo +foo bar +foo Bar +Foo bar +Foo Bar +foo Baz +Foo Baz +Baz foo +Baz Foo +Baz Boo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.test b/extensions/spellcheck/hunspell/tests/unit/data/i58202.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i58202.wrong new file mode 100644 index 000000000..886584d80 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.wrong @@ -0,0 +1,13 @@ +fOO +BAr +baz +BOo +foobar +fooBar +Foobar +FooBar +fooBaz +FooBaz +Bazfoo +BazFoo +BazBoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.aff b/extensions/spellcheck/hunspell/tests/unit/data/i68568.aff new file mode 100644 index 000000000..f0c639e8d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.aff @@ -0,0 +1,7 @@ +# Sant'Elia -> SANT'ELIA (Italian) +# OpenOffice.org Issue 68658 + +PFX a Y 1 +PFX a 0 Sant' E + +WORDCHARS ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.dic b/extensions/spellcheck/hunspell/tests/unit/data/i68568.dic new file mode 100644 index 000000000..966010835 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.dic @@ -0,0 +1,2 @@ +1 +Elia/a diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.test b/extensions/spellcheck/hunspell/tests/unit/data/i68568.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i68568.wrong new file mode 100644 index 000000000..998e9f4e4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.wrong @@ -0,0 +1,5 @@ +sant'elia +sant'Elia +Sant'elia +Sant' +SANT' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.aff new file mode 100644 index 000000000..7076ee938 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.aff @@ -0,0 +1,8 @@ +# Sant'Elia -> SANT'ELIA (Italian) +# OpenOffice.org Issue 68658 +SET UTF-8 + +PFX a Y 1 +PFX a 0 Foó' B + +WORDCHARS ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.dic new file mode 100644 index 000000000..bc38229fa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.dic @@ -0,0 +1,2 @@ +1 +Bár/a diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.test b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.wrong new file mode 100644 index 000000000..0713c1369 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.wrong @@ -0,0 +1,5 @@ +foó'bár +foó'Bár +Foó'bár +foó' +FOÓ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.aff b/extensions/spellcheck/hunspell/tests/unit/data/iconv.aff new file mode 100644 index 000000000..36cf7a223 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.aff @@ -0,0 +1,10 @@ +# input conversion (accept comma acuted letters also with cedilla, +# as de facto replacement of the Romanian standard) +SET UTF-8 + +ICONV 4 +ICONV ş ș +ICONV ţ ț +ICONV Ş Ș +ICONV Ţ Ț + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.dic b/extensions/spellcheck/hunspell/tests/unit/data/iconv.dic new file mode 100644 index 000000000..8326eee2d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.dic @@ -0,0 +1,5 @@ +4 +Chișinău +Țepes +ț +Ș diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.good b/extensions/spellcheck/hunspell/tests/unit/data/iconv.good new file mode 100644 index 000000000..746cf1e53 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.good @@ -0,0 +1,6 @@ +Chișinău +Chişinău +Țepes +Ţepes +Ş +ţ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.test b/extensions/spellcheck/hunspell/tests/unit/data/iconv.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.aff b/extensions/spellcheck/hunspell/tests/unit/data/ignore.aff new file mode 100644 index 000000000..238dc15e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.aff @@ -0,0 +1,5 @@ +# ignore characters in words (for Arabic Harakat or Hebrew niqqud) +IGNORE aeiou + +PFX A Y 1 +PFX A 0 re . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.dic b/extensions/spellcheck/hunspell/tests/unit/data/ignore.dic new file mode 100644 index 000000000..846983b7d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.dic @@ -0,0 +1,3 @@ +2 +xmpl +expression/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.good b/extensions/spellcheck/hunspell/tests/unit/data/ignore.good new file mode 100644 index 000000000..d7dd645c2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.good @@ -0,0 +1,6 @@ +example +expression +xmpl +xprssn +reexpression +rxprssn diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.test b/extensions/spellcheck/hunspell/tests/unit/data/ignore.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.aff new file mode 100644 index 000000000..8646676d0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.aff @@ -0,0 +1,6 @@ +# Arabic test for feature ignoring diacritics +SET UTF-8 +# Arabic diacritics (harakat): +# sukun, shadda, kasra, damma, fatha, kasratan, dammantan, fathatan (left to right) +IGNORE ًٌٍَُِّْ +WORDCHARS ًٌٍَُِّْ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.dic new file mode 100644 index 000000000..d4a2a81e7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.dic @@ -0,0 +1,10 @@ +9 +طِير +فَتحة +ضُمة +كِسرة +فتحًتان +ضمتانٌ +كسرتاٍن +شدّة +سكوْن diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.good b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.good new file mode 100644 index 000000000..d463cd59f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.good @@ -0,0 +1,9 @@ +طير +فتحة +ضمة +كسرة +فتحتان +ضمتان +كسرتان +شدة +سكون diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.test b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.aff b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.aff new file mode 100644 index 000000000..b08006bf7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.aff @@ -0,0 +1,3 @@ +# keep case in signed words +KEEPCASE A +WORDCHARS . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.dic b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.dic new file mode 100644 index 000000000..bf9992acf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.dic @@ -0,0 +1,5 @@ +4 +foo/A +Bar/A +baz./A +Quux./A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.good b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.good new file mode 100644 index 000000000..e6ff1817d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.good @@ -0,0 +1,4 @@ +foo +Bar +baz. +Quux. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.sug b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.sug new file mode 100644 index 000000000..551dd8bb3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.sug @@ -0,0 +1,8 @@ +foo +foo +Bar +Bar +baz. +baz. +Quux. +Quux. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.test b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.wrong new file mode 100644 index 000000000..3b7914291 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.wrong @@ -0,0 +1,8 @@ +Foo +FOO +BAR +bar +Baz. +BAZ. +quux. +QUUX. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.aff b/extensions/spellcheck/hunspell/tests/unit/data/korean.aff new file mode 100644 index 000000000..979e3c228 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.aff @@ -0,0 +1 @@ +SET UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.dic b/extensions/spellcheck/hunspell/tests/unit/data/korean.dic new file mode 100644 index 000000000..95cb4508e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.dic @@ -0,0 +1,3 @@ +2 +들어오세요 +안녕하세요 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.good b/extensions/spellcheck/hunspell/tests/unit/data/korean.good new file mode 100644 index 000000000..660d506bb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.good @@ -0,0 +1,2 @@ +들어오세요 +안녕하세요 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.test b/extensions/spellcheck/hunspell/tests/unit/data/korean.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.wrong b/extensions/spellcheck/hunspell/tests/unit/data/korean.wrong new file mode 100644 index 000000000..5ea85cead --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.wrong @@ -0,0 +1 @@ +들어오세 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.aff b/extensions/spellcheck/hunspell/tests/unit/data/map.aff new file mode 100644 index 000000000..3e78baba6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.aff @@ -0,0 +1,9 @@ +# With MAP suggestion, Hunspell can add missing accents to a word. + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +MAP 3 +MAP u +MAP o +MAP (ss) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.dic b/extensions/spellcheck/hunspell/tests/unit/data/map.dic new file mode 100644 index 000000000..744394f0c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.dic @@ -0,0 +1,4 @@ +3 +Frhstck +tkrfr +gro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.sug b/extensions/spellcheck/hunspell/tests/unit/data/map.sug new file mode 100644 index 000000000..cadb75422 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.sug @@ -0,0 +1,3 @@ +Frhstck +tkrfr +gro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.test b/extensions/spellcheck/hunspell/tests/unit/data/map.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.wrong b/extensions/spellcheck/hunspell/tests/unit/data/map.wrong new file mode 100644 index 000000000..251c8a1e9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.wrong @@ -0,0 +1,3 @@ +Fruhstuck +tukorfuro +gross diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.aff b/extensions/spellcheck/hunspell/tests/unit/data/maputf.aff new file mode 100644 index 000000000..30edb2a78 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.aff @@ -0,0 +1,11 @@ +# With MAP suggestion, Hunspell can add missing accents to a word. + +SET UTF-8 + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +MAP 3 +MAP uúü +MAP öóo +MAP ß(ss) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.dic b/extensions/spellcheck/hunspell/tests/unit/data/maputf.dic new file mode 100644 index 000000000..1c6fa8d05 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.dic @@ -0,0 +1,4 @@ +3 +Frühstück +tükörfúró +groß diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.sug b/extensions/spellcheck/hunspell/tests/unit/data/maputf.sug new file mode 100644 index 000000000..81d09e021 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.sug @@ -0,0 +1,3 @@ +Frühstück +tükörfúró +groß diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.test b/extensions/spellcheck/hunspell/tests/unit/data/maputf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/maputf.wrong new file mode 100644 index 000000000..251c8a1e9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.wrong @@ -0,0 +1,3 @@ +Fruhstuck +tukorfuro +gross diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.aff b/extensions/spellcheck/hunspell/tests/unit/data/morph.aff new file mode 100644 index 000000000..608085860 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.aff @@ -0,0 +1,12 @@ +# example for morphological analysis, stemming and generation +PFX P Y 1 +PFX P 0 un . dp:pfx_un sp:un + +SFX S Y 1 +SFX S 0 s . is:plur + +SFX Q Y 1 +SFX Q 0 s . is:sg_3 + +SFX R Y 1 +SFX R 0 able/PS . ds:der_able diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.dic b/extensions/spellcheck/hunspell/tests/unit/data/morph.dic new file mode 100644 index 000000000..f8d58a6d4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.dic @@ -0,0 +1,10 @@ +9 +drink/S po:noun +drink/RQ po:verb al:drank al:drunk ts:present +drank po:verb st:drink is:past_1 +drunk po:verb st:drink is:past_2 +eat/RQ po:verb al:ate al:eaten ts:present +ate po:verb st:eat is:past_1 +eaten po:verb st:eat is:past_2 +phenomenon po:noun al:phenomena +phenomena po:noun st:phenomenon is:plur diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.good b/extensions/spellcheck/hunspell/tests/unit/data/morph.good new file mode 100644 index 000000000..9f0d24768 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.good @@ -0,0 +1,26 @@ +drink +drinks +drinkable +drinkables +undrinkable +undrinkables +drank +drunk +phenomenon +phenomena +drink eat +drink eats +drink ate +drink eaten +drink eatable +drink eatables +drink phenomena +drinks eat +drinks eats +drinks ate +drinks eaten +drinks eatable +drinks eatables +drinks phenomena +undrinkable phenomena +phenomenon drinks diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.morph b/extensions/spellcheck/hunspell/tests/unit/data/morph.morph new file mode 100644 index 000000000..9965d7ea8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.morph @@ -0,0 +1,48 @@ +> drink +analyze(drink) = st:drink po:noun +analyze(drink) = st:drink po:verb al:drank al:drunk ts:present +stem(drink) = drink +> drinks +analyze(drinks) = st:drink po:verb al:drank al:drunk ts:present is:sg_3 +analyze(drinks) = st:drink po:noun is:plur +stem(drinks) = drink +> drinkable +analyze(drinkable) = st:drink po:verb al:drank al:drunk ts:present ds:der_able +stem(drinkable) = drinkable +> drinkables +analyze(drinkables) = st:drink po:verb al:drank al:drunk ts:present ds:der_able is:plur +stem(drinkables) = drinkable +> undrinkable +analyze(undrinkable) = dp:pfx_un sp:un st:drink po:verb al:drank al:drunk ts:present ds:der_able +stem(undrinkable) = undrinkable +> undrinkables +analyze(undrinkables) = dp:pfx_un sp:un st:drink po:verb al:drank al:drunk ts:present ds:der_able is:plur +stem(undrinkables) = undrinkable +> drank +analyze(drank) = po:verb st:drink is:past_1 +stem(drank) = drink +> drunk +analyze(drunk) = po:verb st:drink is:past_2 +stem(drunk) = drink +> phenomenon +analyze(phenomenon) = st:phenomenon po:noun al:phenomena +stem(phenomenon) = phenomenon +> phenomena +analyze(phenomena) = po:noun st:phenomenon is:plur +stem(phenomena) = phenomenon +generate(drink, eat) = drink +generate(drink, eats) = drinks +generate(drink, ate) = drank +generate(drink, eaten) = drunk +generate(drink, eatable) = drinkable +generate(drink, eatables) = drinkables +generate(drink, phenomena) = drinks +generate(drinks, eat) = drink +generate(drinks, eats) = drinks +generate(drinks, ate) = drank +generate(drinks, eaten) = drunk +generate(drinks, eatable) = drinkable +generate(drinks, eatables) = drinkables +generate(drinks, phenomena) = drinks +generate(undrinkable, phenomena) = undrinkables +generate(phenomenon, drinks) = phenomena diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.test b/extensions/spellcheck/hunspell/tests/unit/data/morph.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.aff new file mode 100644 index 000000000..a5981ef69 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.aff @@ -0,0 +1,5 @@ +NEEDAFFIX X +COMPOUNDFLAG Y + +SFX A Y 1 +SFX A 0 s/Y . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.dic new file mode 100644 index 000000000..b5792765e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.dic @@ -0,0 +1,3 @@ +2 +foo/YXA +bar/Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.good new file mode 100644 index 000000000..f9e0663f3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.good @@ -0,0 +1,3 @@ +bar +foos +barfoos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.wrong new file mode 100644 index 000000000..257cc5642 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.wrong @@ -0,0 +1 @@ +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.aff new file mode 100644 index 000000000..c434dac66 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.aff @@ -0,0 +1,2 @@ +NEEDAFFIX X +COMPOUNDFLAG Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.dic new file mode 100644 index 000000000..ff32e878b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.dic @@ -0,0 +1,5 @@ +4 +foo st:foo id:1 +foo/YX st:foo id:2 +foo/Y st:foo id:3 +bar/Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.good new file mode 100644 index 000000000..7e4b098ef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.good @@ -0,0 +1,5 @@ +foo +bar +foobar +barfoo + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.morph b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.morph new file mode 100644 index 000000000..0f3e47431 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.morph @@ -0,0 +1,13 @@ +> foo +analyze(foo) = st:foo id:1 +analyze(foo) = st:foo id:3 +stem(foo) = foo +> bar +analyze(bar) = st:bar +stem(bar) = bar +> foobar +analyze(foobar) = pa:foo st:foo id:3 pa:bar +stem(foobar) = foo +> barfoo +analyze(barfoo) = pa:bar st:bar pa:foo st:foo id:3 +stem(barfoo) = barfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.aff new file mode 100644 index 000000000..5d55d38e9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.aff @@ -0,0 +1,8 @@ +# neeadaffix on affixes +NEEDAFFIX X + +SFX A Y 1 +SFX A 0 s/XB . + +SFX B Y 1 +SFX B 0 baz . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.dic new file mode 100644 index 000000000..001d95e77 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.dic @@ -0,0 +1,2 @@ +2 +foo/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.good new file mode 100644 index 000000000..dc9a6a97d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.good @@ -0,0 +1,2 @@ +foo +foosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.wrong new file mode 100644 index 000000000..c09c408f2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.wrong @@ -0,0 +1 @@ +foos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.aff new file mode 100644 index 000000000..c434dac66 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.aff @@ -0,0 +1,2 @@ +NEEDAFFIX X +COMPOUNDFLAG Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.dic new file mode 100644 index 000000000..96f80c12b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.dic @@ -0,0 +1,5 @@ +4 +foo/X [1] +foo/Y [2] +foo/YX [3] +bar/Y [4] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.good new file mode 100644 index 000000000..7e4b098ef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.good @@ -0,0 +1,5 @@ +foo +bar +foobar +barfoo + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.aff new file mode 100644 index 000000000..6399a3e98 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.aff @@ -0,0 +1,13 @@ +# on affixes +NEEDAFFIX X + +SFX A Y 2 +SFX A 0 suf/B . +SFX A 0 pseudosuf/XB . + +SFX B Y 1 +SFX B 0 bar . + +PFX C Y 2 +PFX C 0 pre . +PFX C 0 pseudopre/X . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.dic new file mode 100644 index 000000000..83131e27a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.dic @@ -0,0 +1,2 @@ +1 +foo/AC diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.good new file mode 100644 index 000000000..d1b86bf83 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.good @@ -0,0 +1,11 @@ +foo +prefoo +foosuf +prefoosuf +foosufbar +prefoosufbar +pseudoprefoosuf +pseudoprefoosufbar +pseudoprefoopseudosufbar +prefoopseudosuf +prefoopseudosufbar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.wrong b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.wrong new file mode 100644 index 000000000..fdd1797fd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.wrong @@ -0,0 +1,3 @@ +pseudoprefoo +foopseudosuf +pseudoprefoopseudosuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.aff b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.aff new file mode 100644 index 000000000..19e698121 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.aff @@ -0,0 +1,21 @@ +# Test fix of suffixed ngram suggestions with UTF-8 encoding and long flags. +# Based on Vitaly Piryatinsky's bug report and example. +SET UTF-8 +FLAG num + +PFX 101 Y 1 +PFX 101 0 пред . + +SFX 1381 Y 1 +SFX 1381 0 о . + +SFX 2000 Y 3 +SFX 2000 0 ам . +SFX 2000 0 ами . +SFX 2000 0 ах . + +SFX 2022 Y 4 +SFX 2022 0 а . +SFX 2022 0 у . +SFX 2022 0 ом . +SFX 2022 0 е . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.dic b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.dic new file mode 100644 index 000000000..27ce413ae --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.dic @@ -0,0 +1,2 @@ +1 +человек/2022,2000,101 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.good b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.good new file mode 100644 index 000000000..366d92a9b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.good @@ -0,0 +1 @@ +человек diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.sug b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.sug new file mode 100644 index 000000000..58ab09b53 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.sug @@ -0,0 +1,2 @@ +человек +человек diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.test b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.wrong new file mode 100644 index 000000000..97de996e0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.wrong @@ -0,0 +1,2 @@ +времячко +человеко diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.aff b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.aff new file mode 100644 index 000000000..c9361da4c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.aff @@ -0,0 +1,5 @@ +# don't suggest word with NOSUGGEST flag (for example vulgar or obscene words) +# See OpenOffice.org Issue #55498 +# (nosuggest.sug is an empty file) +NOSUGGEST A +COMPOUNDFLAG B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.dic b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.dic new file mode 100644 index 000000000..dc80c916d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.dic @@ -0,0 +1,3 @@ +1 +foo/AB +bar/B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.good b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.good new file mode 100644 index 000000000..ad91a5e31 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.good @@ -0,0 +1,3 @@ +foo +foobar +barfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.sug b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.sug new file mode 100644 index 000000000..e69de29bb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.test b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.wrong b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.wrong new file mode 100644 index 000000000..89c7a1a9c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.wrong @@ -0,0 +1,3 @@ +foox +foobarx +barfoox diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.aff b/extensions/spellcheck/hunspell/tests/unit/data/oconv.aff new file mode 100644 index 000000000..13a3d9b20 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.aff @@ -0,0 +1,12 @@ +# output conversion +SET UTF-8 + +OCONV 7 +OCONV a A +OCONV á Á +OCONV b B +OCONV c C +OCONV d D +OCONV e E +OCONV é É + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.dic b/extensions/spellcheck/hunspell/tests/unit/data/oconv.dic new file mode 100644 index 000000000..359186cac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.dic @@ -0,0 +1,4 @@ +3 +bébé +dádá +aábcdeé diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.good b/extensions/spellcheck/hunspell/tests/unit/data/oconv.good new file mode 100644 index 000000000..6cdaab16e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.good @@ -0,0 +1,2 @@ +bébé +dádá diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.sug b/extensions/spellcheck/hunspell/tests/unit/data/oconv.sug new file mode 100644 index 000000000..a191c629d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.sug @@ -0,0 +1,3 @@ +BÉBÉ +DÁDÁ +AÁBCDEÉ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.test b/extensions/spellcheck/hunspell/tests/unit/data/oconv.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.wrong b/extensions/spellcheck/hunspell/tests/unit/data/oconv.wrong new file mode 100644 index 000000000..73dcc895a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.wrong @@ -0,0 +1,3 @@ +béb +dád +aábcde diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.aff b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.aff new file mode 100644 index 000000000..e700b0e54 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.aff @@ -0,0 +1,5 @@ +# words only in compounds (see also fogemorpheme example) +ONLYINCOMPOUND O +COMPOUNDFLAG A +SFX B Y 1 +SFX B 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.dic b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.dic new file mode 100644 index 000000000..dc742f7ab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.dic @@ -0,0 +1,3 @@ +2 +foo/A +pseudo/OAB diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.good b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.good new file mode 100644 index 000000000..151d59734 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.good @@ -0,0 +1,4 @@ +foo +pseudofoo +foopseudo +foopseudos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.sug b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.sug new file mode 100644 index 000000000..e69de29bb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.test b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.wrong b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.wrong new file mode 100644 index 000000000..115d0c617 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.wrong @@ -0,0 +1,2 @@ +pseudo +pseudos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.aff b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.aff new file mode 100644 index 000000000..5d0ac5e69 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.aff @@ -0,0 +1,12 @@ +# affixes only in compounds (see also fogemorpheme example) +ONLYINCOMPOUND O +COMPOUNDFLAG A +COMPOUNDPERMITFLAG P + +SFX B Y 1 +SFX B 0 s/OP . + +# obligate fogemorpheme by forbidding the stem (0) in compounds + +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN 0/B /A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.dic b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.dic new file mode 100644 index 000000000..1adab653b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.dic @@ -0,0 +1,3 @@ +2 +foo/A +pseudo/AB diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.good b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.good new file mode 100644 index 000000000..a31ce34ac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.good @@ -0,0 +1,3 @@ +foo +foopseudo +pseudosfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.test b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.wrong new file mode 100644 index 000000000..29a71a3c3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.wrong @@ -0,0 +1,3 @@ +pseudos +foopseudos +pseudofoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.aff new file mode 100644 index 000000000..413aca404 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.aff @@ -0,0 +1,13 @@ +FLAG long +COMPOUNDBEGIN Ca +COMPOUNDMIDDLE Cb +COMPOUNDEND Cc +COMPOUNDPERMITFLAG Cp +ONLYINCOMPOUND Cx + +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN /Ch /Xs + +SFX Ch Y 2 +SFX Ch 0 s/CaCbCxCp . +SFX Ch 0 s-/CaCbCcCp . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.dic new file mode 100644 index 000000000..e7831b704 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.dic @@ -0,0 +1,4 @@ +3 +schoonheid/Ch +port/CcXs +sport/Cc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.good new file mode 100644 index 000000000..fbaf830be --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.good @@ -0,0 +1 @@ +schoonheidssport diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.wrong new file mode 100644 index 000000000..3f9e8949b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.wrong @@ -0,0 +1 @@ +schoonheidsport diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.aff new file mode 100644 index 000000000..22dfe69d8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.aff @@ -0,0 +1,27 @@ +# Test file based on OpenTaal's Dutch dictionary, coded by Ruud Baars + +WORDCHARS - +NOSPLITSUGS +FLAG long + +COMPOUNDBEGIN Ca +COMPOUNDMIDDLE Cb +COMPOUNDEND Cc +COMPOUNDPERMITFLAG Cp +ONLYINCOMPOUND Cx + +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN 0/Ch /Xs +CHECKCOMPOUNDPATTERN 0/Xm /Xm + +SFX CA Y 2 +SFX CA 0 /CaCp . +SFX CA 0 -/CaCp . + +SFX CB Y 2 +SFX CB 0 /CbCp . +SFX CB 0 -/CbCp . + +SFX Ch Y 2 +SFX Ch 0 s/CaCbCxCp . +SFX Ch 0 s-/CaCbCcCp . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.dic new file mode 100644 index 000000000..52581e942 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.dic @@ -0,0 +1,4 @@ +100 +test/CACBCc +zout/CACBXm +suiker/CACBXm \ No newline at end of file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.good new file mode 100644 index 000000000..e604d6e2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.good @@ -0,0 +1 @@ +zout-suikertest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.wrong new file mode 100644 index 000000000..d8ddb16a5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.wrong @@ -0,0 +1 @@ +zoutsuikertest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.aff new file mode 100644 index 000000000..fa073432f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.aff @@ -0,0 +1,9 @@ +TRY r + +FORBIDDENWORD F +COMPOUNDRULE 2 +COMPOUNDRULE WW +COMPOUNDRULE WWW + +SFX S Y 1 +SFX S 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.dic new file mode 100644 index 000000000..44375948f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.dic @@ -0,0 +1,5 @@ +4 +foo/W +word/W +bar/WS +foowordbar/FS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.good new file mode 100644 index 000000000..73a96a784 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.good @@ -0,0 +1,3 @@ +fooword +wordbar +barwordfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.sug b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.sug new file mode 100644 index 000000000..60111a417 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.sug @@ -0,0 +1 @@ +barwordfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.wrong new file mode 100644 index 000000000..59dfddfb2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.wrong @@ -0,0 +1,5 @@ +foowordbar +foowordbars +foowordba +foowordbas +barwodfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.aff new file mode 100644 index 000000000..441354d6b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.aff @@ -0,0 +1,7 @@ +TRY r + +FORBIDDENWORD F +COMPOUNDFLAG W + +SFX S Y 1 +SFX S 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.dic new file mode 100644 index 000000000..895dd6230 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.dic @@ -0,0 +1,5 @@ +3 +foo/WS +word/W +bar/WS +foowordbar/FS \ No newline at end of file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.good new file mode 100644 index 000000000..17cf47de3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.good @@ -0,0 +1,4 @@ +fooword +wordbar +barwordfoo +barwordfoos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.sug b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.sug new file mode 100644 index 000000000..60111a417 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.sug @@ -0,0 +1 @@ +barwordfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.wrong new file mode 100644 index 000000000..59dfddfb2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.wrong @@ -0,0 +1,5 @@ +foowordbar +foowordbars +foowordba +foowordbas +barwodfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.aff new file mode 100644 index 000000000..15c914bec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.aff @@ -0,0 +1,8 @@ +KEEPCASE K +COMPOUNDBEGIN B +COMPOUNDEND E +COMPOUNDFLAG C +COMPOUNDMIN 1 +WORDCHARS - +BREAK 1 +BREAK # diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.dic new file mode 100644 index 000000000..b05ec131a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.dic @@ -0,0 +1,7 @@ +5 +tv-/KB +-tv/KE +word/C +NATO-/B +-NATO/E + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.good new file mode 100644 index 000000000..e1c112910 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.good @@ -0,0 +1,4 @@ +tv-word +word-tv +NATO-word +word-NATO diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.sug b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.sug new file mode 100644 index 000000000..07dde3fe6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.sug @@ -0,0 +1,8 @@ +Tv-word, Tv- word, Word +Tv- word, Word +word -tv, word-tv, word +word -tv, word-tv, word +wordword-tv, word +Tv-word-tv +NATO- +-NATO diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.wrong new file mode 100644 index 000000000..b15752ed2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.wrong @@ -0,0 +1,8 @@ +TV-word +Tv-word +word-TV +word-Tv +wordword-TV +TV-word-TV +Nato-word +word-nato diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.aff b/extensions/spellcheck/hunspell/tests/unit/data/phone.aff new file mode 100644 index 000000000..5a27c14d7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.aff @@ -0,0 +1,255 @@ +# phonetic suggestions by PHONE and optional ph field of dictionary words +# Documentationo of PHONE: http://aspell.net/man-html/Phonetic-Code.html + +# phonetic_english.h - phonetic transformation rules for use with phonetic.c +# Copyright (C) 2000 Björn Jacke +# +# This rule set is based on Lawrence Phillips original metaphone +# algorithm with modifications made by Michael Kuhn in his +# C implantation, more modifications by Björn Jacke when +# converting the algorithm to a rule set and minor +# touch ups by Kevin Atkinson +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1 as published by the Free Software Foundation; +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Björn Jacke may be reached by email at bjoern.jacke@gmx.de +# +# Changelog: +# +# 2000-01-05 Björn Jacke +# - first version with translation rules derived from +# metaphone.cc distributed with aspell 0.28.3 +# - "TH" is now representated as "@" because "0" is a +# meta character +# - removed TH(!vowel) --> T; always use TH --> # instead +# - dropped "^AE" -> "E" (redundant) +# - "ing" is transformed to "N", not "NK" +# - "SCH(EO)" transforms to "SK" now +# - added R --> SILENT if (after a vowel) and no (vowel or +# "y" follows) like in "Marcy" or "abort" +# - H is SILENT in RH at beginning of words +# - H is SILENT if vowel leads and "Y" follows +# - some ".OUGH.." --> ...F exceptions added +# - "^V" transforms to "W" +# 2000-01-07 Kevin Atkinson +# Converted from header to data file. +# +# 2007-08-23 László Németh +# Add PHONE header and PHONE keywords +# +# version 1.1 + +PHONE 105 +PHONE AH(AEIOUY)-^ *H +PHONE AR(AEIOUY)-^ *R +PHONE A(HR)^ * +PHONE A^ * +PHONE AH(AEIOUY)- H +PHONE AR(AEIOUY)- R +PHONE A(HR) _ +PHONE BB- _ +PHONE B B +PHONE CQ- _ +PHONE CIA X +PHONE CH X +PHONE C(EIY)- S +PHONE CK K +PHONE COUGH^ KF +PHONE CC< C +PHONE C K +PHONE DG(EIY) K +PHONE DD- _ +PHONE D T +PHONE < E +PHONE EH(AEIOUY)-^ *H +PHONE ER(AEIOUY)-^ *R +PHONE E(HR)^ * +PHONE ENOUGH^$ *NF +PHONE E^ * +PHONE EH(AEIOUY)- H +PHONE ER(AEIOUY)- R +PHONE E(HR) _ +PHONE FF- _ +PHONE F F +PHONE GN^ N +PHONE GN$ N +PHONE GNS$ NS +PHONE GNED$ N +PHONE GH(AEIOUY)- K +PHONE GH _ +PHONE GG9 K +PHONE G K +PHONE H H +PHONE IH(AEIOUY)-^ *H +PHONE IR(AEIOUY)-^ *R +PHONE I(HR)^ * +PHONE I^ * +PHONE ING6 N +PHONE IH(AEIOUY)- H +PHONE IR(AEIOUY)- R +PHONE I(HR) _ +PHONE J K +PHONE KN^ N +PHONE KK- _ +PHONE K K +PHONE LAUGH^ LF +PHONE LL- _ +PHONE L L +PHONE MB$ M +PHONE MM M +PHONE M M +PHONE NN- _ +PHONE N N +PHONE OH(AEIOUY)-^ *H +PHONE OR(AEIOUY)-^ *R +PHONE O(HR)^ * +PHONE O^ * +PHONE OH(AEIOUY)- H +PHONE OR(AEIOUY)- R +PHONE O(HR) _ +PHONE PH F +PHONE PN^ N +PHONE PP- _ +PHONE P P +PHONE Q K +PHONE RH^ R +PHONE ROUGH^ RF +PHONE RR- _ +PHONE R R +PHONE SCH(EOU)- SK +PHONE SC(IEY)- S +PHONE SH X +PHONE SI(AO)- X +PHONE SS- _ +PHONE S S +PHONE TI(AO)- X +PHONE TH @ +PHONE TCH-- _ +PHONE TOUGH^ TF +PHONE TT- _ +PHONE T T +PHONE UH(AEIOUY)-^ *H +PHONE UR(AEIOUY)-^ *R +PHONE U(HR)^ * +PHONE U^ * +PHONE UH(AEIOUY)- H +PHONE UR(AEIOUY)- R +PHONE U(HR) _ +PHONE V^ W +PHONE V F +PHONE WR^ R +PHONE WH^ W +PHONE W(AEIOU)- W +PHONE X^ S +PHONE X KS +PHONE Y(AEIOU)- Y +PHONE ZZ- _ +PHONE Z S + +#The rules in a different view: +# +# Exceptions: +# +# Beginning of word: "gn", "kn-", "pn-", "wr-" ----> drop first letter +# "Aebersold", "Gnagy", "Knuth", "Pniewski", "Wright" +# +# Beginning of word: "x" ----> change to "s" +# as in "Deng Xiaopeng" +# +# Beginning of word: "wh-" ----> change to "w" +# as in "Whalen" +# Beginning of word: leading vowels are transformed to "*" +# +# "[crt]ough" and "enough" are handled separately because of "F" sound +# +# +# A --> A at beginning +# _ otherwise +# +# B --> B unless at the end of word after "m", as in "dumb", "McComb" +# +# C --> X (sh) if "-cia-" or "-ch-" +# S if "-ci-", "-ce-", or "-cy-" +# SILENT if "-sci-", "-sce-", or "-scy-", or "-cq-" +# K otherwise, including in "-sch-" +# +# D --> K if in "-dge-", "-dgy-", or "-dgi-" +# T otherwise +# +# E --> A at beginnig +# _ SILENT otherwise +# +# F --> F +# +# G --> SILENT if in "-gh-" and not at end or before a vowel +# in "-gn" or "-gned" or "-gns" +# in "-dge-" etc., as in above rule +# K if before "i", or "e", or "y" if not double "gg" +# +# K otherwise (incl. "GG"!) +# +# H --> SILENT if after vowel and no vowel or "Y" follows +# or after "-ch-", "-sh-", "-ph-", "-th-", "-gh-" +# or after "rh-" at beginning +# H otherwise +# +# I --> A at beginning +# _ SILENT otherwise +# +# J --> K +# +# K --> SILENT if after "c" +# K otherwise +# +# L --> L +# +# M --> M +# +# N --> N +# +# O --> A at beginning +# _ SILENT otherwise +# +# P --> F if before "h" +# P otherwise +# +# Q --> K +# +# R --> SILENT if after vowel and no vowel or "Y" follows +# R otherwise +# +# S --> X (sh) if before "h" or in "-sio-" or "-sia-" +# SK if followed by "ch(eo)" (SCH(EO)) +# S otherwise +# +# T --> X (sh) if "-tia-" or "-tio-" +# 0 (th) if before "h" +# silent if in "-tch-" +# T otherwise +# +# U --> A at beginning +# _ SILENT otherwise +# +# V --> V if first letter of word +# F otherwise +# +# W --> SILENT if not followed by a vowel +# W if followed by a vowel +# +# X --> KS +# +# Y --> SILENT if not followed by a vowel +# Y if followed by a vowel +# +# Z --> S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.dic b/extensions/spellcheck/hunspell/tests/unit/data/phone.dic new file mode 100644 index 000000000..51b0743d0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.dic @@ -0,0 +1,11 @@ +10 +Brasilia +brassily +Brazilian +brilliance +brilliancy +brilliant +brain +brass +Churchillian +xxxxxxxxxx ph:Brasilia diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.sug b/extensions/spellcheck/hunspell/tests/unit/data/phone.sug new file mode 100644 index 000000000..cc22e3798 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.sug @@ -0,0 +1 @@ +Brasilia, Xxxxxxxxxx, Brilliant, Brazilian, Brassily, Brilliance diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.test b/extensions/spellcheck/hunspell/tests/unit/data/phone.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.wrong b/extensions/spellcheck/hunspell/tests/unit/data/phone.wrong new file mode 100644 index 000000000..ca9db395e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.wrong @@ -0,0 +1 @@ +Brasillian diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.aff b/extensions/spellcheck/hunspell/tests/unit/data/rep.aff new file mode 100644 index 000000000..485755c89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.aff @@ -0,0 +1,21 @@ +# With REP suggestions, we can fix typical language specific misspellings. + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +REP 8 +REP f ph +REP ph f +REP shun$ tion +REP ^alot$ a_lot # add the highest priority for "a lot" suggestion to "alot" +REP ^foo$ bar +REP ' _ # "un'alunno" -> "un alunno" +REP ^vinten$ vinte_e_un +REP s 's + + +SFX A Y 1 +SFX A 0 's . + + +WORDCHARS ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.dic b/extensions/spellcheck/hunspell/tests/unit/data/rep.dic new file mode 100644 index 000000000..f9a4c008b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.dic @@ -0,0 +1,15 @@ +10 +form +phantom +vacation +vacations +a +lot +un +alunno +bar +barbars +vinte +e +un +auto/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.sug b/extensions/spellcheck/hunspell/tests/unit/data/rep.sug new file mode 100644 index 000000000..b48a5b80e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.sug @@ -0,0 +1,8 @@ +form +phantom +vacation +a lot, lot +un alunno +bar +vinte e un +auto's, auto diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.test b/extensions/spellcheck/hunspell/tests/unit/data/rep.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.wrong b/extensions/spellcheck/hunspell/tests/unit/data/rep.wrong new file mode 100644 index 000000000..cd9699c4c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.wrong @@ -0,0 +1,11 @@ +phorm +fantom +vacashun +vacashuns +alot +un'alunno +foo +foobars +barfoos +vinten +autos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.aff b/extensions/spellcheck/hunspell/tests/unit/data/reputf.aff new file mode 100644 index 000000000..ac434a426 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.aff @@ -0,0 +1,9 @@ +# With REP suggestions, we can fix typical language specific misspellings. + +SET UTF-8 + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +REP 1 +REP oo őő diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.dic b/extensions/spellcheck/hunspell/tests/unit/data/reputf.dic new file mode 100644 index 000000000..1890fcb8e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.dic @@ -0,0 +1,2 @@ +1 +főő diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.sug b/extensions/spellcheck/hunspell/tests/unit/data/reputf.sug new file mode 100644 index 000000000..8a00bc371 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.sug @@ -0,0 +1 @@ +főő diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.test b/extensions/spellcheck/hunspell/tests/unit/data/reputf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/reputf.wrong new file mode 100644 index 000000000..257cc5642 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.wrong @@ -0,0 +1 @@ +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.aff b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.aff new file mode 100644 index 000000000..3ab347319 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.aff @@ -0,0 +1,8 @@ +# Forbid compound word with triple letters +CHECKCOMPOUNDTRIPLE +# Allow simplified forms +SIMPLIFIEDTRIPLE + +COMPOUNDMIN 2 + +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.dic b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.dic new file mode 100644 index 000000000..cfe7a35dc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.dic @@ -0,0 +1,3 @@ +2 +glass/A +sko/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.good b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.good new file mode 100644 index 000000000..23a4815e8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.good @@ -0,0 +1,3 @@ +glass +sko +glassko diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.test b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.wrong b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.wrong new file mode 100644 index 000000000..281128768 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.wrong @@ -0,0 +1 @@ +glasssko diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.aff b/extensions/spellcheck/hunspell/tests/unit/data/slash.aff new file mode 100644 index 000000000..6ab104b9e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.aff @@ -0,0 +1,4 @@ +# slashes in words (\/) + +# (only for tokenization) +WORDCHARS /: diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.dic b/extensions/spellcheck/hunspell/tests/unit/data/slash.dic new file mode 100644 index 000000000..478276df6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.dic @@ -0,0 +1,5 @@ +4 +/ +1\/2 +http:\/\/ +\/usr\/share\/myspell\/ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.good b/extensions/spellcheck/hunspell/tests/unit/data/slash.good new file mode 100644 index 000000000..4a25e205f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.good @@ -0,0 +1,4 @@ +/ +1/2 +http:// +/usr/share/myspell/ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.test b/extensions/spellcheck/hunspell/tests/unit/data/slash.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.aff b/extensions/spellcheck/hunspell/tests/unit/data/sug.aff new file mode 100644 index 000000000..b1f2adba6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.aff @@ -0,0 +1,15 @@ +# new suggestion methods of Hunspell 1.5: +# capitalization: nasa -> NASA +# long swap: permenant -> permanent +# long mov: Ghandi -> Gandhi +# double two characters: vacacation -> vacation +# space with REP: "alot" -> "a lot" ("a lot" need to be in the dic file.) + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 +REP 1 +REP alot a_lot +KEY qwertzuiop|asdfghjkl|yxcvbnm|aq +WORDCHARS . +FORBIDDENWORD ? + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.dic b/extensions/spellcheck/hunspell/tests/unit/data/sug.dic new file mode 100644 index 000000000..0c22cedf4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.dic @@ -0,0 +1,11 @@ +1 +NASA +Gandhi +grateful +permanent +vacation +a +lot +have +which +McDonald diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.sug b/extensions/spellcheck/hunspell/tests/unit/data/sug.sug new file mode 100644 index 000000000..e277bdb77 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.sug @@ -0,0 +1,12 @@ +NASA +Gandhi +grateful +permanent +vacation +a lot, lot +permanent. Vacation +have +which +Gandhi +McDonald +permanent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.test b/extensions/spellcheck/hunspell/tests/unit/data/sug.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.wrong b/extensions/spellcheck/hunspell/tests/unit/data/sug.wrong new file mode 100644 index 000000000..4d184d5a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.wrong @@ -0,0 +1,12 @@ +nasa +Ghandi +greatful +permenant +vacacation +alot +permanent.Vacation +ahev +hwihc +GAndhi +Mcdonald +permqnent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/List_of_common_misspellings.txt b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/List_of_common_misspellings.txt new file mode 100644 index 000000000..571f3796a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/List_of_common_misspellings.txt @@ -0,0 +1,4020 @@ +# source: http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines +abandonned abandoned +aberation aberration +abilties abilities +abilty ability +abondon abandon +abondoned abandoned +abondoning abandoning +abondons abandons +aborigene aborigine +abortificant abortifacient +abreviated abbreviated +abreviation abbreviation +abritrary arbitrary +absense absence +absolutly absolutely +absorbsion absorption +absorbtion absorption +abundacies abundances +abundancies abundances +abundunt abundant +abutts abuts +acadamy academy +acadmic academic +accademic academic +accademy academy +acccused accused +accelleration acceleration +accension accession, ascension +acceptence acceptance +acceptible acceptable +accessable accessible +accidentaly accidentally +accidently accidentally +acclimitization acclimatization +acommodate accommodate +accomadate accommodate +accomadated accommodated +accomadates accommodates +accomadating accommodating +accomadation accommodation +accomadations accommodations +accomdate accommodate +accomodate accommodate +accomodated accommodated +accomodates accommodates +accomodating accommodating +accomodation accommodation +accomodations accommodations +accompanyed accompanied +accordeon accordion +accordian accordion +accoring according +accoustic acoustic +accquainted acquainted +accross across +accussed accused +acedemic academic +acheive achieve +acheived achieved +acheivement achievement +acheivements achievements +acheives achieves +acheiving achieving +acheivment achievement +acheivments achievements +achievment achievement +achievments achievements +achive achieve, archive +achived achieved, archived +achivement achievement +achivements achievements +acknowldeged acknowledged +acknowledgeing acknowledging +ackward awkward, backward +acomplish accomplish +acomplished accomplished +acomplishment accomplishment +acomplishments accomplishments +acording according +acordingly accordingly +acquaintence acquaintance +acquaintences acquaintances +acquiantence acquaintance +acquiantences acquaintances +acquited acquitted +activites activities +activly actively +actualy actually +acuracy accuracy +acused accused +acustom accustom +acustommed accustomed +adavanced advanced +adbandon abandon +additinally additionally +additionaly additionally +addmission admission +addopt adopt +addopted adopted +addoptive adoptive +addres address, adders +addresable addressable +addresed addressed +addresing addressing +addressess addresses +addtion addition +addtional additional +adecuate adequate +adhearing adhering +adherance adherence +admendment amendment +admininistrative administrative +adminstered administered +adminstrate administrate +adminstration administration +adminstrative administrative +adminstrator administrator +admissability admissibility +admissable admissible +admited admitted +admitedly admittedly +adn and +adolecent adolescent +adquire acquire +adquired acquired +adquires acquires +adquiring acquiring +adres address +adresable addressable +adresing addressing +adress address +adressable addressable +adressed addressed +adressing addressing, dressing +adventrous adventurous +advertisment advertisement +advertisments advertisements +advesary adversary +adviced advised +aeriel aerial +aeriels aerials +afair affair +afficianados aficionados +afficionado aficionado +afficionados aficionados +affilate affiliate +affilliate affiliate +affort afford, effort +aforememtioned aforementioned +againnst against +agains against +agaisnt against +aganist against +aggaravates aggravates +aggreed agreed +aggreement agreement +aggregious egregious +aggresive aggressive +agian again +agianst against +agin again +agina again, angina +aginst against +agravate aggravate +agre agree +agred agreed +agreeement agreement +agreemnt agreement +agregate aggregate +agregates aggregates +agreing agreeing +agression aggression +agressive aggressive +agressively aggressively +agressor aggressor +agricuture agriculture +agrieved aggrieved +ahev have +ahppen happen +ahve have +aicraft aircraft +aiport airport +airbourne airborne +aircaft aircraft +aircrafts aircraft +airporta airports +airrcraft aircraft +aisian asian +albiet albeit +alchohol alcohol +alchoholic alcoholic +alchol alcohol +alcholic alcoholic +alcohal alcohol +alcoholical alcoholic +aledge allege +aledged alleged +aledges alleges +alege allege +aleged alleged +alegience allegiance +algebraical algebraic +algorhitms algorithms +algoritm algorithm +algoritms algorithms +alientating alienating +alledge allege +alledged alleged +alledgedly allegedly +alledges alleges +allegedely allegedly +allegedy allegedly +allegely allegedly +allegence allegiance +allegience allegiance +allign align +alligned aligned +alliviate alleviate +allopone allophone +allopones allophones +allready already +allthough although +alltime all-time +alltogether altogether +almsot almost +alochol alcohol +alomst almost +alot a lot, allot +alotted allotted +alowed allowed +alowing allowing +alreayd already +alse else +alsot also +alternitives alternatives +altho although +althought although +altough although +alusion allusion, illusion +alwasy always +alwyas always +amalgomated amalgamated +amatuer amateur +amature armature, amateur +amendmant amendment +amerliorate ameliorate +amke make +amking making +ammend amend +ammended amended +ammendment amendment +ammendments amendments +ammount amount +ammused amused +amoung among +amoungst amongst +amung among +analagous analogous +analitic analytic +analogeous analogous +anarchim anarchism +anarchistm anarchism +anbd and +ancestory ancestry +ancilliary ancillary +androgenous androgynous +androgeny androgyny +anihilation annihilation +aniversary anniversary +annoint anoint +annointed anointed +annointing anointing +annoints anoints +annouced announced +annualy annually +annuled annulled +anohter another +anomolies anomalies +anomolous anomalous +anomoly anomaly +anonimity anonymity +anounced announced +ansalisation nasalisation +ansalization nasalization +ansestors ancestors +antartic antarctic +anthromorphization anthropomorphization +anual annual, anal +anulled annulled +anwsered answered +anyhwere anywhere +anyother any other +anytying anything +aparent apparent +aparment apartment +apenines apennines, Apennines +aplication application +aplied applied +apolegetics apologetics +apon upon, apron +apparant apparent +apparantly apparently +appart apart +appartment apartment +appartments apartments +appealling appealing, appalling +appeareance appearance +appearence appearance +appearences appearances +appenines apennines, Apennines +apperance appearance +apperances appearances +applicaiton application +applicaitons applications +appologies apologies +appology apology +apprearance appearance +apprieciate appreciate +approachs approaches +appropiate appropriate +appropraite appropriate +appropropiate appropriate +approproximate approximate +approxamately approximately +approxiately approximately +approximitely approximately +aprehensive apprehensive +apropriate appropriate +aproximate approximate +aproximately approximately +aquaintance acquaintance +aquainted acquainted +aquiantance acquaintance +aquire acquire +aquired acquired +aquiring acquiring +aquisition acquisition +aquitted acquitted +aranged arranged +arangement arrangement +arbitarily arbitrarily +arbitary arbitrary +archaelogists archaeologists +archaelogy archaeology +archaoelogy archeology, archaeology +archaology archeology, archaeology +archeaologist archeologist, archaeologist +archeaologists archeologists, archaeologists +archetect architect +archetects architects +archetectural architectural +archetecturally architecturally +archetecture architecture +archiac archaic +archictect architect +archimedian archimedean +architechturally architecturally +architechture architecture +architechtures architectures +architectual architectural +archtype archetype +archtypes archetypes +aready already +areodynamics aerodynamics +argubly arguably +arguement argument +arguements arguments +arised arose +arival arrival +armamant armament +armistace armistice +aroud around +arrangment arrangement +arrangments arrangements +arround around +artical article +artice article +articel article +artifical artificial +artifically artificially +artillary artillery +arund around +asetic ascetic +asign assign +aslo also +asociated associated +asorbed absorbed +asphyxation asphyxiation +assasin assassin +assasinate assassinate +assasinated assassinated +assasinates assassinates +assasination assassination +assasinations assassinations +assasined assassinated +assasins assassins +assassintation assassination +assemple assemble +assertation assertion +asside aside +assisnate assassinate +assit assist +assitant assistant +assocation association +assoicate associate +assoicated associated +assoicates associates +assosication assassination +asssassans assassins +assualt assault +assualted assaulted +assymetric asymmetric +assymetrical asymmetrical +asteriod asteroid +asthetic aesthetic +asthetical aesthetical +asthetically aesthetically +asume assume +aswell as well +atain attain +atempting attempting +atheistical atheistic +athenean athenian +atheneans athenians +athiesm atheism +athiest atheist +atorney attorney +atribute attribute +atributed attributed +atributes attributes +attaindre attainder, attained +attemp attempt +attemped attempted +attemt attempt +attemted attempted +attemting attempting +attemts attempts +attendence attendance +attendent attendant +attendents attendants +attened attended +attension attention +attitide attitude +attributred attributed +attrocities atrocities +audeince audience +auromated automated +austrailia Australia +austrailian Australian +auther author +authobiographic autobiographic +authobiography autobiography +authorative authoritative +authorites authorities +authorithy authority +authoritiers authorities +authoritive authoritative +authrorities authorities +autochtonous autochthonous +autoctonous autochthonous +automaticly automatically +automibile automobile +automonomous autonomous +autor author +autority authority +auxilary auxiliary +auxillaries auxiliaries +auxillary auxiliary +auxilliaries auxiliaries +auxilliary auxiliary +availablity availability +availaible available +availble available +availiable available +availible available +avalable available +avalance avalanche +avaliable available +avation aviation +avengence a vengeance +averageed averaged +avilable available +awared awarded +awya away +baceause because +backgorund background +backrounds backgrounds +bakc back +banannas bananas +bandwith bandwidth +bankrupcy bankruptcy +banruptcy bankruptcy +baout about, bout +basicaly basically +basicly basically +bcak back +beachead beachhead +beacuse because +beastiality bestiality +beatiful beautiful +beaurocracy bureaucracy +beaurocratic bureaucratic +beautyfull beautiful +becamae became +becasue because +beccause because +becomeing becoming +becomming becoming +becouse because +becuase because +bedore before +befoer before +beggin begin, begging +begginer beginner +begginers beginners +beggining beginning +begginings beginnings +beggins begins +begining beginning +beginnig beginning +behavour behavior, behaviour +beleagured beleaguered +beleif belief +beleive believe +beleived believed +beleives believes +beleiving believing +beligum belgium +belive believe +belived believed +belives believes, beliefs +belligerant belligerent +bellweather bellwether +bemusemnt bemusement +beneficary beneficiary +beng being +benificial beneficial +benifit benefit +benifits benefits +bergamont bergamot +Bernouilli Bernoulli +beseige besiege +beseiged besieged +beseiging besieging +betwen between +beween between +bewteen between +bilateraly bilaterally +billingualism bilingualism +binominal binomial +bizzare bizarre +blaim blame +blaimed blamed +blessure blessing +Blitzkreig Blitzkrieg +boaut bout, boat, about +bodydbuilder bodybuilder +bombardement bombardment +bombarment bombardment +bondary boundary +Bonnano Bonanno +borke broke +boundry boundary +bouyancy buoyancy +bouyant buoyant +boyant buoyant +Brasillian Brazilian +breakthough breakthrough +breakthroughts breakthroughs +breif brief +breifly briefly +brethen brethren +bretheren brethren +briliant brilliant +brillant brilliant +brimestone brimstone +Britian Britain +Brittish British +broacasted broadcast +broadacasting broadcasting +broady broadly +Buddah Buddha +buisness business +buisnessman businessman +buoancy buoyancy +buring burying, burning, burin, during +burried buried +busineses business, businesses +busness business +bussiness business +cacuses caucuses +cahracters characters +calaber caliber +calander calendar, calender, colander +calculs calculus +calenders calendars +caligraphy calligraphy +caluclate calculate +caluclated calculated +caluculate calculate +caluculated calculated +calulate calculate +calulated calculated +Cambrige Cambridge +camoflage camouflage +campain campaign +campains campaigns +candadate candidate +candiate candidate +candidiate candidate +cannister canister +cannisters canisters +cannnot cannot +cannonical canonical +cannotation connotation +cannotations connotations +cant cannot, can not, can't +caost coast +caperbility capability +Capetown Cape Town +capible capable +captial capital +captued captured +capturd captured +carachter character +caracterized characterized +carcas carcass, Caracas +carefull careful +careing caring +carismatic charismatic +Carmalite Carmelite +carmel caramel, carmel-by-the-sea +carniverous carnivorous +carreer career +carrers careers +Carribbean Caribbean +Carribean Caribbean +cartdridge cartridge +Carthagian Carthaginian +carthographer cartographer +cartilege cartilage +cartilidge cartilage +cartrige cartridge +casette cassette +casion caisson +cassawory cassowary +cassowarry cassowary +casulaties casualties +casulaty casualty +catagories categories +catagorized categorized +catagory category +catergorize categorize +catergorized categorized +Cataline Catiline, Catalina +cathlic catholic +catholocism catholicism +catterpilar caterpillar +catterpilars caterpillars +cattleship battleship +causalities casualties +Ceasar Caesar +Celcius Celsius +cellpading cellpadding +cementary cemetery +cemetarey cemetery +cemetaries cemeteries +cemetary cemetery +cencus census +censur censor, censure +cententenial centennial +centruies centuries +centruy century +ceratin certain, keratin +cerimonial ceremonial +cerimonies ceremonies +cerimonious ceremonious +cerimony ceremony +ceromony ceremony +certainity certainty +certian certain +cervial cervical, servile, serval +chalenging challenging +challange challenge +challanged challenged +challege challenge +Champange Champagne +changable changeable +charachter character +charactor character +charachters characters +charactersistic characteristic +charactors characters +charasmatic charismatic +charaterized characterized +chariman chairman +charistics characteristics +chasr chaser, chase +cheif chief +chemcial chemical +chemcially chemically +chemestry chemistry +chemicaly chemically +childbird childbirth +childen children +choosen chosen +chracter character +chuch church +churchs churches +Cincinatti Cincinnati +Cincinnatti Cincinnati +circulaton circulation +circumsicion circumcision +circut circuit +ciricuit circuit +ciriculum curriculum +civillian civilian +claer clear +claerer clearer +claerly clearly +claimes claims +clas class +clasic classic +clasical classical +clasically classically +cleareance clearance +clera clear, sclera +clincial clinical +clinicaly clinically +cmo com +cmoputer computer +co-incided coincided +coctail cocktail +coform conform +cognizent cognizant +coincedentally coincidentally +colaborations collaborations +colateral collateral +colelctive collective +collaberative collaborative +collecton collection +collegue colleague +collegues colleagues +collonade colonnade +collonies colonies +collony colony +collosal colossal +colonizators colonizers +comander commander, commandeer +comando commando +comandos commandos +comany company +comapany company +comback comeback +combanations combinations +combinatins combinations +combusion combustion +comdemnation condemnation +comemmorates commemorates +comemoretion commemoration +comision commission +comisioned commissioned +comisioner commissioner +comisioning commissioning +comisions commissions +comission commission +comissioned commissioned +comissioner commissioner +comissioning commissioning +comissions commissions +comited committed +comiting committing +comitted committed +comittee committee +comitting committing +commandoes commandos +commedic comedic +commemerative commemorative +commemmorate commemorate +commemmorating commemorating +commerical commercial +commerically commercially +commericial commercial +commericially commercially +commerorative commemorative +comming coming +comminication communication +commision commission +commisioned commissioned +commisioner commissioner +commisioning commissioning +commisions commissions +commited committed +commitee committee +commiting committing +committe committee +committment commitment +committments commitments +commmemorated commemorated +commongly commonly +commonweath commonwealth +commuications communications +commuinications communications +communciation communication +communiation communication +communites communities +compability compatibility +comparision comparison +comparisions comparisons +comparitive comparative +comparitively comparatively +compatabilities compatibilities +compatability compatibility +compatable compatible +compatablities compatibilities +compatablity compatibility +compatiable compatible +compatiblities compatibilities +compatiblity compatibility +compeitions competitions +compensantion compensation +competance competence +competant competent +competative competitive +competion competition, completion +competitiion competition +competive competitive +competiveness competitiveness +comphrehensive comprehensive +compitent competent +completedthe completed the +completelyl completely +completetion completion +complier compiler +componant component +comprable comparable +comprimise compromise +compulsary compulsory +compulsery compulsory +computarized computerized +concensus consensus +concider consider +concidered considered +concidering considering +conciders considers +concieted conceited +concieved conceived +concious conscious +conciously consciously +conciousness consciousness +condamned condemned +condemmed condemned +condidtion condition +condidtions conditions +conditionsof conditions of +conected connected +conection connection +conesencus consensus +confidental confidential +confidentally confidentially +confids confides +configureable configurable +confortable comfortable +congradulations congratulations +congresional congressional +conived connived +conjecutre conjecture +conjuction conjunction +Conneticut Connecticut +conotations connotations +conquerd conquered +conquerer conqueror +conquerers conquerors +conqured conquered +conscent consent +consciouness consciousness +consdider consider +consdidered considered +consdiered considered +consectutive consecutive +consenquently consequently +consentrate concentrate +consentrated concentrated +consentrates concentrates +consept concept +consequentually consequently +consequeseces consequences +consern concern +conserned concerned +conserning concerning +conservitive conservative +consiciousness consciousness +consicousness consciousness +considerd considered +consideres considered +consious conscious +consistant consistent +consistantly consistently +consituencies constituencies +consituency constituency +consituted constituted +consitution constitution +consitutional constitutional +consolodate consolidate +consolodated consolidated +consonent consonant +consonents consonants +consorcium consortium +conspiracys conspiracies +conspiriator conspirator +constaints constraints +constanly constantly +constarnation consternation +constatn constant +constinually continually +constituant constituent +constituants constituents +constituion constitution +constituional constitutional +consttruction construction +constuction construction +consulant consultant +consumate consummate +consumated consummated +contaiminate contaminate +containes contains +contamporaries contemporaries +contamporary contemporary +contempoary contemporary +contemporaneus contemporaneous +contempory contemporary +contendor contender +contined continued +continous continuous +continously continuously +continueing continuing +contravercial controversial +contraversy controversy +contributer contributor +contributers contributors +contritutions contributions +controled controlled +controling controlling +controll control +controlls controls +controvercial controversial +controvercy controversy +controveries controversies +controversal controversial +controversey controversy +controvertial controversial +controvery controversy +contruction construction +conveinent convenient +convenant covenant +convential conventional +convertables convertibles +convertion conversion +conveyer conveyor +conviced convinced +convienient convenient +coordiantion coordination +coorperation cooperation, corporation +coorperations corporations +copmetitors competitors +coputer computer +copywrite copyright +coridal cordial +cornmitted committed +corosion corrosion +corparate corporate +corperations corporations +correcters correctors +correponding corresponding +correposding corresponding +correspondant correspondent +correspondants correspondents +corridoors corridors +corrispond correspond +corrispondant correspondent +corrispondants correspondents +corrisponded corresponded +corrisponding corresponding +corrisponds corresponds +costitution constitution +coucil council +coudl could, cloud +councellor councillor, counselor, councilor +councellors councillors, counselors, councilors +counries countries +countains contains +countires countries +coururier courier, couturier +coverted converted, covered, coveted +cpoy coy, copy +creaeted created +creedence credence +critereon criterion +criterias criteria +criticists critics +critising criticising, criticizing +critisising criticising +critisism criticism +critisisms criticisms +critisize criticise, criticize +critisized criticised, criticized +critisizes criticises, criticizes +critisizing criticising, criticizing +critized criticized +critizing criticizing +crockodiles crocodiles +crowm crown +crtical critical +crticised criticised +crucifiction crucifixion +crusies cruises +crystalisation crystallisation +culiminating culminating +cumulatative cumulative +curch church +curcuit circuit +currenly currently +curriculem curriculum +cxan cyan +cyclinder cylinder +dael deal, dial, dahl +dalmation dalmatian +damenor demeanor +Dardenelles Dardanelles +dacquiri daiquiri +debateable debatable +decendant descendant +decendants descendants +decendent descendant +decendents descendants +decideable decidable +decidely decidedly +decieved deceived +decison decision +decomissioned decommissioned +decomposit decompose +decomposited decomposed +decompositing decomposing +decomposits decomposes +decress decrees +decribe describe +decribed described +decribes describes +decribing describing +dectect detect +defendent defendant +defendents defendants +deffensively defensively +deffine define +deffined defined +definance defiance +definate definite +definately definitely +definatly definitely +definetly definitely +definining defining +definit definite +definitly definitely +definiton definition +defintion definition +degrate degrade +delagates delegates +delapidated dilapidated +delerious delirious +delevopment development +deliberatly deliberately +delusionally delusively +demenor demeanor +demographical demographic +demolision demolition +demorcracy democracy +demostration demonstration +denegrating denigrating +densly densely +deparment department +deparments departments +deparmental departmental +dependance dependence +dependancy dependency +dependant dependent +deram dram, dream +deriviated derived +derivitive derivative +derogitory derogatory +descendands descendants +descibed described +descision decision +descisions decisions +descriibes describes +descripters descriptors +descripton description +desctruction destruction +descuss discuss +desgined designed +deside decide +desigining designing +desinations destinations +desintegrated disintegrated +desintegration disintegration +desireable desirable +desitned destined +desktiop desktop +desorder disorder +desoriented disoriented +desparate desperate, disparate +despatched dispatched +despict depict +despiration desperation +dessicated desiccated +dessigned designed +destablized destabilized +destory destroy +detailled detailed +detatched detached +deteoriated deteriorated +deteriate deteriorate +deterioriating deteriorating +determinining determining +detremental detrimental +devasted devastated +develope develop +developement development +developped developed +develpment development +devels delves +devestated devastated +devestating devastating +devide divide +devided divided +devistating devastating +devolopement development +diablical diabolical +diamons diamonds +diaster disaster +dichtomy dichotomy +diconnects disconnects +dicover discover +dicovered discovered +dicovering discovering +dicovers discovers +dicovery discovery +dicussed discussed +didnt didn't +diea idea, die +dieing dying, dyeing +dieties deities +diety deity +diferent different +diferrent different +differentiatiations differentiations +differnt different +difficulity difficulty +diffrent different +dificulties difficulties +dificulty difficulty +dimenions dimensions +dimention dimension +dimentional dimensional +dimentions dimensions +dimesnional dimensional +diminuitive diminutive +diosese diocese +diphtong diphthong +diphtongs diphthongs +diplomancy diplomacy +dipthong diphthong +dipthongs diphthongs +dirived derived +disagreeed disagreed +disapeared disappeared +disapointing disappointing +disappearred disappeared +disaproval disapproval +disasterous disastrous +disatisfaction dissatisfaction +disatisfied dissatisfied +disatrous disastrous +discontentment discontent +discribe describe +discribed described +discribes describes +discribing describing +disctinction distinction +disctinctive distinctive +disemination dissemination +disenchanged disenchanted +disiplined disciplined +disobediance disobedience +disobediant disobedient +disolved dissolved +disover discover +dispair despair +disparingly disparagingly +dispence dispense +dispenced dispensed +dispencing dispensing +dispicable despicable +dispite despite +dispostion disposition +disproportiate disproportionate +disputandem disputandum +disricts districts +dissagreement disagreement +dissapear disappear +dissapearance disappearance +dissapeared disappeared +dissapearing disappearing +dissapears disappears +dissappear disappear +dissappears disappears +dissappointed disappointed +dissarray disarray +dissobediance disobedience +dissobediant disobedient +dissobedience disobedience +dissobedient disobedient +distiction distinction +distingish distinguish +distingished distinguished +distingishes distinguishes +distingishing distinguishing +distingquished distinguished +distrubution distribution +distruction destruction +distructive destructive +ditributed distributed +diversed diverse, diverged +divice device +divison division +divisons divisions +doccument document +doccumented documented +doccuments documents +docrines doctrines +doctines doctrines +documenatry documentary +doens does +doesnt doesn't +doign doing +dominaton domination +dominent dominant +dominiant dominant +donig doing +dosen't doesn't +doub doubt, daub +doulbe double +dowloads downloads +dramtic dramatic +draughtman draughtsman +Dravadian Dravidian +dreasm dreams +driectly directly +drnik drink +druming drumming +drummless drumless +dupicate duplicate +durig during +durring during +duting during +dyas dryas +eahc each +ealier earlier +earlies earliest +earnt earned +ecclectic eclectic +eceonomy economy +ecidious deciduous +eclispe eclipse +ecomonic economic +ect etc +eearly early +efel evil +effeciency efficiency +effecient efficient +effeciently efficiently +efficency efficiency +efficent efficient +efficently efficiently +efford effort, afford +effords efforts, affords +effulence effluence +eigth eighth, eight +eiter either +elction election +electic eclectic, electric +electon election, electron +electrial electrical +electricly electrically +electricty electricity +elementay elementary +eleminated eliminated +eleminating eliminating +eles eels +eletricity electricity +elicided elicited +eligable eligible +elimentary elementary +ellected elected +elphant elephant +embarass embarrass +embarassed embarrassed +embarassing embarrassing +embarassment embarrassment +embargos embargoes +embarras embarrass +embarrased embarrassed +embarrasing embarrassing +embarrasment embarrassment +embezelled embezzled +emblamatic emblematic +eminate emanate +eminated emanated +emision emission +emited emitted +emiting emitting +emition emission, emotion +emmediately immediately +emmigrated emigrated +emminent eminent, imminent +emminently eminently +emmisaries emissaries +emmisarries emissaries +emmisarry emissary +emmisary emissary +emmision emission +emmisions emissions +emmited emitted +emmiting emitting +emmitted emitted +emmitting emitting +emnity enmity +emperical empirical +emphaised emphasised +emphsis emphasis +emphysyma emphysema +empirial empirical, imperial +emprisoned imprisoned +enameld enameled +enchancement enhancement +encouraing encouraging +encryptiion encryption +encylopedia encyclopedia +endevors endeavors +endevour endeavour +endig ending +endolithes endoliths +enduce induce +ened need +enflamed inflamed +enforceing enforcing +engagment engagement +engeneer engineer +engeneering engineering +engieneer engineer +engieneers engineers +enlargment enlargement +enlargments enlargements +Enlish English, enlist +enourmous enormous +enourmously enormously +ensconsed ensconced +entaglements entanglements +enteratinment entertainment +entitity entity +entitlied entitled +entrepeneur entrepreneur +entrepeneurs entrepreneurs +enviorment environment +enviormental environmental +enviormentally environmentally +enviorments environments +enviornment environment +enviornmental environmental +enviornmentalist environmentalist +enviornmentally environmentally +enviornments environments +enviroment environment +enviromental environmental +enviromentalist environmentalist +enviromentally environmentally +enviroments environments +envolutionary evolutionary +envrionments environments +enxt next +epidsodes episodes +epsiode episode +equialent equivalent +equilibium equilibrium +equilibrum equilibrium +equiped equipped +equippment equipment +equitorial equatorial +equivelant equivalent +equivelent equivalent +equivilant equivalent +equivilent equivalent +equivlalent equivalent +erally orally, really +eratic erratic +eratically erratically +eraticly erratically +erested arrested, erected +errupted erupted +esential essential +esitmated estimated +esle else +especialy especially +essencial essential +essense essence +essentail essential +essentialy essentially +essentual essential +essesital essential +estabishes establishes +establising establishing +ethnocentricm ethnocentrism +ethose those, ethos +Europian European +Europians Europeans +Eurpean European +Eurpoean European +evenhtually eventually +eventally eventually +eventially eventually +eventualy eventually +everthing everything +everytime every time +everyting everything +eveyr every +evidentally evidently +exagerate exaggerate +exagerated exaggerated +exagerates exaggerates +exagerating exaggerating +exagerrate exaggerate +exagerrated exaggerated +exagerrates exaggerates +exagerrating exaggerating +examinated examined +exampt exempt +exapansion expansion +excact exact +excange exchange +excecute execute +excecuted executed +excecutes executes +excecuting executing +excecution execution +excedded exceeded +excelent excellent +excell excel +excellance excellence +excellant excellent +excells excels +excercise exercise +exchanching exchanging +excisted existed +exculsivly exclusively +execising exercising +exection execution +exectued executed +exeedingly exceedingly +exelent excellent +exellent excellent +exemple example +exept except +exeptional exceptional +exerbate exacerbate +exerbated exacerbated +exerciese exercises +exerpt excerpt +exerpts excerpts +exersize exercise +exerternal external +exhalted exalted +exhibtion exhibition +exibition exhibition +exibitions exhibitions +exicting exciting +exinct extinct +existance existence +existant existent +existince existence +exliled exiled +exludes excludes +exmaple example +exonorate exonerate +exoskelaton exoskeleton +expalin explain +expeced expected +expecially especially +expeditonary expeditionary +expeiments experiments +expell expel +expells expels +experiance experience +experianced experienced +expiditions expeditions +expierence experience +explaination explanation +explaning explaining +explictly explicitly +exploititive exploitative +explotation exploitation +expropiated expropriated +expropiation expropriation +exressed expressed +extemely extremely +extention extension +extentions extensions +extered exerted +extermist extremist +extint extinct, extant +extradiction extradition +extraterrestial extraterrestrial +extraterrestials extraterrestrials +extravagent extravagant +extrememly extremely +extremeophile extremophile +extremly extremely +extrordinarily extraordinarily +extrordinary extraordinary +eyar year, eyas +eyars years, eyas +eyasr years, eyas +faciliate facilitate +faciliated facilitated +faciliates facilitates +facilites facilities +facillitate facilitate +facinated fascinated +facist fascist +familes families +familliar familiar +famoust famous +fanatism fanaticism +Farenheit Fahrenheit +fatc fact +faught fought +favoutrable favourable +feasable feasible +Febuary February +fedreally federally +feromone pheromone +fertily fertility +fianite finite +fianlly finally +ficticious fictitious +fictious fictitious +fidn find +fiel feel, field, file, phial +fiels feels, fields, files, phials +fiercly fiercely +fightings fighting +filiament filament +fimilies families +finacial financial +finaly finally +financialy financially +firends friends +firts flirts, first +fisionable fissionable +flamable flammable +flawess flawless +fleed fled, freed +Flemmish Flemish +florescent fluorescent +flourescent fluorescent +fluorish flourish +follwoing following +folowing following +fomed formed +fomr from, form +fonetic phonetic +fontrier fontier +foootball football +forbad forbade +forbiden forbidden +foreward foreword +forfiet forfeit +forhead forehead +foriegn foreign +Formalhaut Fomalhaut +formallize formalize +formallized formalized +formaly formally +formelly formerly +formidible formidable +formost foremost +forsaw foresaw +forseeable foreseeable +fortelling foretelling +forunner forerunner +foucs focus +foudn found +fougth fought +foundaries foundries +foundary foundry +Foundland Newfoundland +fourties forties +fourty forty +fouth fourth +foward forward +fucntion function +fucntioning functioning +Fransiscan Franciscan +Fransiscans Franciscans +freind friend +freindly friendly +frequentily frequently +frome from +fromed formed +froniter frontier +fufill fulfill +fufilled fulfilled +fulfiled fulfilled +fundametal fundamental +fundametals fundamentals +funguses fungi +funtion function +furuther further +futher further +futhermore furthermore +futhroc futhark, futhorc +gae game, Gael, gale +galatic galactic +Galations Galatians +gallaxies galaxies +galvinized galvanized +Gameboy Game Boy +ganerate generate +ganes games +ganster gangster +garantee guarantee +garanteed guaranteed +garantees guarantees +garnison garrison +gauarana guaraná +gaurantee guarantee +gauranteed guaranteed +gaurantees guarantees +gaurd guard, gourd +gaurentee guarantee +gaurenteed guaranteed +gaurentees guarantees +geneological genealogical +geneologies genealogies +geneology genealogy +generaly generally +generatting generating +genialia genitalia +geographicial geographical +geometrician geometer +geometricians geometers +gerat great +Ghandi Gandhi +glight flight +gnawwed gnawed +godess goddess +godesses goddesses +Godounov Godunov +gogin going, Gauguin +goign going +gonig going +Gothenberg Gothenburg +Gottleib Gottlieb +gouvener governor +govement government +govenment government +govenrment government +goverance governance +goverment government +govermental governmental +governer governor +governmnet government +govorment government +govormental governmental +govornment government +gracefull graceful +graet great +grafitti graffiti +gramatically grammatically +grammaticaly grammatically +grammer grammar +grat great +gratuitious gratuitous +greatful grateful +greatfully gratefully +greif grief +gridles griddles +gropu group +grwo grow +Guaduloupe Guadalupe, Guadeloupe +Guadulupe Guadalupe, Guadeloupe +guage gauge +guarentee guarantee +guarenteed guaranteed +guarentees guarantees +Guatamala Guatemala +Guatamalan Guatemalan +guerilla guerrilla +guerillas guerrillas +guerrila guerrilla +guerrilas guerrillas +guidence guidance +Guilia Giulia +Guilio Giulio +Guiness Guinness +Guiseppe Giuseppe +gunanine guanine +gurantee guarantee +guranteed guaranteed +gurantees guarantees +guttaral guttural +gutteral guttural +habaeus habeas +habeus habeas +Habsbourg Habsburg +haemorrage haemorrhage +haev have, heave +Hallowean Hallowe'en, Halloween +halp help +hapen happen +hapened happened +hapening happening +happend happened +happended happened +happenned happened +harased harassed +harases harasses +harasment harassment +harasments harassments +harassement harassment +harras harass +harrased harassed +harrases harasses +harrasing harassing +harrasment harassment +harrasments harassments +harrassed harassed +harrasses harassed +harrassing harassing +harrassment harassment +harrassments harassments +hasnt hasn't +haviest heaviest +headquater headquarter +headquarer headquarter +headquatered headquartered +headquaters headquarters +healthercare healthcare +heared heard +heathy healthy +Heidelburg Heidelberg +heigher higher +heirarchy hierarchy +heiroglyphics hieroglyphics +helment helmet +helpfull helpful +helpped helped +hemmorhage hemorrhage +herad heard, Hera +heridity heredity +heroe hero +heros heroes +hertzs hertz +hesistant hesitant +heterogenous heterogeneous +hieght height +hierachical hierarchical +hierachies hierarchies +hierachy hierarchy +hierarcical hierarchical +hierarcy hierarchy +hieroglph hieroglyph +hieroglphs hieroglyphs +higer higher +higest highest +higway highway +hillarious hilarious +himselv himself +hinderance hindrance +hinderence hindrance +hindrence hindrance +hipopotamus hippopotamus +hismelf himself +histocompatability histocompatibility +historicians historians +hitsingles hit singles +holliday holiday +homestate home state +homogeneize homogenize +homogeneized homogenized +honory honorary +horrifing horrifying +hosited hoisted +hospitible hospitable +hounour honour +housr hours, house +howver however +hsitorians historians +hstory history +hten then, hen, the +htere there, here +htey they +htikn think +hting thing +htink think +htis this +humer humor, humour +humerous humorous, humerus +huminoid humanoid +humoural humoral +humurous humorous +husban husband +hvae have +hvaing having +hvea have, heave +hwihc which +hwile while +hwole whole +hydogen hydrogen +hydropile hydrophile +hydropilic hydrophilic +hydropobe hydrophobe +hydropobic hydrophobic +hygeine hygiene +hypocracy hypocrisy +hypocrasy hypocrisy +hypocricy hypocrisy +hypocrit hypocrite +hypocrits hypocrites +iconclastic iconoclastic +idaeidae idea +idaes ideas +idealogies ideologies +idealogy ideology +identicial identical +identifers identifiers +ideosyncratic idiosyncratic +idesa ideas, ides +idiosyncracy idiosyncrasy +Ihaca Ithaca +illegimacy illegitimacy +illegitmate illegitimate +illess illness +illiegal illegal +illution illusion +ilness illness +ilogical illogical +imagenary imaginary +imagin imagine +imaginery imaginary, imagery +imanent eminent, imminent +imcomplete incomplete +imediately immediately +imense immense +imigrant emigrant, immigrant +imigrated emigrated, immigrated +imigration emigration, immigration +iminent eminent, imminent, immanent +immediatley immediately +immediatly immediately +immidately immediately +immidiately immediately +immitate imitate +immitated imitated +immitating imitating +immitator imitator +immunosupressant immunosuppressant +impecabbly impeccably +impedence impedance +implamenting implementing +impliment implement +implimented implemented +imploys employs +importamt important +imprioned imprisoned +imprisonned imprisoned +improvision improvisation +improvments improvements +inablility inability +inaccessable inaccessible +inadiquate inadequate +inadquate inadequate +inadvertant inadvertent +inadvertantly inadvertently +inagurated inaugurated +inaguration inauguration +inappropiate inappropriate +inaugures inaugurates +inbalance imbalance +inbalanced imbalanced +inbetween between +incarcirated incarcerated +incidentially incidentally +incidently incidentally +inclreased increased +includ include +includng including +incompatabilities incompatibilities +incompatability incompatibility +incompatable incompatible +incompatablities incompatibilities +incompatablity incompatibility +incompatiblities incompatibilities +incompatiblity incompatibility +incompetance incompetence +incompetant incompetent +incomptable incompatible +incomptetent incompetent +inconsistant inconsistent +incorperation incorporation +incorportaed incorporated +incorprates incorporates +incorruptable incorruptible +incramentally incrementally +increadible incredible +incredable incredible +inctroduce introduce +inctroduced introduced +incuding including +incunabla incunabula +indefinately indefinitely +indefineable undefinable +indefinitly indefinitely +indentical identical +indepedantly independently +indepedence independence +independance independence +independant independent +independantly independently +independece independence +independendet independent +indictement indictment +indigineous indigenous +indipendence independence +indipendent independent +indipendently independently +indespensible indispensable +indespensable indispensable +indispensible indispensable +indisputible indisputable +indisputibly indisputably +indite indict +individualy individually +indpendent independent +indpendently independently +indulgue indulge +indutrial industrial +indviduals individuals +inefficienty inefficiently +inevatible inevitable +inevitible inevitable +inevititably inevitably +infalability infallibility +infallable infallible +infectuous infectious +infered inferred +infilitrate infiltrate +infilitrated infiltrated +infilitration infiltration +infinit infinite +inflamation inflammation +influencial influential +influented influenced +infomation information +informtion information +infrantryman infantryman +infrigement infringement +ingenius ingenious +ingreediants ingredients +inhabitans inhabitants +inherantly inherently +inheritage heritage, inheritance +inheritence inheritance +inital initial +initally initially +initation initiation +initiaitive initiative +inlcuding including +inmigrant immigrant +inmigrants immigrants +innoculated inoculated +inocence innocence +inofficial unofficial +inot into +inpeach impeach +inpolite impolite +inprisonment imprisonment +inproving improving +insectiverous insectivorous +insensative insensitive +inseperable inseparable +insistance insistence +insitution institution +insitutions institutions +inspite in spite, inspire +instade instead +instatance instance +institue institute +instuction instruction +instuments instruments +instutionalized institutionalized +instutions intuitions +insurence insurance +intelectual intellectual +inteligence intelligence +inteligent intelligent +intenational international +intepretation interpretation +intepretator interpretor +interational international +interbread interbreed, interbred +interchangable interchangeable +interchangably interchangeably +intercontinetal intercontinental +intered interred, interned +interelated interrelated +interferance interference +interfereing interfering +intergrated integrated +intergration integration +interm interim +internation international +interpet interpret +interrim interim +interrugum interregnum +intertaining entertaining +interupt interrupt +intervines intervenes +intevene intervene +intial initial +intially initially +intrduced introduced +intrest interest +introdued introduced +intruduced introduced +intrusted entrusted +intutive intuitive +intutively intuitively +inudstry industry +inumerable enumerable, innumerable +inventer inventor +invertibrates invertebrates +investingate investigate +involvment involvement +irelevent irrelevant +iresistable irresistible +iresistably irresistibly +iresistible irresistible +iresistibly irresistibly +iritable irritable +iritated irritated +ironicly ironically +irregardless regardless +irrelevent irrelevant +irreplacable irreplaceable +irresistable irresistible +irresistably irresistibly +isnt isn't +Israelies Israelis +issueing issuing +itnroduced introduced +iunior junior +iwll will +iwth with +Japanes Japanese +jaques jacques +jeapardy jeopardy +jewllery jewellery +Johanine Johannine +Jospeh Joseph +jouney journey +journied journeyed +journies journeys +jstu just +jsut just +Juadaism Judaism +Juadism Judaism +judical judicial +judisuary judiciary +juducial judicial +juristiction jurisdiction +juristictions jurisdictions +kindergarden kindergarten +klenex kleenex +knifes knives +knive knife +knowlege knowledge +knowlegeable knowledgeable +knwo know +knwos knows +konw know +konws knows +kwno know +labatory lavatory, laboratory +labled labelled, labeled +labratory laboratory +laguage language +laguages languages +larg large +largst largest +larrry larry +lastr last +lattitude latitude +launchs launch +launhed launched +lavae larvae +layed laid +lazyness laziness +leaded led +leage league +leanr lean, learn, leaner +leathal lethal +lefted left +legitamate legitimate +legitmate legitimate +leibnitz leibniz +lenght length +leran learn +lerans learns +lieuenant lieutenant +leutenant lieutenant +levetate levitate +levetated levitated +levetates levitates +levetating levitating +levle level +liasion liaison +liason liaison +liasons liaisons +libary library +libell libel +libguistic linguistic +libguistics linguistics +libitarianisn libertarianism +lible libel, liable +lieing lying +liek like +liekd liked +liesure leisure +lieved lived +liftime lifetime +lightyear light year +lightyears light years +likelyhood likelihood +linnaena linnaean +lippizaner lipizzaner +liquify liquefy +liscense license, licence +lisence license, licence +lisense license, licence +listners listeners +litature literature +literture literature +littel little +litterally literally +liuke like +livley lively +lmits limits +loev love +lonelyness loneliness +longitudonal longitudinal +lonley lonely +lonly lonely, only +loosing losing +lotharingen lothringen +lsat last +lukid likud +lveo love +lvoe love +Lybia Libya +mackeral mackerel +magasine magazine +magincian magician +magnificient magnificent +magolia magnolia +mailny mainly +maintainance maintenance +maintainence maintenance +maintance maintenance +maintenence maintenance +maintinaing maintaining +maintioned mentioned +majoroty majority +maked marked, made +makse makes +Malcom Malcolm +maltesian Maltese +mamal mammal +mamalian mammalian +managable manageable, manageably +managment management +manisfestations manifestations +manoeuverability maneuverability +manouver maneuver, manoeuvre +manouverability maneuverability, manoeuvrability, manoeuverability +manouverable maneuverable, manoeuvrable +manouvers maneuvers, manoeuvres +mantained maintained +manuever maneuver, manoeuvre +manuevers maneuvers, manoeuvres +manufacturedd manufactured +manufature manufacture +manufatured manufactured +manufaturing manufacturing +manuver maneuver +mariage marriage +marjority majority +markes marks +marketting marketing +marmelade marmalade +marrage marriage +marraige marriage +marrtyred martyred +marryied married +Massachussets Massachusetts +Massachussetts Massachusetts +massmedia mass media +masterbation masturbation +mataphysical metaphysical +materalists materialist +mathamatics mathematics +mathematican mathematician +mathematicas mathematics +matheticians mathematicians +mathmatically mathematically +mathmatician mathematician +mathmaticians mathematicians +mccarthyst mccarthyist +mchanics mechanics +meaninng meaning +mear wear, mere, mare +mechandise merchandise +medacine medicine +medeival medieval +medevial medieval +mediciney mediciny +medievel medieval +mediterainnean mediterranean +Mediteranean Mediterranean +meerkrat meerkat +melieux milieux +membranaphone membranophone +memeber member +menally mentally +meranda veranda, Miranda +mercentile mercantile +messanger messenger +messenging messaging +metalic metallic +metalurgic metallurgic +metalurgical metallurgical +metalurgy metallurgy +metamorphysis metamorphosis +metaphoricial metaphorical +meterologist meteorologist +meterology meteorology +methaphor metaphor +methaphors metaphors +Michagan Michigan +micoscopy microscopy +midwifes midwives +mileau milieu +milennia millennia +milennium millennium +mileu milieu +miliary military +milion million +miliraty military +millenia millennia +millenial millennial +millenialism millennialism +millenium millennium +millepede millipede +millioniare millionaire +millitary military +millon million +miltary military +minature miniature +minerial mineral +miniscule minuscule +ministery ministry +minstries ministries +minstry ministry +minumum minimum +mirrorred mirrored +miscelaneous miscellaneous +miscellanious miscellaneous +miscellanous miscellaneous +mischeivous mischievous +mischevious mischievous +mischievious mischievous +misdameanor misdemeanor +misdameanors misdemeanors +misdemenor misdemeanor +misdemenors misdemeanors +misfourtunes misfortunes +misile missile +Misouri Missouri +mispell misspell +mispelled misspelled +mispelling misspelling +missen mizzen +Missisipi Mississippi +Missisippi Mississippi +missle missile +missonary missionary +misterious mysterious +mistery mystery +misteryous mysterious +mkae make +mkaes makes +mkaing making +mkea make +moderm modem +modle model +moent moment +moeny money +mohammedans muslims +moil mohel +moleclues molecules +momento memento +monestaries monasteries +monestary monastery, monetary +monickers monikers +monolite monolithic +Monserrat Montserrat +montains mountains +montanous mountainous +monts months +montypic monotypic +moreso more, more so +morgage mortgage +Morisette Morissette +Morrisette Morissette +morroccan moroccan +morrocco morocco +morroco morocco +mosture moisture +motiviated motivated +mounth month +movei movie +movment movement +mroe more +mucuous mucous +muder murder +mudering murdering +muhammadan muslim +multicultralism multiculturalism +multipled multiplied +multiplers multipliers +munbers numbers +muncipalities municipalities +muncipality municipality +munnicipality municipality +muscels mussels, muscles +muscial musical +muscician musician +muscicians musicians +mutiliated mutilated +myraid myriad +mysef myself +mysogynist misogynist +mysogyny misogyny +mysterous mysterious +Mythraic Mithraic +naieve naive +Napoleonian Napoleonic +naturaly naturally +naturely naturally +naturual natural +naturually naturally +Nazereth Nazareth +neccesarily necessarily +neccesary necessary +neccessarily necessarily +neccessary necessary +neccessities necessities +necesarily necessarily +necesary necessary +necessiate necessitate +neglible negligible +negligable negligible +negociate negotiate +negociation negotiation +negociations negotiations +negotation negotiation +neice niece, nice +neigborhood neighborhood +neigbour neighbour, neighbor +neigbourhood neighbourhood +neigbouring neighbouring, neighboring +neigbours neighbours, neighbors +neolitic neolithic +nessasarily necessarily +nessecary necessary +nestin nesting +neverthless nevertheless +newletters newsletters +Newyorker New Yorker +nickle nickel +nightfa;; nightfall +nightime nighttime +nineth ninth +ninteenth nineteenth +ninties 1990s +ninty ninety +nkow know +nkwo know +nmae name +noncombatents noncombatants +nonsence nonsense +nontheless nonetheless +noone no one +norhern northern +northen northern +northereastern northeastern +notabley notably +noteable notable +noteably notably +noteriety notoriety +noth north +nothern northern +noticable noticeable +noticably noticeably +noticeing noticing +noticible noticeable +notwhithstanding notwithstanding +noveau nouveau +nowdays nowadays +nowe now +nto not +nucular nuclear +nuculear nuclear +nuisanse nuisance +Nullabour Nullarbor +numberous numerous +Nuremburg Nuremberg +nusance nuisance +nutritent nutrient +nutritents nutrients +nuturing nurturing +obediance obedience +obediant obedient +obession obsession +obssessed obsessed +obstacal obstacle +obstancles obstacles +obstruced obstructed +ocasion occasion +ocasional occasional +ocasionally occasionally +ocasionaly occasionally +ocasioned occasioned +ocasions occasions +ocassion occasion +ocassional occasional +ocassionally occasionally +ocassionaly occasionally +ocassioned occasioned +ocassions occasions +occaison occasion +occassion occasion +occassional occasional +occassionally occasionally +occassionaly occasionally +occassioned occasioned +occassions occasions +occationally occasionally +occour occur +occurance occurrence +occurances occurrences +occured occurred +occurence occurrence +occurences occurrences +occuring occurring +occurr occur +occurrance occurrence +occurrances occurrences +octohedra octahedra +octohedral octahedral +octohedron octahedron +ocuntries countries +ocuntry country +ocurr occur +ocurrance occurrence +ocurred occurred +ocurrence occurrence +offcers officers +offcially officially +offereings offerings +offical official +officals officials +offically officially +officaly officially +officialy officially +offred offered +oftenly often +oging going, ogling +omision omission +omited omitted +omiting omitting +omlette omelette +ommision omission +ommited omitted +ommiting omitting +ommitted omitted +ommitting omitting +omniverous omnivorous +omniverously omnivorously +omre more +onot note, not +onyl only +openess openness +oponent opponent +oportunity opportunity +opose oppose +oposite opposite +oposition opposition +oppenly openly +oppinion opinion +opponant opponent +oppononent opponent +oppositition opposition +oppossed opposed +opprotunity opportunity +opression oppression +opressive oppressive +opthalmic ophthalmic +opthalmologist ophthalmologist +opthalmology ophthalmology +opthamologist ophthalmologist +optmizations optimizations +optomism optimism +orded ordered +organim organism +organiztion organization +orgin origin, organ +orginal original +orginally originally +orginize organise +oridinarily ordinarily +origanaly originally +originall original, originally +originaly originally +originially originally +originnally originally +origional original +orignally originally +orignially originally +otehr other +ouevre oeuvre +overshaddowed overshadowed +overthere over there +overwelming overwhelming +overwheliming overwhelming +owrk work +owudl would +oxigen oxygen +oximoron oxymoron +paide paid +paitience patience +palce place, palace +paleolitic paleolithic +paliamentarian parliamentarian +Palistian Palestinian +Palistinian Palestinian +Palistinians Palestinians +pallete palette +pamflet pamphlet +pamplet pamphlet +pantomine pantomime +Papanicalou Papanicolaou +paralel parallel +paralell parallel +paralelly parallelly +paralely parallelly +parallely parallelly +paranthesis parenthesis +paraphenalia paraphernalia +parellels parallels +parituclar particular +parliment parliament +parrakeets parakeets +parralel parallel +parrallel parallel +parrallell parallel +parrallelly parallelly +parrallely parallelly +partialy partially +particually particularly +particualr particular +particuarly particularly +particularily particularly +particulary particularly +pary party +pased passed +pasengers passengers +passerbys passersby +pasttime pastime +pastural pastoral +paticular particular +pattented patented +pavillion pavilion +payed paid +peacefuland peaceful and +peageant pageant +peculure peculiar +pedestrain pedestrian +peice piece +Peloponnes Peloponnesus +penatly penalty +penerator penetrator +penisula peninsula +penisular peninsular +penninsula peninsula +penninsular peninsular +pennisula peninsula +pensinula peninsula +peom poem +peoms poems +peopel people +peotry poetry +perade parade +percepted perceived +percieve perceive +percieved perceived +perenially perennially +perfomers performers +performence performance +performes performed, performs +perhasp perhaps +perheaps perhaps +perhpas perhaps +peripathetic peripatetic +peristent persistent +perjery perjury +perjorative pejorative +permanant permanent +permenant permanent +permenantly permanently +permissable permissible +perogative prerogative +peronal personal +perosnality personality +perphas perhaps +perpindicular perpendicular +perseverence perseverance +persistance persistence +persistant persistent +personel personnel, personal +personell personnel +personnell personnel +persuded persuaded +persue pursue +persued pursued +persuing pursuing +persuit pursuit +persuits pursuits +pertubation perturbation +pertubations perturbations +pessiary pessary +petetion petition +Pharoah Pharaoh +phenomenom phenomenon +phenomenonal phenomenal +phenomenonly phenomenally +phenomonenon phenomenon +phenomonon phenomenon +phenonmena phenomena +Philipines Philippines +philisopher philosopher +philisophical philosophical +philisophy philosophy +Phillipine Philippine +Phillipines Philippines +Phillippines Philippines +phillosophically philosophically +philospher philosopher +philosphies philosophies +philosphy philosophy +Phonecian Phoenecian +phongraph phonograph +phylosophical philosophical +physicaly physically +pich pitch +pilgrimmage pilgrimage +pilgrimmages pilgrimages +pinapple pineapple +pinnaple pineapple +pinoneered pioneered +plagarism plagiarism +planation plantation +planed planned +plantiff plaintiff +plateu plateau +plausable plausible +playright playwright +playwrite playwright +playwrites playwrights +pleasent pleasant +plebicite plebiscite +plesant pleasant +poeoples peoples +poety poetry +poisin poison +polical political +polinator pollinator +polinators pollinators +politican politician +politicans politicians +poltical political +polute pollute +poluted polluted +polutes pollutes +poluting polluting +polution pollution +polyphonyic polyphonic +polysaccaride polysaccharide +polysaccharid polysaccharide +pomegranite pomegranate +pomotion promotion +poportional proportional +popoulation population +popularaty popularity +populare popular +populer popular +portayed portrayed +portraing portraying +Portugese Portuguese +portuguease portuguese +posess possess +posessed possessed +posesses possesses +posessing possessing +posession possession +posessions possessions +posion poison +positon position, positron +possable possible +possably possibly +posseses possesses +possesing possessing +possesion possession +possessess possesses +possibile possible +possibilty possibility +possiblility possibility +possiblilty possibility +possiblities possibilities +possiblity possibility +possition position +Postdam Potsdam +posthomous posthumous +postion position +postive positive +potatos potatoes +portait portrait +potrait portrait +potrayed portrayed +poulations populations +poverful powerful +poweful powerful +powerfull powerful +practial practical +practially practically +practicaly practically +practicioner practitioner +practicioners practitioners +practicly practically +practioner practitioner +practioners practitioners +prairy prairie +prarie prairie +praries prairies +pratice practice +preample preamble +precedessor predecessor +preceed precede +preceeded preceded +preceeding preceding +preceeds precedes +precentage percentage +precice precise +precisly precisely +precurser precursor +predecesors predecessors +predicatble predictable +predicitons predictions +predomiantly predominately +prefered preferred +prefering preferring +preferrably preferably +pregancies pregnancies +preiod period +preliferation proliferation +premeire premiere +premeired premiered +premillenial premillennial +preminence preeminence +premission permission +Premonasterians Premonstratensians +preocupation preoccupation +prepair prepare +prepartion preparation +prepatory preparatory +preperation preparation +preperations preparations +preriod period +presedential presidential +presense presence +presidenital presidential +presidental presidential +presitgious prestigious +prespective perspective +prestigeous prestigious +prestigous prestigious +presumabely presumably +presumibly presumably +pretection protection +prevelant prevalent +preverse perverse +previvous previous +pricipal principal +priciple principle +priestood priesthood +primarly primarily +primative primitive +primatively primitively +primatives primitives +primordal primordial +priveledges privileges +privelege privilege +priveleged privileged +priveleges privileges +privelige privilege +priveliged privileged +priveliges privileges +privelleges privileges +privilage privilege +priviledge privilege +priviledges privileges +privledge privilege +privte private +probabilaty probability +probablistic probabilistic +probablly probably +probalibity probability +probaly probably +probelm problem +proccess process +proccessing processing +procede proceed, precede +proceded proceeded, preceded +procedes proceeds, precedes +procedger procedure +proceding proceeding, preceding +procedings proceedings +proceedure procedure +proces process +processer processor +proclaimation proclamation +proclamed proclaimed +proclaming proclaiming +proclomation proclamation +profesion profusion, profession +profesor professor +professer professor +proffesed professed +proffesion profession +proffesional professional +proffesor professor +profilic prolific +progessed progressed +programable programmable +progrom pogrom, program +progroms pogroms, programs +prohabition prohibition +prologomena prolegomena +prominance prominence +prominant prominent +prominantly prominently +prominately prominently, predominately +promiscous promiscuous +promotted promoted +pronomial pronominal +pronouced pronounced +pronounched pronounced +pronounciation pronunciation +proove prove +prooved proved +prophacy prophecy +propietary proprietary +propmted prompted +propoganda propaganda +propogate propagate +propogates propagates +propogation propagation +propostion proposition +propotions proportions +propper proper +propperly properly +proprietory proprietary +proseletyzing proselytizing +protaganist protagonist +protaganists protagonists +protocal protocol +protoganist protagonist +protrayed portrayed +protruberance protuberance +protruberances protuberances +prouncements pronouncements +provacative provocative +provded provided +provicial provincial +provinicial provincial +provisonal provisional +provisiosn provision +proximty proximity +pseudononymous pseudonymous +pseudonyn pseudonym +psuedo pseudo +psycology psychology +psyhic psychic +publicaly publicly +puchasing purchasing +Pucini Puccini +Puertorrican Puerto Rican +Puertorricans Puerto Ricans +pumkin pumpkin +puritannical puritanical +purposedly purposely +purpotedly purportedly +pursuade persuade +pursuaded persuaded +pursuades persuades +pususading persuading +puting putting +pwoer power +pyscic psychic +qtuie quite, quiet +quantaty quantity +quantitiy quantity +quarantaine quarantine +Queenland Queensland +questonable questionable +quicklyu quickly +quinessential quintessential +quitted quit +quizes quizzes +qutie quite, quiet +rabinnical rabbinical +racaus raucous +radiactive radioactive +radify ratify +raelly really +rarified rarefied +reaccurring recurring +reacing reaching +reacll recall +readmition readmission +realitvely relatively +realsitic realistic +realtions relations +realy really +realyl really +reasearch research +rebiulding rebuilding +rebllions rebellions +rebounce rebound +reccomend recommend +reccomendations recommendations +reccomended recommended +reccomending recommending +reccommend recommend +reccommended recommended +reccommending recommending +reccuring recurring +receeded receded +receeding receding +receivedfrom received from +recepient recipient +recepients recipients +receving receiving +rechargable rechargeable +reched reached +recide reside +recided resided +recident resident +recidents residents +reciding residing +reciepents recipients +reciept receipt +recieve receive +recieved received +reciever receiver +recievers receivers +recieves receives +recieving receiving +recipiant recipient +recipiants recipients +recived received +recivership receivership +recogise recognise +recogize recognize +recomend recommend +recomended recommended +recomending recommending +recomends recommends +recommedations recommendations +reconaissance reconnaissance +reconcilation reconciliation +reconized recognized +reconnaissence reconnaissance +recontructed reconstructed +recordproducer record producer +recquired required +recrational recreational +recrod record +recuiting recruiting +recuring recurring +recurrance recurrence +rediculous ridiculous +reedeming redeeming +reenforced reinforced +refect reflect +refedendum referendum +referal referral +refered referred +referiang referring +refering referring +refernces references +referrence reference +referrs refers +reffered referred +refference reference +refrence reference +refrences references +refrers refers +refridgeration refrigeration +refridgerator refrigerator +refromist reformist +refusla refusal +regardes regards +regluar regular +reguarly regularly +regulaion regulation +regulaotrs regulators +regularily regularly +rehersal rehearsal +reicarnation reincarnation +reigining reigning +reknown renown +reknowned renowned +rela real +relaly really +relatiopnship relationship +relativly relatively +relected reelected +releive relieve +releived relieved +releiver reliever +releses releases +relevence relevance +relevent relevant +reliablity reliability +relient reliant +religeous religious +religous religious +religously religiously +relinqushment relinquishment +relitavely relatively +relized realised, realized +relpacement replacement +remaing remaining +remeber remember +rememberable memorable +rememberance remembrance +remembrence remembrance +remenant remnant +remenicent reminiscent +reminent remnant +reminescent reminiscent +reminscent reminiscent +reminsicent reminiscent +rendevous rendezvous +rendezous rendezvous +renedered rende +renewl renewal +rentors renters +reoccurrence recurrence +reorganision reorganisation +repatition repetition, repartition +repentence repentance +repentent repentant +repeteadly repeatedly +repetion repetition +repid rapid +reponse response +reponsible responsible +reportadly reportedly +represantative representative +representive representative +representives representatives +reproducable reproducible +reprtoire repertoire +repsectively respectively +reptition repetition +requirment requirement +requred required +resaurant restaurant +resembelance resemblance +resembes resembles +resemblence resemblance +resevoir reservoir +resignement resignment +resistable resistible +resistence resistance +resistent resistant +respectivly respectively +responce response +responibilities responsibilities +responisble responsible +responnsibilty responsibility +responsability responsibility +responsibile responsible +responsibilites responsibilities +responsiblity responsibility +ressemblance resemblance +ressemble resemble +ressembled resembled +ressemblence resemblance +ressembling resembling +resssurecting resurrecting +ressurect resurrect +ressurected resurrected +ressurection resurrection +ressurrection resurrection +restaraunt restaurant +restaraunteur restaurateur +restaraunteurs restaurateurs +restaraunts restaurants +restauranteurs restaurateurs +restauration restoration +restauraunt restaurant +resteraunt restaurant +resteraunts restaurants +resticted restricted +restraunt restraint, restaurant +resturant restaurant +resturaunt restaurant +resurecting resurrecting +retalitated retaliated +retalitation retaliation +retreive retrieve +returnd returned +revaluated reevaluated +reveral reversal +reversable reversible +revolutionar revolutionary +rewitten rewritten +rewriet rewrite +rhymme rhyme +rhythem rhythm +rhythim rhythm +rhytmic rhythmic +rigeur rigueur, rigour, rigor +rigourous rigorous +rininging ringing +rised rose +Rockerfeller Rockefeller +rococco rococo +rocord record +roomate roommate +rougly roughly +rucuperate recuperate +rudimentatry rudimentary +rulle rule +runing running +runnung running +russina Russian +Russion Russian +rwite write +rythem rhythm +rythim rhythm +rythm rhythm +rythmic rhythmic +rythyms rhythms +sacrafice sacrifice +sacreligious sacrilegious +sacrifical sacrificial +saftey safety +safty safety +salery salary +sanctionning sanctioning +sandwhich sandwich +Sanhedrim Sanhedrin +santioned sanctioned +sargant sergeant +sargeant sergeant +sasy says, sassy +satelite satellite +satelites satellites +Saterday Saturday +Saterdays Saturdays +satisfactority satisfactorily +satric satiric +satrical satirical +satrically satirically +sattelite satellite +sattelites satellites +saught sought +saveing saving +saxaphone saxophone +scaleable scalable +scandanavia Scandinavia +scaricity scarcity +scavanged scavenged +schedual schedule +scholarhip scholarship +scholarstic scholastic, scholarly +scientfic scientific +scientifc scientific +scientis scientist +scince science +scinece science +scirpt script +scoll scroll +screenwrighter screenwriter +scrutinity scrutiny +scuptures sculptures +seach search +seached searched +seaches searches +secceeded seceded, succeeded +seceed succeed, secede +seceeded succeeded, seceded +secratary secretary +secretery secretary +sedereal sidereal +seeked sought +segementation segmentation +seguoys segues +seige siege +seing seeing +seinor senior +seldomly seldom +senarios scenarios +sence sense +senstive sensitive +sensure censure +seperate separate +seperated separated +seperately separately +seperates separates +seperating separating +seperation separation +seperatism separatism +seperatist separatist +sepina subpoena +sepulchure sepulchre, sepulcher +sepulcre sepulchre, sepulcher +sergent sergeant +settelement settlement +settlment settlement +severeal several +severley severely +severly severely +sevice service +shaddow shadow +shamen shaman, shamans +sheat sheath, sheet, cheat +sheild shield +sherif sheriff +shineing shining +shiped shipped +shiping shipping +shopkeeepers shopkeepers +shorly shortly +shortwhile short while +shoudl should +shoudln should, shouldn't +shouldnt shouldn't +shreak shriek +shrinked shrunk +sicne since +sideral sidereal +sieze seize, size +siezed seized, sized +siezing seizing, sizing +siezure seizure +siezures seizures +siginificant significant +signficant significant +signficiant significant +signfies signifies +signifantly significantly +significently significantly +signifigant significant +signifigantly significantly +signitories signatories +signitory signatory +similarily similarly +similiar similar +similiarity similarity +similiarly similarly +simmilar similar +simpley simply +simplier simpler +simultanous simultaneous +simultanously simultaneously +sincerley sincerely +singsog singsong +sinse sines, since +Sionist Zionist +Sionists Zionists +Sixtin Sistine +Skagerak Skagerrak +skateing skating +slaugterhouses slaughterhouses +slowy slowly +smae same +smealting smelting +smoe some +sneeks sneaks +snese sneeze +socalism socialism +socities societies +soem some +sofware software +sohw show +soilders soldiers +solatary solitary +soley solely +soliders soldiers +soliliquy soliloquy +soluable soluble +somene someone +somtimes sometimes +somwhere somewhere +sophicated sophisticated +sorceror sorcerer +sorrounding surrounding +sotry story +sotyr satyr, story +soudn sound +soudns sounds +sould could, should, sold +sountrack soundtrack +sourth south +sourthern southern +souvenier souvenir +souveniers souvenirs +soveits soviets +sovereignity sovereignty +soverign sovereign +soverignity sovereignty +soverignty sovereignty +spainish Spanish +speach speech +specfic specific +speciallized specialised, specialized +specif specific, specify +specifiying specifying +speciman specimen +spectauclar spectacular +spectaulars spectaculars +spects aspects, expects +spectum spectrum +speices species +spendour splendour +spermatozoan spermatozoon +spoace space +sponser sponsor +sponsered sponsored +spontanous spontaneous +sponzored sponsored +spoonfulls spoonfuls +sppeches speeches +spreaded spread +sprech speech +spred spread +spriritual spiritual +spritual spiritual +sqaure square +stablility stability +stainlees stainless +staion station +standars standards +stange strange +startegic strategic +startegies strategies +startegy strategy +stateman statesman +statememts statements +statment statement +steriods steroids +sterotypes stereotypes +stilus stylus +stingent stringent +stiring stirring +stirrs stirs +stlye style +stong strong +stopry story +storeis stories +storise stories +stornegst strongest +stoyr story +stpo stop +stradegies strategies +stradegy strategy +strat start, strata +stratagically strategically +streemlining streamlining +stregth strength +strenghen strengthen +strenghened strengthened +strenghening strengthening +strenght strength +strenghten strengthen +strenghtened strengthened +strenghtening strengthening +strengtened strengthened +strenous strenuous +strictist strictest +strikely strikingly +strnad strand +stroy story, destroy +structual structural +stubborness stubbornness +stucture structure +stuctured structured +studdy study +studing studying +stuggling struggling +sturcture structure +subcatagories subcategories +subcatagory subcategory +subconsiously subconsciously +subjudgation subjugation +submachne submachine +subpecies subspecies +subsidary subsidiary +subsiduary subsidiary +subsquent subsequent +subsquently subsequently +substace substance +substancial substantial +substatial substantial +substituded substituted +substract subtract +substracted subtracted +substracting subtracting +substraction subtraction +substracts subtracts +subtances substances +subterranian subterranean +suburburban suburban +succceeded succeeded +succcesses successes +succedded succeeded +succeded succeeded +succeds succeeds +succesful successful +succesfully successfully +succesfuly successfully +succesion succession +succesive successive +successfull successful +successully successfully +succsess success +succsessfull successful +suceed succeed +suceeded succeeded +suceeding succeeding +suceeds succeeds +sucesful successful +sucesfully successfully +sucesfuly successfully +sucesion succession +sucess success +sucesses successes +sucessful successful +sucessfull successful +sucessfully successfully +sucessfuly successfully +sucession succession +sucessive successive +sucessor successor +sucessot successor +sucide suicide +sucidial suicidal +sufferage suffrage +sufferred suffered +sufferring suffering +sufficent sufficient +sufficently sufficiently +sumary summary +sunglases sunglasses +suop soup +superceeded superseded +superintendant superintendent +suphisticated sophisticated +suplimented supplemented +supose suppose +suposed supposed +suposedly supposedly +suposes supposes +suposing supposing +supplamented supplemented +suppliementing supplementing +suppoed supposed +supposingly supposedly +suppy supply +supress suppress +supressed suppressed +supresses suppresses +supressing suppressing +suprise surprise +suprised surprised +suprising surprising +suprisingly surprisingly +suprize surprise +suprized surprised +suprizing surprising +suprizingly surprisingly +surfce surface +surley surly, surely +suround surround +surounded surrounded +surounding surrounding +suroundings surroundings +surounds surrounds +surplanted supplanted +surpress suppress +surpressed suppressed +surprize surprise +surprized surprised +surprizing surprising +surprizingly surprisingly +surrended surrounded, surrendered +surrepetitious surreptitious +surrepetitiously surreptitiously +surreptious surreptitious +surreptiously surreptitiously +surronded surrounded +surrouded surrounded +surrouding surrounding +surrundering surrendering +surveilence surveillance +surveill surveil +surveyer surveyor +surviver survivor +survivers survivors +survivied survived +suseptable susceptible +suseptible susceptible +suspention suspension +swaer swear +swaers swears +swepth swept +swiming swimming +syas says +symetrical symmetrical +symetrically symmetrically +symetry symmetry +symettric symmetric +symmetral symmetric +symmetricaly symmetrically +synagouge synagogue +syncronization synchronization +synonomous synonymous +synonymns synonyms +synphony symphony +syphyllis syphilis +sypmtoms symptoms +syrap syrup +sysmatically systematically +sytem system +sytle style +tabacco tobacco +tahn than +taht that +talekd talked +targetted targeted +targetting targeting +tast taste +tath that +tattooes tattoos +taxanomic taxonomic +taxanomy taxonomy +teached taught +techician technician +techicians technicians +techiniques techniques +technitian technician +technnology technology +technolgy technology +teh the +tehy they +telelevision television +televsion television +telphony telephony +temerature temperature +temparate temperate +temperarily temporarily +temperment temperament +tempertaure temperature +temperture temperature +temprary temporary +tenacle tentacle +tenacles tentacles +tendacy tendency +tendancies tendencies +tendancy tendency +tennisplayer tennis player +tepmorarily temporarily +terrestial terrestrial +terriories territories +terriory territory +territorist terrorist +territoy territory +terroist terrorist +testiclular testicular +tghe the +thast that, that's +theather theater, theatre +theese these +theif thief +theives thieves +themselfs themselves +themslves themselves +ther there, their, the +therafter thereafter +therby thereby +theri their +thgat that +thge the +thier their +thign thing +thigns things +thigsn things +thikn think +thikning thinking, thickening +thikns thinks +thiunk think +thn then +thna than +thne then +thnig thing +thnigs things +thoughout throughout +threatend threatened +threatning threatening +threee three +threshhold threshold +thrid third +throrough thorough +throughly thoroughly +throught thought, through, throughout +througout throughout +thru through +thsi this +thsoe those +thta that +thyat that +tiem time, Tim +tihkn think +tihs this +timne time +tiome time, tome +tje the +tjhe the +tjpanishad upanishad +tkae take +tkaes takes +tkaing taking +tlaking talking +tobbaco tobacco +todays today's +todya today +toghether together +tolerence tolerance +Tolkein Tolkien +tomatos tomatoes +tommorow tomorrow +tommorrow tomorrow +tongiht tonight +toriodal toroidal +tormenters tormentors +torpeados torpedoes +torpedos torpedoes +tothe to the +toubles troubles +tounge tongue +tourch torch, touch +towords towards +towrad toward +tradionally traditionally +traditionaly traditionally +traditionnal traditional +traditition tradition +tradtionally traditionally +trafficed trafficked +trafficing trafficking +trafic traffic +trancendent transcendent +trancending transcending +tranform transform +tranformed transformed +transcendance transcendence +transcendant transcendent +transcendentational transcendental +transcripting transcribing, transcription +transending transcending +transesxuals transsexuals +transfered transferred +transfering transferring +transformaton transformation +transistion transition +translater translator +translaters translators +transmissable transmissible +transporation transportation +tremelo tremolo +tremelos tremolos +triguered triggered +triology trilogy +troling trolling +troup troupe +troups troupes, troops +truely truly +trustworthyness trustworthiness +turnk turnkey, trunk +Tuscon Tucson +tust trust +twelth twelfth +twon town +twpo two +tyhat that +tyhe they +typcial typical +typicaly typically +tyranies tyrannies +tyrany tyranny +tyrranies tyrannies +tyrrany tyranny +ubiquitious ubiquitous +uise use +Ukranian Ukrainian +ultimely ultimately +unacompanied unaccompanied +unahppy unhappy +unanymous unanimous +unathorised unauthorised +unavailible unavailable +unballance unbalance +unbeleivable unbelievable +uncertainity uncertainty +unchallengable unchallengeable +unchangable unchangeable +uncompetive uncompetitive +unconcious unconscious +unconciousness unconsciousness +unconfortability discomfort +uncontitutional unconstitutional +unconvential unconventional +undecideable undecidable +understoon understood +undesireable undesirable +undetecable undetectable +undoubtely undoubtedly +undreground underground +uneccesary unnecessary +unecessary unnecessary +unequalities inequalities +unforetunately unfortunately +unforgetable unforgettable +unforgiveable unforgivable +unfortunatley unfortunately +unfortunatly unfortunately +unfourtunately unfortunately +unihabited uninhabited +unilateraly unilaterally +unilatreal unilateral +unilatreally unilaterally +uninterruped uninterrupted +uninterupted uninterrupted +UnitesStates UnitedStates +univeral universal +univeristies universities +univeristy university +universtiy university +univesities universities +univesity university +unkown unknown +unlikey unlikely +unmanouverable unmaneuverable, unmanoeuvrable +unmistakeably unmistakably +unneccesarily unnecessarily +unneccesary unnecessary +unneccessarily unnecessarily +unneccessary unnecessary +unnecesarily unnecessarily +unnecesary unnecessary +unoffical unofficial +unoperational nonoperational +unoticeable unnoticeable +unplease displease +unplesant unpleasant +unprecendented unprecedented +unprecidented unprecedented +unrepentent unrepentant +unrepetant unrepentant +unrepetent unrepentant +unsed used, unused, unsaid +unsubstanciated unsubstantiated +unsuccesful unsuccessful +unsuccesfully unsuccessfully +unsuccessfull unsuccessful +unsucesful unsuccessful +unsucesfuly unsuccessfully +unsucessful unsuccessful +unsucessfull unsuccessful +unsucessfully unsuccessfully +unsuprised unsurprised +unsuprising unsurprising +unsuprisingly unsurprisingly +unsuprized unsurprised +unsuprizing unsurprising +unsuprizingly unsurprisingly +unsurprized unsurprised +unsurprizing unsurprising +unsurprizingly unsurprisingly +untill until +untranslateable untranslatable +unuseable unusable +unusuable unusable +unviersity university +unwarrented unwarranted +unweildly unwieldy +unwieldly unwieldy +upcomming upcoming +upgradded upgraded +usally usually +useage usage +usefull useful +usefuly usefully +useing using +usualy usually +ususally usually +vaccum vacuum +vaccume vacuum +vacinity vicinity +vaguaries vagaries +vaieties varieties +vailidty validity +valetta valletta +valuble valuable +valueable valuable +varations variations +varient variant +variey variety +varing varying +varities varieties +varity variety +vasall vassal +vasalls vassals +vegatarian vegetarian +vegitable vegetable +vegitables vegetables +vegtable vegetable +vehicule vehicle +vell well +venemous venomous +vengance vengeance +vengence vengeance +verfication verification +verison version +verisons versions +vermillion vermilion +versitilaty versatility +versitlity versatility +vetween between +veyr very +vigeur vigueur, vigour, vigor +vigilence vigilance +vigourous vigorous +villian villain +villification vilification +villify vilify +villin villi, villain, villein +vincinity vicinity +violentce violence +virutal virtual +virtualy virtually +virutally virtually +visable visible +visably visibly +visting visiting +vistors visitors +vitories victories +volcanoe volcano +voleyball volleyball +volontary voluntary +volonteer volunteer +volonteered volunteered +volonteering volunteering +volonteers volunteers +volounteer volunteer +volounteered volunteered +volounteering volunteering +volounteers volunteers +vreity variety +vrey very +vriety variety +vulnerablility vulnerability +vyer very +vyre very +waht what +wanna want to +warantee warranty +wardobe wardrobe +warrent warrant +warrriors warriors +wasnt wasn't +wass was +watn want +wayword wayward +weaponary weaponry +weas was +wehn when +weild wield, wild +weilded wielded +wendsay Wednesday +wensday Wednesday +wereabouts whereabouts +whant want +whants wants +whcih which +wheras whereas +wherease whereas +whereever wherever +whic which +whihc which +whith with +whlch which +whn when +wholey wholly +wholy wholly, holy +whta what +whther whether +wich which, witch +widesread widespread +wief wife +wierd weird +wiew view +wih with +wiht with +wille will +willingless willingness +wirting writing +withdrawl withdrawal, withdraw +witheld withheld +withing within +withold withhold +witht with +witn with +wiull will +wnat want +wnated wanted +wnats wants +wohle whole +wokr work +wokring working +wonderfull wonderful +workststion workstation +worls world +wordlwide worldwide +worshipper worshiper +worshipping worshiping +worstened worsened +woudl would +wresters wrestlers +wriet write +writen written +wroet wrote +wrok work +wroking working +ws was +wtih with +wupport support +xenophoby xenophobia +yaching yachting +yatch yacht +yeasr years +yeild yield +yeilding yielding +Yementite Yemenite, Yemeni +yearm year +yera year +yeras years +yersa years +youseff yousef +youself yourself +ytou you +yuo you +joo you +zeebra zebra + +[[Category:Wikipedia tools]] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.am b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.am new file mode 100644 index 000000000..b8be6c5b6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.am @@ -0,0 +1,6 @@ +EXTRA_DIST= \ +List_of_common_misspellings.txt \ +Makefile.orig \ +prepare \ +README \ +test diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.in b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.in new file mode 100644 index 000000000..11d332705 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.in @@ -0,0 +1,435 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = tests/suggestiontest +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/codeset.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \ + $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \ + $(top_srcdir)/m4/inttypes-pri.m4 \ + $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/visibility.m4 \ + $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ + $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSESLIB = @CURSESLIB@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENCAT = @GENCAT@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC2 = @GLIBC2@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_ASPRINTF = @HAVE_ASPRINTF@ +HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@ +HAVE_SNPRINTF = @HAVE_SNPRINTF@ +HAVE_VISIBILITY = @HAVE_VISIBILITY@ +HAVE_WPRINTF = @HAVE_WPRINTF@ +HUNSPELL_VERSION_MAJOR = @HUNSPELL_VERSION_MAJOR@ +HUNSPELL_VERSION_MINOR = @HUNSPELL_VERSION_MINOR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPTH = @LIBPTH@ +LIBPTH_PREFIX = @LIBPTH_PREFIX@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBC = @LTLIBC@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBPTH = @LTLIBPTH@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +WOE32 = @WOE32@ +WOE32DLL = @WOE32DLL@ +XFAILED = @XFAILED@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ +List_of_common_misspellings.txt \ +Makefile.orig \ +prepare \ +README \ +test + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/suggestiontest/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/suggestiontest/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/README b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/README new file mode 100644 index 000000000..c50e05cea --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/README @@ -0,0 +1,16 @@ +source of text data: Wikipedia +http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines + +For testing Hunspell you need the extended en_US dictionary with phonetic table: +http://hunspell.sourceforge.net/en_US.zip + +test: +make -f Makefile.orig + +test only with Hunspell: + +make -f Makefile.orig single + +test with different input file and dictionaries: + +INPUT=dutchlist.txt HUNSPELL=nl_NL ASPELL=nl make -f Makefile.orig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/prepare b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/prepare new file mode 100644 index 000000000..a72d931b8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/prepare @@ -0,0 +1,40 @@ +#!/bin/bash +# Check common misspellings +# input file format: +# word->word1, ... +# Source: http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines + +hunspell=../../src/tools/hunspell +hlang=${HUNSPELL:-en_US} +alang=${ASPELL:-en_US} +input=${INPUT:-List_of_common_misspellings.txt} + +# remove bad words recognised by Hunspell as good +cat $input | sed 's/[-]>/ /' | $hunspell -d $hlang -1 -L | + +# remove items with dash for Aspell +grep '^[^-]* ' | + +# remove spaces from end of lines +sed 's/ *$//' >$input.1 + +# remove bad words recognised by Aspell as good +cut -f 1 -d ' ' $input.1 | aspell -l $alang --list | +awk 'FILENAME=="-"{a[$1]=1;next}a[$1]{print$0}' - $input.1 | + +# change commas with tabs +sed 's/, */ /g' >$input.2 + +# remove lines with unrecognised suggestions (except suggestion with spaces) +cut -d ' ' -f 2- $input.2 | tr "\t" "\n" | grep -v ' ' >x.1 +cat x.1 | $hunspell -l -d $hlang >x.2 +cat x.1 | aspell -l $alang --list >>x.2 +cat x.2 | awk 'BEGIN{FS="\t"} +FILENAME=="-"{a[$1]=1;next}a[$2]!=1 && a[$3]!=1{print $0}' - $input.2 >$input.3 + +cut -f 1 -d ' ' $input.3 | aspell -l $alang -a | grep -v ^$ | sed -n '2,$p' | +sed 's/^.*: //;s/, / /g' >$input.4 + +cat $input.3 | $hunspell -d $hlang -a -1 | grep -v ^$ | sed -n '2,$p' | +sed 's/^.*: //;s/, / /g' >$input.5 + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/test b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/test new file mode 100644 index 000000000..8e6c1cc1f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/test @@ -0,0 +1,25 @@ +#!/bin/bash +# Check common misspellings +# input file format: +# word->word1, ... +# Source: http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines + +input=${INPUT:-List_of_common_misspellings.txt} + +function check() { +cat $1 | awk 'BEGIN{maxord=0;FS="\t"}FILENAME=="-"{for (i=1; i<=NF; i++){a[NR,$(i)]=i};max=NR;next}{x1=a[NR-max,$2];x2=a[NR-max,$3];sug++;if($3)sug++;if (!x1&&!x2){mis2++;misrow=misrow"\n"$0};if(!x1||($3 && !x2))mis++;ord+=x1+x2;}END{ +print "Missed rows", misrow; +print "=======================================" +print maxord, "max. suggestion for a word"; +print max, "input rows"; +print mis2, "missing rows"; +print sug, "expected suggestions"; +print mis, "missing suggestions"; +print ord/(sug-mis), "average ranking"; +}' - $2 +} + +test -f $input.4 && check $input.4 $input.3 >result.aspell +check $input.5 $input.3 >result.hunspell +test -f result.aspell && tail -6 result.aspell +tail -6 result.hunspell diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.aff new file mode 100644 index 000000000..60294d24c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.aff @@ -0,0 +1,15 @@ +# new suggestion methods of Hunspell 1.5: +# capitalization: nasa -> NASA +# long swap: permenant -> permanent +# long mov: Ghandi -> Gandhi +# double two characters: vacacation -> vacation +# space with REP: "alot" -> "a lot" ("a lot" need to be in the dic file.) + +SET UTF-8 +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 +REP 1 +REP alot a_lot +KEY qwertzuiop|asdfghjkl|yxcvbnm|aq +WORDCHARS . +FORBIDDENWORD ? diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.dic new file mode 100644 index 000000000..cf7c9aadb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.dic @@ -0,0 +1,11 @@ +10 +NASA +Gandhi +grateful +permanent +vacation +a +lot +have +which +McDonald diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.sug b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.sug new file mode 100644 index 000000000..e277bdb77 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.sug @@ -0,0 +1,12 @@ +NASA +Gandhi +grateful +permanent +vacation +a lot, lot +permanent. Vacation +have +which +Gandhi +McDonald +permanent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.test b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.wrong new file mode 100644 index 000000000..4d184d5a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.wrong @@ -0,0 +1,12 @@ +nasa +Ghandi +greatful +permenant +vacacation +alot +permanent.Vacation +ahev +hwihc +GAndhi +Mcdonald +permqnent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/test.sh b/extensions/spellcheck/hunspell/tests/unit/data/test.sh new file mode 100644 index 000000000..c89ca9bf7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/test.sh @@ -0,0 +1,111 @@ +#!/bin/bash +export LC_ALL="C" + +function check_valgrind_log () { +if [ "$VALGRIND" != "" ]; then + if [ -f $TEMPDIR/test.pid* ]; then + log=`ls $TEMPDIR/test.pid*` + if ! grep -q 'ERROR SUMMARY: 0 error' $log; then + echo "Fail in $NAME $1 checking detected by Valgrind" + echo "$log Valgrind log file moved to $TEMPDIR/badlogs" + mv $log $TEMPDIR/badlogs + exit 1 + fi + if grep -q 'LEAK SUMMARY' $log; then + echo "Memory leak in $NAME $1 checking detected by Valgrind" + echo "$log Valgrind log file moved to $TEMPDIR/badlogs" + mv $log $TEMPDIR/badlogs + exit 1 + fi + rm -f $log + fi +fi +} + +TESTDIR=. +TEMPDIR=$TESTDIR/testSubDir +NAME="$1" +shift + +if [ ! -d $TEMPDIR ]; then + mkdir $TEMPDIR +fi + +shopt -s expand_aliases + +alias hunspell='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la ../src/tools/hunspell' +alias analyze='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la ../src/tools/analyze' + +if [ "$VALGRIND" != "" ]; then + rm -f $TEMPDIR/test.pid* + if [ ! -d $TEMPDIR/badlogs ]; then + mkdir $TEMPDIR/badlogs + fi + + alias hunspell='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la valgrind --tool=$VALGRIND --leak-check=yes --show-reachable=yes --log-file=$TEMPDIR/test.pid ../src/tools/hunspell' + alias analyze='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la valgrind --tool=$VALGRIND --leak-check=yes --show-reachable=yes --log-file=$TEMPDIR/test.pid ../src/tools/analyze' +fi + +# Tests good words +if test -f $TESTDIR/$NAME.good; then + hunspell -l $* -d $TESTDIR/$NAME <$TESTDIR/$NAME.good >$TEMPDIR/$NAME.good + if test -s $TEMPDIR/$NAME.good; then + echo "=============================================" + echo "Fail in $NAME.good. Good words recognised as wrong:" + cat $TEMPDIR/$NAME.good + rm -f $TEMPDIR/$NAME.good + exit 1 + fi + rm -f $TEMPDIR/$NAME.good +fi + +check_valgrind_log "good words" + +# Tests bad words +if test -f $TESTDIR/$NAME.wrong; then + hunspell -l $* -d $TESTDIR/$NAME <$TESTDIR/$NAME.wrong >$TEMPDIR/$NAME.wrong + tr -d ' ' <$TESTDIR/$NAME.wrong >$TEMPDIR/$NAME.wrong.detab + if ! cmp $TEMPDIR/$NAME.wrong $TEMPDIR/$NAME.wrong.detab >/dev/null; then + echo "=============================================" + echo "Fail in $NAME.wrong. Bad words recognised as good:" + tr -d ' ' <$TESTDIR/$NAME.wrong >$TEMPDIR/$NAME.wrong.detab + diff $TEMPDIR/$NAME.wrong.detab $TEMPDIR/$NAME.wrong | grep '^<' | sed 's/^..//' + rm -f $TEMPDIR/$NAME.wrong $TEMPDIR/$NAME.wrong.detab + exit 1 + fi + rm -f $TEMPDIR/$NAME.wrong $TEMPDIR/$NAME.wrong.detab +fi + +check_valgrind_log "bad words" + +# Tests morphological analysis +if test -f $TESTDIR/$NAME.morph; then + sed 's/ $//' $TESTDIR/$NAME.good >$TEMPDIR/$NAME.good + analyze $TESTDIR/$NAME.aff $TESTDIR/$NAME.dic $TEMPDIR/$NAME.good >$TEMPDIR/$NAME.morph + if ! cmp $TEMPDIR/$NAME.morph $TESTDIR/$NAME.morph >/dev/null; then + echo "=============================================" + echo "Fail in $NAME.morph. Bad analysis?" + diff $TESTDIR/$NAME.morph $TEMPDIR/$NAME.morph | grep '^<' | sed 's/^..//' + rm -f $TEMPDIR/$NAME.morph + exit 1 + fi + rm -f $TEMPDIR/$NAME.{morph,good} +fi + +check_valgrind_log "morphological analysis" + +# Tests suggestions +if test -f $TESTDIR/$NAME.sug; then + hunspell $* -a -d $TESTDIR/$NAME <$TESTDIR/$NAME.wrong | grep '^&' | \ + sed 's/^[^:]*: //' >$TEMPDIR/$NAME.sug + if ! cmp $TEMPDIR/$NAME.sug $TESTDIR/$NAME.sug >/dev/null; then + echo "=============================================" + echo "Fail in $NAME.sug. Bad suggestion?" + diff $TESTDIR/$NAME.sug $TEMPDIR/$NAME.sug + rm -f $TEMPDIR/$NAME.sug + exit 1 + fi + rm -f $TEMPDIR/$NAME.sug +fi + +check_valgrind_log "suggestion" diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.aff new file mode 100644 index 000000000..f56998b9f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.aff @@ -0,0 +1,3 @@ +SET UTF-8 + +# removing byte order mark from affix file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.dic new file mode 100644 index 000000000..8b10768e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.dic @@ -0,0 +1,2 @@ +1 +apéritif diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.good new file mode 100644 index 000000000..c344eaf5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.good @@ -0,0 +1,2 @@ +apéritif +APÉRITIF diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.test new file mode 100644 index 000000000..1d25699aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 -1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.aff new file mode 100644 index 000000000..784935c84 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.aff @@ -0,0 +1,3 @@ +SET UTF-8 + +# removing byte order mark from dic file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.dic new file mode 100644 index 000000000..b763179a0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.dic @@ -0,0 +1,2 @@ +1 +apéritif diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.good new file mode 100644 index 000000000..c344eaf5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.good @@ -0,0 +1,2 @@ +apéritif +APÉRITIF diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.test new file mode 100644 index 000000000..1d25699aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 -1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.aff new file mode 100644 index 000000000..979e3c228 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.aff @@ -0,0 +1 @@ +SET UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.dic new file mode 100644 index 000000000..4a040eeb0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.dic @@ -0,0 +1,5 @@ +4 # Old Persian numbers (1-4), source: Wikipedia +𐏑 +𐏒 +𐏒𐏑 +𐏒𐏒 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.good new file mode 100644 index 000000000..9f989d339 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.good @@ -0,0 +1,5 @@ +𐏑 +𐏒 +𐏒𐏑 +𐏒𐏒 + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.sug b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.sug new file mode 100644 index 000000000..bfe2a539f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.sug @@ -0,0 +1,2 @@ +𐏒𐏑, 𐏒𐏒 +𐏒𐏑, 𐏒𐏒 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.test new file mode 100644 index 000000000..1d25699aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 -1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.wrong b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.wrong new file mode 100644 index 000000000..d18dfa4c2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.wrong @@ -0,0 +1,2 @@ +𐏑𐏒𐏒 +𐏑𐏒𐏒 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8.aff new file mode 100644 index 000000000..e8934d71b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.aff @@ -0,0 +1,10 @@ +SET UTF-8 + +SFX A Y 7 +SFX A 0 őő . +SFX A 0 ő o +SFX A 0 ő ó +SFX A ó ő ó +SFX A ó őoo ó +SFX A o őo o +SFX A 0 ó [abcdó] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8.dic new file mode 100644 index 000000000..e7cb34daf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.dic @@ -0,0 +1,3 @@ +2 +foo/A +foó/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8.good new file mode 100644 index 000000000..08aa4dadf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.good @@ -0,0 +1,9 @@ +foo +foó +fooőő +fooő +foóő +foő +foőo +foőoo +foóó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.aff b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.aff new file mode 100644 index 000000000..43506afa3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.aff @@ -0,0 +1,3 @@ +SET UTF-8 +COMPOUNDMIN 3 +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.dic b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.dic new file mode 100644 index 000000000..ab90a1b70 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.dic @@ -0,0 +1,9 @@ +8 +foo/A +bar/A +fóó/A +áár/A +xy/A +yz/A +éé/A +őő/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.good b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.good new file mode 100644 index 000000000..1a1a1b19c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.good @@ -0,0 +1,5 @@ +foobar +barfoo +foobarfoo +fóóáár +áárfóó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.test b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.wrong b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.wrong new file mode 100644 index 000000000..fa385c1b0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.wrong @@ -0,0 +1,7 @@ +xyyz +fooxy +xyfoo +fooxybar +ééőő +fóóéé +őőáár diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.aff b/extensions/spellcheck/hunspell/tests/unit/data/warn.aff new file mode 100644 index 000000000..d586fa33e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.aff @@ -0,0 +1,13 @@ +# WARN flag +# The signed word, and its suffixed forms result warning message in command-line + +#Use to forbid the words with flag WARN +#FORBIDWARN + +WARN W + +SFX A Y 1 +SFX A 0 s . + +REP 1 +REP foo bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.dic b/extensions/spellcheck/hunspell/tests/unit/data/warn.dic new file mode 100644 index 000000000..d63f6047e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.dic @@ -0,0 +1,3 @@ +1 +foo/WA +bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.good b/extensions/spellcheck/hunspell/tests/unit/data/warn.good new file mode 100644 index 000000000..542f439a4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.good @@ -0,0 +1,2 @@ +foo +foos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.test b/extensions/spellcheck/hunspell/tests/unit/data/warn.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.aff b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.aff new file mode 100644 index 000000000..fdb047b0c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.aff @@ -0,0 +1,12 @@ +PSEUDOROOT X +COMPOUNDFLAG Y + +SFX A Y 1 +SFX A 0 0 . > + +SFX B Y 1 +SFX B 0 0 . > + +SFX C Y 2 +SFX C 0 0/XAB . +SFX C 0 baz/XAB . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.dic b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.dic new file mode 100644 index 000000000..72cba8d34 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.dic @@ -0,0 +1,3 @@ +2 +foo/XA bar +analyze(bar) = st:bar > +analyze(bar) = st:bar +analyze(bar) = st:bar > +analyze(bar) = st:bar > +stem(bar) = bar +> foo +analyze(foo) = st:foo +stem(foo) = foo +> barbaz +analyze(barbaz) = st:bar > +analyze(barbaz) = st:bar > +stem(barbaz) = bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.test b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js b/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js new file mode 100644 index 000000000..a67eeaec0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js @@ -0,0 +1,220 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var Cc = Components.classes; +var Ci = Components.interfaces; + +const tests = [ + ["affixes", "iso-8859-1"], + ["condition", "iso-8859-1"], + ["condition-utf", "UTF-8"], + ["base", "iso-8859-1"], + ["base-utf", "UTF-8"], + ["allcaps", "iso-8859-1"], + ["allcaps-utf", "UTF-8"], + ["allcaps2", "iso-8859-1"], + ["allcaps3", "iso-8859-1"], + ["keepcase", "iso-8859-1"], + ["i58202", "iso-8859-1"], + ["map", "iso-8859-1"], + ["rep", "iso-8859-1"], + ["sug", "iso-8859-1"], + ["sugutf", "UTF-8"], + ["phone", "iso-8859-1"], + ["flag", "iso-8859-1"], + ["flaglong", "iso-8859-1"], + ["flagnum", "iso-8859-1"], + ["flagutf8", "UTF-8"], + ["slash", "iso-8859-1"], + ["forbiddenword", "iso-8859-1"], + ["nosuggest", "iso-8859-1"], + ["alias", "iso-8859-1"], + ["alias2", "iso-8859-1"], + ["alias3", "iso-8859-1"], + ["breakdefault", "iso-8859-1"], + ["break", "UTF-8"], + ["needaffix", "iso-8859-1"], + ["needaffix2", "iso-8859-1"], + ["needaffix3", "iso-8859-1"], + ["needaffix4", "iso-8859-1"], + ["needaffix5", "iso-8859-1"], + ["circumfix", "iso-8859-1"], + ["fogemorpheme", "iso-8859-1"], + ["onlyincompound", "iso-8859-1"], + ["complexprefixes", "iso-8859-1"], + ["complexprefixes2", "iso-8859-1"], + ["complexprefixesutf", "UTF-8"], + ["conditionalprefix", "iso-8859-1"], + ["zeroaffix", "iso-8859-1"], + ["utf8", "UTF-8"], + ["utf8-bom", "UTF-8", {1: "todo"}], + ["utf8-bom2", "UTF-8", {1: "todo"}], + ["utf8-nonbmp", "UTF-8", {1: "todo", 2: "todo", 3: "todo", 4: "todo"}], + ["compoundflag", "iso-8859-1"], + ["compoundrule", "iso-8859-1"], + ["compoundrule2", "iso-8859-1"], + ["compoundrule3", "iso-8859-1"], + ["compoundrule4", "iso-8859-1"], + ["compoundrule5", "UTF-8"], + ["compoundrule6", "iso-8859-1"], + ["compoundrule7", "iso-8859-1"], + ["compoundrule8", "iso-8859-1"], + ["compoundaffix", "iso-8859-1"], + ["compoundaffix2", "iso-8859-1"], + ["compoundaffix3", "iso-8859-1"], + ["checkcompounddup", "iso-8859-1"], + ["checkcompoundtriple", "iso-8859-1"], + ["simplifiedtriple", "iso-8859-1"], + ["checkcompoundrep", "iso-8859-1"], + ["checkcompoundcase2", "iso-8859-1"], + ["checkcompoundcaseutf", "UTF-8"], + ["checkcompoundpattern", "iso-8859-1"], + ["checkcompoundpattern2", "iso-8859-1"], + ["checkcompoundpattern3", "iso-8859-1"], + ["checkcompoundpattern4", "iso-8859-1"], + ["utfcompound", "UTF-8"], + ["checksharps", "iso-8859-1"], + ["checksharpsutf", "UTF-8"], + ["germancompounding", "iso-8859-1"], + ["germancompoundingold", "iso-8859-1"], + ["i35725", "iso-8859-1"], + ["i53643", "iso-8859-1"], + ["i54633", "iso-8859-1"], + ["i54980", "iso-8859-1", {1: "todo", 3: "todo"}], + ["maputf", "UTF-8"], + ["reputf", "UTF-8"], + ["ignore", "iso-8859-1"], + ["ignoreutf", "UTF-8", + {1: "todo", 2: "todo", 3: "todo", 4: "todo", 5: "todo", 6: "todo", + 7: "todo", 8: "todo"}], + ["1592880", "iso-8859-1"], + ["1695964", "iso-8859-1"], + ["1463589", "iso-8859-1"], + ["1463589-utf", "UTF-8"], + ["IJ", "iso-8859-1"], + ["i68568", "iso-8859-1"], + ["i68568utf", "UTF-8"], + ["1706659", "iso-8859-1"], + ["digits-in-words", "iso-8859-1"], +// ["colons-in-words", "iso-8859-1"], Suggestion test only + ["ngram-utf-fix", "UTF-8"], + ["morph", "us-ascii", + {11: "todo", 12: "todo", 13: "todo", 14: "todo", 15: "todo", 16: "todo", + 17: "todo", 18: "todo", 19: "todo", 20: "todo", 21: "todo", 22: "todo", + 23: "todo", 24: "todo", 25: "todo", 26: "todo", 27: "todo"}], + ["1975530", "UTF-8"], + ["fullstrip", "iso-8859-1"], + ["iconv", "UTF-8"], + ["oconv", "UTF-8"], + ["encoding", "iso-8859-1", {1: "todo", 3: "todo"}], + ["korean", "UTF-8"], + ["opentaal-forbiddenword1", "UTF-8"], + ["opentaal-forbiddenword2", "UTF-8"], + ["opentaal-keepcase", "UTF-8"], + ["arabic", "UTF-8"], + ["2970240", "iso-8859-1"], + ["2970242", "iso-8859-1"], + ["breakoff", "iso-8859-1"], + ["opentaal-cpdpat", "iso-8859-1"], + ["opentaal-cpdpat2", "iso-8859-1"], + ["2999225", "iso-8859-1"], + ["onlyincompound2", "iso-8859-1"], + ["forceucase", "iso-8859-1"], + ["warn", "iso-8859-1"] +]; + +function do_get_file_by_line(file, charset) { + dump("getting file by line for file " + file.path + "\n"); + dump("using charset " + charset +"\n"); + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fis.init(file, 0x1 /* READONLY */, + 0o444, Ci.nsIFileInputStream.CLOSE_ON_EOF); + + let lis = Cc["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Ci.nsIConverterInputStream); + lis.init(fis, charset, 1024, 0); + lis.QueryInterface(Ci.nsIUnicharLineInputStream); + + var val = {}; + while (lis.readLine(val)) { + yield val.value; + val = {}; + } +} + +function do_run_test(checker, name, charset, todo_good, todo_bad) { + dump("\n\n\n\n"); + dump("running test for " + name + "\n"); + if (!checker) { + do_throw("Need spell checker here!"); + } + + let good = do_get_file("data/" + name + ".good", true); + let bad = do_get_file("data/" + name + ".wrong", true); + let sug = do_get_file("data/" + name + ".sug", true); + + dump("Need some expected output\n") + do_check_true(good.exists() || bad.exists() || sug.exists()); + + dump("Setting dictionary to " + name + "\n"); + checker.dictionary = name; + + if (good.exists()) { + var good_counter = 0; + for (val in do_get_file_by_line(good, charset)) { + let todo = false; + good_counter++; + if (todo_good && todo_good[good_counter]) { + todo = true; + dump("TODO\n"); + } + + dump("Expect word " + val + " is spelled correctly\n"); + if (todo) { + todo_check_true(checker.check(val)); + } else { + do_check_true(checker.check(val)); + } + } + } + + if (bad.exists()) { + var bad_counter = 0; + for (val in do_get_file_by_line(bad, charset)) { + let todo = false; + bad_counter++; + if (todo_bad && todo_bad[bad_counter]) { + todo = true; + dump("TODO\n"); + } + + dump("Expect word " + val + " is spelled wrong\n"); + if (todo) { + todo_check_false(checker.check(val)); + } else { + do_check_false(checker.check(val)); + } + } + } + + // XXXkhuey test suggestions +} + +function run_test() { + let spellChecker = Cc["@mozilla.org/spellchecker/engine;1"]. + getService(Ci.mozISpellCheckingEngine); + + do_check_true(!!spellChecker, "Should have a spell checker"); + spellChecker.QueryInterface(Ci.mozISpellCheckingEngine); + let testdir = do_get_file("data/", false); + spellChecker.loadDictionariesFromDir(testdir); + + function do_run_test_closure(test) { + [name, charset, todo_good, todo_bad] = test; + do_run_test(spellChecker, name, charset, todo_good, todo_bad); + } + + tests.forEach(do_run_test_closure); +} diff --git a/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini b/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini new file mode 100644 index 000000000..39e55e51f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +head = +tail = +skip-if = toolkit == 'android' +support-files = data/** + +[test_hunspell.js] diff --git a/extensions/spellcheck/idl/moz.build b/extensions/spellcheck/idl/moz.build new file mode 100644 index 000000000..c1fd32f14 --- /dev/null +++ b/extensions/spellcheck/idl/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +XPIDL_SOURCES += [ + 'mozIPersonalDictionary.idl', + 'mozISpellCheckingEngine.idl', + 'mozISpellI18NManager.idl', + 'mozISpellI18NUtil.idl', +] + +XPIDL_MODULE = 'spellchecker' + diff --git a/extensions/spellcheck/idl/mozIPersonalDictionary.idl b/extensions/spellcheck/idl/mozIPersonalDictionary.idl new file mode 100644 index 000000000..ce3bf3cb2 --- /dev/null +++ b/extensions/spellcheck/idl/mozIPersonalDictionary.idl @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIStringEnumerator; + +[scriptable, uuid(7EF52EAF-B7E1-462B-87E2-5D1DBACA9048)] + +/** + * This interface represents a Personal Dictionary. + */ + +interface mozIPersonalDictionary : nsISupports { + + /** + * Load the dictionary + */ + void load(); + + /** + * Save the dictionary + */ + void save(); + + /** + * Get the (lexicographically sorted) list of words + */ + readonly attribute nsIStringEnumerator wordList; + + /** + * Check a unicode string + */ + boolean check(in wstring word, in wstring lang); + + /** + * Add a word to the personal dictionary + */ + void addWord(in wstring word, in wstring lang); + + /** + * Remove a word from the personal dictionary + */ + void removeWord(in wstring word, in wstring lang); + + /** + * Add a word to the ignore all list + */ + void ignoreWord(in wstring word); + + /** + * Clear the ignore list + */ + void endSession(); + + /** + * These three functions are here in case we want to store previous + * misspellings and return them at the head of the misspell list. + */ + + /** + * Add a misspelling to the list of corrections + */ + void addCorrection(in wstring word,in wstring correction, in wstring lang); + + /** + * Remove a misspelling from the list of corrections + */ + void removeCorrection(in wstring word,in wstring correction, in wstring lang); + + /** + * Get a list of previous corrections for the word + */ + void getCorrection(in wstring word, [array, size_is(count)] out wstring words, out uint32_t count); +}; diff --git a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl new file mode 100644 index 000000000..95784b141 --- /dev/null +++ b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIFile; +interface mozIPersonalDictionary; + +[scriptable, uuid(8ba643a4-7ddc-4662-b976-7ec123843f10)] + +/** + * This interface represents a SpellChecker. + */ + +interface mozISpellCheckingEngine : nsISupports { + /** + * The name of the current dictionary. Is either a value from + * getDictionaryList or the empty string if no dictionary is selected. + * Setting this attribute to a value not in getDictionaryList will throw + * NS_ERROR_FILE_NOT_FOUND. + * + * If the dictionary is changed to no dictionary (the empty string), an + * observer is allowed to set another dictionary before it returns. + */ + attribute wstring dictionary; + + /** + * The language this spellchecker is using when checking + */ + readonly attribute wstring language; + + /** + * Does the engine provide its own personal dictionary? + */ + readonly attribute boolean providesPersonalDictionary; + + /** + * Does the engine provide its own word utils? + */ + readonly attribute boolean providesWordUtils; + + /** + * The name of the engine + */ + readonly attribute wstring name; + + /** + * a string indicating the copyright of the engine + */ + readonly attribute wstring copyright; + + /** + * the personal dictionary + */ + attribute mozIPersonalDictionary personalDictionary; + + /** + * Get the list of dictionaries + */ + void getDictionaryList([array, size_is(count)] out wstring dictionaries, out uint32_t count); + + /** + * check a word + */ + boolean check(in wstring word); + + /** + * get a list of suggestions for a misspelled word + */ + void suggest(in wstring word,[array, size_is(count)] out wstring suggestions, out uint32_t count); + + /** + * Load dictionaries from the specified dir + */ + void loadDictionariesFromDir(in nsIFile dir); + + /** + * Add dictionaries from a directory to the spell checker + */ + void addDirectory(in nsIFile dir); + + /** + * Remove dictionaries from a directory from the spell checker + */ + void removeDirectory(in nsIFile dir); +}; + +%{C++ +#define DICTIONARY_SEARCH_DIRECTORY "DictD" +#define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL" + +#define SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION \ + "spellcheck-dictionary-remove" +%} diff --git a/extensions/spellcheck/idl/mozISpellI18NManager.idl b/extensions/spellcheck/idl/mozISpellI18NManager.idl new file mode 100644 index 000000000..b702608a9 --- /dev/null +++ b/extensions/spellcheck/idl/mozISpellI18NManager.idl @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" +#include "mozISpellI18NUtil.idl" + +[scriptable, uuid(AEB8936F-219C-4D3C-8385-D9382DAA551A)] + +/** + * This interface contains various I18N related code used in various places + * by the spell checker. + */ + +interface mozISpellI18NManager : nsISupports { + /** + * Get a mozISpellI18NUtil interface that best matches the given language. + */ + mozISpellI18NUtil getUtil(in wstring language); +}; diff --git a/extensions/spellcheck/idl/mozISpellI18NUtil.idl b/extensions/spellcheck/idl/mozISpellI18NUtil.idl new file mode 100644 index 000000000..17d9ec234 --- /dev/null +++ b/extensions/spellcheck/idl/mozISpellI18NUtil.idl @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +[scriptable, uuid(B075D5DC-1DF1-441A-BEBF-680D8CAAA19C)] + +/** + * This interface contains various I18N related code used in various places by the spell checker. + */ + +interface mozISpellI18NUtil : nsISupports { + + const uint32_t kCheck=0; + const uint32_t kSuggest=1; + + /** + * The language being used to check spelling + */ + readonly attribute wstring language; + + /** + * Given a word return a list of possible root forms of that word + */ + void getRootForm(in wstring word, + in uint32_t type, + [array, size_is(count)] out wstring words, + out uint32_t count); + + /** + * Given a word return a list of possible root forms of that word + */ + void fromRootForm(in wstring word, + [array, size_is(icount)] in wstring iwords, + in uint32_t icount, + [array, size_is(ocount)] out wstring owords, + out uint32_t ocount); + + /** + * Given a unicode string and an offset, find the beginning and end of the + * next word. begin and end are -1 if there are no words remaining in the + * string. This should really be folded into the Line/WordBreaker. + */ + void findNextWord(in wstring word, in uint32_t length, in uint32_t offset, out int32_t begin, out int32_t end); +}; diff --git a/extensions/spellcheck/locales/Makefile.in b/extensions/spellcheck/locales/Makefile.in new file mode 100644 index 000000000..4cd2a4204 --- /dev/null +++ b/extensions/spellcheck/locales/Makefile.in @@ -0,0 +1,7 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DICTIONARY_FILES = $(strip $(wildcard $(LOCALE_SRCDIR)/hunspell/*.dic) $(wildcard $(LOCALE_SRCDIR)/hunspell/*.aff)) +DICTIONARY_DEST = $(FINAL_TARGET)/dictionaries +INSTALL_TARGETS += DICTIONARY diff --git a/extensions/spellcheck/locales/en-US/hunspell/README_en_US.txt b/extensions/spellcheck/locales/en-US/hunspell/README_en_US.txt new file mode 100644 index 000000000..6a3813d34 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/README_en_US.txt @@ -0,0 +1,347 @@ +en_US-mozilla Hunspell Dictionary +Generated from SCOWL Version 2017.01.22 +Tue Jan 24 22:59:28 EST 2017 + +http://wordlist.sourceforge.net + +README file for English Hunspell dictionaries derived from SCOWL. + +These dictionaries are created using the speller/make-hunspell-dict +script in SCOWL. + +The following dictionaries are available: + + en_US (American) + en_CA (Canadian) + en_GB-ise (British with "ise" spelling) + en_GB-ize (British with "ize" spelling) + en_AU (Australian) + + en_US-large + en_CA-large + en_GB-large (with both "ise" and "ize" spelling) + en_AU-large + +The normal (non-large) dictionaries correspond to SCOWL size 60 and, +to encourage consistent spelling, generally only include one spelling +variant for a word. The large dictionaries correspond to SCOWL size +70 and may include multiple spelling for a word when both variants are +considered almost equal. The larger dictionaries however (1) have not +been as carefully checked for errors as the normal dictionaries and +thus may contain misspelled or invalid words; and (2) contain +uncommon, yet valid, words that might cause problems as they are +likely to be misspellings of more common words (for example, "ort" and +"calender"). + +To get an idea of the difference in size, here are 25 random words +only found in the large dictionary for American English: + + Bermejo Freyr's Guenevere Hatshepsut Nottinghamshire arrestment + crassitudes crural dogwatches errorless fetial flaxseeds godroon + incretion jalapeño's kelpie kishkes neuroglias pietisms pullulation + stemwinder stenoses syce thalassic zees + +The en_US, en_CA and en_AU are the official dictionaries for Hunspell. +The en_GB and large dictionaries are made available on an experimental +basis. If you find them useful please send me a quick email at +kevina@gnu.org. + +If none of these dictionaries suite you (for example, maybe you want +the normal dictionary that also includes common variants) additional +dictionaries can be generated at http://app.aspell.net/create or by +modifying speller/make-hunspell-dict in SCOWL. Please do let me know +if you end up publishing a customized dictionary. + +If a word is not found in the dictionary or a word is there you think +shouldn't be, you can lookup the word up at http://app.aspell.net/lookup +to help determine why that is. + +General comments on these list can be sent directly to me at +kevina@gnu.org or to the wordlist-devel mailing lists +(https://lists.sourceforge.net/lists/listinfo/wordlist-devel). If you +have specific issues with any of these dictionaries please file a bug +report at https://github.com/kevina/wordlist/issues. + +IMPORTANT CHANGES INTRODUCED In 2016.11.20: + +New Australian dictionaries thanks to the work of Benjamin Titze +(btitze@protonmail.ch). + +IMPORTANT CHANGES INTRODUCED IN 2016.04.24: + +The dictionaries are now in UTF-8 format instead of ISO-8859-1. This +was required to handle smart quotes correctly. + +IMPORTANT CHANGES INTRODUCED IN 2016.01.19: + +"SET UTF8" was changes to "SET UTF-8" in the affix file as some +versions of Hunspell do not recognize "UTF8". + +ADDITIONAL NOTES: + +The NOSUGGEST flag was added to certain taboo words. While I made an +honest attempt to flag the strongest taboo words with the NOSUGGEST +flag, I MAKE NO GUARANTEE THAT I FLAGGED EVERY POSSIBLE TABOO WORD. +The list was originally derived from Németh László, however I removed +some words which, while being considered taboo by some dictionaries, +are not really considered swear words in today's society. + +COPYRIGHT, SOURCES, and CREDITS: + +The English dictionaries come directly from SCOWL +and is thus under the same copyright of SCOWL. The affix file is +a heavily modified version of the original english.aff file which was +released as part of Geoff Kuenning's Ispell and as such is covered by +his BSD license. Part of SCOWL is also based on Ispell thus the +Ispell copyright is included with the SCOWL copyright. + +The collective work is Copyright 2000-2016 by Kevin Atkinson as well +as any of the copyrights mentioned below: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell these word + lists, the associated scripts, the output created from the scripts, + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appears in all copies and + that both that copyright notice and this permission notice appear in + supporting documentation. Kevin Atkinson makes no representations + about the suitability of this array for any purpose. It is provided + "as is" without express or implied warranty. + +Alan Beale also deserves special credit as he has, +in addition to providing the 12Dicts package and being a major +contributor to the ENABLE word list, given me an incredible amount of +feedback and created a number of special lists (those found in the +Supplement) in order to help improve the overall quality of SCOWL. + +The 10 level includes the 1000 most common English words (according to +the Moby (TM) Words II [MWords] package), a subset of the 1000 most +common words on the Internet (again, according to Moby Words II), and +frequently class 16 from Brian Kelk's "UK English Wordlist +with Frequency Classification". + +The MWords package was explicitly placed in the public domain: + + The Moby lexicon project is complete and has + been place into the public domain. Use, sell, + rework, excerpt and use in any way on any platform. + + Placing this material on internal or public servers is + also encouraged. The compiler is not aware of any + export restrictions so freely distribute world-wide. + + You can verify the public domain status by contacting + + Grady Ward + 3449 Martha Ct. + Arcata, CA 95521-4884 + + grady@netcom.com + grady@northcoast.com + +The "UK English Wordlist With Frequency Classification" is also in the +Public Domain: + + Date: Sat, 08 Jul 2000 20:27:21 +0100 + From: Brian Kelk + + > I was wondering what the copyright status of your "UK English + > Wordlist With Frequency Classification" word list as it seems to + > be lacking any copyright notice. + + There were many many sources in total, but any text marked + "copyright" was avoided. Locally-written documentation was one + source. An earlier version of the list resided in a filespace called + PUBLIC on the University mainframe, because it was considered public + domain. + + Date: Tue, 11 Jul 2000 19:31:34 +0100 + + > So are you saying your word list is also in the public domain? + + That is the intention. + +The 20 level includes frequency classes 7-15 from Brian's word list. + +The 35 level includes frequency classes 2-6 and words appearing in at +least 11 of 12 dictionaries as indicated in the 12Dicts package. All +words from the 12Dicts package have had likely inflections added via +my inflection database. + +The 12Dicts package and Supplement is in the Public Domain. + +The WordNet database, which was used in the creation of the +Inflections database, is under the following copyright: + + This software and database is being provided to you, the LICENSEE, + by Princeton University under the following license. By obtaining, + using and/or copying this software and database, you agree that you + have read, understood, and will comply with these terms and + conditions.: + + Permission to use, copy, modify and distribute this software and + database and its documentation for any purpose and without fee or + royalty is hereby granted, provided that you agree to comply with + the following copyright notice and statements, including the + disclaimer, and that the same appear on ALL copies of the software, + database and documentation, including modifications that you make + for internal use or for distribution. + + WordNet 1.6 Copyright 1997 by Princeton University. All rights + reserved. + + THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- + ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE + LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT INFRINGE ANY + THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + The name of Princeton University or Princeton may not be used in + advertising or publicity pertaining to distribution of the software + and/or database. Title to copyright in this software, database and + any associated documentation shall at all times remain with + Princeton University and LICENSEE agrees to preserve same. + +The 40 level includes words from Alan's 3esl list found in version 4.0 +of his 12dicts package. Like his other stuff the 3esl list is also in the +public domain. + +The 50 level includes Brian's frequency class 1, words appearing +in at least 5 of 12 of the dictionaries as indicated in the 12Dicts +package, and uppercase words in at least 4 of the previous 12 +dictionaries. A decent number of proper names is also included: The +top 1000 male, female, and Last names from the 1990 Census report; a +list of names sent to me by Alan Beale; and a few names that I added +myself. Finally a small list of abbreviations not commonly found in +other word lists is included. + +The name files form the Census report is a government document which I +don't think can be copyrighted. + +The file special-jargon.50 uses common.lst and word.lst from the +"Unofficial Jargon File Word Lists" which is derived from "The Jargon +File". All of which is in the Public Domain. This file also contain +a few extra UNIX terms which are found in the file "unix-terms" in the +special/ directory. + +The 55 level includes words from Alan's 2of4brif list found in version +4.0 of his 12dicts package. Like his other stuff the 2of4brif is also +in the public domain. + +The 60 level includes all words appearing in at least 2 of the 12 +dictionaries as indicated by the 12Dicts package. + +The 70 level includes Brian's frequency class 0 and the 74,550 common +dictionary words from the MWords package. The common dictionary words, +like those from the 12Dicts package, have had all likely inflections +added. The 70 level also included the 5desk list from version 4.0 of +the 12Dics package which is in the public domain. + +The 80 level includes the ENABLE word list, all the lists in the +ENABLE supplement package (except for ABLE), the "UK Advanced Cryptics +Dictionary" (UKACD), the list of signature words from the YAWL package, +and the 10,196 places list from the MWords package. + +The ENABLE package, mainted by M\Cooper , +is in the Public Domain: + + The ENABLE master word list, WORD.LST, is herewith formally released + into the Public Domain. Anyone is free to use it or distribute it in + any manner they see fit. No fee or registration is required for its + use nor are "contributions" solicited (if you feel you absolutely + must contribute something for your own peace of mind, the authors of + the ENABLE list ask that you make a donation on their behalf to your + favorite charity). This word list is our gift to the Scrabble + community, as an alternate to "official" word lists. Game designers + may feel free to incorporate the WORD.LST into their games. Please + mention the source and credit us as originators of the list. Note + that if you, as a game designer, use the WORD.LST in your product, + you may still copyright and protect your product, but you may *not* + legally copyright or in any way restrict redistribution of the + WORD.LST portion of your product. This *may* under law restrict your + rights to restrict your users' rights, but that is only fair. + +UKACD, by J Ross Beresford , is under the +following copyright: + + Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved. + + The following restriction is placed on the use of this publication: + if The UK Advanced Cryptics Dictionary is used in a software package + or redistributed in any form, the copyright notice must be + prominently displayed and the text of this document must be included + verbatim. + + There are no other restrictions: I would like to see the list + distributed as widely as possible. + +The 95 level includes the 354,984 single words, 256,772 compound +words, 4,946 female names and the 3,897 male names, and 21,986 names +from the MWords package, ABLE.LST from the ENABLE Supplement, and some +additional words found in my part-of-speech database that were not +found anywhere else. + +Accent information was taken from UKACD. + +The VarCon package was used to create the American, British, Canadian, +and Australian word list. It is under the following copyright: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Kevin Atkinson makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Copyright 2016 by Benjamin Titze + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Benjamin Titze makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Since the original words lists come from the Ispell distribution: + + Copyright 1993, Geoff Kuenning, Granada Hills, CA + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All modifications to the source code must be clearly marked as + such. Binary redistributions based on modified source code + must be clearly marked as modified versions in the documentation + and/or other materials provided with the distribution. + (clause 4 removed with permission from Geoff Kuenning) + 5. The name of Geoff Kuenning may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +Build Date: Tue Jan 24 22:59:28 EST 2017 diff --git a/extensions/spellcheck/locales/en-US/hunspell/README_mozilla.txt b/extensions/spellcheck/locales/en-US/hunspell/README_mozilla.txt new file mode 100644 index 000000000..27be3d7b6 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/README_mozilla.txt @@ -0,0 +1,6 @@ +README_mozilla + +To edit the dictionary use "dictionary-sources/edit-dictionary". + +For additional info see dictionary-sources/README. + diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-added b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-added new file mode 100644 index 000000000..6cb38be64 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-added @@ -0,0 +1,5740 @@ +API's +APIs +ATPase +ATPase's +Ab's +Abba +Abbie +Abbie's +Abdel +Abdel's +AbeBooks +Abie +Abie's +Abra +Abra's +Abramo +Abramo's +ActiveX +ActiveX's +Acura +Acura's +Adah +Adah's +Adair +Adair's +Adaline +Adaline's +Adamo +Adamo's +AddThis +AddThis's +Adda +Adda's +Addi +Addi's +Addy +Addy's +Ade +Ade's +Adel +Adel's +Adelaida +Adelaida's +Adelbert +Adelbert's +Adelheid +Adelheid's +Adelina +Adelina's +Adelle +Adelle's +Adena +Adena's +Adey +Adey's +Adham +Adham's +Adi +Adi's +Adina +Adina's +Adlai +Adlai's +Adolphe +Adolphe's +Adolphus +Adolphus's +Adore's +Adria +Adria's +Adriane +Adriane's +Adrianna +Adrianna's +Adrianne +Adrianne's +Adriano +Adriano's +Adrien +Adrien's +Afton +Afton's +Agata +Agata's +Agathe +Agathe's +Agilent +Agnese +Agnese's +Agosto +Agosto's +Aharon +Aharon's +Aidan +Aidan's +Aila +Aila's +Ailey +Ailey's +Aime +Aime's +Ainsley +Ainsley's +Ainslie +Ainslie's +Ajay +Ajay's +Akim +Akim's +Alain +Alain's +Alameda +Alameda's +Aland +Aland's +Alanna +Alanna's +Alanson +Alanson's +Alasdair +Alasdair's +Alastair +Alastair's +Albertina +Albertina's +Albertine +Albertine's +Albie +Albie's +Albina +Albina's +Albrecht +Albrecht's +Aldin +Aldin's +Aldis +Aldis's +Aldon +Aldon's +Aldous +Aldous's +Aldrich +Aldrich's +Aldridge +Aldridge's +Aldus +Aldus's +Aleksandr +Aleksandr's +Alena +Alena's +Alene +Alene's +Alessandra +Alessandra's +Alessandro +Alessandro's +Alethea +Alethea's +Alexa +Alexa's +Alexandr +Alexandr's +Alexandre +Alexandre's +Alexandrina +Alexandrina's +Alexandros +Alexi +Alexi's +Alexia +Alexia's +Alexina +Alexina's +Alf +Alf's +Alfie +Alfie's +Alfons +Alfons's +Alfonse +Alfonse's +Algernon +Algernon's +Alia +Alia's +Alick +Alick's +Alida +Alida's +Alina +Alina's +Alis +Alister +Alister's +Alix +Alix's +Alla +Alla's +Allard +Allard's +Allene +Allene's +Alleyn +Alleyn's +Allister +Allister's +Allyn +Allyn's +Almeria +Almeria's +Almira +Almira's +Alon +Alon's +Alonso +Alonso's +Aloysius +Aloysius's +Alric +Alric's +Alvan +Alvan's +Alvina +Alvina's +Alvis +Alvis's +Alvy +Alvy's +Alwin +Alwin's +Alwyn +Alwyn's +Alyosha +Alyosha's +Alys +Alys's +Alyss +Amabel +Amabel's +Amalie +Amalie's +Amara +Amara's +Amata +Amata's +Ambros +Ambros's +Ambrose +Ambrosio +Ambrosio's +Ambrosius +Ambrosius's +Ame +Ame's +Amelie +Amelie's +Amerigo +Amerigo's +Amery +Amery's +Ami +Ami's +Amil +Amil's +Amory +Amory's +Analise +Analise's +Anatol +Anatol's +Anders +Andi +Andi's +Andie +Andie's +Andra +Andra's +Andras +Andreas +Andree +Andree's +Andrej +Andrej's +Andrey +Andrey's +Andria +Andria's +Andros +Andrus +Andrus's +Anet +Anet's +Ange +Ange's +Angele +Angele's +Angeli +Angeli's +Angelika +Angelika's +Ania +Ania's +Annabella +Annabella's +Annalise +Annalise's +Anneliese +Anneliese's +Annelise +Annelise's +Annemarie +Annemarie's +Anni +Anni's +Annis +Anny +Anny's +Ansel +Ansel's +Ansell +Ansell's +Ansley +Ansley's +Anson +Anson's +Anstice +Anstice's +Anthea +Anthea's +Antin +Antin's +Antonella +Antonella's +Antoni +Antoni's +Antonie +Antonie's +Antonietta +Antonietta's +Antonin +Antonin's +Antonina +Antonina's +Antonino +Antonino's +Any's +Anya +Anya's +Arabella +Arabella's +Arabidopsis +Archambault +Archambault's +Archy +Archy's +Arda +Arda's +Ardis +Ardis's +Aretha +Aretha's +Ari +Ari's +Arial +Arial's +Ariana +Ariana's +Arie +Arie's +Arielle +Arielle's +Arin +Arin's +Arlen +Arlen's +Arlette +Arlette's +Arley +Arley's +Arlie +Arlie's +Arlin +Arlin's +Arly +Arly's +Arman +Arman's +Armin +Armin's +Arnaldo +Arnaldo's +Arne +Arni +Arni's +Arnie +Arnie's +Arnoldo +Arnoldo's +Arte +Arte's +Artemas +Artemus +Artemus's +Artur +Artur's +Artus +Artus's +Arty's +Arv +Arv's +Arvin +Arvin's +Asa +Asa's +Ase +Ase's +Ashby +Ashby's +Asher +Ashleigh +Ashleigh's +Ashton +Astra +Astra's +Astrid +Astrid's +Athlon +Athlon's +Aube +Aubert +Aubert's +Aubry +Aubry's +Audie +Audie's +Audre +Audre's +Augie +Augie's +Auguste +Auguste's +Augustin +Augustin's +Augusto +Augusto's +Aurea +Aurea's +Aurel +Aurel's +Aurelie +Aurelie's +Aurore +Aurore's +Aveline +Aveline's +Averell +Averell's +Averil +Averil's +Averill +Averill's +Avigdor +Avigdor's +Aviva +Aviva's +Avram +Avram's +Avril +Avril's +Axe +Axe's +Axel +Aylmer +Aylmer's +Aymer +Aymer's +Ayn +Ayn's +Bab +Bab's +Babb +Babb's +Babbie +Babbie's +Babette +Babette's +Babs +Bailie +Bailie's +Baillie +Baillie's +Baily +Baily's +Bald's +Bancorp +Barbe +Barbe's +Barbee +Barbee's +Barbette +Barbette's +Barbey +Barbey's +Barde +Barde's +Bari +Bari's +Barret +Barret's +Barri +Barri's +Barris +Bartel +Bartel's +Barthel +Barthel's +Bartlet +Bartlet's +Bartolomeo +Bartolomeo's +Bartram +Bartram's +Barty +Barty's +Bary +Bary's +Basia +Basia's +Basile +Basile's +Basilio +Basilio's +Basilius +Basilius's +Bastian +Bastian's +Bastien +Bastien's +Baudoin +Baudoin's +Bax +Bayard +Bea +Bea's +Beale +Beale's +Bebe +Bebe's +Becca +Becca's +Becka +Becka's +Beckham +Beckham's +Beckie +Beckie's +Bel +Bel's +Belkin +Belkin's +Bellevue +Bellevue's +Beltran +Beltran's +Belva +Belva's +Benedetta +Benedetta's +Benedetto +Benedetto's +Benedick +Benedick's +Benedicta +Benedicta's +Benedicto +Benedicto's +Benedikt +Benedikt's +Bengt +Bengt's +Benji +Benji's +Benjie +Benjie's +Benjy +Benjy's +Benn +Benn's +Benoit +Benoit's +Ber +Ber's +Berk +Berk's +Berke +Berke's +Berkley +Berkley's +Bernardine +Bernhard +Bernhard's +Berni +Berni's +Berri +Berri's +Berthe +Berthe's +Berti +Berti's +Berton +Berton's +Bespin +Bespin's +Bessy +Bessy's +Betsey +Betsey's +Betta +Betta's +Betti +Bettina +Bettina's +Bevan +Bevin +Bevvy's +BibSonomy +BibSonomy's +BibTeX +BibTeX's +Bibby +Bibby's +Bibi +Bibi's +Bil +Bil's +Bili +Bili's +Bink +Bink's +Binky +Binky's +Binnie +Binnie's +Birgit +Birgit's +Birgitta +Birgitta's +Birk +Birk's +Biron +Biron's +BizRate +BizRate's +Bjorn +Bjorn's +Blakeley +Blakeley's +Blanch's +Blane +Blane's +BlinkList +BlinkList's +Blithe's +Bloomberg +Bloomberg's +Bo +Bo's +Bondy +Bondy's +Bonsai +Bonsai's +Boothe +Boothe's +Bord +Bord's +Bourke +Bourke's +Boyce +Boyce's +Braden +Braden's +Bram +Bram's +Brande +Brande's +Brander +Brander's +Brannon +Brannon's +Brantley +Brantley's +Bree +Bree's +Bren +Bren's +Brenden +Brenden's +Brendon +Brendon's +Brenna +Brenna's +Brianne +Brianne's +Briant +Briant's +Bridie +Bridie's +Brien +Brien's +Brigg +Brigg's +Brigida +Brigida's +Brigit +Brigit's +Brigitta +Brigitta's +Briny's +Brion +Brion's +Brita +Brita's +Britta +Britta's +Brittan +Brittan's +Brod +Brod's +Broderick +Broderick's +Brodie +Brodie's +Brody +Brody's +Bron +Bron's +Brose +Brose's +Bryn +Bryn's +Brynn +Brynn's +Bucky +Bucky's +Budd +Budd's +Burk +Burk's +Burkina +Burkina's +Burnaby +Burnaby's +Burnard +Burnard's +Byram +Byram's +Byrom +Byrom's +CEOs +CFCs +Cad +Cad's +Caicos +Caicos's +Cale +Cale's +Calley +Calley's +Calli +Calli's +Cally +Cally's +Cambridgeshire +Cambridgeshire's +Cami +Cami's +Camila +Camila's +Camino +Camino's +Cammie +Cammie's +Cammy +Cammy's +Candi +Candi's +Candida +Candida's +Candra +Candra's +CareerBuilder +CareerBuilder's +Caren +Caren's +Cari +Cari's +Caria +Carin +Carin's +Carine +Carine's +Carita +Carita's +Carlen +Carlen's +Carleton +Carleton's +Carley +Carley's +Carlie +Carlie's +Carling +Carling's +Carlisle +Carlisle's +Carlota +Carlotta +Carlotta's +Carmel +Carmelita +Carmelita's +Carmina +Carmina's +Caro +Caro's +Carola +Carola's +Carolan +Carolan's +Carolus +Carolus's +Carolyne +Carolyne's +Caron +Caron's +Carrol +Carrol's +Caryl +Caryl's +Caryn +Caryn's +Casar +Casar's +Casi +Casi's +Casper +Casper's +Cass +Cass's +Cassi +Cassi's +Cassini +Cassini's +Cassy +Cassy's +Catarina +Catarina's +Cate +Cate's +Caterina +Caterina's +Catharina +Catharina's +Catharine +Catharine's +Cathie +Cathie's +Cati +Cati's +Catie +Catie's +Catlin +Catlin's +Catrina +Catrina's +Catriona +Catriona's +Caye +Caye's +Caz +Caz's +Cece +Cece's +Cecilio +Cecilio's +Ced +Ced's +Ceil +Ceil's +Cele +Cele's +Celestia +Celestia's +Celestina +Celestina's +Celestine +Celestine's +Celie +Celie's +Celine +Celine's +Celle +Celle's +Centro +Centro's +Cesare +Cesare's +Chaim +Chaim's +Chancey +Chancey's +Chanda +Chanda's +Chane +Chane's +Channa +Channa's +Chantal +Chantal's +Chara +Charis +Charisse +Charisse's +Charlot +Charlot's +Charlotta +Charlotta's +Charlton +Charmian +Charmian's +Chas +ChatZilla +ChatZilla's +Chatham +Chatham's +Cher +Chere +Chere's +Cherise +Cherise's +Cherish's +Ches +Chet +Chet's +Chev +Chev's +Chico +Chico's +Chilton +Chilton's +Chloris +Chloris's +Choi +Choi's +Chrissie +Chrissie's +Chrissy +Chrissy's +Christabel +Christabel's +Christel +Christel's +Christen's +Christiana +Christiana's +Christiane +Christiane's +Christianized +Christianizing +Christoph +Christoph's +Christophe +Christos +Christos's +Cicely +Cicely's +Ciel +Ciel's +Cindi +Cindi's +Cingular +Cingular's +Cirillo +Cirillo's +Ciro +Ciro's +Cissy +Cissy's +Clari +Clari's +Claribel +Claribel's +Clarinda +Clarinda's +Clarisse +Clarisse's +Clarita +Clarita's +Clarkson +Clarkson's +Clary +Clary's +Claudian +Claudian's +Clayborne +Clayborne's +Clea +Clea's +Clemence +Clemence's +Clemente +Clemente's +Clementina +Clementina's +Clemmie +Clemmie's +Cleon +Clerc +Clerc's +Cletus +Cletus's +Cleve +Cleve's +Clo +Clo's +Clotilda +Clotilda's +ColdFusion +ColdFusion's +Colet +Coletta +Coletta's +Collen +Collen's +Collette +Collette's +Colline +Colline's +Colman +Colman's +Comcast +Comcast's +Composer +Composer's +Computerworld +Computerworld's +Conant +Conant's +Conchita +Conchita's +Concordia +Concordia's +Connor +Connor's +Conny +Conny's +Conrado +Conrado's +Conroy +Conroy's +Constancia +Constancia's +Constanta +Constanta's +Constantia +Constantin +Constantin's +Constantino +Constantino's +Consuela +Consuela's +Coralie +Coralie's +Corbet +Corbet's +Corbett +Corbett's +Corbie +Corbie's +Corbin +Corbin's +Corby +Cordell +Cordell's +Cordy +Cordy's +Coretta +Coretta's +Cori +Cori's +Corinna +Corinna's +Corliss +Corliss's +Corney +Corney's +Corny's +Corrie +Corrie's +Corry +Corry's +Cort +Cort's +Cosette +Cosette's +Cosimo +Cosimo's +Cosme +Cosme's +Cosmo +Cosmo's +Costa +Costa's +Costanza +Costanza's +Councillor +Councillor's +Councillors +Courtenay +Courtenay's +Craggy's +Craigslist +Craigslist's +Cris +Cris's +Crissy +Crissy's +Crista +Crista's +Cristal +Cristal's +Cristian +Cristian's +Cristiano +Cristiano's +Cristobal +Cristobal's +Culley +Culley's +Cully +Cully's +Culver +Culver's +Cumbria +Cumbria's +Curcio +Curcio's +Curr +Curr's +Curran +Curran's +Currey +Currey's +Currie +Currie's +Curtice +Curtice's +Cy +Cybil +Cybil's +Cyndi +Cyndi's +Cynthy +Cynthy's +Cyrille +Cyrille's +D'Arcy +DRM +DVDs +Dacey +Dacey's +Dacia +Daffy's +Dag's +Dagmar +Dagmar's +Dagny +Dagny's +Dal +Dal's +Dalia +Dalia's +Dalila +Dalila's +Dall +Dall's +Damara +Damara's +Damaris +Damaris's +Damiano +Damiano's +Danette +Danette's +Dani +Dani's +Dania +Dania's +Danica +Danica's +Daniela +Daniela's +Daniele +Daniele's +Daniella +Daniella's +Danna +Danna's +Danni +Danni's +Dar +Dar's +Dara +Dara's +Darcey +Darcey's +Darci +Darci's +Darcie +Darcie's +Dari +Dari's +Daria +Daria's +Daron +Daron's +Darsie +Darsie's +Darya +Darya's +Dasha +Dasha's +Dav +Dav's +Davey +Davey's +Davida +Davida's +Davide +Davide's +Davie +Davie's +Davin +Davin's +Davina +Davina's +Dayna +Dayna's +Daytona +Daytona's +De +De's +DeKalb +DeKalb's +DealTime +DealTime's +Deane +Deane's +Deb +Deb's +Debbi +Debbi's +Debi +Debi's +Dede +Dede's +Deedee +Deedee's +Dela +Dela's +Delmore +Delmore's +Deloitte +Deloitte's +Deloria +Deloria's +Delphine +Delphine's +Demetri +Demetri's +Demetria +Demetria's +Demott +Demott's +Dene +Deni +Deni's +Denney +Denney's +Dennie +Dennie's +Dennison +Dennison's +Denton +Denton's +Deny's +Denys +Der +Der's +Derk +Derk's +Derry +Des +Deseret +Deseret's +Desi +Desi's +Dev +Dev's +Deva +Deva's +Devan +Devan's +Devlin +Devlin's +Dex +Dex's +Dhabi +Dian +Dian's +Dickie +Dickie's +Dicky +Dicky's +Didi +Didi's +Dierdre +Dierdre's +Dieter +Dieter's +Digg +Digg's +Diggs +Dimitri +Dimitri's +Dinny +Dinny's +Dione +Dionisio +Dionisio's +Dita +Dita's +DivX +DivX's +Dodi +Dodi's +Dodie +Dodie's +Dolf +Dolf's +Dolley +Dolley's +Dolph +Dolph's +Dom +Domenic +Domenic's +Domenico +Domenico's +Domini +Domini's +Dominik +Dominik's +Donal +Donal's +Dore +Dore's +Dorey +Dorey's +Dori +Dori's +Doria +Doria's +Dorie +Dorie's +Dorise +Dorise's +Doro +Doro's +Dorotea +Dorotea's +Dorothee +Dorothee's +Dorrie +Dorrie's +Dorris +Dosi +Dosi's +Dottie +Dottie's +Dotty's +Dougie +Dougie's +Dov +Dov's +Doy +Doy's +Dre +Dre's +Dreamweaver +Dreamweaver's +Drona +Drona's +Dru +Dru's +Drusilla +Drusilla's +Duff +Duff's +Duffie +Duffie's +Dugald +Dugald's +Dulce +Dulce's +Dulcie +Dulcie's +Dulcinea +Dulcinea's +Dunstan +Dur +Durand +Durand's +Durward +Durward's +Dyan +Dyan's +Dyna +Dyna's +Eadie +Eadie's +Eal +Eal's +Eamon +Eamon's +Early's +Easton +Easton's +Eb +Eb's +Eba +Eba's +Ebba +Ebba's +Ebenezer +Ebenezer's +Eberhard +Eberhard's +Ecma +Ecma's +Eda +Eda's +Edd +Edd's +Ede +Edgard +Edgard's +Edi +Edi's +Edie +Edie's +Edin +Edin's +Editha +Editha's +Edlin +Edlin's +Edouard +Edouard's +Eduard +Eduard's +Edvard +Edvard's +Edy +Edy's +Edythe +Edythe's +Efrem +Efrem's +Egan +Egan's +Egbert +Egon +Egon's +Egor +Egor's +Ekaterina +Ekaterina's +El +Elaina +Elaina's +Elana +Elana's +Elayne +Elayne's +Elden +Elden's +Eldin +Eldin's +Eldredge +Eldredge's +Eldridge +Eldridge's +Eleanora +Eleanora's +Eleanore +Eleanore's +Elene +Elene's +Eleni +Eleni's +Eleonora +Eleonora's +Eleonore +Eleonore's +Elfreda +Elfreda's +Elfrida +Elfrida's +Elia +Elie +Elie's +Elihu +Elihu's +Elisabet +Elisabet's +Elisabetta +Elisabetta's +Elissa +Elissa's +Elke +Elke's +Elle +Elle's +Ellery +Ellery's +Elli +Elli's +Ellsworth +Ellsworth's +Ellwood +Ellwood's +Elly +Elly's +Ellyn +Ellyn's +Elmira +Elmira's +Elmore +Elmore's +Eloisa +Eloisa's +Elsbeth +Elsbeth's +Else's +Elsevier +Elsevier's +Elsey +Elsey's +Elspeth +Elspeth's +Elston +Elston's +Elwin +Elwin's +Elwyn +Elwyn's +Ely +Elyse +Elyse's +Elyssa +Elyssa's +Ema +Ema's +Emanuele +Emanuele's +Emeline +Emeline's +Emilie +Emilie's +Emlen +Emlen's +Emlyn +Emlyn's +Emmaline +Emmaline's +Emmeline +Emmeline's +Emmerich +Emmerich's +Emmet +Emmet's +Emmie +Emmie's +EndNote +EndNote's +Engelbert +Engelbert's +Ennis +Enrica +Enrica's +Ephrem +Ephrem's +Eran +Eran's +Erastus +Erastus's +Erda +Erda's +Erl +Erl's +Erroll +Erroll's +Erskine +Erv +Erv's +Esdras +Esme +Esme's +Essa +Essa's +Esta +Esta's +Estevan +Estevan's +Estrella +Estrella's +Ethelbert +Ethelyn +Ethelyn's +Etienne +Etienne's +Ettie +Ettie's +Ettore +Ettore's +Etty +Etty's +Eudora +Eudora's +Eugen +Eugen's +Eugenius +Eugenius's +Eulalie +Eulalie's +Euphemia +Euphemia's +Eustace +Eustace's +Eustacia +Eustacia's +Ev +Ev's +Evelina +Evelina's +Eveline +Eveline's +Everard +Everard's +Evey +Evey's +Evie +Evie's +Evin +Evin's +Evy +Evy's +Ewan +Ewan's +Ewart +Ewart's +Ewell +Ewell's +Ewen +Ewen's +Expedia +Expedia's +Ezequiel +Ezequiel's +Faber +Faber's +Fabien +Fabien's +Fabio +Fabio's +Fae +Fae's +Fairfax +Fairleigh +Fairleigh's +Fairlie +Fairlie's +Falkner +Fallon +Fallon's +Fania +Fania's +Far's +Fara +Fara's +Farah +Farah's +Farr +Farr's +Farrah +Farrah's +Farrand +Farrand's +Farrel +Farrel's +Farris +Farris's +Faso +Faso's +Faustina +Faustina's +Fayette +Fayette's +Fayre +Fayre's +Feliks +Feliks's +Feng +Feng's +Fennec +Fennec's +Feodor +Feodor's +Ferd +Ferd's +Ferdie +Ferdie's +Ferdy +Ferdy's +Fernanda +Fernanda's +Fernande +Fernande's +Fernandina +Fernandina's +Ferne +Ferne's +Ferrel +Ferrel's +Fey's +Fianna +Fidelia +Fidelia's +Fidelio +Fidelio's +Fifi +Fifi's +Filip +Filip's +Filippo +Filippo's +FilmSpot +FilmSpot's +Filmer +Filmer's +Fina +Fina's +FindArticles +FindArticles's +FindLaw +FindLaw's +Findlay +Findlay's +Findley +Findley's +Finlay +Finlay's +Fitz +Fitz's +Flem +Flemming +Flemming's +Fletch +Fletch's +Fleur +Fleur's +Flickr +Flickr's +Flin +Flin's +Flinn +Flinn's +Flock +Flock's +Flor +Flor's +Flore +Flore's +Florencia +Florencia's +Florette +Florette's +Florian +Florian's +Florinda +Florinda's +Floris +Florrie +Florrie's +Flossy's +Fons +Forex +Forex's +Forrester +Forrester's +Foss +Foss's +Francesco +Francesco's +Franklyn +Franklyn's +Franky +Franky's +Frannie +Frannie's +Frans +Fransisco +Fransisco's +Franzen +Franzen's +Frasier +Frasier's +Frazer +Frederica +Frederica's +Frederich +Frederich's +Frederico +Frederico's +Frederik +Frederik's +Frederique +Frederique's +Fredrika +Fredrika's +Free's +FreeBSD +FreeBSD's +Freeland +Freeland's +Friederike +Friederike's +Friedrich +FrontPage +FrontPage's +Fukushima +Fukushima's +Fulvia +Fulvia's +GHz's +GaAs +Gabby +Gabby's +Gabe +Gabe's +Gabi +Gabi's +Gabriele +Gabriele's +Gabriella +Gabriella's +Gaby +Gaby's +Gae +Gae's +Galina +Galina's +Galvan +Galvan's +Galvin +Galvin's +Gamaliel +Gamaliel's +GameCube +GameCube's +GameFAQs +GameFAQs's +GameSpot +GameSpot's +Gan +Gan's +Gannon +Gannon's +Gard +Gardiner +Gare +Gare's +Garey +Garey's +Garrard +Garrard's +Garvin +Garvin's +Garwood +Garwood's +Gaspar +Gaspard +Gaspard's +Gasparo +Gasparo's +Gasper +Gasper's +Gaston +Gaston's +Gauthier +Gauthier's +Gav +Gav's +Gavan +Gavan's +Gaven +Gaven's +Gaye +Gaye's +Gaylord +Gaylord's +Gaynor +Gaynor's +Gbps +Gecko +Gecko's +GenBank +GenBank's +Genevra +Genevra's +Genia +Genia's +Genna +Genna's +Genny +Genny's +Geno +Geno's +Geoff +Geoff's +Geordie +Georg +Georg's +Georgi +Georgi's +Georgiana +Georgiana's +Georgianna +Georgianna's +Georgie +Georgie's +Georgy +Georgy's +Gerda +Gerda's +Gerhard +Gerhard's +Gerhardt +Gerhardt's +Geri +Geri's +Germain +Germain's +Germaine +Germaine's +Gerome +Gerome's +Gerrard +Gerrard's +Gerri +Gerri's +Gert +Gert's +Gertie +Gertie's +Gertrud +Gertrud's +Gertrudis +Gertrudis's +Gerty +Gerty's +Gery +Gery's +Giacomo +Giacomo's +Gian +Gian's +Gianna +Gianna's +Gianni +Gianni's +Gib +Gib's +Gibb +Gibb's +Giff +Giff's +Giffard +Giffard's +Gifford +Gifford's +Gigi +Gigi's +Gilberte +Gilberte's +Gillan +Gillan's +Gilles +Gillie's +Gilly +Gilly's +Ginevra +Ginevra's +Ginnie +Ginnie's +Giordano +Giordano's +Giorgi +Giorgi's +Giorgio +Giorgio's +Giovanna +Giovanna's +Giraud +Gisela +Gisela's +Gisele +Gisele's +Giulia +Giulia's +Giulietta +Giulietta's +Giulio +Giulio's +Giusto +Giusto's +Glendon +Glendon's +Glennie +Glennie's +Gloriana +Gloriana's +Gloucestershire +Gloucestershire's +Glyn +Glyn's +Glynis +Glynis's +Glynn +Glynn's +GmbH +Godfrey +Godfrey's +Godwin +Goldy +Goldy's +Goran +Goran's +Gordan +Gordan's +Gorden +Gorden's +Gordie +Gordie's +Gordy +Gordy's +Gottfried +Gottfried's +Gracia +Gracia's +Graeme +Graeme's +Gran's +Grange +Granger +Grannie +Grannie's +Grantham +Grantham's +Grantley +Grantley's +Granville +Granville's +Grata +Grata's +Gratia +Gratia's +Grazia +Grazia's +Gregoire +Gregoire's +Gregor +Gregor's +Gregorius +Gregorius's +Grenville +Grete +Grete's +Gretna +Gretna's +Gretta +Gretta's +Grier +Grier's +Griff +Griff's +Griffiths +Griselda +Griswold +Griswold's +Guenevere +Guenevere's +Guglielmo +Guglielmo's +Gui +Gui's +Guido's +Guilbert +Guilbert's +Guildford +Guildford's +Guillaume +Guillaume's +Gunilla +Gunilla's +Gunter +Gussie +Gussie's +Gussy's +Gusta +Gusta's +Gustaf +Gustaf's +Gustave +Gustave's +Gusti +Gusti's +Gusty's +Gwendolen +Gwendolen's +Gwyneth +Gwyneth's +Gwynne +Gwynne's +HTTPS +Had's +Hadleigh +Hadleigh's +Hadley +Hadley's +Hadria +Hadria's +Hagan +Hagan's +Hagen +Hailey +Hailey's +Hakeem +Hakeem's +Hakim +Hakim's +Hali +Hali's +Hally +Hally's +Hamas +Hamas's +Hamel +Hamel's +Hamid +Hamid's +Hamil +Hamil's +Hamish +Hamish's +Hammad +Hammad's +Hana +Hana's +Hanan +Hanan's +Hanni +Hanni's +Happy's +Harald +Harald's +Harbert +Harbert's +Harcourt +Harcourt's +Harland +Harland's +Harlin +Harlin's +Harman +Harman's +Harmonia +Harmonia's +Harmonie +Harmonie's +Haroun +Haroun's +Harri +Harri's +Harriette +Harriette's +Harriot +Harriot's +Harriott +Harriott's +Hartley +Hartwell +Hartwell's +Harv +Harv's +Harwell +Harwell's +Hashim +Hashim's +Haslett +Haslett's +Hassan +Hassan's +Hastie +Hastie's +Hasty's +Hatti +Hatti's +Hatty +Hatty's +Haydon +Haydon's +Hayley +Hayley's +Hayyim +Hayyim's +Hazlett +Hazlett's +Hedda +Hedda's +Hedi +Hedi's +Hedwig +Hedwig's +Hedy +Hedy's +Hejira's +Helaina +Helaina's +Helge +Helge's +Hellenized +Helvetica +Hendrik +Hendrik's +Henriette +Henriette's +Hephzibah +Hephzibah's +Herbie +Herbie's +Herby +Herby's +Herc +Herc's +Hercule +Hercule's +Hermann +Hermann's +Hermia +Hermia's +Hermine +Hermine's +Hermione +Hermione's +Hermon +Hernando +Hernando's +Herold +Herold's +Hersch +Hersch's +Hersh +Hersh's +Herta +Herta's +Hertfordshire +Hertfordshire's +Hertha +Hertha's +Herve +Herve's +Hervey +Hervey's +Hestia +Hestia's +Hetty +Hetty's +Hew's +Hewett +Hewett's +Hi's +Hilde +Hilde's +Hildegarde +Hildegarde's +Hildy +Hildy's +Hillard +Hillard's +Hillery +Hillery's +Hilliard +Hillier +Hillier's +Hillsborough +Hillsborough's +Hilly's +Hillyer +Hillyer's +Hinze +Hinze's +Hirsch +Hirsch's +Hobie +Hobie's +Honoria +Honoria's +Horatia +Horatia's +Horatius +Horatius's +Horst +Horst's +Hort +Hort's +Hortense +Hortensia +Hortensia's +Hotmail +Hotmail's +Houghton +Houghton's +Howey +Howey's +Howie +Howie's +Hoyt +Hoyt's +Hughie +Hugues +Hugues's +Hulda +Hulda's +Humbert +Humbert's +Humfrey +Humfrey's +Husein +Husein's +Hy +Hy's +Hyacinthe +Hyacinthe's +Hyatt +Hyatt's +Hyman +Hyman's +Hymie +IMDb +IMDb's +IMDbPro +IMDbPro's +IPO's +IPOs +Iain +Iain's +Ianthe +Ianthe's +Ibrahim +Ibrahim's +Ichabod +Ichabod's +Iggy +Iggy's +Ignace +Ignace's +Ignaz +Ignaz's +Ignazio +Ignazio's +Ikey +Ikey's +Ileana +Ileana's +Ilka +Ilka's +Illa +Illa's +Ilsa +Ilsa's +Ilse +Ilse's +Immanuel +Imogen +Imogen's +Inga +Inga's +Ingeborg +Ingeborg's +Ingemar +Ingemar's +Inger +Inger's +Inglis +Inglis's +Ingmar +Ingmar's +Inigo +Inigo's +Inna +Inna's +Inness +Inness's +Innis +Innis's +Iona +Irena +Irena's +Irina +Irina's +Irv +Irv's +Isa +Isaak +Isaak's +Isadora +Isadora's +Isadore +Isadore's +Isak +Isak's +Isidor +Isidor's +Isidora +Isidora's +Isidore +Isidore's +Isidoro +Isidoro's +Isobel +Isobel's +Issy +Issy's +Ivar +Ivar's +Ive +Ive's +Iver +Iver's +Ivie +Ivie's +Ivoire +Ivor +Ivor's +Izzy +Izzy's +JPEG's +JPEGs +Jabez +Jabez's +Jacinta +Jacinta's +Jacki +Jacki's +Jacklin +Jacklin's +Jacobo +Jacobo's +Jacqui +Jacqui's +Jacquie +Jacquie's +Jada +Jada's +Jae +Jae's +Jakob +Jakob's +Jameson +Jamey +Jamey's +Jamil +Jamil's +Jamison +Jamison's +Janek +Janek's +Janey +Janey's +Janina +Janos +Janos's +Jany +Jany's +Jarret +Jarret's +Jase +Jase's +Jasmin +Jasmin's +Jaye +Jaye's +Jayme +Jayme's +Jeana +Jeana's +Jeane +Jeane's +Jedediah +Jedediah's +Jedidiah +Jedidiah's +Jehu +Jemima +Jemima's +Jemmy +Jemmy's +Jen +Jen's +Jena +Jena's +Jenn +Jenn's +Jenni +Jenni's +Jeno +Jeno's +Jens +Jere +Jere's +Jeremias +Jeremias's +Jeremie +Jeremie's +Jerrie +Jerrie's +Jervis +Jervis's +Jessamine +Jessamine's +Jessamyn +Jessamyn's +Jessey +Jessey's +Jessi +Jessi's +Jessy +Jessy's +Jethro +Jilly +Jilly's +Joachim +Joana +Joana's +Joane +Joane's +Joanie +Joanie's +Joannes +Joby +Joby's +Jocelin +Jocelin's +Jocelyne +Jocelyne's +Jocko +Jocko's +Joelle +Joelle's +Johan +Johan's +Jojo +Jojo's +Joli +Joli's +Jolie +Jolie's +Joly +Joly's +Jone +Jone's +Jordana +Jordana's +Jordon +Jordon's +Jori +Jori's +Jory +Jory's +Joscelin +Joscelin's +Josepha +Josepha's +Josey +Josey's +Josias +Josias's +Josselyn +Josselyn's +Jourdain +Jourdain's +Jourdan +Jourdan's +Joya +Joya's +Joye +Joye's +Jozef +Jozef's +Jud +Judi +Judi's +Jule +Jule's +Juli +Juli's +Juliane +Juliane's +Julianna +Julianna's +Julienne's +Junia +Junia's +Junie +Junie's +Justina +Justina's +Justus +Justus's +Jyoti +Jyoti's +Kahlil +Kahlil's +Kai +Kai's +Kaia +Kaia's +Kaila +Kaila's +Kain +Kain's +Kaine +Kaine's +Kaitlyn +Kaitlyn's +Kaja +Kaja's +Kala +Kala's +Kalil +Kalil's +Kalina +Kalina's +Kalle +Kalle's +Kandy +Kania +Kania's +Kanya +Kanya's +Kare +Kare's +Karel +Karel's +Karim +Karim's +Karine +Karine's +Karlen +Karlen's +Karly +Karly's +Karna +Karna's +Karnataka +Karnataka's +Karolina +Karolina's +Karoline +Karoline's +Karoly +Karoly's +Karon +Karon's +Kaspar +Kaspar's +Kasper +Kasper's +Kass +Kassandra +Kassandra's +Kat +Kat's +Kata +Kata's +Katalin +Katalin's +Katerina +Katerina's +Kath +Kath's +Katha +Katha's +Katharina +Katharina's +Kathe +Kathe's +Katherina +Katherina's +Kathi +Kathi's +Kati +Kati's +Katinka +Katinka's +Katrine +Katrinka +Katrinka's +Katya +Katya's +Kaycee +Kaycee's +Kaylee +Kaylee's +Kayne +Kayne's +Kean +Keane +Keane's +Kearney +Kearney's +Keefe +Keefe's +Keefer +Keefer's +Keeley +Keeley's +Keely +Keely's +Keene +Keene's +Keir +Keir's +Kellen +Kellen's +Kendal +Kendal's +Kendell +Kendell's +Kendricks +Kenn +Kenn's +Kenna +Kenna's +Kennett +Kennett's +Ker +Ker's +Kerala +Kerala's +Kerby +Kerby's +Kerk +Kerk's +Kerrie +Kerrie's +Kerstin +Kerstin's +Kerwin +Kerwin's +Kev +Kev's +Kevan +Kevan's +Khalil +Khalil's +Ki +Ki's +Kile +Kile's +Kiley +Kiley's +Kilian +Kilian's +Killian +Killian's +Kimball +Kimball's +Kimbell +Kimbell's +Kimble +Kimble's +Kimmy +Kimmy's +Kincaid +Kincaid's +Kingsley +Kinko +Kinsley +Kinsley's +Kipp +Kipp's +Kira +Kira's +Kiri +Kiri's +Kitts +Kitts's +Klara +Klara's +Klemens +Klemens's +Klement +Klement's +Konstantin +Konstantin's +Koo +Koo's +Kora +Kora's +Kore +Kore's +Koren +Koren's +Kori +Kori's +Kort +Kort's +Kosovo +Kosovo's +Kristian +Kristian's +Krystyna +Krystyna's +Kuala +Kuala's +Kyla +Kyla's +Kylie +Kylie's +Kym +Kym's +Laetitia +Laetitia's +Lainey +Lainey's +Lakers +Lakers's +Lalo +Lalo's +Lamond +Lamond's +Laney +Laney's +Langston +Langston's +Lani +Lani's +Lanie +Lanie's +Lanna +Lanna's +Lari +Lari's +Larisa +Larisa's +Larissa +Larissa's +Laughton +Launce +Launce's +Laure +Laure's +Laurens +Lauretta +Lauretta's +Laurette +Laurette's +Lauryn +Lauryn's +Lavina +Lavina's +Lavinia +Lavinia's +Lawry +Lawry's +Lawton +Lawton's +Layne +Layne's +Layton +Layton's +Lazar +Lazar's +Lazare +Lazare's +Leandra +Leandra's +Leela +Leela's +Leena +Leena's +Leese +Leese's +Leia +Leia's +Leica +Leica's +Leighton +Leighton's +Lek +Lek's +Lem +Lem's +Lennard +Lennard's +Lennie +Lennie's +Leone +Leone's +Leonhard +Leonhard's +Leonie +Leonie's +Leonora +Leonora's +Leonore +Leonore's +Leontine +Leontine's +Leora +Leora's +Leroi +Leroi's +Letizia +Letizia's +Lettie +Lettie's +Letty +Letty's +Lev +Levey +Levey's +Levin +Levin's +Levon +Levon's +Lewes +Lexi +Lexi's +Lexie +Lexie's +LexisNexis +LexisNexis's +Lexy +Lexy's +Leyla +Leyla's +Lia +Lia's +Liam +Liam's +Lian +Lian's +Liana +Liana's +Liane +Liane's +Lianne +Lianne's +Libbey +Libbey's +Libbie +Libbie's +Lida +Lida's +Lief's +Lightning +Lightning's +Lil +Lil's +Lilah +Lilah's +Liliane +Liliane's +Lilias +Lilla +Lilla's +Lilli +Lilli's +Linc +Linc's +Lincolnshire +Lincolnshire's +Lindi +Lindi's +Lindon +Lindon's +Linea +Linea's +LinkedIn +LinkedIn's +Linn +Linn's +Linnea +Linnea's +Linnell +Linnell's +Lisbeth +Lisbeth's +Lise +Lise's +Lisette +Lisette's +Lisle +Lisle's +Lissa +Lissa's +Lissy +Lissy's +Lita +Lita's +Liv +Liv's +LiveJournal +LiveJournal's +Livvy +Livvy's +Lizabeth +Lizabeth's +Lizbeth +Lizbeth's +Lizette +Lizette's +Lodovico +Lodovico's +Logitech +Logitech's +Lolly's +Lona +Lona's +Loni +Loni's +Lonny +Lonny's +LookSmart +LookSmart's +Lorain +Lorain's +Lorant +Lorant's +Lorenza +Lorenza's +Lorette +Lorette's +Loria +Loria's +Lorin +Lorin's +Lorinda +Lorinda's +Lorne +Lorne's +Lory +Lory's +Lotta +Lotta's +Lotte +Lotte's +Lotti +Lotti's +Lotty +Lotty's +Lovell +Loy +Loy's +Luca +Luca's +Luci +Luci's +Luciana +Luciana's +Lucie +Lucie's +Lucienne +Lucienne's +Lucina +Lucky's +Ludovico +Ludovico's +Ludvig +Ludvig's +Luise +Luise's +Lukas +Lukas's +Lura +Lura's +Ly +Ly's +Lycos +Lycos's +Lyda +Lyda's +Lydie +Lydie's +Lydon +Lydon's +Lyn +Lyn's +Lynde +Lynde's +Lyndsay +Lyndsay's +Lyndsey +Lyndsey's +Lyssa +Lyssa's +MHz's +MPEG's +MPEGs +Mab +Macau +Macau's +Macromedia +Macromedia's +Mada +Mada's +Madalyn +Madalyn's +Maddalena +Maddalena's +Maddi +Maddi's +Maddie +Maddie's +Maddy +Maddy's +Madelaine +Madelaine's +Madelon +Madelon's +Magda +Magda's +Magdalen +Maggi +Maggi's +Maggy +Maggy's +Mahala +Mahala's +Mahalia +Mahalia's +Mahmoud +Mahmoud's +Mahmud +Mahmud's +Maia +Maia's +Mair +Mair's +Maire +Maire's +Maison +Maison's +Mal +Mala +Mala's +Malia +Malia's +Malina +Malina's +Malissa +Malissa's +Malva +Malva's +Malvin +Malvin's +Malvina +Malvina's +Mame +Mame's +Manda +Manda's +Mandel +Mandel's +Mandi +Mandi's +Mandie +Mandie's +Mannie +Mannie's +Manny +Manny's +Mano +Mano's +Manolo +Manolo's +Manon +Manon's +Manya +Manya's +MapQuest +MapQuest's +Marcela +Marcela's +Marcelle +Marcelle's +Marcello +Marcello's +Marcellus +Maren +Maren's +Marga +Marga's +Margalit +Margalit's +Margareta +Margareta's +Margarete +Margarete's +Margaretha +Margaretha's +Margarethe +Margarethe's +Margaretta +Margaretta's +Margaux +Marget +Marget's +Margit +Margit's +Margot's +Margy +Margy's +Mariam +Mariam's +Marianna +Marianna's +Maribeth +Maribeth's +Mariel +Mariel's +Marielle +Marielle's +Mariette +Mariette's +Marika +Marika's +Marilee +Marilee's +Mariska +Mariska's +Marita +Marita's +Marj +Marj's +Marja +Marja's +Markos +Markus +Markus's +Marlee +Marlee's +Marleen +Marleen's +Marlena +Marlena's +Marline +Marline's +Marlo +Marlo's +Marlow +Marlow's +Marmaduke +Marmaduke's +Marney +Marney's +Marni +Marni's +Marnie +Marnie's +Marris +Marris's +Marthe +Marthe's +Marti +Marti's +Martie +Martie's +Martino +Martino's +Martyn +Martyn's +Marv +Marv's +Marya +Marya's +Marybeth +Marybeth's +Marylin +Marylin's +Marys +Masha +Masha's +Massimiliano +Massimiliano's +Massimo +Massimo's +Mata +Mata's +Mateo +Mateo's +MathML +MathML's +Mathe +Mathe's +Mathilda +Mathilda's +Mathilde +Mathilde's +Matias +Matias's +Matilde +Matilde's +Matteo +Matteo's +Matthieu +Matthieu's +Matti +Matti's +Mattias +Mattias's +Matty +Matty's +Maudie +Maudie's +Maurie +Maurie's +Maurits +Maurits's +Maurizio +Maurizio's +Maury +Maxie +Maxie's +Maximilien +Maximilien's +Maximo +Maximo's +Maybelle +Maybelle's +Maye +Maye's +Mayne +Mayne's +Mbps +McAfee +McAfee's +McCann +McCann's +Meaghan +Meaghan's +Meara +Meara's +Medline +Medline's +Meggie +Meggie's +Mei +Mei's +Mela +Mela's +Melania +Melania's +Melicent +Melicent's +Melina +Melina's +Melita +Melita's +Mella +Mella's +Melli +Melli's +Mellie +Mellie's +Melly +Melly's +Melodie +Melodie's +Melony +Melony's +Melvyn +Melvyn's +Menard +Menard's +Merci +Merci's +Meriel +Meriel's +Merl +Merl's +Merrie +Merrie's +Merrily's +Merry's +Mersey +Merv +Merv's +Merwin +Merwin's +Merwyn +Merwyn's +Meryl +Meryl's +Metacafe +Metacafe's +Micaela +Micaela's +Michaela +Michaela's +Michail +Michail's +Michal +Michal's +Micheline +Micheline's +Michell +Michell's +Micki +Micki's +Mignon +Mignon's +Mikael +Mikael's +Mikel +Mikel's +Mikey +Mikey's +Mikkel +Mikkel's +Milena +Milena's +Milli +Milli's +Milly +Milly's +Mina +Mina's +Minda +Minda's +Minette +Minette's +Minna +Minne +Minne's +Minny +Minny's +Minta +Minta's +Mirabel +Mirabel's +Mirabella +Mirabella's +Mirabelle +Mirabelle's +Miran +Miran's +Mireille +Mireille's +Mirella +Mirella's +Mirna +Mirna's +Mischa +Mischa's +Misha +Misha's +Missie +Missie's +Mohandas +Mohandas's +Moise +Moise's +Moishe +Moishe's +Monika +Monika's +Monro +Monro's +Monti +Monti's +Mora +Mora's +Mord +Mord's +Mordecai +Morena +Morena's +Morey +Morey's +Morgana +Morgana's +Morgen +Morgen's +Moria +Moria's +Moritz +Moritz's +Morna +Morna's +Morrie +Morrie's +Morten +Morten's +Morty +Morty's +Mose +Mose's +Moshe +Moshe's +Moyra +Moyra's +Mozillian +Mozillian's +Mozillians +Munroe +Munroe's +Murdock +Murdock's +Murry +Murry's +My's +MySQL +MySQL's +MySpell +MySpell's +Myer +Myer's +Myriam +Myriam's +NGO +NGO's +NGOs +NSPR +NSPR's +NSS +NSS's +Nada +Nada's +Nadu +Nadu's +Nadya +Nadya's +Nana +Nana's +Nance +Nance's +Nanci +Nanci's +Nani +Nani's +Nanni +Nanni's +Nanon +Nanon's +Napa +Napa's +Nara +Nari +Nari's +Naruto +Naruto's +Nata +Nata's +Natal's +Natale +Natale's +Natalya +Natalya's +Nathalie +Nathalie's +Nathanael +Nathanial +Nathanial's +Natividad +Natividad's +Natty's +Neale +Neale's +Nealy +Nealy's +Necko +Necko's +Neda +Neda's +Nedda +Nedda's +Neddy +Neddy's +Neel +Neel's +Neely +Neely's +Neill +Neill's +Neils +Nelle +Nelle's +Nelli +Nelli's +Nels +Nerissa +Nerissa's +Nessa +Nessa's +Nessie +Nessie's +Nesta +Nesta's +Nester +Nester's +NetBSD +NetBSD's +Netta +Netta's +Nevil +Nevil's +Nevile +Nevile's +Neville +Neville's +Nevin +Nevin's +Nevins +NexTag +NexTag's +Nextel +Nextel's +Nial +Nial's +Niall +Niall's +Nichol +Nichol's +Nicki +Nicki's +Nickie +Nickie's +Nicko +Nicko's +Nicky +Nicky's +Nico +Nico's +Nicol +Nicol's +Nicolai +Nicolette +Nicolette's +Nicolis +Nicolle +Nicolle's +Niel +Niel's +Niels +Niki +Niki's +Niko +Niko's +Nikola +Nikola's +Nikolaos +Nikolaos's +Nikolas +Nikolaus +Nikolaus's +Nikos +Niles +Nils +Nilson +Nilson's +Ninette +Ninette's +Ninon +Ninon's +Niue +Niue's +Niven +Niven's +Noam +Noam's +Noland +Noland's +Noll +Noll's +Nomi +Nomi's +Noni +Noni's +Nonie +Nonie's +Nonna +Nonna's +Norah +Norah's +Norrie +Norrie's +Nortel +Nortel's +Notre +Nowell +Nowell's +Nye +Nye's +Nyssa +Nyssa's +Obed +Obed's +Obie +Octavius +Octavius's +Odette +Odette's +Odie +Odie's +Odo +Odo's +Ody +Ody's +Olimpia +Olimpia's +Olly +Olly's +Olwen +Olwen's +Olympe +Olympe's +Oona +Oona's +Opaline +Opaline's +OpenBSD +OpenBSD's +Orazio +Orazio's +Orel +Oren +Oren's +Oriana +Oriana's +Orlan +Orlan's +Orland +Orland's +Orren +Orren's +Orrin +Orrin's +Orson +Orson's +Orton +Orton's +Orv +Orv's +Oryza +Oryza's +Osbourne +Osbourne's +Osmond +Osmond's +Osmund +Osmund's +Ossie +Ossie's +Otho +Otho's +Ottilie +Ottilie's +Oxley +Oxley's +Ozzy +Ozzy's +PDA +PDA's +PDAs +PDF's +PDFs +PRNewswire +PRNewswire's +Paco +Paco's +Padgett +Padgett's +Padraic +Padraic's +Padraig +Padraig's +Palin +Palin's +Paloma +Paloma's +Pancho +Pancho's +Paola +Paola's +Paolina +Paolina's +Paolo +Paolo's +Papageno +Papageno's +Papua +Papua's +Parke +Parke's +Pascale +Pascale's +Paten +Paten's +Paton +Patric +Patric's +Patricio +Patricio's +Patrizia +Patrizia's +Patten +Patten's +Pattie +Pattie's +Paule +Paule's +Paulie +Paulie's +Paulina +Paulina's +Paulo +Paulo's +Pauly +Pauly's +Pavel +Pavel's +Pavia +Pavia's +Paxton +Payton +Payton's +Peadar +Peadar's +Pearce +Pearce's +Pearle +Pearle's +Peder +Peder's +Pegeen +Pegeen's +Peirce +Peirce's +Penrod +Penrod's +Pepe +Pepe's +Pepi +Pepi's +Pepita +Pepita's +Perceval +Peri +Peri's +Perkin +Perkin's +Perla +Perla's +Perle +Perle's +Perri +Perri's +Perrine +Perrine's +Persis +Peta +Peta's +Peterborough +Peterborough's +Petey +Petey's +Petr +Petr's +Petronella +Petronella's +Petronilla +Petronilla's +Peyton +Peyton's +Phebe +Philippa +Philippa's +Phillida +Phillida's +Phillipe +Phillipe's +Phillis +Phillis's +Philomena +Philomena's +Phineas +Phineas's +Photoshop +Photoshop's +Phyllida +Phyllida's +Pia +Pia's +Pictor +Pierrette +Pierrette's +Pierson +Pierson's +Pieter +Pieter's +Pietra +Pietra's +Pietro +Pietro's +Pinchas +Pinchas's +Piotr +Piotr's +Pippa +Pippa's +PostScript +PostScript's +PostgreSQL +PostgreSQL's +Poul +Poul's +Poynter +Poynter's +Prentiss +Prentiss's +Prinz +Pris +Prisca +Prisca's +Prism +Prism's +Prix +ProQuest +ProQuest's +Pru +Pru's +Prudy +Prudy's +Prue +Prue's +Pryce +Pryce's +Pseudomonas +Pseudomonas's +PubMed +PubMed's +Qaeda +Qaeda's +Queenie +Queenie's +Quent +Quent's +QuickList +QuickList's +QuickTime +QuickTime's +Quillan +Quillan's +Quincey +Quincey's +Quinlan +Quinlan's +Quint +Quint's +Quinta +Quinta's +Quintana +Quintana's +Quintin +Quintin's +Quintus +Quintus's +Qwest +Qwest's +Rab +Rab's +Rabi +Raf +Raf's +Rafa +Rafa's +Rafe +Rafe's +Raff +Raff's +Raffaello +Raffaello's +Rafferty +Rafferty's +Rafi +Rafi's +Ragnar +Ragnar's +Rahel +Rahel's +Raimondo +Raimondo's +Raimund +Raimund's +Raimundo +Raimundo's +Raina +Raina's +Raine +Raine's +Rainer +Rainer's +Ralf +Ralf's +Rana +Rana's +Rance +Rance's +Randa +Randa's +Rani +Rani's +Ravi +Ravi's +Ravid +Ravid's +Raviv +Raviv's +Rawley +Rawley's +Raye +Raye's +Raymund +Raymund's +Rayna +Rayna's +Rayner +Rayner's +Raynor +Raynor's +Rea +Rea's +Reade +Rebeca +Rebeca's +Rebecca's +Rebecka +Rebecka's +Redd +Redd's +Ree +Ree's +Reece +Reece's +Reena +Reena's +Rees +Regan +Regan's +Regen +Regen's +Regine +Regine's +Reiko +Reiko's +Reina +Reina's +Reine +Reine's +Reinhard +Reinhard's +Remanence +Remanent +Remy +Remy's +Renae +Renae's +Renaldo +Renaldo's +Renard +Renard's +Renata +Renata's +Renate +Renate's +Renato +Renato's +Renaud +Renaud's +Renie +Renie's +Rennie +Rennie's +Reta +Reta's +Reuven +Reuven's +Rey +Rey's +Reynard +Reynard's +Reynold +Reynold's +Rhett +Rhett's +Rhianna +Rhianna's +Rhino +Rhino's +Rhona +Rhona's +Rhys +Rhys's +Ric +Ric's +Rica +Rica's +Ricard +Ricard's +Riccardo +Riccardo's +Richart +Richart's +Rickard +Rickard's +Rickert +Rickert's +Ricki +Ricki's +Rik +Rik's +Riki +Riki's +Rikki +Rikki's +Rina +Rina's +Rinaldo +Rinaldo's +Riordan +Riordan's +Risa +Risa's +Ritchie +Ritchie's +Riva +Riva's +Roarke +Roarke's +Robb +Robb's +Robina +Robina's +Robinet +Robinet's +Robinette +Robinette's +Robinia +Robinia's +Roby +Roby's +Roch +Roch's +Roda +Roda's +Rodd +Rodd's +Roddy +Roddy's +Roderic +Roderic's +Roderigo +Roderigo's +Rodham +Rodham's +Rodi +Rodi's +Rodolph +Rodolph's +Rodolphe +Rodolphe's +Rog +Rog's +Roi +Roi's +Rois +Roldan +Roldan's +Rolf +Rolfe +Rolfe's +Rollie +Rollie's +Rollin +Rollin's +Rollo +Rolph +Rolph's +Roma +Roma's +Romain +Romain's +Romola +Romola's +Romy +Romy's +Rona +Rona's +Ronni +Ronni's +Rorke +Rorke's +Ros +Rosaleen +Rosaleen's +Rosalia +Rosalia's +Rosaline +Rosaline's +Rosamond +Rosamond's +Rosamund +Rosamund's +Rosco +Rosco's +Roseanne +Roseanne's +Roselle +Roselle's +Rosina +Rosina's +Rosita +Rosita's +Rossie +Rossie's +Rosy's +Routledge +Routledge's +Rowan +Rowan's +Rowen +Rowen's +Roxana +Roxana's +Roxane +Roxane's +Roxanna +Roxanna's +Royall +Royall's +Roz +Roz's +Rubi +Rubi's +Rubia +Rubia's +Rudd +Rudd's +Ruddy's +Rudiger +Rudiger's +Rudolfo +Rudolfo's +Rufe +Rufe's +Ruggiero +Ruggiero's +Ruprecht +Ruprecht's +Rurik +Rustin +Rustin's +Rutger +Rutger's +Rutter +Rutter's +Ruy +Ruy's +SNP +SNP's +SNPs +Saba +Saba's +Saccharomyces +Saccharomyces's +Sacha +Sacha's +Sada +Sada's +Saleem +Saleem's +Salim +Salim's +Sallee +Sallee's +Salomon +Salomon's +Samaria +Sande +Sande's +Sanderson +Sanderson's +Sandi +Sandi's +Sandie +Sandie's +Sandor +Sandor's +Sandro +Sandro's +Sanson +Sanson's +Sansone +Sansone's +Sapphira +Sarbanes +Sarbanes's +Saree +Saree's +Sarge +Sarge's +Sarina +Sarina's +Sarita +Sarita's +Sascha +Sascha's +Saunderson +Saunderson's +Sauveur +Sauveur's +Savina +Savina's +Saxe +Saxe's +Sayer +Sayer's +Sayre +Sayre's +Scarface +Scarface's +Scarlett +Scarlett's +Schwarz +Schwarz's +Scotti +Scotti's +SeaMonkey +SeaMonkey's +Seamus +Seamus's +Sebastiano +Sebastiano's +Sebastien +Sebastien's +Sela +Sela's +Selby +Selby's +Selene +Selene's +Selig +Selig's +Selina +Selina's +Sella +Sella's +Selle +Selle's +Sena +Sena's +Sergent +Sergent's +Shalom's +Shamus +Shamus's +Shandy +Shandy's +Shani +Shani's +Shanta +Shanta's +Shara +Shara's +SharePoint +SharePoint's +Sharma +Sharma's +Shayla +Shayla's +Shayna +Shayna's +Shayne +Shayne's +Sheela +Sheela's +Sheilah +Sheilah's +Shel +Shel's +Shelagh +Shelagh's +Shem +Shem's +Shen +Shen's +Shenzhen +Shenzhen's +Shep +Shep's +Sher +Sher's +Sherm +Sherm's +Sherwin +Sherwin's +Shina +Shina's +Shir +Shir's +Shirl +Shirl's +Sholom +Sholom's +Shoshana +Shoshana's +Sib +Sib's +Sibley +Sibley's +Sibylla +Sibylla's +Sibylle +Sibylle's +Sidonia +Sidonia's +Sig +Sigismondo +Sigismondo's +Sigrid +Sigrid's +Silvan +Silvan's +Silvana +Silvana's +Silvano +Silvano's +Silvanus +Silvanus's +Silvester +Silvester's +Silvie +Silvie's +Silvio +Silvio's +Sim's +Simeon +Simeon's +Simmonds +Simmonds's +Simona +Simona's +Siobhan +Siobhan's +Sion +Sissie +Sissie's +Siward +Siward's +Skelly +Skelly's +Skipton +Skipton's +Skylar +Skylar's +Skyler +Skyler's +Slade +Slade's +Sly's +Smitty +Smitty's +Snowl +Snowl's +Sofie +Sofie's +Solaris +Solaris's +Solly +Solly's +Somerset +Songbird +Songbird's +Sophi +Sophi's +Sophronia +Sophronia's +Sorcha +Sorcha's +Sparc +SpiderMonkey +SpiderMonkey's +Stace +Stace's +Standford +Standford's +Stanfield +Stanfield's +Stanislas +Stanislas's +Stanislaus +Stanislaus's +Stanislaw +Stanislaw's +Stanly +Stanly's +Stanwood +Stanwood's +Stavros +Stearn +Stearn's +Stefania +Stefania's +Stefano +Stefano's +Steffen +Steffen's +Steffi +Steffi's +Stephani +Stephani's +Stephanus +Stephanus's +Stillman +Stillman's +Stinky's +Stoddard +Stoddard's +Stormy's +StumbleUpon +StumbleUpon's +Sukey +Sukey's +Suki +Suki's +Sula +Sula's +Sunbird +Sunbird's +Sunderland +Sunderland's +Sunny's +Susann +Susann's +Susannah +Susannah's +Susi +Susi's +Susy +Susy's +Suzanna +Suzanna's +Suzi +Suzi's +Suzie +Suzie's +Svend +Svend's +Swindon +Swindon's +Sybilla +Sybilla's +Sybille +Sybille's +Syd +Syd's +Sylvan's +Symantec +Symantec's +Symbian +Symbian's +Symon +Symon's +TEirtza +TEirtza's +THz +THz's +Tabb +Tabb's +Taber +Taber's +Tabor +Taddeo +Taddeo's +Tait +Tait's +Talbert +Talbert's +Talia +Talia's +Tallulah +Tallulah's +Talya +Talya's +Tamar +Tamar's +Tamarin +Tamarin's +Tamas +Tana +Tandy +Tandy's +Tani +Tani's +Tann +Tann's +Taryn +Taryn's +Tatiana +Tatiana's +TechRepublic +TechRepublic's +Technorati +Technorati's +Teddie +Teddie's +Tedi +Tedi's +Teena +Teena's +Templeton +Templeton's +Teodor +Teodor's +Teodora +Teodora's +Teodoro +Teodoro's +Tera +Tera's +Terese +Terese's +Teresita +Teresita's +Terrill +Terrill's +Terza +Terza's +Tesco +Tesco's +Thacher +Thacher's +Thatcherism +Thaxter +Thaxter's +Theda +Theda's +Thekla +Thekla's +Theo +Theo's +Theobald +Theobald's +Theodor +Theodor's +Theodosia +Theodosia's +Thia +Thia's +Thibaut +Thibaut's +Thom +Thom's +Thoma +Thoma's +Thomasin +Thomasin's +Thomasina +Thomasina's +Thorin +Thorin's +Thorndike +Thorny's +Thorstein +Thorstein's +Thorsten +Thorsten's +Thorvald +Thorvald's +Thurstan +Thurstan's +Thurston +Thurston's +Tiebout +Tiebout's +Tierney +Tierney's +Tilda +Tilda's +Tildi +Tildi's +Tildy +Tildy's +Tillie +Tillie's +Tilly +Tilly's +Timi +Timi's +Timotheus +Timotheus's +Tinderbox +Tinderbox's +Tish +Tish's +Tobe +Tobe's +Tobey +Tobi +Tobi's +Tobias +Tobias's +Tobie +Tobie's +Tobin +Tobin's +Toma +Toma's +Tomaso +Tomaso's +Tomi +Tomi's +Tootsie +Tootsie's +Tore's +Torey +Torey's +Tori +Tori's +Torin +Torin's +Torr +Torr's +Torre +Torre's +Torrence +Torrence's +Torrey +Torrey's +Torrie +Torrie's +Torry +Torry's +Tova +Tova's +Tove +Tove's +Traver +Traver's +Travers +Tremain +Tremain's +Tremaine +Tremaine's +Tremayne +Tremayne's +Treo +Treo's +Trev +Trev's +TripAdvisor +TripAdvisor's +Tripp +Tripp's +Tris +Trish +Trish's +Trista +Trista's +Trix +Trix's +Trixie +Trixie's +Trude +Trude's +Trudi +Trudi's +Trueman +Trueman's +Tully +Tully's +Twyla +Twyla's +Tybalt +Tybalt's +Tye +Tye's +Tynan +Tynan's +Tyne +Tyne's +Tyrus +Tyrus's +UI +UI's +UIs +Ubiquity +Ubiquity's +Udell +Udell's +Ugo +Ugo's +Ula +Ula's +Ulick +Ulick's +Ulises +Ulises's +Ulla +Ulla's +Ulric +Ulric's +Ulrica +Ulrica's +Ulrich +Ulrich's +Ulrike +Ulrike's +Umberto +Umberto's +Una +Una's +Urbain +Urbain's +Urbano +Urbano's +Uri +Uri's +Uta +Uta's +Vachel +Vachel's +Vaclav +Vaclav's +Vail +Vail's +Valdemar +Valdemar's +Valentia +Valentia's +Valentina +Valentina's +Valera +Valle +Valle's +Valli +Valli's +Vanda +Vanda's +Vania +Vania's +Vanna +Vanna's +Vanni +Vanni's +Vanya +Vanya's +Vasili +Vasili's +Vasily +Vasily's +Vassili +Vassili's +Vassily +Vassily's +Venkman +Venkman's +Vere +Vere's +Verena +Verena's +Verney +Verney's +Vernor +Vernor's +Veronika +Veronika's +Veronique +Vi +Vi's +Vick +Vick's +Vicodin +Vicodin's +Vida +Vida's +Vikki +Vikki's +Vin +Vin's +Vina +Vina's +Vinnie +Vinnie's +Vinny +Vinny's +Violante +Violante's +Violetta +Violetta's +Violette +Violette's +Virgilio +Virgilio's +Virginie +Virginie's +Vite +Vite's +Vitoria +Vittoria +Vittoria's +Vittorio +Vittorio's +Viv +Viv's +Vivi +Vivi's +Viviana +Viviana's +Vivie +Vivie's +Vivien +Vivien's +Vodafone +Vodafone's +Von +Von's +WASPs +Wadsworth +Wadsworth's +Wainwright +Wainwright's +Wakefield +Wallas +Wallas's +Wallie +Wallie's +Wally +Wally's +Walther +Walther's +Warcraft +Warcraft's +Warde +Warde's +Warwickshire +Warwickshire's +Wat +Wat's +Waverley +Waverley's +Waverly +Waverly's +Wayland +Wayland's +Waylon +Waylon's +Weave +Weave's +WebSphere +WebSphere's +Weider +Weider's +Welby +Welby's +Wendel +Wendel's +Werner +Werner's +Wernher +Wernher's +Wes +Westbrook +Westbrook's +Westley +Westley's +Whitby +Whitby's +Whittaker +Whittaker's +WiFi's +WikiPatents +WikiPatents's +Wikibooks +Wikibooks's +Wikimedia +Wikimedia's +Wikinews +Wikinews's +Wikiquote +Wikiquote's +Wikisource +Wikisource's +Wiktionary +Wiktionary's +Wilden +Wilden's +Wilfrid +Wilfrid's +Wilhelmine +Willem +Willem's +Willey +Willey's +Willi +Willi's +Wilmette +Wilmette's +Wiltshire +Wiltshire's +Windham +Windham's +Windy's +Winfield +Winfield's +Winn +Winn's +Winna +Winna's +Winne +Winne's +Winnifred +Winnifred's +Winny +Winny's +Winona +Winona's +Winslow +Winslow's +Witty's +Woodie +Woodie's +WordPress +WordPress's +Worden +Worden's +WorldCat +WorldCat's +Worthington +Worthington's +Wye +Wyn +Wyn's +Wyndham +Wyndham's +Wynne +Wynne's +XBL +XBL's +XPCOM +XPCOM's +XPConnect +XPConnect's +XPInstall +XPInstall's +XUL +XUL's +XULRunner +XULRunner's +Xanax +Xanax's +Xbox +Xbox's +Xena +Xena's +Ximenez +Ximenez's +Yancey +Yancey's +Yancy +Yancy's +Yardley +Yardley's +Yasmin +Yasmin's +Yehudi +Yehudi's +Yelena +Yelena's +Yetta +Yetta's +Ynez +Ynez's +Yolande +Yolande's +Yorke +Yorke's +Yorker +Yorker's +Yoshi +Yoshi's +Yoshiko +Yoshiko's +Ysabel +Ysabel's +Yul +Yul's +Yvon +Yvon's +Yvor +Yvor's +ZDNet +ZDNet's +Zaccaria +Zaccaria's +Zach +Zacharias +Zack +Zack's +Zahara +Zahara's +Zak +Zak's +Zarah +Zarah's +Zaria +Zaria's +Zea +Zea's +Zeb +Zeb's +Zebulon +Zebulon's +Zelda +Zelda's +Zena +Zena's +Zenia +Zenia's +Zhang +Zhang's +Zhao +Zhao's +Zhou +Zhou's +Zia +Zia's +Ziff +Ziff's +Zita +Zita's +Zora +Zora's +Zune +Zune's +abridgement +abridgement's +abridgements +absorbances +absorbancy +absorbancy's +actin +admin's +adoptee +adoptee's +adoptees +advocator +advocator's +advocators +adware's +adwares +aggregator +aggregator's +aggregators +alkoxy +anonymization +anonymization's +anonymizations +anonymize +anonymized +anonymizes +anonymizing +anthropomorphized +anthropomorphizes +antisense +antivirus's +apatosaurus +apatosaurus's +arXiv +arXiv's +archaeoastronomy +archaeoastronomy's +archaeologic +archaeomagnetic +archaeomagnetism +aryl +aryl's +aryls +astroarchaeologies +astroarchaeology +astroarchaeology's +astrobiology +astrobiology's +astrobleme +astroblemes +asynchronicity +aurei +auteur's +auteurs +autocomplete +autocompletes +avant-garde +axe +axe's +badging +biodiesel +biodiesel's +bioinformatic +bioinformatic's +bioinformatics +biosyntheses +biotech's +blogroll +blogroll's +blogrolls +bloviate +bloviated +bloviates +bloviating +bloviation +bloviator +bloviator's +bloviators +bookselling +broadcasted +cDNA +canceller +canceller's +canonicalization +canonicalization's +canonicalizations +canonicalize +canonicalized +canonicalizes +canonicalizing +capita +carboxylic +carnitas +cerevisiae +cerevisiae's +cerevisiaes +charcuterie +chemistries +chickenshit's +ciphertext +ciphertexts +closable +codec +codec's +codecs +codon's +coli +colonoscope +colonoscope's +colonoscopes +commenters +compositeness +concurrents +conferable +config +config's +configs +conformant +conmanly +corrigibility +corrigibility's +corrigible +corruptibly +court-martial +court-martialed +court-martialing +court-martials +crappiness +crimeware +crimeware's +cryonic +cryptologist +cryptologist's +cryptologists +cryptosystem +cryptosystems +cul-de-sac +cyber +cytokine +cytokine's +datasheet +datasheet's +datasheets +decertification +decertifications +decertified +decertifies +decertify +decertifying +deconstructionist's +degenerations +dehydrogenase's +deliverables +dequeue +dequeued +dequeues +dequeuing +designee +designings +dialoged +dialoging +dialogs +dialogued +dialoguer +dialoguing +diatomaceous +dihydro +disarrangements +disassembler +disassembler's +disassemblers +disassembly's +disclaimable +disclosable +discountenance's +disintermediation +disintermediations +dissentious +djinn +donator +donator's +donators +durian +durian's +durians +eBook +eBook's +eBooks +eCommerce +eCommerce's +elicitor +elicitor's +elicitors +encyclopaedia +enqueue +enqueued +enqueues +enqueuing +eschatologist +eschatologist's +eschatologists +exacta +exactable +exactas +exactingness +exactions +exactor +exactor's +exactors +experimentalism +filesystem +filesystem's +filesystems +filmography +financials +fluidize +fluidizes +fluidizing +flyer +flyer's +flyers +foci +forma +fracker +frackers +freegan +freegans +fuckhead's +gamification +gamified +gamifies +gamify +gamifying +gastroenterologist +gastroenterologist's +gastroenterology +gigajoule +gigajoule's +gigajoules +grande +grey +grey's +greybeard's +greybeards +greyed +greyer +greyest +greying +greyness's +greys +hentai +hexane's +hexanes +hippopotami +holdem +iPods +idolator +idolator's +idolators +inactives +inactivities +incentivize +incentivized +incentivizes +incentivizing +inclosable +incorrigibleness +inkjet +inkjet's +inkjets +intermediacies +intermediacy +intermediated +intermediateness +intermediating +intermediation +intermediations +intermediator +intermediator's +intermediators +interruptible +intersexual +intersexual's +intersexualism +intersexuality +intersexuals +jewellery +judgement +judgement's +judgements +kbps +keylogger +keylogger's +keyloggers +keylogging +keylogging's +keyloggings +labelled +lector +lector's +lectors +lepidopterist +lepidopterist's +lepidopterists +limnological +limnologist +limnologist's +limnologists +limnology +limnology's +linguistical +mRNA +malwares +mammalia +megajoule +megajoule's +mesothelioma +mesothelioma's +metadata's +methoxy +migrator +migrator's +migrators +misandrist +misandrist's +misandrists +misandry +misjudgement +misjudgement's +misjudgements +mitigations +modeller +modeller's +modellers +modelling +modelling's +modellings +motorsport +motorsport's +motorsports +multicast +murine +musculus +namespace +namespace's +namespaces +nano +natively +nave +navely +naver +navest +navety +navety's +navet +navet's +neurophysiology's +neuroscience's +neurosciences +neuroscientist +neuroscientist's +neuroscientists +newswires +octopi +oligo +opposable +opposer +outlier's +parallelization +parallelization's +parallelizations +parallelize +parallelized +parallelizes +parallelizing +permalink +permalink's +permalinks +permittee +phlebotomist +phlebotomist's +phlebotomists +phlebotomize +phlebotomized +phlebotomizes +phlebotomizing +pho +phosphorylate +phosphorylated +phosphorylates +phosphorylating +plaintext +polynucleotide +polynucleotide's +polynucleotides +polypeptide's +poutine +poutines +prejudgement +prejudgement's +prejudgements +preliminarily +proclaimable +procreations +profiler +profiler's +profilers +programmatically +pronate +pronated +pronates +pronating +pronation +pronator +pronator's +pronators +proprietorships +propyl +pseudorandom +pseudorandomly +racoon +rasterization +rasterization's +rasterize +rasterized +rasterizer +rasterizes +rasterizing +reactivity's +reappointments +rebroadcasted +recency +recompilation's +recurse +recursed +recurses +recursing +reflux's +relocations +renominations +repartitions +resizable +resizer +resubmission's +retransmission's +rheumatological +rheumatologist +rheumatologist's +rheumatologists +rheumatology +rheumatology's +rotatably +sativa +savoir +schnaps +schrod +schrods +scot-free +screenshot's +searchable +selfing +selfism +selfist +selfists +seraphim +shemale +shemale's +shemales +shithead's +shitload's +shitloads +showtime's +showtimes +signalling +signup +signup's +signups +snarkily +sommelier +sommelier's +sommeliers +spelt +spick +spicks +spywares +substituent's +substituents +subsumptions +syllabi +synches +synesthesia +synesthete +synesthetes +synesthetic +synthase +synthase's +synthases +sysadmin's +sysop's +tRNA +tRNA's +telecom +telecom's +teleported +teleporting +teleports +testcase +testcase's +testcases +testsuite +testsuite's +testsuites +textbox +textbox's +textboxes +thaliana +therebetween +traceur +traceur's +traceurs +trackback +trackback's +trackbacks +transfect +transfected +transfecting +transfects +transgenderism +transgene +transgenes +triages +triaging +tweep +tweeps +uncancelled +uncheck +unchecking +unchecks +undeliverables +undesignated +unironic +unironically +unlabelled +validator +validators +vertebrata +volcanological +volcanologist +volcanologist's +volcanologists +volcanology +volcanology's +webdesign +webdesign's +webdesigns +whitepaper +whitepaper's +whitepapers +wop's diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-removed b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-removed new file mode 100644 index 000000000..50f550e0a --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-removed @@ -0,0 +1 @@ +ABCs diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-specific b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-specific new file mode 100644 index 000000000..790dc8084 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-specific @@ -0,0 +1,74 @@ +Bespin +Bespin's +Bonsai +Bonsai's +Bugzilla +Bugzilla's +Camino +Camino's +ChatZilla +ChatZilla's +Composer +Composer's +Fennec +Fennec's +Firefox +Firefox's +Flock +Flock's +Gecko +Gecko's +JavaScript +JavaScript's +Lightning +Lightning's +Mozilla +Mozilla's +NSPR +NSPR's +NSS +NSS's +Necko +Necko's +Netscape +Netscape's +Penelope +Penelope's +Prism +Prism's +Rhino +Rhino's +SeaMonkey +SeaMonkey's +Snowl +Snowl's +Songbird +Songbird's +SpiderMonkey +SpiderMonkey's +Sunbird +Sunbird's +Tamarin +Tamarin's +Thunderbird +Thunderbird's +Tinderbox +Tinderbox's +Ubiquity +Ubiquity's +Venkman +Venkman's +Weave +Weave's +XBL +XBL's +XPCOM +XPCOM's +XPConnect +XPConnect's +XPInstall +XPInstall's +XUL +XUL's +XULRunner +XULRunner's diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/README b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/README new file mode 100644 index 000000000..e1cc0590f --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/README @@ -0,0 +1,56 @@ +ADDING OR REMOVING ENTRIES IN THE DICTIONARY: + +To edit the dictionary use "edit-dictionary" and than copy the +resulting "en-US.dic" file info place. + +UPGRADING TO A NEW UPSTREAM VERSION: + +In order to upgrade to the latest dictionary some scripts found in +SCOWL (the source of the en_US Hunspell dictionary) are used. The +en_US dictionary is also generated from the SCOWL source. + +1) Unpack the tarball (tar.gz) version of the latest version of SCOWL +in the current directory and rename the directory from +"scowl-YYYY.MM.DD" to "scowl". You can find the latest version at +http://wordlist.aspell.net/ or +http://sourceforge.net/projects/wordlist/files/SCOWL/ + +2) Run the script "./make-new-dict" to generate a new dictionary and +make sure it runs without any errors. + +3) Do a quick sanity check on the resulting dictionary +"en_US-mozilla.dic". For example make sure the size is about the same +(it should likely be slightly large) as the original dictionary. + +4) Once everything is okay copy the new dictionary in place using +"./install-new-dict" and commit the changes. + +NOTES ON UPGRADE PROCESS: + +The dictionary upgrade scripts work by expanding (i.e. unmunching) the +affix compression dictionaries to create simple wordlists and use +those to generate a new dictionary. + +The upgrade script expects the original upstream version to be kept in +the directory "orig". + +The install script renames "orig" to "orig-bk" and copies the new +upstream version to "orig". The install script also copies the +original Mozilla dictionary to the "mozilla-bk". + +SUBMITTING MOZILLA SPECIFIC CHANGES UPSTREAM: + +The upgrade script creates two files that can be reviewed and possible +submitted upstream. The file "5-mozilla-removed" lists words that were +removed in the Mozilla dictionary and the file "5-mozilla-added" +contains the list of words that were added. When submitting new words +upstream Mozilla specific words that are found in "5-mozilla-specific" +(expanded from mozilla-specific.txt) should likely be removed from the list. + +ABOUT mozilla-specific.txt: + +This file contains Mozilla-specific words that should not be submitted +upstream. For example, "Firefox" goes here. (See bug 237921). + +Note that the file 5-mozilla-specific is generated by expanding +mozilla-specific.txt and should not be edited directly. diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/edit-dictionary b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/edit-dictionary new file mode 100755 index 000000000..ad77e47fd --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/edit-dictionary @@ -0,0 +1,31 @@ +#!/bin/sh +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# +# edit-dictionary + +set -e + +if [ -z "$EDITOR" ]; then + echo 'Need to set the $EDITOR environment variable to your favorite editor!' + exit 1 +fi + +# Strip the first line that contains the count +tail -n +2 ../en-US.dic > en-US.stripped + +# Open the patched hunspell editor and let the user edit it +echo "Now the dictionary is going to be opened for you to edit. When you're done, just quit the editor" +echo -n "Press Enter to begin." +read foo +$EDITOR en-US.stripped + +# Add back the line count +wc -l < en-US.stripped | tr -d '[:blank:]' > en-US.dic +LC_ALL=C sort en-US.stripped >> en-US.dic + +# Clean up +rm -f en-US.stripped + diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/install-new-dict b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/install-new-dict new file mode 100755 index 000000000..24492cad2 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/install-new-dict @@ -0,0 +1,39 @@ +#!/bin/sh + +# +# This script copies the new dictionary created by make-new-dict in +# place. +# + +set -e + +WKDIR="`pwd`" +export SCOWL="$WKDIR/scowl/" +SPELLER="$SCOWL/speller" + +set -x + +if [ -e orig-bk ]; then echo "$0: directory 'orig-bk' exists." 1>&2 ; exit 0; fi +mv orig orig-bk +mkdir orig +cp $SPELLER/en_US-custom.dic $SPELLER/en_US-custom.aff $SPELLER/README_en_US-custom.txt orig + +mkdir mozilla-bk +mv ../en-US.dic ../en-US.aff ../README_en_US.txt mozilla-bk + +# Convert the affix file to ISO8859-1 +sed -i=bak -e '/^ICONV/d' -e 's/^SET UTF-8$/SET ISO8859-1/' en_US-mozilla.aff + +# Convert the dictionary to ISO8859-1 +mv en_US-mozilla.dic en_US-mozilla-utf8.dic +iconv -f utf-8 -t iso-8859-1 < en_US-mozilla-utf8.dic > en_US-mozilla.dic + +cp en_US-mozilla.aff ../en-US.aff +cp en_US-mozilla.dic ../en-US.dic +cp README_en_US-mozilla.txt ../README_en_US.txt + +set +x + +echo "New dictionary copied into place. Please commit the changes." + + diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/make-new-dict b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/make-new-dict new file mode 100755 index 000000000..012b9154e --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/make-new-dict @@ -0,0 +1,69 @@ +#!/bin/sh + +# +# This script creates a new dictionary by expanding the original, +# Mozilla's, and the upstream dictionary to remove affix flags and +# then doing the wordlist equivalent of diff3 to create a new +# dictionary. +# +# The files 2-mozilla-add and 2-mozilla-rem contain words added and +# removed, receptively in the Mozilla dictionary. The final +# dictionary will be in hunspell-en_US-mozilla.zip. +# + +set -e + +export LANG=C +export LC_ALL=C +export LC_CTYPE=C +export LC_COLLATE=C + +WKDIR="`pwd`" + +export SCOWL="$WKDIR/scowl/" + +ORIG="$WKDIR/orig/" +SPELLER="$SCOWL/speller" + +expand() { + grep -v '^[0-9]\+$' | $SPELLER/munch-list expand $1 | sort -u +} + +cd $SPELLER +MK_LIST="../mk-list -v1 --accents=both en_US 60" +cat < params.txt +With Input Command: $MK_LIST +EOF +# note: output of make-hunspell-dict is utf-8 +$MK_LIST | ./make-hunspell-dict -one en_US-custom params.txt > ./make-hunspell-dict.log +cd $WKDIR + +# Note: Input and output of "expand" is always iso-8859-1. +# All expanded word list files are thus in iso-8859-1. + +expand $SPELLER/en.aff < $SPELLER/en.dic.supp > 0-special # input: ASCII + +# input in utf-8, expand expects iso-8859-1 so use iconv +iconv -f utf-8 -t iso-8859-1 $ORIG/en_US-custom.dic | expand $SPELLER/en_US-custom.aff > 1-base.txt + +expand ../en-US.aff < ../en-US.dic > 2-mozilla.txt # input: iso-8850-1 + +# input in utf-8, expand expects iso-8859-1 so use iconv +iconv -f utf-8 -t iso-8859-1 $SPELLER/en_US-custom.dic | expand $SPELLER/en_US-custom.aff > 3-upstream.txt + +comm -23 1-base.txt 2-mozilla.txt > 2-mozilla-rem +comm -13 1-base.txt 2-mozilla.txt > 2-mozilla-add +comm -23 3-upstream.txt 2-mozilla-rem | cat - 2-mozilla-add | sort -u > 4-patched.txt + +# note: output of make-hunspell-dict is utf-8 +cat 4-patched.txt | comm -23 - 0-special | $SPELLER/make-hunspell-dict -one en_US-mozilla /dev/null + +# sanity check should yield identical results +#comm -23 1-base.txt 3-upstream.txt > 3-upstream-rem +#comm -13 1-base.txt 3-upstream.txt > 3-upstream-add +#comm -23 2-mozilla.txt 3-upstream-rem | cat - 3-upstream-add | sort -u > 4-patched-v2.txt + +expand ../en-US.aff < mozilla-specific.txt > 5-mozilla-specific + +comm -12 3-upstream.txt 2-mozilla-rem > 5-mozilla-removed +comm -13 3-upstream.txt 2-mozilla-add > 5-mozilla-added diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/mozilla-specific.txt b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/mozilla-specific.txt new file mode 100644 index 000000000..800541ba8 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/mozilla-specific.txt @@ -0,0 +1,37 @@ +Bespin/M +Bonsai/M +Bugzilla/M +Camino/M +ChatZilla/M +Composer/M +Fennec/M +Firefox/M +Flock/M +Gecko/M +JavaScript/M +Lightning/M +Mozilla/M +Necko/M +Netscape/M +NSPR/M +NSS/M +Penelope/M +Prism/M +Rhino/M +SeaMonkey/M +Snowl/M +Songbird/M +Sunbird/M +SpiderMonkey/M +Tamarin/M +Thunderbird/M +Tinderbox/M +Ubiquity/M +Venkman/M +Weave/M +XBL/M +XPCOM/M +XPConnect/M +XPInstall/M +XUL/M +XULRunner/M diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/README_en_US-custom.txt b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/README_en_US-custom.txt new file mode 100644 index 000000000..0d725dadb --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/README_en_US-custom.txt @@ -0,0 +1,348 @@ +en_US-custom Hunspell Dictionary +Generated from SCOWL Version 2017.01.22 +Tue Jan 24 22:59:27 EST 2017 + +http://wordlist.sourceforge.net + +README file for English Hunspell dictionaries derived from SCOWL. + +These dictionaries are created using the speller/make-hunspell-dict +script in SCOWL. + +The following dictionaries are available: + + en_US (American) + en_CA (Canadian) + en_GB-ise (British with "ise" spelling) + en_GB-ize (British with "ize" spelling) + en_AU (Australian) + + en_US-large + en_CA-large + en_GB-large (with both "ise" and "ize" spelling) + en_AU-large + +The normal (non-large) dictionaries correspond to SCOWL size 60 and, +to encourage consistent spelling, generally only include one spelling +variant for a word. The large dictionaries correspond to SCOWL size +70 and may include multiple spelling for a word when both variants are +considered almost equal. The larger dictionaries however (1) have not +been as carefully checked for errors as the normal dictionaries and +thus may contain misspelled or invalid words; and (2) contain +uncommon, yet valid, words that might cause problems as they are +likely to be misspellings of more common words (for example, "ort" and +"calender"). + +To get an idea of the difference in size, here are 25 random words +only found in the large dictionary for American English: + + Bermejo Freyr's Guenevere Hatshepsut Nottinghamshire arrestment + crassitudes crural dogwatches errorless fetial flaxseeds godroon + incretion jalapeño's kelpie kishkes neuroglias pietisms pullulation + stemwinder stenoses syce thalassic zees + +The en_US, en_CA and en_AU are the official dictionaries for Hunspell. +The en_GB and large dictionaries are made available on an experimental +basis. If you find them useful please send me a quick email at +kevina@gnu.org. + +If none of these dictionaries suite you (for example, maybe you want +the normal dictionary that also includes common variants) additional +dictionaries can be generated at http://app.aspell.net/create or by +modifying speller/make-hunspell-dict in SCOWL. Please do let me know +if you end up publishing a customized dictionary. + +If a word is not found in the dictionary or a word is there you think +shouldn't be, you can lookup the word up at http://app.aspell.net/lookup +to help determine why that is. + +General comments on these list can be sent directly to me at +kevina@gnu.org or to the wordlist-devel mailing lists +(https://lists.sourceforge.net/lists/listinfo/wordlist-devel). If you +have specific issues with any of these dictionaries please file a bug +report at https://github.com/kevina/wordlist/issues. + +IMPORTANT CHANGES INTRODUCED In 2016.11.20: + +New Australian dictionaries thanks to the work of Benjamin Titze +(btitze@protonmail.ch). + +IMPORTANT CHANGES INTRODUCED IN 2016.04.24: + +The dictionaries are now in UTF-8 format instead of ISO-8859-1. This +was required to handle smart quotes correctly. + +IMPORTANT CHANGES INTRODUCED IN 2016.01.19: + +"SET UTF8" was changes to "SET UTF-8" in the affix file as some +versions of Hunspell do not recognize "UTF8". + +ADDITIONAL NOTES: + +The NOSUGGEST flag was added to certain taboo words. While I made an +honest attempt to flag the strongest taboo words with the NOSUGGEST +flag, I MAKE NO GUARANTEE THAT I FLAGGED EVERY POSSIBLE TABOO WORD. +The list was originally derived from Németh László, however I removed +some words which, while being considered taboo by some dictionaries, +are not really considered swear words in today's society. + +COPYRIGHT, SOURCES, and CREDITS: + +The English dictionaries come directly from SCOWL +and is thus under the same copyright of SCOWL. The affix file is +a heavily modified version of the original english.aff file which was +released as part of Geoff Kuenning's Ispell and as such is covered by +his BSD license. Part of SCOWL is also based on Ispell thus the +Ispell copyright is included with the SCOWL copyright. + +The collective work is Copyright 2000-2016 by Kevin Atkinson as well +as any of the copyrights mentioned below: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell these word + lists, the associated scripts, the output created from the scripts, + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appears in all copies and + that both that copyright notice and this permission notice appear in + supporting documentation. Kevin Atkinson makes no representations + about the suitability of this array for any purpose. It is provided + "as is" without express or implied warranty. + +Alan Beale also deserves special credit as he has, +in addition to providing the 12Dicts package and being a major +contributor to the ENABLE word list, given me an incredible amount of +feedback and created a number of special lists (those found in the +Supplement) in order to help improve the overall quality of SCOWL. + +The 10 level includes the 1000 most common English words (according to +the Moby (TM) Words II [MWords] package), a subset of the 1000 most +common words on the Internet (again, according to Moby Words II), and +frequently class 16 from Brian Kelk's "UK English Wordlist +with Frequency Classification". + +The MWords package was explicitly placed in the public domain: + + The Moby lexicon project is complete and has + been place into the public domain. Use, sell, + rework, excerpt and use in any way on any platform. + + Placing this material on internal or public servers is + also encouraged. The compiler is not aware of any + export restrictions so freely distribute world-wide. + + You can verify the public domain status by contacting + + Grady Ward + 3449 Martha Ct. + Arcata, CA 95521-4884 + + grady@netcom.com + grady@northcoast.com + +The "UK English Wordlist With Frequency Classification" is also in the +Public Domain: + + Date: Sat, 08 Jul 2000 20:27:21 +0100 + From: Brian Kelk + + > I was wondering what the copyright status of your "UK English + > Wordlist With Frequency Classification" word list as it seems to + > be lacking any copyright notice. + + There were many many sources in total, but any text marked + "copyright" was avoided. Locally-written documentation was one + source. An earlier version of the list resided in a filespace called + PUBLIC on the University mainframe, because it was considered public + domain. + + Date: Tue, 11 Jul 2000 19:31:34 +0100 + + > So are you saying your word list is also in the public domain? + + That is the intention. + +The 20 level includes frequency classes 7-15 from Brian's word list. + +The 35 level includes frequency classes 2-6 and words appearing in at +least 11 of 12 dictionaries as indicated in the 12Dicts package. All +words from the 12Dicts package have had likely inflections added via +my inflection database. + +The 12Dicts package and Supplement is in the Public Domain. + +The WordNet database, which was used in the creation of the +Inflections database, is under the following copyright: + + This software and database is being provided to you, the LICENSEE, + by Princeton University under the following license. By obtaining, + using and/or copying this software and database, you agree that you + have read, understood, and will comply with these terms and + conditions.: + + Permission to use, copy, modify and distribute this software and + database and its documentation for any purpose and without fee or + royalty is hereby granted, provided that you agree to comply with + the following copyright notice and statements, including the + disclaimer, and that the same appear on ALL copies of the software, + database and documentation, including modifications that you make + for internal use or for distribution. + + WordNet 1.6 Copyright 1997 by Princeton University. All rights + reserved. + + THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- + ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE + LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT INFRINGE ANY + THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + The name of Princeton University or Princeton may not be used in + advertising or publicity pertaining to distribution of the software + and/or database. Title to copyright in this software, database and + any associated documentation shall at all times remain with + Princeton University and LICENSEE agrees to preserve same. + +The 40 level includes words from Alan's 3esl list found in version 4.0 +of his 12dicts package. Like his other stuff the 3esl list is also in the +public domain. + +The 50 level includes Brian's frequency class 1, words appearing +in at least 5 of 12 of the dictionaries as indicated in the 12Dicts +package, and uppercase words in at least 4 of the previous 12 +dictionaries. A decent number of proper names is also included: The +top 1000 male, female, and Last names from the 1990 Census report; a +list of names sent to me by Alan Beale; and a few names that I added +myself. Finally a small list of abbreviations not commonly found in +other word lists is included. + +The name files form the Census report is a government document which I +don't think can be copyrighted. + +The file special-jargon.50 uses common.lst and word.lst from the +"Unofficial Jargon File Word Lists" which is derived from "The Jargon +File". All of which is in the Public Domain. This file also contain +a few extra UNIX terms which are found in the file "unix-terms" in the +special/ directory. + +The 55 level includes words from Alan's 2of4brif list found in version +4.0 of his 12dicts package. Like his other stuff the 2of4brif is also +in the public domain. + +The 60 level includes all words appearing in at least 2 of the 12 +dictionaries as indicated by the 12Dicts package. + +The 70 level includes Brian's frequency class 0 and the 74,550 common +dictionary words from the MWords package. The common dictionary words, +like those from the 12Dicts package, have had all likely inflections +added. The 70 level also included the 5desk list from version 4.0 of +the 12Dics package which is in the public domain. + +The 80 level includes the ENABLE word list, all the lists in the +ENABLE supplement package (except for ABLE), the "UK Advanced Cryptics +Dictionary" (UKACD), the list of signature words from the YAWL package, +and the 10,196 places list from the MWords package. + +The ENABLE package, mainted by M\Cooper , +is in the Public Domain: + + The ENABLE master word list, WORD.LST, is herewith formally released + into the Public Domain. Anyone is free to use it or distribute it in + any manner they see fit. No fee or registration is required for its + use nor are "contributions" solicited (if you feel you absolutely + must contribute something for your own peace of mind, the authors of + the ENABLE list ask that you make a donation on their behalf to your + favorite charity). This word list is our gift to the Scrabble + community, as an alternate to "official" word lists. Game designers + may feel free to incorporate the WORD.LST into their games. Please + mention the source and credit us as originators of the list. Note + that if you, as a game designer, use the WORD.LST in your product, + you may still copyright and protect your product, but you may *not* + legally copyright or in any way restrict redistribution of the + WORD.LST portion of your product. This *may* under law restrict your + rights to restrict your users' rights, but that is only fair. + +UKACD, by J Ross Beresford , is under the +following copyright: + + Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved. + + The following restriction is placed on the use of this publication: + if The UK Advanced Cryptics Dictionary is used in a software package + or redistributed in any form, the copyright notice must be + prominently displayed and the text of this document must be included + verbatim. + + There are no other restrictions: I would like to see the list + distributed as widely as possible. + +The 95 level includes the 354,984 single words, 256,772 compound +words, 4,946 female names and the 3,897 male names, and 21,986 names +from the MWords package, ABLE.LST from the ENABLE Supplement, and some +additional words found in my part-of-speech database that were not +found anywhere else. + +Accent information was taken from UKACD. + +The VarCon package was used to create the American, British, Canadian, +and Australian word list. It is under the following copyright: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Kevin Atkinson makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Copyright 2016 by Benjamin Titze + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Benjamin Titze makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Since the original words lists come from the Ispell distribution: + + Copyright 1993, Geoff Kuenning, Granada Hills, CA + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All modifications to the source code must be clearly marked as + such. Binary redistributions based on modified source code + must be clearly marked as modified versions in the documentation + and/or other materials provided with the distribution. + (clause 4 removed with permission from Geoff Kuenning) + 5. The name of Geoff Kuenning may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +Build Date: Tue Jan 24 22:59:27 EST 2017 +With Input Command: ../mk-list -v1 --accents=both en_US 60 diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.aff b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.aff new file mode 100644 index 000000000..d0cccb3dc --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.aff @@ -0,0 +1,205 @@ +SET UTF-8 +TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' +ICONV 1 +ICONV ’ ' +NOSUGGEST ! + +# ordinal numbers +COMPOUNDMIN 1 +# only in compounds: 1th, 2th, 3th +ONLYINCOMPOUND c +# compound rules: +# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.) +# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.) +COMPOUNDRULE 2 +COMPOUNDRULE n*1t +COMPOUNDRULE n*mp +WORDCHARS 0123456789 + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 90 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP alot a_lot +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion +REP size cise diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.dic b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.dic new file mode 100644 index 000000000..53e1bb406 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.dic @@ -0,0 +1,49468 @@ +49467 +0/nm +0th/pt +1/n1 +1st/p +1th/tc +2/nm +2nd/p +2th/tc +3/nm +3rd/p +3th/tc +4/nm +4th/pt +5/nm +5th/pt +6/nm +6th/pt +7/nm +7th/pt +8/nm +8th/pt +9/nm +9th/pt +A/SM +AA/M +AAA +AB/M +ABA +ABC/SM +ABM/SM +ABS +AC/M +ACLU/M +ACT +ACTH/M +AD/M +ADC +ADD +ADM +ADP/M +AF +AFAIK +AFB +AFC/M +AFDC +AFN +AFT +AI/SM +AIDS/M +AK +AL +AM/M +AMA +AMD/M +ANSI/S +ANZUS/M +AOL/M +AP/M +APB +APC +API +APO +APR +AR +ARC +ASAP +ASCII/SM +ASL/M +ASPCA +ATM/M +ATP/M +ATV +AV +AVI +AWACS/M +AWOL/M +AZ/M +AZT/M +Aachen/M +Aaliyah/M +Aaron/M +Abbas/M +Abbasid/M +Abbott/M +Abby/M +Abdul/M +Abe/M +Abel/M +Abelard/M +Abelson/M +Aberdeen/M +Abernathy/M +Abidjan/M +Abigail/M +Abilene/M +Abner/M +Aborigine/MS +Abraham/M +Abram/MS +Abrams/M +Absalom/M +Abuja/M +Abyssinia/M +Abyssinian/M +Ac/M +Acadia/M +Acapulco/M +Accenture/M +Accra/M +Acevedo/M +Achaean/M +Achebe/M +Achernar/M +Acheson/M +Achilles/M +Aconcagua/M +Acosta/M +Acropolis +Acrux/M +Actaeon/M +Acton/M +Acts/M +Acuff/M +Ada/SM +Adam/SM +Adams/M +Adan/M +Adana/M +Adar/M +Addams/M +Adderley/M +Addie/M +Addison/M +Adela/M +Adelaide/M +Adele/M +Adeline/M +Aden/M +Adenauer/M +Adhara/M +Adidas/M +Adirondack/SM +Adirondacks/M +Adkins/M +Adler/M +Adm +Admiralty +Adolf/M +Adolfo/M +Adolph/M +Adonis/MS +Adrenalin/MS +Adrian/M +Adriana/M +Adriatic/M +Adrienne/M +Advent/MS +Adventist/MS +Advil/M +Aegean/M +Aelfric/M +Aeneas/M +Aeneid/M +Aeolus/M +Aeroflot/M +Aeschylus/M +Aesculapius/M +Aesop/M +Afghan/SM +Afghani/M +Afghanistan/M +Afr +Africa/M +African/SM +Afrikaans/M +Afrikaner/SM +Afro/SM +Afrocentric +Afrocentrism/M +Ag/M +Agamemnon/M +Agana +Agassi/M +Agassiz/M +Agatha/M +Aggie/M +Aglaia/M +Agnes/M +Agnew/M +Agni/M +Agra/M +Agricola/M +Agrippa/M +Agrippina/M +Aguascalientes +Aguilar/M +Aguinaldo/M +Aguirre/M +Agustin/M +Ahab/M +Ahmad/M +Ahmadabad/M +Ahmadinejad/M +Ahmed/M +Ahriman/M +Aida/M +Aiken/M +Aileen/M +Aimee/M +Ainu/M +Airedale/MS +Aires/M +Aisha/M +Ajax/M +Akbar/M +Akhmatova/M +Akihito/M +Akita/M +Akiva/M +Akkad/M +Akron/M +Al/M +Ala/S +Alabama/M +Alabaman/MS +Alabamian/SM +Aladdin/M +Alamo/M +Alamogordo/M +Alan/M +Alana/M +Alar/M +Alaric/M +Alaska/M +Alaskan/MS +Alba/M +Albania/M +Albanian/MS +Albany/M +Albee/M +Alberio/M +Albert/M +Alberta/M +Albertan +Alberto/M +Albigensian/M +Albion/M +Albireo/M +Albuquerque/M +Alcatraz/M +Alcestis/M +Alcibiades/M +Alcindor/M +Alcmena/M +Alcoa/M +Alcott/M +Alcuin/M +Alcyone/M +Aldan/M +Aldebaran/M +Alden/M +Alderamin/M +Aldo/M +Aldrin/M +Alec/M +Aleichem/M +Alejandra/M +Alejandro/M +Alembert/M +Aleppo/M +Aleut/MS +Aleutian/SM +Alex/M +Alexander/MS +Alexandra/M +Alexandria/M +Alexandrian +Alexei/M +Alexis/M +Alfonso/M +Alfonzo/M +Alford/M +Alfred/M +Alfreda/M +Alfredo/M +Algenib/M +Alger/M +Algeria/M +Algerian/SM +Algieba/M +Algiers/M +Algol/M +Algonquian/SM +Algonquin/MS +Alhambra/M +Alhena/M +Ali/M +Alice/M +Alicia/M +Alighieri/M +Aline/M +Alioth/M +Alisa/M +Alisha/M +Alison/M +Alissa/M +Alistair/M +Alkaid/M +Allah/M +Allahabad/M +Allan/M +Alleghenies/M +Allegheny/SM +Allegra/M +Allen/M +Allende/M +Allentown/M +Allhallows/M +Allie/MS +Allison/M +Allstate/M +Allyson/M +Alma/M +Almach/M +Almaty/M +Almighty/M +Almohad/M +Almoravid/M +Alnilam/M +Alnitak/M +Alonzo/M +Alpert/M +Alphard/M +Alphecca/M +Alpheratz/M +Alphonse/M +Alphonso/M +Alpine/M +Alpo/M +Alps/M +Alsace/M +Alsatian/SM +Alsop/M +Alston/M +Alta/M +Altai/M +Altaic/M +Altair/M +Altamira/M +Althea/M +Altiplano/M +Altman/M +Altoids/M +Alton/M +Aludra/M +Alva/M +Alvarado/M +Alvarez/M +Alvaro/M +Alvin/M +Alyce/M +Alyson/M +Alyssa/M +Alzheimer/M +Am/MNR +Amadeus/M +Amado/M +Amalia/M +Amanda/M +Amarillo/M +Amaru/M +Amaterasu/M +Amati/M +Amazon/SM +Amazonian +Amber/M +Amelia/M +Amen/M +Amenhotep/M +Amerasian/M +America/SM +American/MS +Americana/M +Americanism/MS +Americanization/MS +Americanize/GDS +Amerind/SM +Amerindian/MS +Ameslan/M +Amharic/M +Amherst/M +Amie/M +Amiga/M +Amish/M +Amman/M +Amoco/M +Amos/M +Amparo/M +Ampere/M +Amritsar/M +Amsterdam/M +Amtrak/M +Amundsen/M +Amur/M +Amway/M +Amy/M +Ana/M +Anabaptist/M +Anabel/M +Anacin/M +Anacreon/M +Anaheim/M +Analects/M +Ananias/M +Anasazi/M +Anastasia/M +Anatole/M +Anatolia/M +Anatolian/M +Anaxagoras/M +Anchorage/M +Andalusia/M +Andalusian/M +Andaman/M +Andean/M +Andersen/M +Anderson/M +Andes/M +Andorra/M +Andorran/SM +Andre/MS +Andrea/M +Andrei/M +Andres/M +Andretti/M +Andrew/SM +Andrews/M +Andrianampoinimerina/M +Android/M +Andromache/M +Andromeda/M +Andropov/M +Andy/M +Angara/M +Angel/M +Angela/M +Angeles/M +Angelia/M +Angelica/M +Angelico/M +Angelina/M +Angeline/M +Angelique/M +Angelita/M +Angelo/M +Angelou/M +Angevin/M +Angie/M +Angkor/M +Angle/MS +Anglia/M +Anglican/SM +Anglicanism/MS +Anglicism/MS +Anglicization +Anglicize +Anglo/M +Anglophile/M +Anglophobe +Angola/M +Angolan/MS +Angora/SM +Angstrom/M +Anguilla/M +Angus/M +Aniakchak/M +Anibal/M +Anita/M +Ankara/M +Ann/M +Anna/M +Annabel/M +Annabelle/M +Annam/M +Annapolis/M +Annapurna/M +Anne/M +Annette/M +Annie/M +Annmarie/M +Annunciation/SM +Anouilh/M +Anselm/M +Anselmo/M +Anshan/M +Antaeus/M +Antananarivo/M +Antarctic/M +Antarctica/M +Antares/M +Anthony/M +Anthropocene +Antichrist/SM +Antietam/M +Antigone/M +Antigua/M +Antillean +Antilles/M +Antioch/M +Antipas/M +Antipodes +Antofagasta/M +Antoine/M +Antoinette/M +Anton/M +Antone/M +Antonia/M +Antoninus/M +Antonio/M +Antonius/M +Antony/M +Antwan/M +Antwerp/M +Anubis/M +Anzac/M +Apache/SM +Apalachicola/M +Apatosaurus +Apennines/M +Aphrodite/M +Apia/M +Apocalypse/M +Apocrypha/M +Apollinaire/M +Apollo/SM +Apollonian/M +Apostle/M +Appalachia/M +Appalachian/SM +Appalachians/M +Appaloosa/SM +Apple/M +Appleseed/M +Appleton/M +Appomattox/M +Apr/M +April/MS +Apuleius/M +Aquafresh/M +Aquarian +Aquarius/MS +Aquila/M +Aquinas/M +Aquino/M +Aquitaine/M +Ar/M +Ara/M +Arab/SM +Arabia/M +Arabian/MS +Arabic/M +Arabist/MS +Araby/M +Araceli/M +Arafat/M +Aragon +Araguaya/M +Aral/M +Aramaic/M +Aramco/M +Arapaho/MS +Arapahoes +Ararat/M +Araucanian/M +Arawak/M +Arawakan/M +Arbitron/M +Arcadia/M +Arcadian/M +Archean/M +Archibald/M +Archie/M +Archimedes/M +Arctic/M +Arcturus/M +Ardabil +Arden/M +Arequipa/M +Ares/M +Argentina/M +Argentine/M +Argentinean +Argentinian/MS +Argo/SM +Argonaut/MS +Argonne/M +Argos/M +Argus/M +Ariadne/M +Arianism/M +Ariel/M +Aries/MS +Ariosto/M +Aristarchus/M +Aristides/M +Aristophanes/M +Aristotelian/M +Aristotle/M +Arius/M +Ariz +Arizona/M +Arizonan/SM +Arizonian/MS +Arjuna/M +Ark/M +Arkansan/MS +Arkansas/M +Arkhangelsk/M +Arkwright/M +Arlene/M +Arline/M +Arlington/M +Armageddon/SM +Armagnac/M +Armand/M +Armando/M +Armani/M +Armenia/M +Armenian/SM +Arminius/M +Armonk/M +Armour/M +Armstrong/M +Arneb/M +Arnhem/M +Arno/M +Arnold/M +Arnulfo/M +Aron/M +Arrhenius/M +Arron/M +Art/M +Artaxerxes/M +Artemis/M +Arthur/M +Arthurian/M +Artie/M +Arturo/M +Aruba/M +Aryan/MS +As/M +Asama/M +Ascella/M +Ascension/M +Asgard/M +Ashanti/M +Ashcroft/M +Ashe/M +Ashgabat +Ashikaga/M +Ashkenazim/M +Ashkhabad/M +Ashlee/M +Ashley/M +Ashmolean/M +Ashurbanipal/M +Asia/M +Asiago +Asian/MS +Asiatic/SM +Asimov/M +Asmara/M +Asoka/M +Aspell/M +Aspen/M +Asperger/M +Aspidiske/M +Asquith/M +Assad/M +Assam/M +Assamese/M +Assembly +Assisi/M +Assyria/M +Assyrian/SM +Astaire/M +Astana/M +Astarte/M +Aston/M +Astor/M +Astoria/M +Astrakhan/M +AstroTurf/M +Asturias/M +Asuncion/M +Asunción/M +Aswan/M +At/SM +Atacama/M +Atahualpa/M +Atalanta/M +Atari/M +Ataturk/M +Atatürk/M +Athabasca/M +Athabaska +Athabaskan/SM +Athanasius +Athena/M +Athene/M +Athenian/SM +Athens/M +Atkins/M +Atkinson/M +Atlanta/M +Atlantes +Atlantic/M +Atlantis/M +Atlas/MS +Atman/M +Atonement +Atreus/M +Atria/M +Atropos/M +Attic/M +Attica/M +Attila/M +Attlee/M +Attn +Attucks/M +Atwood/M +Au/M +Aubrey/M +Auckland/M +Auden/M +Audi/M +Audion/M +Audra/M +Audrey/M +Audubon/M +Aug/M +Augean/M +Augsburg/M +August/MS +Augusta/M +Augustan/M +Augustine/M +Augustinian/MS +Augustus/M +Aurangzeb/M +Aurelia/M +Aurelio/M +Aurelius/M +Aureomycin/M +Auriga/M +Aurora/M +Auschwitz/M +Aussie/MS +Austen/M +Austerlitz/M +Austin/MS +Australasia/M +Australasian +Australia/M +Australian/SM +Australoid/M +Australopithecus/M +Austria/M +Austrian/SM +Austronesian/M +Autumn/M +Av/M +Ava/M +Avalon/M +Ave/M +Aventine/M +Avernus/M +Averroes/M +Avery/M +Avesta/M +Avicenna/M +Avignon/M +Avila/M +Avior/M +Avis/M +Avogadro/M +Avon/M +Axis +Axum/M +Ayala/M +Ayers/M +Aymara/M +Ayrshire/M +Ayurveda/M +Ayyubid/M +Azana/M +Azania/M +Azazel/M +Azerbaijan/M +Azerbaijani/MS +Azores/M +Azov/M +Aztec/SM +Aztecan/M +Aztlan/M +B/MNT +BA/M +BASIC/SM +BB/M +BBB/M +BBC/M +BBQ +BBS +BBSes +BC/M +BFF +BIA +BIOS +BITNET +BLT/SM +BM/M +BMW/M +BO +BP/M +BPOE +BR +BS/M +BSA +BSD/SM +BTU +BTW +BYOB +Ba/M +Baal/SM +Baath/M +Baathist/M +Babbage/M +Babbitt/M +Babel/MS +Babylon/MS +Babylonia/M +Babylonian/SM +Bacall/M +Bacardi/M +Bacchanalia/M +Bacchic +Bacchus/M +Bach/M +Backus/M +Bacon/M +Bactria/M +Baden/M +Badlands/M +Baedeker/MS +Baez/M +Baffin/M +Baggies/M +Baghdad/M +Baguio/M +Baha'i/M +Baha'ullah/M +Bahama/SM +Bahamanian +Bahamas/M +Bahamian/MS +Bahia/M +Bahrain/M +Baikal/M +Bailey/M +Baird/M +Bakelite/M +Baker/M +Bakersfield/M +Baku/M +Bakunin/M +Balanchine/M +Balaton/M +Balboa/M +Balder/M +Baldwin/SM +Balearic/M +Balfour/M +Bali/M +Balinese/M +Balkan/MS +Balkans/M +Balkhash/M +Ball/M +Ballard/M +Balthazar/M +Baltic/M +Baltimore/M +Baluchistan/M +Balzac/M +Bamako/M +Bambi/M +Banach/M +Bancroft/M +Bandung/M +Bangalore/M +Bangkok/M +Bangladesh/M +Bangladeshi/SM +Bangor/M +Bangui/M +Banjarmasin/M +Banjul/M +Banks/M +Banneker/M +Bannister/M +Banting/M +Bantu/MS +Baotou/M +Baptist/SM +Baptiste/M +Barabbas/M +Barack/M +Barbadian/SM +Barbados/M +Barbara/M +Barbarella/M +Barbarossa/M +Barbary/M +Barber/M +Barbie/M +Barbour/M +Barbra/M +Barbuda/M +Barcelona/M +Barclay/SM +Barclays/M +Bardeen/M +Barents/M +Barker/M +Barkley/M +Barlow/M +Barnabas/M +Barnaby/M +Barnard/M +Barnaul/M +Barnes/M +Barnett/M +Barney/M +Barnum/M +Baroda/M +Barquisimeto/M +Barr/M +Barranquilla/M +Barrera/M +Barrett/M +Barrie/M +Barron/M +Barry/M +Barrymore/M +Bart/M +Barth/MS +Bartholdi/M +Bartholomew/M +Bartlett/M +Bartok/M +Barton/M +Bartók/M +Baruch/M +Baryshnikov/M +Basel/M +Basho/M +Basic +Basie/M +Basil/M +Basque/MS +Basra/M +Bass/M +Basseterre/M +Bastille/M +Basutoland/M +Bataan/M +Bates/M +Bathsheba/M +Batista/M +Batman/M +Battle/M +Batu/M +Baudelaire/M +Baudouin/M +Baudrillard/M +Bauer/M +Bauhaus/M +Baum/M +Bavaria/M +Bavarian/M +Baxter/M +Bayamon +Bayer/M +Bayes/M +Bayesian/M +Bayeux/M +Baylor/M +Bayonne/M +Bayreuth/M +Baywatch/M +Be/MH +Beach/M +Beadle/M +Bean/M +Beard/M +Beardmore/M +Beardsley/M +Bearnaise/M +Beasley/M +Beatlemania/M +Beatles/M +Beatrice/M +Beatrix/M +Beatriz/M +Beatty/M +Beau/M +Beaufort/M +Beaujolais/M +Beaumarchais/M +Beaumont/M +Beauregard/M +Beauvoir/M +Bechtel/M +Beck/MR +Becker/M +Becket/M +Beckett/M +Becky/M +Becquerel/M +Bede/M +Bedouin/SM +Beebe/M +Beecher/M +Beefaroni/M +Beelzebub/M +Beerbohm/M +Beethoven/M +Beeton/M +Begin/M +Behan/M +Behring/M +Beiderbecke/M +Beijing/M +Beirut/M +Bekesy/M +Bela/M +Belarus/M +Belau/M +Belem/M +Belfast/M +Belg +Belgian/SM +Belgium/M +Belgrade/M +Belinda/M +Belize/M +Bell/M +Bella/M +Bellamy/M +Bellatrix/M +Belleek/M +Bellini/M +Bellow/M +Belmont/M +Belmopan/M +Belorussian/MS +Belshazzar/M +Beltane/M +Belushi/M +Ben/M +Benacerraf/M +Benares/M +Benchley/M +Bender/M +Bendix/M +Benedict/M +Benedictine/MS +Benelux/M +Benet/M +Benetton/M +Bengal/SM +Bengali/M +Benghazi/M +Benin/M +Beninese/M +Benita/M +Benito/M +Benjamin/M +Bennett/M +Bennie/M +Benny/M +Benson/M +Bentham/M +Bentley/M +Benton/M +Benz/M +Benzedrine/M +Beowulf/M +Berber/SM +Berenice/M +Beretta/M +Berg/MNR +Bergen/M +Berger/M +Bergerac/M +Bergman/M +Bergson/M +Beria/M +Bering/M +Berkeley/M +Berkshire/SM +Berkshires/M +Berle/M +Berlin/SZMR +Berliner/M +Berlioz/M +Berlitz/M +Bermuda/SM +Bermudan/SM +Bermudian/SM +Bern/M +Bernadette/M +Bernadine/M +Bernanke/M +Bernard/M +Bernardo/M +Bernays/M +Bernbach/M +Bernese +Bernhardt/M +Bernice/M +Bernie/M +Bernini/M +Bernoulli/M +Bernstein/M +Berra/M +Berry/M +Bert/M +Berta/M +Bertelsmann/M +Bertha/M +Bertie/M +Bertillon/M +Bertram/M +Bertrand/M +Beryl/M +Berzelius/M +Bess/M +Bessel/M +Bessemer/M +Bessie/M +Best/M +Betelgeuse/M +Beth/M +Bethany/M +Bethe/M +Bethesda/M +Bethlehem/M +Bethune/M +Betsy/M +Bette/M +Bettie/M +Betty/M +Bettye/M +Beulah/M +Beveridge +Beverley/M +Beverly/M +Beyer/M +Bharat/M +Bhopal/M +Bhutan/M +Bhutanese/M +Bhutto/M +Bi/M +Bialystok/M +Bianca/M +Bib +Bible/MS +Biblical/M +Bic/M +Biddle/M +Biden/M +Bierce/M +Bigfoot/M +Biggles/M +Biko/M +Bilbao/M +Bilbo/M +Bill/MJ +Billie/M +Billings/M +Billy/M +Bimini/M +Bioko/M +Bird/M +Birdseye/M +Birkenstock/M +Birmingham/M +Biro/M +Biscay/M +Biscayne/M +Bishkek/M +Bishop/M +Bismarck/M +Bismark/M +Bisquick/M +Bissau/M +BitTorrent/M +Bizet/M +Bjerknes/M +Bjork/M +Bk/M +Black/MS +BlackBerry/M +Blackbeard/M +Blackburn/M +Blackfeet/M +Blackfoot/M +Blackpool/M +Blackshirt/M +Blackstone/M +Blackwell/M +Blaine/M +Blair/M +Blake/M +Blanca/M +Blanchard/M +Blanche/M +Blankenship/M +Blantyre/M +Blatz/M +Blavatsky/M +Blenheim/M +Blevins/M +Bligh/M +Bloch/M +Blockbuster/M +Bloemfontein/M +Blondel/M +Blondie/M +Bloom/MR +Bloomer/M +Bloomfield/M +Bloomingdale/M +Bloomsbury/M +Blu +Blucher/M +Bluebeard/M +Bluetooth/M +Blvd +Blythe/M +Boadicea +Boas/M +Bob/M +Bobbi/M +Bobbie/M +Bobbitt/M +Bobby/M +Boccaccio/M +Bodhidharma/M +Bodhisattva/M +Bodleian +Boeing/M +Boeotia/M +Boeotian/M +Boer/SM +Boethius/M +Bogart/M +Bogota/M +Bogotá/M +Bohemia/M +Bohemian/SM +Bohr/M +Boise/M +Bojangles/M +Boleyn/M +Bolivar/M +Bolivia/M +Bolivian/MS +Bollywood/M +Bologna/M +Bolshevik/SM +Bolsheviki +Bolshevism/M +Bolshevist/M +Bolshoi/M +Bolton/M +Boltzmann/M +Bombay/M +Bonaparte/M +Bonaventure/M +Bond/M +Bonhoeffer/M +Boniface/M +Bonita/M +Bonn/MR +Bonner/M +Bonneville/M +Bonnie/M +Bono/M +Booker/M +Boole/M +Boolean/M +Boone/M +Bootes/M +Booth/M +Bordeaux/M +Borden/M +Bordon/M +Boreas/M +Borg/SM +Borges/M +Borgia/M +Borglum/M +Boris/M +Bork/M +Borlaug/M +Born/M +Borneo/M +Borobudur/M +Borodin/M +Boru/M +Bosch/M +Bose/M +Bosnia/M +Bosnian +Bosporus/M +Boston/MS +Bostonian/M +Boswell/M +Botox +Botswana/M +Botticelli/M +Boulder/M +Boulez/M +Bourbaki/M +Bourbon/SM +Bournemouth/M +Bovary/M +Bowditch/M +Bowell/M +Bowen/M +Bowers/M +Bowery/M +Bowie/M +Bowman/M +Boyd/M +Boyer/M +Boyle/M +Boötes/M +Br/MT +Brad/MY +Bradbury/M +Braddock/M +Bradford/M +Bradley/M +Bradly/M +Bradshaw/M +Bradstreet/M +Brady/M +Bragg/M +Brahe/M +Brahma/MS +Brahmagupta/M +Brahman/MS +Brahmani +Brahmanism/SM +Brahmaputra/M +Brahms/M +Braille/MS +Brain/M +Brampton/M +Bran/M +Branch/M +Brandeis/M +Branden/M +Brandenburg/M +Brandi/M +Brandie/M +Brando/M +Brandon/M +Brandt/M +Brandy/M +Brant/M +Braque/M +Brasilia/M +Bratislava/M +Brattain/M +Bray/M +Brazil/M +Brazilian/MS +Brazos/M +Brazzaville/M +Breakspear/M +Breathalyzer +Brecht/M +Breckenridge/M +Bremen/M +Brenda/M +Brendan/M +Brennan/M +Brenner/M +Brent/M +Brenton/M +Brest/M +Bret/M +Breton/M +Brett/M +Brewer/M +Brewster/M +Brezhnev/M +Brian/M +Briana/M +Brianna/M +Brice/M +Bridalveil/M +Bridgeport/M +Bridger/M +Bridges/M +Bridget/M +Bridgetown/M +Bridgett/M +Bridgette/M +Bridgman/M +Brie/SM +Brigadoon/M +Briggs/M +Brigham/M +Bright/M +Brighton/M +Brigid/M +Brigitte/M +Brillo/M +Brinkley/M +Brisbane/M +Bristol/M +Brit/SM +Britain/M +Britannia/M +Britannic/M +Britannica/M +Briticism/SM +British/MRZ +Britisher/M +Britney/M +Briton/MS +Britt/MN +Brittany/SM +Britten/M +Brittney/M +Brno/M +Broadway/SM +Brobdingnag/M +Brobdingnagian/M +Brock/M +Brokaw/M +Bronson/M +Bronte/M +Brontosaurus +Bronx/M +Brooke/MS +Brooklyn/M +Brooks/M +Bros +Brown/MG +Browne/M +Brownian/M +Brownie/S +Browning/M +Brownshirt/M +Brownsville/M +Brubeck/M +Bruce/M +Bruckner/M +Bruegel +Brummel/M +Brunei/M +Bruneian/MS +Brunelleschi/M +Brunhilde/M +Bruno/M +Brunswick/M +Brussels/M +Brut/M +Brutus/M +Bryan/M +Bryant/M +Bryce/M +Brynner/M +Bryon/M +Brzezinski/M +Btu/M +Buber/M +Buchanan/M +Bucharest/M +Buchenwald/M +Buchwald/M +Buck/M +Buckingham/M +Buckley/M +Buckner/M +Bud/M +Budapest/M +Buddha/SM +Buddhism/SM +Buddhist/SM +Buddy/M +Budweiser/M +Buffalo/M +Buffy/M +Buford/M +Bugatti/M +Bugzilla/M +Buick/M +Bujumbura/M +Bukhara/M +Bukharin/M +Bulawayo/M +Bulfinch/M +Bulganin/M +Bulgar/M +Bulgari/M +Bulgaria/M +Bulgarian/SM +Bullock/M +Bullwinkle/M +Bultmann/M +Bumppo/M +Bunche/M +Bundesbank/M +Bundestag/M +Bunin/M +Bunker/M +Bunsen/M +Bunuel/M +Bunyan/M +Burbank/M +Burberry/M +Burch/M +Burger/M +Burgess/M +Burgoyne/M +Burgundian/M +Burgundy/SM +Burke/M +Burks/M +Burl/M +Burlington/M +Burma/M +Burmese/M +Burnett/M +Burns/M +Burnside/M +Burr/M +Burris/M +Burroughs/M +Bursa/M +Burt/M +Burton/M +Burundi/M +Burundian/MS +Busch/M +Bush/M +Bushido/M +Bushnell/M +Butler/M +Butterfingers/M +Buxtehude/M +Buñuel/M +Byblos/M +Byers/M +Byrd/M +Byron/M +Byronic/M +Byzantine/MS +Byzantium/M +C/SM +CA +CAD/M +CAI +CAM +CAP +CARE +CATV +CB +CBC/M +CBS/M +CCTV +CCU +CD/M +CDC +CDT +CEO/M +CF +CFC/M +CFO +CGI +CIA/M +CID +CNN/M +CNS/M +CO/M +COBOL/SM +COD +COL +COLA +CPA/M +CPI/M +CPO +CPR/M +CPU/M +CRT/SM +CST/M +CT/M +CV +CVS/M +CZ +Ca/M +Cabernet/M +Cabot/M +Cabral/M +Cabrera/M +Cabrini/M +Cadette +Cadillac/M +Cadiz/M +Caedmon/M +Caerphilly/M +Caesar/SM +Cage/M +Cagney/M +Cahokia/M +Caiaphas/M +Cain/SM +Cairo/M +Caitlin/M +Cajun/MS +Cal/M +Calais/M +Calcutta/M +Calder/M +Calderon/M +Caldwell/M +Caleb/M +Caledonia/M +Calgary/M +Calhoun/M +Cali/M +Caliban/M +Calif +California/M +Californian/SM +Caligula/M +Callaghan/M +Callahan/M +Callao/M +Callas/M +Callie/M +Calliope/M +Callisto/M +Caloocan/M +Calvary/M +Calvert/M +Calvin/M +Calvinism/MS +Calvinist/MS +Calvinistic +Camacho/M +Cambodia/M +Cambodian/SM +Cambrian/SM +Cambridge/M +Camden/M +Camel/M +Camelopardalis/M +Camelot/MS +Camembert/MS +Cameron/M +Cameroon/SM +Cameroonian/MS +Camilla/M +Camille/M +Camoens/M +Campanella/M +Campbell/M +Campinas/M +Campos/M +Camry/M +Camus/M +Can/M +Canaan/M +Canaanite/MS +Canad +Canada/M +Canadian/SM +Canadianism +Canaletto/M +Canaries/M +Canaveral/M +Canberra/M +Cancer/SM +Cancun/M +Candace/M +Candice/M +Candide/M +Candy/M +Cannes/M +Cannon/M +Canon/M +Canopus/M +Cantabrigian/M +Canterbury/M +Canton/M +Cantonese/M +Cantor/M +Cantrell/M +Cantu/M +Canute/M +Capablanca/M +Capek/M +Capella/M +Capet/M +Capetian/M +Capetown/M +Caph/M +Capistrano/M +Capitol/SM +Capitoline/M +Capone/M +Capote/M +Capra/M +Capri/M +Capricorn/MS +Capt +Capuchin/M +Capulet/M +Cara/M +Caracalla/M +Caracas/M +Caravaggio/M +Carboloy/M +Carboniferous/M +Carborundum/M +Cardenas/M +Cardiff/M +Cardin/M +Cardozo/M +Carey/M +Carib/MS +Caribbean/MS +Carina/M +Carissa/M +Carl/M +Carla/M +Carlene/M +Carlin/M +Carlo/MS +Carlos/M +Carlsbad/M +Carlson/M +Carlton/M +Carly/M +Carlyle/M +Carmela/M +Carmella/M +Carmelo/M +Carmen/M +Carmichael/M +Carmine/M +Carnap/M +Carnation/M +Carnegie/M +Carney/M +Carnot/M +Carol/M +Carole/M +Carolina/M +Caroline/M +Carolingian/M +Carolinian/M +Carolyn/M +Carpathian/SM +Carpathians/M +Carpenter/M +Carr/M +Carranza/M +Carrie/RM +Carrier/M +Carrillo/M +Carroll/M +Carson/M +Carter/M +Cartesian/M +Carthage/M +Carthaginian/MS +Cartier/M +Cartwright/M +Caruso/M +Carver/M +Cary/M +Casablanca/M +Casals/M +Casandra/M +Casanova/SM +Cascades/M +Case/M +Casey/M +Cash/M +Casio/M +Caspar/M +Caspian/M +Cassandra/SM +Cassatt/M +Cassidy/M +Cassie/M +Cassiopeia/M +Cassius/M +Castaneda/M +Castile/M +Castilian +Castillo/M +Castlereagh/M +Castor/M +Castries/M +Castro/M +Catalan/SM +Catalina/M +Catalonia/M +Catawba/M +Caterpillar/M +Cathay/M +Cather/M +Catherine/M +Cathleen/M +Catholic/MS +Catholicism/MS +Cathryn/M +Cathy/M +Catiline/M +Cato/M +Catskill/SM +Catskills/M +Catt/M +Catullus/M +Caucasian/MS +Caucasoid +Caucasus/M +Cauchy/M +Cavendish/M +Cavour/M +Caxton/M +Cayenne/M +Cayman/M +Cayuga/SM +Cayuse +Cb +Cd/M +Ce/M +Ceausescu/M +Cebu/M +Cebuano/M +Cecelia/M +Cecil/M +Cecile/M +Cecilia/M +Cecily/M +Cedric/M +Celebes/M +Celeste/M +Celia/M +Celina/M +Cellini/M +Celsius/M +Celt/SM +Celtic/SM +Cenozoic/M +Centaurus/M +Centigrade +Central +Cepheid/M +Cepheus/M +Cerberus/M +Cerenkov/M +Ceres/M +Cerf/M +Cervantes/M +Cesar/M +Cesarean/M +Cessna/M +Cetus/M +Ceylon/M +Ceylonese +Cezanne/M +Cf/M +Ch'in/M +Ch/N +Chablis/M +Chad/M +Chadian/MS +Chadwick/M +Chagall/M +Chaitanya/M +Chaitin/M +Chaldea +Chaldean/M +Challenger/M +Chalmers +Chamberlain/M +Chambers/M +Champlain/M +Champollion/M +Chan/M +Chance/M +Chancellorsville/M +Chandigarh/M +Chandler/M +Chandon/M +Chandra/M +Chandragupta/M +Chandrasekhar/M +Chanel/M +Chaney/M +Chang/M +Changchun/M +Changsha/M +Chantilly/M +Chaplin/M +Chaplinesque +Chapman/M +Chappaquiddick/M +Chapultepec/M +Charbray/M +Chardonnay/M +Charity/M +Charlemagne/M +Charlene/M +Charles/M +Charleston/MS +Charley/M +Charlie/M +Charlotte/M +Charlottetown/M +Charmaine/M +Charmin/M +Charolais/M +Charon/M +Chartism/M +Chartres/M +Charybdis/M +Chase/M +Chasity/M +Chateaubriand/M +Chattahoochee/M +Chattanooga/M +Chatterley/M +Chatterton/M +Chaucer/M +Chauncey/M +Chautauqua/M +Chavez/M +Chayefsky/M +Che/M +Chechen/M +Chechnya/M +Cheddar/M +Cheer/M +Cheerios/M +Cheetos/M +Cheever/M +Chekhov/M +Chekhovian +Chelsea/M +Chelyabinsk/M +Chen/M +Cheney/M +Chengdu/M +Chennai/M +Cheops/M +Cheri/M +Cherie/M +Chernenko/M +Chernobyl/M +Chernomyrdin/M +Cherokee/MS +Cherry/M +Cheryl/M +Chesapeake/M +Cheshire/M +Chester/M +Chesterfield/M +Chesterton/M +Chevalier/M +Cheviot/M +Chevrolet/M +Chevron/M +Chevy/M +Cheyenne/SM +Chi/M +Chianti/MS +Chiba/M +Chibcha/M +Chicago/M +Chicagoan/M +Chicana/M +Chicano/M +Chickasaw/MS +Chiclets/M +Chihuahua/MS +Chile/M +Chilean/MS +Chimborazo/M +Chimera/MS +Chimu/M +Chin/M +China/M +Chinatown/M +Chinese/M +Chinook/MS +Chipewyan/M +Chippendale/M +Chippewa/SM +Chiquita/M +Chirico/M +Chisholm/M +Chisinau/M +Chittagong/M +Chivas/M +Chloe/M +Choctaw/SM +Chomsky/M +Chongqing/M +Chopin/M +Chopra/M +Chou/M +Chretien/M +Chris/M +Christ/MS +Christa/M +Christchurch/M +Christendom/MS +Christensen/M +Christi/M +Christian/SM +Christianity/SM +Christianize +Christie/M +Christina/M +Christine/M +Christlike +Christmas/MS +Christmastide/MS +Christmastime/MS +Christoper/M +Christopher/M +Chronicles +Chrysler/M +Chrysostom/M +Chrystal/M +Chuck/M +Chukchi/M +Chumash/M +Chung/M +Church/M +Churchill/M +Churriguera/M +Chuvash/M +Ci/M +Cicero/M +Cid/M +Cimabue/M +Cincinnati/M +Cinderella/MS +Cindy/M +CinemaScope/M +Cinerama/M +Cipro/M +Circe/M +Cisco/M +Citibank/M +Citigroup/M +Citroen/M +Cl/MV +Claiborne/M +Clair/M +Claire/M +Clairol/M +Clancy/M +Clapeyron/M +Clapton/M +Clara/M +Clare/M +Clarence/M +Clarendon/M +Clarice/M +Clarissa/M +Clark/M +Clarke/M +Claude/M +Claudette/M +Claudia/M +Claudine/M +Claudio/M +Claudius/M +Claus/M +Clausewitz/M +Clausius/M +Clay/M +Clayton/M +Clearasil/M +Clem/XM +Clemenceau/M +Clemens/M +Clement/MS +Clementine/M +Clements/M +Clemons/M +Clemson/M +Cleo/M +Cleopatra/M +Cleveland/M +Cliburn/M +Cliff/M +Clifford/M +Clifton/M +Cline/M +Clint/M +Clinton/M +Clio/M +Clive/M +Clorets/M +Clorox/M +Closure/M +Clotho/M +Clouseau/M +Clovis/M +Clyde/M +Clydesdale/M +Clytemnestra/M +Cm/M +Cmdr +Co/M +Cobain/M +Cobb/M +Cochabamba/M +Cochin/M +Cochise/M +Cochran/M +Cockney/M +Cocteau/M +Cod +Cody/M +Coffey/M +Cognac/M +Cohan/M +Cohen/M +Coimbatore/M +Cointreau/M +Coke/SM +Col/M +Colbert/M +Colby/M +Cole/M +Coleen/M +Coleman/M +Coleridge/M +Colette/M +Colfax/M +Colgate/M +Colin/M +Colleen/M +Collier/M +Collin/SM +Collins/M +Colo +Cologne/M +Colombia/M +Colombian/MS +Colombo/M +Colon/M +Coloradan/SM +Colorado/M +Coloradoan +Colosseum/M +Colt/M +Coltrane/M +Columbia/M +Columbine/M +Columbus/M +Com +Comanche/MS +Combs/M +Comdr +Comintern/M +Commandment +Commons/M +Commonwealth +Communion/SM +Communism +Communist/SM +Como/M +Comoran +Comoros/M +Compaq/M +Compton/M +CompuServe/M +Comte/M +Conakry/M +Conan/M +Concepcion/M +Concepción/M +Concetta/M +Concord/SM +Concorde/M +Condillac/M +Condorcet/M +Conestoga/M +Confederacy/M +Confederate/MS +Confucian/SM +Confucianism/MS +Confucius/M +Cong/M +Congo/M +Congolese/M +Congregational +Congregationalist/MS +Congress/MS +Congressional +Congreve/M +Conley/M +Conn/MR +Connecticut/M +Connemara/M +Conner/M +Connery/M +Connie/M +Connolly/M +Connors/M +Conrad/M +Conrail/M +Conservative +Constable/M +Constance/M +Constantine/M +Constantinople/M +Constitution +Consuelo/M +Continent/M +Continental/M +Contreras/M +Conway/M +Cook/M +Cooke/M +Cooley/M +Coolidge/M +Cooper/M +Cooperstown/M +Coors/M +Copacabana/M +Copeland/M +Copenhagen/M +Copernican/M +Copernicus/M +Copland/M +Copley/M +Copperfield/M +Coppertone/M +Coppola/M +Coptic/M +Cora/M +Cordelia/M +Cordilleras/M +Cordoba/M +Corey/M +Corfu/M +Corina/M +Corine/M +Corinne/M +Corinth/M +Corinthian/MS +Corinthians/M +Coriolanus/M +Coriolis/M +Cork +Corleone/M +Cormack/M +Corneille/M +Cornelia/M +Cornelius/M +Cornell/M +Corning/M +Cornish/MS +Cornwall/M +Cornwallis/M +Coronado/M +Corot/M +Corp +Correggio/M +Corrine/M +Corsica/M +Corsican/M +Cortes/MS +Cortland/M +Corvallis/M +Corvette/M +Corvus/M +Cory/M +Cosby/M +Cossack/M +Costco/M +Costello/M +Costner/M +Cote/M +Cotonou/M +Cotopaxi/M +Cotswold/M +Cotton/M +Coulomb/M +Coulter/M +Couperin/M +Courbet/M +Courtney/M +Cousteau/M +Coventry/SM +Coward/M +Cowell/M +Cowley/M +Cowper/M +Cox/M +Coy/M +Cozumel/M +Cpl +Cr/MT +Crabbe/M +Craft/M +Craig/M +Cranach/M +Crane/M +Cranmer/M +Crater/M +Crawford/M +Cray/M +Crayola/M +Creation/M +Creator/M +Crecy/M +Cree/DSM +Creek/SM +Creighton/M +Creole/SM +Creon/M +Cressida/M +Crest/M +Cretaceous/M +Cretan/SM +Crete/M +Crichton/M +Crick/M +Crimea/M +Crimean/M +Criollo/M +Crisco/M +Cristina/M +Croat/SM +Croatia/M +Croatian/MS +Croce/M +Crockett/M +Croesus/M +Cromwell/M +Cromwellian/M +Cronin/M +Cronkite/M +Cronus/M +Crookes/M +Crosby/M +Cross/M +Crow/SM +Crowley/M +Crucifixion/MS +Cruikshank/M +Cruise/M +Crusades's +Crusoe/M +Crux/M +Cruz/M +Cryptozoic/M +Crystal/M +Csonka/M +Ct +Ctesiphon/M +Cthulhu/M +Cu/M +Cuba/M +Cuban/SM +Cuchulain/M +Cuisinart/M +Culbertson/M +Cullen/M +Cumberland/M +Cummings/M +Cunard/M +Cunningham/M +Cupid/M +Curacao/M +Curie/M +Curitiba/M +Currier/M +Curry/RM +Curt/M +Curtis/M +Custer/M +Cuvier/M +Cuzco/M +Cybele/M +Cyclades/M +Cyclopes/M +Cyclops/M +Cygnus/M +Cymbeline/M +Cynthia/M +Cyprian/M +Cypriot/MS +Cyprus/M +Cyrano/M +Cyril/M +Cyrillic/M +Cyrus/M +Czech/M +Czechia/M +Czechoslovak +Czechoslovakia/M +Czechoslovakian/SM +Czechs +Czerny/M +D/M +DA/M +DAR +DAT/M +DBMS/M +DC/M +DD/M +DDS/M +DDT/S +DE +DEA +DEC/SD +DH +DHS +DI +DJ +DMCA +DMD/M +DMZ +DNA/M +DOA +DOB +DOD +DOE +DOS/M +DOT +DP/SM +DPT +DST +DTP +DUI +DVD +DVR/SM +DWI +Dachau/M +Dacron/SM +Dada/M +Dadaism/M +Daedalus/M +Daguerre/M +Dagwood/M +Dahomey/M +Daimler/M +Daisy/M +Dakar/M +Dakota/SM +Dakotan/M +Dalai +Dale/M +Daley/M +Dali/M +Dalian/M +Dallas/M +Dalmatia/M +Dalmatian/SM +Dalton/M +Damascus/M +Dame/MN +Damian/M +Damien/M +Damion/M +Damocles/M +Damon/M +Dan/M +Dana/M +Danae/M +Danaë/M +Dane/SM +Danelaw/M +Dangerfield/M +Danial/M +Daniel/SM +Danielle/M +Daniels/M +Danish/M +Dannie/M +Danny/M +Danone/M +Dante/M +Danton/M +Danube/M +Danubian/M +Daphne/M +Darby/M +Darcy/M +Dardanelles/M +Dare/M +Daren/M +Darfur/M +Darin/M +Dario/M +Darius/M +Darjeeling/M +Darla/M +Darlene/M +Darling/M +Darnell/M +Darrel/M +Darrell/M +Darren/M +Darrin/M +Darrow/M +Darryl/M +Darth/M +Dartmoor/M +Dartmouth/M +Darvon/M +Darwin/M +Darwinian/M +Darwinism/SM +Darwinist +Daryl/M +Datamation +Daugherty/M +Daumier/M +Davao/M +Dave/M +Davenport/M +David/MS +Davidson/M +Davies/M +Davis/M +Davy/SM +Dawes/M +Dawkins +Dawn/M +Dawson/M +Day/M +Dayan +Dayton/M +DeGeneres/M +Deadhead/M +Dean/M +Deana/M +Deandre/M +Deann/M +Deanna/M +Deanne/M +Death/M +Debbie/M +Debby/M +Debian/M +Debora/M +Deborah/M +Debouillet/M +Debra/M +Debs/M +Debussy/M +Dec/M +Decalogue/M +Decatur/M +Decca/M +Deccan/M +December/SM +Decker/M +Dedekind/M +Dee/M +Deena/M +Deere/M +Defoe/M +Degas/M +Deidre/M +Deimos/M +Deirdre/M +Deity +Dejesus/M +Del/M +Delacroix/M +Delacruz/M +Delaney/M +Delano/M +Delaware/MS +Delawarean/SM +Delbert/M +Deleon/M +Delgado/M +Delhi/M +Delia/M +Delibes/M +Delicious/M +Delilah/M +Delilahs +Delius/M +Dell/M +Della/M +Delmar/M +Delmarva/M +Delmer/M +Delmonico/M +Delores/M +Deloris/M +Delphi/M +Delphic/M +Delphinus/M +Delta/M +Dem/G +Demavend/M +Demerol/M +Demeter/M +Demetrius/M +Deming/M +Democrat/SM +Democratic +Democritus/M +Demosthenes/M +Dempsey/M +Dena/M +Denali +Deneb/M +Denebola/M +Deng/M +Denis/M +Denise/M +Denmark/M +Dennis/M +Denny/M +Denver/M +Deon/M +Depp/M +Derby/M +Derek/M +Derick/M +Dermot/M +Derrick/M +Derrida/M +Descartes/M +Desdemona/M +Desiree/M +Desmond/M +Detroit/M +Deuteronomy/M +Deutschmark/SM +Devanagari/M +Devi/M +Devil/M +Devin/M +Devon/M +Devonian/M +Dewar/M +Dewayne/M +Dewey/M +Dewitt/M +Dexedrine/M +Dexter/M +Dhaka/M +Dhaulagiri/M +Di/SM +DiCaprio/M +DiMaggio/M +Diaghilev/M +Dial/M +Diana/M +Diane/M +Diann/M +Dianna/M +Dianne/M +Dias +Diaspora/MS +Dick/XM +Dickens/M +Dickensian +Dickerson/M +Dickinson/M +Dickson/M +Dictaphone/SM +Diderot/M +Dido/M +Didrikson/M +Diefenbaker/M +Diego/M +Diem/M +Dietrich/M +Dijkstra/M +Dijon/M +Dilbert/MS +Dillard/M +Dillinger/M +Dillon/M +Dina/M +Dinah/M +Dino/M +Diocletian/M +Diogenes/M +Dion/M +Dionne/M +Dionysian/M +Dionysus/M +Diophantine/M +Dior/M +Dipper/M +Dir +Dirac/M +Dirichlet/M +Dirk/M +Dis/M +Disney/M +Disneyland/M +Disraeli/M +Divine/M +Diwali/M +Dix/M +Dixie/M +Dixiecrat/M +Dixieland/SM +Dixon/M +Djibouti/M +Dmitri/M +Dnepr +Dnepropetrovsk/M +Dnieper/M +Dniester/M +Dobbin/M +Doberman/M +Dobro/M +Doctor +Doctorow/M +Dodge/M +Dodgson/M +Dodoma/M +Dodson/M +Doe/M +Doha/M +Dolby/M +Dole/M +Dollie/M +Dolly/M +Dolores/M +Domesday/M +Domingo/M +Dominguez/M +Dominic/M +Dominica/M +Dominican/MS +Dominick/M +Dominion +Dominique/M +Domitian/M +Don/SM +Dona/M +Donahue/M +Donald/M +Donaldson/M +Donatello/M +Donetsk/M +Donizetti/M +Donn/MR +Donna/M +Donne/M +Donnell/M +Donner/M +Donnie/M +Donny/M +Donovan/M +Dooley/M +Doolittle/M +Doonesbury/M +Doppler/M +Dora/M +Dorcas/M +Doreen/M +Dorian/M +Doric/M +Doris/M +Doritos/M +Dorothea/M +Dorothy/M +Dorset/M +Dorsey/M +Dorthy/M +Dortmund/M +Dostoevsky/M +Dot/M +Dotson/M +Douala/M +Douay/M +Doubleday/M +Doug/M +Douglas/M +Douglass/M +Douro/M +Dover/M +Dow/M +Downs/M +Downy/M +Doyle/M +Dr +Draco/M +Draconian/M +Dracula/M +Drake/M +Dramamine/SM +Drambuie/M +Drano/M +Dravidian/M +Dreiser/M +Dresden/M +Drew/M +Dreyfus/M +Dristan/M +Dropbox/M +Drudge/M +Druid/M +Dryden/M +Dschubba/M +Du +DuPont/M +Duane/M +Dubai/M +Dubcek/M +Dubhe/M +Dublin/M +Dubrovnik/M +Duchamp/M +Dudley/M +Duffy/M +Duisburg/M +Duke/M +Dulles/M +Duluth/M +Dumas/M +Dumbledore/M +Dumbo/M +Dumpster/M +Dunant/M +Dunbar/M +Duncan/M +Dundee +Dunedin/M +Dunkirk/M +Dunlap/M +Dunn/M +Dunne/M +Duracell/M +Duran/M +Durant/M +Durante/M +Durban/M +Durer/M +Durex/M +Durham/MS +Durkheim/M +Duroc/M +Durocher/M +Duse/M +Dushanbe/M +Dusseldorf/M +Dustbuster/M +Dustin/M +Dusty/M +Dutch/M +Dutchman/M +Dutchmen/M +Dutchwoman +Duvalier/M +Dvina/M +Dvorak/M +Dvorák/M +Dwayne/M +Dwight/M +Dy/M +Dyer/M +Dylan/M +Dyson/M +Dzerzhinsky/M +Dzungaria/M +Dürer/M +Düsseldorf/M +E/SM +EC +ECG/M +ECMAScript/M +EDP/M +EDT +EEC/M +EEG/M +EEO +EEOC +EFL +EFT +EKG/M +ELF/M +EM +EMT +ENE/M +EOE +EPA/M +ER +ERA +ESE/M +ESL +ESP/M +ESPN/M +ESR +EST/M +ET +ETA +ETD +EU +EULA/S +Eakins/M +Earhart/M +Earl/M +Earle/M +Earlene/M +Earline/M +Earnest/M +Earnestine/M +Earnhardt/M +Earp/M +East/SZMR +Easter/M +Eastern/R +Eastman/M +Eastwood/M +Eaton/M +Eben/M +Ebeneezer/M +Ebert/M +Ebola/M +Ebonics/M +Ebony/M +Ebro/M +Ecclesiastes/M +Eco/M +Ecstasy +Ecuador/M +Ecuadoran/SM +Ecuadorean +Ecuadorian/SM +Ed/MNX +Edam/SM +Edda/M +Eddie/M +Eddington/M +Eddy/M +Eden/M +Edgar/M +Edgardo/M +Edinburgh/M +Edison/M +Edith/M +Edmond/M +Edmonton/M +Edmund/M +Edna/M +Edsel/M +Eduardo/M +Edward/SM +Edwardian/M +Edwardo/M +Edwards/M +Edwin/M +Edwina/M +Eeyore/M +Effie/M +Efrain/M +Efren/M +Eggo/M +Egypt/M +Egyptian/MS +Egyptology/M +Ehrenberg/M +Ehrlich/M +Eichmann/M +Eiffel/M +Eileen/M +Einstein/MS +Eire/M +Eisenhower/M +Eisenstein/M +Eisner/M +Elaine/M +Elam/M +Elanor/M +Elastoplast/M +Elba/M +Elbe/M +Elbert/M +Elbrus/M +Eldon/M +Eleanor/M +Eleazar/M +Electra/M +Elena/M +Elgar/M +Eli/M +Elias/M +Elijah/M +Elinor/M +Eliot/M +Elisa/M +Elisabeth/M +Elise/M +Eliseo/M +Elisha/M +Eliza/M +Elizabeth/M +Elizabethan/SM +Ella/M +Ellen/M +Ellesmere/M +Ellie/M +Ellington/M +Elliot/M +Elliott/M +Ellis/M +Ellison/M +Elma/M +Elmer/M +Elmo/M +Elnath/M +Elnora/M +Elohim/M +Eloise/M +Eloy/M +Elroy/M +Elsa/M +Elsie/M +Elsinore/M +Eltanin/M +Elton/M +Elul/M +Elva/M +Elvia/M +Elvin/M +Elvira/M +Elvis/M +Elway/M +Elwood/M +Elysee/M +Elysian/M +Elysium/SM +Elysée/M +Emacs/M +Emanuel/M +Emerson/M +Emery/M +Emil/M +Emile/M +Emilia/M +Emilio/M +Emily/M +Eminem/M +Eminence +Emma/M +Emmanuel/M +Emmett/M +Emmy/M +Emory/M +Encarta/M +Endymion/M +Eng/M +Engels/M +England/M +English/MRS +Englishman/M +Englishmen/M +Englishwoman/M +Englishwomen/M +Enid/M +Enif/M +Eniwetok/M +Enkidu/M +Enoch/M +Enos/M +Enrico/M +Enrique/M +Enron/M +Enterprise/M +Eocene/M +Epcot/M +Ephesian/MS +Ephesus/M +Ephraim/M +Epictetus/M +Epicurean/M +Epicurus/M +Epimethius/M +Epiphany/SM +Episcopal +Episcopalian/MS +Epistle +Epsom/M +Epson/M +Epstein/M +Equuleus/M +Er/M +Erasmus/M +Erato/M +Eratosthenes/M +Erebus/M +Erector/M +Erewhon/M +Erhard/M +Eric/M +Erica/M +Erich/M +Erick/M +Ericka/M +Erickson/M +Ericson/M +Ericsson/M +Eridanus/M +Erie/M +Erik/M +Erika/M +Erin/M +Eris/MS +Eritrea/M +Eritrean/SM +Erlenmeyer/M +Erma/M +Erna/M +Ernest/M +Ernestine/M +Ernesto/M +Ernie/M +Ernst/M +Eros/MS +Errol/M +Erse/M +ErvIn/M +Erwin/M +Esau/M +Escher/M +Escherichia/M +Escondido +Eskimo/MS +Esmeralda/M +Esperanto/M +Esperanza/M +Espinoza/M +Esq/M +Esquire/MS +Essen/M +Essene/M +Essequibo/M +Essex/M +Essie/M +Establishment +Esteban/M +Estela/M +Estella/M +Estelle/M +Ester/M +Esterhazy/M +Esterházy/M +Estes/M +Esther/M +Estonia/M +Estonian/SM +Estrada/M +Ethan/M +Ethel/M +Ethelred/M +Ethernet/M +Ethiopia/M +Ethiopian/SM +Etna/M +Eton/M +Etruria/M +Etruscan/M +Etta/M +Eu/M +Eucharist/MS +Eucharistic +Euclid/M +Euclidean/M +Eugene/M +Eugenia/M +Eugenie/M +Eugenio/M +Eula/M +Euler/M +Eumenides/M +Eunice/M +Euphrates/M +Eur +Eurasia/M +Eurasian/MS +Euripides/M +Eurodollar/SM +Europa/M +Europe/M +European/MS +Eurydice/M +Eustachian/M +Euterpe/M +Eva/M +Evan/SM +Evangelical +Evangelina/M +Evangeline/M +Evangelist/M +Evans/M +Evansville/M +Eve/M +Evelyn/M +Evenki/M +EverReady/M +Everest/M +Everett/M +Everette/M +Everglades/M +Evert/M +Evian/M +Evita/M +Ewing/M +Excalibur/M +Excedrin/M +Excellency/SM +Exchequer +Exercycle/M +Exocet/M +Exodus/M +Exxon/M +Eyck/M +Eyre/M +Eysenck/M +Ezekiel/M +Ezra/M +F/MD +FAA +FAQ/SM +FBI/M +FCC +FD +FDA +FDIC/M +FDR/M +FHA/M +FICA/M +FIFO +FL +FM/SM +FNMA/M +FOFL +FORTRAN/M +FPO +FSF/M +FSLIC +FTC +FUD/S +FWD +FWIW +FY +FYI +Faberge/M +Fabergé/M +Fabian/MS +Facebook/M +Faeroe/M +Fafnir/M +Fagin/M +Fahd/M +Fahrenheit/M +Fairbanks/M +Faisal/M +Faisalabad/M +Faith/M +Falasha/M +Falkland/SM +Falklands/M +Fallopian/M +Falstaff/M +Falwell/M +Fannie/M +Fanny/M +Faraday/M +Fargo/M +Farley/M +Farmer/M +Farragut/M +Farrakhan/M +Farrell/M +Farrow/M +Farsi/M +Fascist +Fassbinder/M +Fatah/M +Fates/M +Father/SM +Fatima/M +Fatimid/M +Faulkner/M +Faulknerian/M +Fauntleroy/M +Faust/M +Faustian/M +Faustino/M +Faustus/M +Fawkes/M +Fay/M +Faye/M +Fe/M +Feb/M +February/SM +Fed/SM +FedEx/M +Federal/MS +Federalist/M +Federico/M +Feds/M +Felecia/M +Felice/M +Felicia/M +Felicity/M +Felipe/M +Felix/M +Fellini/M +Fenian/M +Ferber/M +Ferdinand/M +Fergus/M +Ferguson/M +Ferlinghetti/M +Fermat/M +Fermi/M +Fern/M +Fernandez/M +Fernando/M +Ferrari/M +Ferraro/M +Ferrell/M +Ferris/M +Feynman/M +Fez/M +Fiat/M +Fiberglas/M +Fibonacci/M +Fichte/M +Fidel/M +Fido/M +Fielding/M +Fields/M +Figaro/M +Figueroa/M +Fiji/M +Fijian/MS +Filipino/MS +Fillmore/M +Filofax/M +Finch/M +Finland/M +Finley/M +Finn/SM +Finnbogadottir/M +Finnegan/M +Finnish/M +Fiona/M +Firefox/M +Firestone/M +Fischer/M +Fisher/M +Fisk/M +Fitch/M +Fitzgerald/M +Fitzpatrick/M +Fitzroy/M +Fizeau/M +Fla +Flanagan/M +Flanders/M +Flathead +Flatt/M +Flaubert/M +Fleischer/M +Fleming/M +Flemish/M +Fletcher/M +Flint/M +Flintstones/M +Flo/M +Flora/M +Florence/M +Florentine/M +Flores/M +Florida/M +Floridan/M +Floridian/SM +Florine/M +Florsheim/M +Flory/M +Flossie/M +Flowers/M +Floyd/M +Flynn/M +Fm/M +Foch/M +Fokker/M +Foley/M +Folgers/M +Folsom/M +Fomalhaut/M +Fonda/M +Foosball/M +Forbes/M +Ford/M +Foreman/M +Forest/MR +Forester/M +Formica/MS +Formosa/M +Formosan/M +Forrest/M +Forster/M +Fortaleza/M +Fosse/M +Foster/M +Fotomat/M +Foucault/M +Fourier/M +Fourneyron/M +Fourth +Fowler/M +Fox/MS +Fr/MD +Fragonard/M +Fran/M +France/SM +Frances/M +Francesca/M +Francine/M +Francis/M +Francisca/M +Franciscan/MS +Francisco/M +Franck/M +Franco/M +Francois/M +Francoise/M +Francophile +Franglais/M +Frank/SM +Frankel/M +Frankenstein/M +Frankfort/M +Frankfurt/MR +Frankfurter/M +Frankie/M +Frankish +Franklin/M +Franks/M +Franny/M +Franz/M +Fraser/M +Frau/MN +Fraulein +Frazier/M +Fred/M +Freda/M +Freddie/M +Freddy/M +Frederic/M +Frederick/M +Fredericton/M +Fredric/M +Fredrick/M +Freeman/M +Freemason/SM +Freemasonry/SM +Freetown/M +Freida/M +Fremont/M +French/MS +Frenchman/M +Frenchmen/M +Frenchwoman/M +Frenchwomen/M +Freon/M +Fresnel/M +Fresno/M +Freud/M +Freudian/M +Frey/M +Freya/M +Fri/M +Friday/SM +Frieda/M +Friedan/M +Friedman/M +Friend/SM +Frigga/M +Frigidaire/M +Frisbee/M +Frisco/M +Frisian/MS +Frito/M +Fritz/M +Frobisher/M +Frodo/M +Froissart/M +Fromm/M +Fronde/M +Frontenac/M +Frost/M +Frostbelt/M +Frunze/M +Fry/M +Frye/M +Fuchs/M +Fuentes/M +Fugger/M +Fuji/M +Fujitsu/M +Fujiwara/M +Fujiyama/M +Fukuoka/M +Fukuyama/M +Fulani/M +Fulbright/M +Fuller/M +Fullerton/M +Fulton/M +Funafuti/M +Fundy/M +Furies/M +Furtwangler/M +Furtwängler/M +Fushun/M +Fuzhou/M +Fuzzbuster/M +G/MNRB +GA +GAO +GATT/M +GB/M +GCC/M +GDP/M +GE/M +GED +GHQ/M +GHz +GI +GIF +GIGO +GM/M +GMAT +GMO +GMT/M +GNP/M +GNU/M +GOP/M +GP/M +GPA +GPO +GPS +GPU +GSA +GTE/M +GU +GUI/M +Ga/M +Gable/M +Gabon/M +Gabonese/M +Gaborone/M +Gabriel/M +Gabriela/M +Gabrielle/M +Gacrux/M +Gadsden/M +Gaea/M +Gael/SM +Gaelic/M +Gagarin/M +Gage/M +Gaia/M +Gail/M +Gaiman/M +Gaines/M +Gainsborough/M +Galahad/SM +Galapagos/M +Galatea/M +Galatia/M +Galatians/M +Galaxy +Galbraith/M +Gale/M +Galen/M +Galibi/M +Galilean/SM +Galilee/M +Galileo/M +Gall/M +Gallagher/M +Gallegos/M +Gallic/M +Gallicism/SM +Gallo/M +Galloway/M +Gallup/M +Galois/M +Galsworthy/M +Galvani/M +Galveston/M +Gama +Gamay/M +Gambia/M +Gambian/SM +Gamble/M +Gamow/M +Gandalf/M +Gandhi/M +Gandhian/M +Ganesha/M +Ganges/M +Gangtok/M +Gantry/M +Ganymede/M +Gap/M +Garbo/M +Garcia/M +Gardner/M +Gareth/M +Garfield/M +Garfunkel/M +Gargantua/M +Garibaldi/M +Garland/M +Garner/M +Garrett/M +Garrick/M +Garrison/M +Garry/M +Garth/M +Garvey/M +Gary/M +Garza/M +Gascony/M +Gasser/M +Gastroenterology +Gates/M +Gatling/M +Gatorade/M +Gatsby/M +Gatun/M +Gauguin/M +Gaul/SM +Gaulish +Gauss/M +Gaussian/M +Gautama/M +Gautier/M +Gavin/M +Gawain/M +Gay/M +Gayle/M +Gaza/M +Gaziantep/M +Gd/M +Gdansk/M +Ge/M +Geffen/M +Gehenna/M +Gehrig/M +Geiger/M +Gelbvieh/M +Geller/M +Gemini/MS +Gen/M +Gena/M +Genaro/M +Gene/M +Genesis/M +Genet/M +Geneva/M +Genevieve/M +Genghis/M +Genoa/SM +Gentoo/M +Gentry/M +Geo/M +Geoffrey/M +George/MS +Georgetown/M +Georgette/M +Georgia/M +Georgian/MS +Georgina/M +Ger/M +Gerald/M +Geraldine/M +Gerard/M +Gerardo/M +Gerber/M +Gere/M +Geritol/M +German/MS +Germanic/M +Germany/M +Geronimo/M +Gerry/M +Gershwin/M +Gertrude/M +Gestapo/SM +Gethsemane/M +Getty/M +Gettysburg/M +Gewurztraminer/M +Gewürztraminer/M +Ghana/M +Ghanaian +Ghats/M +Ghazvanid/M +Ghent/M +Ghibelline/M +Giacometti/M +Giannini/M +Giauque/M +Gibbon/M +Gibbs/M +Gibraltar/MS +Gibson/M +Gide/M +Gideon/M +Gielgud/M +Gienah/M +Gil/M +Gila/M +Gilbert/M +Gilberto/M +Gilchrist/M +Gilda/M +Gilead/M +Giles/M +Gilgamesh/M +Gill/M +Gillespie/M +Gillette/M +Gilliam/M +Gillian/M +Gilligan/M +Gilman +Gilmore/M +Gina/M +Ginger/M +Gingrich/M +Ginny/M +Gino/M +Ginsberg/M +Ginsburg/M +Ginsu/M +Giorgione/M +Giotto/M +Giovanni/M +Giraudoux/M +Giselle/M +Gish/M +GitHub/M +Giuliani/M +Giuseppe/M +Giza/M +Gk +Gladstone/MS +Gladys/M +Glaser/M +Glasgow/M +Glass/M +Glastonbury/M +Glaswegian/SM +Glaxo/M +Gleason/M +Glen/M +Glenda/M +Glendale +Glenlivet/M +Glenn/M +Glenna/M +Gloria/M +Gloucester/M +Glover/M +Gnostic/M +Gnosticism/M +GnuPG +Goa/M +Gobi/M +God/M +Godard/M +Goddard/M +Godel/M +Godhead/M +Godiva/M +Godot/M +Godspeed/SM +Godthaab/M +Godunov/M +Godzilla/M +Goebbels/M +Goering/M +Goethals/M +Goethe/M +Goff/M +Gog/M +Gogol/M +Goiania/M +Golan/M +Golconda/M +Golda/M +Goldberg/M +Golden/M +Goldie/M +Goldilocks/M +Golding/M +Goldman/M +Goldsmith/M +Goldwater/M +Goldwyn/M +Golgi/M +Golgotha/M +Goliath/M +Gomez/M +Gomorrah/M +Gompers/M +Gomulka/M +Gondwanaland/M +Gonzales/M +Gonzalez/M +Gonzalo/M +Good/M +Goodall/M +Goodman/M +Goodrich/M +Goodwill/M +Goodwin/M +Goodyear/M +Google/M +Goolagong/M +Gopher +Gorbachev/M +Gordian/M +Gordimer/M +Gordon/M +Gore/M +Goren/M +Gorey/M +Gorgas/M +Gorgon/M +Gorgonzola/M +Gorky/M +Gospel/MS +Goteborg/M +Goth/M +Gotham/M +Gothic/MS +Goths +Gouda/SM +Gould/M +Gounod/M +Governor +Goya/M +Gr/B +Grable/M +Gracchus/M +Grace/M +Graceland/M +Gracie/M +Graciela/M +Grady/M +Graffias/M +Grafton/M +Graham/M +Grahame/M +Grail/M +Grammy/M +Grampians/M +Granada/M +Grant/M +Grass/M +Graves/M +Gray/M +Grecian/M +Greece/M +Greek/SM +Greeley/M +Green/SM +Greene/M +Greenland/M +Greenlandic +Greenpeace/M +Greensboro/M +Greensleeves/M +Greenspan/M +Greenwich/M +Greer/M +Greg/M +Gregg/M +Gregorian/M +Gregorio/M +Gregory/M +Grenada/M +Grenadian/MS +Grenadines/M +Grendel/M +Grenoble/M +Gresham/M +Greta/M +Gretchen/M +Gretel/M +Gretzky/M +Grey/M +Grieg/M +Griffin/M +Griffith/M +Grimes/M +Grimm/M +Grinch/M +Gris/M +Gromyko/M +Gropius/M +Gross/M +Grosz/M +Grotius/M +Grover/M +Grozny +Grumman/M +Grundy/M +Grunewald/M +Grus/M +Gruyere/SM +Gruyère/M +Grünewald/M +Guadalajara/M +Guadalcanal/M +Guadalquivir/M +Guadalupe/M +Guadeloupe/M +Guallatiri/M +Guam/M +Guamanian +Guangzhou/M +Guantanamo/M +Guarani/M +Guarnieri/M +Guatemala/M +Guatemalan/MS +Guayaquil/M +Gucci/M +Guelph/M +Guernsey/MS +Guerra/M +Guerrero/M +Guevara/M +Guggenheim/M +Guiana/M +Guido +Guillermo/M +Guinea/M +Guinean/MS +Guinevere/M +Guinness/M +Guiyang/M +Guizot/M +Gujarat/M +Gujarati/M +Gujranwala/M +Gullah/M +Gulliver/M +Gumbel/M +Gunther/M +Guofeng/M +Gupta/M +Gurkha/M +Gus/M +Gustav/M +Gustavo/M +Gustavus/M +Gutenberg/M +Guthrie/M +Gutierrez/M +Guy/M +Guyana/M +Guyanese/M +Guzman/M +Gwalior/M +Gwen/M +Gwendoline/M +Gwendolyn/M +Gwyn/M +Gypsy/SM +Gödel/M +Göteborg/M +H/M +HBO/M +HDD +HDMI +HDTV +HF/M +HHS +HI +HIV/M +HM +HMO/M +HMS +HOV +HP/M +HPV +HQ/M +HR +HRH +HS +HSBC/M +HST +HT +HTML/M +HTTP +HUD/M +Ha/M +Haas/M +Habakkuk/M +Haber/M +Hadar/M +Hades/M +Hadrian/M +Hafiz/M +Hagar/M +Haggai/M +Hagiographa/M +Hague/M +Hahn/M +Haida/SM +Haifa/M +Haiphong/M +Haiti/M +Haitian/MS +Hakka/M +Hakluyt/M +Hal/SM +Haldane/M +Hale/M +Haleakala/M +Haley/M +Halifax/M +Hall/M +Halley/M +Halliburton/M +Hallie/M +Hallmark/M +Halloween/MS +Hallstatt/M +Halon/M +Hals/M +Halsey/M +Ham/M +Haman/M +Hamburg/MS +Hamhung/M +Hamilcar/M +Hamill/M +Hamilton/M +Hamiltonian/M +Hamitic/M +Hamlet/M +Hamlin/M +Hammarskjold/M +Hammerstein/M +Hammett/M +Hammond/M +Hammurabi/M +Hampshire/M +Hampton/M +Hamsun/M +Han/SM +Hancock/M +Handel/M +Handy/M +Haney/M +Hangul/M +Hangzhou/M +Hank/M +Hanna/M +Hannah/M +Hannibal/M +Hanoi/M +Hanover/M +Hanoverian/M +Hans/MN +Hansel/M +Hansen/M +Hanson/M +Hanuka +Hanukah/M +Hanukkah/M +Hanukkahs +Hapsburg/M +Harare/M +Harbin/M +Hardin/M +Harding/M +Hardy/M +Hargreaves/M +Harlan/M +Harlem/M +Harlequin/M +Harley/M +Harlow/M +Harmon/M +Harold/M +Harper/M +Harpy/SM +Harrell/M +Harriet/M +Harriett/M +Harrington/M +Harris/M +Harrisburg/M +Harrison/M +Harrods/M +Harry/M +Hart/M +Harte/M +Hartford/M +Hartline/M +Hartman/M +Harvard/M +Harvey/M +Hasbro/M +Hasidim/M +Haskell/M +Hastings/M +Hatfield/M +Hathaway/M +Hatsheput/M +Hatteras/M +Hattie/M +Hauptmann/M +Hausa/M +Hausdorff/M +Havana/MS +Havarti/M +Havel/M +Havoline/M +Haw +Hawaii/M +Hawaiian/SM +Hawking/M +Hawkins/M +Hawks +Hawthorne/M +Hay/SM +Hayden/M +Haydn/M +Hayek/M +Hayes/M +Haynes/M +Hays/M +Hayward/M +Haywood/M +Hayworth/M +Hazel/M +Hazlitt/M +He/M +Head/M +Hearst/M +Heath/MR +Heather/M +Heaviside/M +Heb +Hebe/M +Hebert/M +Hebraic/M +Hebraism/SM +Hebrew/MS +Hebrews/M +Hebrides/M +Hecate/M +Hector/M +Hecuba/M +Heep/M +Hefner/M +Hegel/M +Hegelian/M +Hegira/M +Heidegger/M +Heidelberg/M +Heidi/M +Heifetz/M +Heimlich/M +Heine/M +Heineken/M +Heinlein/M +Heinrich/M +Heinz/M +Heisenberg/M +Heisman/M +Helen/M +Helena/M +Helene/M +Helga/M +Helicon/M +Heliopolis/M +Helios/M +Hellene/SM +Hellenic/M +Hellenism/MS +Hellenist +Hellenistic/M +Hellenization/M +Hellenize/M +Heller/M +Hellespont/M +Hellman/M +Helmholtz/M +Heloise/M +Helsinki/M +Helvetian +Helvetius/M +Hemingway/M +Hench/M +Henderson/M +Hendrick/MS +Hendricks/M +Hendrix/M +Henley/M +Hennessy/M +Henri/M +Henrietta/M +Henrik/M +Henry/M +Hensley/M +Henson/M +Hepburn/M +Hephaestus/M +Hepplewhite/M +Hera/M +Heracles/M +Heraclitus/M +Herakles/M +Herbart/M +Herbert/M +Herculaneum/M +Herculean +Hercules/M +Herder/M +Hereford/SM +Herero/M +Heriberto/M +Herman/M +Hermaphroditus/M +Hermes/M +Herminia/M +Hermitage/M +Hermite/M +Hermosillo/M +Hernandez/M +Herod/M +Herodotus/M +Herr/MG +Herrera/M +Herrick/M +Herring/M +Herschel/M +Hersey/M +Hershel/M +Hershey/M +Hertz/M +Hertzsprung/M +Herzegovina/M +Herzl/M +Heshvan/M +Hesiod/M +Hesperus/M +Hess/M +Hesse/M +Hessian/M +Hester/M +Heston/M +Hettie/M +Hewitt/M +Hewlett/M +Heyerdahl/M +Heywood/M +Hezbollah/M +Hezekiah/M +Hf/M +Hg/M +Hialeah/M +Hiawatha/M +Hibernia/M +Hibernian +Hickman/M +Hickok/M +Hicks/M +Hieronymus/M +Higashiosaka +Higgins/M +Highlander/SM +Highlands +Highness/M +Hilario/M +Hilary/M +Hilbert/M +Hilda/M +Hildebrand/M +Hilfiger/M +Hill/M +Hillary/M +Hillel/M +Hilton/M +Himalaya/SM +Himalayan +Himalayas/M +Himmler/M +Hinayana/M +Hindemith/M +Hindenburg/M +Hindi/M +Hindu/SM +Hinduism/SM +Hindustan/M +Hindustani/SM +Hines/M +Hinton/M +Hipparchus/M +Hippocrates/M +Hippocratic/M +Hiram/M +Hirobumi/M +Hirohito/M +Hiroshima/M +Hispanic/SM +Hispaniola/M +Hiss/M +Hitachi/M +Hitchcock/M +Hitler/MS +Hittite/SM +Hmong/M +Ho/M +Hobart/M +Hobbes/M +Hobbs/M +Hockney/M +Hodge/SM +Hodges/M +Hodgkin/M +Hoff/M +Hoffa/M +Hoffman/M +Hofstadter/M +Hogan/M +Hogarth/M +Hogwarts/M +Hohenlohe/M +Hohenstaufen/M +Hohenzollern/M +Hohhot/M +Hohokam/M +Hokkaido/M +Hokusai/M +Holbein/M +Holcomb/M +Holden/M +Holder/M +Holiday/M +Holiness +Holland/ZSMR +Hollander/M +Hollerith/M +Holley/M +Hollie/M +Hollis/M +Holloway/M +Holly/M +Hollywood/M +Holman/M +Holmes/M +Holocaust/M +Holocene/M +Holst/M +Holstein/SM +Holt/M +Homer/M +Homeric/M +Hon +Honda/M +Honduran/MS +Honduras/M +Honecker/M +Honeywell/M +Hong +Honiara/M +Honolulu/M +Honorable +Honshu/M +Hood/M +Hooke/RM +Hooker/M +Hooper/M +Hoosier/MS +Hooters/M +Hoover/MS +Hope/M +Hopewell/M +Hopi/SM +Hopkins/M +Hopper/M +Horace/M +Horacio/M +Horatio/M +Hormel/M +Hormuz/M +Horn/M +Hornblower/M +Horne/M +Horowitz/M +Horthy/M +Horton/M +Horus/M +Hosea/M +Host/SM +Hotpoint/M +Hottentot/SM +Houdini/M +House/M +Housman/M +Houston/M +Houyhnhnm/M +Hovhaness/M +Howard/M +Howe/M +Howell/MS +Howells/M +Howrah +Hoyle/M +Hrothgar/M +Hts +Huang/M +Hubbard/M +Hubble/M +Huber/M +Hubert/M +Huck/M +Huddersfield +Hudson/M +Huerta/M +Huey/M +Huff/M +Huffman/M +Huggins/M +Hugh/MS +Hughes/M +Hugo/M +Huguenot/MS +Hui/M +Huitzilopotchli/M +Hull/M +Humberto/M +Humboldt/M +Hume/M +Hummer/M +Humphrey/SM +Humvee/M +Hun/SM +Hung/M +Hungarian/SM +Hungary/M +Hunspell/M +Hunt/MR +Hunter/M +Huntington/M +Huntley/M +Huntsville/M +Hurley/M +Huron/M +Hurst/M +Hus/M +Hussein/M +Husserl/M +Hussite/M +Huston/M +Hutchinson/M +Hutton/M +Hutu/M +Huxley/M +Huygens/M +Hyades/M +Hyde/M +Hyderabad/M +Hydra/M +Hymen/M +Hyperion/M +Hyundai/M +Hz/M +Héloise/M +I'd +I'll +I'm +I've +I/M +IA +IBM/M +ICBM/SM +ICC +ICU +ID/SM +IDE +IE +IED +IEEE +IKEA/M +IL +IMF/M +IMHO +IMNSHO +IMO +IN +ING/M +INRI +INS +IOU/M +IP +IPA +IPO +IQ/M +IRA/SM +IRC +IRS/M +ISBN +ISIS +ISO/M +ISP +ISS +IT +IUD +IV/SM +IVF +Ia +Iaccoca/M +Iago/M +Ian/M +Iapetus/M +Ibadan/M +Iberia/M +Iberian/M +Ibiza/M +Iblis/M +Ibo/M +Ibsen/M +Icahn/M +Icarus/M +Ice +Iceland/MRZ +Icelander/M +Icelandic/M +Ida/M +Idaho/SM +Idahoan/MS +Idahoes +Ieyasu/M +Ignacio/M +Ignatius/M +Igor/M +Iguassu/M +Ijsselmeer/M +Ike/M +Ikhnaton/M +Ila/M +Ilene/M +Iliad/SM +Ill +Illinois/M +Illinoisan/MS +Illuminati/M +Ilyushin/M +Imam +Imelda/M +Imhotep/M +Imodium/M +Imogene/M +Imus/M +In/M +Ina/M +Inc +Inca/SM +Inchon/M +Incorporated +Ind +Independence/M +India/M +Indian/MS +Indiana/M +Indianan/SM +Indianapolis/M +Indianian +Indies/M +Indira/M +Indochina/M +Indochinese/M +Indonesia/M +Indonesian/SM +Indore/M +Indra/M +Indus/M +Indy/SM +Ines/M +Inez/M +Inge/M +Inglewood +Ingram/M +Ingres/M +Ingrid/M +Innocent/M +Innsbruck +Inonu/M +Inquisition/M +Inst +Instagram/M +Instamatic/M +Intel/M +Intelsat/M +Internationale/M +Internet/SM +Interpol/M +Inuit/MS +Inuktitut/M +Invar/M +Io/M +Ionesco/M +Ionian/MS +Ionic/SM +Iowa/SM +Iowan/MS +Iphigenia/M +Ipswich +Iqaluit/M +Iqbal/M +Iquitos/M +Ir/M +Ira/M +Iran/M +Iranian/SM +Iraq/M +Iraqi/MS +Ireland/M +Irene/M +Iris/M +Irish/MR +Irishman/M +Irishmen/M +Irishwoman/M +Irishwomen/M +Irkutsk/M +Irma/M +Iroquoian/SM +Iroquois/M +Irrawaddy/M +Irtish/M +Irvin/M +Irvine/M +Irving/M +Irwin/M +Isaac/M +Isabel/M +Isabella/M +Isabelle/M +Isaiah/M +Iscariot/M +Isfahan/M +Isherwood/M +Ishim/M +Ishmael/M +Ishtar/M +Isiah/M +Isidro/M +Isis/M +Islam/MS +Islamabad/M +Islamic/M +Islamism/M +Islamist/M +Islamophobia +Islamophobic +Ismael/M +Ismail/M +Isolde/M +Ispell/M +Israel/SM +Israeli/SM +Israelite/M +Issac/M +Issachar/M +Istanbul/M +Isuzu/M +It +Itaipu/M +Ital +Italian/SM +Italianate +Italy/M +Itasca/M +Ithaca/M +Ithacan/M +Ito/M +Iva/M +Ivan/M +Ivanhoe/M +Ives/M +Ivorian +Ivory/M +Ivy/M +Iyar/M +Izaak/M +Izanagi/M +Izanami/M +Izhevsk/M +Izmir/M +Izod/M +Izvestia/M +J/MD +JCS +JD +JFK/M +JP +JPEG +JV +Jack/M +Jackie/M +Jacklyn/M +Jackson/M +Jacksonian/M +Jacksonville/M +Jacky/M +Jaclyn/M +Jacob/SM +Jacobean/M +Jacobi/M +Jacobin/M +Jacobite/M +Jacobs/M +Jacobson/M +Jacquard/M +Jacqueline/M +Jacquelyn/M +Jacques/M +Jacuzzi/M +Jagger/M +Jagiellon/M +Jaguar/M +Jahangir/M +Jaime/M +Jain/M +Jainism/M +Jaipur/M +Jakarta/M +Jake/M +Jamaal/M +Jamaica/M +Jamaican/SM +Jamal/M +Jamar/M +Jame/SM +Jamel/M +James/M +Jamestown/M +Jami/M +Jamie/M +Jan/M +Jana/M +Janacek/M +Jane/M +Janell/M +Janelle/M +Janet/M +Janette/M +Janice/M +Janie/M +Janine/M +Janis/M +Janissary/M +Janjaweed/M +Janna/M +Jannie/M +Jansen/M +Jansenist/M +January/SM +Janus/M +Jap/SM +Japan/M +Japanese/MS +Japura/M +Jared/M +Jarlsberg/M +Jarred/M +Jarrett/M +Jarrod/M +Jarvis/M +Jasmine/M +Jason/M +Jasper/M +Jataka/M +Java/SM +JavaScript/M +Javanese/M +Javier/M +Jaxartes/M +Jay/M +Jayapura/M +Jayawardene/M +Jaycee/MS +Jaycees/M +Jayne/M +Jayson/M +Jean/M +Jeanette/M +Jeanie/M +Jeanine/M +Jeanne/M +Jeannette/M +Jeannie/M +Jeannine/M +Jed/M +Jedi/M +Jeep/M +Jeeves/M +Jeff/M +Jefferey/M +Jefferson/M +Jeffersonian/M +Jeffery/M +Jeffrey/M +Jeffry/M +Jehoshaphat/M +Jehovah/M +Jekyll/M +Jenifer/M +Jenkins/M +Jenna/M +Jenner/M +Jennie/M +Jennifer/M +Jennings/M +Jenny/M +Jensen/M +Jephthah/M +Jerald/M +Jeremiah/M +Jeremiahs +Jeremy/M +Jeri/M +Jericho/M +Jermaine/M +Jeroboam/M +Jerold/M +Jerome/M +Jerri/M +Jerrod/M +Jerrold/M +Jerry/M +Jersey/MS +Jerusalem/M +Jess/M +Jesse/M +Jessica/M +Jessie/M +Jesuit/MS +Jesus/M +Jetway/M +Jew/SM +Jewel/M +Jewell/M +Jewess/MS +Jewish/PM +Jewry/M +Jezebel/SM +Jidda/M +Jilin/M +Jill/M +Jillian/M +Jim/M +Jimenez/M +Jimmie/M +Jimmy/M +Jinan/M +Jinnah/M +Jinny/M +Jivaro/M +Jo/M +Joan/M +Joann/M +Joanna/M +Joanne/M +Joaquin/M +Job/SM +Jobs/M +Jocasta/M +Jocelyn/M +Jock/M +Jockey/M +Jodi/M +Jodie/M +Jody/M +Joe/M +Joel/M +Joey/M +Jogjakarta/M +Johann/M +Johanna/M +Johannes/M +Johannesburg/M +John/SM +Johnathan/M +Johnathon/M +Johnie/M +Johnnie/M +Johnny/M +Johns/M +Johnson/M +Johnston/M +Jolene/M +Joliet/M +Jolson/M +Jon/M +Jonah/M +Jonahs +Jonas/M +Jonathan/M +Jonathon/M +Jones/M +Joni/M +Jonson/M +Joplin/M +Jordan/M +Jordanian/MS +Jorge/M +Jose/M +Josef/M +Josefa/M +Josefina/M +Joseph/M +Josephine/M +Josephs +Josephson/M +Josephus/M +Josh/M +Joshua/M +Josiah/M +Josie/M +Josue/M +Joule/M +Jove/M +Jovian/M +Joy/M +Joyce/M +Joycean/M +Joyner/M +Jpn +Jr/M +Juan/M +Juana/M +Juanita/M +Juarez/M +Jubal/M +Judaeo +Judah/M +Judaic +Judaical +Judaism/MS +Judas/MS +Judd/M +Jude/M +Judea/M +Judges +Judith/M +Judson/M +Judy/M +Juggernaut/M +Jul +Jules/M +Julia/M +Julian/M +Juliana/M +Julianne/M +Julie/M +Juliet/M +Juliette/M +Julio/M +Julius/M +Julliard/M +July/SM +Jun/M +June/SM +Juneau/M +Jung/M +Jungfrau/M +Jungian/M +Junior/SM +Junker/SM +Juno/M +Jupiter/M +Jurassic/M +Jurua/M +Justice/M +Justin/M +Justine/M +Justinian/M +Jutland/M +Juvenal/M +K/SMNGJ +KB/M +KC +KFC/M +KGB/M +KIA +KKK/M +KO/M +KP +KS +KY +Kaaba/M +Kabul/M +Kafka/M +Kafkaesque/M +Kagoshima/M +Kahlua/M +Kaifeng/M +Kaiser/MS +Kaitlin/M +Kalahari/M +Kalamazoo/M +Kalashnikov/M +Kalb/M +Kalevala/M +Kalgoorlie/M +Kali/M +Kalmyk/M +Kama/M +Kamchatka/M +Kamehameha/M +Kampala/M +Kampuchea/M +Kan/SM +Kanchenjunga/M +Kandahar/M +Kandinsky/M +Kane/M +Kannada/M +Kano/M +Kanpur/M +Kansan/MS +Kansas/M +Kant/M +Kantian/M +Kaohsiung/M +Kaposi/M +Kara/M +Karachi/M +Karaganda/M +Karakorum/M +Karamazov/M +Kareem/M +Karen/M +Karenina/M +Kari/M +Karin/M +Karina/M +Karl/M +Karla/M +Karloff/M +Karo/M +Karol/M +Karroo/M +Karyn/M +Kasai/M +Kasey/M +Kashmir/SM +Kasparov/M +Kate/M +Katelyn/M +Katharine/M +Katherine/M +Katheryn/M +Kathiawar/M +Kathie/M +Kathleen/M +Kathmandu/M +Kathrine/M +Kathryn/M +Kathy/M +Katie/M +Katina/M +Katmai/M +Katmandu/M +Katowice/M +Katrina/M +Katy/M +Kauai/M +Kaufman/M +Kaunas/M +Kaunda/M +Kawabata/M +Kawasaki/M +Kay/M +Kaye/M +Kayla/M +Kazakh/M +Kazakhs +Kazakhstan/M +Kazan/M +Kazantzakis/M +Kb/M +Keaton/M +Keats/M +Keck/M +Keenan/M +Keewatin/M +Keillor/M +Keisha/M +Keith/M +Keller/M +Kelley/M +Kelli/M +Kellie/M +Kellogg/M +Kelly/M +Kelsey/M +Kelvin/M +Kemerovo/M +Kemp/M +Kempis/M +Ken/M +Kendall/M +Kendra/M +Kendrick/M +Kenmore/M +Kennan/M +Kennedy/M +Kenneth/M +Kennith/M +Kenny/M +Kent/M +Kenton/M +Kentuckian/MS +Kentucky/M +Kenya/M +Kenyan/SM +Kenyatta/M +Kenyon/M +Keogh/M +Keokuk/M +Kepler/M +Kerensky/M +Keri/M +Kermit/M +Kern/M +Kerouac/M +Kerr/M +Kerri/M +Kerry/M +Kettering/M +Keven/M +Kevin/M +Kevlar/M +Kevorkian/M +Kewpie/M +Key/M +Keynes/M +Keynesian/M +Khabarovsk/M +Khachaturian/M +Khalid/M +Khan/M +Kharkov/M +Khartoum/M +Khayyam/M +Khazar/M +Khmer/M +Khoikhoi/M +Khoisan/M +Khomeini/M +Khorana/M +Khrushchev/M +Khufu/M +Khulna/M +Khwarizmi/M +Khyber/M +Kickapoo/M +Kidd/M +Kiel/M +Kierkegaard/M +Kieth/M +Kiev/M +Kigali/M +Kikuyu/M +Kilauea/M +Kilimanjaro/M +Kilroy/M +Kim/M +Kimberley/M +Kimberly/M +King/M +Kingston/M +Kingstown/M +Kinko's +Kinney/M +Kinsey/M +Kinshasa/M +Kiowa/MS +Kip/M +Kipling/M +Kirby/M +Kirchhoff/M +Kirchner/M +Kirghistan/M +Kirghiz/M +Kirghizia/M +Kiribati/M +Kirinyaga/M +Kirk/M +Kirkland/M +Kirkpatrick/M +Kirov/M +Kirsten/M +Kisangani/M +Kishinev/M +Kislev/M +Kissinger/M +Kit/M +Kitakyushu/M +Kitchener/M +Kitty/M +Kiwanis/M +Klan/M +Klansman/M +Klaus/M +Klee/M +Kleenex/MS +Klein/M +Klimt/M +Kline/M +Klingon/M +Klondike/MS +Kmart/M +Knapp/M +Knesset/M +Kngwarreye/M +Knickerbocker/M +Knievel/M +Knight/M +Knopf/M +Knossos/M +Knowles/M +Knox/M +Knoxville/M +Knudsen/M +Knuth/M +Knuths +Kobe/M +Koch/M +Kochab/M +Kodachrome/M +Kodak/M +Kodaly/M +Kodiak/M +Koestler/M +Kohinoor/M +Kohl/M +Koizumi/M +Kojak/M +Kolyma/M +Kommunizma/M +Kong/M +Kongo/M +Konrad/M +Koontz/M +Koppel/M +Koran/MS +Koranic +Korea/M +Korean/SM +Kornberg/M +Kory/M +Korzybski/M +Kosciusko/M +Kossuth/M +Kosygin/M +Koufax/M +Kowloon/M +Kr/M +Kraft/M +Krakatau/M +Krakatoa/M +Krakow/M +Kramer/M +Krasnodar/M +Krasnoyarsk/M +Krebs/M +Kremlin/M +Kremlinologist +Kremlinology +Kresge/M +Kringle/M +Kris/M +Krishna/M +Krishnamurti/M +Krista/M +Kristen/M +Kristi/M +Kristie/M +Kristin/M +Kristina/M +Kristine/M +Kristopher/M +Kristy/M +Kroc/M +Kroger/M +Kronecker/M +Kropotkin/M +Kruger/M +Krugerrand/M +Krupp/M +Krystal/M +Kshatriya/M +Kublai/M +Kubrick/M +Kuhn/M +Kuibyshev/M +Kulthumm/M +Kunming/M +Kuomintang/M +Kurd/M +Kurdish/M +Kurdistan/M +Kurosawa/M +Kurt/M +Kurtis/M +Kusch/M +Kutuzov/M +Kuwait/M +Kuwaiti/SM +Kuznets/M +Kuznetsk/M +Kwakiutl/M +Kwan/M +Kwangchow/M +Kwangju/M +Kwanzaa/MS +Ky/MH +Kyle/M +Kyoto/M +Kyrgyzstan/M +Kyushu/M +L'Amour/M +L'Enfant +L'Oreal/M +L'Ouverture/M +L/MN +LA +LAN/M +LBJ/M +LC +LCD/M +LCM +LDC +LED/M +LG/M +LGBT +LIFO +LL +LLB/M +LLD/M +LNG +LOGO +LP/M +LPG +LPN/SM +LSAT +LSD/M +LVN +La/SM +Lab +Laban/M +Labrador/SM +Labradorean +Labradorian +Lacey/M +Lachesis/M +Lacy/M +Ladoga/M +Ladonna/M +Lady/M +Ladyship/MS +Lafayette/M +Lafitte/M +Lagos/M +Lagrange/M +Lagrangian/M +Lahore/M +Laius/M +Lajos/M +Lakeisha/M +Lakewood +Lakisha/M +Lakota/M +Lakshmi/M +Lamaism/SM +Lamar/M +Lamarck/M +Lamaze/M +Lamb/M +Lambert/M +Lamborghini/M +Lambrusco/M +Lamentations +Lamont/M +Lana/M +Lanai/M +Lancashire/M +Lancaster/M +Lance/M +Lancelot/M +Land/M +Landon/M +Landry/M +Landsat/M +Landsteiner/M +Lane/M +Lang/M +Langerhans/M +Langland/M +Langley/M +Langmuir/M +Lanka/M +Lankan/M +Lanny/M +Lansing/M +Lanzhou/M +Lao/SM +Laocoon/M +Laos/M +Laotian/SM +Laplace/M +Lapland/MR +Lapp/SM +Lara/M +Laramie/M +Lardner/M +Laredo/M +Larousse/M +Larry/M +Lars/MN +Larsen/M +Larson/M +Lascaux/M +Lassa/M +Lassen/M +Lassie/M +Lat/M +Latasha/M +Lateran/M +Latham/M +Latin/MRS +Latina +Latino/SM +Latisha/M +Latonya/M +Latoya/M +Latrobe/M +Latvia/M +Latvian/MS +Laud/MR +Lauder/M +Laue/M +Laundromat/M +Laura/M +Laurasia/M +Laurel/M +Lauren/M +Laurence/M +Laurent/M +Lauri/M +Laurie/M +Laval/M +Lavern/M +Laverne/M +Lavoisier/M +Lavonne/M +Lawanda/M +Lawrence/M +Lawson/M +Layamon/M +Layla/M +Lazaro/M +Lazarus/M +Le/SM +Lea/M +Leach/M +Leadbelly/M +Leah/M +Leakey/M +Lean/M +Leander/M +Leann/M +Leanna/M +Leanne/M +Lear/M +Learjet/M +Leary/M +Leavenworth/M +Lebanese/M +Lebanon/M +Lebesgue/M +Leblanc/M +Leda/M +Lederberg/M +Lee/M +Leeds/M +Leeuwenhoek/M +Leeward/M +Left +Legendre/M +Leger/M +Leghorn/M +Lego/M +Legree/M +Lehman/M +Leibniz/M +Leicester/SM +Leiden/M +Leif/M +Leigh/M +Leila/M +Leipzig/M +Lela/M +Leland/M +Lelia/M +Lemaitre/M +Lemuel/M +Lemuria/M +Len/M +Lena/M +Lenard/M +Lenin/M +Leningrad/M +Leninism/M +Leninist/M +Lennon/M +Lenny/M +Leno/M +Lenoir/M +Lenora/M +Lenore/M +Lent/SMN +Lenten/M +Leo/SM +Leola/M +Leon/M +Leona/M +Leonard/M +Leonardo/M +Leoncavallo/M +Leonel/M +Leonid/M +Leonidas/M +Leonor/M +Leopold/M +Leopoldo/M +Lepidus/M +Lepke/M +Lepus/M +Lerner/M +Leroy/M +Les/M +Lesa/M +Lesley/M +Leslie/M +Lesotho/M +Lesseps/M +Lessie/M +Lester/M +Lestrade/M +Leta/M +Letha/M +Lethe/M +Leticia/M +Letitia/M +Letterman/M +Levant/M +Levesque/M +Levi/SM +Leviathan/M +Levine/M +Leviticus/M +Levitt/M +Levy/M +Lew/M +Lewinsky/M +Lewis/M +Lexington/M +Lexus/M +Lhasa/MS +Lhotse/M +Li/MY +Libby/M +Liberace/M +Liberal +Liberia/M +Liberian/SM +Libra/MS +LibreOffice/M +Libreville/M +Librium/M +Libya/M +Libyan/SM +Lichtenstein/M +Lidia/M +Lie/M +Lieberman/M +Liebfraumilch/M +Liechtenstein/ZMR +Liechtensteiner/M +Liege/M +Lieut +Lila/M +Lilia/M +Lilian/M +Liliana/M +Lilith/M +Liliuokalani/M +Lille/M +Lillian/M +Lillie/M +Lilliput/M +Lilliputian/MS +Lilly/M +Lilongwe/M +Lily/M +Lima/M +Limbaugh/M +Limbo +Limburger/M +Limoges/M +Limousin/M +Limpopo/M +Lin/M +Lina/M +Lincoln/MS +Lind/M +Linda/M +Lindbergh/M +Lindsay/M +Lindsey/M +Lindy/M +Linnaeus/M +Linotype/M +Linton/M +Linus/M +Linux/MS +Linwood/M +Lionel/M +Lipizzaner/M +Lippi/M +Lippmann/M +Lipscomb/M +Lipton/M +Lisa/M +Lisbon/M +Lissajous/M +Lister/M +Listerine/M +Liston/M +Liszt/M +Lithuania/M +Lithuanian/MS +Little/M +Litton/M +Liverpool/M +Liverpudlian/SM +Livia/M +Livingston/M +Livingstone/M +Livonia/M +Livy/M +Liz/M +Liza/M +Lizzie/M +Lizzy/M +Ljubljana/M +Llewellyn/M +Lloyd/M +Ln +Loafer/SM +Lobachevsky/M +Lochinvar/M +Locke/M +Lockean/M +Lockheed/M +Lockwood/M +Lodge/M +Lodz/M +Loewe/M +Loewi/M +Loews/M +Logan/M +Lohengrin/M +Loire/M +Lois/M +Loki/M +Lola/M +Lolita/M +Lollard/M +Lollobrigida/M +Lombard/M +Lombardi/M +Lombardy/M +Lome/M +Lon/M +London/MRZ +Londoner/M +Long/M +Longfellow/M +Longstreet/M +Longueuil +Lonnie/M +Lopez/M +Lora/M +Loraine/M +Lord/SM +Lordship/SM +Lorelei/M +Loren/M +Lorena/M +Lorene/M +Lorentz/M +Lorenz/M +Lorenzo/M +Loretta/M +Lori/M +Lorie/M +Lorna/M +Lorraine/M +Lorre/M +Lorrie/M +Los +Lot/M +Lothario/SM +Lott/M +Lottie/M +Lou/M +Louella/M +Louie/M +Louis/M +Louisa/M +Louise/M +Louisiana/M +Louisianan/MS +Louisianian/MS +Louisville/M +Lourdes/M +Louvre/M +Love/M +Lovecraft/M +Lovelace/M +Lowe/M +Lowell/M +Lowenbrau/M +Lowery/M +Lowlands +Loyang/M +Loyd/M +Loyola/M +Lr +Lt +Ltd +Lu/M +Luanda/M +Luann/M +Lubavitcher/M +Lubbock/M +Lubumbashi/M +Lucas/M +Luce/M +Lucia/M +Lucian/M +Luciano/M +Lucien/M +Lucifer/M +Lucile/M +Lucille/M +Lucinda/M +Lucio/M +Lucite/SM +Lucius/M +Lucknow/M +Lucretia/M +Lucretius/M +Lucy/M +Luddite/MS +Ludhiana/M +Ludwig/M +Luella/M +Lufthansa/M +Luftwaffe/M +Luger/M +Lugosi/M +Luigi/M +Luis/M +Luisa/M +Luke/M +Lula/M +Lully/M +Lulu/M +Lumiere/M +Lumière/M +Luna/M +Lupe/M +Lupercalia/M +Lupus/M +Luria/M +Lusaka/M +Lusitania/M +Luther/M +Lutheran/SM +Lutheranism/MS +Luvs/M +Luxembourg/ZMR +Luxembourger/M +Luxembourgian +Luz/M +Luzon/M +Lvov/M +LyX/M +Lyallpur +Lycra/M +Lycurgus/M +Lydia/M +Lydian/SM +Lyell/M +Lyle/M +Lyly/M +Lyman/M +Lyme/M +Lynch/M +Lynda/M +Lyndon/M +Lynette/M +Lynn/M +Lynne/M +Lynnette/M +Lyon/SM +Lyons/M +Lyra/M +Lysenko/M +Lysistrata/M +Lysol/M +M/SMGB +MA/M +MASH +MB/M +MBA/M +MC +MCI/M +MD/M +MDT +ME +MEGO/S +MFA/M +MGM/M +MHz +MI/M +MIA +MIDI/M +MIPS +MIRV +MIT/M +MM +MN +MO +MOOC +MP/M +MPEG +MRI/M +MS/M +MSG/M +MST/M +MSW +MT/M +MTV/M +MVP/M +MW +Maalox/M +Mabel/M +Mable/M +Mac/M +MacArthur/M +MacBride/M +MacDonald/M +MacLeish/M +Macao/M +Macaulay/M +Macbeth/M +Maccabees +Maccabeus/M +Mace/M +Macedon/M +Macedonia/M +Macedonian/SM +Mach/M +Machiavelli/M +Machiavellian/M +Macias/M +Macintosh/M +Mack/M +Mackenzie/M +Mackinac/M +Mackinaw/M +Macmillan/M +Macon/M +Macumba/M +Macy/M +Madagascan/SM +Madagascar/M +Madam +Madden/M +Maddox/M +Madeira/SM +Madeleine/M +Madeline/M +Madelyn/M +Madge/M +Madison/M +Madonna/SM +Madras/M +Madrid/M +Madurai/M +Mae/M +Maeterlinck/M +Mafia/MS +Mafioso/M +Magdalena/M +Magdalene/M +Magellan/M +Magellanic/M +Maggie/M +Maghreb/M +Magi +Maginot/M +Magnitogorsk/M +Magog/M +Magoo/M +Magritte/M +Magsaysay/M +Magus +Magyar/SM +Mahabharata/M +Maharashtra/M +Mahavira/M +Mahayana/M +Mahayanist/M +Mahdi/M +Mahfouz/M +Mahican/SM +Mahler/M +Mai/M +Maidenform/M +Maigret/M +Mailer/M +Maillol/M +Maiman/M +Maimonides/M +Maine/MZR +Mainer/M +Maisie/M +Maitreya/M +Maj +Majesty +Major/M +Majorca/M +Majuro/M +Makarios/M +Maker/M +Malabar/M +Malabo/M +Malacca/M +Malachi/M +Malagasy/M +Malamud/M +Malaprop/M +Malawi/M +Malawian/SM +Malay/MS +Malaya/M +Malayalam/M +Malayan/MS +Malaysia/M +Malaysian/MS +Malcolm/M +Maldive/MS +Maldives/M +Maldivian/MS +Maldonado/M +Male/M +Mali/M +Malian/SM +Malibu/M +Malinda/M +Malinowski/M +Mallarme/M +Mallarmé/M +Mallomars/M +Mallory/M +Malone/M +Malory/M +Malplaquet/M +Malraux/M +Malta/M +Maltese/M +Malthus/M +Malthusian/SM +Mameluke/M +Mamet/M +Mamie/M +Mammon/SM +Mamore/M +Man/M +Managua/M +Manama/M +Manasseh/M +Manchester/M +Manchu/SM +Manchuria/M +Manchurian/M +Mancini/M +Mancunian/MS +Mandalay/M +Mandarin/M +Mandela/M +Mandelbrot/M +Mandingo/M +Mandrell/M +Mandy/M +Manet/M +Manfred/M +Manhattan/SM +Mani/M +Manichean/M +Manila/SM +Manitoba/M +Manitoulin/M +Manley/M +Mann/GM +Mannheim/M +Manning/M +Mansfield/M +Manson/M +Mantegna/M +Mantle/M +Manuel/M +Manuela/M +Manx/M +Mao/M +Maoism/SM +Maoist/SM +Maori/MS +Mapplethorpe/M +Maputo/M +Mar/SM +Mara/M +Maracaibo/M +Marat/M +Maratha/M +Marathi/M +Marathon/M +Marc/M +Marceau/M +Marcel/M +Marcelino/M +Marcella/M +Marcelo/M +March/MS +Marci/M +Marcia/M +Marciano/M +Marcie/M +Marco/MS +Marconi/M +Marcos/M +Marcus/M +Marcuse +Marcy/M +Marduk/M +Margaret/M +Margarita/M +Margarito/M +Marge/M +Margery/M +Margie/M +Margo/M +Margot +Margret/M +Margrethe/M +Marguerite/M +Mari/SM +Maria/M +Marian/M +Mariana/SM +Marianas/M +Marianne/M +Mariano/M +Maribel/M +Maricela/M +Marie/M +Marietta/M +Marilyn/M +Marin/M +Marina/M +Marine/SM +Mario/M +Marion/M +Maris/M +Marisa/M +Marisol/M +Marissa/M +Maritain/M +Maritza/M +Mariupol +Marius/M +Marjorie/M +Marjory/M +Mark/SM +Markab/M +Markham/M +Markov/M +Marks/M +Marla/M +Marlboro/M +Marlborough/M +Marlene/M +Marley/M +Marlin/M +Marlon/M +Marlowe/M +Marmara/M +Marne/M +Maronite/M +Marple/M +Marquesas/M +Marquette/M +Marquez/M +Marquis/M +Marquita/M +Marrakesh/M +Marriott/M +Mars/MS +Marsala/M +Marseillaise/MS +Marseilles/M +Marsh/M +Marsha/M +Marshall/M +Marta/M +Martel/M +Martha/M +Martial/M +Martian/SM +Martin/M +Martina/M +Martinez/M +Martinique/M +Marty/M +Marva/M +Marvell/M +Marvin/M +Marx/M +Marxian +Marxism/SM +Marxist/SM +Mary/M +Maryann/M +Maryanne/M +Maryellen/M +Maryland/MR +Marylander/M +Marylou/M +Masada/M +Masai/M +Masaryk/M +Mascagni/M +Masefield/M +Maserati/M +Maseru/M +Mashhad/M +Mason/MS +Masonic/M +Masonite/M +Mass/MS +Massachusetts/M +Massasoit/M +Massenet/M +Massey/M +Master/S +MasterCard/M +Masters/M +Mather/M +Mathew/SM +Mathews/M +Mathewson/M +Mathias/M +Mathis/M +Matilda/M +Matisse/M +Matt/M +Mattel/M +Matterhorn/M +Matthew/SM +Matthews/M +Matthias/M +Mattie/M +Maud/M +Maude/M +Maugham/M +Maui/M +Maupassant/M +Maura/M +Maureen/M +Mauriac/M +Maurice/M +Mauricio/M +Maurine/M +Mauritania/M +Mauritanian/SM +Mauritian/SM +Mauritius/M +Mauro/M +Maurois/M +Mauryan/M +Mauser/M +Mavis/M +Max/M +Maximilian/M +Maxine/M +Maxwell/M +May/SMR +Maya/SM +Mayan/MS +Mayer/M +Mayfair/M +Mayflower/M +Maynard/M +Mayo/M +Maypole +Mayra/M +Mays/M +Maytag/M +Mazama/M +Mazarin/M +Mazatlan/M +Mazda/M +Mazola/M +Mazzini/M +Mb/M +Mbabane/M +Mbini/M +McAdam/M +McBride/M +McCain/M +McCall/M +McCarthy/M +McCarthyism/M +McCartney/M +McCarty/M +McClain/M +McClellan/M +McClure/M +McConnell/M +McCormick/M +McCoy/M +McCray/M +McCullough/M +McDaniel/M +McDonald/M +McDonnell/M +McDowell/M +McEnroe/M +McFadden/M +McFarland/M +McGee/M +McGovern/M +McGowan/M +McGuffey/M +McGuire/M +McIntosh/M +McIntyre/M +McKay/M +McKee/M +McKenzie/M +McKinley/M +McKinney/M +McKnight/M +McLaughlin/M +McLean/M +McLeod/M +McLuhan/M +McMahon/M +McMillan/M +McNamara/M +McNaughton/M +McNeil/M +McPherson/M +McQueen/M +McVeigh/M +Md/M +Me +Mead/M +Meade/M +Meadows/M +Meagan/M +Meany/M +Mecca/MS +Medan/M +Medea/M +Medellin/M +Media/M +Medicaid/SM +Medicare/SM +Medici/M +Medina/M +Mediterranean/MS +Medusa/M +Meg/M +Megan/M +Meghan/M +Meier/M +Meighen/M +Meiji/M +Meir/M +Mejia/M +Mekong/M +Mel/M +Melanesia/M +Melanesian/M +Melanie/M +Melba/M +Melbourne/M +Melchior/M +Melchizedek/M +Melendez/M +Melinda/M +Melisa/M +Melisande/M +Melissa/M +Mellon/M +Melody/M +Melpomene/M +Melton/M +Melva/M +Melville/M +Melvin/M +Memling/M +Memphis/M +Menander/M +Mencius/M +Mencken/M +Mendel/M +Mendeleev/M +Mendelian/M +Mendelssohn/M +Mendez/M +Mendocino/M +Mendoza/M +Menelaus/M +Menelik/M +Menes/M +Mengzi +Menkalinan/M +Menkar/M +Menkent/M +Mennen/M +Mennonite/MS +Menominee/M +Menotti/M +Mensa/M +Mentholatum/M +Menuhin/M +Menzies/M +Mephisto +Mephistopheles/M +Merak/M +Mercado/M +Mercator/M +Mercedes/M +Mercer/M +Mercia/M +Merck/M +Mercurochrome/M +Mercury/SM +Meredith/M +Merino/M +Merle/M +Merlin/M +Merlot/M +Merovingian/M +Merriam/M +Merrick/M +Merrill/M +Merrimack/M +Merritt/M +Merthiolate/M +Merton/M +Mervin/M +Mesa/M +Mesabi/M +Meshed/M +Mesmer/M +Mesolithic/M +Mesopotamia/M +Mesopotamian +Mesozoic/M +Messerschmidt/M +Messiaen/M +Messiah/M +Messiahs +Messianic +Messieurs +Metallica/M +Metamucil/M +Methodism/SM +Methodist/SM +Methuselah/M +Metternich/M +Meuse/M +Mex +Mexicali/M +Mexican/MS +Mexico/M +Meyer/MS +Meyerbeer/M +Meyers/M +Mfume/M +Mg/M +Mgr +MiG/M +Mia/M +Miami/MS +Miaplacidus/M +Micah/M +Micawber/M +Mich/M +Michael/M +Michaelmas/MS +Micheal/M +Michel/M +Michelangelo/M +Michele/M +Michelin/M +Michelle/M +Michelob/M +Michelson/M +Michigan/M +Michigander/MS +Michiganite +Mick/M +Mickey/M +Mickie/M +Micky/M +Micmac/SM +Micronesia/M +Micronesian/M +Microsoft/M +Midas/M +Middleton/M +Mideast +Mideastern +Midland/MS +Midway/M +Midwest/M +Midwestern/MR +Miguel/M +Mike/M +Mikhail/M +Mikoyan/M +Milagros/M +Milan/M +Milanese +Mildred/M +Miles/M +Milford/M +Milken/M +Mill/SMR +Millard/M +Millay/M +Miller/M +Millet/M +Millicent/M +Millie/M +Millikan/M +Mills/M +Milne/M +Milo/M +Milosevic/M +Milquetoast/M +Miltiades/M +Milton/M +Miltonic/M +Miltown/M +Milwaukee/M +Mimi/M +Mimosa/M +Min/M +Minamoto/M +Mindanao/M +Mindoro/M +Mindy/M +Minerva/M +Ming/M +Mingus/M +Minn +Minneapolis/M +Minnelli/M +Minnesota/M +Minnesotan/SM +Minnie/M +Minoan/MS +Minolta/M +Minos/M +Minot/M +Minotaur/M +Minsk/M +Minsky/M +Mintaka/M +Minuit/M +Minuteman/M +Miocene/M +Mir/M +Mira/M +Mirabeau/M +Mirach/M +Miranda/M +Mirfak/M +Miriam/M +Miro/M +Mirzam/M +Miskito/M +Miss +Mississauga/M +Mississippi/M +Mississippian/SM +Missouri/M +Missourian/MS +Missy/M +Mistassini/M +Mister +Mistress +Misty/M +Mitch/M +Mitchel/M +Mitchell/M +Mitford/M +Mithra/M +Mithridates/M +Mitsubishi/M +Mitterrand/M +Mitty/M +Mitzi/M +Mixtec/M +Mizar/M +Mk +Mlle +Mme/S +Mn/M +Mnemosyne/M +Mo/M +Mobil/M +Mobile/M +Mobutu/M +Modesto/M +Modigliani/M +Moe/M +Moet/M +Mogadishu/M +Mogul/MS +Mohacs/M +Mohamed/M +Mohammad/M +Mohammedan/SM +Mohammedanism/SM +Mohave/SM +Mohawk/SM +Mohegan +Moho/M +Mohorovicic/M +Moira/M +Moises/M +Moiseyev/M +Mojave/SM +Moldavia/M +Moldavian +Moldova/M +Moldovan +Moliere/M +Molina/M +Moll/M +Mollie/M +Molly/M +Molnar/M +Moloch/M +Molokai/M +Molotov/M +Moluccas/M +Mombasa/M +Mon/SM +Mona/M +Monacan +Monaco/M +Mondale/M +Monday/SM +Mondrian/M +Monegasque/SM +Monera/M +Monet/M +Mongol/SM +Mongolia/M +Mongolian/SM +Mongolic/M +Mongoloid +Monica/M +Monique/M +Monk/M +Monmouth/M +Monongahela/M +Monroe/M +Monrovia/M +Monsanto/M +Monsieur/M +Monsignor/SM +Mont/M +Montague/M +Montaigne/M +Montana/M +Montanan/SM +Montcalm/M +Monte/M +Montenegrin/M +Montenegro/M +Monterrey/M +Montesquieu/M +Montessori/M +Monteverdi/M +Montevideo/M +Montezuma/M +Montgolfier/M +Montgomery/M +Monticello/M +Montoya/M +Montpelier/M +Montrachet/M +Montreal/M +Montserrat/M +Monty/M +Moody/M +Moog/M +Moon/M +Mooney/M +Moor/SM +Moore/M +Moorish/M +Morales/M +Moran/M +Moravia/M +Moravian/M +Mordred/M +More/M +Moreno/M +Morgan/SM +Moriarty/M +Morin/M +Morison/M +Morita/M +Morley/M +Mormon/SM +Mormonism/SM +Moro/M +Moroccan/SM +Morocco/M +Moroni/M +Morpheus/M +Morphy/M +Morris/M +Morrison/M +Morrow/M +Morse/M +Mort/M +Mortimer/M +Morton/M +Mosaic/M +Moscow/M +Moseley/M +Moselle/M +Moses/M +Moslem/M +Mosley/M +Moss/M +Mosul/M +Motorola/M +Motown/M +Motrin/M +Mott/M +Moulton/M +Mount/M +Mountbatten/M +Mountie/MS +Moussorgsky/M +Mouthe/M +Mouton/M +Mowgli/M +Mozambican/SM +Mozambique/M +Mozart/M +Mozilla/M +Mr/SM +Ms/S +Msgr +Mt +Muawiya/M +Mubarak/M +Mueller/M +Muenster/MS +Mugabe/M +Muhammad/M +Muhammadan/MS +Muhammadanism/SM +Muir/M +Mujib/M +Mulder/M +Mullen/M +Muller/M +Mulligan/M +Mullikan/M +Mullins/M +Mulroney/M +Multan/M +Multics +Mumbai/M +Mumford/M +Munch/M +Munchhausen/M +Munich/M +Munoz/M +Munro/M +Munster/M +Muppet/M +Murasaki/M +Murat/M +Murchison/M +Murcia +Murdoch/M +Muriel/M +Murillo/M +Murine/M +Murmansk/M +Murphy/M +Murray/M +Murrow/M +Murrumbidgee/M +Muscat/M +Muscovite/M +Muscovy/M +Muse/M +Musharraf/M +Musial/M +Muskogee/M +Muslim/MS +Mussolini/M +Mussorgsky/M +Mutsuhito/M +Muzak/M +MySpace/M +Myanmar/M +Mycenae/M +Mycenaean/M +Myers/M +Mylar/MS +Myles/M +Myra/M +Myrdal/M +Myrna/M +Myron/M +Myrtle/M +Mysore/M +Myst/M +Münchhausen/M +N'Djamena +N/MD +NAACP/M +NAFTA/M +NASA/M +NASCAR/M +NASDAQ/M +NATO/M +NB +NBA/M +NBC/M +NBS +NC +NCAA/M +NCO +ND +NE/M +NEH +NF +NFC +NFL/M +NH +NHL/M +NIH +NIMBY +NJ +NLRB +NM +NORAD/M +NOW +NP +NPR/M +NR +NRA +NRC +NS +NSA/M +NSC +NSF +NSFW +NT +NV +NW/M +NWT +NY +NYC +NYSE +NZ +Na/M +Nabisco/M +Nabokov/M +Nader/M +Nadia/M +Nadine/M +Nagasaki/M +Nagoya/M +Nagpur/M +Nagy/M +Nahuatl/MS +Nahum/M +Naipaul/M +Nair/M +Nairobi/M +Naismith/M +Nam/M +Namath/M +Namibia/M +Namibian/MS +Nan/M +Nanak/M +Nanchang/M +Nancy/M +Nanette/M +Nanjing/M +Nannie/M +Nanook/M +Nansen/M +Nantes/M +Nantucket/M +Naomi/M +Naphtali/M +Napier/M +Naples/M +Napoleon/MS +Napoleonic/M +Napster/M +Narcissus/M +Narmada/M +Narnia/M +Narraganset +Narragansett/M +Nash/M +Nashua/M +Nashville/M +Nassau/M +Nasser/M +Nat/M +Natalia/M +Natalie/M +Natasha/M +Natchez/M +Nate/MN +Nathan/SM +Nathaniel/M +Nathans/M +Nation/M +Nationwide/M +Nativity/M +Nature +Naugahyde/M +Nauru/M +Nautilus/M +Navajo/SM +Navajoes +Navarre/M +Navarro/M +Navratilova/M +Navy +Nazarene/M +Nazareth/M +Nazca/M +Nazi/SM +Nazism/MS +Nb/M +Nd/M +Ndjamena/M +Ne/M +NeWS +NeWSes +Neal/M +Neanderthal/SM +Neapolitan/M +Neb +Nebr +Nebraska/M +Nebraskan/MS +Nebuchadnezzar/M +Ned/M +Nefertiti/M +Negev/M +Negress/MS +Negritude +Negro/MS +Negroes +Negroid/SM +Negros/M +Nehemiah/M +Nehru/M +Neil/M +Nelda/M +Nell/M +Nellie/M +Nelly/M +Nelsen/M +Nelson/M +Nembutal/M +Nemesis/M +Neogene/M +Neolithic +Nepal/M +Nepalese/M +Nepali/MS +Neptune/M +Nereid/M +Nerf/M +Nero/M +Neruda/M +Nescafe/M +Nesselrode/M +Nestle/M +Nestor/M +Nestorius/M +Netflix/M +Netherlander/SM +Netherlands/M +Netscape/M +Nettie/M +Netzahualcoyotl/M +Nev/M +Neva/M +Nevada/M +Nevadan/SM +Nevadian +Nevis/M +Nevsky/M +Newark/M +Newcastle/M +Newfoundland/MRS +Newman/M +Newport/M +Newsweek/M +Newton/M +Newtonian/M +Nexis/M +Ngaliema/M +Nguyen/M +Ni/M +Niagara/M +Niamey/M +Nibelung/M +Nicaea/M +Nicaragua/M +Nicaraguan/SM +Niccolo/M +Nice/M +Nicene/M +Nichiren/M +Nicholas/M +Nichole/M +Nichols/M +Nicholson/M +Nick/M +Nickelodeon/M +Nicklaus/M +Nickolas/M +Nicobar/M +Nicodemus/M +Nicola/SM +Nicolas/M +Nicole/M +Nicosia/M +Niebuhr/M +Nielsen/M +Nietzsche/M +Nieves/M +Nigel/M +Niger/M +Nigeria/M +Nigerian/MS +Nigerien/M +Nightingale/M +Nijinsky/M +Nike/M +Nikita/M +Nikkei/M +Nikki/M +Nikolai/M +Nikolayev/M +Nikon/M +Nile/M +Nimitz/M +Nimrod/M +Nina/M +Nineveh/M +Nintendo/M +Niobe/M +Nippon/M +Nipponese/M +Nirenberg/M +Nirvana/M +Nisan/M +Nisei/M +Nissan/M +Nita/M +Nivea/M +Nixon/M +Nkrumah/M +No/SM +NoDoz/M +Noah/M +Nobel/M +Nobelist/MS +Noble/M +Noe/M +Noel/SM +Noelle/M +Noemi/M +Nokia/M +Nola/M +Nolan/M +Nome/M +Nona/M +Nootka/M +Nora/M +Norbert/M +Norberto/M +Nordic/MS +Noreen/M +Norfolk/M +Noriega/M +Norma/M +Norman/MS +Normand/M +Normandy/M +Norplant/M +Norris/M +Norse/M +Norseman/M +Norsemen/M +North/M +Northampton/M +Northeast/MS +Northern/MR +Northerner/M +Northrop/M +Northrup/M +Norths +Northwest/SM +Norton/M +Norw +Norway/M +Norwegian/SM +Norwich/M +Nosferatu/M +Nostradamus/M +Nottingham/M +Nouakchott/M +Noumea/M +Nov/M +Nova/M +Novartis/M +November/MS +Novgorod/M +Novocain/MS +Novocaine +Novokuznetsk/M +Novosibirsk/M +Noxzema/M +Noyce/M +Noyes/M +Np/M +Nubia/M +Nubian/M +Nukualofa/M +Numbers/M +Nunavut/M +Nunez/M +Nunki/M +Nuremberg/M +Nureyev/M +NutraSweet/M +NyQuil/M +Nyasa/M +Nyerere/M +O'Brien/M +O'Casey/M +O'Connell/M +O'Connor/M +O'Donnell/M +O'Hara/M +O'Higgins/M +O'Keeffe/M +O'Neil/M +O'Neill/M +O'Rourke/M +O'Toole/M +O/SM +OAS/M +OB +OCR +OD/SM +OE +OED +OH +OHSA/M +OJ +OK/SMDG +OMB/M +ON +OPEC/M +OR +OS/M +OSHA/M +OSes +OT +OTB +OTC +OTOH +Oahu/M +Oakland/M +Oakley/M +Oates/M +Oaxaca/M +Ob/M +Obadiah/M +Obama/M +Obamacare +Oberlin/M +Oberon/M +Occam/M +Occident +Occidental/MS +Oceania/M +Oceanside +Oceanus/M +Ochoa/M +Oct/M +Octavia/M +Octavian/M +Octavio/M +October/SM +Odell/M +Oder/M +Odessa/M +Odets/M +Odin/M +Odis/M +Odom/M +Odysseus/M +Odyssey/M +Oedipal/M +Oedipus/M +Oersted/M +Ofelia/M +Offenbach/M +OfficeMax/M +Ogbomosho/M +Ogden/M +Ogilvy/M +Oglethorpe/M +Ohio/M +Ohioan/SM +Oise/M +Ojibwa/SM +Okayama +Okeechobee/M +Okefenokee/M +Okhotsk/M +Okinawa/M +Okinawan +Okla +Oklahoma/M +Oklahoman/M +Oktoberfest/M +Ola/M +Olaf/M +Olajuwon/M +Olav/M +Oldenburg/M +Oldfield/M +Oldsmobile/M +Olduvai/M +Olen/M +Olenek/M +Olga/M +Oligocene/M +Olin/M +Olive/MR +Oliver/M +Olivetti/M +Olivia/M +Olivier/M +Ollie/M +Olmec/M +Olmsted/M +Olsen/M +Olson/M +Olympia/SM +Olympiad/MS +Olympian/MS +Olympic/SM +Olympics/M +Olympus/M +Omaha/MS +Oman/M +Omani/MS +Omar/M +Omayyad/M +Omdurman/M +Omnipotent +Omsk/M +Onassis/M +Oneal/M +Onega/M +Onegin/M +Oneida/MS +Onion/M +Ono/M +Onondaga/MS +Onsager/M +Ont +Ontarian +Ontario/M +Oort/M +Opal/M +Opel/M +OpenOffice/M +Ophelia/M +Ophiuchus/M +Oppenheimer/M +Opposition +Oprah/M +Ora/M +Oracle/M +Oran/M +Orange/M +Oranjestad/M +Orbison/M +Ordovician/M +Ore/N +Oreg +Oregon/M +Oregonian/SM +Oreo/M +Orestes/M +Orient/M +Oriental/MS +Orientalism +Orin/M +Orinoco/M +Orion/M +Oriya/M +Orizaba/M +Orkney/M +Orlando/M +Orleans/M +Orlon/MS +Orly/M +Orpheus/M +Orphic/M +Orr/M +Ortega/M +Orthodox +Ortiz/M +Orval/M +Orville/M +Orwell/M +Orwellian/M +Os/M +Osage/MS +Osaka/M +Osbert/M +Osborn/M +Osborne/M +Oscar/MS +Osceola/M +Osgood/M +Oshawa/M +Oshkosh/M +Osiris/M +Oslo/M +Osman/M +Ostrogoth/M +Ostwald/M +Osvaldo/M +Oswald/M +Othello/M +Otis/M +Ottawa/SM +Otto/M +Ottoman/M +Ouagadougou/M +Ouija/MS +Ovid/M +Owen/SM +Owens/M +Oxford/SM +Oxnard/M +Oxonian/M +Oxus/M +Oxycontin/M +Oz/M +Ozark/MS +Ozarks/M +Ozymandias/M +Ozzie/M +P/MN +PA/M +PAC/M +PARC/S +PASCAL +PBS/M +PBX +PC/SM +PCB +PCMCIA +PCP/M +PD +PDF +PDQ +PDT +PE +PET/M +PFC +PG +PGP +PIN +PJ's +PLO/M +PM/SMDG +PMS/M +PO +POW/M +PP +PPS +PR +PRC/M +PRO +PS/M +PST/M +PT +PTA/M +PTO +PVC/M +PW +PX +Pa/M +Paar/M +Pablo/M +Pablum/M +Pabst/M +Pace/M +Pacheco/M +Pacific/M +Pacino/M +Packard/M +Padang +Paderewski/M +Padilla/M +Paganini/M +Page/M +Paglia/M +Pahlavi/M +Paige/M +Paine/M +Paiute/SM +Pakistan/M +Pakistani/SM +Palau/M +Palembang/M +Paleocene/M +Paleogene/M +Paleolithic/M +Paleozoic/M +Palermo/M +Palestine/M +Palestinian/SM +Palestrina/M +Paley/M +Palikir/M +Palisades/M +Palladio/M +Palmer/M +Palmerston/M +Palmolive/M +Palmyra/M +Palomar/M +Pam/M +Pamela/M +Pamirs/M +Pampers/M +Pan/M +Panama/SM +Panamanian/MS +Panasonic/M +Pandora/M +Pangaea/M +Pankhurst/M +Panmunjom/M +Pansy/M +Pantagruel/M +Pantaloon/M +Pantheon/M +Panza/M +Paracelsus/M +Paraclete/M +Paradise +Paraguay/M +Paraguayan/MS +Paralympic/S +Paramaribo/M +Paramount/M +Parana/M +Paraná/M +Parcheesi/M +Pareto/M +Paris/M +Parisian/MS +Park/SMR +Parker/M +Parkinson/M +Parkinsonism +Parkman/M +Parks/M +Parliament/M +Parmenides +Parmesan/MS +Parnassus/MS +Parnell/M +Parr/M +Parrish/M +Parsee/SM +Parsi/MS +Parsifal/M +Parsons/M +Parthenon/M +Parthia/M +Pasadena/M +Pascal/SM +Pasquale/M +Passion/SM +Passover/MS +Pasternak/M +Pasteur/M +Pat/M +Patagonia/M +Patagonian/M +Pate/M +Patel/M +Paterson/M +Patna/M +Patrica/M +Patrice/M +Patricia/M +Patrick/M +Patsy/M +Patterson/M +Patti/M +Patton/M +Patty/M +Paul/GM +Paula/M +Paulette/M +Pauli/M +Pauline/M +Pauling/M +Pavarotti/M +Pavlov/M +Pavlova/M +Pavlovian/M +Pawnee/SM +PayPal/M +Payne/M +Pb/M +Pd/M +Peabody/M +Peace/M +Peale/M +Pearl/M +Pearlie/M +Pearson/M +Peary/M +Pechora/M +Peck/M +Peckinpah/M +Pecos/M +Pedro/M +Peel/M +Peg/M +Pegasus/MS +Peggy/M +Pei/M +Peiping/M +Pekinese/M +Peking/SM +Pekingese/SM +Pele/M +Pelee/M +Peloponnese/M +Pembroke/M +Pen/M +Pena/M +Penderecki/M +Penelope/M +Penn/M +Penna +Penney/M +Pennington/M +Pennsylvania/M +Pennsylvanian/MS +Penny/M +Pennzoil/M +Pensacola/M +Pentagon/M +Pentateuch/M +Pentax/M +Pentecost/SM +Pentecostal/MS +Pentecostalism +Pentium/SM +Peoria/M +Pepin/M +Pepsi/M +Pepys/M +Pequot/M +Percheron/M +Percival/M +Percy/M +Perelman/M +Perez/M +Periclean/M +Pericles/M +Perkins/M +Perl/SM +Perm/M +Permalloy/M +Permian/M +Pernod/M +Peron/M +Perot/M +Perrier/M +Perry/RM +Perseid/M +Persephone/M +Persepolis/M +Perseus/M +Pershing/M +Persia/M +Persian/SM +Perth/M +Peru/M +Peruvian/MS +Peshawar/M +Petain/M +Pete/RMZ +Peter/M +Peters/MN +Petersen/M +Peterson/M +Petra/M +Petrarch/M +Petty/M +Peugeot/M +Pfc +Pfizer/M +PhD/M +Phaedra/M +Phaethon/M +Phanerozoic/M +Pharaoh/M +Pharaohs +Pharisaic +Pharisaical +Pharisee/MS +Phekda/M +Phelps/M +Phidias/M +Phil/MY +Philadelphia/M +Philby/M +Philemon/M +Philip/MS +Philippe/M +Philippians/M +Philippine/SM +Philippines/M +Philips/M +Philistine/M +Phillip/SM +Phillipa/M +Phillips/M +Philly/M +Phipps/M +Phobos/M +Phoebe/M +Phoenicia/M +Phoenician/SM +Phoenix/M +Photostat/MS +Photostatted +Photostatting +Phrygia/M +Phyllis/M +Piaf/M +Piaget/M +Pianola/M +Picasso/M +Piccadilly/M +Pickering/M +Pickett/M +Pickford/M +Pickwick/M +Pict/M +Piedmont/M +Pierce/M +Pierre/M +Pierrot/M +Pike/M +Pilate/MS +Pilates/M +Pilcomayo/M +Pilgrim/SM +Pillsbury/M +Pinatubo/M +Pincus/M +Pindar/M +Pinkerton/M +Pinocchio/M +Pinochet/M +Pinter/M +Pinyin +Pippin/M +Piraeus/M +Pirandello/M +Pisa/M +Pisces/M +Pisistratus/M +Pissaro/M +Pitcairn/M +Pitt/SM +Pittman/M +Pitts/M +Pittsburgh/M +Pius/M +Pizarro/M +Pkwy +Pl +Place +Planck/M +Plano +Plantagenet/M +Plasticine/M +Plataea/M +Plath/M +Plato/M +Platonic +Platonism/M +Platonist/M +Platte/M +Plautus/M +PlayStation/M +Playboy/M +Playtex/M +Pleiades/M +Pleistocene/M +Plexiglas/MS +Pliny/M +Pliocene/SM +Plutarch/M +Pluto/M +Plymouth/M +Pm/M +Po/M +Pocahontas/M +Pocono/SM +Poconos/M +Podgorica/M +Podhoretz/M +Podunk/M +Poe/M +Pogo/M +Poincare/M +Poincaré/M +Poiret/M +Poirot/M +Poisson/M +Poitier/M +Pokemon/M +Pokémon/M +Pol/MY +Poland/M +Polanski/M +Polaris/M +Polaroid/MS +Pole/SM +Polish/M +Politburo/M +Polk/M +Pollard/M +Pollock/M +Pollux/M +Polly/M +Pollyanna/M +Polo/M +Poltava/M +Polyhymnia/M +Polynesia/M +Polynesian/MS +Polyphemus/M +Pomerania/M +Pomeranian/M +Pomona/M +Pompadour/M +Pompeian +Pompeii/M +Pompey/M +Ponce/M +Pontchartrain/M +Pontiac/M +Pontianak/M +Pooh/M +Poole/M +Poona/M +Pope/M +Popeye/M +Popocatepetl/M +Popper/M +Poppins/M +Popsicle/M +Porfirio/M +Porrima/M +Porsche/M +Port/MR +Porter/M +Portia/M +Portland/M +Porto/M +Portsmouth/M +Portugal/M +Portuguese/M +Poseidon/M +Post/M +Potemkin/M +Potomac/M +Potsdam/M +Pottawatomie/M +Potter/M +Potts/M +Pound/M +Poussin/M +Powell/M +PowerPC/M +PowerPoint/M +Powers/M +Powhatan/M +Poznan/M +Pr/M +Prada/M +Prado/M +Praetorian/M +Prague/M +Praia/M +Prakrit/M +Pratchett/M +Pratt/M +Pravda/M +Praxiteles/M +Preakness/M +Precambrian/M +Preminger/M +Premyslid/M +Prensa/M +Prentice/M +Pres +Presbyterian/SM +Presbyterianism/MS +Prescott/M +Presley/M +Preston/M +Pretoria/M +Priam/M +Pribilof/M +Price/M +Priestley/M +Prince/M +Princeton/M +Principe/M +Priscilla/M +Prius/M +Private +Procrustean/M +Procrustes/M +Procter/M +Procyon/M +Prof +Prohibition +Prokofiev/M +Promethean/M +Prometheus/M +Prophets +Proserpina/M +Proserpine/M +Protagoras/M +Proterozoic/M +Protestant/MS +Protestantism/SM +Proteus/M +Proudhon/M +Proust/M +Provencal/MS +Provence/M +Provençal/M +Proverbs +Providence/SM +Provo/M +Prozac/MS +Prudence/M +Prudential/M +Pruitt/M +Prussia/M +Prussian/MS +Prut/M +Pryor/M +Psalms/M +Psalter/MS +Psyche/M +Pt/M +Ptah/M +Ptolemaic/M +Ptolemy/SM +Pu/M +Puccini/M +Puck/M +Puckett/M +Puebla/M +Pueblo/M +Puerto +Puget/M +Pugh/M +Pulaski/M +Pulitzer/M +Pullman/MS +Punch/M +Punic/M +Punjab/M +Punjabi/M +Purana/M +Purcell/M +Purdue/M +Purgatory +Purim/MS +Purina/M +Puritan/M +Puritanism/MS +Purus/M +Pusan/M +Pusey/M +Pushkin/M +Pushtu/M +Putin/M +Putnam/M +Puzo/M +Pvt +Pygmalion/M +Pygmy/SM +Pyle/M +Pym/M +Pynchon/M +Pyongyang/M +Pyotr/M +Pyrenees/M +Pyrex/MS +Pyrrhic/M +Pythagoras/M +Pythagorean/M +Pythias/M +Python/M +Pétain/M +Pôrto/M +Q +QA +QB +QC +QED +QM +QWERTY +Qaddafi/M +Qantas/M +Qatar/M +Qatari/MS +Qingdao/M +Qiqihar/M +Qom/M +Quaalude/M +Quaker/MS +Quakerism/SM +Quaoar/M +Quasimodo/M +Quaternary/M +Quayle/M +Que +Quebec/M +Quebecker +Quebecois/M +Quechua/M +Queen/MS +Queens/M +Queensland/M +Quentin/M +Quetzalcoatl/M +Quezon/M +Quincy/M +Quinn/M +Quintilian/M +Quinton/M +Quirinal/M +Quisling/M +Quito/M +Quixote/M +Quixotism/M +Qumran/M +Quonset/M +Qur'an +Qur'anic +Quran +Quranic +Québecois/M +R/MD +RAF/M +RAM/SM +RBI +RC +RCA/M +RCMP +RD +RDA +REIT +REM/SM +RF +RFC/S +RFD +RI +RIF +RIP +RISC +RN/M +RNA/M +ROFL +ROM/M +ROTC/M +RP +RR +RSFSR +RSI +RSV +RSVP +RTFM +RV/SM +Ra/M +Rabat/M +Rabelais/M +Rabelaisian/M +Rabin/M +Rachael/M +Rachel/M +Rachelle/M +Rachmaninoff/M +Racine/M +Radcliffe/M +Rae/M +Rafael/M +Raffles/M +Ragnarok/M +Ragnarök/M +Rainier/M +Raleigh/M +Ralph/M +Rama/M +Ramada/M +Ramadan/MS +Ramakrishna/M +Ramanujan/M +Ramayana/M +Rambo/M +Ramirez/M +Ramiro/M +Ramon/M +Ramona/M +Ramos/M +Ramsay/M +Ramses/M +Ramsey/M +Rand/M +Randal/M +Randall/M +Randell/M +Randi/M +Randolph/M +Randy/M +Rangoon/M +Rankin/M +Rankine/M +Raoul/M +Raphael/M +Rappaport/M +Rapunzel/M +Raquel/M +Rasalgethi/M +Rasalhague/M +Rasmussen/M +Rasputin/M +Rasta +Rastaban/M +Rastafarian/MS +Rastafarianism +Rather/M +Ratliff/M +Raul/M +Ravel/M +Rawalpindi/M +Ray/M +RayBan/M +Rayburn/M +Rayleigh/M +Raymond/M +Raymundo/M +Rb/M +Rd +Re/M +Reading/M +Reagan/M +Reaganomics/M +Realtor/M +Reasoner/M +Reba/M +Rebekah/M +Recife/M +Reconstruction/M +Red/SM +Redeemer/M +Redford/M +Redgrave/M +Redmond/M +Reebok/M +Reed/M +Reese/M +Reeves/M +Reformation/MS +Refugio/M +Reggie/M +Regina/M +Reginae/M +Reginald/M +Regor/M +Regulus/M +Rehnquist/M +Reich/M +Reichstag's +Reid/M +Reilly/M +Reinaldo/M +Reinhardt/M +Reinhold/M +Remarque/M +Rembrandt/M +Remington/M +Remus/M +Rena/M +Renaissance/SM +Renascence +Renault/M +Rene/M +Renee/M +Reno/M +Renoir/M +Rep +Representative +Republican/SM +Republicanism +Requiem/MS +Resistance +Restoration/M +Resurrection +Reuben/M +Reunion/M +Reuters/M +Reuther/M +Rev +Reva/M +Revelation/SM +Revelations/M +Revere/M +Reverend/M +Revlon/M +Rex/M +Reyes/M +Reykjavik/M +Reyna/M +Reynaldo/M +Reynolds/M +Rf/M +Rh/M +Rhea/M +Rhee/M +Rheingau/M +Rhenish/M +Rhiannon/M +Rhine/M +Rhineland/M +Rhoda/M +Rhode/S +Rhodes/M +Rhodesia/M +Rhodesian +Rhonda/M +Rhone/M +Ribbentrop/M +Ricardo/M +Rice/M +Rich/M +Richard/MS +Richards/M +Richardson/M +Richelieu/M +Richie/M +Richmond/M +Richter/M +Richthofen/M +Rick/M +Rickenbacker/M +Rickey/M +Rickie/M +Rickover/M +Ricky/M +Rico/M +Riddle/M +Ride/M +Riefenstahl/M +Riel/M +Riemann/M +Riesling/MS +Riga/M +Rigel/M +Riggs/M +Right +Rigoberto/M +Rigoletto/M +Riley/M +Rilke/M +Rimbaud/M +Ringling/M +Ringo/M +Rio/SM +Rios/M +Ripley/M +Risorgimento/M +Rita/M +Ritalin/M +Ritz/M +Rivas/M +Rivera/M +Rivers/M +Riverside +Riviera/MS +Riyadh/M +Rizal/M +Rn/M +Roach/M +Roanoke/M +Rob/M +Robbie/M +Robbin/MS +Robbins/M +Robby/M +Roberson/M +Robert/MS +Roberta/M +Roberto/M +Roberts/M +Robertson/M +Robeson/M +Robespierre/M +Robin/M +Robinson/M +Robitussin/M +Robles/M +Robson/M +Robt/M +Robyn/M +Rocco/M +Rocha/M +Rochambeau/M +Roche/M +Rochelle/M +Rochester/M +Rock/M +Rockefeller/M +Rockford/M +Rockies/M +Rockne/M +Rockwell/M +Rocky/SM +Rod/M +Roddenberry/M +Roderick/M +Rodger/MS +Rodgers/M +Rodin/M +Rodney/M +Rodolfo/M +Rodrick/M +Rodrigo/M +Rodriguez/M +Rodriquez/M +Roeg/M +Roentgen +Rogelio/M +Roger/MS +Rogers/M +Roget/M +Rojas/M +Roku/M +Rolaids/M +Roland/M +Rolando/M +Rolex/M +Rolland/M +Rollerblade/M +Rollins/M +Rolodex/M +Rolvaag/M +Rom +Roman/MS +Romanesque/MS +Romania/M +Romanian/MS +Romano/M +Romanov/M +Romans/M +Romansh/M +Romantic +Romanticism +Romany/SM +Rome/SM +Romeo/M +Romero/M +Rommel/M +Romney/M +Romulus/M +Ron/M +Ronald/M +Ronda/M +Ronnie/M +Ronny/M +Ronstadt/M +Rontgen +Rooney/M +Roosevelt/M +Root/M +Roquefort/SM +Rorschach/M +Rory/M +Rosa/M +Rosales/M +Rosalie/M +Rosalind/M +Rosalinda/M +Rosalyn/M +Rosanna/M +Rosanne/M +Rosario/M +Roscoe/M +Rose/M +Roseann/M +Roseau/M +Rosecrans/M +Rosella/M +Rosemarie/M +Rosemary/M +Rosenberg/M +Rosendo/M +Rosenzweig/M +Rosetta/M +Rosicrucian/M +Rosie/M +Roslyn/M +Ross/M +Rossetti/M +Rossini/M +Rostand/M +Rostov/M +Rostropovich/M +Roswell/M +Rotarian/M +Roth/M +Rothko/M +Rothschild/M +Rotterdam/M +Rottweiler/M +Rouault/M +Rourke/M +Rousseau/M +Rove/RM +Rover/M +Rowe/M +Rowena/M +Rowland/M +Rowling/M +Roxanne/M +Roxie/M +Roxy/M +Roy/M +Royal/M +Royce/M +Rozelle/M +Rte +Ru/MH +Rubaiyat/M +Rubbermaid/M +Ruben/SM +Rubens/M +Rubicon/MS +Rubik/M +Rubin/M +Rubinstein/M +Ruby/M +Ruchbah/M +Rudolf/M +Rudolph/M +Rudy/M +Rudyard/M +Rufus/M +Rugby +Ruhr/M +Ruiz/M +Rukeyser/M +Rumanian/SM +Rumpelstiltskin/M +Rumsfeld/M +Runnymede/M +Runyon/M +Rupert/M +Rush/M +Rushdie/M +Rushmore/M +Ruskin/M +Russ/M +Russel/M +Russell/M +Russia/M +Russian/SM +Russo/M +Rustbelt/M +Rusty/M +Rutan/M +Rutgers/M +Ruth/M +Rutherford/M +Ruthie/M +Rutledge/M +Rwanda/MS +Rwandan/SM +Rwy +Rx +Ry +Ryan/M +Rydberg/M +Ryder/M +Ryukyu/M +S/MN +SA +SAC +SALT/M +SAM/M +SAP/M +SARS/M +SASE +SAT +SBA +SC/M +SCSI/M +SD +SDI +SE/M +SEATO +SEC/M +SF +SGML/M +SIDS/M +SJ +SJW +SK +SLR +SO/S +SOB/M +SOP/M +SOS/M +SOSes +SPCA +SPF +SQL +SRO +SS +SSA +SSE/M +SSS +SST +SSW/M +ST +STD +STOL +SUSE/M +SUV +SVN/M +SW/M +SWAK +SWAT +Saab/M +Saar/M +Saarinen/M +Saatchi/M +Sabbath/M +Sabbaths +Sabik/M +Sabin/M +Sabina/M +Sabine/M +Sabre/M +Sabrina/M +Sacajawea/M +Sacco/M +Sachs/M +Sacramento/M +Sadat/M +Saddam/M +Sadducee/M +Sade/M +Sadie/M +Sadr/M +Safavid/M +Safeway/M +Sagan/M +Saginaw/M +Sagittarius/MS +Sahara/M +Saharan/M +Sahel/M +Saigon/M +Saiph/M +Sakai/M +Sakha/M +Sakhalin/M +Sakharov/M +Saki/M +Saks/M +Sal/MY +Saladin/M +Salado/M +Salamis/M +Salas/M +Salazar/M +Salem/M +Salerno/M +Salinas/M +Salinger/M +Salisbury/M +Salish/M +Salk/M +Sallie/M +Sallust/M +Sally/M +Salome/M +Salonika/M +Salton/M +Salvador/M +Salvadoran/SM +Salvadorean/MS +Salvadorian/MS +Salvatore/M +Salween/M +Salyut/M +Sam/M +Samantha/M +Samar/M +Samara/M +Samaritan/MS +Samarkand/M +Sammie/M +Sammy/M +Samoa/M +Samoan/SM +Samoset/M +Samoyed/M +Sampson/M +Samson/M +Samsonite/M +Samsung/M +Samuel/M +Samuelson/M +San'a +San/M +Sana/M +Sanaa/M +Sanchez/M +Sancho/M +Sand/ZM +Sandburg/M +Sanders/M +Sandinista/M +Sandoval/M +Sandra/M +Sandy/M +Sanford/M +Sanforized/M +Sang/MR +Sanger/M +Sanhedrin/M +Sanka/M +Sankara/M +Sanskrit/M +Santa/M +Santana/M +Santayana/M +Santeria/M +Santiago/M +Santos/M +Sappho/M +Sapporo/M +Sara/M +Saracen/MS +Saragossa/M +Sarah/M +Sarajevo/M +Saran/M +Sarasota/M +Saratov/M +Sarawak/M +Sardinia/M +Sargasso/M +Sargent/M +Sargon/M +Sarnoff/M +Saroyan/M +Sarto/M +Sartre/M +Sasha/M +Sask +Saskatchewan/M +Saskatoon/M +Sasquatch/MS +Sassanian/M +Sassoon/M +Sat/M +Satan/M +Satanism/M +Satanist/M +Saturday/MS +Saturn/M +Saturnalia/M +Saudi/MS +Saul/M +Saunders/M +Saundra/M +Saussure/M +Sauternes +Savage/M +Savannah/M +Savior/M +Savonarola/M +Savoy/M +Savoyard/M +Sawyer/M +Saxon/MS +Saxony/M +Sayers/M +Sb/M +Sc/M +Scala/M +Scan +Scandinavia/M +Scandinavian/MS +Scaramouch/M +Scarborough/M +Scarlatti/M +Scheat/M +Schedar/M +Scheherazade/M +Schelling/M +Schenectady/M +Schiaparelli/M +Schick/M +Schiller/M +Schindler/M +Schlesinger/M +Schliemann/M +Schlitz/M +Schmidt/M +Schnabel/M +Schnauzer/M +Schneider/M +Schoenberg/M +Schopenhauer/M +Schrieffer/M +Schrodinger/M +Schroeder/M +Schrödinger/M +Schubert/M +Schultz/M +Schulz/M +Schumann/M +Schumpeter/M +Schuyler/M +Schuylkill/M +Schwartz/M +Schwarzenegger/M +Schwarzkopf/M +Schweitzer/M +Schweppes/M +Schwinger/M +Schwinn/M +Scientologist/SM +Scientology/M +Scipio/M +Scopes/M +Scorpio/SM +Scorpius/M +Scorsese/M +Scot/SM +Scotch/MS +Scotchman/M +Scotchmen/M +Scotchwoman/M +Scotchwomen/M +Scotia/M +Scotland/M +Scotsman/M +Scotsmen/M +Scotswoman/M +Scotswomen/M +Scott/M +Scottie/SM +Scottish/M +Scottsdale/M +Scrabble/MS +Scranton/M +Scriabin/M +Scribner/M +Scripture/SM +Scrooge/M +Scruggs/M +Scud/M +Sculley/M +Scylla/M +Scythia/M +Scythian/M +Se/MH +Seaborg/M +Seagram/M +Sean/M +Sears/M +Seattle/M +Sebastian/M +Sec +Seconal/M +Secretariat/M +Secretary +Seder/MS +Sedna/M +Seebeck/M +Seeger/M +Sega/M +Segovia/M +Segre/M +Segundo/M +Seiko/M +Seine/M +Seinfeld/M +Sejong/M +Selassie/M +Selectric/M +Selena/M +Seleucid/M +Seleucus/M +Selim/M +Seljuk/M +Selkirk/M +Sellers/M +Selma/M +Selznick/M +Semarang/M +Seminole/MS +Semiramis/M +Semite/MS +Semitic/SM +Semtex/M +Senate/MS +Sendai/M +Seneca/MS +Senegal/M +Senegalese/M +Senghor/M +Senior/M +Sennacherib/M +Sennett/M +Sensurround/M +Seoul/M +Sep +Sephardi/M +Sepoy/M +Sept/M +September/MS +Septuagint/MS +Sequoya/M +Serb/SM +Serbia/M +Serbian/MS +Serena/M +Serengeti/M +Sergei/M +Sergio/M +Serpens/M +Serra/M +Serrano/M +Set/M +Seth/M +Seton/M +Seurat/M +Seuss/M +Sevastopol/M +Severn/M +Severus/M +Seville/M +Sevres/M +Seward/M +Sextans/M +Sexton/M +Seychelles/M +Seyfert/M +Seymour/M +Sgt +Shackleton/M +Shaffer/M +Shah/M +Shaka/M +Shaker +Shakespeare/M +Shakespearean/M +Shana/M +Shane/M +Shanghai/M +Shankara/M +Shanna/M +Shannon/M +Shantung/M +Shapiro/M +Shari'a/M +Shari/M +Sharif/M +Sharlene/M +Sharon/M +Sharp/M +Sharpe/M +Sharron/M +Shasta/M +Shaula/M +Shaun/M +Shauna/M +Shavian/M +Shavuot/M +Shaw/M +Shawn/M +Shawna/M +Shawnee/SM +Shcharansky/M +Shea/M +Sheba/M +Shebeli/M +Sheena/M +Sheetrock/M +Sheffield/M +Sheila/M +Shelby/M +Sheldon/M +Shelia/M +Shell/M +Shelley/M +Shelly/M +Shelton/M +Shenandoah/M +Shenyang/M +Sheol/M +Shepard/M +Shepherd/M +Sheppard/M +Sheratan/M +Sheraton/M +Sheree/M +Sheri/M +Sheridan/M +Sherlock/M +Sherman/M +Sherpa/M +Sherri/M +Sherrie/M +Sherry/M +Sherwood/M +Sheryl/M +Shetland/SM +Shetlands/M +Shevardnadze/M +Shevat/M +Shi'ite/M +Shields/M +Shiite/MS +Shijiazhuang/M +Shikoku/M +Shillong/M +Shiloh/M +Shinto/MS +Shintoism/MS +Shintoist/MS +Shiraz/M +Shirley/M +Shiva/M +Shockley/M +Short/M +Shorthorn/M +Shoshone/SM +Shostakovitch/M +Shrek/M +Shreveport/M +Shriner/M +Shropshire/M +Shula/M +Shylock/M +Shylockian/M +Si/M +Siam/M +Siamese/M +Sian/M +Sibelius/M +Siberia/M +Siberian/MS +Sibyl/M +Sicilian/SM +Sicily/M +Sid/M +Siddhartha/M +Sidney/M +Siegfried/M +Siemens/M +Sierpinski/M +Sierras +Sigismund/M +Sigmund/M +Sigurd/M +Sihanouk/M +Sikh/M +Sikhism +Sikhs +Sikkim/M +Sikkimese/M +Sikorsky/M +Silas/M +Silesia/M +Silurian/SM +Silva/M +Silvia/M +Simenon/M +Simmental/M +Simmons/M +Simon/M +Simone/M +Simpson/SM +Simpsons/M +Sims/M +Sinai/M +Sinatra/M +Sinbad/M +Sinclair/M +Sindbad/M +Sindhi/M +Singapore/M +Singaporean/SM +Singer/M +Singh/M +Singleton/M +Sinhalese/M +Sinkiang/M +Sioux/M +Sir/SM +Sirius/M +Sister/MS +Sistine/M +Sisyphean/M +Sisyphus/M +Siva/M +Sivan/M +Sjaelland/M +Skinner/M +Skippy/M +Skopje/M +Skye/M +Skylab/M +Skype/M +Slackware/M +Slashdot/M +Slater/M +Slav/SM +Slavic/M +Slavonic/M +Slinky/M +Sloan/M +Sloane/M +Slocum/M +Slovak/SM +Slovakia/M +Slovakian +Slovene/SM +Slovenia/M +Slovenian/MS +Slurpee/M +Sm/M +Small/M +Smetana/M +Smirnoff/M +Smith/M +Smithson/M +Smithsonian/M +Smokey/M +Smolensk/M +Smollett/M +Smuts/M +Smyrna +Sn/M +Snake/M +Snapple/M +Snead/M +Snell/M +Snickers/M +Snider/M +Snoopy/M +Snow/M +Snowbelt/M +Snyder/M +Soave/M +Soc +Socorro/M +Socrates/M +Socratic/M +Soddy/M +Sodom/M +Sofia/M +Soho/M +Sol/M +Solis/M +Solomon/M +Solon/M +Solzhenitsyn/M +Somali/SM +Somalia/M +Somalian/MS +Somme/M +Somoza/M +Son/M +Sondheim/M +Sondra/M +Songhai/M +Songhua/M +Sonia/M +Sonja/M +Sonny/M +Sonora/M +Sontag/M +Sony/M +Sonya/M +Sophia/M +Sophie/M +Sophoclean/M +Sophocles/M +Sopwith/M +Sorbonne/M +Sosa/M +Soto/M +Souphanouvong/M +Sourceforge/M +Sousa/M +South/M +Southampton/M +Southeast/MS +Southern/ZR +Southerner/M +Southey/M +Souths +Southwest/MS +Soviet/M +Soweto/M +Soyinka/M +Soyuz/M +Sp +Spaatz/M +Spackle/M +Spahn/M +Spain/M +Spam/M +Span +Spanglish +Spaniard/SM +Spanish/M +Sparks/M +Sparta/M +Spartacus/M +Spartan/MS +Spears/M +Speer/M +Spence/RM +Spencer/M +Spencerian/M +Spengler/M +Spenglerian/M +Spenser/M +Spenserian/M +Sperry/M +Sphinx/M +Spica/M +Spielberg/M +Spillane/M +Spinoza/M +Spinx/M +Spiro/M +Spirograph/M +Spitsbergen/M +Spitz/M +Spock/M +Spokane/M +Springfield/M +Springsteen/M +Sprint/M +Sprite/M +Sputnik/M +Sq +Squanto/M +Squibb/M +Sr/M +Srinagar/M +Srivijaya/M +St +Sta +Stacey/M +Staci/M +Stacie/M +Stacy/M +Stael/M +Stafford/M +StairMaster/M +Stalin/M +Stalingrad/M +Stalinist/M +Stallone/M +Stamford/M +Stan/M +Standish/M +Stanford/M +Stanislavsky/M +Stanley/M +Stanton/M +Staples/M +Starbucks/M +Stark/M +Starkey/M +Starr/M +Statehouse/MS +Staten/M +States +Stateside +Staubach/M +Ste +Steadicam/M +Steele/M +Stefan/M +Stefanie/M +Stein/MR +Steinbeck/M +Steinem/M +Steiner/M +Steinmetz/M +Steinway/M +Stella/M +Stendhal/M +Stengel/M +Stephan/M +Stephanie/M +Stephen/MS +Stephens/M +Stephenson/M +Sterling/M +Stern/M +Sterne/M +Sterno/M +Stetson/M +Steuben/M +Steve/M +Steven/MS +Stevens/M +Stevenson/M +Stevie/M +Stewart/M +Stieglitz/M +Stilton/SM +Stimson/M +Stine/M +Stirling/M +Stockhausen/M +Stockholm/M +Stockton/M +Stoic/SM +Stoicism/MS +Stokes/M +Stolichnaya/M +Stolypin/M +Stone/M +Stonehenge/M +Stoppard/M +Stout/M +Stowe/M +Strabo/M +Stradivari +Stradivarius/M +Strasbourg/M +Strauss/M +Stravinsky/M +Streisand/M +Strickland/M +Strindberg/M +Stromboli/M +Strong/M +Stu/M +Stuart/MS +Studebaker/M +Stuttgart/M +Stuyvesant/M +Stygian/M +Styrofoam/SM +Styron/M +Styx/M +Suarez/M +Subaru/M +Sucre/M +Sucrets/M +Sudan/M +Sudanese/M +Sudetenland/M +Sudoku/M +Sudra/M +Sue/M +Suetonius/M +Suez/M +Suffolk/M +Sufi/M +Sufism/M +Suharto/M +Sui/M +Sukarno/M +Sukkot +Sukkoth/M +Sukkoths +Sulawesi/M +Suleiman/M +Sulla/M +Sullivan/M +Sumatra/M +Sumatran/SM +Sumeria/M +Sumerian/SM +Summer/MS +Summers/M +Sumner/M +Sumter/M +Sun/SM +Sunbeam/M +Sunbelt/M +Sundanese/M +Sundas/M +Sunday/MS +Sung/M +Sunkist/M +Sunni/SM +Sunnite/MS +Sunnyvale/M +Superbowl/M +Superfund/M +Superglue/M +Superior/M +Superman/M +Supt +Surabaja +Surabaya/M +Surat/M +Suriname/M +Surinamese +Surya/M +Susan/M +Susana/M +Susanna/M +Susanne/M +Susie/M +Susquehanna/M +Sussex/M +Sutherland/M +Sutton/M +Suva/M +Suwanee/M +Suzanne/M +Suzette/M +Suzhou/M +Suzuki/M +Suzy/M +Svalbard/M +Sven/M +Svengali/M +Sverdlovsk +Swahili/SM +Swammerdam/M +Swanee/M +Swansea/M +Swanson/M +Swazi/SM +Swaziland/M +Swed/N +Swede/SM +Sweden/M +Swedenborg/M +Swedish/M +Sweeney/M +Sweet/M +Swift/M +Swinburne/M +Swiss/MS +Swissair/M +Switz +Switzerland/M +Sybil/M +Sydney/M +Sykes/M +Sylvester/M +Sylvia/M +Sylvie/M +Synge/M +Syracuse/M +Syria/M +Syriac/M +Syrian/MS +Szilard/M +Szymborska/M +Sèvres/M +T'ang/M +T/MDG +TA +TARP +TB/M +TBA +TD +TDD +TEFL +TELNET/S +TELNETTed +TELNETTing +TESL +TESOL +TGIF +THC +TKO/M +TLC/M +TM +TN +TNT/M +TOEFL +TQM +TV/SM +TVA +TWA/M +TWX +TX +Ta/M +Tabasco/SM +Tabatha/M +Tabernacle/MS +Tabitha/M +Tabriz/MS +Tacitus/M +Tacoma/M +Tad/M +Tadzhik/M +Taegu/M +Taejon/M +Taft/M +Tagalog/SM +Tagore/M +Tagus/M +Tahiti/M +Tahitian/MS +Tahoe/M +Taichung/M +Tainan +Taine/M +Taipei/M +Taiping/M +Taiwan/M +Taiwanese/M +Taiyuan/M +Tajikistan/M +Taklamakan/M +Talbot/M +Taliban/M +Taliesin/M +Tallahassee/M +Tallchief/M +Talley/M +Talleyrand/M +Tallinn/M +Talmud/MS +Talmudic +Talmudist +Tamara/M +Tameka/M +Tamera/M +Tamerlane/M +Tami/M +Tamika/M +Tamil/MS +Tammany/M +Tammi/M +Tammie/M +Tammuz/M +Tammy/M +Tampa/M +Tampax/M +Tamra/M +Tamworth/M +Tancred/M +Taney/M +Tanganyika/M +Tangier/MS +Tangshan/M +Tania/M +Tanisha/M +Tanner/M +Tannhauser/M +Tannhäuser/M +Tantalus/M +Tanya/M +Tanzania/M +Tanzanian/SM +Tao/M +Taoism/MS +Taoist/MS +Tara/M +Tarantino/M +Tarawa/M +Tarazed/M +Tarbell/M +Target/M +Tarim/M +Tarkenton/M +Tarkington/M +Tartar/MS +Tartary/M +Tartuffe/M +Tarzan/M +Tasha/M +Tashkent/M +Tasman/M +Tasmania/M +Tasmanian/M +Tass/M +Tatar/MS +Tate/M +Tatum/M +Taurus/MS +Tawney/M +Taylor/M +Tb/M +Tbilisi/M +Tc/M +Tchaikovsky/M +Te/M +TeX +TeXes +Teasdale/M +Technicolor/M +Tecumseh/M +Ted/M +Teddy/M +Teflon/MS +Tegucigalpa/M +Tehran +TelePrompTer +TelePrompter/M +Telemachus/M +Telemann/M +Teletype +Tell/MR +Teller/M +Telugu/M +Tempe +Templar/M +Tenn/M +Tennessean/SM +Tennessee/M +Tennyson/M +Tenochtitlan/M +Teotihuacan/M +Terence/M +Teresa/M +Tereshkova/M +Teri/M +Terkel/M +Terpsichore/M +Terr/M +Terra/M +Terran/M +Terrance/M +Terrell/M +Terrence/M +Terri/M +Terrie/M +Territory +Terry/M +Tertiary/M +Tesla/M +Tess/M +Tessa/M +Tessie/M +Tet/M +Tethys/M +Tetons/M +Teuton/MS +Teutonic/M +Tevet/M +Tex/M +Texaco/M +Texan/MS +Texas/M +Th/M +Thackeray/M +Thad/M +Thaddeus/M +Thai/SM +Thailand/M +Thales/M +Thalia/M +Thames/M +Thanh/M +Thanksgiving/MS +Thant/M +Thar/M +Tharp/M +Thatcher/M +Thea/M +Thebes/M +Theiler/M +Thelma/M +Themistocles/M +Theocritus/M +Theodora/M +Theodore/M +Theodoric/M +Theodosius/M +Theosophy/M +Theravada/M +Theresa/M +Therese/M +Thermopylae/M +Thermos +Theron/M +Theseus/M +Thespian/M +Thespis/M +Thessalonian/SM +Thessaloniki/M +Thessaloníki/M +Thessaly/M +Thieu/M +Thimbu/M +Thimphu +Thomas/M +Thomism/M +Thomistic/M +Thompson/M +Thomson/M +Thor/M +Thorazine/M +Thoreau/M +Thornton/M +Thoroughbred/M +Thorpe/M +Thoth/M +Thrace/M +Thracian/M +Thu +Thucydides/M +Thule/M +Thunderbird/M +Thur/S +Thurber/M +Thurman/M +Thurmond/M +Thursday/SM +Thutmose/M +Ti/M +Tia/M +Tianjin/M +Tiber/M +Tiberius/M +Tibet/M +Tibetan/MS +Ticketmaster/M +Ticonderoga/M +Tide/M +Tienanmen/M +Tientsin/M +Tiffany/M +Tigris/M +Tijuana/M +Tillich/M +Tillman/M +Tilsit/M +Tim/M +Timbuktu/M +Timex/M +Timmy/M +Timon/M +Timor/M +Timothy/M +Timur/M +Timurid/M +Tina/M +Ting/M +Tinkerbell/M +Tinkertoy/M +Tinseltown/M +Tintoretto/M +Tippecanoe/M +Tipperary/M +Tirane +Tiresias/M +Tirol/M +Tirolean +Tisha/M +Tishri/M +Titan/SM +Titania/M +Titanic/M +Titian/M +Titicaca/M +Tito/M +Titus/M +Tl/M +Tlaloc/M +Tlingit/M +Tm/M +Tobago/M +Tobit/M +Toby/M +Tocantins/M +Tocqueville/M +Tod/M +Todd/M +Togo/M +Togolese/M +Tojo/M +Tokay/M +Tokugawa/M +Tokyo/M +Tokyoite +Toledo/MS +Tolkien/M +Tolstoy/M +Toltec/M +Tolyatti/M +Tom/M +Tomas/M +Tombaugh/M +Tomlin/M +Tommie/M +Tommy/M +Tompkins/M +Tomsk/M +Tonga/M +Tongan/MS +Toni/M +Tonia/M +Tonto/M +Tony/M +Tonya/M +Topeka/M +Topsy/M +Torah/M +Torahs +Toronto/M +Torquemada/M +Torrance/M +Torrens/M +Torres/M +Torricelli/M +Tortola/M +Tortuga/M +Torvalds/M +Tory/SM +Tosca/M +Toscanini/M +Toshiba/M +Toto/M +Toulouse/M +Townes/M +Townsend/M +Toynbee/M +Toyoda/M +Toyota/M +Tracey/M +Traci/M +Tracie/M +Tracy/M +Trafalgar/M +Trailways/M +Trajan/M +Tran/M +Transcaucasia/M +Transvaal/M +Transylvania/M +Transylvanian/M +Trappist/SM +Travis/M +Travolta/M +Treasury/SM +Treblinka/M +Trekkie/M +Trent/M +Trenton/M +Trevelyan/M +Trevino/M +Trevor/M +Trey/M +Triangulum/M +Triassic/M +Tricia/M +Trident/M +Trieste/M +Trimurti/M +Trina/M +Trinidad/M +Trinidadian/MS +Trinity/SM +Tripitaka/M +Tripoli/M +Trippe/M +Trisha/M +Tristan/M +Triton/M +Trobriand/M +Troilus/M +Trojan/MS +Trollope/M +Trondheim/M +Tropicana/M +Trotsky/M +Troy/M +Troyes +Truckee/M +Trudeau/M +Trudy/M +Truffaut/M +Trujillo/M +Truman/M +Trumbull/M +Trump/M +Truth/M +Tsimshian/M +Tsiolkovsky/M +Tsitsihar/M +Tsongkhapa/M +Tswana/M +Tu/M +Tuamotu/M +Tuareg/M +Tubman/M +Tucker/M +Tucson/M +Tucuman/M +Tudor/SM +Tue/S +Tues/M +Tuesday/MS +Tulane/M +Tull/M +Tulsa/M +Tulsidas/M +Tums/M +Tungus/M +Tunguska/M +Tunis/M +Tunisia/M +Tunisian/MS +Tunney/M +Tupi/M +Tupperware/M +Tupungato/M +Turgenev/M +Turin/M +Turing/M +Turk/SM +Turkestan/M +Turkey/M +Turkic/MS +Turkish/M +Turkmenistan/M +Turner/M +Turpin/M +Tuscaloosa/M +Tuscan/M +Tuscany/M +Tuscarora/MS +Tuscon/M +Tuskegee/M +Tussaud/M +Tut/M +Tutankhamen/M +Tutsi/M +Tutu/M +Tuvalu/M +Tuvaluan +Twain/M +Tweed/M +Tweedledee/M +Tweedledum/M +Twila/M +Twinkies/M +Twitter/M +Twizzlers/M +Twp +Ty/M +Tycho/M +Tylenol/M +Tyler/M +Tyndale/M +Tyndall/M +Tyre/M +Tyree/M +Tyrolean +Tyrone/M +Tyson/M +U/M +UAR +UAW +UBS/M +UCLA/M +UFO/SM +UHF/M +UK/M +UL +UN/M +UNESCO/M +UNICEF/M +UNIX/M +UPC +UPI/M +UPS/M +URL/S +US/M +USA/M +USAF +USB +USCG +USDA/M +USIA +USMC +USN +USO +USP +USPS +USS +USSR/M +UT/M +UTC +UV/M +Ubangi/M +Ubuntu/M +Ucayali/M +Uccello/M +Udall/M +Ufa/M +Uganda/M +Ugandan/MS +Uighur/M +Ujungpandang/M +Ukraine/M +Ukrainian/SM +Ulster/M +Ultrasuede/M +Ulyanovsk/M +Ulysses/M +Umbriel/M +Underwood/M +Ungava/M +Unicode/M +Unilever/M +Union/SM +Unionist +Uniroyal/M +Unitarian/MS +Unitarianism/MS +Unitas/M +Unix/S +Unukalhai/M +Upanishads/M +Updike/M +Upjohn/M +Upton/M +Ur/M +Ural/SM +Urals/M +Urania/M +Uranus/M +Urban/M +Urdu/M +Urey/M +Uriah/M +Uriel/M +Uris/M +Urquhart/M +Ursa/M +Ursula/M +Ursuline/M +Uruguay/M +Uruguayan/MS +Urumqi/M +Usenet/MS +Ustinov/M +Ut +Utah/M +Utahan/MS +Ute/SM +Utopia/SM +Utopian/SM +Utrecht/M +Utrillo/M +Uzbek/M +Uzbekistan/M +Uzi/SM +V/M +VA +VAT/M +VAX +VAXes +VCR/M +VD/M +VDT +VDU +VF +VFW/M +VG +VGA +VHF/M +VHS +VI/M +VIP/SM +VISTA +VJ +VLF/M +VOA +VP +VT +VTOL +Va/M +Vader/M +Vaduz/M +Val/M +Valarie/M +Valdez/M +Valencia/SM +Valenti/M +Valentin/M +Valentine/M +Valentino/M +Valenzuela/M +Valeria/M +Valerian/M +Valerie/M +Valery/M +Valhalla/M +Valium/MS +Valkyrie/SM +Vallejo +Valletta/M +Valois/M +Valparaiso/M +Valvoline/M +Valéry/M +Van/M +Vance/M +Vancouver/M +Vandal/MS +Vanderbilt/M +Vandyke/M +Vanessa/M +Vang/M +Vanuatu/M +Vanzetti/M +Varanasi/M +Varese/M +Vargas/M +Vaseline/SM +Vasquez/M +Vassar/M +Vatican/M +Vauban/M +Vaughan/M +Vaughn/M +Vazquez/M +Veblen/M +Veda/SM +Vedanta/M +Veep +Vega/SM +Vegas/M +Vegemite/M +Vela/M +Velasquez/M +Velazquez/M +Velcro/MS +Velez/M +Velma/M +Velveeta/M +Velásquez/M +Velázquez/M +Venetian/SM +Venezuela/M +Venezuelan/SM +Venice/M +Venn/M +Ventolin/M +Venus/MS +Venusian/M +Vera/M +Veracruz/M +Verde/M +Verdi/M +Verdun/M +Verizon/M +Verlaine/M +Vermeer/M +Vermont/ZMR +Vermonter/M +Vern/M +Verna/M +Verne/M +Vernon/M +Verona/M +Veronese/M +Veronica/M +Versailles/M +Vesalius/M +Vespasian/M +Vespucci/M +Vesta/M +Vesuvius/M +Viacom/M +Viagra/M +Vic/M +Vicente/M +Vichy/M +Vicki/M +Vickie/M +Vicksburg/M +Vicky/M +Victor/M +Victoria/M +Victorian/MS +Victorianism +Victrola/M +Vidal/M +Vienna/M +Viennese/M +Vientiane/M +Vietcong/M +Vietminh/M +Vietnam/M +Vietnamese/M +Vijayanagar/M +Vijayawada/M +Viking/MS +Vila/M +Villa/M +Villarreal/M +Villon/M +Vilma/M +Vilnius/M +Vilyui/M +Vince/M +Vincent/M +Vindemiatrix/M +Vinson/M +Viola/M +Violet/M +Virgie/M +Virgil/M +Virginia/M +Virginian/SM +Virgo/SM +Visa/M +Visakhapatnam/M +Visayans/M +Vishnu/M +Visigoth/M +Visigoths +Vistula/M +Vitim/M +Vito/M +Vitus/M +Vivaldi/M +Vivekananda/M +Vivian/M +Vivienne/M +Vlad/M +Vladimir/M +Vladivostok/M +Vlaminck/M +Vlasic/M +VoIP +Vogue/M +Volcker/M +Voldemort/M +Volga/M +Volgograd/M +Volkswagen/M +Volstead/M +Volta/M +Voltaire/M +Volvo/M +Vonda/M +Vonnegut/M +Voronezh/M +Vorster/M +Voyager/M +Vt +Vuitton/M +Vulcan/M +Vulg +Vulgate/SM +W/MDT +WA +WAC +WASP/M +WATS/M +WC +WHO/M +WI +WMD +WNW/M +WP +WSW/M +WTO +WV +WW +WWI +WWII +WWW/M +WY +WYSIWYG +Wabash/M +Wac +Waco/M +Wade/M +Wagner/M +Wagnerian/M +Wahhabi/M +Waikiki/M +Waite/M +Wake/M +Waksman/M +Wald/MN +Waldemar/M +Walden/M +Waldensian/M +Waldheim/M +Waldo/M +Waldorf/M +Wales/M +Walesa/M +Walgreen/M +Walker/M +Walkman/M +Wall/SMR +Wallace/M +Wallenstein/M +Waller/M +Wallis/M +Walloon/M +Walls/M +Walmart/M +Walpole/M +Walpurgisnacht/M +Walsh/M +Walt/MRZ +Walter/M +Walters/M +Walton/M +Wanamaker/M +Wanda/M +Wang/M +Wankel/M +Ward/M +Ware/MG +Warhol/M +Waring/M +Warner/M +Warren/M +Warsaw/M +Warwick/M +Wasatch/M +Wash/M +Washington/M +Washingtonian/MS +Wassermann/M +Waterbury/M +Waterford/M +Watergate/M +Waterloo/MS +Waters/M +Watkins/M +Watson/M +Watt/SM +Watteau/M +Watts/M +Watusi/M +Waugh/M +Wave +Wayne/M +Weaver/M +Web/MR +Webb/M +Weber/M +Webern/M +Webster/MS +Wed/M +Weddell/M +Wedgwood/M +Wednesday/MS +Weeks/M +Wehrmacht/M +Wei/M +Weierstrass/M +Weill/M +Weinberg/M +Weiss/M +Weissmuller/M +Weizmann/M +Weldon/M +Welland/M +Weller/M +Welles/M +Wellington/SM +Wells/M +Welsh/M +Welshman/M +Welshmen/M +Welshwoman +Wendell/M +Wendi/M +Wendy/M +Wesak/M +Wesley/M +Wesleyan/M +Wessex/M +Wesson/M +West/SM +Western/MRS +Westinghouse/M +Westminster/M +Weston/M +Westphalia/M +Weyden/M +Wezen/M +Wharton/M +Wheaties/M +Wheatstone/M +Wheeler/M +Wheeling/M +Whig/SM +Whipple/M +Whirlpool/M +Whistler/M +Whitaker/M +White/SM +Whitefield/M +Whitehall/M +Whitehead/M +Whitehorse/M +Whiteley/M +Whitfield/M +Whitley/M +Whitman/M +Whitney/M +Whitsunday/MS +Whittier/M +WiFi +Wicca/M +Wichita/M +Wiemar/M +Wiesel/M +Wiesenthal/M +Wiggins/M +Wigner/M +Wii/M +Wikileaks +Wikipedia/M +Wilberforce/M +Wilbert/M +Wilbur/M +Wilburn/M +Wilcox/M +Wilda/M +Wilde/MR +Wilder/M +Wiles/M +Wiley/M +Wilford/M +Wilfred/M +Wilfredo/M +Wilhelm/M +Wilhelmina/M +Wilkerson/M +Wilkes/M +Wilkins/M +Wilkinson/M +Will/M +Willa/M +Willamette/M +Willard/M +Willemstad/M +William/SM +Williams/M +Williamson/M +Willie/M +Willis/M +Willy/M +Wilma/M +Wilmer/M +Wilmington/M +Wilson/M +Wilsonian/M +Wilton/M +Wimbledon/M +Wimsey/M +Winchell/M +Winchester/MS +Windbreaker/M +Windex/M +Windhoek/M +Windows/M +Windsor/SM +Windward/M +Winesap/M +Winfred/M +Winfrey/M +Winifred/M +Winkle/M +Winnebago/M +Winnie/M +Winnipeg/M +Winston/M +Winters/M +Winthrop/M +Wis +Wisc +Wisconsin/M +Wisconsinite/MS +Wise/M +Witt/M +Wittgenstein/M +Witwatersrand/M +Wm/M +Wobegon/M +Wodehouse/M +Wolf/M +Wolfe/M +Wolff/M +Wolfgang/M +Wollongong/M +Wollstonecraft/M +Wolsey/M +Wolverhampton +Wonder/M +Wonderbra/M +Wong/M +Wood/SM +Woodard/M +Woodhull/M +Woodrow/M +Woods/M +Woodstock/M +Woodward/M +Woolf/M +Woolite/M +Woolongong/M +Woolworth/M +Wooster/M +Wooten/M +Worcester/SM +Worcestershire/M +Wordsworth/M +Workman/M +Worms/M +Wotan/M +Wovoka/M +Wozniak/M +Wozzeck/M +Wrangell/M +Wren/M +Wright/M +Wrigley/M +Wroclaw/M +Wu/M +Wuhan/M +Wurlitzer/M +Wyatt/M +Wycherley/M +Wycliffe/M +Wyeth/M +Wylie/M +Wynn/M +Wyo +Wyoming/M +Wyomingite/SM +X/M +XEmacs/M +XL/M +XML +XS +XXL +Xanadu/M +Xanthippe/M +Xavier/M +Xe/SM +Xenakis/M +Xenia/M +Xenophon/M +Xerox/MS +Xerxes/M +Xhosa/M +Xi'an/M +Xian/SM +Xiaoping/M +Ximenes/M +Xingu/M +Xiongnu/M +Xmas/MS +Xochipilli/M +Xuzhou/M +Y/M +YMCA/M +YMHA +YMMV +YT +YWCA/M +YWHA +Yacc/M +Yahoo/M +Yahtzee/M +Yahweh/M +Yakima/M +Yakut/M +Yakutsk/M +Yale/M +Yalow/M +Yalta/M +Yalu/M +Yamagata/M +Yamaha/M +Yamoussoukro/M +Yang/M +Yangon/M +Yangtze/M +Yank/SM +Yankee/SM +Yaobang/M +Yaounde/M +Yaqui/M +Yaren +Yaroslavl/M +Yataro/M +Yates/M +Yb/M +Yeager/M +Yeats/M +Yekaterinburg/M +Yellowknife/M +Yellowstone/M +Yeltsin/M +Yemen/M +Yemeni/SM +Yemenite +Yenisei/M +Yerevan/M +Yerkes/M +Yesenia/M +Yevtushenko/M +Yggdrasil/M +Yiddish/M +Ymir/M +Yoda/M +Yoknapatawpha/M +Yoko/M +Yokohama/M +Yolanda/M +Yong/M +Yonkers/M +York/M +Yorkie/M +Yorkshire/MS +Yorktown/M +Yoruba/M +Yosemite/M +Yossarian/M +YouTube/M +Young/M +Youngstown/M +Ypres/M +Ypsilanti/M +Yuan/M +Yucatan/M +Yugo/M +Yugoslav/MS +Yugoslavia/M +Yugoslavian/SM +Yukon/M +Yule/SM +Yuletide/MS +Yuma/SM +Yunnan/M +Yuri/M +Yves/M +Yvette/M +Yvonne/M +Z/SMNXT +Zachariah/M +Zachary/M +Zachery/M +Zagreb/M +Zaire/M +Zairian +Zambezi/M +Zambia/M +Zambian/SM +Zamboni/M +Zamenhof/M +Zamora/M +Zane/M +Zanuck/M +Zanzibar/M +Zapata/M +Zaporozhye/M +Zapotec/M +Zappa/M +Zara/M +Zarathustra/M +Zealand/M +Zebedee/M +Zechariah/M +Zedekiah/M +Zedong/M +Zeffirelli/M +Zeke/M +Zelig/M +Zelma/M +Zen/M +Zenger/M +Zeno/M +Zephaniah/M +Zephyrus/M +Zeppelin/M +Zest/M +Zeus/M +Zhdanov +Zhengzhou/M +Zhivago/M +Zhukov/M +Zibo/M +Ziegfeld/M +Ziegler/M +Ziggy/M +Zika +Zimbabwe/M +Zimbabwean/SM +Zimmerman/M +Zinfandel/M +Zion/SM +Zionism/SM +Zionist/SM +Ziploc/M +Zn/M +Zoe/M +Zola/M +Zollverein/M +Zoloft/M +Zomba/M +Zorn/M +Zoroaster/M +Zoroastrian/MS +Zoroastrianism/SM +Zorro/M +Zosma/M +Zr/M +Zsigmondy/M +Zubenelgenubi/M +Zubeneschamali/M +Zukor/M +Zulu/SM +Zululand +Zuni/M +Zurich/M +Zwingli/M +Zworykin/M +Zyrtec/M +Zyuganov/M +Zzz +Zürich/M +a/S +aah +aardvark/SM +ab/SDY +aback +abacus/MS +abaft +abalone/SM +abandon/LSDG +abandonment/M +abase/LGDS +abasement/M +abash/GLDS +abashed/UY +abashment/M +abate/LGDS +abated/U +abatement/M +abattoir/MS +abbe/SM +abbess/MS +abbey/MS +abbot/MS +abbr +abbrev/S +abbreviate/DSGNX +abbreviation/M +abbé/SM +abdicate/GNDSX +abdication/M +abdomen/SM +abdominal +abduct/DSG +abductee/MS +abduction/SM +abductor/MS +abeam +aberrant +aberration/MS +aberrational +abet/S +abetted +abetter/SM +abetting +abettor/SM +abeyance/M +abhor/S +abhorred +abhorrence/M +abhorrent/Y +abhorring +abidance/M +abide/GS +abiding/Y +ability/IEMS +abject/YP +abjection/M +abjectness/M +abjuration/SM +abjuratory +abjure/ZGDRS +abjurer/M +ablate/XGNVDS +ablation/M +ablative/MS +ablaze +able/UT +abler +abloom +ablution/SM +abnegate/GNDS +abnegation/M +abnormal/Y +abnormality/SM +aboard +abode/MS +abolish/GDS +abolition/M +abolitionism/M +abolitionist/SM +abominable +abominably +abominate/DSGNX +abomination/M +aboriginal/MS +aborigine/SM +aborning +abort/GVDS +abortion/MS +abortionist/MS +abortive/Y +abound/DSG +about +above/M +aboveboard +abracadabra/M +abrade/GDS +abrasion/MS +abrasive/MYPS +abrasiveness/M +abreast +abridge/DSG +abridgment/MS +abroad +abrogate/XGNDS +abrogation/M +abrogator/MS +abrupt/TPRY +abruptness/M +abs/M +abscess/MDSG +abscissa/SM +abscission/M +abscond/ZGSDR +absconder/M +abseil/MDSG +absence/SM +absent/DYSG +absentee/MS +absenteeism/M +absentminded/YP +absentmindedness/M +absinthe/M +absolute/PMYTNS +absoluteness/M +absolution/M +absolutism/M +absolutist/MS +absolve/DSG +absorb/AGDS +absorbance +absorbency/M +absorbent/SM +absorbing/Y +absorption/M +absorptive +abstain/DRZGS +abstainer/M +abstemious/PY +abstemiousness/M +abstention/MS +abstinence/M +abstinent +abstract/GSPMDY +abstracted/YP +abstractedness/M +abstraction/SM +abstractness/MS +abstruse/YP +abstruseness/M +absurd/TPRY +absurdist/MS +absurdity/SM +absurdness/M +abundance/SM +abundant/Y +abuse's +abuse/EGVDS +abuser/MS +abusive/YP +abusiveness/M +abut/SL +abutment/MS +abutted +abutting +abuzz +abysmal/Y +abyss/MS +abyssal +ac +acacia/MS +academe/M +academia/M +academic/SM +academical/Y +academician/MS +academy/SM +acanthus/MS +accede/GDS +accelerate/GNXDS +acceleration/M +accelerator/SM +accent/MDSG +accented/U +accentual +accentuate/GNDS +accentuation/M +accept/DSBG +acceptability/M +acceptableness/M +acceptably/U +acceptance/SM +acceptation/MS +accepted/U +access/MDSG +accessibility/IM +accessible/I +accessibly/I +accession/MDGS +accessorize/DSG +accessory/SM +accident/MS +accidental/SMY +acclaim/MDGS +acclamation/M +acclimate/DSGN +acclimation/M +acclimatization/M +acclimatize/DSG +acclivity/SM +accolade/SM +accommodate/XGNDS +accommodating/Y +accommodation/M +accompanied/U +accompaniment/MS +accompanist/SM +accompany/DSG +accomplice/SM +accomplish/DSLG +accomplished/U +accomplishment/MS +accord/GMDS +accordance/M +accordant +according/Y +accordion/MS +accordionist/MS +accost/GMDS +account/MDSBG +accountability/M +accountable/U +accountancy/M +accountant/MS +accounted/U +accounting/M +accouter/SGD +accouterments/M +accoutre/DSG +accoutrements +accredit/SGD +accreditation/M +accredited/U +accretion/MS +accrual/MS +accrue/GDS +acct +acculturate/DSGN +acculturation/M +accumulate/XGNVDS +accumulation/M +accumulator/MS +accuracy/IM +accurate/IY +accurateness/M +accursed/P +accursedness/M +accusation/MS +accusative/MS +accusatory +accuse/ZGDRS +accuser/M +accusing/Y +accustom/DSG +accustomed/U +ace/DSMG +acerbate/DSG +acerbic +acerbically +acerbity/M +acetaminophen/M +acetate/MS +acetic +acetone/M +acetonic +acetyl +acetylene/M +ache/DSMG +achene/MS +achieve/BLZGDRS +achievement/SM +achiever/M +aching/Y +achoo/M +achromatic +achy/TR +acid/SMY +acidic +acidify/GDS +acidity/M +acidosis/M +acidulous +acknowledge/DSGL +acknowledged/U +acknowledgement/MS +acknowledgment/SM +acme/SM +acne/M +acolyte/MS +aconite/MS +acorn/MS +acoustic/S +acoustical/Y +acoustics/M +acquaint/AGSD +acquaintance/SM +acquaintanceship/M +acquainted/U +acquiesce/DSG +acquiescence/M +acquiescent/Y +acquire/ZGBDRSL +acquirement/M +acquisition/MS +acquisitive/YP +acquisitiveness/M +acquit/S +acquittal/MS +acquitted +acquitting +acre/SM +acreage/MS +acrid/PTRY +acridity/M +acridness/M +acrimonious/YP +acrimoniousness/M +acrimony/M +acrobat/MS +acrobatic/S +acrobatically +acrobatics/M +acronym/MS +acrophobia/M +acropolis/MS +across +acrostic/SM +acrylamide +acrylic/MS +act's +act/ASDGV +acting/M +actinium/M +action/ASM +actionable +activate/ICANGSD +activation/ICAM +activator/MS +active's +active/IKY +activeness/M +actives +activism/M +activist/MS +activities +activity/IM +actor/AMS +actress/MS +actual/Y +actuality/SM +actualization/M +actualize/GDS +actuarial +actuary/SM +actuate/GNDS +actuation/M +actuator/SM +acuity/M +acumen/M +acupressure/M +acupuncture/M +acupuncturist/SM +acute/PMYTRS +acuteness/M +acyclovir/M +acyl +ad/SM +adage/MS +adagio/MS +adamant/MY +adapt/BZGVDRS +adaptability/M +adaptation/MS +adapter/M +adaption/S +add/SDRBZG +addend/MS +addenda +addendum/M +adder/M +addible +addict/GVMDS +addiction/SM +addition/SM +additional/Y +additive/SM +addle/GDS +address's +address/AGDS +addressable +addressed/U +addressee/SM +adduce/GDS +adenine/M +adenocarcinoma +adenoid/SM +adenoidal +adept/MYPS +adeptness/M +adequacy/IM +adequate/IY +adequateness/M +adhere/GDS +adherence/M +adherent/SM +adhesion/M +adhesive/PSM +adhesiveness/M +adiabatic +adieu/MS +adios +adipose +adiós +adj +adjacency/M +adjacent/Y +adjectival/Y +adjective/MS +adjoin/GDS +adjourn/DGLS +adjournment/SM +adjudge/GDS +adjudicate/GNVXDS +adjudication/M +adjudicator/SM +adjudicatory +adjunct/MS +adjuration/MS +adjure/GDS +adjust/AGDSL +adjustable +adjuster/SM +adjustment/AMS +adjutant/SM +adman/M +admen +admin/S +administer/DGS +administrate/XDSGNV +administration/M +administrative/Y +administrator/MS +admirably +admiral/MS +admiralty/M +admiration/M +admire/BZGDRS +admirer/M +admiring/Y +admissibility/IM +admissible/I +admissibly +admission/AM +admissions +admit/AS +admittance/M +admitted/Y +admitting/A +admix/GDS +admixture/SM +admonish/LDSG +admonishment/MS +admonition/MS +admonitory +ado/M +adobe/MS +adolescence/SM +adolescent/SM +adopt/AGVDS +adoptable +adopter/MS +adoption/SM +adorableness/M +adorably +adoration/M +adore/BZGDRS +adorer/M +adoring/Y +adorn/LGDS +adorned/U +adornment/MS +adrenal/MS +adrenalin's +adrenaline/M +adrenergic +adrift +adroit/PY +adroitness/M +adsorb/SDG +adsorbent/MS +adsorption/SM +adulate/DSGN +adulation/M +adulator/MS +adulatory +adult/MS +adulterant/MS +adulterate/GNDS +adulterated/U +adulteration/M +adulterer/SM +adulteress/MS +adulterous +adultery/SM +adulthood/M +adumbrate/GNDS +adumbration/M +adv +advance/LDSMG +advancement/SM +advantage/EDSMG +advantageous/EY +advent/SM +adventitious/Y +adventure/DRSMZG +adventurer/M +adventuresome +adventuress/MS +adventurism +adventurist/S +adventurous/YP +adventurousness/M +adverb/SM +adverbial/SMY +adversarial +adversary/SM +adverse/PRYT +adverseness/M +adversity/SM +advert/SMDG +advertise/LZGDRS +advertised/U +advertisement/MS +advertiser/M +advertising/M +advertorial/SM +advice/M +advisability/IM +advisable/I +advisably +advise/LDRSZGB +advised/UY +advisement/M +adviser/M +advisor/SM +advisory/SM +advocacy/M +advocate/MGDS +advt +adware +adz/MS +adze/M +aegis/M +aeon/SM +aerate/DSGN +aeration/M +aerator/SM +aerial/SMY +aerialist/MS +aerie/MS +aerobatic/S +aerobatics/M +aerobic/S +aerobically +aerobics/M +aerodrome/MS +aerodynamic/S +aerodynamically +aerodynamics/M +aerogram/S +aerogramme/S +aeronautic/S +aeronautical +aeronautics/M +aerosol/MS +aerospace/M +aesthete/MS +aesthetic/S +aesthetically +aestheticism/M +aesthetics/M +afar +affability/M +affable +affably +affair/MS +affect's +affect/EGDS +affectation/SM +affected/UY +affecting/Y +affection/EM +affectionate/Y +affections +afferent +affiance/GDS +affidavit/SM +affiliate's +affiliate/EGNDS +affiliated/U +affiliation/EM +affiliations +affinity/SM +affirm/AGDS +affirmation/AMS +affirmative/MYS +affix/GMDS +afflatus/M +afflict/GDS +affliction/SM +affluence/M +affluent/Y +afford/GDSB +affordability +affordably +afforest/EGSD +afforestation/M +affray/MS +affront/GMDS +afghan/MS +aficionado/MS +afield +afire +aflame +afloat +aflutter +afoot +aforementioned +aforesaid +aforethought +afoul +afraid/U +afresh +aft/RZ +afterbirth/M +afterbirths +afterburner/MS +aftercare/M +aftereffect/MS +afterglow/SM +afterimage/MS +afterlife/M +afterlives +aftermarket/MS +aftermath/M +aftermaths +afternoon/MS +aftershave/SM +aftershock/SM +aftertaste/SM +afterthought/SM +afterward/S +afterword/MS +again +against +agape/M +agar/M +agate/MS +agave/M +age/DSMGJ +ageing/SM +ageism/M +ageist/SM +ageless/YP +agelessness/M +agency/SM +agenda/SM +agent/AMS +ageratum/M +agglomerate/DSMGNX +agglomeration/M +agglutinate/DSXGN +agglutination/M +aggrandize/GLDS +aggrandizement/M +aggravate/GNXDS +aggravating/Y +aggravation/M +aggregate/MGNDSX +aggregation/M +aggression/M +aggressive/PY +aggressiveness/M +aggressor/SM +aggrieve/DSG +aggro +aghast +agile/Y +agility/M +aging/M +agitate/XGNDS +agitation/M +agitator/MS +agitprop/M +agleam +aglitter +aglow +agnostic/MS +agnosticism/M +ago +agog +agonist/S +agonize/GDS +agonizing/Y +agony/SM +agoraphobia/M +agoraphobic/MS +agrarian/MS +agrarianism/M +agree/EBLDS +agreeableness/EM +agreeably/E +agreeing/E +agreement/ESM +agribusiness/MS +agricultural/Y +agriculturalist/MS +agriculture/M +agriculturist/MS +agronomic +agronomist/MS +agronomy/M +aground +ague/M +ah +aha +ahchoo +ahead +ahem +ahoy +aid/SMDG +aide/SM +aided/U +aigrette/MS +ail/SDLG +aileron/SM +ailment/SM +aim/SMDG +aimless/YP +aimlessness/M +ain't +air/SMDJG +airbag/MS +airbase/SM +airbed/S +airborne +airbrush/MDSG +airbus/MS +aircraft/M +aircraftman +aircraftmen +aircrew/S +airdrome/S +airdrop/SM +airdropped +airdropping +airfare/SM +airfield/SM +airflow/M +airfoil/SM +airfreight/M +airgun/S +airhead/SM +airily +airiness/M +airing/M +airless/P +airlessness/M +airletter/S +airlift/SGMD +airline/RSMZ +airliner/M +airlock/SM +airmail/GSMD +airman/M +airmen +airplane/MS +airplay/M +airport/SM +airship/SM +airshow/S +airsick/P +airsickness/M +airspace/M +airspeed +airstrike/MS +airstrip/SM +airtight +airtime/M +airwaves/M +airway/MS +airwoman +airwomen +airworthiness/M +airworthy/P +airy/PTR +aisle/MS +aitch/MS +ajar +aka +akimbo +akin +alabaster/M +alack +alacrity/M +alarm/GMDS +alarming/Y +alarmist/SM +alas +alb/SM +albacore/SM +albatross/MS +albeit +albinism/M +albino/MS +album/MNS +albumen/M +albumin/M +albuminous +alchemist/SM +alchemy/M +alcohol/SM +alcoholic/MS +alcoholically +alcoholism/M +alcove/MS +alder/MS +alderman/M +aldermen +alderwoman/M +alderwomen +ale/SMV +aleatory +alehouse/SM +alembic/SM +alert/GMDYPS +alertness/M +alewife/M +alewives +alfalfa/M +alfresco +alga/M +algae +algal +algebra/SM +algebraic +algebraically +algorithm/SM +algorithmic +alias/GMDS +alibi/GMDS +alien/BGMDS +alienable/IU +alienate/DSGN +alienation/M +alienist/SM +alight/GDS +align/ALGDS +aligned/U +aligner/MS +alignment/AMS +alike/U +aliment/MDSG +alimentary +alimony/M +aliveness/M +aliyah/M +aliyahs +alkali/MS +alkalies +alkaline +alkalinity/M +alkalize/DSG +alkaloid/SM +alkyd/MS +all/M +allay/GDS +allegation/MS +allege/GDS +alleged/Y +allegiance/MS +allegoric +allegorical/Y +allegorist/MS +allegory/SM +allegretto/MS +allegro/MS +allele/MS +alleluia/SM +allergen/SM +allergenic +allergic +allergically +allergist/SM +allergy/SM +alleviate/DSGN +alleviation/M +alley/MS +alleyway/SM +alliance/SM +alligator/MS +alliterate/DSXGNV +alliteration/M +alliterative/Y +allocate/ADSGN +allocation/AM +allocations +allot/LS +allotment/SM +allotted +allotting +allover +allow/EGDS +allowable/U +allowably +allowance/SM +alloy/GMDS +alloyed/U +allspice/M +allude/GDS +allure/MGLDS +allurement/MS +alluring/Y +allusion/SM +allusive/PY +allusiveness/M +alluvial/M +alluvium/SM +ally/GDSM +almanac/SM +almighty +almond/MS +almoner/SM +almost +alms/M +almshouse/MS +aloe/SM +aloft +aloha/MS +alone +along +alongshore +alongside +aloof/PY +aloofness/M +aloud +alp/SM +alpaca/MS +alpha/MS +alphabet/SM +alphabetic +alphabetical/Y +alphabetization/SM +alphabetize/ZGDRS +alphabetizer/M +alphanumeric +alphanumerical/Y +alpine/S +already +alright +also +alt/S +altar/MS +altarpiece/SM +alter/GDBS +alterable/U +alteration/MS +altercation/SM +altered/U +alternate/DSMYGNVX +alternation/M +alternative/MYS +alternator/SM +although +altimeter/MS +altitude/MS +alto/SM +altogether +altruism/M +altruist/SM +altruistic +altruistically +alum/SM +alumina/M +aluminum/M +alumna/M +alumnae +alumni +alumnus/M +alveolar/S +always +am/N +amalgam/SM +amalgamate/XGNDS +amalgamation/M +amanuenses +amanuensis/M +amaranth/M +amaranths +amaretto/M +amaryllis/MS +amass/GDS +amateur/SM +amateurish/YP +amateurishness/M +amateurism/M +amatory +amaze/LMGDS +amazement/M +amazing/Y +amazon/MS +amazonian +ambassador/SM +ambassadorial +ambassadorship/MS +ambassadress/MS +amber/M +ambergris/M +ambiance/MS +ambidexterity/M +ambidextrous/Y +ambience/MS +ambient +ambiguity/SM +ambiguous/UY +ambit +ambition/MS +ambitious/YP +ambitiousness/M +ambivalence/M +ambivalent/Y +amble/MZGDRS +ambler/M +ambrosia/M +ambrosial +ambulance/MS +ambulanceman +ambulancemen +ambulancewoman +ambulancewomen +ambulant +ambulate/DSXGN +ambulation/M +ambulatory/SM +ambuscade/MGDS +ambush/GMDS +ameba/MS +amebae +amebic +ameboid +ameliorate/GNVDS +amelioration/M +amen/B +amenability/M +amenably +amend/BLGDS +amendment/SM +amenity/SM +amerce/GLDS +amercement/SM +americium/M +amethyst/SM +amiability/M +amiable +amiably +amicability/M +amicable +amicably +amid +amide/MS +amidship/S +amidst +amigo/MS +amino +amir/SM +amiss +amity/M +ammeter/SM +ammo/M +ammonia/M +ammonium +ammunition/M +amnesia/M +amnesiac/MS +amnesic/SM +amnesty/GDSM +amniocenteses +amniocentesis/M +amnion/MS +amniotic +amoeba/MS +amoebae +amoebic +amok +among +amontillado/SM +amoral/Y +amorality/M +amorous/YP +amorousness/M +amorphous/PY +amorphousness/M +amortization/SM +amortize/DSGB +amount/GMDS +amour/MS +amoxicillin +amp/SMY +amperage/M +ampere/MS +ampersand/MS +amphetamine/SM +amphibian/MS +amphibious/Y +amphitheater/SM +amphora/M +amphorae +ampicillin +ample/TR +amplification/M +amplifier/M +amplify/NDRSXZG +amplitude/SM +ampoule/MS +ampule/MS +amputate/GNDSX +amputation/M +amputee/MS +amt +amuck +amulet/MS +amuse/LGDS +amusement/MS +amusing/Y +amylase/M +an/CS +anabolism/M +anachronism/SM +anachronistic +anachronistically +anaconda/SM +anaerobe/SM +anaerobic +anaerobically +anagram/MS +anal/Y +analgesia/M +analgesic/SM +analog/MS +analogical/Y +analogize/GDS +analogous/YP +analogousness/M +analogue/SM +analogy/SM +analysand/MS +analyses/A +analysis/AM +analyst/SM +analytic +analytical/Y +analyticalally +analyzable +analyze/ADSG +analyzer/SM +anapest/SM +anapestic/MS +anarchic +anarchically +anarchism/M +anarchist/MS +anarchistic +anarchy/M +anathema/SM +anathematize/DSG +anatomic +anatomical/Y +anatomist/SM +anatomize/DSG +anatomy/SM +ancestor/SM +ancestral/Y +ancestress/MS +ancestry/SM +anchor/MDGS +anchorage/MS +anchorite/MS +anchorman/M +anchormen +anchorpeople +anchorperson/SM +anchorwoman/M +anchorwomen +anchovy/SM +ancient/SPMRYT +ancientness/M +ancillary/SM +and +andante/SM +andiron/SM +androgen/M +androgenic +androgynous +androgyny/M +android/SM +anecdotal/Y +anecdote/MS +anemia/M +anemic +anemically +anemometer/SM +anemone/SM +anent +anesthesia/M +anesthesiologist/SM +anesthesiology/M +anesthetic/SM +anesthetist/MS +anesthetization/SM +anesthetize/GDS +aneurysm/SM +anew +angel/MS +angelfish/MS +angelic +angelica/M +angelical/Y +anger/GMDS +angina/M +angioplasty/SM +angiosperm/SM +angle/MZGDRS +angler/M +angleworm/MS +anglicism/S +anglicize/GDS +angling/M +anglophile/S +anglophone/S +angora/MS +angostura +angrily +angry/TR +angst/M +angstrom/MS +anguish/GMDS +angular +angularity/SM +angulation +anhydrous +aniline/M +animadversion/MS +animadvert/GSD +animal/MS +animalcule/SM +animate/ADSGN +animated/Y +animation/AM +animations +animator/MS +anime/M +animism/M +animist/SM +animistic +animosity/SM +animus/M +anion/MS +anionic +anise/M +aniseed/M +anisette/M +ankh/M +ankhs +ankle/MS +anklebone/MS +anklet/MS +annalist/SM +annals/M +anneal/GDS +annelid/MS +annex/GMDS +annexation/MS +annihilate/DSGN +annihilation/M +annihilator/SM +anniversary/SM +annotate/DSXGNV +annotation/M +annotator/MS +announce/DRSLZG +announced/U +announcement/MS +announcer/M +annoy/GDS +annoyance/MS +annoying/Y +annual/MYS +annualized +annuitant/SM +annuity/SM +annul/LS +annular +annulled +annulling +annulment/SM +annunciation/SM +anode/MS +anodize/GDS +anodyne/MS +anoint/GDLS +anointment/M +anomalous/Y +anomaly/SM +anon/S +anonymity/M +anonymous/Y +anopheles/M +anorak/MS +anorectic/SM +anorexia/M +anorexic/MS +another +answer/BMDGS +answerable/U +answered/U +answerphone/S +ant/SMD +antacid/SM +antagonism/SM +antagonist/SM +antagonistic +antagonistically +antagonize/DSG +antarctic +ante/SM +anteater/MS +antebellum +antecedence/M +antecedent/SM +antechamber/SM +antedate/GDS +antediluvian +anteing +antelope/MS +antenatal +antenna/SM +antennae +anterior +anteroom/MS +anthem/MS +anther/MS +anthill/SM +anthologist/SM +anthologize/DSG +anthology/SM +anthracite/M +anthrax/M +anthropocentric +anthropoid/MS +anthropological/Y +anthropologist/SM +anthropology/M +anthropomorphic +anthropomorphically +anthropomorphism/M +anthropomorphize +anthropomorphous +anti/SM +antiabortion +antiabortionist/MS +antiaircraft +antibacterial/MS +antibiotic/MS +antibody/SM +antic/MS +anticancer +antichrist/SM +anticipate/GNXDS +anticipated/U +anticipation/M +anticipatory +anticked +anticking +anticlerical +anticlimactic +anticlimactically +anticlimax/MS +anticline/SM +anticlockwise +anticoagulant/MS +anticommunism/M +anticommunist/SM +anticyclone/SM +anticyclonic +antidemocratic +antidepressant/MS +antidote/MS +antifascist/MS +antifreeze/M +antigen/SM +antigenic +antigenicity/M +antihero/M +antiheroes +antihistamine/SM +antiknock/M +antilabor +antilogarithm/SM +antimacassar/MS +antimalarial +antimatter/M +antimicrobial +antimissile +antimony/M +antinuclear +antioxidant/MS +antiparticle/SM +antipasti +antipasto/MS +antipathetic +antipathy/SM +antipersonnel +antiperspirant/SM +antiphon/SM +antiphonal/MYS +antipodal/S +antipodean/MS +antipodes/M +antipollution +antipoverty +antiquarian/SM +antiquarianism/M +antiquary/SM +antiquate/GDS +antique/DSMG +antiquity/SM +antirrhinum/S +antiscience +antisemitic +antisemitism/M +antisepsis/M +antiseptic/SM +antiseptically +antiserum/MS +antislavery +antisocial/Y +antispasmodic/MS +antisubmarine +antitank +antitheses +antithesis/M +antithetic +antithetical/Y +antitoxin/MS +antitrust +antivenin/MS +antivenom +antiviral/MS +antivirus +antivivisectionist/MS +antiwar +antler/MDS +antonym/SM +antonymous +antrum +antsy/TR +anus/MS +anvil/MS +anxiety/SM +anxious/YP +anxiousness/M +any +anybody/SM +anyhow +anymore +anyone/M +anyplace +anything/SM +anytime +anyway/S +anywhere +anywise +aorta/MS +aortic +apace +apart +apartheid/M +apartment/MS +apathetic +apathetically +apathy/M +apatite/M +ape/DSMG +apelike +aperitif/MS +aperture/SM +apex/MS +aphasia/M +aphasic/MS +aphelia +aphelion/SM +aphid/MS +aphorism/MS +aphoristic +aphoristically +aphrodisiac/SM +apiarist/SM +apiary/SM +apical/Y +apiece +apish/Y +aplenty +aplomb/M +apocalypse/SM +apocalyptic +apocrypha/M +apocryphal/Y +apogee/MS +apolitical/Y +apologetic/U +apologetically +apologia/SM +apologist/MS +apologize/GDS +apology/SM +apoplectic +apoplexy/SM +apoptosis +apoptotic +apostasy/SM +apostate/SM +apostatize/GDS +apostle/MS +apostleship/M +apostolic +apostrophe/MS +apothecary/SM +apothegm/SM +apotheoses +apotheosis/M +app/SM +appall/GDS +appalling/Y +appaloosa/MS +apparatchik/S +apparatus/MS +apparel/MDGS +apparent/Y +apparition/SM +appeal/GMDS +appealing/UY +appear/AESDG +appearance/EAMS +appease/LZGDRS +appeasement/SM +appeaser/M +appellant/SM +appellate/XN +appellation/M +append/GDS +appendage/SM +appendectomy/SM +appendices +appendicitis/M +appendix/MS +appertain/GDS +appetite/SM +appetizer/MS +appetizing/Y +applaud/ZGDRS +applauder/M +applause/M +apple/MS +applejack/M +applesauce/M +applet/MS +appliance/SM +applicability/M +applicable/I +applicably +applicant/SM +application/AM +applicator/SM +applier/MS +applique/DSM +appliqueing +appliqué/SMG +appliquéd +apply/ANXGDS +appoint/AELSVGD +appointee/SM +appointment's/A +appointment/ESM +apportion/AGDLS +apportionment/AM +appose/GDS +apposite/YNVP +appositeness/M +apposition/M +appositive/SM +appraisal/AMS +appraise/ADSG +appraiser/MS +appreciable/I +appreciably/I +appreciate/DSXGNV +appreciated/U +appreciation/M +appreciative/Y +appreciator/MS +appreciatory +apprehend/GDS +apprehension/MS +apprehensive/YP +apprehensiveness/M +apprentice/DSMG +apprenticeship/MS +apprise/GDS +approach/GBMDS +approachable/UI +approbation/EM +approbations +appropriate/PYGNXDS +appropriated/U +appropriateness/IM +appropriation/M +appropriator/SM +approval/EM +approvals +approve/EGDS +approved/U +approving/EY +approx +approximate/DSXYGN +approximation/M +appurtenance/SM +appurtenant +apricot/MS +apron/MS +apropos +apse/SM +apt/IYPT +apter +aptitude/SM +aptness/IM +aqua/SM +aquaculture/M +aqualung/MS +aquamarine/SM +aquanaut/MS +aquaplane/MGDS +aquarium/MS +aquatic/SM +aquatically +aquatics/M +aquatint/S +aquavit/M +aqueduct/MS +aqueous +aquifer/SM +aquiline +arabesque/MS +arability/M +arachnid/MS +arachnophobia +arbiter/SM +arbitrage/MZGDRS +arbitrager/M +arbitrageur/SM +arbitrament/SM +arbitrarily +arbitrariness/M +arbitrary/P +arbitrate/GNDS +arbitration/M +arbitrator/MS +arbor/MS +arboreal +arboretum/SM +arborvitae/SM +arbutus/MS +arc/SMDG +arcade/MS +arcane +arch/PZTGVMDRSY +archaeological/Y +archaeologist/SM +archaeology/M +archaic +archaically +archaism/MS +archaist/MS +archangel/MS +archbishop/SM +archbishopric/SM +archdeacon/SM +archdiocesan +archdiocese/MS +archduchess/MS +archduke/MS +archenemy/SM +archeological/Y +archeologist/SM +archeology/M +archer/M +archery/M +archetypal +archetype/MS +archfiend/MS +archiepiscopal +archipelago/MS +archipelagoes +architect/SM +architectonic/S +architectonics/M +architectural/Y +architecture/MS +architrave/SM +archival +archive/DSMG +archivist/MS +archness/M +archway/SM +arctic/MS +ardent/Y +ardor/MS +arduous/YP +arduousness/M +are/SMB +area/SM +areal +aren't +arena/MS +argent/M +arginine +argon/M +argosy/SM +argot/MS +arguable/IU +arguably/U +argue/ZGDRS +arguer/M +argument/MS +argumentation/M +argumentative/PY +argumentativeness/M +argyle/MS +aria/SM +arid/Y +aridity/M +aright +arise/GS +arisen +aristocracy/SM +aristocrat/SM +aristocratic +aristocratically +arithmetic/M +arithmetical/Y +arithmetician/MS +ark/SM +arm's +arm/EAGDS +armada/MS +armadillo/SM +armament/AEM +armaments +armature/MS +armband/MS +armchair/MS +armed/U +armful/MS +armhole/SM +armistice/SM +armlet/MS +armload/S +armor/ZGMDRS +armored/U +armorer/M +armorial +armory/SM +armpit/MS +armrest/SM +army/SM +aroma/MS +aromatherapist/MS +aromatherapy/M +aromatic/MS +aromatically +arose +around +arousal/M +arouse/GDS +arpeggio/MS +arr +arraign/DGSL +arraignment/SM +arrange/AESDLG +arrangement's/E +arrangement/ASM +arranger/SM +arrant +arras/MS +array/EGMDS +arrears/M +arrest/AGMDS +arrhythmia/M +arrhythmic +arrhythmical +arrival/MS +arrive/GDS +arrogance/M +arrogant/Y +arrogate/GNDS +arrogation/M +arrow/MS +arrowhead/MS +arrowroot/M +arroyo/MS +arsed +arsenal/MS +arsenic/M +arsing +arson/M +arsonist/SM +art/SM +arterial +arteriole/MS +arteriosclerosis/M +artery/SM +artful/PY +artfulness/M +arthritic/MS +arthritis/M +arthropod/MS +arthroscope/SM +arthroscopic +arthroscopy +artichoke/SM +article/MDS +articulacy/I +articular +articulate/YGNPDSX +articulateness/IM +articulation/M +artifact/SM +artifice/RSMZ +artificer/M +artificial/Y +artificiality/M +artillery/M +artilleryman/M +artillerymen +artiness/M +artisan/MS +artist/MS +artiste/MS +artistic/I +artistically +artistry/M +artless/PY +artlessness/M +artsy/TR +artwork/MS +arty/PTR +arugula +arum/SM +asap +asbestos/M +ascend/AGDS +ascendance/M +ascendancy/M +ascendant/SM +ascension/MS +ascent/MS +ascertain/GDSBL +ascertainment/M +ascetic/MS +ascetically +asceticism/M +ascot/MS +ascribe/GBDS +ascription/M +aseptic +aseptically +asexual/Y +asexuality/M +ash/MDNSG +ashamed/UY +ashcan/MS +ashlar/MS +ashore +ashram/MS +ashtray/SM +ashy/TR +aside/MS +asinine/Y +asininity/SM +ask/SDG +askance +asked/U +askew +aslant +asleep +asocial +asp/SMNX +asparagus/M +aspartame/M +aspect/MS +aspen/M +asperity/SM +aspersion/MS +asphalt/MDGS +asphodel/SM +asphyxia/M +asphyxiate/DSXGN +asphyxiation/M +aspic/MS +aspidistra/MS +aspirant/MS +aspirate/MGNDSX +aspiration/M +aspirator/SM +aspire/GDS +aspirin/MS +ass/MS +assail/GBDS +assailable/U +assailant/SM +assassin/SM +assassinate/GNXDS +assassination/M +assault/MDRGS +assay/ZGMDRS +assayer/M +assemblage/SM +assemble/AEGSD +assembler/MS +assemblies +assembly/AM +assemblyman/M +assemblymen +assemblywoman/M +assemblywomen +assent/GMDS +assert/AGVDS +assertion/AM +assertions +assertive/YP +assertiveness/M +assess/ALGDS +assessment/ASM +assessor/MS +asset/MS +asseverate/DSGN +asseveration/M +asshole/MS! +assiduity/M +assiduous/PY +assiduousness/M +assign's +assign/ALGDS +assignable +assignation/MS +assigned/U +assignee/M +assigner/MS +assignment/AMS +assignor/MS +assimilate/DSGN +assimilation/M +assist/GMDS +assistance/M +assistant/SM +assisted/U +assize/MS +assn +assoc +associate's +associate/EDSGNV +association/EM +associations +assonance/M +assonant/MS +assort/GLDS +assortment/MS +asst +assuage/GDS +assume/BGDS +assumption/SM +assumptive +assurance/ASM +assure/AGDS +assured/MYS +astatine/M +aster/EMS +asterisk/GMDS +astern +asteroid/MS +asthma/M +asthmatic/SM +asthmatically +astigmatic +astigmatism/SM +astir +astonish/DSLG +astonishing/Y +astonishment/M +astound/GDS +astounding/Y +astraddle +astrakhan/M +astral +astray +astride +astringency/M +astringent/SMY +astrolabe/SM +astrologer/SM +astrological/Y +astrologist/MS +astrology/M +astronaut/MS +astronautic/S +astronautical +astronautics/M +astronomer/SM +astronomic +astronomical/Y +astronomy/M +astrophysical +astrophysicist/MS +astrophysics/M +astute/PYTR +astuteness/M +asunder +asylum/SM +asymmetric +asymmetrical/Y +asymmetry/SM +asymptomatic +asymptotic +asymptotically +asynchronous/Y +at +atavism/M +atavist/SM +atavistic +ataxia/M +ataxic/MS +ate +atelier/SM +atheism/M +atheist/MS +atheistic +atherosclerosis/M +atherosclerotic +athirst +athlete/MS +athletic/S +athletically +athleticism +athletics/M +athwart +atilt +atishoo +atlas/MS +atmosphere/MS +atmospheric/S +atmospherically +atmospherics/M +atoll/MS +atom/SM +atomic +atomically +atomize/ZGDRS +atomizer/M +atonal/Y +atonality/M +atone/LGDS +atonement/M +atop +atria +atrial +atrioventricular +atrium/M +atrocious/PY +atrociousness/M +atrocity/SM +atrophy/DSMG +atropine/M +attach/ALGDS +attache/BM +attached/U +attachment/AM +attachments +attaché/MS +attack/ZGMDRS +attacker/M +attain/AGDS +attainability/M +attainable/U +attainder/M +attainment/SM +attar/M +attempt's +attempt/ASDG +attend/SDRZG +attendance/SM +attendant/SM +attended/U +attendee/SM +attention/IM +attentions +attentive/IPY +attentiveness/IM +attenuate/DSGN +attenuation/M +attest/SDG +attestation/SM +attested/U +attic/SM +attire/DSMG +attitude/SM +attitudinal +attitudinize/GDS +attn +attorney/MS +attract/SGVDB +attractant/MS +attraction/MS +attractive/UY +attractiveness/M +attribute/DSMGNVBX +attributed/U +attribution/M +attributive/MYS +attrition/M +attune/DSG +atty +atwitter +atypical/Y +aubergine/S +auburn/M +auction/MDGS +auctioneer/SM +audacious/YP +audaciousness/M +audacity/M +audibility/IM +audible/MS +audibly/I +audience/MS +audio/MS +audiological +audiologist/SM +audiology/M +audiometer/SM +audiophile/SM +audiotape/SM +audiovisual/S +audiovisuals/M +audit/GMDS +audition/SMDG +auditor/MS +auditorium/SM +auditory +auger/MS +aught/MS +augment/DRZGS +augmentation/MS +augmentative +augmenter/M +augur/GMDS +augury/SM +august/PTRY +augustness/M +auk/SM +aunt/SM +auntie/SM +aura/MS +aural/Y +aureola/M +aureole/SM +aureus +auricle/SM +auricular +aurora/SM +auscultate/GNDSX +auscultation/M +auspice/SM +auspicious/IY +auspiciousness/M +austere/RYT +austerity/SM +austral +authentic/IU +authentically +authenticate/XGNDS +authenticated/U +authentication/M +authenticity/M +author/SMDG +authoress/MS +authorial +authoritarian/MS +authoritarianism/M +authoritative/YP +authoritativeness/M +authority/SM +authorization/MS +authorize/AGDS +authorized/U +authorship/M +autism/M +autistic +auto/MS +autobahn/SM +autobiographer/SM +autobiographic +autobiographical/Y +autobiography/SM +autoclave/MS +autocracy/SM +autocrat/SM +autocratic +autocratically +autocross +autodidact/SM +autograph/MDG +autographs +autoimmune +autoimmunity/M +automaker/SM +automate/GNDS +automatic/SM +automatically +automation/M +automatism/M +automatize/GDS +automaton/SM +automobile/DSMG +automotive +autonomic +autonomous/Y +autonomy/M +autopilot/SM +autopsy/GDSM +autosuggestion +autoworker/MS +autumn/SM +autumnal +aux +auxiliary/SM +auxin/M +av/RZ +avail/BGMDS +availability/UM +available/U +avalanche/SM +avarice/M +avaricious/Y +avast +avatar/MS +avaunt +avdp +ave +avenge/ZGDRS +avenger/M +avenue/MS +average/MYGDS +averred +averring +averse/XN +aversion/M +avert/GDS +avg +avian +aviary/SM +aviation/M +aviator/MS +aviatrices +aviatrix/MS +avid/Y +avidity/M +avionic/S +avionics/M +avitaminosis/M +avocado/SM +avocation/MS +avocational +avoid/SDGB +avoidable/U +avoidably/U +avoidance/M +avoirdupois/M +avouch/DSG +avow/EDGS +avowal/ESM +avowed/Y +avuncular/Y +aw +await/GDS +awake/GS +awaken/AGDS +awakening/SM +award/GMDS +awardee/S +aware/UP +awareness/UM +awash +away +awe/DSMG +aweigh +awesome/YP +awesomeness/M +awestruck +awful/YP +awfuller +awfullest +awfulness/M +awhile +awkward/RYPT +awkwardness/M +awl/SM +awn/GJSM +awning/M +awoke +awoken +awol +awry +ax/MDSG +axial/Y +axiom/SM +axiomatic +axiomatically +axis/M +axle/MS +axletree/SM +axolotl/SM +axon/MS +ayah/M +ayahs +ayatollah/M +ayatollahs +aye/SM +azalea/SM +azimuth/M +azimuths +azure/SM +b/KDT +baa/SMDG +babble/MZGDRS +babbler/M +babe/SM +babel/MS +baboon/MS +babushka/SM +baby/TGDRSM +babyhood/M +babyish +babysat +babysit/S +babysitter/MS +babysitting/M +baccalaureate/SM +baccarat/M +bacchanal/MS +bacchanalia/M +bacchanalian/MS +baccy +bachelor/SM +bachelorhood/M +bacillary +bacilli +bacillus/M +back/SJZGMDR +backache/MS +backbench/S +backbit +backbite/ZGRS +backbiter/M +backbitten +backboard/SM +backbone/MS +backbreaking +backchat +backcloth +backcloths +backcomb/DSG +backdate/GDS +backdoor +backdrop/MS +backer/M +backfield/SM +backfire/MGDS +backgammon/M +background/MRZS +backgrounder/M +backhand/MDRSZG +backhanded/Y +backhander/M +backhoe/MS +backing/M +backlash/MS +backless +backlog/MS +backlogged +backlogging +backpack/ZGMDRS +backpacker/M +backpacking/M +backpedal/SDG +backrest/SM +backroom/S +backscratching/M +backseat/SM +backside/SM +backslapper/SM +backslapping/M +backslash/MS +backslid +backslide/RSZG +backslider/M +backspace/DSMG +backspin/M +backstabber/MS +backstabbing +backstage/M +backstair/S +backstop/SM +backstopped +backstopping +backstory/S +backstreet/S +backstretch/MS +backstroke/MGDS +backtalk/M +backtrack/SDG +backup/MS +backward/PSY +backwardness/M +backwash/M +backwater/SM +backwoods/M +backwoodsman/M +backwoodsmen +backyard/SM +bacon/M +bacteria/M +bacterial +bactericidal +bactericide/SM +bacteriologic +bacteriological +bacteriologist/SM +bacteriology/M +bacterium/M +bad/MYP +badder +baddest +baddie/M +baddy/SM +bade +badge/MZRS +badger/GMD +badinage/M +badlands/M +badman/M +badmen +badminton/M +badmouth/GD +badmouths +badness/M +baffle/MZGDRSL +bafflement/M +baffler/M +bag/SM +bagatelle/SM +bagel/MS +bagful/MS +baggage/M +bagged +baggie/M +baggily +bagginess/M +bagging +baggy/PTRS +bagpipe/MZRS +bagpiper/M +baguette/MS +bah +baht/SM +bail/SBGMD +bailey/S +bailiff/S +bailiwick/MS +bailout/SM +bailsman/M +bailsmen +bairn/MS +bait/SGMD +baize/M +bake/DRSMZG +baked/U +baker/M +bakery/SM +bakeshop/MS +baklava/M +baksheesh/M +balaclava/MS +balalaika/MS +balance's +balance/UDSG +balboa/SM +balcony/SM +bald/STGPDRY +balderdash/M +baldfaced +baldness/M +baldric/SM +baldy/S +bale/DRSMZG +baleen/M +baleful/PY +balefulness/M +baler/M +balk/SGMD +balky/RT +ball/SGMD +ballad/SM +balladeer/MS +balladry/M +ballast/GSMD +ballcock/MS +ballerina/SM +ballet/SM +balletic +ballgame/MS +ballgirl/S +ballgown/S +ballistic/S +ballistics/M +balloon/SGMD +balloonist/MS +ballot/SMDG +ballpark/MS +ballplayer/MS +ballpoint/MS +ballroom/MS +balls/DSG +ballsy/RT +bally +ballyhoo/SMDG +balm/SM +balminess/M +balmy/RTP +baloney/M +balsa/MS +balsam/SM +balsamic +baluster/SM +balustrade/MS +bamboo/SM +bamboozle/DSG +ban/SM +banal/Y +banality/SM +banana/SM +band's +band/ESGD +bandage/DSMG +bandana/SM +bandanna/MS +bandbox/MS +bandeau/M +bandeaux +bandit/SM +banditry/M +bandleader/S +bandmaster/SM +bandoleer/SM +bandolier/SM +bandsman/M +bandsmen +bandstand/SM +bandwagon/SM +bandwidth +bandwidths +bandy/DRSTG +bane/SM +baneful +bang/SGMDR +bangle/SM +bani +banish/GLDS +banishment/M +banister/SM +banjo/MS +banjoist/SM +bank/SZGBMDR +bankbook/SM +bankcard/SM +banker/M +banking/M +banknote/SM +bankroll/SGMD +bankrupt/SGMD +bankruptcy/SM +banned +banner/SM +banning +bannock/MS +banns/M +banquet/ZGMDRS +banqueter/M +banquette/SM +banshee/MS +bantam/SM +bantamweight/SM +banter/GSMD +bantering/Y +banyan/SM +banzai/SM +baobab/SM +bap/S +baptism/MS +baptismal +baptist/S +baptistery/SM +baptistry/SM +baptize/ZGDRS +baptized/U +baptizer/M +bar's +bar/ECUTS +barb/SZGMDR +barbacoa +barbarian/SM +barbarianism/MS +barbaric +barbarically +barbarism/SM +barbarity/SM +barbarize/DSG +barbarous/Y +barbecue/DSMG +barbel/SM +barbell/MS +barber/GMD +barberry/SM +barbershop/MS +barbie/S +barbiturate/SM +barbwire/M +barcarole/SM +bard/SM +bardic +bare/DRSPYG +bareback/D +barefaced/Y +barefoot/D +barehanded +bareheaded +barelegged +bareness/M +barf/SGMDY +barfly/SM +bargain/MDRZGS +bargainer/M +barge/MGDS +bargeman/M +bargemen +barhop/S +barhopped +barhopping +barista/MS +baritone/MS +barium/M +bark's +bark/CSGD +barkeep/ZMRS +barkeeper/M +barker/SM +barley/M +barmaid/MS +barman/M +barmen +barmy/RT +barn/SM +barnacle/MDS +barney/S +barnstorm/SDRZG +barnstormer/M +barnyard/SM +barometer/MS +barometric +barometrically +baron/MS +baronage/MS +baroness/MS +baronet/MS +baronetcy/SM +baronial +barony/SM +baroque/M +barque/SM +barrack/MDGS +barracuda/SM +barrage/MGDS +barre/MGJDS +barred/UEC +barrel/GSMD +barrelled +barrelling +barren/TPSMR +barrenness/M +barrette/SM +barricade/MGDS +barrier/MS +barring/ECU +barrio/SM +barrister/MS +barroom/MS +barrow/SM +bartender/SM +barter/ZGSMDR +barterer/M +baryon/SM +basal/Y +basalt/M +basaltic +base's +base/CDSLTG +baseball/SM +baseboard/MS +baseless +baseline/MS +basely +baseman/M +basemen +basement/CMS +baseness/M +baser +bash/GMDS +bashful/PY +bashfulness/M +bashing/M +basic/MS +basically +basil/M +basilica/MS +basilisk/MS +basin/MS +basinful/MS +basis/M +bask/SGD +basket/SM +basketball/MS +basketry/M +basketwork/M +basque/S +bass/MS +basset/SM +bassinet/MS +bassist/MS +basso/MS +bassoon/MS +bassoonist/SM +basswood/MS +bast/M +bastard/MS +bastardization/MS +bastardize/GDS +bastardy/M +baste/ZGNXDRS +baster/M +bastion/M +bat/SM +batch/MDSG +bate/KACGSD +bath/ZGMDRS +bathe/M +bather/M +bathetic +bathhouse/MS +bathing/M +bathmat/MS +bathos/M +bathrobe/SM +bathroom/SM +baths +bathtub/MS +bathwater +bathyscaph/MS +bathyscaphe/M +bathyscaphs +bathysphere/MS +batik/MS +batiste/M +batman/M +batmen +baton/MS +batsman/M +batsmen +battalion/SM +batted +batten/GSMD +batter/JZGSMDR +batterer/M +battery/SM +batting/M +battle/LDRSMZG +battleax/MS +battleaxe/M +battledore/SM +battledress +battlefield/MS +battlefront/MS +battleground/MS +battlement/SM +battler/M +battleship/SM +batty/RT +bauble/SM +baud/SM +bauxite/M +bawd/SM +bawdily +bawdiness/M +bawdy/PRT +bawl/SGMD +bay/SMDG +bayberry/SM +bayonet/SMDG +bayou/MS +bazaar/SM +bazillion/S +bazooka/SM +bbl +bdrm +be +beach/MDSG +beachcomber/SM +beachfront +beachhead/MS +beachwear/M +beacon/SM +bead/SGMD +beading/M +beadle/SM +beady/RT +beagle/SM +beak/SZMDR +beaker/M +beam/SGMD +bean/SGMD +beanbag/MS +beanfeast/S +beanie/SM +beanpole/MS +beansprout/S +beanstalk/MS +bear/SZGBJMR +bearable/U +bearably/U +beard/MDGS +beardless +bearer/M +bearing/M +bearish/PY +bearishness/M +bearlike +bearskin/MS +beast/MS +beastliness/M +beastly/TPRM +beat/SZGBMNRJ +beatable/U +beaten/U +beater/M +beatific +beatifically +beatification/M +beatify/GXNDS +beating/M +beatitude/SM +beatnik/MS +beau/SM +beaut/MS +beauteous/Y +beautician/SM +beautification/M +beautifier/M +beautiful/Y +beautify/NDRSZG +beauty/SM +beaux +beaver/SGMD +bebop/MS +becalm/GSD +became +because +beck/SM +beckon/SGD +becloud/GDS +become/S +becoming/UY +becquerel/S +bed/SM +bedaub/GSD +bedazzle/GDSL +bedazzlement/M +bedbug/SM +bedchamber/S +bedclothes/M +bedded +bedder +bedding/M +bedeck/GSD +bedevil/LGDS +bedevilment/M +bedfellow/SM +bedhead/S +bedim/S +bedimmed +bedimming +bedizen/GDS +bedlam/SM +bedpan/SM +bedpost/SM +bedraggle/GDS +bedridden +bedrock/SM +bedroll/SM +bedroom/SM +bedside/SM +bedsit/S +bedsitter/S +bedsore/SM +bedspread/SM +bedstead/SM +bedtime/SM +bee/RSMZGJ +beebread/M +beech/MS +beechnut/MS +beef/SGMD +beefburger/SM +beefcake/MS +beefiness/M +beefsteak/MS +beefy/RPT +beehive/MS +beekeeper/MS +beekeeping/M +beeline/MS +been +beep/SZGMDR +beeper/M +beer/M +beery/TR +beeswax/M +beet/SM +beetle/MGDS +beetroot/S +beeves +befall/SGN +befell +befit/S +befitted +befitting/Y +befog/S +befogged +befogging +before +beforehand +befoul/DGS +befriend/SGD +befuddle/GLDS +befuddlement/M +beg/S +began +begat +beget/S +begetter/S +begetting +beggar/MDYGS +beggary/M +begged +begging +begin/S +beginner/SM +beginning/MS +begone +begonia/SM +begot +begotten +begrime/DSG +begrudge/DSG +begrudging/Y +beguile/DRSZGL +beguilement/M +beguiler/M +beguiling/Y +beguine/SM +begum/MS +begun +behalf/M +behalves +behave/GDS +behavior/SM +behavioral/Y +behaviorism/M +behaviorist/MS +behead/DGS +beheld +behemoth/M +behemoths +behest/MS +behind/MS +behindhand +behold/NRZGS +beholder/M +behoove/DSG +beige/M +being/M +bejewel/SDG +belabor/SDG +belated/Y +belay/GDS +belch/GMDS +beleaguer/GSD +belfry/SM +belie/DS +belief/EUM +beliefs +believable/U +believably/U +believe/EDRSZG +believer/EUMS +believing/U +belittle/LDSG +belittlement/M +bell/SGMD +belladonna/M +bellboy/SM +belle/MS +belled/A +belletrist/MS +belletristic +bellhop/SM +bellicose +bellicosity/M +belligerence/M +belligerency/M +belligerent/MYS +belling/A +bellman/M +bellmen +bellow/MDGS +bellwether/MS +belly/GDSM +bellyache/MGDS +bellybutton/SM +bellyful/MS +belong/JDGS +belonging/M +beloved/SM +below +belt/SGMD +beltway/SM +beluga/MS +belying +bemire/GDS +bemoan/DGS +bemuse/LGDS +bemused/Y +bemusement/M +bench/GMDS +benchmark/MS +bend/BSZGMR +bender/M +bendy/TR +beneath +benedictine +benediction/SM +benedictory +benefaction/SM +benefactor/MS +benefactress/MS +benefice/SM +beneficence/M +beneficent/Y +beneficial/Y +beneficiary/SM +benefit/SMDG +benevolence/SM +benevolent/Y +benighted/Y +benign/Y +benignant +benignity/M +bent/SM +bentwood/M +benumb/DSG +benzene/M +benzine/M +benzyl +bequeath/DG +bequeaths +bequest/MS +berate/GDS +bereave/DSLG +bereavement/MS +bereft +beret/MS +berg/SM +beriberi/M +berk/S +berkelium/M +berm/SM +berry/GDSM +berrylike +berserk +berth/GMD +berths +beryl/MS +beryllium/M +beseech/ZGRS +beseecher/M +beseeching/Y +beseem/DSG +beset/S +besetting +beside/S +besiege/ZGDRS +besieger/M +besmear/DSG +besmirch/GDS +besom/MS +besot/S +besotted +besotting +besought +bespangle/DSG +bespatter/GSD +bespeak/SG +bespectacled +bespoke +bespoken +best/SGMD +bestial/Y +bestiality/M +bestiary/SM +bestir/S +bestirred +bestirring +bestow/DGS +bestowal/SM +bestrew/SDG +bestrewn +bestridden +bestride/SG +bestrode +bestseller/MS +bestselling +bet/SM +beta/SM +betake/GS +betaken +betcha +betel/M +bethink/SG +bethought +betide/GDS +betimes +betoken/GDS +betook +betray/DRZGS +betrayal/SM +betrayer/M +betroth/DG +betrothal/SM +betrothed/M +betroths +better/MDGLS +betterment/M +betting +bettor/MS +between +betwixt +bevel/GMDS +beverage/SM +bevvy/S +bevy/SM +bewail/DGS +beware/GDS +bewhiskered +bewigged +bewilder/LSGD +bewildering/Y +bewilderment/M +bewitch/GLDS +bewitching/Y +bewitchment/M +bey/SM +beyond +bezel/MS +bf +bhaji +bi/SMRZ +biannual/Y +bias/GMDS +biased/U +biassed +biassing +biathlon/SM +bib/SM +bible/MS +biblical +bibliographer/MS +bibliographic +bibliographical/Y +bibliography/SM +bibliophile/SM +bibulous +bicameral +bicameralism/M +bicarb/MS +bicarbonate/MS +bicentenary/SM +bicentennial/SM +bicep/MS +biceps/M +bicker/MDRZGS +bickerer/M +biconcave +biconvex +bicuspid/MS +bicycle/DRSMZG +bicycler/M +bicyclist/SM +bid/SMG +biddable +bidden/U +bidder/MS +bidding/M +biddy/SM +bide/S +bidet/MS +bidirectional/Y +biennial/MYS +biennium/MS +bier/M +biff/SGD +bifocal/S +bifocals/M +bifurcate/XDSGN +bifurcation/M +big/P +bigamist/SM +bigamous +bigamy/M +bigger +biggest +biggie/MS +biggish +bighead/SM +bighearted/P +bigheartedness/M +bighorn/SM +bight/MS +bigmouth/M +bigmouths +bigness/M +bigot/MDS +bigotry/SM +bigwig/MS +bijou/M +bijoux +bike/DRSMZG +biker/M +bikini/MS +bilabial/MS +bilateral/Y +bilberry/S +bile/M +bilge/MS +bilingual/SMY +bilingualism/M +bilious/P +biliousness/M +bilirubin +bilk/SZGDR +bilker/M +bill/SBJGMD +billboard/MS +billet/GMDS +billfold/SM +billhook/S +billiard/S +billiards/M +billing/M +billingsgate/M +billion/MHS +billionaire/SM +billionth/M +billionths +billow/GMDS +billowy +billy/SM +billycan/S +bimbo/MS +bimetallic/SM +bimetallism/M +bimonthly/SM +bin/SM +binary/SM +bind's +bind/AUGS +binder/MS +bindery/SM +binding/MS +bindweed/M +binge/MGDS +bingeing +bingo/M +binman +binmen +binnacle/SM +binned +binning +binocular/MS +binomial/SM +bio/SM +biochemical/SMY +biochemist/MS +biochemistry/M +biodegradability/M +biodegrade/DSGB +biodiversity/M +bioethics/M +biofeedback/M +biog +biographer/SM +biographic +biographical/Y +biography/SM +biol +biologic +biological/Y +biologist/MS +biology/M +biomass/M +biomedical +bionic/S +bionically +bionics/M +biophysical +biophysicist/MS +biophysics/M +biopic/MS +biopsy/GDSM +bioreactor/S +biorhythm/MS +biosensor/S +biosphere/SM +biosynthesis +biotech +biotechnological +biotechnology/M +biotin/M +bipartisan +bipartisanship/M +bipartite +biped/MS +bipedal +biplane/MS +bipolar +bipolarity/M +biracial +birch/GMDS +bird/SZGMDR +birdbath/M +birdbaths +birdbrain/SMD +birdcage/S +birder/M +birdhouse/MS +birdie/MDS +birdieing +birdlike +birdlime/M +birdseed/M +birdsong +birdwatcher/SM +birdying +biretta/SM +birth/ZGMDR +birthday/MS +birther/M +birthmark/MS +birthplace/MS +birthrate/MS +birthright/MS +births/A +birthstone/SM +biscuit/SM +bisect/DGS +bisection/MS +bisector/SM +bisexual/MYS +bisexuality/M +bishop/MS +bishopric/SM +bismuth/M +bison/M +bisque/M +bistro/MS +bit/CSMG +bitch/GMDS +bitchily +bitchiness/M +bitchy/PRT +bitcoin/SM +bite/RSMZ +biter/M +biting/Y +bitmap/S +bitten +bitter/PMRYTS +bittern/SM +bitterness/M +bitters/M +bittersweet/MS +bitty/TR +bitumen/M +bituminous +bivalent +bivalve/SM +bivouac/MS +bivouacked +bivouacking +biweekly/SM +biyearly +biz/M +bizarre/Y +bk +bl/DG +blab/SM +blabbed +blabber/DGS +blabbermouth/M +blabbermouths +blabbing +black/PXTGMDNRYS +blackamoor/MS +blackball/SGMD +blackberry/GSM +blackbird/SM +blackboard/MS +blackcurrant/S +blacken/DG +blackface +blackguard/SM +blackhead/MS +blacking/M +blackish +blackjack/MDGS +blackleg/S +blacklist/MDSG +blackmail/MDRSZG +blackmailer/M +blackness/M +blackout/SM +blacksmith/M +blacksmiths +blacksnake/SM +blackthorn/SM +blacktop/SM +blacktopped +blacktopping +bladder/MS +blade/MDS +blag/S +blagged +blagging +blah/M +blahs/M +blame/BMGDRS +blameable +blameless/YP +blamelessness/M +blameworthiness/M +blameworthy/P +blammo +blanch/GDS +blancmange/MS +bland/PTRY +blandish/DSLG +blandishment/SM +blandness/M +blank/TGPMDRYS +blanket/GMDS +blankness/M +blare/MGDS +blarney/SMDG +blase +blaspheme/ZGDRS +blasphemer/M +blasphemous/Y +blasphemy/SM +blast/ZGMDRS +blaster/M +blastoff/MS +blasé +blat/S +blatancy/SM +blatant/Y +blather/SMDG +blaze/MZGDRS +blazer/M +blazon/MDGS +bldg +bleach/MDRSZG +bleached/U +bleacher/M +bleak/TPRY +bleakness/M +blear +blearily +bleariness/M +bleary/PRT +bleat/GMDS +bleed/ZGRS +bleeder/M +bleeding/M +bleep/ZGMDRS +bleeper/M +blemish/GMDS +blemished/U +blench/DSG +blend/ZGMDRS +blender/M +bless/GDSJ +blessed/YP +blessedness/M +blessing/M +bletch +blew +blight/ZGMDRS +blimey +blimp/MS +blimpish +blind/PZTGMDRYS +blinder/M +blindfold/SMDG +blinding/Y +blindness/M +blindside/DSG +blini/MS +blink/ZGMDRS +blinker/MDG +blintz/MS +blintze/M +blip/SM +bliss/M +blissful/YP +blissfulness/M +blister/GMDS +blistering/Y +blistery +blithe/PYTR +blitheness/M +blither/G +blithesome +blitz/GMDS +blitzkrieg/MS +blivet/S +blizzard/SM +bloat/ZGDRS +bloatware +blob/SM +blobbed +blobbing +bloc/SM +block's +block/UGDS +blockade/MZGDRS +blockader/M +blockage/MS +blockbuster/SM +blockbusting/M +blocker/MS +blockhead/SM +blockhouse/MS +blog/SM +blogged +blogger/MS +blogging +bloke/MS +blokish +blond/PTMRS +blonde/MS +blondish +blondness/M +blood/GMDS +bloodbath/M +bloodbaths +bloodcurdling +bloodhound/SM +bloodily +bloodiness/M +bloodless/YP +bloodlessness/M +bloodletting/M +bloodline/SM +bloodmobile/MS +bloodshed/M +bloodshot +bloodstain/SMD +bloodstock/M +bloodstream/SM +bloodsucker/SM +bloodsucking +bloodthirstily +bloodthirstiness/M +bloodthirsty/RPT +bloody/PTGDRS +bloom/ZGMDRS +bloomer/M +bloop/ZGMDRS +blooper/M +blossom/GMDS +blossomy +blot/SM +blotch/GMDS +blotchy/TR +blotted +blotter/MS +blotting +blotto +blouse/MGDS +blow/SZGMR +blower/M +blowfly/SM +blowgun/MS +blowhard/MS +blowhole/S +blowjob/SM +blowlamp/S +blown +blowout/SM +blowpipe/SM +blowsy/RT +blowtorch/MS +blowup/MS +blowy/TR +blowzy/RT +blubber/GSMD +blubbery +bludgeon/MDGS +blue/DRSPMTG +bluebell/MS +blueberry/SM +bluebird/MS +bluebonnet/SM +bluebottle/SM +bluefish/MS +bluegill/MS +bluegrass/M +blueing/M +blueish +bluejacket/SM +bluejay/SM +bluejeans/M +blueness/M +bluenose/MS +bluepoint/MS +blueprint/MDGS +bluestocking/SM +bluesy/RT +bluet/MS +bluff/ZTGPMDRYS +bluffer/M +bluffness/M +bluing/M +bluish +blunder/MDRZGS +blunderbuss/MS +blunderer/M +blunt/PTGDRYS +bluntness/M +blur/SM +blurb/MS +blurred +blurriness/M +blurring +blurry/TRP +blurt/GDS +blush/ZGMDRS +blusher/M +bluster/MDRSZG +blusterer/M +blusterous +blustery +blvd +boa/SM +boar/SM +board/ZGMDRS +boarder/M +boarding/M +boardinghouse/MS +boardroom/MS +boardwalk/MS +boast/ZGMDRS +boaster/M +boastful/PY +boastfulness/M +boat/SZGMDR +boater/M +boathouse/MS +boating/M +boatload/S +boatman/M +boatmen +boatswain/SM +boatyard/S +bob/SM +bobbed +bobbin/MS +bobbing +bobble/MGDS +bobby/SM +bobbysoxer/SM +bobcat/MS +bobolink/SM +bobsled/SM +bobsledded +bobsledder/MS +bobsledding +bobsleigh/M +bobsleighs +bobtail/SM +bobwhite/MS +bocce/M +bocci/M +boccie/M +bock/M +bod/SMDG +bodacious +bode/S +bodega/MS +bodge/GDS +bodice/MS +bodily +bodkin/MS +body/DSM +bodybuilder/SM +bodybuilding/M +bodyguard/MS +bodysuit/SM +bodywork/M +boffin/S +boffo +bog/SM +boga +bogey/GMDS +bogeyman/M +bogeymen +bogged +bogging +boggle/GDS +boggy/TR +bogie/MS +bogon +bogosity +bogus +bogyman/M +bogymen +bohemian/SM +bohemianism/M +boil/SJZGMDR +boiler/M +boilermaker/SM +boilerplate/M +boink/GDS +boisterous/YP +boisterousness/M +bola/SM +bold/PTRY +boldface/DM +boldness/M +bole/SM +bolero/MS +bolivar/MS +bolivares +boll/SM +bollard/S +bollix/GMDS +bollocking/S +bollocks +bologna/M +bolshevik/SM +bolshie +bolshy +bolster/GMDS +bolt's +bolt/USGD +bolthole/S +bolus/MS +bomb/SJZGMDR +bombard/GDLS +bombardier/MS +bombardment/SM +bombast/M +bombastic +bombastically +bomber/M +bombproof +bombshell/SM +bombsite/S +bonanza/MS +bonbon/MS +bonce/S +bond/SGMD +bondage/M +bondholder/MS +bonding/M +bondman/M +bondmen +bondsman/M +bondsmen +bondwoman/M +bondwomen +bone/DRSMZG +bonehead/SMD +boneless +boner/M +boneshaker/S +boneyard +bonfire/MS +bong/SGMD +bongo/MS +bonhomie/M +boniness/M +bonito/MS +bonk/SZGD +bonnet/MS +bonny/TR +bonobo/MS +bonsai/M +bonus/MS +bony/PTR +boo/SMDHG +boob/SGMD +booboo/MS +booby/SM +boodle/MS +booger/S +boogeyman/M +boogeymen +boogie/MDS +boogieing +boogieman/M +boohoo/GMDS +book/SBJGMD +bookbinder/SM +bookbindery/SM +bookbinding/M +bookcase/MS +bookend/MS +bookie/MS +booking/M +bookish +bookkeeper/MS +bookkeeping/M +booklet/MS +bookmaker/SM +bookmaking/M +bookmark/SMDG +bookmobile/SM +bookplate/MS +bookseller/MS +bookshelf/M +bookshelves +bookshop/SM +bookstall/S +bookstore/MS +bookworm/SM +boom/SZGMDR +boombox/MS +boomerang/MDGS +boon/SM +boondocks/M +boondoggle/MZGDRS +boondoggler/M +boonies/M +boor/SM +boorish/PY +boorishness/MS +boost/ZGMDRS +booster/M +boot's +boot/ASGD +bootblack/SM +bootee/MS +booth/M +booths +bootie/M +bootlace/S +bootleg/MS +bootlegged +bootlegger/MS +bootlegging/M +bootless +bootstrap/MS +bootstrapped +bootstrapping +booty/SM +booze/MZGDRS +boozer/M +boozy/TR +bop/SM +bopped +bopping +borax/M +bordello/MS +border/GMDS +borderland/MS +borderline/MS +bore/DRSMZG +boredom/M +borehole/S +borer/M +boring/Y +born/IAU +borne +boron/M +borough/M +boroughs +borrow/SDRZGJ +borrower/M +borrowing/M +borsch/M +borscht/M +borstal/S +borzoi/SM +bosh/M +bosom's +bosom/US +bosomy +boss/DSGM +bossily +bossiness/M +bossism/M +bossy/RTP +bosun/SM +bot/S +botanic +botanical/Y +botanist/SM +botany/M +botch/DRSZGM +botcher/M +both +bother/SMDG +botheration +bothersome +botnet/SM +bottle/DRSMZG +bottleneck/MS +bottler/M +bottom/SMDG +bottomless +botulinum +botulism/M +boudoir/SM +bouffant/SM +bougainvillea/MS +bough/M +boughs +bought +bouillabaisse/SM +bouillon/MS +boulder/SM +boules +boulevard/SM +bounce/DRSMZG +bouncer/M +bouncily +bounciness/M +bouncy/RTP +bound/ASMGD +boundary/SM +bounden +bounder/SM +boundless/PY +boundlessness/M +bounteous/YP +bounteousness/M +bountiful/YP +bountifulness/M +bounty/SM +bouquet/SM +bourbon/SM +bourgeois/M +bourgeoisie/M +boustrophedon +bout/MS +boutique/SM +boutonniere/MS +boutonnière/MS +bouzouki/MS +bovine/SM +bovver +bow/ZGSMDR +bowdlerization/MS +bowdlerize/DSG +bowed/U +bowel/SM +bower/M +bowl/MDRZGS +bowleg/SM +bowlegged +bowler/M +bowlful/SM +bowline/SM +bowling/M +bowman/M +bowmen +bowsprit/SM +bowstring/SM +bowwow/SM +box/ZGMDNRS +boxcar/SM +boxer/M +boxing/M +boxlike +boxroom/S +boxwood/M +boxy/RT +boy/SM +boycott/SGMD +boyfriend/MS +boyhood/SM +boyish/YP +boyishness/M +boysenberry/SM +bozo/MS +bpm +bps +bra/SM +brace/MZGDRS +bracelet/MS +bracer/M +bracero/MS +bracken/M +bracket/GMDS +brackish/P +brackishness/M +bract/MS +brad/SM +bradawl/S +bradycardia +brae/SM +brag/SM +braggadocio/SM +braggart/SM +bragged +bragger/MS +bragging +braid/GMDS +braiding/M +braille/M +brain/GMDS +brainchild/M +brainchildren/M +braininess/M +brainless/Y +brainpower +brainstorm/SMDG +brainstorming/M +brainteaser/SM +brainwash/DSG +brainwashing/M +brainwave/S +brainy/PTR +braise/GDS +brake/MGDS +brakeman/M +brakemen +bramble/MS +brambly +bran/M +branch/GMDS +branchlike +brand/ZGMDRS +branded/U +brander/M +brandish/DSG +brandy/GDSM +brash/PTRY +brashness/M +brass/MS +brasserie/MS +brassiere/MS +brassily +brassiness/M +brassy/PTR +brat/SM +bratty/RT +bratwurst/SM +bravado/M +brave/GPMYDTRS +braveness/M +bravery/M +bravo/SM +bravura/SM +brawl/SDRZGM +brawler/M +brawn/M +brawniness/M +brawny/RTP +bray/DGSM +braze/DRSZG +brazen/SDYGP +brazenness/M +brazer/M +brazier/SM +breach/GMDS +bread/GMDHS +breadbasket/SM +breadboard/SM +breadbox/MS +breadcrumb/MS +breadfruit/SM +breadline/MS +breadth/M +breadths +breadwinner/SM +break/BMZGRS +breakable/MS +breakage/MS +breakaway/MS +breakdown/MS +breaker/M +breakeven/M +breakfast/MDGS +breakfront/MS +breakneck +breakout/MS +breakpoints +breakthrough/M +breakthroughs +breakup/SM +breakwater/SM +bream/MS +breast/SMDG +breastbone/MS +breastfed +breastfeed/GS +breastplate/SM +breaststroke/SM +breastwork/MS +breath/MDRSZGB +breathalyze/ZGDRS +breathe +breather/M +breathing/M +breathless/PY +breathlessness/M +breaths +breathtaking/Y +breathy/RT +bred/I +breech/MS +breed/SRZGM +breeder/M +breeding/IM +breeze/DSMG +breezeway/SM +breezily +breeziness/M +breezy/RTP +brethren +breve/SM +brevet/SM +brevetted +brevetting +breviary/SM +brevity/M +brew/MDRZGS +brewer/M +brewery/SM +brewpub/SM +briar/SM +bribe/DRSMZG +briber/M +bribery/M +brick/SMDG +brickbat/SM +brickie/S +bricklayer/MS +bricklaying/M +brickwork/M +brickyard/S +bridal/SM +bride/SM +bridegroom/SM +bridesmaid/MS +bridge/DSMG +bridgeable/U +bridgehead/SM +bridgework/M +bridle/DSMG +bridled/U +bridleway/S +brie/MZR +brief's +brief/CSDTGJ +briefcase/SM +briefer +briefing/CM +briefly +briefness/M +brier/M +brig/MS +brigade/SM +brigadier/MS +brigand/SM +brigandage/M +brigantine/MS +bright/SPNRYXT +brighten/DRZG +brightener/M +brightness/M +brights/M +brill +brilliance/M +brilliancy/M +brilliant/MYS +brilliantine/M +brim/MS +brimful +brimless +brimmed +brimming +brimstone/M +brindle/DM +brine/M +bring/SRZG +bringer/M +brininess/M +brink/SM +brinkmanship/M +briny/RTP +brioche/SM +briquet/SM +briquette/MS +brisk/SDRYTGP +brisket/SM +briskness/M +bristle/DSMG +bristly/TR +britches/M +brittle/PRMT +brittleness/M +bro/SMH +broach/MDSG +broad/SMNRYXTP +broadband/M +broadcast/AMGS +broadcaster/MS +broadcasting/M +broadcloth/M +broaden/DG +broadloom/M +broadminded +broadness/M +broadsheet/SM +broadside/MGDS +broadsword/SM +brocade/DSMG +broccoli/M +brochette/SM +brochure/MS +brogan/SM +brogue/SM +broil/SMDRZG +broiler/M +broke +broken/YP +brokenhearted/Y +brokenness/M +broker/SMDG +brokerage/MS +brolly/S +bromide/SM +bromidic +bromine/M +bronc/SM +bronchi +bronchial +bronchitic +bronchitis/M +bronchus/M +bronco/SM +broncobuster/SM +brontosaur/MS +brontosaurus/MS +bronze/DSMG +brooch/MS +brood/SMDRZG +brooder/M +broodily +brooding/MY +broodmare/MS +broody/RMPT +brook/SMDG +brooklet/SM +broom/SM +broomstick/MS +broth/MRZ +brothel/MS +brother/MY +brotherhood/MS +brotherliness/M +broths +brougham/SM +brought +brouhaha/SM +brow/MS +browbeat/SNG +brown/SMDRPTG +brownfield +brownie/MS +brownish +brownness/M +brownout/SM +brownstone/MS +browse/DRSMZG +browser/M +brr +bruin/SM +bruise/DRSMZG +bruiser/M +bruising/M +bruit/SDG +brunch/MDSG +brunet/SM +brunette/MS +brunt/M +brush/MDSG +brushoff/SM +brushstroke/S +brushwood/M +brushwork/M +brusque/RPYT +brusqueness/M +brutal/Y +brutality/SM +brutalization/M +brutalize/GDS +brute/SM +brutish/PY +brutishness/M +bu +bub/SM +bubble/DSMG +bubblegum/M +bubbly/RMT +bubo/M +buboes +buccaneer/SGMD +buck/MDGS +buckaroo/SM +buckboard/MS +bucket/SGMD +bucketful/MS +buckeye/MS +buckle's +buckle/UDSG +buckler/MS +buckram/M +bucksaw/MS +buckshot/M +buckskin/MS +buckteeth +bucktooth/MD +buckwheat/M +buckyball/SM +bucolic/MS +bucolically +bud/SM +budded +budding/S +buddy/SM +budge/DSG +budgerigar/MS +budget/SGMD +budgetary +budgie/SM +buff/AMDGS +buffalo/MDG +buffaloes +buffer/SMDG +buffet/SMDGJ +buffoon/SM +buffoonery/M +buffoonish +bug's +bug/CS +bugaboo/SM +bugbear/SM +bugged/C +bugger/SMDG +buggery +bugging/C +buggy/RSMT +bugle/DRSMZG +bugler/M +build/SMRZGJ +builder/M +building/M +buildup/SM +built/AI +builtin +bulb/MS +bulbous +bulge/DSMG +bulgy/RT +bulimarexia/M +bulimia/M +bulimic/SM +bulk/MDGS +bulkhead/MS +bulkiness/M +bulky/RTP +bull/MDGS +bulldog/SM +bulldogged +bulldogging +bulldoze/ZGDRS +bulldozer/M +bullet/SM +bulletin/MDGS +bulletproof/SDG +bullfight/SMRZG +bullfighter/M +bullfighting/M +bullfinch/MS +bullfrog/MS +bullhead/MDS +bullheaded/PY +bullheadedness/M +bullhorn/MS +bullion/M +bullish/YP +bullishness/M +bullock/SM +bullpen/SM +bullring/MS +bullshit/MS! +bullshitted/! +bullshitter/SM! +bullshitting/! +bullwhip/S +bully/DSMG +bulrush/MS +bulwark/MS +bum/SM +bumbag/S +bumble/DRSZG +bumblebee/SM +bumbler/M +bumf +bummed +bummer/SM +bummest +bumming +bump/MDRZGS +bumper/M +bumph +bumpiness/M +bumpkin/MS +bumptious/PY +bumptiousness/M +bumpy/PRT +bun/SM +bunch/MDSG +bunchy/RT +bunco/SMDG +buncombe/M +bundle/DSMG +bung/MDGS +bungalow/MS +bungee/SM +bunghole/MS +bungle/DRSMZG +bungler/M +bunion/SM +bunk's +bunk/CDGS +bunker/SM +bunkhouse/SM +bunko/SMDG +bunkum/M +bunny/SM +bunt/MDGSJ +bunting/M +buoy/MDGS +buoyancy/M +buoyant/Y +bur/SMY +burble/DSMG +burbs/M +burden's +burden/USGD +burdensome +burdock/M +bureau/SM +bureaucracy/SM +bureaucrat/MS +bureaucratic +bureaucratically +bureaucratization/M +bureaucratize/GDS +burg/MRZS +burgeon/DSG +burger/M +burgh/MRZ +burgher/M +burghs +burglar/MS +burglarize/GDS +burglarproof +burglary/SM +burgle/DSG +burgomaster/SM +burgundy/SM +burial/ASM +burka/SM +burl/MDS +burlap/M +burlesque/MGDS +burliness/M +burly/RPT +burn/MDRZGSB +burnable/SM +burner/M +burnish/ZGMDRS +burnisher/M +burnoose/MS +burnous/MS +burnout/MS +burnt +burp/MDGS +burr/MDGS +burrito/MS +burro/SM +burrow/SMDRZG +burrower/M +bursa/M +bursae +bursar/SM +bursary/SM +bursitis/M +burst/SMG +bury/ADSG +bus/AMS +busboy/SM +busby/SM +bused +busgirl/MS +bush/MDSGJ +bushel/SGMD +bushiness/M +bushing/M +bushman/M +bushmaster/SM +bushmen +bushwhack/DRSZG +bushwhacker/M +bushy/RPT +busily +business/MS +businesslike +businessman/M +businessmen +businessperson/SM +businesswoman/M +businesswomen +busing/M +busk/DRZGS +buskin/SM +busload/S +buss/M +bust/MDRZGS +buster/M +bustle/DSMG +busty/RZT +busy/DRSTGP +busybody/SM +busyness/M +busywork/M +but/ACS +butane/M +butch/MRSZ +butcher/MDG +butchery/SM +butler/SM +butt/MDRZGS +butte/SM +butted/A +butter/MDG +butterball/MS +buttercream +buttercup/SM +butterfat/M +butterfingered +butterfingers/M +butterfly/GDSM +buttermilk/M +butternut/SM +butterscotch/M +buttery/TRSM +butting/A +buttock/SM +button's +button/USDG +buttonhole/DSMG +buttonwood/MS +buttress/MDSG +butty/S +buxom +buy/ZGSMR +buyback/SM +buyer/M +buyout/SM +buzz/MDRSZG +buzzard/MS +buzzer/M +buzzkill/SM +buzzword/SM +bx +bxs +by/M +bye/SM +bygone/SM +bylaw/SM +byline/SM +bypass/GMDS +bypath/M +bypaths +byplay/M +byproduct/MS +byre/S +byroad/SM +bystander/MS +byte/MS +byway/SM +byword/SM +byzantine +c/IES +ca +cab/SMRZ +cabal/MS +cabala/M +caballero/MS +cabana/SM +cabaret/SM +cabbage/MS +cabbed +cabbie/M +cabbing +cabby/SM +cabdriver/SM +cabin/MS +cabinet/SM +cabinetmaker/MS +cabinetmaking/M +cabinetry/M +cabinetwork/M +cable/MGDS +cablecast/GMS +cablegram/MS +cabochon/SM +caboodle/M +caboose/SM +cabriolet/SM +cabstand/SM +cacao/MS +cache/MGDS +cachepot/SM +cachet/MS +cackle/MZGDRS +cackler/M +cacophonous +cacophony/SM +cacti +cactus/M +cad/SM +cadaver/SM +cadaverous +caddie/MDS +caddish/YP +caddishness/M +caddying +cadence/DSM +cadenza/SM +cadet/MS +cadge/ZGDRS +cadger/M +cadmium/M +cadre/MS +caducei +caduceus/M +caesarean/MS +caesura/SM +cafe/SM +cafeteria/MS +cafetiere/S +caff/CS +caffeinated +caffeine/M +caftan/MS +café/SM +cage/DSMG +cagey +cagier +cagiest +cagily +caginess/M +cagoule/S +cahoot/MS +caiman/MS +cairn/MS +caisson/SM +caitiff/SM +cajole/ZGLDRS +cajolement/M +cajoler/M +cajolery/M +cake/DSMG +cakewalk/SM +cal +calabash/MS +calaboose/SM +calamari/SM +calamine/M +calamitous/Y +calamity/SM +calcareous +calciferous +calcification/M +calcify/GNDS +calcimine/DSMG +calcine/DSG +calcite/M +calcium/M +calculable/I +calculate/AGNVDSX +calculated/Y +calculating/Y +calculation/AM +calculator/SM +calculi +calculus/M +caldera/SM +caldron/SM +calendar/MDGS +calender's +calf/M +calfskin/M +caliber/SM +calibrate/GNDSX +calibration/M +calibrator/SM +calico/MS +calicoes +californium/M +caliper/SGMD +caliph/M +caliphate/MS +caliphs +calisthenic/S +calisthenics/M +calk/SGMD +call/ASGMD +calla/MS +callable +callback/MS +called/U +caller/MS +calligrapher/SM +calligraphic +calligraphist/MS +calligraphy/M +calling/SM +calliope/MS +callosity/SM +callous/PGDSY +callousness/M +callow/RPT +callowness/M +callus/MDSG +calm/PSTGMDRY +calmness/M +caloric +calorie/MS +calorific +calumet/MS +calumniate/GNDS +calumniation/M +calumniator/MS +calumnious +calumny/SM +calve/GDS +calypso/MS +calyx/MS +cam/SM +camaraderie/M +camber/MDSG +cambial +cambium/SM +cambric/M +camcorder/SM +came +camel/MS +camelhair/M +camellia/MS +cameo/MS +camera/MS +cameraman/M +cameramen +camerawoman/M +camerawomen +camerawork +camiknickers +camisole/SM +camomile/SM +camouflage/MZGDRS +camouflager/M +camp's +camp/CSGD +campaign/SMDRZG +campaigner/M +campanile/SM +campanologist/MS +campanology/M +camper/MS +campfire/SM +campground/SM +camphor/M +camping/M +campsite/SM +campus/MS +campy/TR +camshaft/SM +can't +can/SMDRZG +canal/MS +canalization/M +canalize/GDS +canape/MS +canapé/MS +canard/MS +canary/SM +canasta/M +cancan/MS +cancel/DRSZG +canceler/M +cancellation/SM +cancelled +cancelling +cancer/MS +cancerous +candelabra/SM +candelabrum/M +candid/YP +candida +candidacy/SM +candidate/MS +candidature/SM +candidness/M +candle/MZGDRS +candlelight/M +candlelit +candlepower/M +candler/M +candlestick/MS +candlewick/SM +candor/M +candy/GDSM +candyfloss +cane/SM +canebrake/MS +caner/M +canine/MS +canister/SM +canker/GMDS +cankerous +cannabis/MS +canned +cannelloni/M +cannery/SM +cannibal/SM +cannibalism/M +cannibalistic +cannibalization/M +cannibalize/GDS +cannily/U +canniness/M +canning +cannon/GMDS +cannonade/MGDS +cannonball/SM +cannot +canny/UTR +canoe/MDS +canoeing +canoeist/SM +canola/M +canon/MS +canonical/Y +canonization/SM +canonize/DSG +canoodle/DSG +canopy/GDSM +canst +cant's +cant/CZRDGS +cantabile +cantaloupe/SM +cantankerous/PY +cantankerousness/M +cantata/MS +canteen/MS +canter/CM +cantered +cantering +canticle/MS +cantilever/MDGS +canto/MS +canton/MLS +cantonal +cantonment/MS +cantor/MS +canvas/MGDS +canvasback/SM +canvass/MDRSZG +canvasser/M +canyon/MGS +cap/SMDRBZ +capabilities +capability/IM +capable/I +capably/I +capacious/PY +capaciousness/M +capacitance/M +capacities +capacitor/SM +capacity/IM +caparison/MDGS +cape/SM +caper/GMD +capeskin/M +capillarity/M +capillary/SM +capital/MSY +capitalism/M +capitalist/SM +capitalistic +capitalistically +capitalization/M +capitalize/ADSG +capitation/CSM +capitol/SM +capitulate/ADSXGN +capitulation/AM +caplet/MS +capo/SM +capon/MS +capped/UA +capping/UA +cappuccino/SM +caprice/SM +capricious/PY +capriciousness/M +capsicum/SM +capsize/DSG +capstan/SM +capstone/MS +capsular +capsule/DSMG +capsulize/DSG +capt +captain/SMDG +captaincy/SM +caption/SMDG +captious/YP +captiousness/M +captivate/DSGN +captivation/M +captivator/SM +captive/SM +captivity/SM +captor/MS +capture/ADSMG +car/SMDRZG +carafe/MS +caramel/SM +caramelize/DSG +carapace/SM +carat/MS +caravan/SM +caravansarai/S +caravansary/SM +caravanserai/M +caravel/SM +caraway/SM +carbide/SM +carbine/SM +carbohydrate/SM +carbolic +carbon/MS +carbonaceous +carbonate/MGNDS +carbonation/M +carboniferous +carbonize/GDS +carborundum/M +carboy/MS +carbs +carbuncle/SM +carbuncular +carburetor/SM +carcass/MS +carcinogen/SM +carcinogenic/MS +carcinogenicity/M +carcinoma/MS +card/ESGMD +cardamom/SM +cardamon/S +cardboard/M +carder/MS +cardholder/S +cardiac +cardie/S +cardigan/SM +cardinal/SMY +cardio +cardiogram/SM +cardiograph/M +cardiographs +cardiologist/MS +cardiology/M +cardiomyopathy +cardiopulmonary +cardiovascular +cardsharp/MRZS +cardsharper/M +care/SM +careen/DGS +career/MDGS +careerism +careerist/SM +carefree +careful/YP +carefuller +carefullest +carefulness/M +caregiver/SM +careless/PY +carelessness/M +carer/M +caress/MDSG +caret/MS +caretaker/MS +careworn +carfare/M +cargo/M +cargoes +carhop/MS +caribou/SM +caricature/MGDS +caricaturist/SM +caries/M +carillon/SM +caring/M +carious +carjack/JSDRZG +carjacker/M +carjacking/M +carload/SM +carmine/SM +carnage/M +carnal/Y +carnality/M +carnation/IMS +carnelian/MS +carney/MS +carnie/M +carnival/MS +carnivora +carnivore/SM +carnivorous/PY +carnivorousness/M +carny/SM +carob/MS +carol/ZGMDRS +caroler/M +carom/GMDS +carotene/M +carotid/SM +carousal/SM +carouse/DRSMZG +carousel/SM +carouser/M +carp/SZGMDR +carpal/MS +carpel/MS +carpenter/MDGS +carpentry/M +carper/M +carpet/MDGS +carpetbag/MS +carpetbagged +carpetbagger/MS +carpetbagging +carpeting/M +carpi +carpool/SMDG +carport/SM +carpus/M +carrel/MS +carriage/SM +carriageway/S +carrier/M +carrion/M +carrot/MS +carroty +carry/ZGDRSM +carryall/SM +carrycot/S +carryout +carryover/MS +carsick/P +carsickness/M +cart/SZGMDR +cartage/M +cartel/MS +carter/M +carthorse/SM +cartilage/SM +cartilaginous +cartload/SM +cartographer/SM +cartographic +cartography/M +carton/MS +cartoon/SMDG +cartoonist/MS +cartridge/MS +cartwheel/GMDS +carve/JZGDRS +carver/M +carvery/S +carving/M +caryatid/MS +casaba/MS +cascade/DSMG +cascara/SM +case/LDSJMG +casebook/S +cased/U +caseharden/DGS +casein/M +caseload/MS +casement/MS +casework/ZMR +caseworker/M +cash/GMDS +cashback/M +cashbook/MS +cashew/MS +cashier/GSMD +cashless +cashmere/M +casing/M +casino/MS +cask/SM +casket/MS +cassava/SM +casserole/DSMG +cassette/MS +cassia/MS +cassock/SM +cassowary/SM +cast/ASGM +castanet/MS +castaway/MS +caste/JMZRS +castellated +caster/M +castigate/DSGN +castigation/M +castigator/SM +casting/AM +castle/MGDS +castoff/SM +castor/MS +castrate/GNXDS +castration/M +casual/PMYS +casualness/M +casualty/SM +casuist/SM +casuistic +casuistry/M +cat/SM +cataclysm/MS +cataclysmal +cataclysmic +catacomb/SM +catafalque/MS +catalepsy/M +cataleptic/MS +catalog/ZGSMDR +cataloger/M +catalogue/DSMG +catalogued/U +catalpa/SM +catalyses +catalysis/M +catalyst/MS +catalytic/M +catalyze/GDS +catamaran/SM +catapult/GMDS +cataract/MS +catarrh/M +catastrophe/MS +catastrophic +catastrophically +catatonia/M +catatonic/SM +catbird/SM +catboat/SM +catcall/GSMD +catch/ZGJLMRS +catchall/MS +catcher/M +catchment/MS +catchpenny +catchphrase/SM +catchword/MS +catchy/RT +catechism/SM +catechist/SM +catechize/DSG +categorical/Y +categorization/MS +categorize/GDS +category/SM +cater/ZGJDRS +catercorner +caterer/M +caterpillar/MS +caterwaul/SMDG +catfish/MS +catgut/M +catharses +catharsis/M +cathartic/SM +cathedral/SM +catheter/SM +catheterize/DSG +cathode/SM +cathodic +catholic +catholicity/M +cation/MS +catkin/MS +catlike +catnap/MS +catnapped +catnapping +catnip/M +catsuit/S +catsup/MS +cattail/SM +catted +cattery/S +cattily +cattiness/M +catting +cattle/M +cattleman/M +cattlemen +catty/TPR +catwalk/SM +caucus/MDSG +caudal/Y +caught/U +cauldron/MS +cauliflower/SM +caulk/ZGMDRS +caulker/M +causal/Y +causality/SM +causation/M +causative +cause/MZGDRS +causeless +causer/M +causerie/SM +causeway/SM +caustic/SM +caustically +causticity/M +cauterization/M +cauterize/GDS +caution/SMDG +cautionary +cautious/IY +cautiousness/M +cavalcade/MS +cavalier/SMY +cavalry/SM +cavalryman/M +cavalrymen +cave/DRSMZG +caveat/MS +caveman/M +cavemen +cavern/MS +cavernous/Y +caviar/M +cavil/ZGJMDRS +caviler/M +caving/M +cavity/FSM +cavort/DGS +caw/SMDG +cay/CSM +cayenne/M +cayuse/MS +cc +cease/CMGDS +ceasefire/MS +ceaseless/YP +ceaselessness/M +ceca +cecal +cecum/M +cedar/MS +cede/FAGSD +ceder/MS +cedilla/SM +ceilidh +ceilidhs +ceiling/MS +celandine/M +celeb/S +celebrant/SM +celebrate/DSGNX +celebration/M +celebrator/SM +celebratory +celebrity/SM +celeriac +celerity/M +celery/M +celesta/MS +celestial/Y +celibacy/M +celibate/MS +cell/SMD +cellar/MS +cellist/SM +cellmate/SM +cello/MS +cellophane/M +cellphone/MS +cellular/SM +cellulite/M +cellulitis +celluloid/M +cellulose/M +cement/MDRZGS +cementer/M +cementum/M +cemetery/SM +cenobite/MS +cenobitic +cenotaph/M +cenotaphs +censer/MS +censor/MDGS +censored/U +censorial +censorious/PY +censoriousness/M +censorship/M +censure/BDRSMZG +censurer/M +census/MDSG +cent/SZMR +centaur/SM +centavo/SM +centenarian/MS +centenary/SM +centennial/MYS +center/MDG +centerboard/SM +centerfold/MS +centerpiece/MS +centigrade +centigram/SM +centiliter/MS +centime/SM +centimeter/MS +centipede/SM +central/SMY +centralism +centralist +centrality/M +centralization/CM +centralize/CGDS +centralizer/MS +centrifugal/Y +centrifuge/DSMG +centripetal/Y +centrism/M +centrist/MS +centurion/SM +century/SM +cephalic +ceramic/SM +ceramicist/SM +ceramics/M +ceramist/MS +cereal/MS +cerebellar +cerebellum/SM +cerebra +cerebral +cerebrate/GNDS +cerebration/M +cerebrovascular +cerebrum/MS +cerement/MS +ceremonial/SMY +ceremonious/UY +ceremoniousness/M +ceremony/SM +cerise/M +cerium/M +cermet/M +cert/S +certain/UY +certainty/USM +certifiable +certifiably +certificate/MGNXDS +certification/M +certify/DSG +certitude/IM +certitudes +cerulean/M +cervical +cervices +cervix/M +cesarean/MS +cesium/M +cessation/MS +cession/KAFSM +cesspit/S +cesspool/MS +cetacean/MS +cf +cg +ch/IFVT +chad/S +chafe/GDS +chaff/GMDS +chaffinch/MS +chagrin/GSMD +chain's +chain/UGDS +chainsaw/MDGS +chair/GMDS +chairlift/MS +chairman/M +chairmanship/SM +chairmen +chairperson/SM +chairwoman/M +chairwomen +chaise/MS +chalcedony/M +chalet/MS +chalice/SM +chalk/GMDS +chalkboard/SM +chalkiness/M +chalky/PRT +challenge/DRSMZG +challenged/U +challenger/M +challis/M +chamber/SMD +chamberlain/MS +chambermaid/MS +chambray/M +chameleon/SM +chamois/M +chamomile/MS +champ/ZGMDS +champagne/MS +champion/GMDS +championship/MS +chance/MGDS +chancel/SM +chancellery/SM +chancellor/MS +chancellorship/M +chancery/SM +chanciness/M +chancre/SM +chancy/PRT +chandelier/SM +chandler/MS +change/MZGDRS +changeability/M +changeable/P +changeableness/M +changeably +changed/U +changeless/Y +changeling/SM +changeover/SM +changer/M +changing/U +channel/GSMD +channelization/M +channelize/DSG +chanson/SM +chant/ZGMDRS +chanter/M +chanteuse/MS +chantey/SM +chanticleer/MS +chaos/M +chaotic +chaotically +chap/SM +chaparral/SM +chapati/S +chapatti/S +chapbook/MS +chapeau/SM +chapel/MS +chaperon/MDGS +chaperonage/M +chaperone/SM +chaperoned/U +chaplain/MS +chaplaincy/SM +chaplet/SM +chapped +chapping +chappy/S +chapter/SM +char/SM +charabanc/MS +character/MS +characterful +characteristic/SM +characteristically/U +characterization/MS +characterize/DSG +characterless +charade/SM +charbroil/GDS +charcoal/MS +chard/M +chardonnay/SM +charge/AESDGM +chargeable/A +charged/U +charger/SM +charily +chariness/M +chariot/SM +charioteer/MS +charisma/M +charismatic/MS +charitable/P +charitableness/M +charitably/U +charity/SM +charlady/S +charlatan/SM +charlatanism/M +charlatanry/M +charlie/S +charm/ZGMDRS +charmer/M +charming/Y +charmless +charred +charring +chart/GMDS +charted/U +charter's +charter/ASGD +charterer/MS +chartreuse/M +charwoman/M +charwomen +chary/TRP +chase/MZGDRS +chaser/M +chasm/MS +chassis/M +chaste/PYTR +chasten/DGS +chasteness/M +chastise/DRSZGL +chastisement/SM +chastiser/M +chastity/M +chasuble/SM +chat/SM +chateau/SM +chateaux +chatelaine/SM +chatline/S +chatroom/M +chatted +chattel/MS +chatter/MDRZGS +chatterbox/MS +chatterer/M +chattily +chattiness/M +chatting +chatty/TPR +chauffeur/GMDS +chauvinism/M +chauvinist/SM +chauvinistic +chauvinistically +cheap/PXTNRY +cheapen/DG +cheapness/M +cheapo +cheapskate/MS +cheat/ZGMDRS +cheater/M +check/AGMDS +checkbook/SM +checkbox +checked/U +checker/MDGS +checkerboard/SM +checkers/M +checklist/MS +checkmate/MGDS +checkoff/SM +checkout/SM +checkpoint/SM +checkroom/MS +checksum +checkup/MS +cheddar/M +cheek/GMDS +cheekbone/SM +cheekily +cheekiness/M +cheeky/TPR +cheep/GMDS +cheer/ZGMDRS +cheerer/M +cheerful/YP +cheerfuller +cheerfullest +cheerfulness/M +cheerily +cheeriness/M +cheerio/MS +cheerleader/SM +cheerless/PY +cheerlessness/M +cheery/TPR +cheese/MGDS +cheeseboard/S +cheeseburger/SM +cheesecake/SM +cheesecloth/M +cheeseparing/M +cheesiness/M +cheesy/TPR +cheetah/M +cheetahs +chef/SM +chem +chemical/SMY +chemise/MS +chemist/MS +chemistry/M +chemo/M +chemotherapeutic +chemotherapy/M +chemurgy/M +chenille/M +cherish/DSG +cheroot/MS +cherry/SM +chert/M +cherub/MS +cherubic +cherubim +chervil/M +chess/M +chessboard/MS +chessman/M +chessmen +chest/MDS +chesterfield/SM +chestful/SM +chestnut/SM +chesty/TR +chevalier/SM +cheviot/M +chevron/MS +chew/SZGMDR +chewer/M +chewiness/M +chewy/PTR +chg +chge +chi/SM +chiaroscuro/M +chic/PTMR +chicane/MS +chicanery/SM +chichi/MS +chick/XMNS +chickadee/SM +chicken/MDG +chickenfeed/M +chickenhearted +chickenpox/M +chickenshit/S! +chickpea/SM +chickweed/M +chicle/M +chicness/M +chicory/SM +chide/GDS +chiding/Y +chief/TMRYS +chiefdom/M +chieftain/MS +chieftainship/SM +chiffon/M +chiffonier/MS +chigger/MS +chignon/MS +chihuahua/SM +chilblain/SM +child/M +childbearing/M +childbirth/M +childbirths +childcare/M +childhood/SM +childish/YP +childishness/M +childless/P +childlessness/M +childlike +childminder/S +childminding +childproof/GSD +children/M +chili/M +chilies +chill/JPZTGMDRS +chiller/M +chilliness/M +chilling/Y +chillness/M +chilly/TPR +chimaera/MS +chime/MZGDRS +chimer/M +chimera/MS +chimeric +chimerical +chimney/MS +chimp/MS +chimpanzee/SM +chin/SM +china/M +chinaware/M +chinchilla/MS +chine/MS +chink/GMDS +chinless +chinned +chinning +chino/MS +chinstrap/MS +chintz/M +chintzy/RT +chinwag/S +chip/SM +chipboard +chipmunk/SM +chipolata/S +chipped +chipper/MS +chippie +chipping/S +chippy/S +chirography/M +chiropodist/MS +chiropody/M +chiropractic/SM +chiropractor/SM +chirp/GMDS +chirpily +chirpy/PTR +chirrup/GMDS +chisel/ZGMDRS +chiseler/M +chiselled +chiseller/MS +chiselling +chit/SM +chitchat/SM +chitchatted +chitchatting +chitin/M +chitinous +chitlins/M +chitosan +chitterlings/M +chivalrous/PY +chivalrousness/M +chivalry/M +chive/MS +chivvy/GDS +chivy/GDS +chlamydia/MS +chlamydiae +chloral/M +chlordane/M +chloride/MS +chlorinate/GNDS +chlorination/M +chlorine/M +chlorofluorocarbon/SM +chloroform/SGMD +chlorophyll/M +chloroplast/MS +chm +choc/S +chock/GMDS +chockablock +chocoholic/SM +chocolate/MS +chocolatey +chocolaty +choice/MTRS +choir/MS +choirboy/MS +choirmaster/SM +choke/MZGDRS +chokecherry/SM +choker/M +cholecystectomy +cholecystitis +choler/M +cholera/M +choleric +cholesterol/M +chomp/ZGMDRS +choose/ZGRS +chooser/M +choosiness/M +choosy/TPR +chop/SM +chophouse/SM +chopped +chopper/MDGS +choppily +choppiness/M +chopping +choppy/TPR +chopstick/SM +choral/MYS +chorale/MS +chord/MS +chordal +chordate/SM +chore/MS +chorea/M +choreograph/DRZG +choreographer/M +choreographic +choreographically +choreographs +choreography/M +chorister/SM +choroid/MS +chortle/MZGDRS +chortler/M +chorus/GMDS +chose +chosen +chow/SGMD +chowder/MS +chrism/M +christen/ASGD +christening/MS +christian/U +christology +chromatic +chromatically +chromatin/M +chromatography +chrome/MGDS +chromium/M +chromosomal +chromosome/MS +chronic +chronically +chronicle/DRSMZG +chronicler/M +chronograph/M +chronographs +chronological/Y +chronologist/MS +chronology/SM +chronometer/SM +chrysalis/MS +chrysanthemum/MS +chub/SM +chubbiness/M +chubby/TPR +chuck/GMDS +chuckhole/SM +chuckle/MGDS +chuffed +chug/SM +chugged +chugging +chukka/MS +chum/SM +chummed +chummily +chumminess/M +chumming +chummy/PTR +chump/MS +chunder/GDS +chunk/GMDS +chunkiness/M +chunky/PTR +chunter/DGS +church/MS +churchgoer/SM +churchgoing/M +churchman/M +churchmen +churchwarden/MS +churchwoman +churchwomen +churchyard/SM +churl/MS +churlish/PY +churlishness/M +churn/ZGMDRS +churner/M +chute/MS +chutney/MS +chutzpah/M +chyme/M +château/M +châteaux +châtelaine/SM +ciabatta/SM +ciao/S +cicada/MS +cicatrices +cicatrix/M +cicerone/SM +ciceroni +cider's +cider/S +cigar/MS +cigarette/MS +cigarillo/MS +cilantro/M +cilia +cilium/M +cinch/GMDS +cinchona/SM +cincture/SM +cinder/GMDS +cine +cinema/MS +cinematic +cinematographer/MS +cinematographic +cinematography/M +cinnabar/M +cinnamon/M +cipher's +cipher/CGDS +cir +circa +circadian +circle/MGDS +circlet/MS +circuit/MDGS +circuital +circuitous/YP +circuitousness/M +circuitry/M +circuity/M +circular/SMY +circularity/M +circularize/DSG +circulate/ADSG +circulation/SM +circulatory +circumcise/XDSGN +circumcised/U +circumcision/M +circumference/MS +circumferential +circumflex/MS +circumlocution/MS +circumlocutory +circumnavigate/XGNDS +circumnavigation/M +circumpolar +circumscribe/GDS +circumscription/MS +circumspect/Y +circumspection/M +circumstance/MGDS +circumstantial/Y +circumvent/DSG +circumvention/M +circus/MS +cirque/MS +cirrhosis/M +cirrhotic/SM +cirri +cirrus/M +cistern/MS +cit +citadel/MS +citation/AMS +cite's +cite/IAGSD +citified +citizen/MS +citizenry/M +citizenship/M +citric +citron/MS +citronella/M +citrous +citrus/MS +city/SM +citywide +civet/MS +civic/S +civically +civics/M +civil/UY +civilian/MS +civility/ISM +civilization/MS +civilize/GDS +civilized/U +civvies/M +ck +cl +clack/GMDS +clad/U +cladding/M +claim's +claim/CKEAGDS +claimable/A +claimant/MS +claimed/U +claimer/ECSM +clairvoyance/M +clairvoyant/MS +clam/SM +clambake/MS +clamber/ZGMDRS +clamberer/M +clammed +clammily +clamminess/M +clamming +clammy/PTR +clamor/GMDS +clamorous +clamp/GMDS +clampdown/MS +clan/SM +clandestine/Y +clang/ZGMDRS +clangor/M +clangorous/Y +clank/GMDS +clannish/P +clannishness/M +clansman/M +clansmen +clanswoman +clanswomen +clap/SM +clapboard/MDGS +clapped +clapper/MS +clapperboard/S +clapping/M +claptrap/M +claque/MS +claret/MS +clarification/M +clarify/XDSNG +clarinet/SM +clarinetist/SM +clarinettist/MS +clarion/MDGS +clarity/M +clash/GMDS +clasp's +clasp/UGDS +class/GMDS +classic/MS +classical/MY +classicism/M +classicist/MS +classifiable +classification/CAM +classifications +classified's +classified/U +classifieds +classifier/MS +classify/ACSDGN +classiness/M +classless/P +classmate/MS +classroom/MS +classwork/M +classy/TRP +clatter/GMDS +clausal +clause/MS +claustrophobia/M +claustrophobic +clavichord/SM +clavicle/MS +clavier/MS +claw's +claw/CSGD +clay/M +clayey +clayier +clayiest +clean/BJPZTGDRYS +cleaner/M +cleaning/M +cleanliness/UM +cleanly/UTPR +cleanness/UM +cleanse/ZGDRS +cleanser/M +cleanup/MS +clear/JPTGMDRYS +clearance/SM +clearheaded +clearing/M +clearinghouse/SM +clearness/M +clearway/S +cleat/MS +cleavage/MS +cleave/ZGDRS +cleaver/M +clef/SM +cleft/MS +clematis/MS +clemency/IM +clement/Y +clementine/S +clench/GMDS +clerestory/SM +clergy/SM +clergyman/M +clergymen +clergywoman/M +clergywomen +cleric/MS +clerical/Y +clericalism/M +clerk/GMDS +clerkship/M +clever/PTRY +cleverness/M +clevis/MS +clew/SGMD +cliche/MDS +cliché/MS +clichéd +click/BZGMDRS +clicker/M +client/MS +clientele/MS +clientèle/MS +cliff/MS +cliffhanger/SM +cliffhanging +clifftop/S +clii +climacteric/M +climactic +climate/SM +climatic +climatically +climatologist/SM +climatology/M +climax/MDSG +climb/SMDRZGB +climber/M +climbing/M +clime/SM +clinch/MDRSZG +clincher/M +cling/SMRZG +clinger/M +clingfilm +clingy/RT +clinic/SM +clinical/Y +clinician/SM +clink/SMDRZG +clinker/M +cliometric/S +cliometrician/MS +cliometrics/M +clip/SM +clipboard/MS +clipped +clipper/SM +clipping/SM +clique/SM +cliquey +cliquish/YP +cliquishness/M +clit/SM +clitoral +clitorides +clitoris/MS +clix +cloaca/M +cloacae +cloak's +cloak/USDG +cloakroom/MS +clobber/SMDG +cloche/SM +clock/SMDG +clockwise +clockwork/SM +clod/MS +cloddish +clodhopper/MS +clog's +clog/US +clogged/U +clogging/U +cloisonne/M +cloisonné/M +cloister/SMDG +cloistral +clomp/SDG +clonal +clone/DSMG +clonk/SMDG +clop/MS +clopped +clopping +close/DRSMYTGJP +closefisted +closemouthed +closeness/M +closeout/MS +closet/SMDG +closeup/SM +closing/M +closure/ESM +clot/MS +cloth/M +clothe/UDSG +clotheshorse/MS +clothesline/SM +clothespin/SM +clothier/MS +clothing/M +cloths +clotted +clotting +cloture/SM +cloud/SMDG +cloudburst/SM +clouded/U +cloudiness/M +cloudless +cloudy/RPT +clout/SMDG +clove/RSMZ +cloven +clover/M +cloverleaf/SM +cloverleaves +clown/SMDG +clownish/YP +clownishness/M +cloy/DGS +cloying/Y +club/MS +clubbable +clubbed +clubber/S +clubbing +clubfeet +clubfoot/MD +clubhouse/SM +clubland +cluck/SMDG +clue/MGDS +clueless +clump/SMDG +clumpy/TR +clumsily +clumsiness/M +clumsy/TRP +clung +clunk/SMDRZG +clunker/M +clunky/TR +cluster/MDSG +clutch/GMDS +clutter/MDSG +cluttered/U +clvi +clvii +clxi +clxii +clxiv +clxix +clxvi +clxvii +cm +cnidarian/MS +co/ESD +coach/MDSG +coachload/S +coachman/M +coachmen +coachwork +coadjutor/MS +coagulant/MS +coagulate/GNDS +coagulation/M +coagulator/MS +coal/MDGS +coalesce/GDS +coalescence/M +coalescent +coalface/MS +coalfield/S +coalition/MS +coalitionist/MS +coalmine/S +coarse/RYTP +coarsen/SDG +coarseness/M +coast/SMDRZG +coastal +coaster/M +coastguard/S +coastline/MS +coat/MDGJS +coating/M +coatroom/S +coattail/SM +coauthor/MDGS +coax/DRSZG +coaxer/M +coaxial +coaxing/Y +cob/SM +cobalt/M +cobber/S +cobble/DRSMZG +cobbler/M +cobblestone/SM +cobnut/S +cobra/SM +cobweb/SM +cobwebbed +cobwebby/RT +coca/M +cocaine/M +cocci/S +coccus/M +coccyges +coccyx/M +cochineal/M +cochlea/SM +cochleae +cochlear +cock/MDGS +cockade/SM +cockamamie +cockatoo/SM +cockatrice/SM +cockchafer/S +cockcrow/SM +cockerel/SM +cockeyed +cockfight/MGS +cockfighting/M +cockily +cockiness/M +cockle/SM +cockleshell/SM +cockney/SM +cockpit/SM +cockroach/MS +cockscomb/SM +cocksucker/MS! +cocksure +cocktail/MS +cocky/RTP +coco/MS +cocoa/SM +coconut/SM +cocoon/SMDG +cod/SM +coda/MS +codded +codding +coddle/DSG +code's +code/CZGDRS +codeine/M +codependency/M +codependent/SM +coder/CM +codex/M +codfish/MS +codger/SM +codices +codicil/SM +codification/M +codifier/M +codify/XDRSNZG +codon/S +codpiece/MS +codswallop +coed/MS +coeducation/M +coeducational +coefficient/MS +coelenterate/MS +coequal/MYS +coerce/DRSZGNV +coercer/M +coercion/M +coeval/SMY +coexist/DSG +coexistence/M +coexistent +coextensive +coffee/SM +coffeecake/SM +coffeehouse/MS +coffeemaker/SM +coffeepot/MS +coffer/SM +cofferdam/MS +coffin/SMDG +cog/SM +cogency/M +cogent/Y +cogitate/DSXGNV +cogitation/M +cogitator/MS +cognac/SM +cognate/MS +cognition/AM +cognitional +cognitive/Y +cognizable +cognizance/AM +cognizant +cognomen/SM +cognoscente/M +cognoscenti +cogwheel/SM +cohabit/SGD +cohabitant/MS +cohabitation/M +coheir/SM +cohere/DSG +coherence/IM +coherency/M +coherent/IY +cohesion/M +cohesive/YP +cohesiveness/M +coho/MS +cohort/SM +coif/MDGS +coiffed +coiffing +coiffure/DSMG +coil's/A +coil/UADGS +coin/MDRZGS +coinage/SM +coincide/DSG +coincidence/MS +coincident +coincidental/Y +coiner/M +coinsurance/M +coir +coital +coitus/M +coke/MGDS +col/S +cola/MS +colander/SM +cold/MRYTPS +coldblooded +coldness/M +coleslaw/M +coleus/MS +coley/S +colic/M +colicky +coliseum/MS +colitis/M +coll +collaborate/DSXGNV +collaboration/M +collaborationist +collaborative/Y +collaborator/MS +collage/SM +collagen +collapse/MGDS +collapsible +collar/SMDG +collarbone/SM +collard/SM +collarless +collate/DSXGN +collateral/MY +collateralize +collation/M +collator/MS +colleague/MS +collect's +collect/ASGVD +collectable/MS +collected/U +collectedly +collectible/SM +collection/AMS +collective/MYS +collectivism/M +collectivist/SM +collectivization/M +collectivize/DSG +collector/MS +colleen/SM +college/SM +collegiality/M +collegian/MS +collegiate +collide/DSG +collie/RSMZ +collier/M +colliery/SM +collision/SM +collocate/MGNDSX +collocation/M +colloid/SM +colloidal +colloq +colloquial/Y +colloquialism/SM +colloquies +colloquium/MS +colloquy/M +collude/DSG +collusion/M +collusive +cologne/SM +colon/SM +colonel/SM +colonelcy/M +colones +colonial/SMY +colonialism/M +colonialist/MS +colonist/SM +colonization/ACM +colonize/CAGSD +colonizer/MS +colonnade/MDS +colonoscopy/SM +colony/SM +colophon/SM +color's +color/AEGDS +colorant/SM +coloration/EM +coloratura/MS +colorblind/P +colorblindness/M +colored's +colored/U +coloreds +colorfast/P +colorfastness/M +colorful/PY +colorfulness/M +coloring's +colorist/S +colorization/M +colorize/DSG +colorless/PY +colorlessness/M +colorway/S +colossal/Y +colossi +colossus/M +colostomy/SM +colostrum/M +colt/MS +coltish +columbine/SM +column/SMD +columnar +columnist/SM +com/JL +coma/MS +comaker/SM +comatose +comb/MDRZGJS +combat/SMDGV +combatant/SM +combativeness/M +combed/U +comber/M +combination/SM +combine's +combine/ADSG +combined/U +combiner/MS +combings/M +combo/SM +combustibility/M +combustible/MS +combustion/M +combustive +come/IMZGRS +comeback/MS +comedian/MS +comedic +comedienne/MS +comedown/MS +comedy/SM +comeliness/M +comely/RPT +comer's +comestible/SM +comet/SM +comeuppance/SM +comfit's +comfit/ES +comfort/ESMDG +comfortable/P +comfortableness/M +comfortably/U +comforter/MS +comforting/Y +comfortless +comfy/RT +comic/SM +comical/Y +comicality/M +coming/M +comity/M +comm +comma/SM +command/SMDRLZG +commandant/MS +commandeer/GDS +commander/M +commandment/MS +commando/SM +commemorate/XGNVDS +commemoration/M +commemorator/MS +commence/ADSLG +commencement/AM +commencements +commend/ASDBG +commendably +commendation/AMS +commendatory +commensurable +commensurate/IY +comment/GSMD +commentary/SM +commentate/DSG +commentator/SM +commerce/M +commercial/SMY +commercialism/M +commercialization/M +commercialize/GDS +commie/SM +commingle/DSG +commiserate/GNVDSX +commiseration/M +commissar/SM +commissariat/SM +commissary/SM +commission's +commission/ACSGD +commissionaire/S +commissioner/SM +commit/AS +commitment/MS +committal/SM +committed/AU +committee/SM +committeeman/M +committeemen +committeewoman/M +committeewomen +committer/S +committing/A +commode's +commode/EIS +commodification +commodious/Y +commodity/SM +commodore/SM +common's +common/UPRYT +commonality/S +commonalty/M +commoner/MS +commonness/UM +commonplace/MS +commons +commonsense +commonweal/MH +commonwealth/M +commonwealths +commotion/SM +communal/Y +commune/XDSMGN +communicability/M +communicable/I +communicably +communicant/MS +communicate/GNVDSX +communication/M +communicative/U +communicator/SM +communion/M +communique/SM +communism/M +communist/SM +communistic +community/SM +commutation/MS +commutative +commutator/SM +commute/BDRSMZG +commuter/M +comp/MDYGS +compact/TGSMDRYP +compaction +compactness/M +compactor/SM +companion/SBM +companionably +companionship/M +companionway/MS +company/SM +comparability/M +comparable/I +comparably/I +comparative/MYS +compare/BDSMG +comparison/MS +compartment/SM +compartmental +compartmentalization/M +compartmentalize/DSG +compass/GMDS +compassion/M +compassionate/Y +compatibility/IM +compatible/IMS +compatibly/I +compatriot/MS +compeer/SM +compel/S +compelled +compelling/Y +compendious +compendium/SM +compensate/DSXGN +compensated/U +compensation/M +compensatory +compere/DSG +compete/DSG +competence/IM +competences +competencies +competency/IM +competent/IY +competition/SM +competitive/PY +competitiveness/M +competitor/SM +compilation/SM +compile/DRSZG +compiler/M +complacence/M +complacency/M +complacent/Y +complain/DRZGS +complainant/MS +complainer/M +complaint/SM +complaisance/M +complaisant/Y +complected +complement/SGMD +complementary +complete/PYTGNXDRS +completed/U +completeness/IM +completion/M +complex/MSY +complexion/MDS +complexional +complexity/SM +compliance/M +compliant/Y +complicate/GDS +complicated/Y +complication/M +complicit +complicity/M +compliment/MDGS +complimentary/U +comply/NDSXG +compo/S +component/SM +comport/LSGD +comportment/M +compose/AECGSD +composedly +composer/MS +composite/MYGNXDS +composition/CM +compositor/SM +compost/SGMD +composure/EM +compote/SM +compound/GMDBS +compounded/U +comprehend/SDG +comprehensibility/IM +comprehensible/I +comprehensibly/I +comprehension/IM +comprehensions +comprehensive/PMYS +comprehensiveness/M +compress's +compress/CGDS +compressed/U +compressible +compression/CM +compressor/SM +comprise/GDS +compromise/MGDS +comptroller/MS +compulsion/MS +compulsive/YP +compulsiveness/M +compulsorily +compulsory/SM +compunction/SM +computation/SM +computational/Y +compute/ADSG +computer/MS +computerate +computerization/M +computerize/GDS +computing/M +compère/DSG +comrade/SMY +comradeship/M +con/GSM +concatenate/XDSGN +concatenation/M +concave/YP +concaveness/M +conceal/SDRZGBL +concealed/U +concealer/M +concealment/M +conceit/SMD +conceited/PY +conceitedness/M +conceivable/I +conceivably/I +conceive/DSGB +concentrate/DSMGNX +concentration/M +concentric +concentrically +concept/SM +conception/SM +conceptional +conceptual/Y +conceptualization/MS +conceptualize/DSG +concern/UMD +concerned/UY +concerning +concerns +concert's +concert/ESDG +concerted/Y +concertgoer/S +concertina/SGMD +concertize/DSG +concertmaster/MS +concerto/SM +concessionaire/MS +concessional +concessionary +conch/M +conchie/S +conchs +concierge/MS +conciliate/DSGN +conciliation/AM +conciliator/SM +conciliatory +concise/RPYTN +conciseness/M +concision/M +conclave/SM +conclude/DSG +conclusion/MS +conclusive/IYP +conclusiveness/IM +concoct/SDG +concoction/MS +concomitant/MYS +concord/M +concordance/SM +concordant +concordat/SM +concourse/SM +concrete/DSPMYGNX +concreteness/M +concretion/M +concubinage/M +concubine/MS +concupiscence/M +concupiscent +concur/S +concurred +concurrence/SM +concurrency +concurring +concuss/V +concussion/SM +condemn/SDRZG +condemnation/MS +condemnatory +condemner/M +condensate/MNXS +condensation/M +condense/DRSZG +condenser/M +condescending/Y +condescension/M +condign +condiment/MS +condition's +condition/AGSD +conditional/SMY +conditioned/U +conditioner/SM +conditioning/M +condo/SM +condolence/SM +condom/SM +condominium/MS +condone/DSG +condor/SM +conduce/DSGV +conduct/MDGV +conductance/M +conductibility/M +conductible +conduction/M +conductivity/M +conductor/MS +conductress/MS +conduit/SM +cone/M +coney/SM +confab/SM +confabbed +confabbing +confabulate/XDSGN +confabulation/M +confection/SZMR +confectioner/M +confectionery/SM +confederacy/SM +confederate/M +confer/S +conferee/SM +conference/MGS +conferrable +conferral/M +conferred +conferrer/MS +conferring +confessed/Y +confession/SM +confessional/SM +confessor/MS +confetti/M +confidant/MS +confidante/SM +confide/DRSZG +confidence/SM +confident/Y +confidential/Y +confidentiality/M +confider/M +confiding/Y +configuration/S +configure/B +confined/U +confinement/MS +confirm/ASDG +confirmation/ASM +confirmatory +confirmed/U +confiscate/DSGNX +confiscation/M +confiscator/SM +confiscatory +conflagration/MS +conflate/XDSGN +conflation/M +conflict/SGMD +confluence/MS +confluent +conform/ZB +conformable/U +conformance/M +conformism/M +conformist/SM +conformity/M +confrere/MS +confrontation/SM +confrontational +confrère/SM +confuse/RZ +confused/Y +confusing/Y +confutation/M +confute/DSG +conga/SMDG +congeal/SLDG +congealment/M +conger/SM +congeries/M +congest/SDGV +congestion/M +conglomerate/DSXMGN +conglomeration/M +congrats/M +congratulate/XGNDS +congratulation/M +congratulatory +congregant/MS +congregate/GNDSX +congregation/M +congregational +congregationalism/M +congregationalist/MS +congress/MS +congressional +congressman/M +congressmen +congresspeople +congressperson/MS +congresswoman/M +congresswomen +congruence/M +congruent/Y +congruity/ISM +congruous +conic/SM +conical/Y +conifer/SM +coniferous +conjectural +conjecture/MGDS +conjoint +conjugal/Y +conjugate/DSXGN +conjugation/M +conjunct/VMS +conjunctiva/SM +conjunctive/SM +conjunctivitis/M +conjuration/MS +conjure/DRSZG +conjurer/M +conk/MDRZ +conman +connect/AEDVGS +connectable +connected/U +connection/EMS +connective/MS +connectivity/M +connector/MS +conned +conning +conniption/MS +connivance/M +connive/DRSZG +conniver/M +connoisseur/SM +connotative +connubial +conquer/ASDG +conquerable/U +conquered/U +conqueror/MS +conquest/AM +conquistador/SM +cons/DSG +consanguineous +consanguinity/M +conscienceless +conscientious/PY +conscientiousness/M +conscious/UYP +consciousness/UM +consciousnesses +conscription/M +consecrate/ADSGN +consecrated/U +consecration/AM +consecrations +consecutive/Y +consensual +consensus/MS +consent/SMDG +consequence/SM +consequent/Y +consequential/IY +conservancy/SM +conservation/M +conservationism/M +conservationist/SM +conservatism/M +conservative/MYS +conservatoire/S +conservator/SM +conservatory/SM +consider/AGSD +considerable/I +considerably +considerate/IPYN +considerateness/IM +consideration/AIM +considerations +considered/U +consign/ASDG +consignee/MS +consignment/MS +consist/SDG +consistence/MS +consistency/ISM +consistent/IY +consistory/SM +consolable/I +consolation/MS +consolatory +consolidate/XDSGN +consolidated/U +consolidation/M +consolidator/MS +consoling/Y +consomme/M +consommé/M +consonance/SM +consonant/SMY +consortia +consortium/M +conspectus/MS +conspicuous/IPY +conspicuousness/IM +conspiracy/SM +conspirator/MS +conspiratorial/Y +conspire/GD +constable/SM +constabulary/SM +constancy/IM +constant/MYS +constellation/SM +consternation/M +constipate/GNDS +constipation/M +constituency/SM +constituent/SM +constitute/ADSGNV +constitution/AM +constitutional/MYS +constitutionalism +constitutionality/UM +constitutions +constrained/U +constraint/SM +constrict/GVSD +constriction/SM +constrictor/SM +construable +construct's +construct/CADVGS +construction/CAMS +constructional +constructionist's +constructionist/CS +constructive/YP +constructiveness/M +constructor/MS +construe/GDS +consul/KSM +consular/K +consulate/SM +consulship/M +consult/GSD +consultancy/SM +consultant/MS +consultation/MS +consultative +consumable/SM +consume/BDRSZG +consumed/U +consumer/M +consumerism/M +consumerist/MS +consummate/YGNXDS +consummated/U +consumption/M +consumptive/SM +cont +contact/ASDG +contactable +contagion/MS +contagious/PY +contagiousness/M +contain/SBLDRZG +container/M +containerization/M +containerize/DSG +containment/M +contaminant/SM +contaminate/ACDSG +contaminated/U +contamination/CM +contaminator/SM +contd +contemn/SDG +contemplate/DSGNV +contemplation/M +contemplative/SMY +contemporaneity/M +contemporaneous/Y +contempt/M +contemptible +contemptibly +contemptuous/YP +contemptuousness/M +contender/MS +content/ESLMDG +contented/EY +contentedness/M +contention/SM +contentious/YP +contentiousness/M +contently +contentment/EM +conterminous/Y +contestable/I +contestant/MS +contested/U +contextualization +contextualize/DSG +contiguity/M +contiguous/Y +continence/IM +continent/SM +continental/SM +contingency/SM +contingent/SMY +continua +continual/Y +continuance/EMS +continuation/EMS +continue/EGDS +continuity/ESM +continuous/EY +continuum/M +contort/GD +contortion/MS +contortionist/SM +contraband/M +contrabassoon/S +contraception/M +contraceptive/SM +contract/MDG +contractible +contractile +contractility +contraction/S +contractual/Y +contradict/SDG +contradiction/SM +contradictory +contradistinction/MS +contraflow/S +contrail/MS +contraindicate/GNXDS +contraindication/M +contralto/SM +contraption/SM +contrapuntal/Y +contrarian/SM +contrarianism +contrariety/M +contrarily +contrariness/M +contrariwise +contrary/PSM +contrast/MDGS +contravene/GDS +contravention/SM +contretemps/M +contribute/XGND +contribution/M +contributor/MS +contributory +contrition/M +contrivance/MS +contrive/ZGDRS +contriver/M +control's +control/CS +controllable/U +controlled/UC +controller/MS +controlling/C +controversial/Y +controversy/SM +controvert/DSG +controvertible/I +contumacious/Y +contumacy/M +contumelious +contumely/SM +contuse/XDSGN +contusion/M +conundrum/SM +conurbation/MS +convalesce/DSG +convalescence/MS +convalescent/SM +convection/M +convectional +convective +convector/S +convene/ADSG +convener/MS +convenience/IMS +convenient/IY +convenor/MS +convent/SM +conventicle/MS +convention/SM +conventional/UY +conventionality/UM +conventionalize/GDS +conventioneer/S +convergence/MS +convergent +conversant +conversation/MS +conversational/Y +conversationalist/SM +converse/Y +convert's +convert/AGSD +converted/U +converter/SM +convertibility/M +convertible/SM +convertor/SM +convex/Y +convexity/M +convey/SBDG +conveyance/MGS +conveyor/MS +convict/GSMD +conviction/MS +convince/GDS +convinced/U +convincing/UY +convivial/Y +conviviality/M +convoke/DSG +convoluted +convolution/MS +convoy/SMDG +convulse/GNVXDS +convulsion/M +convulsive/Y +cony/SM +coo/GSMD +cook's +cook/ADGS +cookbook/MS +cooked/U +cooker/SM +cookery/SM +cookhouse/S +cookie/M +cooking/M +cookout/SM +cookware/SM +cooky/SM +cool/MDRYZTGPS +coolant/SM +cooler/M +coolie/SM +coolness/M +coon/MS! +coonskin/MS +coop/MDRZGS +cooper/MDG +cooperage/M +cooperate/DSGNV +cooperation/M +cooperative/PMYS +cooperativeness/M +cooperator/SM +coordinate/DSMYGN +coordinated/U +coordination/M +coordinator/MS +coot/MS +cootie/SM +cop/GJSMD +copacetic +copay/M +cope/MS +copier/SM +copilot/SM +coping/M +copious/PY +copiousness/M +copped +copper/SM +copperhead/SM +copperplate/M +coppery +copping +copra/M +copse/SM +copter/SM +copula/SM +copulate/GNVDS +copulation/M +copulative/SM +copy's +copy/ADSG +copybook/SM +copycat/MS +copycatted +copycatting +copyist/MS +copyleft +copyright/GSMD +copywriter/MS +coquetry/SM +coquette/DSMG +coquettish/Y +cor +coracle/SM +coral/SM +corbel/SM +cord/EASGDM +cordage/M +cordial/SMY +cordiality/M +cordillera/MS +cordite/M +cordless +cordon/SMDG +cordovan/M +corduroy/MS +corduroys/M +core/MZGDRS +coreligionist/S +corer/M +corespondent/MS +corgi/SM +coriander/M +cork's +cork/UDGS +corkage +corker/SM +corkscrew/SMDG +corm/MS +cormorant/SM +corn/MDRZGS +cornball/MS +cornbread/M +corncob/MS +corncrake/S +cornea/SM +corneal +corner/GMD +cornerstone/SM +cornet/SM +cornfield/S +cornflakes/M +cornflour +cornflower/SM +cornice/MS +cornily +corniness/M +cornmeal/M +cornrow/MDGS +cornstalk/SM +cornstarch/M +cornucopia/MS +corny/PRT +corolla/MS +corollary/SM +corona/SM +coronal/MS +coronary/SM +coronation/SM +coroner/MS +coronet/MS +corp +corpora +corporal/SM +corporate/XYN +corporation/IM +corporatism +corporeal/Y +corporeality/M +corps/MS +corpse/M +corpsman/M +corpsmen +corpulence/M +corpulent +corpus/M +corpuscle/MS +corpuscular +corr +corral/SM +corralled +corralling +correct/DRYTGVSBP +corrected/U +correction/SM +correctional +corrective/SM +correctness/IM +corrector +correlate/XDSMGNV +correlated/U +correlation/M +correlative/MS +correspond/SDG +correspondence/SM +correspondent/SM +corresponding/Y +corridor/SM +corrie/S +corroborate/GNVDSX +corroborated/U +corroboration/M +corroborator/SM +corroboratory +corrode/GDS +corrosion/M +corrosive/SMY +corrugate/GNXDS +corrugation/M +corrupt/DRYPSTG +corruptibility/IM +corruptible/I +corruption/MS +corruptness/M +corsage/MS +corsair/MS +corset/SGMD +cortege/MS +cortex/M +cortical +cortices +cortisone/M +cortège/SM +corundum/M +coruscate/GNDS +coruscation/M +corvette/SM +cos/M +cosh/DSG +cosign/ZGSDR +cosignatory/SM +cosigner/M +cosine/SM +cosmetic/SM +cosmetically +cosmetician/MS +cosmetologist/MS +cosmetology/M +cosmic +cosmically +cosmogonist/SM +cosmogony/SM +cosmological +cosmologist/SM +cosmology/SM +cosmonaut/SM +cosmopolitan/MS +cosmopolitanism/M +cosmos/MS +cosplay +cosponsor/GSMD +cosset/SGD +cossetted +cossetting +cost/MDYGSJ +costar/SM +costarred +costarring +costliness/M +costly/PTR +costume/MZGDRS +costumer/M +costumier/S +cot/SM +cotangent/MS +cote/MS +coterie/MS +coterminous +cotillion/SM +cottage/MZGRS +cottager/M +cottar/SM +cotter/SM +cotton/SGMD +cottonmouth/M +cottonmouths +cottonseed/MS +cottontail/MS +cottonwood/SM +cottony +cotyledon/MS +couch/MDSG +couchette/S +cougar/SM +cough/MDG +coughs +could +could've +couldn't +coulee/SM +coulis +coulomb/MS +coulée/SM +council/MS +councilman/M +councilmen +councilor/MS +councilperson/SM +councilwoman/M +councilwomen +counsel/JMDGS +counselor/MS +count/EASMDG +countable/U +countably +countdown/MS +counted/U +countenance's +countenance/EGDS +counter/EMS +counteract/SGVD +counteraction/MS +counterargument/S +counterattack/GMDS +counterbalance/MGDS +counterblast/S +counterclaim/GSMD +counterclockwise +counterculture/SM +countered +counterespionage/M +counterexample/S +counterfactual +counterfeit/ZGMDRS +counterfeiter/M +counterfoil/MS +countering +counterinsurgency/SM +counterintelligence/M +counterman/M +countermand/GMDS +countermeasure/SM +countermelody/S +countermen +countermove/S +counteroffensive/SM +counteroffer/SM +counterpane/SM +counterpart/SM +counterpetition +counterpoint/MDGS +counterpoise/MGDS +counterproductive +counterrevolution/SM +counterrevolutionary/SM +countersign/GSMD +countersignature/MS +countersink/GSM +counterspy/SM +countersunk +countertenor/MS +countervail/GSD +counterweight/MS +countess/MS +countless +countrified +country/SM +countryman/M +countrymen +countryside/MS +countrywide +countrywoman/M +countrywomen +county/SM +countywide +coup's +coup/AS +coupe/SM +couple's +couple/UCGSD +couplet/MS +coupling/SM +coupon/SM +courage/M +courageous/YP +courageousness/M +courgette/S +courier/MDSG +course/EDGMS +coursebook/S +courser/MS +coursework +court/SMDYG +courteous/EY +courteousness/M +courtesan/SM +courtesy/ESM +courthouse/MS +courtier/SM +courtliness/M +courtly/PRT +courtroom/MS +courtship/MS +courtyard/MS +couscous/M +cousin/SM +couture/M +couturier/MS +cove/MS +coven/SM +covenant/MDSG +cover's +cover/AEUGDS +coverage/M +coverall/MS +covering's +coverings +coverlet/MS +covert/SPMY +covertness/M +coverup/MS +covet/SDG +covetous/YP +covetousness/M +covey/SM +cow/ZGSMDR +coward/SMY +cowardice/M +cowardliness/M +cowbell/MS +cowbird/MS +cowboy/SM +cowcatcher/MS +cower/DG +cowgirl/MS +cowhand/MS +cowherd/MS +cowhide/MS +cowl/MGSJ +cowlick/MS +cowling/M +cowman/M +cowmen +coworker/MS +cowpat/S +cowpoke/MS +cowpox/M +cowpuncher/SM +cowrie/SM +cowshed/S +cowslip/SM +cox/GDS +coxcomb/MS +coxswain/MS +coy/TPRY +coyness/M +coyote/SM +coypu/SM +cozen/SDG +cozenage/M +cozily +coziness/M +cozy/RSMTP +cpd +cpl +cps +crab/MS +crabbed +crabber/SM +crabbily +crabbiness/M +crabbing +crabby/PRT +crabgrass/M +crablike +crabwise +crack/SMDRYZGJ +crackdown/MS +cracker/M +crackerjack/MS +crackhead/MS +crackle/DSJMG +crackling/M +crackpot/MS +crackup/SM +cradle/DSMG +craft/SMDG +craftily +craftiness/M +craftsman/M +craftsmanship/M +craftsmen +craftspeople +craftswoman/M +craftswomen +crafty/RTP +crag/MS +cragginess/M +craggy/RPT +cram/S +crammed +crammer/S +cramming +cramp/SMDG +cramping/M +crampon/SM +cranberry/SM +crane/DSMG +cranial +cranium/SM +crank/SMDG +crankcase/SM +crankily +crankiness/M +crankshaft/MS +cranky/PRT +cranny/DSM +crap/MS +crape/SM +crapped +crapper/S +crappie/RSMT +crapping +crappy +craps/M +crapshooter/MS +crash/MDSG +crass/RYTP +crassness/M +crate/DRSMZG +crater/MDG +cravat/SM +crave/DSGJ +craven/SMYP +cravenness/M +craving/M +craw/MS +crawdad/SM +crawl/SMDRZG +crawler/M +crawlspace/SM +crawly/TRSM +cray/S +crayfish/MS +crayola/S +crayon/GSMD +craze/DSMG +crazily +craziness/M +crazy/PRSMT +creak/SMDG +creakily +creakiness/M +creaky/RPT +cream/SMDRZG +creamer/M +creamery/SM +creamily +creaminess/M +creamy/RPT +crease/ICGMSD +create/KADSGNV +creation's/K +creation/ASM +creationism/SM +creationist/SM +creative/SMYP +creativeness/M +creativity/M +creator/MS +creature/SM +creche/SM +cred +credence/M +credential/SGMD +credenza/SM +credibility/IM +credible/I +credibly/I +credit/EGSBMD +creditably/E +creditor/SM +creditworthy/P +credo/SM +credulity/IM +credulous/IY +credulousness/M +creed/SM +creek/SM +creel/SM +creep/SMRZG +creeper/M +creepily +creepiness/M +creepy/TPR +cremains/M +cremate/GNDSX +cremation/M +crematoria +crematorium/MS +crematory/SM +creme/SM +crenelate/XGNDS +crenelation/M +creole/SM +creosote/MGDS +crepe/SM +crept +crepuscular +crescendo/CSM +crescent/MS +cress/M +crest/SMDG +crestfallen +crestless +cretaceous +cretin/SM +cretinism/M +cretinous +cretonne/M +crevasse/SM +crevice/MS +crew/MDGS +crewel/M +crewelwork/M +crewman/M +crewmen +crib/MS +cribbage/M +cribbed +cribber/MS +cribbing +crick/SMDG +cricket/MRSZG +cricketer/M +crier/M +crikey +crime/SM +criminal/MYS +criminality/M +criminalize/CGDS +criminologist/MS +criminology/M +crimp/SMDG +crimson/SMDG +cringe/DSMG +crinkle/DSMG +crinkly/RT +crinoline/SM +cripes +cripple/DRSMZG +crippler/M +crippleware +crippling/Y +crises +crisis/M +crisp/SMDRYTGP +crispbread/S +crispiness/M +crispness/M +crispy/PRT +crisscross/GMDS +criteria +criterion/M +critic/SM +critical/UY +criticism/MS +criticize/ZGDRS +criticizer/M +critique/MGDS +critter/SM +croak/SMDG +croaky/RT +crochet/SMDRZG +crocheter/M +crocheting/M +crock/SMD +crockery/M +crocodile/SM +crocus/MS +croft/SRZG +croissant/MS +crone/SM +crony/SM +cronyism/M +crook/SMDG +crooked/PTRY +crookedness/M +crookneck/SM +croon/SMDRZG +crooner/M +crop/MS +cropland/SM +cropped +cropper/MS +cropping +croquet/M +croquette/SM +crosier/MS +cross's +cross/AUGTSD +crossbar/SM +crossbeam/MS +crossbones/M +crossbow/SM +crossbowman/M +crossbowmen +crossbred +crossbreed/SGM +crosscheck/SMDG +crosscurrent/MS +crosscut/SM +crosscutting +crosser +crossfire/MS +crosshatch/GDS +crossing/SM +crossly +crossness/M +crossover/MS +crosspatch/MS +crosspiece/SM +crossroad/MS +crossroads/M +crosstown +crosswalk/MS +crosswind/MS +crosswise +crossword/MS +crotch/MS +crotchet/SM +crotchety +crouch/GMDS +croup/M +croupier/M +croupy/ZTR +crouton/MS +crow/MDGS +crowbar/MS +crowd/SMDG +crowded/U +crowdfund/SDG +crowfeet +crowfoot/SM +crown/SMDG +crowned/U +crozier/MS +croûton/MS +crucial/Y +crucible/SM +crucifix/MS +crucifixion/SM +cruciform/SM +crucify/DSG +crud/M +cruddy/TR +crude/RMYTP +crudeness/M +crudites/M +crudity/SM +crudités/M +cruel/RYPT +cruelness/M +cruelty/SM +cruet/SM +cruft/SD +crufty +cruise/DRSMZG +cruiser/M +cruller/MS +crumb/SMDYG +crumble/MGDS +crumbliness/M +crumbly/TPR +crumby/TR +crumminess/M +crummy/PTR +crumpet/MS +crumple/MGDS +crunch/GMDRS +crunchiness/M +crunchy/TRP +crupper/MS +crusade/MZGDRS +crusader/M +cruse/SM +crush/MDRSZG +crusher/M +crushing/Y +crust/SMDG +crustacean/SM +crustal +crustily +crustiness/M +crusty/TRP +crutch/MS +crux/MS +cry/ZGJDRSM +crybaby/SM +cryogenic/S +cryogenics/M +cryonics +cryosurgery/M +crypt/SM +cryptic +cryptically +cryptogram/SM +cryptographer/SM +cryptography/M +crystal/SM +crystalline +crystallization/M +crystallize/ADSG +crystallographic +crystallography +crèche/MS +ct +ctn +ctr +cu +cub/ZGSMDR +cubbyhole/MS +cube/MS +cuber/M +cubic +cubical +cubicle/MS +cubism/M +cubist/SM +cubit/SM +cuboid/S +cuckold/MDSG +cuckoldry/M +cuckoo/SM +cucumber/SM +cud/SM +cuddle/DSMG +cuddly/TR +cudgel/SGMDJ +cue/DSMG +cuff/MDGS +cuisine/SM +culinary +cull/MDGS +cullender/MS +culminate/XDSGN +culmination/M +culotte/SM +culpability/M +culpable/I +culpably +culprit/SM +cult/MS +cultism/M +cultist/MS +cultivable +cultivar/SM +cultivate/BDSGN +cultivated/U +cultivation/M +cultivator/MS +cultural/Y +culture/MGDS +cultured/U +culvert/MS +cum/SM +cumber/SDG +cumbersome/P +cumbersomeness/M +cumbrous +cumin/M +cummerbund/MS +cumming +cumulative/Y +cumuli +cumulonimbi +cumulonimbus/M +cumulus/M +cuneiform/M +cunnilingus/M +cunning/MRYT +cunt/MS! +cup/SM +cupboard/SM +cupcake/MS +cupful/SM +cupid/SM +cupidity/M +cupola/SMD +cuppa/S +cupped +cupping +cupric +cur/SMY +curability/M +curacao +curacy/SM +curare/M +curate/DSMGV +curative/MS +curator/KMS +curatorial +curaçao +curb/MDGS +curbing/M +curbside +curbstone/SM +curd/MS +curdle/DSG +cure's +cure/KZGBDRS +cured/U +curer/KM +curettage/M +curfew/SM +curia/M +curiae +curie/SM +curio/SM +curiosity/SM +curious/YP +curiousness/M +curium/M +curl's +curl/UDGS +curler/SM +curlew/SM +curlicue/DSMG +curliness/M +curling/M +curly/RPT +curmudgeon/MYS +currant/MS +currency/SM +current's +current/FAY +currents +curricula +curricular +curriculum/M +curry/DSMG +currycomb/SGMD +curse/DSMGV +cursed/Y +cursive's +cursive/EAY +cursor/SM +cursorily +cursoriness/M +cursory/P +curt/RYTP +curtail/GDSL +curtailment/SM +curtain/GMDS +curtness/M +curtsy/GDSM +curvaceous/P +curvaceousness/M +curvature/SM +curve/DSMG +curvy/RT +cushion/MDSG +cushy/RT +cusp/MS +cuspid/SM +cuspidor/SM +cuss's +cuss/FEGSD +cussed/PY +custard/MS +custodial +custodian/MS +custodianship/M +custody/M +custom/SZMR +customarily +customary/U +customer/M +customhouse/SM +customization/M +customize/DSG +cut/TSMR +cutaneous +cutaway/MS +cutback/MS +cute/YP +cuteness/M +cutesy/TR +cutey/S +cuticle/MS +cutie/SM +cutlass/MS +cutler/SM +cutlery/M +cutlet/SM +cutoff/SM +cutout/SM +cutter/SM +cutthroat/SM +cutting/MYS +cuttlefish/MS +cutup/SM +cutworm/MS +cw +cwt +cyan/M +cyanide/M +cyberbully/SM +cybercafe/S +cybercafé/S +cybernetic/S +cybernetics/M +cyberpunk/SM +cybersex +cyberspace/MS +cyborg/SM +cyclamen/MS +cycle/ADSMG +cyclic +cyclical/Y +cyclist/MS +cyclometer/MS +cyclone/MS +cyclonic +cyclopaedia/MS +cyclopedia/MS +cyclopes +cyclops/M +cyclotron/MS +cygnet/MS +cylinder/MS +cylindrical +cymbal/MS +cymbalist/MS +cynic/SM +cynical/Y +cynicism/M +cynosure/MS +cypher/M +cypress/MS +cyst/MS +cystic +cystitis +cytokines +cytologist/SM +cytology/M +cytoplasm/M +cytoplasmic +cytosine/M +czar/MS +czarina/SM +czarism +czarist/SM +d'Arezzo/M +d'Estaing/M +d/NXGJ +dB +dab/SM +dabbed +dabber/MS +dabbing +dabble/ZGDRS +dabbler/M +dace/SM +dacha/MS +dachshund/MS +dactyl/MS +dactylic/MS +dad/SM +dadaism/M +dadaist/MS +daddy/SM +dado/SM +dadoes +daemon/MS +daemonic +daffiness/M +daffodil/SM +daffy/PTR +daft/PTRY +daftness/M +dag/S +dagger/MS +dago/S +dagoes +daguerreotype/DSMG +dahlia/MS +dailiness/M +daily/PSM +daintily +daintiness/M +dainty/RSMTP +daiquiri/MS +dairy/GSM +dairying/M +dairymaid/MS +dairyman/M +dairymen +dairywoman/M +dairywomen +dais/MS +daisy/SM +dale/SM +dalliance/MS +dallier/M +dally/ZGDRS +dalmatian/MS +dam/SM +damage/MGDS +damageable +damaged/U +damages/M +damask/MDGS +dame/SM +dammed +damming +dammit +damn/SBGMD +damnably +damnation/M +damned/T +damp/SPXZTGMDNRY +dampen/ZGDR +dampener/M +damper/M +dampness/M +damsel/MS +damselfly/SM +damson/MS +dance/MZGDRS +dancer/M +dancing/M +dandelion/SM +dander/M +dandify/GDS +dandle/GDS +dandruff/M +dandy/TRSM +dang/SZGDR +danger/M +dangerous/Y +dangle/ZGDRS +dangler/M +danish/MS +dank/PTRY +dankness/M +danseuse/MS +dapper/TR +dapple/MGDS +dare/DRSMZG +daredevil/MS +daredevilry/M +darer/M +daresay +daring/MY +dark/PXTMNRY +darken/ZGDR +darkener/M +darkie/S +darkness/M +darkroom/MS +darling/MS +darn/SZGMDR +darned/TR +darner/M +dart/SZGMDR +dartboard/MS +darter/M +dash/ZGMDRS +dashboard/SM +dasher/M +dashiki/MS +dashing/Y +dastard/MYS +dastardliness/M +data +database/SM +datatype +date/DRSMZGV +datebook/S +dated/U +dateless +dateline/MGDS +dater/M +dative/MS +datum/M +daub/SZGMDR +dauber/M +daughter/SMY +daunt/GDS +daunting/Y +dauntless/YP +dauntlessness/M +dauphin/MS +davenport/MS +davit/MS +dawdle/ZGDRS +dawdler/M +dawn/SGMD +day/SM +daybed/MS +daybreak/M +daycare/M +daydream/MDRZGS +daydreamer/M +daylight/MS +daylights/M +daylong +daytime/M +daze/DSMG +dazed/Y +dazzle/MZGDRS +dazzler/M +dazzling/Y +db +dbl +dc +dd/SDG +dded/K +dding/K +deacon/MS +deaconess/MS +dead/XTMNRY +deadbeat/MS +deadbolt/SM +deaden/GD +deadhead/SDG +deadline/SM +deadliness/M +deadlock/GSMD +deadly/TPR +deadpan/MS +deadpanned +deadpanning +deadwood/M +deaf/PXTNR +deafen/GD +deafening/Y +deafness/M +deal/SJZGMR +dealer/M +dealership/SM +dealing/M +dealt +dean/M +deanery/SM +deanship/M +dear/SPTMRYH +dearest/S +dearie/M +dearness/M +dearth/M +dearths +deary/SM +death/MY +deathbed/SM +deathblow/MS +deathless/Y +deathlike +deaths +deathtrap/MS +deathwatch/MS +deaves +deb/SM +debacle/MS +debarkation/M +debarment/M +debate/BMZR +debater/M +debating/M +debauch/MDSG +debauchee/MS +debauchery/SM +debenture/MS +debilitate/DSGN +debilitation/M +debility/SM +debit/D +debonair/PY +debonairness/M +debouch/GDS +debridement +debris/M +debt/SM +debtor/MS +debugger/S +debut/GMD +debutante/SM +decade/MS +decadence/M +decadency/M +decadent/MYS +decaf/MS +decaffeinate/DSG +decagon/MS +decal/MS +decampment/M +decapitate/XGNDS +decapitator/MS +decathlete/S +decathlon/SM +decay/GD +deceased/M +decedent/MS +deceit/MS +deceitful/YP +deceitfulness/M +deceive/UGDS +deceiver/MS +deceiving/Y +decelerate/GNDS +deceleration/M +decelerator/SM +decency/ISM +decennial/SM +decent/IY +deception/MS +deceptive/YP +deceptiveness/M +decibel/MS +decidable/U +decide/BZGDRS +decided/Y +deciduous +deciliter/MS +decimal/SM +decimalization +decimate/DSGN +decimation/M +decimeter/MS +decipherable/UI +decision/IM +decisions +decisive/IPY +decisiveness/IM +deck/SGMD +deckchair/S +deckhand/SM +deckle/S +declamation/MS +declamatory +declaration/MS +declarative +declaratory +declare/DRSZGB +declared/U +declarer/M +declension/SM +declination/M +decline/DRSMZG +decliner/M +declivity/SM +decolletage/SM +decollete +decongestant/MS +deconstructionism +decor/MS +decorate/AGNVDS +decorating/M +decoration/AM +decorations +decorative/Y +decorator/MS +decorous/IY +decorousness/M +decorum/M +decoupage/DSMG +decoy/GMDS +decreasing/Y +decree/MDS +decreeing +decremented +decrements +decrepit +decrepitude/M +decriminalization/M +decry/GDS +decryption +dedicate/AGDS +dedication/SM +dedicator/SM +dedicatory +deduce/GDS +deducible +deduct/GVD +deductible/SM +deduction/SM +deductive/Y +deed/GD +deejay/MS +deem/ASGD +deep/SPXTMNRY +deepen/GD +deepness/M +deer/M +deerskin/M +deerstalker/S +def/Z +defacement/M +defacer/SM +defalcate/DSXGN +defalcation/M +defamation/M +defamatory +defame/ZGDRS +defamer/M +defaulter/SM +defeat/MDRZGS +defeated/U +defeater/M +defeatism/M +defeatist/MS +defecate/GNDS +defecation/M +defect/MDGVS +defection/MS +defective/MPYS +defectiveness/M +defector/MS +defendant/SM +defended/U +defenestration/S +defense/DSMGV +defenseless/YP +defenselessness/M +defensible/I +defensibly/I +defensive/MYP +defensiveness/M +deference/M +deferential/Y +deferral/MS +deferred +deferring +deffer +deffest +defiant/Y +defibrillation +defibrillator/S +deficiency/SM +deficient +deficit/SM +defilement/M +definable/IU +define/AGDS +defined/U +definer/MS +definite/IYVP +definiteness/IM +definition/AM +definitions +definitive/Y +deflate/GNDS +deflation/M +deflationary +deflect/DGVS +deflection/MS +deflector/SM +defogger/SM +defoliant/SM +defoliate/DSGN +defoliation/M +defoliator/MS +deformity/SM +defraud/DRZGS +defrauder/M +defrayal/M +defrock/DG +defroster/MS +deft/PTRY +deftness/M +defunct +defy/GDS +deg +degeneracy/M +degenerate/MV +degrade/B +degree/MS +dehydrator/SM +dehydrogenase +deicer/MS +deification/M +deify/NGDS +deign/GDS +deist/MS +deistic +deity/SM +deject/GDS +dejected/Y +dejection/M +delay/ZDR +delectable +delectably +delectation/M +delegate/GD +delete/XGNDS +deleterious +deletion/M +delft/M +delftware/M +deli/SM +deliberate/XYVP +deliberateness/M +delicacy/ISM +delicate/IY +delicateness/M +delicatessen/SM +delicious/PY +deliciousness/M +delighted/Y +delightful/Y +deliminator +delineate/GNXDS +delineation/M +delinquency/SM +delinquent/SMY +deliquesce/DSG +deliquescent +delirious/YP +deliriousness/M +delirium/SM +deliver/ADGS +deliverable +deliverance/M +delivered/U +deliverer/SM +dell/SM +delphinium/MS +delta/MS +delude/GDS +deluge/MGDS +delusion/MS +delusional +delusive/Y +deluxe +delve/ZGDRS +delver/M +demagogic +demagogically +demagogue/SM +demagoguery/M +demagogy/M +demand/GMDS +demanding/U +demarcate/DSGNX +demarcation/M +demean/GDS +demeanor/M +demented/Y +dementia/M +demesne/MS +demigod/MS +demigoddess/MS +demijohn/SM +demimondaine/SM +demimonde/M +demise/MGDS +demitasse/MS +demo/GMD +democracy/SM +democrat/MS +democratic/U +democratically +democratization/M +democratize/GDS +demode +demographer/SM +demographic/SM +demographically +demographics/M +demography/M +demolish/DSG +demolition/MS +demon/MS +demonetization/M +demoniac +demoniacal/Y +demonic +demonically +demonize/GDS +demonology/SM +demonstrability +demonstrable/I +demonstrably +demonstrate/XGNVDS +demonstration/M +demonstrative/MYSP +demonstrativeness/M +demonstrator/MS +demote/GD +demotic +demount +demulcent/SM +demur/TMRS +demure/PY +demureness/M +demurral/SM +demurred +demurrer/SM +demurring +den/M +denationalization +denaturation +denature/DG +dendrite/SM +dengue/M +deniability +deniable/U +denial/MS +denier/M +denigrate/DSGN +denigration/M +denim/MS +denitrification +denizen/MS +denominational +denotative +denouement/MS +denounce/LDSG +denouncement/SM +dense/PYTR +denseness/M +density/SM +dent/ISGMD +dental/Y +dentifrice/SM +dentin/M +dentine/M +dentist/MS +dentistry/M +dentition/M +denture/IMS +denuclearize/GDS +denudation/M +denude/GDS +denunciation/SM +deny/ZGDRS +deodorant/SM +deodorization/M +deodorize/DRSZG +deodorizer/M +departed/M +department/MS +departmental/Y +departmentalization/M +departmentalize/GDS +departure/SM +dependability/M +dependable/U +dependably +dependence/IM +dependency/SM +dependent/IMYS +depict/GDS +depiction/MS +depilatory/SM +deplete/GNDS +depletion/M +deplorably +deplore/BGDS +deploy/ALGDS +deployment/AM +deployments +deponent/MS +deportation/MS +deportee/MS +deportment/M +deposit/AGMDS +depositor/MS +depository/SM +deprave/GDS +depravity/SM +deprecate/GNDS +deprecating/Y +deprecation/M +deprecatory +depreciate/DSGN +depreciation/M +depredation/SM +depressant/SM +depressing/Y +depression/SM +depressive/SM +depressor/MS +depressurization +deprive/GDS +deprogramming +depth/M +depths +deputation/MS +depute/DSG +deputize/DSG +deputy/SM +derailleur/SM +derailment/SM +derangement/M +derby/SM +derelict/MS +dereliction/M +deride/GDS +derision/M +derisive/PY +derisiveness/M +derisory +derivation/MS +derivative/MS +derive/B +dermal +dermatitis/M +dermatological +dermatologist/SM +dermatology/M +dermis/M +derogate/DSGN +derogation/M +derogatorily +derogatory +derrick/SM +derriere/SM +derringer/SM +derrière/SM +derv +dervish/MS +desalinate/GNDS +desalination/M +desalinization/M +desalinize/GDS +descant/M +descend/FGDS +descendant/MS +descender +describable/I +describe/BZGDR +describer/M +description/SM +descriptive/PY +descriptiveness/M +descriptor/S +descry/GDS +desecrate/DSGN +desecration/M +deselection +desert/SDRZGM +deserter/M +desertification +desertion/SM +deserved/UY +deserving/U +deshabille/M +desiccant/SM +desiccate/DSGN +desiccation/M +desiccator/SM +desiderata +desideratum/M +design/ASDG +designate/DSGNX +designation/M +desirability/UM +desirableness/M +desirably/U +desire/B +desired/U +desirous +desist/SDG +desk/SM +deskill/G +desktop/SM +desolate/PDSYGN +desolateness/M +desolation/M +despair/SMDG +despairing/Y +desperado/M +desperadoes +desperate/YNP +desperateness/M +desperation/M +despicable +despicably +despise/DSG +despite +despoilment/M +despondence/M +despondency/M +despondent/Y +despotic +despotically +despotism/M +dessert/SM +dessertspoon/S +dessertspoonful/S +destination/SM +destine/DSG +destiny/SM +destitute/N +destitution/M +destroy/SZGDR +destroyer/M +destruct/GVMDS +destructibility/IM +destructible/I +destruction/M +destructive/PY +destructiveness/M +desuetude/M +desultorily +desultory +detach/BLGDS +detachment/MS +detain/LGDS +detainee/MS +detainment/M +detect/SDGVB +detectable/U +detected/U +detection/M +detective/SM +detector/SM +detente/SMNX +detention/M +deter/SL +detergent/SM +deteriorate/DSGN +deterioration/M +determent/M +determinable/I +determinant/SM +determinate +determine/AGDS +determined/U +determinedly +determiner/SM +determinism/M +deterministic +deterred/U +deterrence/M +deterrent/MS +deterring +detestably +detestation/M +dethrone/DSLG +dethronement/M +detonate/GNDSX +detonation/M +detonator/SM +detox/MDSG +detoxification/M +detoxify/DSGN +detract/GD +detriment/SM +detrimental/Y +detritus/M +deuce/SM +deuterium/M +devastate/GNDS +devastating/Y +devastation/M +devastator/MS +develop/ASGDL +developed/U +developer/SM +development/ASM +developmental/Y +deviance/M +deviancy/M +deviant/SM +deviate/DSMGNX +deviating/U +deviation/M +devil/SMDGL +devilish/YP +devilishness/M +devilment/M +devilry/SM +deviltry/SM +devious/YP +deviousness/M +devoid +devolution/M +devolve/DSG +devoted/Y +devotee/SM +devotion/MS +devotional/SM +devour/SDG +devout/PRYT +devoutness/M +dew/M +dewberry/SM +dewclaw/SM +dewdrop/SM +dewiness/M +dewlap/SM +dewy/RTP +dexterity/M +dexterous/YP +dexterousness/M +dextrose/M +dharma +dhoti/SM +dhow/MS +diabetes/M +diabetic/SM +diabolic +diabolical/Y +diacritic/MS +diacritical +diadem/SM +diaereses +diaeresis/M +diagnose/DSG +diagnosis/M +diagnostic/S +diagnostically +diagnostician/SM +diagnostics/M +diagonal/SMY +diagram/SM +diagrammatic +diagrammatically +diagrammed +diagramming +dial/AMDGS +dialect/SM +dialectal +dialectic/SM +dialectical +dialectics/M +dialing/S +dialog +dialogue/SM +dialyses +dialysis/M +dialyzes +diam +diamante +diamanté +diameter/SM +diametric +diametrical/Y +diamond/SM +diamondback/MS +diapason/SM +diaper/SMDG +diaphanous +diaphragm/SM +diaphragmatic +diarist/SM +diarrhea/M +diary/SM +diaspora/SM +diastase/M +diastole/M +diastolic +diathermy/M +diatom/SM +diatomic +diatonic +diatribe/SM +dibble/DSMG +dibs/M +dice/GDS +dices/I +dicey +dichotomous +dichotomy/SM +dicier +diciest +dick/MRXZS +dicker/DG +dickey/SM +dickhead/S +dicky/SM +dickybird/S +dicotyledon/MS +dicotyledonous +dict +dicta +dictate/DSMGNX +dictation/M +dictator/SM +dictatorial/Y +dictatorship/SM +diction/M +dictionary/SM +dictum/M +did/AU +didactic +didactically +diddle/DRSZG +diddler/M +diddly +diddlysquat +diddums +didgeridoo/S +didn't +dido/MS +didoes +didst +die/DSM +diehard/SM +dielectric/MS +diereses +dieresis/M +diesel/SMDG +diet/MDRZGS +dietary/SM +dieter/M +dietetic/S +dietetics/M +dietician/MS +dietitian/MS +diff/DRZGS +differ/DG +difference/IM +differences +different/IY +differential/SM +differentiate/DSGN +differentiated/U +differentiation/M +difficult/Y +difficulty/SM +diffidence/M +diffident/Y +diffract/GSD +diffraction/M +diffuse/DSYGNVP +diffuseness/M +diffusion/M +dig/SM +digerati/M +digest/SMDGV +digested/U +digestibility/M +digestible/I +digestion/IM +digestions +digestive/S +digger/SM +digging/S +diggings/M +digicam/S +digit/SM +digital/Y +digitalis/M +digitization +digitize/GDS +dignified/U +dignify/DSG +dignitary/SM +dignity/ISM +digraph/M +digraphs +digress/GVDS +digression/MS +dike/MGDS +diktat/S +dilapidated +dilapidation/M +dilatation/M +dilate/DSGN +dilation/M +dilator/SM +dilatory +dildo/S +dilemma/MS +dilettante/SM +dilettantish +dilettantism/M +diligence/M +diligent/Y +dill/MS +dilly/SM +dillydally/DSG +dilute/DSGNX +diluted/U +dilution/M +dim/PSRY +dime/MS +dimension/SM +dimensional +dimensionless +diminish/GDS +diminished/U +diminuendo/SM +diminuendoes +diminution/SM +diminutive/SM +dimity/M +dimmed/U +dimmer/SM +dimmest +dimming +dimness/M +dimple/DSMG +dimply +dimwit/SM +dimwitted +din/ZGSMDR +dinar/SM +dine/S +diner/M +dinette/MS +ding/MDG +dingbat/MS +dingdong/SGMD +dinghy/SM +dingily +dinginess/M +dingle/SM +dingo/M +dingoes +dingus/MS +dingy/RPT +dink/R +dinky/RSMT +dinned +dinner/SMDG +dinnertime/M +dinnerware/M +dinning +dinosaur/SM +dint/M +diocesan/MS +diocese/MS +diode/SM +diorama/SM +dioxide/SM +dioxin/SM +dip/SM +diphtheria/M +diphthong/SM +diploid/SM +diploma/SM +diplomacy/M +diplomat/MS +diplomata +diplomatic/U +diplomatically +diplomatist/MS +diplopia +dipole/SM +dipped +dipper/SM +dipping +dippy/RT +dipso/S +dipsomania/M +dipsomaniac/MS +dipstick/SM +dipterous +diptych/M +diptychs +dire/YTR +direct/ASDGVT +directer +direction/IM +directional +directionless +directions +directive/SM +directly +directness/IM +director/MS +directorate/SM +directorial +directorship/SM +directory/SM +direful +dirge/SM +dirigible/MS +dirk/MS +dirndl/SM +dirt/M +dirtball/S +dirtily +dirtiness/M +dirty/DRSTGP +dis/M +disable/DSGL +disablement/M +disambiguate/N +disappointing/Y +disarming/Y +disassembly +disastrous/Y +disbandment/M +disbarment/M +disbelieving/Y +disbursal/M +disburse/DSGL +disbursement/MS +disc/M +discern/LSDG +discernible/I +discernibly +discerning/Y +discernment/M +discharged/U +disciple/SM +discipleship/M +disciplinarian/SM +disciplinary +discipline/DSMG +disciplined/U +disclose/DSG +disclosed/U +disco/MG +discography/SM +discoloration/S +discombobulate/DSGN +discombobulation/M +discomfit/DG +discomfiture/M +discommode/DG +disconcerting/Y +disconnected/PY +disconnectedness/M +disconsolate/Y +discordance/M +discordant/Y +discotheque/SM +discourage/LGDS +discouragement/SM +discouraging/Y +discover/ASDG +discovered/U +discoverer/MS +discovery/ASM +discreet/PRYT +discreetness/M +discrepancy/SM +discrepant +discrete/PYN +discreteness/M +discretion/IM +discretionary +discriminant +discriminate/GNDS +discriminating/U +discrimination/M +discriminator/MS +discriminatory +discursiveness/M +discus/MS +discussant/SM +discussion/SM +disdain/SMDG +disdainful/Y +disembowel/SDLG +disembowelment/M +disfigurement/SM +disfranchisement/M +disgorgement/M +disgruntle/LGDS +disgruntlement/M +disguise/GD +disguised/U +disgusted/Y +disgusting/Y +dish/MDSG +dishabille/M +disharmonious +dishcloth/M +dishcloths +disheartening/Y +dishevel/DGLS +dishevelment/M +dishpan/SM +dishrag/SM +dishtowel/MS +dishware/M +dishwasher/MS +dishwater/M +dishy +disillusion/GLD +disillusionment/M +disinfectant/MS +disinfection/M +disinterested/PY +disinterestedness/M +disjointed/YP +disjointedness/M +disjunctive +disjuncture +disk/MS +diskette/MS +dislodge/GDS +dismal/Y +dismantlement/M +dismay/SMDG +dismayed/U +dismember/LGD +dismemberment/M +dismissive/Y +disorder/Y +disorganization/M +disparage/DSGL +disparagement/M +disparaging/Y +disparate/Y +dispatcher/MS +dispel/S +dispelled +dispelling +dispensary/SM +dispensation/MS +dispense/BZGDRS +dispenser/M +dispersal/M +disperse/GNDS +dispersion/M +dispirit/GDS +displeasure/M +disposable/SM +disposal/SM +disposed/I +disposition/ISM +dispossession/M +disproof/SM +disproportional +disprove/B +disputable/I +disputably/I +disputant/MS +disputation/SM +disputatious/Y +dispute/DRSMZGB +disputed/U +disputer/M +disquiet/GSMD +disquisition/MS +disregardful +disrepair/M +disrepute/MB +disrupt/GVSD +disruption/SM +disruptive/Y +dissect/SDG +dissed +dissemblance/M +dissemble/ZGDRS +dissembler/M +disseminate/GNDS +dissemination/M +dissension/SM +dissent/SMDRZG +dissenter/M +dissertation/SM +dissidence/M +dissident/MS +dissimilar +dissimilitude/S +dissing +dissipate/GNDS +dissipation/M +dissociate/GNDS +dissociation/M +dissoluble/I +dissolute/YNP +dissoluteness/M +dissolve/AGDS +dissolved/U +dissonance/SM +dissonant +dissuade/GDS +dissuasive +dist +distaff/SM +distal/Y +distance/DSMG +distant/Y +distaste/SM +distemper/M +distention/SM +distillate/SMNX +distillation/M +distillery/SM +distinct/IYTVP +distincter +distinction/SM +distinctive/YP +distinctiveness/M +distinctness/IM +distinguish/GDSB +distinguishable/I +distinguished/U +distort/GDR +distortion/MS +distract/DG +distracted/Y +distraction/S +distrait +distraught +distress/DG +distressful +distressing/Y +distribute/AGNVDS +distributed/U +distribution/AM +distributional +distributions +distributive/Y +distributor's +distributor/AS +distributorship/S +district's +district/AS +disturb/ZGSDR +disturbance/SM +disturbed/U +disturber/M +disturbing/Y +disunion/M +disyllabic +ditch/MDSG +dither/SMDRZG +ditherer/M +ditransitive +ditsy +ditto/SMDG +dittoes +ditty/SM +ditz/MS +ditzy/R +diuretic/MS +diurnal/Y +div +diva/MS +divalent +divan/SM +dive/MZTGDRS +diver/M +diverge/DSG +divergence/MS +divergent +diverse/XYNP +diverseness/M +diversification/M +diversify/GNDS +diversion/M +diversionary +diversity/SM +divert/SDG +diverticulitis/M +divest/SLDG +divestiture/MS +divestment/M +divide/DRSMZGB +divided/U +dividend/MS +divider/M +divination/M +divine/DRSMYZTG +diviner/M +diving/M +divinity/SM +divisibility/IM +divisible/I +division/MS +divisional +divisive/PY +divisiveness/M +divisor/SM +divorce/DSLMG +divorcee/MS +divorcement/MS +divorcée/MS +divot/SM +divulge/GDS +divvy/DSMG +dixieland/M +dizzily +dizziness/M +dizzy/DRSPTG +djellaba/MS +djellabahs +do/SJMRHZG +doable +dob/S +dobbed +dobbin/SM +dobbing +doberman/MS +dobro +doc/SM +docent/SM +docile/Y +docility/M +dock/MDRZGS +docket/SMDG +dockland/S +dockside +dockworker/MS +dockyard/MS +doctor/SMDG +doctoral +doctorate/MS +doctrinaire/MS +doctrinal +doctrine/MS +docudrama/SM +document/GMDS +documentary/SM +documentation/SM +documented/U +dodder/SMDG +doddery +doddle +dodge/DRSMZG +dodgem/S +dodger/M +dodgy/RT +dodo/MS +doe/SM +doer/M +does/AU +doeskin/MS +doesn't +doff/DGS +dog/SM +dogcart/SM +dogcatcher/SM +doge/MS +dogear/SMDG +dogfight/SM +dogfish/MS +dogged/PY +doggedness/M +doggerel/M +doggie/M +dogging +doggone/TGDRS +doggoned/TR +doggy/RSMT +doghouse/SM +dogie/SM +dogleg/SM +doglegged +doglegging +doglike +dogma/SM +dogmatic +dogmatically +dogmatism/M +dogmatist/SM +dognapper +dogsbody/S +dogsled/S +dogtrot/MS +dogtrotted +dogtrotting +dogwood/MS +doh/M +doily/SM +doing/USM +doldrums/M +dole's +dole/FGDS +doleful/YP +dolefulness/M +doll/MDGS +dollar/SM +dollhouse/SM +dollop/SGMD +dolly/SM +dolmen/SM +dolomite/M +dolor/M +dolorous/Y +dolphin/MS +dolt/MS +doltish/YP +doltishness/M +domain/SM +dome/MGDS +domestic/SM +domestically +domesticate/DSGN +domesticated/U +domestication/M +domesticity/M +domicile/DSMG +domiciliary +dominance/M +dominant/SMY +dominate/DSGN +domination/M +dominatrices +dominatrix/M +domineer/SGD +domineering/Y +dominion/SM +domino/M +dominoes +don't +don/SM +dona/MS +donate/DSXGN +donation/M +done/FAU +dong/MDGS +dongle/SM +donkey/SM +donned +donning +donnish +donnybrook/MS +donor/SM +donuts +doodad/SM +doodah +doodahs +doodle/DRSMZG +doodlebug/SM +doodler/M +doohickey/SM +doolally +doom/MDGS +doomsayer/MS +doomsday/M +doomster/S +door's +door/IS +doorbell/MS +doorjamb/S +doorkeeper/MS +doorknob/MS +doorknocker/S +doorman/M +doormat/SM +doormen +doorplate/SM +doorpost/S +doorstep/MS +doorstepped +doorstepping +doorstop/MS +doorway/SM +dooryard/MS +dopa/M +dopamine +dope/MZGDRS +doper/M +dopey +dopier +dopiest +dopiness/M +doping/M +doppelganger/S +doppelgänger/S +dork/MS +dorky/RT +dorm/MRZS +dormancy/M +dormant +dormer/M +dormice +dormitory/SM +dormouse/M +dorsal/Y +dory/SM +dosage/SM +dose/MGDS +dosh +dosimeter/SM +doss/DRSZG +dosshouse/S +dossier/MS +dost +dot/ZGSMDR +dotage/M +dotard/SM +dotcom/SM +dote/S +doter/M +doting/Y +dotted +dotting +dotty/RT +double's +double/ADSG +doubleheader/MS +doublespeak/M +doublet/MS +doubloon/SM +doubly +doubt/SMDRZG +doubter/M +doubtful/PY +doubtfulness/M +doubting/Y +doubtless/Y +douche/DSMG +dough/M +doughnut/SM +doughty/RT +doughy/TR +dour/RYTP +dourness/M +douse/DSG +dove/MS +dovecot/S +dovecote/SM +dovetail/MDSG +dovish +dowager/MS +dowdily +dowdiness/M +dowdy/RSPT +dowel/SMDG +dower/SMDG +down/MDRZGS +downbeat/SM +downcast +downdraft/MS +downer/M +downfall/SMN +downfield +downgrade/DSMG +downhearted/PY +downheartedness/M +downhill/MS +download/MDBSG +downmarket +downplay/DSG +downpour/MS +downrange +downright +downriver +downscale +downshift/SGD +downside/MS +downsize/GDS +downsizing/M +downspout/MS +downstage +downstairs/M +downstate/M +downstream +downswing/MS +downtime/M +downtown/M +downtrend/MS +downtrodden +downturn/MS +downward/S +downwind +downy/RT +dowry/SM +dowse/DRSZG +dowser/M +doxology/SM +doyen/SM +doyenne/MS +doz/XGDNS +doze/M +dozen/MH +dozily +dozy/RTP +dpi +dpt +drab/MYSP +drabber +drabbest +drabness/M +drachma/MS +draconian +draft's +draft/ASDG +draftee/SM +drafter/SM +draftily +draftiness/M +drafting/M +draftsman/M +draftsmanship/M +draftsmen +draftswoman/M +draftswomen +drafty/RTP +drag/MS +dragged +dragging +draggy/TR +dragnet/SM +dragon/SM +dragonfly/SM +dragoon/SMDG +dragster/S +drain/SMDRZG +drainage/M +drainboard/SM +drainer/M +drainpipe/MS +drake/SM +dram/MS +drama/SM +dramatic/S +dramatically +dramatics/M +dramatist/SM +dramatization/SM +dramatize/DSG +drank +drape/DRSMZG +draper/M +drapery/SM +drastic +drastically +drat +dratted +draughtboard/S +draw/MRZGSJ +drawback/MS +drawbridge/MS +drawer/M +drawing/M +drawl/SMDG +drawn/A +drawstring/MS +dray/MS +dread/SMDG +dreadful/PY +dreadfulness/M +dreadlocks/M +dreadnought/MS +dream/SMDRZG +dreamboat/MS +dreamed/U +dreamer/M +dreamily +dreaminess/M +dreamland/M +dreamless +dreamlike +dreamworld/SM +dreamy/RPT +drear +drearily +dreariness/M +dreary/RPT +dredge/DRSMZG +dredger/M +dregs/M +drench/GDS +dress/AUGSDM +dressage/M +dresser/MS +dressiness/M +dressing/SM +dressmaker/SM +dressmaking/M +dressy/TPR +drew/A +dribble/MZGDRS +dribbler/M +driblet/MS +drier/M +drift/SMDRZG +drifter/M +driftnet/S +driftwood/M +drill/SMDRZG +driller/M +drillmaster/SM +drily +drink/SMRBJZG +drinkable/U +drinker/M +drip/MS +dripped +dripping/SM +drippy/TR +drive/RSMZGJ +drivel/SZGMDR +driveler/M +driven +driver/M +driveshaft/SM +driveway/MS +drizzle/MGDS +drizzly +drogue/SM +droid/S +droll/RPT +drollery/SM +drollness/M +drolly +dromedary/SM +drone/DSMG +drool/SMDG +droop/GSMD +droopiness/M +droopy/TPR +drop/MS +dropkick/MS +droplet/SM +dropout/SM +dropped +dropper/SM +dropping/S +droppings/M +dropsical +dropsy/M +dross/M +drought/SM +drove/RSMZ +drover/M +drown/GSJD +drowning/M +drowse/MGDS +drowsily +drowsiness/M +drowsy/RTP +drub/S +drubbed +drubber/SM +drubbing/MS +drudge/MGDS +drudgery/M +drug/MS +drugged +druggie/SM +drugging +druggist/SM +druggy +drugstore/MS +druid/SM +druidism/M +drum/MS +drumbeat/SM +drumlin/SM +drummed +drummer/SM +drumming +drumstick/SM +drunk/STMNR +drunkard/MS +drunken/PY +drunkenness/M +drupe/SM +druthers/M +dry/ZTGDRSMY +dryad/SM +dryer/SM +dryness/M +drys +drywall/M +dual +dualism/M +duality/M +dub/SM +dubbed +dubber/SM +dubbin/M +dubbing +dubiety/M +dubious/YP +dubiousness/M +ducal +ducat/SM +duchess/MS +duchy/SM +duck/MDGS +duckbill/SM +duckboards +duckling/SM +duckpins/M +duckweed/M +ducky/TRSM +duct's/K +duct/CKIFS +ductile +ductility/M +ducting +ductless +dud/GSMD +dude/MS +dudgeon/M +due's +due/IS +duel/MDRJZGS +dueler/M +duelist/SM +duenna/MS +duet/MS +duff/MDRZGS +duffer/M +dug +dugout/MS +duh +duke/MS +dukedom/SM +dulcet +dulcimer/MS +dull/DRPTGS +dullard/SM +dullness/M +dully +duly/U +dumb/RYPT +dumbbell/SM +dumbfound/SDG +dumbness/M +dumbo/S +dumbstruck +dumbwaiter/SM +dumdum/MS +dummy/SM +dump/MDRZGS +dumpiness/M +dumpling/SM +dumpsite/S +dumpster/SM +dumpy/PTR +dun/SM +dunce/SM +dunderhead/MS +dune/MS +dung/MDGS +dungaree/MS +dungeon/SM +dunghill/MS +dunk/MDGS +dunned +dunner +dunnest +dunning +dunno +duo/SM +duodecimal +duodena +duodenal +duodenum/M +duopoly/S +dupe/MZGDRS +duper/M +duple +duplex/MS +duplicate's +duplicate/AGNDS +duplication/AM +duplicator/MS +duplicitous +duplicity/M +durability/M +durable +durably +durance/M +duration/M +duress/M +during +durst +durum/M +dusk/M +duskiness/M +dusky/RTP +dust/MDRZGS +dustbin/SM +dustcart/S +duster/M +dustiness/M +dustless +dustman +dustmen +dustpan/SM +dustsheet/S +dusty/RTP +dutch +duteous/Y +dutiable +dutiful/YP +dutifulness/M +duty/SM +duvet/SM +dwarf/SGMD +dwarfish +dwarfism/M +dweeb/SM +dwell/SJZGR +dweller/M +dwelling/M +dwelt/I +dwindle/DSG +dyadic +dybbuk/SM +dybbukim +dye/DRSMZG +dyeing/A +dyer/M +dyestuff/M +dying/M +dyke/MS +dynamic/MS +dynamical/Y +dynamics/M +dynamism/M +dynamite/MZGDRS +dynamiter/M +dynamo/SM +dynastic +dynasty/SM +dysentery/M +dysfunction/MS +dysfunctional +dyslectic/SM +dyslexia/M +dyslexic/SM +dyspepsia/M +dyspeptic/MS +dysphagia +dysphoria +dysphoric +dysprosium/M +dystonia +dz +débridement +débutante/SM +décolletage/SM +décolleté +démodé +dérailleur/MS +déshabillé/M +détente/M +e'en +e'er +e/FDST +eBay/M +eMusic/M +ea +each +eager/PTRY +eagerness/M +eagle/MS +eaglet/MS +ear/SMDY +earache/SM +earbud/SM +eardrum/SM +earful/SM +earl/MS +earldom/SM +earliness/M +earlobe/SM +early/RTP +earmark/SMDG +earmuff/SM +earn/DRZTGJS +earned/U +earner/M +earnest/SMYP +earnestness/M +earnings/M +earphone/MS +earpiece/S +earplug/SM +earring/SM +earshot/M +earsplitting +earth's +earth/UDYG +earthbound +earthen +earthenware/M +earthiness/M +earthling/MS +earthly/RT +earthquake/SM +earths/U +earthshaking +earthward/S +earthwork/MS +earthworm/MS +earthy/RTP +earwax/M +earwig/SM +ease/EDSM +easel/SM +easement/SM +easily/U +easiness/UM +easing +east/M +eastbound +easterly/SM +eastern/ZR +easterner/M +easternmost +eastward/S +easy/URTP +easygoing +eat/ZGBSNR +eatable/SM +eaten/U +eater/M +eatery/SM +eave/MS +eavesdrop/S +eavesdropped +eavesdropper/SM +eavesdropping +ebb/SMDG +ebony/SM +ebullience/M +ebullient/Y +ebullition/M +eccentric/SM +eccentrically +eccentricity/SM +eccl +ecclesial +ecclesiastic/SM +ecclesiastical/Y +echelon/SM +echinoderm/SM +echo's +echo/ADG +echoes/A +echoic +echolocation/M +echos +eclair/SM +eclat/M +eclectic/SM +eclectically +eclecticism/M +eclipse/DSMG +ecliptic/M +eclogue/SM +ecocide/M +ecol +ecologic +ecological/Y +ecologist/MS +ecology/M +econ +econometric +economic/S +economical/UY +economics/M +economist/SM +economize/DRSZG +economizer/M +economy/SM +ecosystem/MS +ecotourism/M +ecotourist/MS +ecru/M +ecstasy/SM +ecstatic +ecstatically +ecu/S +ecumenical/Y +ecumenicism/M +ecumenism/M +eczema/M +ed/ACSM +edamame +eddy/DSMG +edelweiss/M +edema/SM +edge/MZGJDRS +edger/M +edgeways +edgewise +edgily +edginess/M +edging/M +edgy/RTP +edibility/M +edible/SMP +edibleness/M +edict/SM +edification/M +edifice/SM +edifier/M +edify/DRSZGN +edifying/U +edit's +edit/ADGS +editable +edited/U +edition/MS +editor/SM +editorial/SMY +editorialize/DSG +editorship/M +educ +educability/M +educable/I +educate/ADSGNV +educated/U +education/AM +educational/Y +educationalist/S +educationist/S +educations +educator/MS +educe/DSGB +edutainment/M +eek +eel/SM +eerie/RT +eerily +eeriness/M +eff/GSD +efface/DSLG +effacement/M +effect/SMDGV +effective/IPY +effectiveness/IM +effectual/IY +effectuate/DSG +effeminacy/M +effeminate/Y +effendi/SM +efferent +effervesce/GDS +effervescence/M +effervescent/Y +effete/YP +effeteness/M +efficacious/Y +efficacy/IM +efficiency/ISM +efficient/IY +effigy/SM +efflorescence/M +efflorescent +effluence/M +effluent/MS +effluvia +effluvium/M +effort/SM +effortless/YP +effortlessness/M +effrontery/M +effulgence/M +effulgent +effuse/DSGNVX +effusion/M +effusive/YP +effusiveness/M +egad +egalitarian/SM +egalitarianism/M +egg/GSMD +eggbeater/MS +eggcup/SM +egghead/SM +eggnog/M +eggplant/MS +eggshell/SM +eglantine/SM +ego/SM +egocentric/MS +egocentrically +egocentricity/M +egoism/M +egoist/SM +egoistic +egoistical/Y +egomania/M +egomaniac/MS +egotism/M +egotist/SM +egotistic +egotistical/Y +egregious/PY +egregiousness/M +egress/MS +egret/SM +eh +eider/SM +eiderdown/MS +eigenvalue/S +eight/SM +eighteen/MHS +eighteenth/M +eighteenths +eighth/M +eighths +eightieth/M +eightieths +eighty/SMH +einsteinium/M +eisteddfod/S +either +ejaculate/GNXDS +ejaculation/M +ejaculatory +eject/SDG +ejection/MS +ejector/SM +eke/DSG +elaborate/YGNDSPX +elaborateness/M +elaboration/M +elan/M +eland/SM +elapse/DSG +elastic/MS +elastically +elasticated +elasticity/M +elasticize/DSG +elate/DSGN +elated/Y +elation/M +elbow/SMDG +elbowroom/M +elder/SMY +elderberry/SM +eldercare/M +eldest +eldritch +elect's +elect/ASDGV +electable +election/AMS +electioneer/DGS +elective/MS +elector/MS +electoral/Y +electorate/MS +electric/S +electrical/Y +electrician/MS +electricity/M +electrification/M +electrifier/M +electrify/ZGNDRS +electrocardiogram/MS +electrocardiograph/M +electrocardiographs +electrocardiography/M +electrocute/DSXGN +electrocution/M +electrode/SM +electrodynamics +electroencephalogram/MS +electroencephalograph/M +electroencephalographic +electroencephalographs +electroencephalography/M +electrologist/SM +electrolysis/M +electrolyte/MS +electrolytic +electromagnet/MS +electromagnetic +electromagnetically +electromagnetism/M +electromotive +electron/MS +electronic/S +electronica/M +electronically +electronics/M +electroplate/DSG +electroscope/SM +electroscopic +electroshock/M +electrostatic/S +electrostatics/M +electrotype/MS +eleemosynary +elegance/IM +elegant/IY +elegiac/MS +elegiacal +elegy/SM +elem +element/MS +elemental/Y +elementary +elephant/SM +elephantiasis/M +elephantine +elev +elevate/XDSGN +elevation/M +elevator/MS +eleven/SMH +elevens/S +eleventh/M +elevenths +elf/M +elfin +elfish +elicit/SDG +elicitation/M +elide/DSG +eligibility/IM +eligible +eliminate/XDSGN +elimination/M +eliminator/S +elision/MS +elite/SM +elitism/M +elitist/MS +elixir/SM +elk/SM +ell/SM +ellipse/MS +ellipsis/M +ellipsoid/SM +ellipsoidal +elliptic +elliptical/Y +elm/SM +elocution/M +elocutionary +elocutionist/SM +elodea/SM +elongate/DSGNX +elongation/M +elope/DSGL +elopement/MS +eloquence/M +eloquent/Y +else +elsewhere +elucidate/DSGNX +elucidation/M +elude/DSG +elusive/YP +elusiveness/M +elver/SM +elves +elvish +em's +em/S +emaciate/GNDS +emaciation/M +email/SMDG +emanate/XDSGN +emanation/M +emancipate/DSGN +emancipation/M +emancipator/MS +emasculate/GNDS +emasculation/M +embalm/SZGDR +embalmer/M +embank/SLGD +embankment/SM +embargo/MDG +embargoes +embark/AEGDS +embarkation/EM +embarkations +embarrass/GLDS +embarrassed/U +embarrassing/Y +embarrassment/SM +embassy/SM +embattled +embed/S +embedded +embedding +embellish/LGDS +embellishment/SM +ember/SM +embezzle/ZGLDRS +embezzlement/M +embezzler/M +embitter/GLDS +embitterment/M +emblazon/GDLS +emblazonment/M +emblem/SM +emblematic +emblematically +embodiment/EM +embody/AEGSD +embolden/DGS +embolism/MS +embolization +emboss/DRSZG +embosser/M +embouchure/M +embower/SGD +embrace/DSMG +embraceable +embrasure/MS +embrocation/MS +embroider/SDRZG +embroiderer/M +embroidery/SM +embroil/DGLS +embroilment/M +embryo/SM +embryological +embryologist/MS +embryology/M +embryonic +emcee/DSM +emceeing +emend/SDG +emendation/MS +emerald/MS +emerge/ADSG +emergence/AM +emergency/SM +emergent +emerita +emeritus +emery/M +emetic/SM +emf/S +emigrant/SM +emigrate/DSXGN +emigration/M +emigre/SM +eminence/MS +eminent/Y +emir/MS +emirate/MS +emissary/SM +emission/SM +emit/S +emitted +emitter/MS +emitting +emo/SM +emoji/SM +emollient/MS +emolument/MS +emote/XDSGNV +emoticon/SM +emotion/M +emotional/UY +emotionalism/M +emotionalize/GDS +emotionless +emotive/Y +empanel/GDS +empathetic +empathize/DSG +empathy/M +emperor/MS +emphases +emphasis/M +emphasize/AGDS +emphatic/U +emphatically +emphysema/M +empire/SM +empiric +empirical/Y +empiricism/M +empiricist/SM +emplacement/SM +employ's +employ/ADGLS +employable/U +employee/SM +employer/SM +employment/UAM +employments +emporium/SM +empower/SDGL +empowerment/M +empress/MS +emptily +emptiness/M +empty/TGPDRSM +empyrean/M +emu/SM +emulate/DSGNVX +emulation/M +emulator/SM +emulsification/M +emulsifier/M +emulsify/NDRSZG +emulsion/MS +en/SM +enable/DRSZG +enabler/M +enact/ASLDG +enactment/ASM +enamel/JSZGMDR +enameler/M +enamelware/M +enamor/SGD +enc +encamp/LSGD +encampment/MS +encapsulate/XGNDS +encapsulation/M +encase/LDSG +encasement/M +encephalitic +encephalitis/M +enchain/DGS +enchant/ELDGS +enchanter/MS +enchanting/Y +enchantment/EM +enchantments +enchantress/MS +enchilada/SM +encipher/SGD +encircle/DSGL +encirclement/M +encl +enclave/MS +enclose/GDS +enclosed/U +enclosure/SM +encode/DRSZG +encoder/M +encomium/MS +encompass/GDS +encore/DSMG +encounter/GSMD +encourage/DSLG +encouragement/SM +encouraging/Y +encroach/GLDS +encroachment/SM +encrust/DGS +encrustation/SM +encrypt/DGS +encryption +encumber/EGSD +encumbered/U +encumbrance/MS +ency +encyclical/SM +encyclopedia/MS +encyclopedic +encyst/LSGD +encystment/M +end/GVSJMD +endanger/SGDL +endangerment/M +endear/SGLD +endearing/Y +endearment/SM +endeavor/GSMD +endemic/MS +endemically +endgame/S +ending/M +endive/SM +endless/PY +endlessness/M +endmost +endocarditis +endocrine/MS +endocrinologist/MS +endocrinology/M +endogenous/Y +endometrial +endometriosis +endometrium +endorphin/MS +endorse/LZGDRS +endorsement/MS +endorser/M +endoscope/MS +endoscopic +endoscopy/M +endothelial +endothermic +endow/SDLG +endowment/MS +endpoint/SM +endue/DSG +endurable/U +endurance/M +endure/DSBG +endways +enema/SM +enemy/SM +energetic +energetically +energize/ZGDRS +energizer/M +energy/SM +enervate/GNDS +enervation/M +enfeeble/GDSL +enfeeblement/M +enfilade/DSMG +enfold/SGD +enforce/LZGDRS +enforceable/U +enforced/U +enforcement/M +enforcer/M +enfranchise/EGDSL +enfranchisement/EM +engage/EADSG +engagement/EMS +engagingly +engender/SGD +engine/SM +engineer/MDGS +engineering/M +engorge/LGDS +engorgement/M +engram/SM +engrave/ZGJDRS +engraver/M +engraving/M +engross/GLDS +engrossment/M +engulf/SLGD +engulfment/M +enhance/LZGDRS +enhancement/SM +enigma/SM +enigmatic +enigmatically +enjambment/SM +enjoin/SGD +enjoy/GBLSD +enjoyably +enjoyment/SM +enlarge/LZGDRS +enlargeable +enlargement/MS +enlarger/M +enlighten/SGLD +enlightened/U +enlightenment/M +enlist/ADGSL +enlistee/SM +enlistment/AM +enlistments +enliven/SLDG +enlivenment/M +enmesh/DSGL +enmeshment/M +enmity/SM +ennoble/DSGL +ennoblement/M +ennui/M +enormity/SM +enormous/PY +enormousness/M +enough/M +enplane/DSG +enquirer/S +enquiringly +enrage/GDS +enrapture/DSG +enrich/DSLG +enrichment/M +enroll/DLSG +enrollment/MS +ensconce/DSG +ensemble/SM +enshrine/GLDS +enshrinement/M +enshroud/DGS +ensign/MS +ensilage/M +enslave/DSGL +enslavement/M +ensnare/DSLG +ensnarement/M +ensue/DSG +ensure/ZGDRS +ensurer/M +entail/DSGL +entailment/M +entangle/EDSLG +entanglement/EM +entanglements +entente/SM +enter/ASGD +enteric +enteritis/M +enterprise/MGS +enterprising/Y +entertain/ZGDRSL +entertainer/M +entertaining/MY +entertainment/MS +enthrall/GDSL +enthrallment/M +enthrone/GDSL +enthronement/SM +enthuse/DSG +enthusiasm/MS +enthusiast/MS +enthusiastic/U +enthusiastically +entice/GDSL +enticement/MS +enticing/Y +entire/Y +entirety/M +entitle/DSGL +entitlement/SM +entity/SM +entomb/DSGL +entombment/M +entomological +entomologist/MS +entomology/M +entourage/SM +entr'acte +entrails/M +entrance/LDSMG +entrancement/M +entrancing/Y +entrant/SM +entrap/LS +entrapment/M +entrapped +entrapping +entreat/GSD +entreating/Y +entreaty/SM +entree/MS +entrench/DSGL +entrenchment/MS +entrepreneur/SM +entrepreneurial +entrepreneurship +entropy/M +entrust/SGD +entry/ASM +entryphone/S +entryway/MS +entrée/MS +entwine/DSG +enumerable +enumerate/DSGNX +enumeration/M +enumerator/SM +enunciate/DSGN +enunciation/M +enure/DSG +enuresis/M +envelop/SLDRZG +envelope/SM +enveloper/M +envelopment/M +envenom/SDG +enviable/U +enviably +envious/PY +enviousness/M +environment/MS +environmental/Y +environmentalism/M +environmentalist/SM +environs/M +envisage/GDS +envision/DGS +envoy/SM +envy/DSMG +envying/Y +enzymatic +enzyme/SM +eolian +eon/SM +eosinophil/S +eosinophilic +epaulet/SM +epee/MS +ephedrine/M +ephemera/M +ephemeral/Y +epic/MS +epicenter/MS +epicure/SM +epicurean/MS +epidemic/SM +epidemically +epidemiological +epidemiologist/SM +epidemiology/M +epidermal +epidermic +epidermis/MS +epidural/S +epiglottis/MS +epigram/SM +epigrammatic +epigraph/M +epigraphs +epigraphy/M +epilepsy/M +epileptic/SM +epilogue/MS +epinephrine/M +epiphany/SM +episcopacy/M +episcopal +episcopate/M +episode/SM +episodic +episodically +epistemic +epistemological +epistemology +epistle/SM +epistolary +epitaph/M +epitaphs +epithelial +epithelium/M +epithet/SM +epitome/SM +epitomize/GDS +epoch/M +epochal +epochs +eponymous +epoxy/DSMG +epsilon/SM +equability/M +equable +equably +equal/SMDYG +equality/IM +equalization/M +equalize/ZGDRS +equalizer/M +equanimity/M +equate/DSGNBX +equation/M +equator/SM +equatorial +equerry/SM +equestrian/SM +equestrianism/M +equestrienne/SM +equidistant/Y +equilateral/SM +equilibrium/EM +equine/SM +equinoctial +equinox/MS +equip/AS +equipage/MS +equipment/M +equipoise/M +equipped/UA +equipping/A +equitable/I +equitably/I +equitation/M +equity/ISM +equiv +equivalence/MS +equivalency/SM +equivalent/MYS +equivocal/UY +equivocalness/M +equivocate/GNXDS +equivocation/M +equivocator/SM +er/C +era/SM +eradicable/I +eradicate/DSGN +eradication/M +eradicator/MS +erase/DRSBZG +eraser/M +erasure/SM +erbium/M +ere +erect/PSGDY +erectile +erection/SM +erectness/M +erector/MS +erelong +eremite/MS +erg/SM +ergo +ergonomic/S +ergonomically +ergonomics/M +ergosterol/M +ergot/M +ermine/SM +erode/DSG +erodible +erogenous +erosion/M +erosive +erotic/S +erotica/M +erotically +eroticism/M +err/GSD +errand/SM +errant/I +errata/SM +erratic +erratically +erratum/M +erroneous/Y +error/SM +ersatz/MS +erst +erstwhile +eruct/SDG +eructation/SM +erudite/YN +erudition/M +erupt/SDGV +eruption/MS +erysipelas/M +erythrocyte/SM +erythromycin +escalate/CDSGN +escalation/CM +escalations +escalator/MS +escallop/SGMD +escalope/S +escapade/MS +escape/LMGDS +escapee/MS +escapement/SM +escapism/M +escapist/MS +escapologist/S +escapology +escargot/MS +escarole/MS +escarpment/MS +eschatological +eschatology +eschew/SDG +escort/SMDG +escritoire/MS +escrow/SM +escudo/SM +escutcheon/SM +esophageal +esophagi +esophagus/MS +esoteric +esoterically +esp +espadrille/MS +espalier/MDSG +especial/Y +espionage/M +esplanade/MS +espousal/M +espouse/GDS +espresso/MS +esprit/M +espy/DSG +esquire/SM +essay/SMDRZG +essayer/M +essayist/SM +essence/SM +essential/IMS +essentially +establish/AESDGL +establishment/AEM +establishments +estate/SM +esteem/ESMDG +ester/SM +esthetic/S +estimable/I +estimate/MGNDSX +estimation/M +estimator/SM +estoppel +estrange/LDSG +estrangement/MS +estrogen/M +estrous +estrus/MS +estuary/SM +eta/SM +etc +etch/DRSZGJ +etcher/M +etching/M +eternal/YP +eternalness/M +eternity/SM +ethane/M +ethanol/M +ether/M +ethereal/Y +ethic/SM +ethical/UY +ethics/M +ethnic/SM +ethnically +ethnicity/M +ethnocentric +ethnocentrism/M +ethnographer/S +ethnographic +ethnographically +ethnography +ethnological/Y +ethnologist/SM +ethnology/M +ethological +ethologist/MS +ethology/M +ethos/M +ethyl/M +ethylene/M +etiolated +etiologic +etiological +etiology/SM +etiquette/M +etude/SM +etymological/Y +etymologist/SM +etymology/SM +eucalypti +eucalyptus/MS +euchre/DSMG +euclidean +eugenic/S +eugenically +eugenicist/MS +eugenics/M +eulogist/MS +eulogistic +eulogize/ZGDRS +eulogizer/M +eulogy/SM +eunuch/M +eunuchs +euphemism/SM +euphemistic +euphemistically +euphonious/Y +euphony/M +euphoria/M +euphoric +euphorically +eureka +euro/MS +europium/M +eutectic +euthanasia/M +euthanize/DSG +euthenics/M +evacuate/XDSGN +evacuation/M +evacuee/MS +evade/DRSZG +evader/M +evaluate/AGNVDSX +evaluation/AM +evanescence/M +evanescent +evangelic +evangelical/SMY +evangelicalism/M +evangelism/M +evangelist/MS +evangelistic +evangelize/GDS +evaporate/GNDS +evaporation/M +evaporator/SM +evasion/SM +evasive/YP +evasiveness/M +eve/ASM +even/MDRYTGSJP +evenhanded/Y +evening/M +evenness/UM +evensong/M +event/SM +eventful/UY +eventfulness/M +eventide/M +eventual/Y +eventuality/SM +eventuate/GDS +ever +everglade/SM +evergreen/SM +everlasting/MYS +evermore +every +everybody/M +everyday +everyone/M +everyplace +everything/M +everywhere +evict/SDG +eviction/MS +evidence/MGDS +evident/Y +evil/MRYTSP +evildoer/SM +evildoing/M +eviller +evillest +evilness/M +evince/DSG +eviscerate/DSGN +evisceration/M +evocation/MS +evocative/Y +evoke/DSG +evolution/M +evolutionary +evolutionist/SM +evolve/DSG +ewe/RSMZ +ewer/M +ex/MS +exabyte/MS +exacerbate/GNDS +exacerbation/M +exact/SPDRYTG +exacting/Y +exaction/M +exactitude/M +exactness/IM +exaggerate/XDSGN +exaggerated/Y +exaggeration/M +exaggerator/MS +exalt/SDG +exaltation/M +exam/MS +examination/AMS +examine/AGDS +examiner/MS +example/MGDS +exampled/U +exasperate/DSGN +exasperated/Y +exasperating/Y +exasperation/M +excavate/GNDSX +excavation/M +excavator/SM +exceed/GSD +exceeding/Y +excel/S +excelled +excellence/M +excellency/SM +excellent/Y +excelling +excelsior/M +except/GSD +exception/BSM +exceptionable/U +exceptional/UY +exceptionalism +excerpt/MDGS +excess/VMS +excessive/Y +exchange/DSMG +exchangeable +exchequer/SM +excise/XDSMGN +excision/M +excitability/M +excitably +excitation/M +excite/BDRSLZG +excited/Y +excitement/SM +exciter/M +exciting/Y +excl +exclaim/DGS +exclamation/SM +exclamatory +exclude/GDS +exclusion/MS +exclusionary +exclusive/PMYS +exclusiveness/M +exclusivity/M +excommunicate/GNDSX +excommunication/M +excoriate/DSGNX +excoriation/M +excrement/M +excremental +excrescence/MS +excrescent +excreta/M +excrete/XGNDS +excretion/M +excretory +excruciating/Y +exculpate/DSGN +exculpation/M +exculpatory +excursion/MS +excursionist/MS +excursive/YP +excursiveness/M +excusable/I +excusably/I +excuse/DSBMG +excused/U +exec/MS +execrable +execrably +execrate/DSGN +execration/M +execute/BXGNVDS +execution/ZMR +executioner/M +executive/SM +executor/MS +executrices +executrix/M +exegeses +exegesis/M +exegetic +exegetical +exemplar/SM +exemplary +exemplification/M +exemplify/GDSXN +exempt/SGD +exemption/SM +exercise/DRSMZG +exerciser/M +exert/SDG +exertion/MS +exeunt +exfoliate/GNDS +exhalation/MS +exhale/DSG +exhaust/GVMDS +exhaustible/I +exhaustion/M +exhaustive/YP +exhaustiveness/M +exhibit/GMDS +exhibition/MS +exhibitionism/M +exhibitionist/MS +exhibitor/SM +exhilarate/DSGN +exhilaration/M +exhort/SDG +exhortation/MS +exhumation/MS +exhume/DSG +exigence/MS +exigency/SM +exigent +exiguity/M +exiguous +exile/DSMG +exist/SDG +existence/MS +existent +existential/Y +existentialism/M +existentialist/MS +exit/MDGS +exobiology/M +exodus/MS +exogenous +exon/MS +exonerate/GNDS +exoneration/M +exoplanet/MS +exorbitance/M +exorbitant/Y +exorcise/DSG +exorcism/SM +exorcist/SM +exoskeleton/SM +exosphere/SM +exothermic +exotic/SM +exotica +exotically +exoticism/M +exp +expand/BGSD +expanse/XMNVS +expansible +expansion/M +expansionary +expansionism/M +expansionist/MS +expansive/YP +expansiveness/M +expat/S +expatiate/GNDS +expatiation/M +expatriate/DSMGN +expatriation/M +expect/GSD +expectancy/M +expectant/Y +expectation/SM +expectorant/SM +expectorate/DSGN +expectoration/M +expedience/IM +expediences +expediencies +expediency/IM +expedient/SMY +expedite/DRSZGNX +expediter/M +expedition/M +expeditionary +expeditious/PY +expeditiousness/M +expel/S +expelled +expelling +expend/GSBD +expendable/SM +expenditure/SM +expense/MS +expensive/IYP +expensiveness/IM +experience/IMD +experiences +experiencing +experiential +experiment/MDRSZG +experimental/Y +experimentation/M +experimenter/M +expert/SPMY +expertise/M +expertness/M +expiate/GNDS +expiation/M +expiatory +expiration/M +expire/DSG +expired/U +expiry/M +explain/ADGS +explainable +explained/U +explanation/MS +explanatory +expletive/MS +explicable/I +explicate/XGNDS +explication/M +explicit/PY +explicitness/M +explode/GDS +exploit/ZGBMDRS +exploitation/M +exploitative +exploited/U +exploiter/M +exploration/MS +exploratory +explore/ZGDRS +explored/U +explorer/M +explosion/SM +explosive/SPMY +explosiveness/M +expo/MS +exponent/MS +exponential/Y +exponentiation +export/BSZGMDR +exportation/M +exporter/M +expose/DSMG +exposed/U +exposition/SM +expositor/SM +expository +expostulate/GNXDS +expostulation/M +exposure/MS +expound/ZGDRS +expounder/M +express/GVMDSY +expressed/U +expressible/I +expression/SM +expressionism/M +expressionist/SM +expressionistic +expressionless/Y +expressive/PY +expressiveness/M +expressway/SM +expropriate/GNXDS +expropriation/M +expropriator/SM +expulsion/MS +expunge/GDS +expurgate/DSGNX +expurgated/U +expurgation/M +exquisite/YP +exquisiteness/M +ext +extant +extemporaneous/PY +extemporaneousness/M +extempore +extemporization/M +extemporize/GDS +extend/SZGDRB +extender/M +extendible +extensible +extension/SM +extensional +extensive/YP +extensiveness/M +extent/SM +extenuate/DSGN +extenuation/M +exterior/MS +exterminate/DSXGN +extermination/M +exterminator/MS +external/MYS +externalization/SM +externalize/DSG +extinct/GDS +extinction/MS +extinguish/ZGBDRS +extinguishable/I +extinguisher/M +extirpate/GNDS +extirpation/M +extol/S +extolled +extolling +extort/SGD +extortion/MRZ +extortionate/Y +extortioner/M +extortionist/MS +extra/SM +extracellular +extract/MDGS +extraction/SM +extractor/MS +extracurricular +extradite/GNBXDS +extradition/M +extrajudicial +extralegal +extramarital +extramural +extraneous/Y +extraordinaire +extraordinarily +extraordinary +extrapolate/XGNDS +extrapolation/M +extrasensory +extraterrestrial/MS +extraterritorial +extraterritoriality/M +extravagance/MS +extravagant/Y +extravaganza/MS +extravehicular +extreme/PMYTRS +extremeness/M +extremism/M +extremist/MS +extremity/SM +extricable/I +extricate/GNDS +extrication/M +extrinsic +extrinsically +extroversion/M +extrovert/SMD +extrude/GDS +extrusion/SM +extrusive +exuberance/M +exuberant/Y +exudation/M +exude/DSG +exult/SDG +exultant/Y +exultation/M +exurb/SM +exurban +exurbanite/SM +exurbia/M +eye/DSMG +eyeball/GMDS +eyebrow/SM +eyedropper/SM +eyeful/SM +eyeglass/MS +eyeing +eyelash/MS +eyeless +eyelet/SM +eyelid/SM +eyeliner/MS +eyeopener/MS +eyeopening +eyepiece/MS +eyesight/M +eyesore/MS +eyestrain/M +eyeteeth +eyetooth/M +eyewash/M +eyewitness/MS +f/CIAVTR +fa/M +fab +fable/DSM +fabric/SM +fabricate/DSGNX +fabrication/M +fabricator/SM +fabulous/Y +facade/SM +face's +face/ACSDG +facecloth/M +facecloths +faceless +facelift/SM +facet/SMDG +facetious/YP +facetiousness/M +facial/SMY +facile/Y +facilitate/GNDS +facilitation/M +facilitator/MS +facility/SM +facing/SM +facsimile/DSM +facsimileing +fact/MS +faction/SM +factional +factionalism/M +factious +factitious +factoid/SM +factor's +factor/ASDG +factorial/MS +factorization +factorize/GDS +factory/SM +factotum/SM +factual/Y +faculty/SM +fad/GSMD +faddish/P +faddist/MS +faddy/P +fade/MS +fading/U +faerie/SM +faff/DGS +fag/SM +fagged +fagging +faggot/SMG +fagot/SMG +faience/M +fail/MDGJS +failing/M +faille/M +failure/SM +fain/RT +faint/SMDRYTGP +fainthearted +faintness/M +fair/MRYTGJPS +fairground/MS +fairing/M +fairness/UM +fairway/SM +fairy/SM +fairyland/SM +faith/M +faithful's +faithful/UPY +faithfulness/UM +faithfuls +faithless/PY +faithlessness/M +faiths +fajita/SM +fajitas/M +fake/MZGDRS +faker/M +fakir/SM +falcon/SMRZ +falconer/M +falconry/M +fall/MNGS +fallacious/Y +fallacy/SM +fallback +fallibility/IM +fallible/P +fallibleness/M +fallibly/I +falloff/SM +fallout/M +fallow/SMDG +false/PRYT +falsehood/SM +falseness/M +falsetto/SM +falsie/SM +falsifiable +falsification/M +falsifier/M +falsify/DRSZGNX +falsity/SM +falter/GSJMD +faltering/Y +fame's +fame/D +familial +familiar/MYS +familiarity/UM +familiarization/M +familiarize/GDS +family/SM +famine/SM +famish/DSG +famous/IY +fan/SM +fanatic/SM +fanatical/Y +fanaticism/M +fanboy/SM +fanciable +fancier/M +fanciful/YP +fancifulness/M +fancily +fanciness/M +fancy/DRSMZTGP +fancywork/M +fandango/MS +fandom +fanfare/SM +fang/MDS +fanlight/SM +fanned +fanning +fanny/SM +fantail/MS +fantasia/SM +fantasist/S +fantasize/GDS +fantastic +fantastical/Y +fantasy/DSMG +fanzine/MS +far +farad/SM +faradize/DG +faraway +farce/SM +farcical/Y +fare/MGDS +farewell/SM +farfetched +farina/M +farinaceous +farm/MDRZGSJ +farmer/M +farmhand/SM +farmhouse/SM +farming/M +farmland/MS +farmstead/MS +farmyard/MS +faro/M +farrago/M +farragoes +farrier/MS +farrow/SMDG +farseeing +farsighted/P +farsightedness/M +fart/MDGS +farther +farthermost +farthest +farthing/SM +fascia/SM +fascicle/SM +fascinate/GNDSX +fascinating/Y +fascination/M +fascism/M +fascist/MS +fascistic +fashion/ZGBMDRS +fashionable/U +fashionably/U +fashioner/M +fashionista/MS +fast/MDRTGSP +fastback/SM +fastball/SM +fasten/UAGDS +fastener/SM +fastening/MS +fastidious/PY +fastidiousness/M +fastness/MS +fat/GSPMD +fatal/Y +fatalism/M +fatalist/SM +fatalistic +fatalistically +fatality/SM +fatback/M +fate/MS +fateful/YP +fatefulness/M +fathead/MDS +father/SGMDY +fatherhood/M +fatherland/MS +fatherless +fathom/SMDGB +fathomable/U +fathomless +fatigue/MDSG +fatigues/M +fatness/M +fatso/S +fatten/SDG +fatter +fattest +fattiness/M +fatty/RSMTP +fatuity/M +fatuous/YP +fatuousness/M +fatwa/SM +faucet/SM +fault/CSMDG +faultfinder/SM +faultfinding/M +faultily +faultiness/M +faultless/PY +faultlessness/M +faulty/PRT +faun/MS +fauna/SM +fauvism/M +fauvist/SM +faux +fave/S +favor/ESMDG +favorable/U +favorably/U +favorite/SM +favoritism/M +fawn/MDRZGS +fawner/M +fax/GMDS +fay/TSMR +faze/GDS +fazed/U +faïence/M +fealty/M +fear/MDGS +fearful/YP +fearfulness/M +fearless/PY +fearlessness/M +fearsome +feasibility/M +feasible/IU +feasibly +feast/SMDRZG +feaster/M +feat/MS +feather/SGMD +featherbedding/M +featherbrained +featherless +featherweight/MS +feathery/TR +feature/DSMG +featureless +febrile +fecal +feces/M +feckless/PY +fecund +fecundate/GNDS +fecundation/M +fecundity/M +fed/SM +federal/SMY +federalism/M +federalist/MS +federalization/M +federalize/GDS +federate/FXDSGN +federation/FM +fedora/SM +fee/SM +feeble/RTP +feebleness/M +feebly +feed/MRZGSJ +feedback/M +feedbag/SM +feeder/M +feeding/M +feedlot/SM +feel/MRZGSJ +feeler/M +feelgood +feeling/MY +feet +feign/SDG +feigned/U +feint/SMDG +feisty/TR +feldspar/M +felicitate/GNXDS +felicitation/M +felicitous/Y +felicity/ISM +feline/SM +fell/MDRZTGS +fella/S +fellatio/M +fellow/SM +fellowman/M +fellowmen +fellowship/MS +felon/SM +felonious +felony/SM +felt/MDGS +fem +female/PSM +femaleness/M +feminine/SMY +femininity/M +feminism/M +feminist/SM +feminize/DSG +femoral +femur/SM +fen/SM +fence/DRSMZG +fencer/M +fencing/M +fend/CDRZGS +fender/CM +fenestration/M +fennel/M +feral +ferment/FCMS +fermentation/M +fermented +fermenting +fermium/M +fern/MS +ferny/RT +ferocious/PY +ferociousness/M +ferocity/M +ferret/GSMD +ferric +ferromagnetic +ferrous +ferrule/MS +ferry/DSMG +ferryboat/SM +ferryman/M +ferrymen +fertile/I +fertility/IM +fertilization/M +fertilize/DRSZG +fertilized/U +fertilizer/M +ferule/SM +fervency/M +fervent/Y +fervid/Y +fervor/M +fess/FKGSD +fest/MRZVS +festal +fester/GMD +festival/SM +festive/YP +festiveness/M +festivity/SM +festoon/GMDS +feta/M +fetal +fetch/DRSZG +fetcher/M +fetching/Y +fete/MGDS +fetid/P +fetidness/M +fetish/MS +fetishism/M +fetishist/SM +fetishistic +fetlock/MS +fetter's +fetter/USGD +fettle/M +fettuccine/M +fetus/MS +feud/MDGS +feudal +feudalism/M +feudalistic +fever/SMD +feverish/YP +feverishness/M +few/TPMR +fewness/M +fey +fez/M +fezzes +ff +fiance/CM +fiancee/MS +fiances +fiancé/SM +fiancée/MS +fiasco/SM +fiascoes +fiat/MS +fib/ZSMR +fibbed +fibber/SM +fibbing +fiber/M +fiberboard/M +fiberfill/M +fiberglass/M +fibril/SM +fibrillate/GNDS +fibrillation/M +fibrin/M +fibroid +fibrosis/M +fibrous +fibula/M +fibulae +fibular +fiche/SM +fichu/SM +fickle/RPT +fickleness/M +fiction/MS +fictional/Y +fictionalization/SM +fictionalize/DSG +fictitious/Y +fictive +ficus/M +fiddle/DRSMZG +fiddler/M +fiddlesticks +fiddly/TR +fidelity/IM +fidget/SGMD +fidgety +fiduciary/SM +fie +fief/MS +fiefdom/MS +field/ISMRZ +fielded +fielder/IM +fielding +fieldsman +fieldsmen +fieldwork/MRZ +fieldworker/M +fiend/SM +fiendish/Y +fierce/PRYT +fierceness/M +fieriness/M +fiery/RPT +fiesta/SM +fife/MZRS +fifer/M +fifteen/MHS +fifteenth/M +fifteenths +fifth/MY +fifths +fiftieth/M +fiftieths +fifty/SMH +fig/SLM +fight/SMRZG +fightback +fighter/IMS +fighting/IM +figment/MS +figuration/FM +figurative/Y +figure's +figure/FEGSD +figurehead/SM +figurine/MS +filament/MS +filamentous +filbert/MS +filch/DSG +file's/KC +file/CAKGDS +filename/S +filer/CSM +filet +filial +filibuster/MDRSZG +filibusterer/M +filigree/DSM +filigreeing +filing's +filings +fill's +fill/AIDGS +filled/U +filler/MS +fillet/MDGS +filling/SM +fillip/MDGS +filly/SM +film/MDGS +filminess/M +filmmaker/SM +filmstrip/MS +filmy/TPR +filo +filter/MDRBSZG +filtered/U +filterer/M +filth/M +filthily +filthiness/M +filthy/RPT +filtrate's +filtrate/IGNDS +filtration/IM +fin/SMR +finagle/DRSZG +finagler/M +final/SMY +finale/MS +finalist/SM +finality/M +finalization/M +finalize/DSG +finance's +finance/ADSG +financial/Y +financier/MS +financing/M +finch/MS +find/JMRZGS +finder/M +finding/M +findings/M +fine's/F +fine/CAFTGDS +finely +fineness/M +finery/AM +finespun +finesse/DSMG +finger/MDGSJ +fingerboard/SM +fingering/M +fingerling/SM +fingermark/S +fingernail/SM +fingerprint/SGMD +fingertip/MS +finial/MS +finical +finickiness/M +finicky/RPT +finis/MS +finish's +finish/ADSG +finished/U +finisher/MS +finite/IY +fink/MDGS +finned +finny +fir/ZGSJMDRH +fire/MS +firearm/SM +fireball/MS +firebomb/MDSJG +firebox/MS +firebrand/SM +firebreak/SM +firebrick/SM +firebug/SM +firecracker/SM +firedamp/M +firefight/MRSZG +firefighter/M +firefighting/M +firefly/SM +fireguard/S +firehouse/SM +firelight/ZMR +fireman/M +firemen +fireplace/SM +fireplug/MS +firepower/M +fireproof/DSG +firer/M +firescreen/S +fireside/MS +firestorm/MS +firetrap/MS +firetruck/MS +firewall/MS +firewater/M +firewood/M +firework/SM +firm/MDRYPTGS +firmament/SM +firmness/M +firmware/M +first/SMY +firstborn/SM +firsthand +firth/M +firths +fiscal/MYS +fish/MDRSZG +fishbowl/SM +fishcake/SM +fisher/M +fisherman/M +fishermen +fishery/SM +fishhook/SM +fishily +fishiness/M +fishing/M +fishmonger/MS +fishnet/SM +fishpond/MS +fishtail/DGS +fishwife/M +fishwives +fishy/TRP +fissile +fission/BM +fissure/SM +fist/MS +fistfight/MS +fistful/SM +fisticuffs/M +fistula/SM +fistulous/M +fit/KAMS +fitful/YP +fitfulness/M +fitly +fitment/S +fitness/UM +fitted/UA +fitter/MS +fittest +fitting/SMY +five/MZRS +fix/ZGBJMDRS +fixate/GNVDSX +fixation/M +fixative/MS +fixed/Y +fixer/M +fixings/M +fixity/M +fixture/MS +fizz/MDSG +fizzle/DSMG +fizzy/RT +fjord/SM +fl/JDG +flab/M +flabbergast/SGD +flabbily +flabbiness/M +flabby/RPT +flaccid/Y +flaccidity/M +flack/SM +flag/MS +flagella +flagellant/S +flagellate/GNDS +flagellation/M +flagellum/M +flagged +flagging/U +flagman/M +flagmen +flagon/MS +flagpole/SM +flagrance/M +flagrancy/M +flagrant/Y +flagship/SM +flagstaff/MS +flagstone/MS +flail/SGMD +flair/SM +flak/M +flake/DSMG +flakiness/M +flaky/TRP +flamage +flambe/MS +flambeed +flambeing +flamboyance/M +flamboyancy/M +flamboyant/Y +flambé/MD +flame/DRSJMZG +flamenco/MS +flameproof/DGS +flamethrower/SM +flamingo/MS +flammability/IM +flammable/SM +flan/MS +flange/MS +flank/SZGMDR +flanker/M +flannel/SGMD +flannelette/M +flap/MS +flapjack/MS +flapped +flapper/SM +flapping +flare/DSMG +flareup/SM +flash/ZTGMDRS +flashback/SM +flashbulb/SM +flashcard/SM +flashcube/SM +flasher/M +flashgun/SM +flashily +flashiness/M +flashing/M +flashlight/MS +flashpoint/SM +flashy/RTP +flask/SM +flat/MYPS +flatbed/SM +flatboat/SM +flatbread +flatcar/SM +flatfeet +flatfish/MS +flatfoot/SMD +flatiron/SM +flatland/M +flatlet/S +flatmate/S +flatness/M +flatted +flatten/SDG +flatter/SDRZG +flatterer/M +flattering/Y +flattery/M +flattest +flatting +flattish +flattop/SM +flatulence/M +flatulent +flatus/M +flatware/M +flatworm/SM +flaunt/MDSG +flaunting/Y +flavor/MDSGJ +flavored/U +flavorful +flavoring/M +flavorless +flavorsome +flaw/MDGS +flawless/PY +flawlessness/M +flax/MN +flay/DGS +flea/MS +fleabag/SM +fleabite/S +fleapit/S +fleck/SGMD +fledged/U +fledgling/MS +flee/S +fleece/MZGDRS +fleecer/M +fleeciness/M +fleecy/RTP +fleeing +fleet/STGMDRYP +fleetingly/M +fleetingness/M +fleetness/M +flesh/GMDSY +fleshly/TR +fleshpot/MS +fleshy/RT +flew +flex/AMS +flexed +flexibility/IM +flexible/I +flexibly/I +flexing +flexion +flextime/M +flibbertigibbet/SM +flick/SZGMDR +flicker/GMD +flier/M +flight/MS +flightiness/M +flightless +flighty/PTR +flimflam/SM +flimflammed +flimflamming +flimsily +flimsiness/M +flimsy/TRP +flinch/GMDS +fling/GM +flint/SM +flintlock/SM +flinty/TR +flip/MS +flippancy/M +flippant/Y +flipped +flipper/MS +flippest +flipping +flippy/S +flirt/SGMD +flirtation/MS +flirtatious/YP +flirtatiousness/M +flirty +flit/MS +flitted +flitting +float/SMDRZG +floater/M +flock/SMDG +flocking/M +floe/MS +flog/S +flogged +flogger/SM +flogging/MS +flood/SMDRG +floodgate/MS +floodlight/MDSG +floodlit +floodplain/MS +floodwater/MS +floor/SMDG +floorboard/MS +flooring/M +floorwalker/SM +floozie/M +floozy/SM +flop/MS +flophouse/MS +flopped +floppily +floppiness/M +flopping +floppy/PRSMT +flora/SM +floral +florescence/IM +florescent/I +floret/SM +florid/PY +floridness/M +florin/SM +florist/SM +floss/MDSG +flossy/RT +flotation/SM +flotilla/MS +flotsam/M +flounce/DSMG +flouncy +flounder/MDSG +flour/SMDG +flourish/GMDS +floury +flout/SMDRZG +flouter/M +flow/MDGS +flowchart/SM +flower's +flower/CSDG +flowerbed/MS +floweriness/M +flowering/S +flowerless +flowerpot/MS +flowery/PTR +flown +flt +flu/M +flub/MS +flubbed +flubbing +fluctuate/GNDSX +fluctuation/M +flue/MS +fluency/M +fluent/Y +fluff/SMDG +fluffiness/M +fluffy/RPT +fluid/SMY +fluidity/M +fluke/SM +fluky/RT +flume/SM +flummox/DSG +flung +flunk/SMDG +flunky/SM +fluoresce/DSG +fluorescence/M +fluorescent +fluoridate/GNDS +fluoridation/M +fluoride/SM +fluorine/M +fluorite/M +fluorocarbon/MS +fluoroscope/SM +fluoroscopic +flurry/GDSM +flush/MDRSTG +fluster/MDSG +flute/DSMG +fluting/M +flutist/MS +flutter/MDSG +fluttery +fluvial +flux/IMS +fluxed +fluxing +fly/ZTGBDRSM +flyaway +flyblown +flyby/M +flybys +flycatcher/MS +flying/M +flyleaf/M +flyleaves +flyover/MS +flypaper/SM +flypast/S +flysheet/S +flyspeck/GMDS +flyswatter/MS +flytrap/S +flyway/SM +flyweight/SM +flywheel/MS +fo'c'sle/MS +foal/MDGS +foam/MDGS +foaminess/M +foamy/RTP +fob/SM +fobbed +fobbing +focal/Y +focus's +focus/ADSG +focused/U +fodder/SM +foe/SM +fog's +fog/CS +fogbound +fogged/C +foggily +fogginess/M +fogging/C +foggy/RTP +foghorn/MS +fogy/SM +fogyish +foible/SM +foil/MDGS +foist/SDG +fol +fold's +fold/AUSGD +foldaway +folder/SM +foldout/MS +foliage/M +folic +folio/SM +folk/MS +folklore/M +folkloric +folklorist/MS +folksiness/M +folksinger/SM +folksinging/M +folksy/PTR +folktale/MS +folkway/MS +foll +follicle/MS +follow/SDRZGJ +follower/M +following/M +followup/S +folly/SM +foment/SGD +fomentation/M +fond/RYTP +fondant/MS +fondle/DSG +fondness/M +fondue/SM +font/MS +fontanel/MS +fontanelle/MS +foo +foobar +food/MS +foodie/SM +foodstuff/SM +fool/MDGS +foolery/SM +foolhardily +foolhardiness/M +foolhardy/TPR +foolish/YP +foolishness/M +foolproof +foolscap/M +foot/MDRZGSJ +footage/M +football/MRZGS +footballer/M +footbridge/SM +footfall/MS +foothill/MS +foothold/MS +footie +footing/M +footless +footlights/M +footling/MS +footlocker/SM +footloose +footman/M +footmen +footnote/MGDS +footpath/M +footpaths +footplate/S +footprint/SM +footrace/MS +footrest/MS +footsie/SM +footslogging +footsore +footstep/MS +footstool/SM +footwear/M +footwork/M +footy +fop/SM +foppery/M +foppish/P +foppishness/M +for/H +fora +forage/DRSMZG +forager/M +foray/SMDG +forbade +forbear/SMG +forbearance/M +forbid/S +forbidden +forbidding/YS +forbore +forborne +force/DSMG +forced/U +forceful/PY +forcefulness/M +forceps/M +forcible +forcibly +ford/MDGSB +fore/MS +forearm/GSMD +forebear/MS +forebode/GJDS +foreboding/M +forecast/MRZGS +forecaster/M +forecastle/MS +foreclose/DSG +foreclosure/MS +forecourt/SM +foredoom/DGS +forefather/MS +forefeet +forefinger/SM +forefoot/M +forefront/SM +foregather/GDS +forego/G +foregoes +foregone +foreground/GMDS +forehand/MS +forehead/MS +foreign/ZRP +foreigner/M +foreignness/M +foreknew +foreknow/GS +foreknowledge/M +foreknown +foreleg/SM +forelimb/MS +forelock/MS +foreman/M +foremast/MS +foremen +foremost +forename/MDS +forenoon/MS +forensic/MS +forensically +forensics/M +foreordain/GSD +forepart/MS +foreperson/SM +foreplay/M +forequarter/MS +forerunner/MS +foresail/MS +foresaw +foresee/RSBZ +foreseeable/U +foreseeing +foreseen/U +foreseer/M +foreshadow/GDS +foreshore/S +foreshorten/DSG +foresight/MD +foresightedness/M +foreskin/MS +forest's +forest/ACGDS +forestall/SGD +forestation/ACM +forester/MS +forestland/M +forestry/M +foretaste/DSMG +foretell/GS +forethought/M +foretold +forever/M +forevermore +forewarn/DSG +forewent +forewoman/M +forewomen +foreword/MS +forfeit/GSMD +forfeiture/SM +forgather/SDG +forgave +forge/DRSMZGVJ +forger/M +forgery/SM +forget/S +forgetful/YP +forgetfulness/M +forgettable/U +forgetting +forging/M +forgivable/U +forgive/BRSZGP +forgiven +forgiveness/M +forgiver/M +forgiving/U +forgo/RZG +forgoer/M +forgoes +forgone +forgot +forgotten/U +fork/MDGS +forkful/SM +forklift/MS +forlorn/Y +form's +form/CAIFDGS +formal/SMY +formaldehyde/M +formalin +formalism/M +formalist/MS +formalities +formality/IM +formalization/M +formalize/GDS +format/SMV +formation/CFASM +formatted/A +formatting/M +formed/U +former/FIAM +formerly +formfitting +formic +formidable +formidably +formless/PY +formlessness/M +formula/MS +formulae +formulaic +formulate/ADSGNX +formulated/U +formulation/AM +formulator/SM +fornicate/GNDS +fornication/M +fornicator/MS +forsake/GS +forsaken +forsook +forsooth +forswear/SG +forswore +forsworn +forsythia/SM +fort/MS +forte/SM +forthcoming/M +forthright/YP +forthrightness/M +forthwith +fortieth/M +fortieths +fortification/M +fortified/U +fortifier/M +fortify/DRSNZGX +fortissimo +fortitude/M +fortnight/MYS +fortress/MS +fortuitous/YP +fortuitousness/M +fortuity/M +fortunate/UY +fortune/MS +fortuneteller/SM +fortunetelling/M +forty/SMH +forum/SM +forward/MDRYZTGSP +forwarder/M +forwardness/M +forwent +fossa +fossil/SM +fossilization/M +fossilize/GDS +foster/GSD +fought +foul/MDRYTGSP +foulard/M +foulmouthed +foulness/M +found/FSDG +foundation/SM +founded/U +founder/GMDS +foundling/SM +foundry/SM +fount/SM +fountain/SM +fountainhead/MS +four/MHS +fourfold +fourposter/SM +fourscore/M +foursome/SM +foursquare +fourteen/SMH +fourteenth/M +fourteenths +fourth/MY +fourths +fowl/MDGS +fox/GMDS +foxfire/M +foxglove/SM +foxhole/MS +foxhound/SM +foxhunt/GS +foxily +foxiness/M +foxtrot/MS +foxtrotted +foxtrotting +foxy/RTP +foyer/SM +fps +fr +fracas/MS +frack/SDG +fractal/SM +fraction/ISM +fractional/Y +fractious/YP +fractiousness/M +fracture/MGDS +frag/S +fragile/RT +fragility/M +fragment/GMDS +fragmentary/M +fragmentation/M +fragrance/MS +fragrant/Y +frail/RYTP +frailness/M +frailty/SM +frame/DRSMZG +framed/U +framer/M +framework/SM +franc/SM +franchise's +franchise/EDSG +franchisee/SM +franchiser/SM +franchisor/SM +francium/M +francophone +frangibility/M +frangible +frank/SMDRYTGP +frankfurter/MS +frankincense/M +frankness/M +frantic +frantically +frappe/SM +frappé/M +frat/MS +fraternal/Y +fraternity/FSM +fraternization/M +fraternize/ZGDRS +fraternizer/M +fratricidal +fratricide/MS +fraud's +fraud/S +fraudster/S +fraudulence/M +fraudulent/Y +fraught +fray's +fray/CDGS +frazzle/MGDS +freak/SMDG +freakish/YP +freakishness/M +freakout/MS +freaky/RT +freckle/DSMG +freckly +free/YTDRS +freebase/MGDS +freebee/SM +freebie/SM +freebooter/SM +freeborn +freedman/M +freedmen +freedom/SM +freehand +freehold/ZMRS +freeholder/M +freeing +freelance/DRSMZG +freelancer/M +freeload/SDRZG +freeloader/M +freeman/M +freemasonry +freemen +freephone +freesia/S +freestanding +freestone/SM +freestyle/SM +freethinker/SM +freethinking/M +freeware/M +freeway/MS +freewheel/DGS +freewill +freezable +freeze's +freeze/UAGS +freezer/MS +freezing's +freight/MDRZGS +freighter/M +french +frenetic +frenetically +frenzied/Y +frenzy/DSM +freq +frequencies +frequency/IM +frequent/DRYSZTG +frequented/U +frequenter/M +fresco/M +frescoes +fresh/PNRYXZT +freshen/ZGDR +freshener/M +freshet/MS +freshman/M +freshmen +freshness/M +freshwater/M +fret/MS +fretful/YP +fretfulness/M +fretsaw/MS +fretted +fretting +fretwork/M +friable +friar/SM +friary/SM +fricassee/DSM +fricasseeing +fricative/SM +friction/SM +frictional +fridge/SM +friedcake/MS +friend's +friend/UGSDY +friendless +friendlies +friendliness/UM +friendly's +friendly/UPTR +friendship/MS +frieze/SM +frig/S +frigate/MS +frigged +frigging +fright/SXGMDN +frighten/DG +frightening/Y +frightful/PY +frightfulness/M +frigid/YP +frigidity/M +frigidness/M +frill/SMD +frilly/TR +fringe's +fringe/IDSG +frippery/SM +frisk/SDG +friskily +friskiness/M +frisky/TRP +frisson/S +fritter/MDSG +fritz/M +frivolity/SM +frivolous/PY +frivolousness/M +frizz/MDSYG +frizzle/MGDS +frizzy/TR +fro +frock's +frock/CUS +frog/MS +frogging/S +frogman/M +frogmarch/GDS +frogmen +frogspawn +frolic/SM +frolicked +frolicker/SM +frolicking +frolicsome +from +frond/SM +front's +front/FSDG +frontage/MS +frontal/Y +frontbench/ZRS +frontier/MS +frontiersman/M +frontiersmen +frontierswoman +frontierswomen +frontispiece/MS +frontward/S +frosh/M +frost's +frost/CSDG +frostbit +frostbite/MGS +frostbitten +frostily +frostiness/M +frosting/SM +frosty/TPR +froth/MDG +frothiness/M +froths +frothy/TPR +froufrou/M +froward/P +frowardness/M +frown/SMDG +frowsy/TR +frowzily +frowziness/M +frowzy/TPR +froze/AU +frozen/UA +fructify/DSG +fructose/M +frugal/Y +frugality/M +fruit/SMDG +fruitcake/MS +fruiterer/S +fruitful/YP +fruitfulness/M +fruitiness/M +fruition/M +fruitless/PY +fruitlessness/M +fruity/TPR +frump/SM +frumpish +frumpy/TR +frustrate/GNXDS +frustrating/Y +frustration/M +frustum/MS +fry/GDSM +fryer/SM +ft +ftp/ZGS +fuchsia/MS +fuck/SMGDRZ! +fucker/M! +fuckhead/S! +fuddle/DSMG +fudge/DSMG +fuehrer/MS +fuel's +fuel/ADGS +fug +fugal +fuggy +fugitive/MS +fugue/SM +fuhrer/SM +fulcrum/MS +fulfill/LDGS +fulfilled/U +fulfilling/U +fulfillment/M +full/MDRZTGSP +fullback/MS +fuller/M +fullness/M +fully +fulminate/DSXGN +fulmination/M +fulsome/PY +fulsomeness/M +fum/S +fumble/DRSMZG +fumbler/M +fumbling/Y +fume/MGDS +fumigant/MS +fumigate/GNDS +fumigation/M +fumigator/SM +fumy/RT +fun/M +function/MDGS +functional/Y +functionalism +functionalist/S +functionality/S +functionary/SM +fund/AMDGS +fundamental/SMY +fundamentalism/M +fundamentalist/SM +funded/U +funding/M +fundraiser/MS +fundraising +funeral/MS +funerary +funereal/Y +funfair/S +fungal +fungi +fungible/MS +fungicidal +fungicide/MS +fungoid +fungous +fungus/M +funicular/SM +funk/MDGS +funkiness/M +funky/PRT +funnel/MDGS +funner +funnest +funnily +funniness/M +funny/TPRSM +funnyman/M +funnymen +fur/SM +furbelow/M +furbish/ADSG +furious/Y +furl's +furl/UDGS +furlong/SM +furlough/GMD +furloughs +furn +furnace/SM +furnish/ADSG +furnished/U +furnishings/M +furniture/M +furor/SM +furred +furrier/M +furriness/M +furring/M +furrow/MDSG +furry/ZTRP +further/SGD +furtherance/M +furthermore +furthermost +furthest +furtive/YP +furtiveness/M +fury/SM +furze/M +fuse's/A +fuse/CAIFGDS +fusee/SM +fuselage/SM +fusibility/M +fusible +fusileer/SM +fusilier/SM +fusillade/MS +fusion/IFKSM +fuss/MDSG +fussbudget/MS +fussily +fussiness/M +fusspot/SM +fussy/TRP +fustian/M +fustiness/M +fusty/TRP +fut +futile/Y +futility/M +futon/SM +future/MS +futurism/M +futurist/MS +futuristic +futurity/SM +futurologist/MS +futurology/M +futz/DSG +fuzz/MDSG +fuzzball/S +fuzzily +fuzziness/M +fuzzy/PTR +fwd +fwy +fête/SM +g/SNXVB +gab/SM +gabardine/SM +gabbed +gabbiness/M +gabbing +gabble/DSMG +gabby/RTP +gaberdine/SM +gabfest/MS +gable/DSM +gad/S +gadabout/SM +gadded +gadder/SM +gadding +gadfly/SM +gadget/SM +gadgetry/M +gadolinium/M +gaff/MDRZGS +gaffe/SM +gaffer/M +gag/SM +gaga +gagged +gagging +gaggle/SM +gaiety/M +gaily +gain's +gain/ADGS +gainer/SM +gainful/Y +gainsaid +gainsay/ZGRS +gainsayer/M +gait/MRZS +gaiter/M +gal/SM +gala/MS +galactic +galaxy/SM +gale's +gale/AS +galena/M +gall/MDGS +gallant/SMY +gallantry/M +gallbladder/MS +galleon/SM +galleria/MS +gallery/SM +galley/SM +gallimaufry/SM +gallium/M +gallivant/GSD +gallon/SM +gallop/SMDG +gallows/M +gallstone/MS +galoot/SM +galore +galosh/MS +galumph/DG +galumphs +galvanic +galvanism/M +galvanization/M +galvanize/DSG +galvanometer/MS +gambit/SM +gamble/DRSMZG +gambler/M +gambling/M +gambol/SMDG +game/MYTGDRSP +gamecock/MS +gamekeeper/MS +gameness/M +gamesmanship/M +gamester/MS +gamete/SM +gametic +gamey +gamin/SM +gamine/SM +gaminess/M +gaming/M +gamma/SM +gammon/M +gammy +gamut/SM +gamy/RTP +gander/SM +gang/MDGS +gangbusters/M +gangland/M +ganglia +gangling +ganglion/M +ganglionic +gangplank/SM +gangrene/DSMG +gangrenous +gangsta/S +gangster/SM +gangway/MS +ganja +gannet/SM +gantlet/MS +gantry/SM +gap/GSMD +gape/MS +gar/SLM +garage/DSMG +garb/MDGS +garbage/M +garbageman +garbanzo/SM +garble/DSG +garcon/SM +garden/SZGMDR +gardener/M +gardenia/MS +gardening/M +garfish/MS +gargantuan +gargle/DSMG +gargoyle/SM +garish/PY +garishness/M +garland/MDGS +garlic/M +garlicky +garment/MS +garner/SGD +garnet/SM +garnish/GLMDS +garnishee/DSM +garnisheeing +garnishment/SM +garotte/MGDS +garret/SM +garrison/MDSG +garrote/MZGDRS +garroter/M +garrotte/MGDS +garrulity/M +garrulous/PY +garrulousness/M +garter/SM +garçon/SM +gas's +gas/CS +gasbag/SM +gaseous +gash/MDSG +gasholder/S +gasket/SM +gaslight/MS +gasman +gasmen +gasohol/M +gasoline/M +gasometer/S +gasp/MDGS +gassed/C +gasses +gassing/C +gassy/RT +gastric +gastritis/M +gastroenteritis/M +gastrointestinal +gastronome/S +gastronomic +gastronomical/Y +gastronomy/M +gastropod/SM +gasworks/M +gate/MGDS +gateau +gateaux +gatecrash/DRSZG +gatecrasher/M +gatehouse/SM +gatekeeper/MS +gatepost/MS +gateway/MS +gather/SJZGMDR +gatherer/M +gathering/M +gator/SM +gauche/RPYT +gaucheness/M +gaucherie/M +gaucho/SM +gaudily +gaudiness/M +gaudy/RPT +gauge/DSMG +gaunt/RPT +gauntlet/MS +gauntness/M +gauze/M +gauziness/M +gauzy/RPT +gave +gavel/SM +gavotte/MS +gawd +gawk/DGS +gawkily +gawkiness/M +gawky/RPT +gawp/DGS +gay/TSPMR +gayness/M +gaze/MZGDRS +gazebo/SM +gazelle/MS +gazer/M +gazette/MGDS +gazetteer/MS +gazillion/S +gazpacho/M +gazump/DGS +gear/MDGS +gearbox/MS +gearing/M +gearshift/MS +gearwheel/SM +gecko/SM +geddit +gee/DS +geeing +geek/MS +geeky/RT +geese +geezer/MS +geisha/M +gel/SM +gelatin/M +gelatinous +gelcap/M +geld/DJGS +gelding/M +gelid +gelignite/M +gelled +gelling +gem/SM +gemmology/M +gemological +gemologist/MS +gemology/M +gemstone/MS +gendarme/MS +gender/MDS +gene/MS +genealogical/Y +genealogist/MS +genealogy/SM +genera +general/SMY +generalissimo/MS +generalist/MS +generality/SM +generalization/MS +generalize/GDS +generalship/M +generate/CAVNGSD +generation/ACM +generational +generations +generator/SM +generic/SM +generically +generosity/SM +generous/PY +generousness/M +genes/S +genesis/M +genetic/S +genetically +geneticist/MS +genetics/M +genial/FY +geniality/FM +geniculate +genie/SM +genii +genital/FY +genitalia/M +genitals/M +genitive/MS +genitourinary +genius/MS +genned +genning +genocidal +genocide/MS +genome/MS +genomics +genre/SM +gent/AMS +genteel/YP +genteelness/M +gentian/SM +gentile/SM +gentility/M +gentle/TGDRSP +gentlefolk/MS +gentlefolks/M +gentleman/MY +gentlemanly/U +gentlemen +gentleness/M +gentlewoman/M +gentlewomen +gently +gentrification/M +gentrify/DSGN +gentry/SM +genuflect/DGS +genuflection/MS +genuine/PY +genuineness/M +genus/M +geocache/DSG +geocentric +geocentrically +geochemistry/M +geode/SM +geodesic/SM +geodesy/M +geodetic +geoengineering +geog +geographer/SM +geographic +geographical/Y +geography/SM +geologic +geological/Y +geologist/MS +geology/SM +geom +geomagnetic +geomagnetism/M +geometer +geometric +geometrical/Y +geometry/SM +geophysical +geophysicist/SM +geophysics/M +geopolitical +geopolitics/M +geostationary +geosynchronous +geosyncline/MS +geothermal +geothermic +geranium/MS +gerbil/MS +geriatric/S +geriatrician/S +geriatrics/M +germ/MS +germane +germanium/M +germicidal +germicide/MS +germinal/M +germinate/GNDS +germination/M +gerontological +gerontologist/MS +gerontology/M +gerrymander/GMDS +gerrymandering/M +gerund/MS +gestalt/S +gestapo/MS +gestate/GNDS +gestation/M +gestational +gesticulate/DSGNX +gesticulation/M +gestural +gesture/MGDS +gesundheit +get/S +getaway/SM +getting +getup/M +gewgaw/SM +geyser/SM +ghastliness/M +ghastly/TPR +ghat/MS +ghee +gherkin/MS +ghetto/SM +ghettoize/GDS +ghost/SMDYG +ghostliness/M +ghostly/RTP +ghostwrite/ZGRS +ghostwriter/M +ghostwritten +ghostwrote +ghoul/SM +ghoulish/YP +ghoulishness/M +giant/SM +giantess/MS +gibber/GDS +gibberish/M +gibbet/GMDS +gibbon/MS +gibbous +gibe/MGDS +giblet/SM +giddily +giddiness/M +giddy/RTP +gift/MDGS +gig/SM +gigabit/SM +gigabyte/MS +gigahertz/M +gigantic +gigantically +gigapixel/MS +gigawatt/SM +gigged +gigging +giggle/DRSMZG +giggler/M +giggly/RT +gigolo/SM +gild/MDRZGS +gilder/M +gilding/M +gill/MS +gillie/S +gillion/S +gilt/MS +gimbals/M +gimcrack/SM +gimcrackery/M +gimlet/GSMD +gimme/SM +gimmick/MS +gimmickry/M +gimmicky +gimp/MDGS +gimpy +gin/SM +ginger/GSMDY +gingerbread/M +gingersnap/SM +gingery +gingham/M +gingivitis/M +ginkgo/SM +ginkgoes +ginned +ginning +ginormous +ginseng/M +giraffe/MS +gird/DRZGS +girder/M +girdle/DSMG +girl/MS +girlfriend/MS +girlhood/SM +girlie +girlish/YP +girlishness/M +girly/S +giro/S +girt/MDGS +girth/M +girths +gist/M +git/S +gite/S +give/ZGJRS +giveaway/MS +giveback/MS +given/SM +giver/M +gizmo/SM +gizzard/MS +glace/S +glaceed +glaceing +glacial/Y +glaciate/XGNDS +glaciation/M +glacier/MS +glacé/SDG +glad/MYSP +gladden/GDS +gladder +gladdest +glade/SM +gladiator/SM +gladiatorial +gladiola/SM +gladioli +gladiolus/M +gladness/M +gladsome +glam +glamor/SGMD +glamorization/M +glamorize/DSG +glamorous/Y +glamour/GMDS +glance/DSMG +gland/SM +glandes +glandular +glans/M +glare/DSMG +glaring/Y +glasnost/M +glass/MDSG +glassblower/MS +glassblowing/M +glassful/SM +glasshouse/S +glassily +glassiness/M +glassware/M +glassy/RTP +glaucoma/M +glaze/DSMG +glazier/SM +glazing/M +gleam/SMDGJ +glean/SDRZGJ +gleaner/M +gleanings/M +glee/M +gleeful/YP +gleefulness/M +glen/MS +glenohumeral +glenoid +glib/YP +glibber +glibbest +glibness/M +glide/DRSMZG +glider/M +gliding/M +glimmer/MDGJS +glimmering/M +glimpse/MGDS +glint/SMDG +glissandi +glissando/M +glisten/MDSG +glister/DSG +glitch/GMDS +glitter/MDSG +glitterati +glittery +glitz/M +glitzy/TR +gloaming/SM +gloat/SMDG +gloating/Y +glob/MDGS +global/Y +globalism/M +globalist/MS +globalization/M +globalize/GDS +globe/SM +globetrotter/MS +globetrotting +globular +globule/MS +globulin/M +glockenspiel/SM +gloom/M +gloomily +gloominess/M +gloomy/TRP +glop/M +gloppy +glorification/M +glorify/GDSN +glorious/IY +glory/DSMG +gloss/MDSG +glossary/SM +glossily +glossiness/M +glossolalia/M +glossy/PTRSM +glottal +glottis/MS +glove/DSMG +glow/MDRZGS +glower/GMD +glowing/Y +glowworm/MS +glucagon +glucose/M +glue/MGDS +glued/U +gluey +gluier +gluiest +glum/YP +glummer +glummest +glumness/M +glut/MNS +gluten/M +glutenous +glutinous/Y +glutted +glutting +glutton/MS +gluttonous/Y +gluttony/M +glycerin/M +glycerine/M +glycerol/M +glycogen/M +glyph +gm +gnarl/SMDG +gnarly/TR +gnash/MDSG +gnat/MS +gnaw/DGS +gneiss/M +gnocchi +gnome/SM +gnomic +gnomish +gnu/SM +go/JMRHZG +goad/MDGS +goal/MS +goalie/SM +goalkeeper/MS +goalkeeping/M +goalless +goalmouth +goalmouths +goalpost/MS +goalscorer/S +goaltender/MS +goat/MS +goatee/SM +goatherd/MS +goatskin/MS +gob/SM +gobbed +gobbet/SM +gobbing +gobble/DRSMZG +gobbledygook/M +gobbler/M +goblet/SM +goblin/SM +gobsmacked +gobstopper/S +god/SM +godawful +godchild/M +godchildren/M +goddam/D +goddammit +goddamn/D +goddaughter/MS +goddess/MS +godfather/SM +godforsaken +godhead/M +godhood/M +godless/PY +godlessness/M +godlike +godliness/UM +godly/URTP +godmother/SM +godparent/SM +godsend/SM +godson/SM +godspeed +goer/M +goes +gofer/SM +goggle/DSMG +goggles/M +going/M +goiter/SM +gold/MNS +goldbrick/ZGSMDR +goldbricker/M +golden/TR +goldenrod/M +goldfield/S +goldfinch/MS +goldfish/MS +goldmine/SM +goldsmith/M +goldsmiths +golf/MDRZGS +golfer/M +golliwog/S +golly/SM +gonad/SM +gonadal +gondola/MS +gondolier/SM +gone/ZR +goner/M +gong/MDGS +gonk/S +gonna +gonorrhea/M +gonorrheal +gonzo +goo/M +goober/SM +good/MYSP +goodby/M +goodbye/MS +goodbys +goodhearted +goodie/M +goodish +goodly/TR +goodness/M +goodnight +goods/M +goodwill/M +goody/SM +gooey +goof/MDGS +goofball/SM +goofiness/M +goofy/RPT +google/DSMG +googly/S +gooier +gooiest +gook/MS +goon/MS +goop/M +goose/DSMG +gooseberry/SM +goosebumps/M +gooseflesh/M +goosestep/S +goosestepped +goosestepping +gopher/SM +gore/MGDS +gorge's +gorge/EDSG +gorgeous/YP +gorgeousness/M +gorgon/SM +gorilla/MS +gorily +goriness/M +gormandize/DRSZG +gormandizer/M +gormless +gorp/MS +gorse/M +gory/RTP +gosh +goshawk/MS +gosling/SM +gospel/MS +gossamer/M +gossip/MDRZGS +gossiper/M +gossipy +got +gotcha/S +goths +gotta +gotten +gouache/S +gouge/DRSMZG +gouger/M +goulash/MS +gourd/SM +gourde/MS +gourmand/SM +gourmet/SM +gout/M +gouty/TR +gov +govern/DGSBL +governable/U +governance/M +governed/U +governess/MS +government/MS +governmental +governor/SM +governorship/M +govt +gown/MDGS +gr +grab/MS +grabbed +grabber/MS +grabbing +grabby/TR +grace/EDSMG +graceful/EPY +gracefulness/EM +graceless/PY +gracelessness/M +gracious/UY +graciousness/M +grackle/MS +grad/MRZSB +gradate/XGNDS +gradation/CM +grade's +grade/CADSG +graded/U +grader/M +gradient/MS +gradual/PY +gradualism/M +gradualness/M +graduate/XMGNDS +graduation/M +graffiti +graffito/M +graft/SMDRZG +grafter/M +graham/S +grail +grain/ISMD +graininess/M +grainy/PTR +gram/KMS +grammar/MS +grammarian/SM +grammatical/UY +gramophone/MS +grampus/MS +gran/S +granary/SM +grand/SMRYPT +grandad/MS +grandam/MS +grandaunt/MS +grandchild/M +grandchildren/M +granddad/SM +granddaddy/SM +granddaughter/SM +grandee/MS +grandeur/M +grandfather/GMDYS +grandiloquence/M +grandiloquent +grandiose/Y +grandiosity/M +grandma/MS +grandmother/MYS +grandnephew/MS +grandness/M +grandniece/MS +grandpa/MS +grandparent/MS +grandson/MS +grandstand/SGMD +granduncle/SM +grange/SM +granite/M +granitic +grannie/M +granny/SM +granola/M +grant/SMDRZG +grantee/MS +granter/M +grantsmanship/M +granular +granularity/M +granulate/GNDS +granulation/M +granule/MS +grape/SM +grapefruit/MS +grapeshot/M +grapevine/SM +graph/MDG +graphic/MS +graphical/Y +graphite/M +graphologist/MS +graphology/M +graphs +grapnel/MS +grapple/MGDS +grasp/SMDBG +grass/MDSG +grasshopper/MS +grassland/MS +grassroots +grassy/TR +grate/DRSMZGJ +grateful/UYP +gratefulness/UM +grater/M +gratification/M +gratify/GNXDS +gratifying/Y +gratin/S +grating/MY +gratis +gratitude/IM +gratuitous/YP +gratuitousness/M +gratuity/SM +gravamen/MS +grave/DRSMYTGP +gravedigger/SM +gravel/SGMDY +graven +graveness/M +graveside/MS +gravestone/SM +graveyard/MS +gravid +gravimeter/MS +gravitas +gravitate/GNDS +gravitation/M +gravitational +gravity/M +gravy/SM +gray/MDRTGSP +graybeard/SM +grayish +grayness/M +graze/DRSMZG +grazer/M +grease/DRSMZG +greasepaint/M +greasily +greasiness/M +greasy/PTR +great/SMRYPT +greatcoat/SM +greathearted +greatness/M +grebe/SM +greed/M +greedily +greediness/M +greedy/PTR +green/GPSMDRYT +greenback/MS +greenbelt/MS +greenery/M +greenfield +greenfly/S +greengage/MS +greengrocer/SM +greenhorn/SM +greenhouse/SM +greenish +greenmail/M +greenness/M +greenroom/SM +greensward/M +greenwood/M +greet/ZGJSDR +greeter/M +greeting/M +gregarious/PY +gregariousness/M +gremlin/SM +grenade/SM +grenadier/MS +grenadine/M +grep/S +grepped +grepping +grew/A +greyhound/SM +gribble/S +grid/MS +griddle/SM +griddlecake/SM +gridiron/SM +gridlock/SMD +grief/SM +grievance/MS +grieve/ZGDRS +griever/M +grievous/PY +grievousness/M +griffin/SM +griffon/SM +grill/SGMDJ +grille/MS +grim/DYPG +grimace/DSMG +grime/SM +griminess/M +grimmer +grimmest +grimness/M +grimy/TRP +grin/MS +grind/SZGMRJ +grinder/M +grindstone/MS +gringo/MS +grinned +grinning +grip/MDRSZG +gripe/SM +griper/M +grippe/MZGDR +gripper/M +grisliness/M +grisly/RTP +grist/MY +gristle/M +gristmill/MS +grit/MS +grits/M +gritted +gritter/SM +grittiness/M +gritting +gritty/RTP +grizzle/DSG +grizzly/TRSM +groan/SGMD +groat/SM +grocer/MS +grocery/SM +grog/M +groggily +grogginess/M +groggy/PRT +groin/SM +grok/S +grokked +grokking +grommet/SM +groom/SZGMDR +groomer/M +grooming/M +groomsman/M +groomsmen +groove/MGDS +groovy/RT +grope/DRSMZG +groper/M +grosbeak/MS +grosgrain/M +gross/PTGMDRSY +grossness/M +grotesque/SPMY +grotesqueness/M +grotto/M +grottoes +grotty/TR +grouch/GMDS +grouchily +grouchiness/M +grouchy/RTP +ground/ZGMDRJS +groundbreaking/MS +groundcloth +groundcloths +grounder/M +groundhog/MS +grounding/M +groundless/Y +groundnut/MS +groundsheet/S +groundskeeper/S +groundsman +groundsmen +groundswell/SM +groundwater/M +groundwork/M +group/JSZGMDR +grouper/M +groupie/MS +grouping/M +groupware/M +grouse/MZGDRS +grouser/M +grout/SGMD +grove/SM +grovel/ZGDRS +groveler/M +grovelled +grovelling +grow/AHSG +grower/MS +growing/I +growl/SZGMDR +growler/M +grown/AI +grownup/MS +growth/AM +growths +grub/MS +grubbed +grubber/MS +grubbily +grubbiness/M +grubbing +grubby/TRP +grubstake/M +grudge/MGDS +grudging/Y +grue/S +gruel/GJM +grueling/Y +gruesome/RYTP +gruesomeness/M +gruff/TPRY +gruffness/M +grumble/DRSMZGJ +grumbler/M +grump/SM +grumpily +grumpiness/M +grumpy/PRT +grunge/MS +grungy/RT +grunion/SM +grunt/SGMD +gt +guacamole/M +guanine/M +guano/M +guarani/MS +guaranies +guarantee/MDS +guaranteeing +guarantor/MS +guaranty/GDSM +guard/SZGMDR +guarded/Y +guarder/M +guardhouse/SM +guardian/SM +guardianship/M +guardrail/SM +guardroom/SM +guardsman/M +guardsmen +guava/SM +gubernatorial +guerilla/SM +guerrilla/SM +guess/ZGBMDRS +guesser/M +guesstimate/DSMG +guesswork/M +guest/SGMD +guestbook/SM +guesthouse/S +guestroom/S +guff/M +guffaw/MDGS +guidance/M +guide/DRSMZG +guidebook/SM +guided/U +guideline/SM +guidepost/SM +guider/M +guild/SZMR +guilder/M +guildhall/MS +guile/M +guileful +guileless/YP +guilelessness/M +guillemot/S +guillotine/DSMG +guilt/M +guiltily +guiltiness/M +guiltless +guilty/PRT +guinea/MS +guise/ESM +guitar/MS +guitarist/SM +gulag/SM +gulch/MS +gulden/MS +gulf/MS +gull/MDSG +gullet/MS +gullibility/M +gullible +gully/SM +gulp/MDRSZG +gulper/M +gum/SM +gumball/S +gumbo/SM +gumboil/SM +gumboot/S +gumdrop/SM +gummed +gumming +gummy/TR +gumption/M +gumshoe/MDS +gumshoeing +gun/SM +gunboat/SM +gunfight/MRZS +gunfighter/M +gunfire/M +gunge +gungy +gunk/M +gunky +gunman/M +gunmen +gunmetal/M +gunned +gunnel/MS +gunner/MS +gunnery/M +gunning +gunny/M +gunnysack/MS +gunpoint/M +gunpowder/M +gunrunner/MS +gunrunning/M +gunship/MS +gunshot/MS +gunslinger/SM +gunsmith/M +gunsmiths +gunwale/MS +guppy/SM +gurgle/MGDS +gurney/MS +guru/MS +gush/MDRSZG +gusher/M +gushing/Y +gushy/TR +gusset/MSDG +gussy/DSG +gust/EMDSG +gustatory +gustily +gusto/M +gusty/RT +gut/SM +gutless/P +gutlessness/M +gutsy/RT +gutted +gutter/SMDG +guttersnipe/MS +gutting +guttural/MS +gutty/RT +guv/S +guvnor/S +guy/SGMD +guzzle/DRSZG +guzzler/M +gym/SM +gymkhana/MS +gymnasium/MS +gymnast/MS +gymnastic/S +gymnastically +gymnastics/M +gymnosperm/SM +gymslip/S +gynecologic +gynecological +gynecologist/SM +gynecology/M +gyp/SM +gypped +gypper/SM +gypping +gypster/SM +gypsum/M +gypsy/SM +gyrate/DSGNX +gyration/M +gyrator/SM +gyrfalcon/MS +gyro/MS +gyroscope/MS +gyroscopic +gyve/MGDS +h'm +h/NRSXZGVJ +ha/SH +haberdasher/SM +haberdashery/SM +habiliment/SM +habit's +habit/ISB +habitability/M +habitat/SM +habitation/MS +habitual/YP +habitualness/M +habituate/GNDS +habituation/M +habitue/SM +habitué/SM +hacienda/SM +hack/MDRZGS +hacker/M +hacking/M +hackish +hackle/MS +hackney/SMDG +hacksaw/SM +hacktivist/MS +hackwork/M +had +haddock/SM +hadn't +hadst +hafnium/M +haft/MS +hag/SM +haggard/YP +haggardness/M +haggis/MS +haggish +haggle/MZGDRS +haggler/M +hagiographer/SM +hagiography/SM +hah +hahnium/M +haiku/M +hail/MDGS +hailstone/MS +hailstorm/MS +hair/MDS +hairball/MS +hairband/S +hairbreadth/M +hairbreadths +hairbrush/MS +haircloth/M +haircut/SM +hairdo/MS +hairdresser/SM +hairdressing/M +hairdrier/MS +hairdryer/MS +hairgrip/S +hairiness/M +hairless +hairlike +hairline/SM +hairnet/SM +hairpiece/MS +hairpin/SM +hairsbreadth/M +hairsbreadths +hairsplitter/SM +hairsplitting/M +hairspray/S +hairspring/MS +hairstyle/MS +hairstylist/SM +hairy/TRP +haj +hajj/M +hajjes +hajji/SM +hake/MS +halal/M +halberd/SM +halcyon +hale/ITGDRS +half/M +halfback/SM +halfhearted/PY +halfheartedness/M +halfpence +halfpenny/SM +halftime/MS +halftone/MS +halfway +halfwit/SM +halibut/SM +halite/M +halitosis/M +hall/MS +hallelujah/M +hallelujahs +hallmark/GMDS +halloo/MDSG +hallow/DSG +hallowed/U +hallucinate/GNXDS +hallucination/M +hallucinatory +hallucinogen/SM +hallucinogenic/SM +hallway/SM +halo/MDGS +halogen/SM +halon +halt/MDRZGS +halter/GMD +halterneck/S +halting/Y +halve/DSG +halyard/MS +ham/SM +hamburg/SZMR +hamburger/M +hamlet/MS +hammed +hammer/MDRSJZG +hammerer/M +hammerhead/SM +hammerlock/SM +hammertoe/MS +hamming +hammock/SM +hammy/TR +hamper/GMDS +hampered/U +hamster/MS +hamstring/GSM +hamstrung +hand's +hand/UDGS +handbag/SM +handball/MS +handbarrow/SM +handbill/MS +handbook/MS +handbrake/S +handcar/SM +handcart/MS +handclasp/MS +handcraft/SMDG +handcuff/MDGS +handed/P +handful/SM +handgun/SM +handheld/MS +handhold/MS +handicap/MS +handicapped +handicapper/MS +handicapping +handicraft/MS +handily +handiness/M +handiwork/M +handkerchief/MS +handle/MZGDRS +handlebar/MS +handler/M +handmade +handmaid/XMNS +handmaiden/M +handout/SM +handover/S +handpick/GDS +handrail/MS +handsaw/SM +handset/SM +handshake/JMGS +handsome/PYTR +handsomeness/M +handspring/MS +handstand/SM +handwork/M +handwoven +handwriting/M +handwritten +handy/UTR +handyman/M +handymen +hang/MDRJZGS +hangar/MS +hangdog +hanger/M +hanging/M +hangman/M +hangmen +hangnail/MS +hangout/SM +hangover/MS +hangup/MS +hank/MRZS +hanker/GJD +hankering/M +hankie/M +hanky/SM +hansom/MS +hap/MY +haphazard/YP +haphazardness/M +hapless/YP +haplessness/M +haploid/MS +happen/SDGJ +happening/M +happenstance/SM +happily/U +happiness/UM +happy/URTP +harangue/MGDS +harass/LZGDRS +harasser/M +harassment/M +harbinger/SM +harbor/GMDS +harbormaster/S +hard/NRYXTP +hardback/MS +hardball/M +hardboard/M +hardbound +hardcore +hardcover/SM +harden/ZGDR +hardened/U +hardener/M +hardhat/MS +hardheaded/PY +hardheadedness/M +hardhearted/PY +hardheartedness/M +hardihood/M +hardily +hardiness/M +hardliner/MS +hardness/M +hardscrabble +hardship/SM +hardstand/SM +hardtack/M +hardtop/SM +hardware/M +hardwired +hardwood/SM +hardworking +hardy/PTR +hare/MGDS +harebell/MS +harebrained +harelip/SM +harelipped +harem/SM +haricot/S +hark/DGS +harlequin/SM +harlot/SM +harlotry/M +harm/MDGS +harmed/U +harmful/YP +harmfulness/M +harmless/PY +harmlessness/M +harmonic/SM +harmonica/MS +harmonically +harmonies +harmonious/PY +harmoniousness/M +harmonium/MS +harmonization/M +harmonize/ZGDRS +harmonizer/M +harmony/EM +harness's +harness/UDSG +harp/MDGS +harpist/SM +harpoon/ZGSMDR +harpooner/M +harpsichord/MS +harpsichordist/SM +harpy/SM +harridan/MS +harrier/M +harrow/SMDG +harrumph/GD +harrumphs +harry/DRSZG +harsh/RYTP +harshness/M +hart/MS +harvest/SMDRZG +harvested/U +harvester/M +hash/AMDSG +hashish/M +hashtag/SM +hasn't +hasp/MS +hassle/DSMG +hassock/SM +hast/DNXG +haste/SM +hasten/DG +hastily +hastiness/M +hasty/RTP +hat/ZGSMDR +hatband/S +hatbox/MS +hatch/MDSG +hatchback/MS +hatcheck/SM +hatched/U +hatchery/SM +hatchet/SM +hatching/M +hatchway/SM +hate/MS +hateful/PY +hatefulness/M +hatemonger/MS +hater/M +hatpin/S +hatred/SM +hatstand/S +hatted +hatter/SM +hatting +hauberk/SM +haughtily +haughtiness/M +haughty/PRT +haul/MDRZGS +haulage/M +hauler/M +haulier/S +haunch/MS +haunt/SMDRZG +haunter/M +haunting/Y +hauteur/M +have/MGS +haven't +haven/SM +haversack/SM +havoc/M +haw/GSMD +hawk/MDRZGS +hawker/M +hawkish/P +hawkishness/M +hawser/SM +hawthorn/MS +hay/GSMD +haycock/SM +hayloft/SM +haymaking +haymow/SM +hayrick/MS +hayride/MS +hayseed/MS +haystack/SM +haywire +hazard/SMDG +hazardous/Y +haze/MZGJDRS +hazel/SM +hazelnut/MS +hazer/M +hazily +haziness/M +hazing/M +hazmat +hazy/RTP +hdqrs +he'd +he'll +he/M +head/MDRZGJS +headache/MS +headband/MS +headbanger/S +headbanging +headboard/SM +headbutt/DSG +headcase/S +headcheese +headcount/S +headdress/MS +header/M +headfirst +headgear/M +headhunt/DRSZG +headhunter/M +headhunting/M +headily +headiness/M +heading/M +headlamp/MS +headland/MS +headless +headlight/MS +headline/MZGDRS +headliner/M +headlock/MS +headlong +headman/M +headmaster/SM +headmen +headmistress/MS +headphone/MS +headpiece/MS +headpin/SM +headquarter/SDG +headquarters/M +headrest/MS +headroom/M +headscarf +headscarves +headset/SM +headship/SM +headshrinker/SM +headsman/M +headsmen +headstall/SM +headstand/SM +headstone/SM +headstrong +headteacher/S +headwaiter/SM +headwaters/M +headway/M +headwind/SM +headword/SM +heady/RTP +heal/DRHZGS +healed/U +healer/M +health/M +healthcare +healthful/PY +healthfulness/M +healthily/U +healthiness/UM +healthy/UTRP +heap/MDGS +hear/AHGJS +heard/AU +hearer/SM +hearing/AM +hearken/SGD +hearsay/M +hearse's +hearse/AS +heart/SM +heartache/MS +heartbeat/MS +heartbreak/SMG +heartbroken +heartburn/M +hearten/ESGD +heartfelt +hearth/M +hearthrug/S +hearths +hearthstone/SM +heartily +heartiness/M +heartland/MS +heartless/PY +heartlessness/M +heartrending/Y +heartsick/P +heartsickness/M +heartstrings/M +heartthrob/MS +heartwarming +heartwood/M +hearty/RSMPT +heat's +heat/ADGS +heated/U +heatedly +heater/SM +heath/MNRX +heathen/M +heathendom/M +heathenish +heathenism/M +heather/M +heaths +heating/M +heatproof +heatstroke/M +heatwave/S +heave/DRSMZG +heaven/SMY +heavenly/TR +heavens/M +heavenward/S +heaver/M +heavily +heaviness/M +heavy/RSMTP +heavyhearted +heavyset +heavyweight/MS +heck/M +heckle/DRSMZG +heckler/M +heckling/M +hectare/SM +hectic +hectically +hectogram/SM +hectometer/MS +hector/SMDG +hedge/DRSMZG +hedgehog/MS +hedgehop/S +hedgehopped +hedgehopping +hedger/M +hedgerow/SM +hedonism/M +hedonist/MS +hedonistic +heed/MDGS +heeded/U +heedful/Y +heedless/PY +heedlessness/M +heehaw/SMDG +heel/MDGS +heelless +heft/MDGS +heftily +heftiness/M +hefty/PRT +hegemonic +hegemony/M +hegira/SM +heifer/SM +height/XSMN +heighten/DG +heinous/YP +heinousness/M +heir/MS +heiress/MS +heirloom/SM +heist/SMDG +held +helical +helices +helicopter/SGMD +heliocentric +heliotrope/SM +helipad/S +heliport/MS +helium/M +helix/M +hell/M +hellbent +hellcat/MS +hellebore/M +hellfire +hellhole/MS +hellion/MS +hellish/YP +hellishness/M +hello/SM +helluva +helm/MS +helmet/SMD +helmsman/M +helmsmen +helot/SM +help/MDRZGSJ +helper/M +helpful/UY +helpfulness/M +helping/M +helpless/PY +helplessness/M +helpline/SM +helpmate/SM +helve/SM +hem/SM +hematite/M +hematologic +hematological +hematologist/MS +hematology/M +heme/M +hemisphere/SM +hemispheric +hemispherical +hemline/SM +hemlock/SM +hemmed +hemmer/SM +hemming +hemoglobin/M +hemophilia/M +hemophiliac/MS +hemorrhage/MGDS +hemorrhagic +hemorrhoid/MS +hemostat/MS +hemp/MN +hemstitch/MDSG +hen/M +hence +henceforth +henceforward +henchman/M +henchmen +henna/SMDG +henpeck/GSD +hep +heparin/M +hepatic +hepatitis/M +hepatocyte/S +hepper +heppest +heptagon/MS +heptagonal +heptathlon/SM +herald/SMDG +heralded/U +heraldic +heraldry/M +herb/MS +herbaceous +herbage/M +herbal/S +herbalist/MS +herbicidal +herbicide/MS +herbivore/SM +herbivorous +herculean +herd/MDRZGS +herder/M +herdsman/M +herdsmen +here/M +hereabout/S +hereafter/SM +hereby +hereditary +heredity/M +herein +hereinafter +hereof +hereon +heresy/SM +heretic/SM +heretical +hereto +heretofore +hereunto +hereupon +herewith +heritable/I +heritage/MS +hermaphrodite/SM +hermaphroditic +hermetic +hermetical/Y +hermit/SM +hermitage/MS +hernia/SM +hernial +herniate/GNDS +herniation/M +hero/M +heroes +heroic/S +heroically +heroics/M +heroin/SM +heroine/SM +heroism/M +heron/SM +herpes/M +herpetologist/SM +herpetology/M +herring/MS +herringbone/M +herself +hertz/M +hesitance/M +hesitancy/M +hesitant/Y +hesitate/DSGNX +hesitating/UY +hesitation/M +hessian +hetero/SM +heterodox +heterodoxy/M +heterogeneity/M +heterogeneous/Y +heterosexual/MYS +heterosexuality/M +heuristic/MS +heuristically +heuristics/M +hew/ZGSDR +hewer/M +hex/GMDS +hexadecimal/S +hexagon/MS +hexagonal +hexagram/SM +hexameter/SM +hey +heyday/SM +hf +hgt +hgwy +hi/SD +hiatus/MS +hibachi/MS +hibernate/GNDS +hibernation/M +hibernator/MS +hibiscus/MS +hiccough/DG +hiccoughs +hiccup/GSMD +hick/MS +hickey/SM +hickory/SM +hid +hidden +hide/MZGJDRS +hideaway/SM +hidebound +hideous/YP +hideousness/M +hideout/MS +hider/M +hiding/M +hie/S +hieing +hierarchic +hierarchical/Y +hierarchy/SM +hieroglyph/M +hieroglyphic/MS +hieroglyphs +high/MRYZTP +highball/SM +highborn +highboy/MS +highbrow/SM +highchair/MS +highfalutin +highhanded/PY +highhandedness/M +highland/MRZS +highlander/M +highlight/SMDRZG +highlighter/M +highness/M +highroad/MS +highs +hightail/DSG +highway/MS +highwayman/M +highwaymen +hijab/SM +hijack/SJZGMDR +hijacker/M +hijacking/M +hike/MZGDRS +hiker/M +hiking/M +hilarious/PY +hilariousness/M +hilarity/M +hill/MS +hillbilly/SM +hilliness/M +hillock/MS +hillside/SM +hilltop/MS +hilly/PRT +hilt/MS +him/S +himself +hind/MRZS +hinder/GD +hindered/U +hindmost +hindquarter/MS +hindrance/SM +hindsight/M +hinge's +hinge/UDSG +hint/MDRZGS +hinter/M +hinterland/SM +hip/SPM +hipbath +hipbaths +hipbone/MS +hiphuggers +hipness/M +hipped +hipper +hippest +hippie/M +hipping +hippo/SM +hippodrome/SM +hippopotamus/MS +hippy/SM +hipster/MS +hiragana +hire's +hire/AGDS +hireling/MS +hirsute/P +hirsuteness/M +hiss/MDSG +hist +histamine/MS +histogram/MS +histologist/SM +histology/M +historian/MS +historic +historical/Y +historicity/M +historiographer/MS +historiography/M +history/SM +histrionic/S +histrionically +histrionics/M +hit/SM +hitch's +hitch/UDSG +hitcher/MS +hitchhike/DRSMZG +hitchhiker/M +hither +hitherto +hitter/SM +hitting +hive/MGDS +hiya +hm +hmm +ho/SMDRYZ +hoagie/MS +hoard/SZGMDRJ +hoarder/M +hoarding/M +hoarfrost/M +hoariness/M +hoarse/YTRP +hoarseness/M +hoary/TRP +hoax/MDRSZG +hoaxer/M +hob/SM +hobbit/S +hobble/MZGDRS +hobbler/M +hobby/SM +hobbyhorse/MS +hobbyist/SM +hobgoblin/MS +hobnail/SGMD +hobnob/S +hobnobbed +hobnobbing +hobo/MS +hoboes +hock/MDSG +hockey/M +hockshop/MS +hod/SM +hodgepodge/SM +hoe/SM +hoecake/SM +hoedown/SM +hoeing +hoer/M +hog/SM +hogan/SM +hogback/SM +hogged +hogging +hoggish/Y +hogshead/SM +hogtie/DS +hogtying +hogwash/M +hoick/SGD +hoist/SGMD +hoke/GDS +hokey +hokier +hokiest +hokum/M +hold/MRJSZG +holdall/S +holder/M +holding/M +holdout/SM +holdover/SM +holdup/MS +hole/MGDS +holey +holiday/SMDG +holidaymaker/S +holiness/UM +holism +holistic +holistically +holler/MDGS +hollow/MDRYPSTG +hollowness/M +holly/SM +hollyhock/MS +holmium/M +holocaust/SM +hologram/MS +holograph/M +holographic +holographs +holography/M +hols +holster/SMDG +holy/URPT +homage/MS +hombre/MS +homburg/SM +home/MYZGDRS +homebody/SM +homeboy/SM +homecoming/SM +homegrown +homeland/MS +homeless/MP +homelessness/M +homelike +homeliness/M +homely/PRT +homemade +homemaker/SM +homemaking/M +homeopath/M +homeopathic +homeopaths +homeopathy/M +homeostasis/M +homeostatic +homeowner/MS +homepage/MS +homer/GMD +homeroom/MS +homeschooling/M +homesick/P +homesickness/M +homespun/M +homestead/SMDRZG +homesteader/M +homestretch/MS +hometown/MS +homeward/S +homework/MRZG +homewrecker/SM +homey/SMP +homeyness/M +homicidal +homicide/MS +homie/RSMT +homiletic +homily/SM +hominess/M +hominid/SM +hominoid/S +hominy/M +homo/MS +homoerotic +homogeneity/M +homogeneous/Y +homogenization/M +homogenize/DSG +homograph/M +homographs +homologous +homonym/SM +homophobia/M +homophobic +homophone/MS +homosexual/SM +homosexuality/M +hon/SZTGMDR +honcho/MS +hone/MS +honer/M +honest/EYT +honester +honesty/EM +honey/SGMD +honeybee/SM +honeycomb/MDSG +honeydew/SM +honeylocust/M +honeymoon/ZGMDRS +honeymooner/M +honeypot/S +honeysuckle/SM +honk/MDRSZG +honker/M +honkie/M +honky/SM +honor/ESGMDB +honorableness/M +honorably/E +honorarily +honorarium/MS +honorary +honoree/SM +honorer/SM +honorific/MS +hooch/M +hood/MDSG +hoodie/MS +hoodlum/SM +hoodoo/MDSG +hoodwink/DGS +hooey/M +hoof/MDRSZG +hook's +hook/UDSG +hookah/M +hookahs +hooker/MS +hookup/MS +hookworm/MS +hooky/M +hooligan/MS +hooliganism/M +hoop/MDSG +hoopla/M +hooray/MS +hoosegow/SM +hoot/MDRSZG +hootch/M +hootenanny/SM +hooter/M +hoover/DSG +hooves +hop/SGMD +hope/MS +hopeful/PSMY +hopefulness/M +hopeless/YP +hopelessness/M +hopped +hopper/MS +hopping +hopscotch/MDSG +hora/MS +horde/DSMG +horehound/SM +horizon/SM +horizontal/SMY +hormonal +hormone/SM +horn/MDS +hornblende/M +hornet/MS +hornless +hornlike +hornpipe/MS +horny/TR +horologic +horological +horologist/MS +horology/M +horoscope/SM +horrendous/Y +horrible/P +horribleness/M +horribly +horrid/Y +horrific +horrifically +horrify/DSG +horrifying/Y +horror/MS +horse's +horse/UDSG +horseback/M +horsebox/S +horseflesh/M +horsefly/SM +horsehair/M +horsehide/M +horselaugh/M +horselaughs +horseless +horseman/M +horsemanship/M +horsemen +horseplay/M +horsepower/M +horseradish/MS +horseshit/! +horseshoe/DSM +horseshoeing +horsetail/SM +horsetrading +horsewhip/SM +horsewhipped +horsewhipping +horsewoman/M +horsewomen +horsey +horsy/TR +hortatory +horticultural +horticulturalist/S +horticulture/M +horticulturist/MS +hosanna/SM +hose/MGDS +hosepipe/S +hosier/MS +hosiery/M +hosp +hospholipase +hospice/MS +hospitable/I +hospitably/I +hospital/SM +hospitality/M +hospitalization/SM +hospitalize/DSG +host/MDSG +hostage/MS +hostel/ZGMDRS +hosteler/M +hostelry/SM +hostess/MDSG +hostile/MYS +hostilities/M +hostility/SM +hostler/MS +hot/SYP +hotbed/MS +hotblooded +hotbox/MS +hotcake/SM +hotdog/MS +hotdogged +hotdogging +hotel/SM +hotelier/MS +hotfoot/MDGS +hothead/DSM +hotheaded/YP +hotheadedness/M +hothouse/SM +hotkey/S +hotline/MS +hotlink/S +hotness/M +hotplate/SM +hotpot/S +hots/M +hotshot/MS +hotted +hotter +hottest +hottie/S +hotting +hound/SGMD +hour/MYS +hourglass/MS +houri/SM +house's +house/ADSG +houseboat/SM +housebound +houseboy/SM +housebreak/RSZG +housebreaker/M +housebreaking/M +housebroke +housebroken +houseclean/DSG +housecleaning/M +housecoat/SM +housefly/SM +houseful/SM +household/SMRZ +householder/M +househusband/SM +housekeeper/MS +housekeeping/M +houselights/M +housemaid/SM +houseman/M +housemaster/S +housemate/S +housemen +housemistress/S +housemother/SM +houseparent/SM +houseplant/MS +houseproud +houseroom +housetop/SM +housewares/M +housewarming/SM +housewife/MY +housewives +housework/M +housing/MS +hove +hovel/SM +hover/SGD +hovercraft/MS +how'd +how're +how/SM +howbeit +howdah/M +howdahs +howdy +however +howitzer/SM +howl/MDRSZG +howler/M +howsoever +hoyden/MS +hoydenish +hp +hr/S +ht +huarache/SM +hub/SM +hubbub/SM +hubby/SM +hubcap/SM +hubris/M +huckleberry/SM +huckster/SGMD +hucksterism/M +huddle/DSMG +hue/DSM +huff/MDSG +huffily +huffiness/M +huffy/PRT +hug/STMR +huge/YP +hugeness/M +hugged +hugging +huh +hula/MS +hulk/MSG +hull/MDRSZG +hullabaloo/SM +huller/M +hum/SM +human/SMRYTP +humane/PY +humaneness/M +humanism/M +humanist/SM +humanistic +humanitarian/MS +humanitarianism/M +humanities/M +humanity/ISM +humanization/CM +humanize/CDSG +humanizer/SM +humankind/M +humanness/M +humanoid/SM +humble/DRSZTGJP +humbleness/M +humbler/M +humbly +humbug/SM +humbugged +humbugging +humdinger/MS +humdrum/M +humeral +humeri +humerus/M +humid/Y +humidification/M +humidifier/CM +humidify/CZGDRS +humidity/M +humidor/SM +humiliate/DSGNX +humiliating/Y +humiliation/M +humility/M +hummed +hummer/SM +humming +hummingbird/SM +hummock/SM +hummocky +hummus/M +humongous +humor/SMDG +humoresque +humorist/MS +humorless/YP +humorlessness/M +humorous/PY +humorousness/M +hump/MDSG +humpback/MDS +humph/DG +humphs +humus/M +hunch/MDSG +hunchback/SMD +hundred/SMH +hundredfold +hundredth/M +hundredths +hundredweight/SM +hung +hunger/SMDG +hungover +hungrily +hungriness/M +hungry/PRT +hunk/MRSZ +hunker/DG +hunky/RT +hunt/MDRSZG +hunter/M +hunting/M +huntress/MS +huntsman/M +huntsmen +hurdle/DRSMZG +hurdler/M +hurdling/M +hurl/MDRSZG +hurler/M +hurling/M +hurrah/GMD +hurrahs +hurray +hurricane/MS +hurried/UY +hurry/DSMG +hurt/MSG +hurtful/YP +hurtfulness/M +hurtle/DSG +husband/GMDS +husbandman/M +husbandmen +husbandry/M +hush/MDSG +husk/MDRSZG +husker/M +huskily +huskiness/M +husky/PRSMT +hussar/SM +hussy/SM +hustings/M +hustle/DRSMZG +hustler/M +hut/SM +hutch/MS +huzza/GSMD +huzzah/MDG +huzzahs +hwy +hyacinth/M +hyacinths +hybrid/SM +hybridism/M +hybridization/M +hybridize/DSG +hydra/SM +hydrangea/SM +hydrant/MS +hydrate's +hydrate/CGNDS +hydration/CM +hydraulic/S +hydraulically +hydraulics/M +hydro/M +hydrocarbon/MS +hydrocephalus/M +hydrodynamic/S +hydrodynamics/M +hydroelectric +hydroelectrically +hydroelectricity/M +hydrofoil/MS +hydrogen/M +hydrogenate/CGDS +hydrogenation/M +hydrogenous +hydrologist/MS +hydrology/M +hydrolyses +hydrolysis/M +hydrolyze/DSG +hydrometer/SM +hydrometry/M +hydrophobia/M +hydrophobic +hydrophone/SM +hydroplane/GDSM +hydroponic/S +hydroponically +hydroponics/M +hydrosphere/M +hydrotherapy/M +hydrous +hydroxide/SM +hyena/SM +hygiene/M +hygienic/U +hygienically +hygienist/MS +hygrometer/SM +hying +hymen/SM +hymeneal +hymn/MDSG +hymnal/MS +hymnbook/SM +hype/MGDRS +hyperactive +hyperactivity/M +hyperbola/SM +hyperbole/M +hyperbolic +hypercritical/Y +hyperglycemia/M +hyperinflation +hyperlink/GSMD +hypermarket/S +hypermedia/M +hyperparathyroidism +hypersensitive/P +hypersensitiveness/M +hypersensitivity/SM +hyperspace/S +hypertension/M +hypertensive/SM +hypertext/M +hyperthyroid/M +hyperthyroidism/M +hypertrophy/DSMG +hyperventilate/GNDS +hyperventilation/M +hyphen/MDSG +hyphenate/XDSMGN +hyphenation/M +hypnoses +hypnosis/M +hypnotherapist/S +hypnotherapy/M +hypnotic/SM +hypnotically +hypnotism/M +hypnotist/MS +hypnotize/GDS +hypo/MS +hypoallergenic +hypochondria/M +hypochondriac/SM +hypocrisy/SM +hypocrite/MS +hypocritical/Y +hypodermic/MS +hypoglycemia/M +hypoglycemic/SM +hypotenuse/MS +hypothalami +hypothalamus/M +hypothermia/M +hypotheses +hypothesis/M +hypothesize/DSG +hypothetical/Y +hypothyroid/M +hypothyroidism/M +hyssop/M +hysterectomy/SM +hysteresis +hysteria/M +hysteric/SM +hysterical/Y +hysterics/M +i/US +iPad/M +iPhone/M +iPod/M +iTunes/M +iamb/MS +iambi +iambic/SM +iambus/MS +ibex/MS +ibid +ibidem +ibis/MS +ibuprofen/M +ice's +ice/CDSG +iceberg/SM +iceboat/SM +icebound +icebox/MS +icebreaker/SM +icecap/SM +iceman/M +icemen +ichthyologist/MS +ichthyology/M +icicle/SM +icily +iciness/M +icing/SM +icky/RT +icon/MS +iconic +iconoclasm/M +iconoclast/SM +iconoclastic +iconography/M +ictus/M +icy/TPR +id/SMY +idea/MS +ideal/SMY +idealism/M +idealist/SM +idealistic +idealistically +idealization/MS +idealize/DSG +idem +idempotent +identical/Y +identifiable/U +identification/M +identified/U +identify/ZGNDRSX +identikit/S +identity/SM +ideogram/SM +ideograph/M +ideographs +ideological/Y +ideologist/SM +ideologue/MS +ideology/SM +ides/M +idiocy/SM +idiom/SM +idiomatic/U +idiomatically +idiopathic +idiosyncrasy/SM +idiosyncratic +idiosyncratically +idiot/SM +idiotic +idiotically +idle/MZTGDRSP +idleness/M +idler/M +idol/MS +idolater/SM +idolatress/MS +idolatrous +idolatry/M +idolization/M +idolize/GDS +idyll/SM +idyllic +idyllically +if/SM +iffiness/M +iffy/RTP +igloo/SM +igneous +ignitable +ignite/AGDS +ignition/MS +ignoble +ignobly +ignominious/Y +ignominy/SM +ignoramus/MS +ignorance/M +ignorant/Y +ignore/GDS +iguana/MS +ii +iii +ilea +ileitis/M +ileum/M +ilia +ilium/M +ilk/SM +ill/SMP +illegal/MYS +illegality/SM +illegibility/M +illegible +illegibly +illegitimacy/M +illegitimate/Y +illiberal/Y +illiberality/M +illicit/YP +illicitness/M +illimitable +illiteracy/M +illiterate/MYS +illness/MS +illogical/Y +illogicality/M +illuminate/GNXDS +illuminating/Y +illumination/M +illumine/DSBG +illus/V +illusion/EMS +illusionist/SM +illusory +illustrate/GNVXDS +illustration/M +illustrative/Y +illustrator/SM +illustrious/PY +illustriousness/M +image/DSMG +imagery/M +imaginable/U +imaginably/U +imaginal +imaginary +imagination/MS +imaginative/UY +imagine/DSBJG +imago/M +imagoes +imam/MS +imbalance/DSM +imbecile/MS +imbecilic +imbecility/SM +imbibe/ZGDRS +imbiber/M +imbrication/M +imbroglio/SM +imbue/DSG +imitable/I +imitate/DSGNVX +imitation/M +imitative/PY +imitativeness/M +imitator/SM +immaculate/PY +immaculateness/M +immanence/M +immanency/M +immanent/Y +immaterial/YP +immateriality/M +immaterialness/M +immature/Y +immaturity/M +immeasurable +immeasurably +immediacies/M +immediacy/SM +immediate/PY +immediateness/M +immemorial/Y +immense/Y +immensity/SM +immerse/XDSGNV +immersible +immersion/M +immigrant/SM +immigrate/DSGN +immigration/M +imminence/M +imminent/Y +immobile +immobility/M +immobilization/M +immobilize/ZGDRS +immoderate/Y +immodest/Y +immodesty/M +immolate/DSGN +immolation/M +immoral/Y +immorality/SM +immortal/MYS +immortality/M +immortalize/DSG +immovability/M +immovable +immovably +immune +immunity/M +immunization/SM +immunize/GDS +immunodeficiency/M +immunodeficient +immunoglobulin/S +immunologic +immunological +immunologist/MS +immunology/M +immure/DSG +immutability/M +immutable +immutably +imp/SMR +impact/SMDG +impair/SDGL +impaired/U +impairment/MS +impala/SM +impale/DSGL +impalement/M +impalpable +impalpably +impanel/SDG +impart/SDG +impartial/Y +impartiality/M +impassably +impasse/BSMV +impassibility/M +impassible +impassibly +impassioned +impassive/YP +impassiveness/M +impassivity/M +impasto/M +impatience/MS +impatiens/M +impatient/Y +impeach/ZGBLDRS +impeachable/U +impeacher/M +impeachment/SM +impeccability/M +impeccable +impeccably +impecunious/PY +impecuniousness/M +impedance/M +impede/DSG +impeded/U +impediment/SM +impedimenta/M +impel/S +impelled +impeller/MS +impelling +impend/SDG +impenetrability/M +impenetrable +impenetrably +impenitence/M +impenitent/Y +imperative/SMY +imperceptibility/M +imperceptible +imperceptibly +imperceptive +imperf +imperfect/SMYP +imperfection/MS +imperfectness/M +imperial/MYS +imperialism/M +imperialist/SM +imperialistic +imperialistically +imperil/GSLD +imperilment/M +imperious/PY +imperiousness/M +imperishable +imperishably +impermanence/M +impermanent/Y +impermeability/M +impermeable +impermeably +impermissible +impersonal/Y +impersonate/GNXDS +impersonation/M +impersonator/SM +impertinence/MS +impertinent/Y +imperturbability/M +imperturbable +imperturbably +impervious/Y +impetigo/M +impetuosity/M +impetuous/YP +impetuousness/M +impetus/MS +impiety/SM +impinge/LDSG +impingement/M +impious/PY +impiousness/M +impish/YP +impishness/M +implacability/M +implacable +implacably +implant/BSGMD +implantation/M +implausibility/SM +implausible +implausibly +implement/GBMDRS +implementable/U +implementation/SM +implemented/U +implicate/DSG +implication/M +implicit/PY +implicitness/M +implode/DSG +implore/DSG +imploring/Y +implosion/MS +implosive +imply/XDSGN +impolite/YP +impoliteness/MS +impolitic +imponderable/MS +import/ZGBSMDR +importance/M +important/Y +importation/MS +importer/M +importunate/Y +importune/GDS +importunity/M +impose/ADSG +imposer/MS +imposing/U +imposingly +imposition/MS +impossibility/SM +impossible/S +impossibly +impost/ZSMR +imposter/M +impostor/SM +imposture/MS +impotence/M +impotency/M +impotent/Y +impound/DGS +impoverish/DSLG +impoverishment/M +impracticability +impracticable +impracticably +impractical/Y +impracticality/M +imprecate/DSXGN +imprecation/M +imprecise/PYN +impreciseness/M +imprecision/M +impregnability/M +impregnable +impregnably +impregnate/GNDS +impregnation/M +impresario/SM +impress/MDSGV +impressed/U +impressibility/M +impressible +impression/BSM +impressionability/M +impressionism/M +impressionist/SM +impressionistic +impressive/PY +impressiveness/M +imprimatur/SM +imprint/MDRZGS +imprinter/M +imprison/SDLG +imprisonment/SM +improbability/SM +improbable +improbably +impromptu/SM +improper/Y +impropriety/SM +improve/GBDSL +improved/U +improvement/MS +improvidence/M +improvident/Y +improvisation/SM +improvisational +improvise/ZGDRS +improviser/M +improvisor/SM +imprudence/M +imprudent/Y +impudence/M +impudent/Y +impugn/ZGSDR +impugner/M +impulse/MGNVDS +impulsion/M +impulsive/PY +impulsiveness/M +impunity/M +impure/RYT +impurity/SM +imputation/SM +impute/BDSG +in/ASM +inaccuracy/S +inaction/M +inadequacy/S +inadvertence/M +inadvertent/Y +inalienability/M +inalienably +inamorata/SM +inane/RYT +inanimate/PY +inanimateness/M +inanity/SM +inappropriate/Y +inarticulate/Y +inasmuch +inaudible +inaugural/SM +inaugurate/XGNDS +inauguration/M +inboard/MS +inbound +inbox/MS +inbreed/S +inc/TGD +incalculably +incandescence/M +incandescent/Y +incantation/SM +incapacitate/GDS +incarcerate/XDSGN +incarceration/M +incarnadine/DSG +incarnate/AXGNDS +incarnation/AM +incendiary/SM +incense/MGDS +incentive's +incentive/ES +inception/SM +incessant/Y +incest/M +incestuous/PY +incestuousness/M +inch/MDSG +inchoate +inchworm/SM +incidence/SM +incident/SM +incidental/MYS +incinerate/DSGN +incineration/M +incinerator/MS +incipience/M +incipient/Y +incise/XGNVDS +incision/M +incisive/PY +incisiveness/M +incisor/MS +incitement/MS +inciter/MS +incl +inclement +inclination/EM +inclinations +incline's +incline/EGDS +include/GDS +inclusion/MS +inclusive/YP +inclusiveness/M +incognito/MS +incombustible +incommode/GD +incommodious +incommunicado +incompatibility/S +incompetent/MS +incomplete/Y +inconceivability/M +incongruous/PY +incongruousness/M +inconsolably +inconstant/Y +incontestability/M +incontestably +incontinent +incontrovertibly +inconvenience/GD +incorporate/ADSGN +incorporated/U +incorporation/AM +incorporeal +incorrect/Y +incorrigibility/M +incorrigible +incorrigibly +incorruptibly +increasing/Y +increment/SMD +incremental/Y +incrementalism +incrementalist/SM +incriminate/GNDS +incrimination/M +incriminatory +incrustation/SM +incubate/GNDS +incubation/M +incubator/SM +incubus/MS +inculcate/DSGN +inculcation/M +inculpate/DSG +incumbency/SM +incumbent/SM +incunabula +incunabulum/M +incur/SB +incurable/MS +incurably +incurious +incurred +incurring +incursion/MS +ind +indebted/P +indebtedness/M +indeed +indefatigable +indefatigably +indefeasible +indefeasibly +indefinably +indelible +indelibly +indemnification/M +indemnify/GDSXN +indemnity/SM +indentation/MS +indention/M +indenture/DG +indescribably +indestructibly +indeterminably +indeterminacy/M +indeterminate/Y +index/ZGMDRS +indexation/SM +indexer/M +indicate/XDSGNV +indication/M +indicative/SMY +indicator/MS +indict/GDSBL +indictment/SM +indie/S +indigence/M +indigenous +indigent/SMY +indignant/Y +indignation/M +indigo/M +indirect/Y +indiscipline +indiscreet/Y +indiscretion/S +indiscriminate/Y +indispensability/M +indispensable/MS +indispensably +indissolubility +indissolubly +indistinguishably +indite/GDS +indium/M +individual/MYS +individualism/M +individualist/MS +individualistic +individualistically +individuality/M +individualization/M +individualize/GDS +individuate/DSGN +individuation/M +indivisibly +indoctrinate/GNDS +indoctrination/M +indolence/M +indolent/Y +indomitable +indomitably +indubitable +indubitably +induce/DRSZGL +inducement/SM +inducer/M +induct/DGV +inductance/M +inductee/SM +induction/MS +inductive/Y +indue/DG +indulge/DSG +indulgence/SM +indulgent/Y +industrial/Y +industrialism/M +industrialist/SM +industrialization/M +industrialize/DSG +industrious/YP +industriousness/M +industry/SM +indwell/SG +inebriate/MGNDS +inebriation/M +inedible +ineffability/M +ineffable +ineffably +inelastic +ineligible/MS +ineligibly +ineluctable +ineluctably +inept/YP +ineptitude/M +ineptness/M +inequality/S +inert/YP +inertia/M +inertial +inertness/M +inescapable +inescapably +inestimably +inevitability/M +inevitable/M +inevitably +inexact/Y +inexhaustibly +inexorability +inexorable +inexorably +inexpedient +inexpert/Y +inexpiable +inexplicably +inexpressibly +inexpressive +inextricably +inf/ZT +infallible +infamy/SM +infancy/M +infant/MS +infanticide/MS +infantile +infantry/SM +infantryman/M +infantrymen +infarct/MS +infarction/M +infatuate/DSXGN +infatuation/M +infect/AESDG +infected/U +infection/ASM +infectious/PY +infectiousness/M +infelicitous +inference/SM +inferential +inferior/MS +inferiority/M +infernal/Y +inferno/MS +inferred +inferring +infest/GDS +infestation/MS +infidel/MS +infidelity/S +infiltrator/SM +infinite/MV +infinitesimal/SMY +infinitival +infinitive/MS +infinitude/M +infinity/SM +infirm +infirmary/SM +infirmity/SM +infix +inflame/DSG +inflammable +inflammation/SM +inflammatory +inflatable/SM +inflate/DSGNB +inflation/EM +inflationary +inflect/SDG +inflection/MS +inflectional +inflict/SDGV +infliction/M +inflight +inflow/SM +influence/MGDS +influenced/U +influential/Y +influenza/M +info/M +infomercial/SM +inform/Z +informal/Y +informant/SM +information/EM +informational +informative/PY +informativeness/M +informed/U +infotainment/M +infra +infrared/M +infrasonic +infrastructural +infrastructure/SM +infrequence/M +infrequent/Y +infringement/MS +infuriate/GDS +infuriating/Y +infuser/SM +ingenious/PY +ingeniousness/M +ingenue/SM +ingenuity/M +ingenuous/EY +ingenuousness/M +ingest/SDG +ingestion/M +inglenook/SM +ingot/SM +ingrain/G +ingrate/SM +ingratiate/GNDS +ingratiating/Y +ingratiation/M +ingredient/MS +ingress/MS +inguinal +ingénue/SM +inhabit/DG +inhabitable/U +inhabitant/SM +inhabited/U +inhalant/SM +inhalation/MS +inhalator/MS +inhaler/SM +inharmonious +inhere/DSG +inherent/Y +inherit/EGSD +inheritance/EM +inheritances +inheritor/SM +inhibit/GSD +inhibition/SM +inhibitor/SM +inhibitory +inhuman/Y +inhumane/Y +inimical/Y +inimitably +iniquitous/Y +iniquity/SM +initial/SGMDY +initialism +initialization +initialize/DSG +initialized/AU +initiate/XMGNVDS +initiated/U +initiation/M +initiative/SM +initiator/MS +initiatory +inject/SDG +injection/SM +injector/SM +injure/DRSZG +injured/U +injurer/M +injurious +ink/MD +inkblot/SM +inkiness/M +inkling/SM +inkstand/SM +inkwell/MS +inky/RTP +inland/M +inline +inmate/SM +inmost +inn/SGMRJ +innards/M +innate/PY +innateness/M +innermost +innersole/SM +innerspring +innervate/GNDS +innervation/M +inning/M +innit +innkeeper/MS +innocence/M +innocent/MYS +innocuous/PY +innocuousness/M +innovate/XDSGNV +innovation/M +innovator/MS +innovatory +innuendo/SM +innuendoes +innumerably +innumerate +inoculate/AGDS +inoculation/MS +inoperative +inordinate/Y +inorganic +inquire/ZGDR +inquirer/M +inquiring/Y +inquiry/SM +inquisition/MS +inquisitional +inquisitive/YP +inquisitiveness/M +inquisitor/SM +inquisitorial +inrush/MS +insane/T +insatiability/M +insatiably +inscribe/ZGDR +inscriber/M +inscription/MS +inscrutability/M +inscrutable/P +inscrutableness/M +inscrutably +inseam/SM +insecticidal +insecticide/MS +insectivore/MS +insectivorous +insecure/Y +inseminate/DSGN +insemination/M +insensate +insensible +insensitive/Y +inseparable/MS +insert's +insert/AGSD +insertion/AM +insertions +insetting +inshore +inside/RSMZ +insider/M +insidious/YP +insidiousness/M +insight/MS +insightful +insignia/SM +insinuate/GNVDSX +insinuation/M +insinuator/SM +insipid/PY +insipidity/M +insist/SGD +insistence/M +insistent/Y +insisting/Y +insofar +insole/SM +insolence/M +insolent/Y +insoluble +insolubly +insolvency/S +insomnia/M +insomniac/SM +insomuch +insouciance/M +insouciant +inspect/AGDS +inspection/SM +inspector/MS +inspectorate/MS +inspiration/MS +inspirational +inspired/U +inspiring/U +inst +instability/S +installation/MS +installer/UMS +installment/SM +instance/GD +instant/MRYS +instantaneous/Y +instantiate/DSG +instar +instate/AGDS +instead +instigate/DSGN +instigation/M +instigator/MS +instillation/M +instinct/VMS +instinctive/Y +instinctual +institute/XMZGNDRS +instituter/M +institution/M +institutional/Y +institutionalization/M +institutionalize/DSG +institutor/MS +instr +instruct/SDGV +instructed/U +instruction/MS +instructional +instructive/Y +instructor/MS +instrument/MDSG +instrumental/MYS +instrumentalist/SM +instrumentality/M +instrumentation/M +insubordinate +insufferable +insufferably +insular +insularity/M +insulate/GNDS +insulation/M +insulator/MS +insulin/M +insult/SMDG +insulting/Y +insuperable +insuperably +insurance/SM +insure/DRSZGB +insured/SM +insurer/M +insurgence/SM +insurgency/SM +insurgent/MS +insurmountably +insurrection/SM +insurrectionist/SM +int +intact +intaglio/MS +integer/MS +integral/SMY +integrate/AEVNGSD +integration/EAM +integrator +integrity/M +integument/SM +intellect/MS +intellectual/MYS +intellectualism/M +intellectualize/GDS +intelligence/M +intelligent/Y +intelligentsia/M +intelligibility/M +intelligible/U +intelligibly/U +intended/SM +intense/YTVR +intensification/M +intensifier/M +intensify/DRSZGN +intensity/S +intensive/MYPS +intensiveness/M +intent/SMYP +intention/MS +intentional/UY +intentness/M +inter/ESL +interact/SGVD +interaction/SM +interactive/Y +interactivity +interbred +interbreed/GS +intercede/GDS +intercept/GMDS +interception/MS +interceptor/SM +intercession/SM +intercessor/MS +intercessory +interchange/DSMG +interchangeability +interchangeable +interchangeably +intercity +intercollegiate +intercom/SM +intercommunicate/DSGN +intercommunication/M +interconnect/GDS +interconnection/SM +intercontinental +intercourse/M +intercultural +interdenominational +interdepartmental +interdependence/M +interdependent/Y +interdict/GMDS +interdiction/M +interdisciplinary +interest/ESMD +interested/U +interesting/Y +interface/MGDS +interfaith +interfere/GDS +interference/M +interferon/M +interfile/GDS +intergalactic +intergovernmental +interim/M +interior/SM +interj +interject/GDS +interjection/SM +interlace/GDS +interlard/DGS +interleave/DSG +interleukin/M +interline/GDSJ +interlinear +interlining/M +interlink/DSG +interlock/GMDS +interlocutor/SM +interlocutory +interlope/ZGDRS +interloper/M +interlude/MGDS +intermarriage/SM +intermarry/GDS +intermediary/SM +intermediate/MYS +interment/EM +interments +intermezzi +intermezzo/MS +interminably +intermingle/DSG +intermission/SM +intermittent/Y +intermix/GDS +internal/SY +internalization/M +internalize/GDS +international/SMY +internationalism/M +internationalist/SM +internationalization +internationalize/DSG +interne/GDL +internecine +internee/SM +interneship/S +internet +internist/MS +internment/M +internship/MS +interoffice +interpenetrate/DSGN +interpersonal +interplanetary +interplay/M +interpolate/XDSGN +interpolation/M +interpose/GDS +interposition/M +interpret/AGVDS +interpretation/AMS +interpretative +interpreted/U +interpreter/MS +interracial +interred/E +interregnum/SM +interrelate/XDSGN +interrelation/M +interrelationship/MS +interring/E +interrogate/DSGNVX +interrogation/M +interrogative/MYS +interrogator/SM +interrogatory/SM +interrupt/ZGMDRS +interrupter/M +interruption/MS +interscholastic +intersect/GDS +intersection/SM +intersession/SM +intersex +intersperse/GNDS +interspersion/M +interstate/MS +interstellar +interstice/MS +interstitial +intertwine/GDS +interurban +interval/SM +intervene/GDS +intervention/SM +interventionism/M +interventionist/SM +interview/ZGMDRS +interviewee/MS +interviewer/M +intervocalic +interwar +interweave/GS +interwove +interwoven +intestacy/M +intestate +intestinal +intestine/MS +intimacy/SM +intimate/MYGNDSX +intimation/M +intimidate/GNDS +intimidating/Y +intimidation/M +intonation/SM +intoxicant/SM +intoxicate/DSGN +intoxication/M +intracranial +intramural +intramuscular +intranet/MS +intransigence/M +intransigent/MYS +intrastate +intrauterine +intravenous/MSY +intrepid/Y +intrepidity/M +intricacy/SM +intricate/Y +intrigue/DRSMZG +intriguer/M +intriguing/Y +intrinsic +intrinsically +intro/SM +introduce/AGDS +introduction/AM +introductions +introductory +introit/SM +introspect/GVDS +introspection/M +introspective/Y +introversion/M +introvert/MDS +intrude/DRSZG +intruder/M +intrusion/SM +intrusive/YP +intrusiveness/M +intuit/SDGV +intuition/S +intuitive/PY +intuitiveness/M +inundate/XDSGN +inundation/M +inure/DSG +invade/DRSZG +invader/M +invalid/GMDYS +invalidism/M +invaluable +invaluably +invariant +invasion/MS +invasive +invective/M +inveigh/GD +inveighs +inveigle/ZGDRS +inveigler/M +invent/ASGVD +invention/AMS +inventive/PY +inventiveness/M +inventor/MS +inventory/DSMG +inverse/SMY +invert/SMDG +invest/ASDGL +investigate/GNVDSX +investigation/M +investigator/SM +investigatory +investiture/MS +investment/AEM +investor/SM +inveteracy/M +inveterate +invidious/YP +invidiousness/M +invigilate/GNDS +invigilator/S +invigorate/ADSG +invigorating/Y +invigoration/M +invincibility/M +invincibly +inviolability/M +inviolably +inviolate +invitation/SM +invitational/SM +invite/DSMG +invited/U +invitee/SM +inviting/Y +invoke/DSG +involuntariness/M +involuntary/P +involution/M +involve/LDSG +involvement/SM +inward/SY +ioctl +iodide/SM +iodine/M +iodize/DSG +ion/USM +ionic +ionization/UM +ionize/UDSG +ionizer/MS +ionosphere/MS +ionospheric +iota/MS +ipecac/SM +irascibility/M +irascible +irascibly +irate/YP +irateness/M +ire/M +ireful +irenic +irides +iridescence/M +iridescent/Y +iridium/M +iris/MS +irk/SGD +irksome/YP +irksomeness/M +iron/MDSG +ironclad/MS +ironic +ironical/Y +ironing/M +ironmonger/S +ironmongery +ironstone/M +ironware/M +ironwood/MS +ironwork/M +irony/SM +irradiate/DSGN +irradiation/M +irrational/SMY +irrationality/M +irreclaimable +irreconcilability/M +irreconcilable +irreconcilably +irrecoverable +irrecoverably +irredeemable +irredeemably +irreducible +irreducibly +irrefutable +irrefutably +irregardless +irregular/MYS +irregularity/SM +irrelevance/MS +irrelevancy/MS +irrelevant/Y +irreligion +irreligious +irremediable +irremediably +irremovable +irreparable +irreparably +irreplaceable +irrepressible +irrepressibly +irreproachable +irreproachably +irresistible +irresistibly +irresolute/PYN +irresoluteness/M +irresolution/M +irrespective +irresponsibility/M +irresponsible +irresponsibly +irretrievable +irretrievably +irreverence/M +irreverent/Y +irreversible +irreversibly +irrevocable +irrevocably +irrigable +irrigate/DSGN +irrigation/M +irritability/M +irritable +irritably +irritant/SM +irritate/DSXGN +irritating/Y +irritation/M +irrupt/DGVS +irruption/SM +ischemia +ischemic +isinglass/M +isl +island/SZMR +islander/M +isle/MS +islet/SM +ism/CM +isms +isn't +isobar/MS +isobaric +isolate/DSMGN +isolation/M +isolationism/M +isolationist/SM +isomer/MS +isomeric +isomerism/M +isometric/S +isometrically +isometrics/M +isomorphic +isosceles +isotherm/SM +isotope/SM +isotopic +isotropic +issuance/M +issue/ADSMG +issuer/MS +isthmian +isthmus/MS +it'd +it'll +it/USM +ital +italic/SM +italicization/M +italicize/GDS +italics/M +itch/MDSG +itchiness/M +itchy/RPT +item/MS +itemization/M +itemize/GDS +iterate/AXGNVDS +iteration/AM +iterator/S +itinerant/SM +itinerary/SM +itself +iv/U +ivory/SM +ivy/DSM +ix +j/F +jab/SM +jabbed +jabber/SMDRZG +jabberer/M +jabbing +jabot/SM +jacaranda/MS +jack/MDGS +jackal/SM +jackass/MS +jackboot/SMD +jackdaw/MS +jacket/SMD +jackhammer/MS +jackknife/MGDS +jackknives +jackpot/MS +jackrabbit/MS +jackstraw/MS +jacquard/M +jade/MGDS +jaded/PY +jadedness/M +jadeite/M +jag/SM +jagged/TPRY +jaggedness/M +jaggies +jaguar/SM +jail/MDRZGS +jailbird/SM +jailbreak/SM +jailer/M +jailhouse/S +jalapeno/MS +jalapeño/MS +jalopy/SM +jalousie/MS +jam/SM +jamb/MS +jambalaya/M +jamboree/MS +jammed +jamming +jammy/RT +jangle/DRSMZG +jangler/M +janitor/SM +janitorial +japan/SM +japanned +japanning +jape/MGDS +jar/SM +jardiniere/SM +jardinière/SM +jarful/MS +jargon/M +jarred +jarring/Y +jasmine/SM +jasper/M +jato/MS +jaundice/DSMG +jaunt/SGMD +jauntily +jauntiness/M +jaunty/RPT +java/M +javelin/SM +jaw/SGMD +jawbone/DSMG +jawbreaker/MS +jawline/S +jay/SM +jaybird/SM +jaywalk/DRSZG +jaywalker/M +jaywalking/M +jazz/MDSG +jazzy/TR +jct +jealous/Y +jealousy/SM +jean/MS +jeans/M +jeep/MS +jeer/MDSG +jeering/MY +jeez +jejuna +jejune +jejunum/M +jell/DSG +jello/SM +jelly/GDSM +jellybean/MS +jellyfish/MS +jellylike +jellyroll/SM +jemmy/GDS +jennet/MS +jenny/SM +jeopardize/GDS +jeopardy/M +jeremiad/MS +jerk/MDSG +jerkily +jerkin/MS +jerkiness/M +jerkwater +jerky/TRMP +jeroboam/S +jerrican/S +jerrybuilt +jerrycan/S +jersey/MS +jest/MDRSZG +jester/M +jesting/Y +jet/SM +jetliner/SM +jetport/MS +jetsam/M +jetted +jetting +jettison/MDSG +jetty/SM +jew +jewel/SZGMDR +jeweler/M +jewelry/SM +jg +jib/SGMD +jibbed +jibbing +jibe/MS +jiff/MS +jiffy/SM +jig's +jig/AS +jigged/A +jigger's +jigger/ASDG +jigging/A +jiggle/DSMG +jiggly +jigsaw/SMDG +jihad/SM +jihadist/SM +jilt/MDSG +jimmy/DSMG +jimsonweed/M +jingle/DSMG +jingly +jingoism/M +jingoist/SM +jingoistic +jink/DSG +jinn/MS +jinni/M +jinricksha/SM +jinrikisha/SM +jinx/MDSG +jitney/SM +jitterbug/MS +jitterbugged +jitterbugger/M +jitterbugging +jitters/M +jittery/RT +jive/MGDS +job/SM +jobbed +jobber/SM +jobbing +jobholder/MS +jobless/P +joblessness/M +jobshare/S +jobsworth +jobsworths +jock/MS +jockey/SGMD +jockstrap/MS +jocose/PY +jocoseness/M +jocosity/M +jocular/Y +jocularity/M +jocund/Y +jocundity/M +jodhpurs/M +joey/S +jog/SM +jogged +jogger/SM +jogging/M +joggle/DSMG +john/MS +johnny/SM +johnnycake/MS +join's +join/AFDSG +joiner/FMS +joinery/M +joint's +joint/EGSD +jointly/F +joist/SM +jojoba +joke/MZGDRS +joker/M +jokey +jokier +jokiest +joking/Y +jollification/SM +jollily +jolliness/M +jollity/M +jolly/TGPDRSM +jolt/MDRSZG +jolter/M +jonquil/SM +josh/MDRSZG +josher/M +jostle/MGDS +jot/SM +jotted +jotter/MS +jotting/MS +joule/SM +jounce/MGDS +jouncy +journal/MS +journalese/M +journalism/M +journalist/SM +journalistic +journey/ZGMDRS +journeyer/M +journeyman/M +journeymen +journo/S +joust/SZGMDR +jouster/M +jousting/M +jovial/Y +joviality/M +jowl/MS +jowly/TR +joy/SGMD +joyful/YP +joyfuller +joyfullest +joyfulness/M +joyless/PY +joylessness/M +joyous/YP +joyousness/M +joyridden +joyride/RSMZG +joyrider/M +joyriding/M +joyrode +joystick/SM +jr +jubilant/Y +jubilation/M +jubilee/SM +judder/GDS +judge's +judge/ADSG +judgemental +judgeship/M +judgment/SM +judgmental/Y +judicatory/SM +judicature/M +judicial/Y +judiciary/SM +judicious/IYP +judiciousness/IM +judo/M +jug/SM +jugful/MS +jugged +juggernaut/SM +jugging +juggle/MZGDRS +juggler/M +jugglery/M +jugular/SM +juice/DRSMZG +juicer/M +juicily +juiciness/M +juicy/PTR +jujitsu/M +jujube/MS +jukebox/MS +julep/SM +julienne +jumble/MGDS +jumbo/SM +jump/MDRSZG +jumper/M +jumpily +jumpiness/M +jumpsuit/MS +jumpy/TRP +jun +junco/SM +junction/FISM +juncture/FMS +jungle/MS +junior/MS +juniper/SM +junk/MDRSZG +junker/M +junket/MDRSZG +junketeer/MS +junketer/M +junkie/M +junky/TRSM +junkyard/MS +junta/SM +juridic +juridical/Y +jurisdiction/SM +jurisdictional +jurisprudence/M +jurist/MS +juristic +juror/FSM +jury/ISM +juryman/M +jurymen +jurywoman/M +jurywomen +just/RYPT +justice/IMS +justifiable/U +justifiably/U +justification/M +justified/U +justify/XGDSN +justness/M +jut/SM +jute/M +jutted +jutting +juvenile/SM +juxtapose/DSG +juxtaposition/SM +k/IFGS +kHz +kW +kWh +kabbala +kabbalah +kabob/SM +kaboom +kabuki/M +kaddish/MS +kaffeeklatch/MS +kaffeeklatsch/MS +kahuna/S +kaiser/MS +kale/M +kaleidoscope/MS +kaleidoscopic +kaleidoscopically +kamikaze/MS +kana +kangaroo/MS +kanji +kaolin/M +kapok/M +kappa/SM +kaput +karakul/M +karaoke/MS +karat/SM +karate/M +karma/M +karmic +kart/MS +katakana +katydid/SM +kayak/SMDG +kayaking/M +kayo/MDSG +kazoo/SM +kc +kebab/SM +kebob/SM +kedgeree +keel/MDSG +keelhaul/DGS +keen/MDRYSTGP +keenness/M +keep/MRSZG +keeper/M +keeping/M +keepsake/MS +keg/SM +kelp/M +kelvin/SM +ken/SM +kenned +kennel/SGMD +kenning +keno/M +kepi/MS +kept +keratin/M +keratitis +kerbside +kerchief/SM +kerfuffle/S +kernel/SM +kerosene/M +kestrel/MS +ketch/MS +ketchup/M +kettle/SM +kettledrum/SM +key/SGMD +keybinding/S +keyboard/ZGSMDR +keyboarder/M +keyboardist/SM +keyhole/MS +keynote/MZGDRS +keynoter/M +keypad/SM +keypunch/ZGMDRS +keypuncher/M +keystone/MS +keystroke/SM +keyword/MS +kg +khaki/SM +khan/MS +kibble/DSMG +kibbutz/MS +kibbutzim +kibitz/ZGDRS +kibitzer/M +kibosh/M +kick/MDRSZG +kickback/SM +kickball/M +kickboxing +kicker/M +kickoff/MS +kickstand/MS +kicky/RT +kid/SM +kidded +kidder/SM +kiddie/SM +kidding +kiddish +kiddo/SM +kidnap/S +kidnapped +kidnapper/MS +kidnapping/MS +kidney/SM +kidskin/M +kielbasa/MS +kielbasi +kike/S +kill/JMDRSZG +killdeer/SM +killer/M +killing/M +killjoy/SM +kiln/MDSG +kilo/MS +kilobyte/SM +kilocycle/SM +kilogram/SM +kilohertz/M +kiloliter/MS +kilometer/MS +kiloton/SM +kilowatt/SM +kilt/MDRS +kilter/M +kimono/MS +kin/M +kinase +kind's +kind/UPRYT +kinda +kindergarten/MS +kindergartner/SM +kindergärtner/SM +kindhearted/PY +kindheartedness/M +kindle/AGDS +kindliness/M +kindling/M +kindly/URT +kindness/UM +kindnesses +kindred/M +kinds +kine/S +kinematic/S +kinematics/M +kinetic/S +kinetically +kinetics/M +kinfolk/SM +kinfolks/M +king/MYS +kingdom/SM +kingfisher/SM +kingly/RT +kingmaker/S +kingpin/SM +kingship/M +kink/MDSG +kinkily +kinkiness/M +kinky/TPR +kinsfolk/M +kinship/M +kinsman/M +kinsmen +kinswoman/M +kinswomen +kiosk/SM +kip/SM +kipped +kipper/MDGS +kipping +kirsch/MS +kismet/M +kiss/MDRSBZG +kisser/M +kissoff/SM +kissogram/S +kit/SGMD +kitbag/MS +kitchen/SM +kitchenette/MS +kitchenware/M +kite/MS +kith/M +kitsch/M +kitschy +kitted +kitten/MS +kittenish +kitting +kitty/SM +kiwi/MS +kiwifruit/MS +kl +klaxon/S +kleptocracy +kleptomania/M +kleptomaniac/SM +kludge/GDS +kluge/DS +klutz/MS +klutziness/M +klutzy/TRP +km +kn +knack/SZMR +knacker/GD +knackwurst/MS +knapsack/MS +knave/SM +knavery/M +knavish/Y +knead/SZGDR +kneader/M +knee/MDS +kneecap/SM +kneecapped +kneecapping +kneeing +kneel/SG +knell/SGMD +knelt +knew +knicker/S +knickerbockers/M +knickers/M +knickknack/MS +knife/DSMG +knight/MDYSG +knighthood/MS +knightliness/M +knish/MS +knit/MS +knitted +knitter/SM +knitting/M +knitwear/M +knives +knob/MS +knobbly +knobby/TR +knock/SZGMDR +knockabout +knockdown/SM +knocker/M +knockoff/SM +knockout/SM +knockwurst/SM +knoll/SM +knot/MS +knothole/SM +knotted +knotting +knotty/TR +know/SB +knowing/UYS +knowledge/M +knowledgeable +knowledgeably +known +knuckle/DSMG +knuckleduster/S +knucklehead/MS +knurl/SGMD +koala/SM +koan/S +kohl +kohlrabi/M +kohlrabies +kola/MS +kook/MS +kookaburra/SM +kookiness/M +kooky/TPR +kopeck/MS +kopek/SM +korma +kosher/DSG +kowtow/GMDS +kph +kraal/SM +kraut/SM! +krill/M +krona/M +krone/RM +kronor +kronur +krypton/M +króna/M +krónur +kt +kuchen/SM +kudos/M +kudzu/SM +kumquat/MS +kvetch/ZGMDRS +kvetcher/M +kw +l/SDXTGJ +la/M +lab/SM +label's +label/ASDG +labeled/U +labia +labial/SM +labile +labium/M +labor/SMDRZG +laboratory/SM +laborer/M +laborious/PY +laboriousness/M +laborsaving +laburnum/MS +labyrinth/M +labyrinthine +labyrinths +lac/M +lace's +lace/UGDS +lacerate/DSGNX +laceration/M +lacewing/SM +lacework/M +lachrymal +lachrymose +lack/MDSG +lackadaisical/Y +lackey/SM +lackluster +laconic +laconically +lacquer/GMDS +lacrimal +lacrosse/M +lactate/GNDS +lactation/M +lacteal +lactic +lactose/M +lacuna/M +lacunae +lacy/RT +lad/SGMDNJ +ladder/GSMD +laddie/SM +laddish/P +lade/S +laden/U +lading/M +ladle/DSMG +lady/SM +ladybird/SM +ladybug/MS +ladyfinger/MS +ladylike/U +ladylove/MS +ladyship/MS +laetrile/M +lag/SZMR +lager/M +laggard/MYS +lagged +lagging/M +lagniappe/SM +lagoon/SM +laid/IA +lain +lair/MS +laird/SM +laity/M +lake/MS +lakefront/S +lakeside +lallygag/S +lallygagged +lallygagging +lam/SM +lama/MS +lamasery/SM +lamb/MDSG +lambada/MS +lambast/GDS +lambaste/S +lambda/SM +lambency/M +lambent/Y +lambkin/SM +lambskin/SM +lambswool +lame/MYZTGDRSP +lamebrain/MDS +lameness/M +lament/BSMDG +lamentably +lamentation/MS +lamina/M +laminae +laminar +laminate/MGNDS +lamination/M +lammed +lamming +lamp/MS +lampblack/M +lamplight/MRZ +lamplighter/M +lampoon/SGMD +lamppost/SM +lamprey/MS +lampshade/SM +lanai/SM +lance/DRSMZG +lancer/M +lancet/SM +land/MDRSGJ +landau/SM +landfall/MS +landfill/MS +landholder/SM +landholding/MS +landing/M +landlady/SM +landless/M +landline/MS +landlocked +landlord/MS +landlubber/MS +landmark/MS +landmass/MS +landmine/S +landowner/MS +landownership +landowning/SM +landscape/MZGDRS +landscaper/M +landslid +landslide/MGS +landslip/S +landsman/M +landsmen +landward/S +lane/MS +language/MS +languid/PY +languidness/M +languish/DSG +languor/SM +languorous/Y +lank/RYTP +lankiness/M +lankness/M +lanky/RTP +lanolin/M +lantern/MS +lanthanum/M +lanyard/MS +lap/SM +laparoscopic +laparoscopy +laparotomy +lapboard/SM +lapdog/SM +lapel/SM +lapidary/SM +lapin/SM +lapped +lappet/SM +lapping +lapse/AKGMSD +laptop/SM +lapwing/MS +larboard/SM +larcenist/SM +larcenous +larceny/SM +larch/MS +lard/MDRSZG +larder/M +lardy/RT +large/RSPMYT +largehearted +largeness/M +largess/M +largish +largo/SM +lariat/SM +lark/MDSG +larkspur/SM +larva/M +larvae +larval +laryngeal +larynges +laryngitis/M +larynx/M +lasagna/MS +lascivious/YP +lasciviousness/M +lase/ZGDRS +laser/M +lash/MDSGJ +lashing/M +lass/MS +lassie/SM +lassitude/M +lasso/SMDG +last/MDYSG +lasting/Y +lat/S +latch's +latch/UDSG +latchkey/SM +late/YTRP +latecomer/MS +latency/M +lateness/M +latent +lateral/MDYSG +latest/M +latex/M +lath/MDRSZG +lathe/M +lather/GMD +lathery +laths +latices +latish +latitude/MS +latitudinal +latitudinarian/MS +latrine/MS +latte/RSM +latter/MY +lattice/MDS +latticework/SM +laud/MDSGB +laudably +laudanum/M +laudatory +laugh/BMDG +laughably +laughing/MY +laughingstock/SM +laughs +laughter/M +launch/AGMDS +launcher/SM +launchpad/SM +launder/DRZGS +launderer/M +launderette/SM +laundress/MS +laundromat/MS +laundry/SM +laundryman/M +laundrymen +laundrywoman/M +laundrywomen +laureate/MS +laureateship/M +laurel/SM +lav/SGD +lava/M +lavage/M +lavaliere/SM +lavatorial +lavatory/SM +lave/S +lavender/SM +lavish/PTGDRSY +lavishness/M +law/SM +lawbreaker/SM +lawbreaking/M +lawful/UPY +lawfulness/UM +lawgiver/MS +lawless/PY +lawlessness/M +lawmaker/MS +lawmaking/M +lawman/M +lawmen +lawn/MS +lawnmower/SM +lawrencium/M +lawsuit/MS +lawyer/SM +lax/TRYP +laxative/MS +laxity/M +laxness/M +lay/AICSGM +layabout/S +layaway/M +layer/CSM +layered +layering/M +layette/MS +layman/M +laymen +layoff/SM +layout/SM +layover/MS +laypeople +layperson/MS +layup/SM +laywoman/M +laywomen +laze/MGDS +lazily +laziness/M +lazy/DRSTGP +lazybones/M +lb/S +lbw +lea/SM +leach/DSG +lead/MDNRSZG +leader/M +leaderless +leadership/SM +leading/M +leaf/MDSG +leafage/M +leafless +leaflet/GMDS +leafstalk/MS +leafy/RT +league/DSMG +leak/MDSG +leakage/MS +leakiness/M +leaky/PRT +lean/MDRSTGJP +leaning/M +leanness/M +leap/MDRSZG +leaper/M +leapfrog/MS +leapfrogged +leapfrogging +leapt +learn/AUGDS +learnedly +learner/MS +learning's +lease/ADSMG +leaseback/SM +leasehold/MRSZ +leaseholder/M +leaser/SM +leash's +leash/UDSG +least/M +leastwise +leather/MS +leatherette/M +leatherneck/MS +leathery +leave/DRSMZGJ +leaven/SGMD +leavened/U +leavening/M +leaver/M +leavings/M +lech/MDRSZG +lecher/M +lecherous/PY +lecherousness/M +lechery/M +lecithin/M +lectern/MS +lecture/MZGDRS +lecturer/M +lectureship/SM +ledge/RSMZ +ledger/M +lee/RSMZ +leech/MDSG +leek/MS +leer/MDG +leeriness/M +leery/RPT +leeward/SM +leeway/M +left/MRST +leftism/M +leftist/SM +leftmost +leftover/SM +leftward/S +lefty/SM +leg/SM +legacy/SM +legal/SMY +legalese/M +legalism/MS +legalistic +legalistically +legality/SM +legalization/M +legalize/GDS +legate/CXMNS +legatee/MS +legation's/AC +legato/SM +legend/SM +legendarily +legendary +legerdemain/M +legged +leggin/SM +legginess/M +legging/MS +leggy/RPT +leghorn/MS +legibility/M +legible +legibly +legion/SM +legionary/SM +legionnaire/SM +legislate/DSGNV +legislation/M +legislative/Y +legislator/MS +legislature/SM +legit +legitimacy/M +legitimate/DSYG +legitimatize/GDS +legitimization/M +legitimize/DSG +legless +legman/M +legmen +legroom/SM +legume/MS +leguminous +legwarmer/S +legwork/M +lei/SM +leisure/DMY +leisureliness/M +leisurewear/M +leitmotif/MS +leitmotiv/MS +lemma/S +lemme/JG +lemming/M +lemon/SM +lemonade/SM +lemongrass +lemony +lemur/SM +lend/RSZG +lender/M +length/MNX +lengthen/GD +lengthily +lengthiness/M +lengths +lengthwise +lengthy/PRT +lenience/M +leniency/M +lenient/Y +lenitive +lens/MS +lent +lentil/MS +lento +leonine +leopard/SM +leopardess/MS +leotard/SM +leper/SM +leprechaun/MS +leprosy/M +leprous +lepta +lepton/MS +lesbian/SM +lesbianism/M +lesion/MS +less/MNRX +lessee/MS +lessen/GD +lesson/MS +lessor/MS +let/ISM +letdown/SM +lethal/Y +lethargic +lethargically +lethargy/M +letter/ZGMDRS +letterbomb/S +letterbox/S +lettered/U +letterer/M +letterhead/MS +lettering/M +letterpress/M +letting/S +lettuce/MS +letup/SM +leucine +leucotomy/S +leukemia/M +leukemic/SM +leukocyte/MS +levee/SM +level/PSZGMDRY +leveler/M +levelheaded/P +levelheadedness/M +levelness/M +lever/SGMD +leverage's +leverage/CDSG +leviathan/MS +levier/M +levitate/DSGN +levitation/M +levity/M +levy/DRSMZG +lewd/RYPT +lewdness/M +lexer/S +lexical +lexicographer/MS +lexicographic +lexicographical +lexicography/M +lexicon/SM +lexis +lg +liabilities +liability/AM +liable/A +liaise/GDS +liaison/MS +liar/MS +lib/M +libation/SM +libber/MS +libel/SZGMDR +libeler/M +libelous +liberal/MYPS +liberalism/M +liberality/M +liberalization/SM +liberalize/GDS +liberalness/M +liberate/CDSGN +liberation/CM +liberator/MS +libertarian/SM +libertine/MS +liberty/SM +libidinal +libidinous +libido/MS +librarian/MS +librarianship +library/SM +librettist/MS +libretto/SM +lice +license/MGDS +licensed/U +licensee/MS +licentiate/SM +licentious/YP +licentiousness/M +lichen/MS +licit/Y +lick/MDJSG +licking/M +licorice/SM +lid/SM +lidded +lidless +lido/MS +lie/DSM +lied/MR +lief/RT +liege/SM +lien/MS +lieu/M +lieutenancy/M +lieutenant/MS +life/MZR +lifebelt/S +lifeblood/M +lifeboat/MS +lifebuoy/MS +lifeforms +lifeguard/SM +lifeless/YP +lifelessness/M +lifelike +lifeline/MS +lifelong +lifer/M +lifesaver/SM +lifesaving/M +lifespan/S +lifestyle/SM +lifetime/MS +lifework/MS +lift/MDRSZG +lifter/M +liftoff/SM +ligament/MS +ligate/GNDS +ligation/M +ligature/MGDS +light's/C +light/CASTGD +lighted/U +lighten/SDRZG +lightener/M +lighter/SM +lightface/MD +lightheaded +lighthearted/YP +lightheartedness/M +lighthouse/MS +lighting's +lightly +lightness/M +lightning/MDS +lightproof +lightship/MS +lightweight/SM +ligneous +lignin +lignite/M +lii +likability/M +likable/P +likableness/M +like/EMGDST +likeability/M +likeable/P +likeableness/M +likelihood/UM +likelihoods +likeliness/UM +likely/UPRT +liken/SGD +likeness/UM +likenesses +liker +likewise +liking/M +lilac/SM +lilliputian +lilo/S +lilt/MDSG +lily/SM +limb/MS +limber/UDSG +limberness/M +limbless +limbo/SM +lime/MGDS +limeade/SM +limelight/M +limerick/SM +limescale +limestone/M +limey/S +limit's +limit/CSZGDR +limitation/CM +limitations +limited/U +limiter's +limiting/S +limitless/P +limitlessness/M +limn/DSG +limo/MS +limousine/MS +limp/MDRYSPTG +limpet/MS +limpid/YP +limpidity/M +limpidness/M +limpness/M +limy/RT +linage/M +linchpin/SM +linden/MS +line/MZGDRSJ +lineage/MS +lineal/Y +lineament/SM +linear/Y +linearity/M +linebacker/MS +lined/U +linefeed +lineman/M +linemen +linen/SM +linens/M +liner/M +linesman/M +linesmen +lineup/MS +ling/M +linger/ZGJDRS +lingerer/M +lingerie/M +lingering/Y +lingo/M +lingoes +lingual +linguine/M +linguini/SM +linguist/SM +linguistic/S +linguistically +linguistics/M +liniment/SM +lining/M +link/MDRSG +linkage/MS +linkman +linkmen +linkup/MS +linnet/MS +lino +linoleum/M +linseed/M +lint's +lint/CDG +lintel/MS +lints +linty/TR +lion/MS +lioness/MS +lionhearted +lionization/M +lionize/GDS +lip/SM +lipid/SM +liposuction/M +lipped +lippy +lipread/GRS +lipreader/M +lipreading/M +lipstick/MDSG +liq +liquefaction/M +liquefy/DSG +liqueur/SM +liquid/MS +liquidate/XGNDS +liquidation/M +liquidator/MS +liquidity/M +liquidize/ZGDRS +liquidizer/M +liquor/MDGS +lira/M +lire +lisle/M +lisp/MDRSZG +lisper/M +lissome +list/MDNSJXG +listed/U +listen/BMDRZG +listener/M +listeria +listing/M +listless/YP +listlessness/M +lit/ZR +litany/SM +litchi/MS +lite +liter/M +literacy/M +literal/SMYP +literalness/M +literariness/M +literary/P +literate/SMY +literati/M +literature/M +lithe/RPYT +litheness/M +lithesome +lithium/M +lithograph/MDRZG +lithographer/M +lithographic +lithographically +lithographs +lithography/M +lithosphere/SM +litigant/SM +litigate/DSGN +litigation/M +litigator/MS +litigious/P +litigiousness/M +litmus/M +litotes/M +litter/MDRSZG +litterateur/MS +litterbug/MS +litterer/M +little/MTRP +littleness/M +littoral/SM +littérateur/SM +liturgical/Y +liturgist/SM +liturgy/SM +livability/M +livable/U +live/ATGDSB +livelihood/SM +liveliness/M +livelong/S +lively/PRT +liven/SGD +liver's +liver/S +liveried +liverish +liverwort/MS +liverwurst/M +livery/CSM +liveryman/CM +liverymen/C +livestock/M +liveware +livid/Y +living/MS +lix/K +lizard/MS +ll +llama/SM +llano/SM +lo +load's +load/AUGSD +loadable +loader/MS +loading's +loaf/MDRSZG +loafer/M +loam/M +loamy/TR +loan/MDRSZG +loaner/M +loansharking/M +loanword/MS +loath/JZGDRS +loathe +loather/M +loathing/M +loathsome/PY +loathsomeness/M +loaves +lob/SMD +lobar +lobbed +lobber/MS +lobbing +lobby/GDSM +lobbyist/MS +lobe/MS +lobotomize/DSG +lobotomy/SM +lobster/MS +local/SMY +locale/MS +locality/SM +localization/M +localize/DSG +locate/EAGNDS +location's/A +location/ESM +locator/MS +locavore/SM +loci +lock/MDRSBZG +locker/M +locket/MS +lockjaw/M +lockout/MS +locksmith/M +locksmiths +lockstep/M +lockup/MS +loco/S +locomotion/M +locomotive/MS +locoweed/SM +locum/S +locus/M +locust/SM +locution/MS +lode/MS +lodestar/MS +lodestone/MS +lodge/DRSJMZG +lodger/M +lodging/M +lodgings/M +loft/MDSG +loftily +loftiness/M +lofty/PRT +log/SM +loganberry/SM +logarithm/SM +logarithmic +logbook/SM +loge/MS +logged +logger/SM +loggerhead/SM +loggia/SM +logging/M +logic/M +logical/Y +logicality/M +logician/MS +login/SM +logistic/S +logistical/Y +logistics/M +logjam/SM +logo/MS +logoff/SM +logon/SM +logotype/SM +logout/SM +logrolling/M +logy/RT +loin/MS +loincloth/M +loincloths +loiter/ZGSDR +loiterer/M +loitering/M +lolcat/SM +loll/DSG +lollipop/SM +lollop/GSD +lolly/S +lollygag/S +lollygagged +lollygagging +lollypop/MS +lone/YZR +loneliness/M +lonely/PTR +loner/M +lonesome/YP +lonesomeness/M +long's +long/KDSTG +longboat/MS +longbow/MS +longer +longevity/M +longhair/MS +longhand/M +longhorn/MS +longhouse/S +longing/MYS +longish +longitude/MS +longitudinal/Y +longshoreman/M +longshoremen +longsighted +longstanding +longtime +longueur/SM +longways +loo +loofah/M +loofahs +look/MDRSZG +lookalike/MS +looker/M +lookout/MS +lookup +loom/MDSG +loon/MS +loonie/M +loony/RSMT +loop/MDSG +loophole/MS +loopy/RT +loos/NRX +loose/UDSTG +loosely +loosen/UGSD +looseness/M +loot/MDRSZG +looter/M +looting/M +lop/S +lope/MGDS +lopped +lopping +lopsided/YP +lopsidedness/M +loquacious/PY +loquaciousness/M +loquacity/M +lord/MDYSG +lordliness/M +lordly/TPR +lordship/SM +lore/M +lorgnette/SM +loris/MS +lorn +lorry/SM +lose/ZGRSJ +loser/M +losing/M +loss/MS +lossless +lost +lot/SM +lotion/SM +lottery/SM +lotto/M +lotus/MS +louche +loud/RYTP +loudhailer/SM +loudmouth/MD +loudmouths +loudness/M +loudspeaker/MS +lough +loughs +lounge/MZGDRS +lounger/M +lour/DSG +louse's +louse/CDSG +lousily +lousiness/M +lousy/TPR +lout/MS +loutish/PY +louver/MDS +lovableness/M +lovably +love/MYZGDRSB +lovebird/SM +lovechild/M +loved/U +loveless +loveliness/M +lovelorn +lovely/RSMTP +lovemaking/M +lover/M +loveseat/SM +lovesick +lovey/S +loving/Y +low/SZTGMDRYP +lowborn +lowboy/MS +lowbrow/SM +lowdown/M +lower/GD +lowercase/M +lowermost +lowish +lowland/SZMR +lowlander/M +lowlife/SM +lowliness/M +lowly/TPR +lowness/M +lox/M +loyal/ETY +loyaler +loyalism/M +loyalist/SM +loyalties +loyalty/EM +lozenge/SM +ltd +luau/MS +lubber/MYS +lube/MGDS +lubricant/SM +lubricate/DSGN +lubrication/M +lubricator/MS +lubricious/Y +lubricity/M +lucid/PY +lucidity/M +lucidness/M +luck/MDSG +luckily/U +luckiness/UM +luckless +lucky/UPTR +lucrative/YP +lucrativeness/M +lucre/M +lucubrate/GNDS +lucubration/M +ludicrous/YP +ludicrousness/M +ludo +luff/DSG +lug/SM +luge/S +luggage/M +lugged +lugger/MS +lugging +lughole/S +lugsail/SM +lugubrious/YP +lugubriousness/M +lukewarm/YP +lukewarmness/M +lull/MDSG +lullaby/SM +lulu/S +lumbago/M +lumbar +lumber/MDRZGS +lumberer/M +lumbering/M +lumberjack/SM +lumberman/M +lumbermen +lumberyard/SM +luminary/SM +luminescence/M +luminescent +luminosity/M +luminous/Y +lummox/MS +lump/MDNSG +lumpectomy/S +lumpiness/M +lumpish +lumpy/TRP +lunacy/SM +lunar +lunatic/SM +lunch/GMDS +lunchbox/S +luncheon/SM +luncheonette/SM +lunchroom/MS +lunchtime/MS +lung/MDSG +lunge/SM +lungfish/MS +lungful/S +lunkhead/MS +lupine/MS +lupus/M +lurch/GMDS +lure/MGDS +lurgy +lurid/PY +luridness/M +lurk/DRSZG +luscious/PY +lusciousness/M +lush/MRSYPT +lushness/M +lust/MDRSG +luster/M +lusterless +lustful/Y +lustily +lustiness/M +lustrous/Y +lusty/PTR +lutanist/SM +lute/MS +lutenist/SM +lutetium/M +luxuriance/M +luxuriant/Y +luxuriate/DSGN +luxuriation/M +luxurious/PY +luxuriousness/M +luxury/SM +lvi +lvii +lxi +lxii +lxiv +lxix +lxvi +lxvii +lyceum/MS +lychee/MS +lychgate/S +lye/MG +lying/M +lymph/M +lymphatic/SM +lymphocyte/SM +lymphoid +lymphoma/SM +lynch/JZGDRS +lyncher/M +lynching/M +lynx/MS +lyre/MS +lyrebird/MS +lyric/SM +lyrical/Y +lyricism/M +lyricist/SM +lysosomal +lysosomes +m/KAS +ma'am +ma/SMH +mac/SGMD +macabre +macadam/M +macadamia/SM +macadamize/GDS +macaque/MS +macaroni/MS +macaroon/MS +macaw/SM +mace/MS +macerate/DSGN +maceration/M +mach/M +machete/SM +machinate/GNDSX +machination/M +machine/DSMGB +machinery/M +machinist/MS +machismo/M +macho/M +mack/MS +mackerel/SM +mackinaw/SM +mackintosh/MS +macrame/M +macramé/M +macro/SM +macrobiotic/S +macrobiotics/M +macrocosm/SM +macroeconomic/S +macroeconomics/M +macrology/S +macron/MS +macrophages +macroscopic +mad/SMYP +madam/SM +madame/M +madcap/MS +madden/DGS +maddening/Y +madder/MS +maddest +madding +made/AU +mademoiselle/MS +madhouse/SM +madman/M +madmen +madness/M +madras/MS +madrasa/SM +madrasah/M +madrasahs +madrassa/SM +madrigal/SM +madwoman/M +madwomen +maelstrom/SM +maestro/SM +mafia/SM +mafiosi +mafioso/M +mag/SM +magazine/SM +mage/MS +magenta/M +maggot/MS +maggoty +magi/M +magic/SM +magical/Y +magician/SM +magicked +magicking +magisterial/Y +magistracy/M +magistrate/SM +magma/M +magnanimity/M +magnanimous/Y +magnate/SM +magnesia/M +magnesium/M +magnet/MS +magnetic +magnetically +magnetism/M +magnetite/M +magnetizable +magnetization/CM +magnetize/CGDS +magneto/SM +magnetometer/SM +magnetosphere +magnification/M +magnificence/M +magnificent/Y +magnifier/M +magnify/ZGXDRSN +magniloquence/M +magniloquent +magnitude/SM +magnolia/MS +magnum/MS +magpie/MS +magus/M +maharaja/SM +maharajah/M +maharajahs +maharanee/MS +maharani/SM +maharishi/SM +mahatma/SM +mahjong/M +mahogany/SM +mahout/MS +maid/MNSX +maiden/MY +maidenhair/M +maidenhead/SM +maidenhood/M +maidservant/SM +mail/JMDRSZG +mailbag/SM +mailbomb/GSD +mailbox/MS +mailer/M +mailing/M +maillot/SM +mailman/M +mailmen +mailshot/S +maim/DSG +main/MYS +mainframe/SM +mainland/MS +mainline/MGDS +mainmast/MS +mainsail/MS +mainspring/MS +mainstay/MS +mainstream/SMDG +maintain/ZGBDRS +maintainability +maintenance/M +maintop/SM +maisonette/MS +maize/SM +majestic +majestically +majesty/SM +majolica/M +major/SGMDY +majordomo/MS +majorette/MS +majoritarian/SM +majoritarianism +majority/SM +make's/A +make/UAGS +makeover/MS +maker/SM +makeshift/SM +makeup/MS +makeweight/S +making/MS +makings/M +malachite/M +maladjusted +maladjustment/M +maladministration +maladroit/PY +maladroitness/M +malady/SM +malaise/M +malamute/MS +malapropism/SM +malaria/M +malarial +malarkey/M +malathion/M +malcontent/MS +male/MPS +malediction/SM +malefaction/M +malefactor/SM +malefic +maleficence/M +maleficent +maleness/M +malevolence/M +malevolent/Y +malfeasance/M +malformation/SM +malformed +malfunction/MDSG +malice/M +malicious/PY +maliciousness/M +malign/DSG +malignancy/SM +malignant/Y +malignity/M +malinger/ZGSDR +malingerer/M +mall/MS +mallard/SM +malleability/M +malleable +mallet/MS +mallow/MS +malnourished +malnutrition/M +malocclusion/M +malodorous +malpractice/SM +malt/MDSG +malted/MS +maltose/M +maltreat/GLDS +maltreatment/M +malty/TR +malware/M +mam/S +mama/MS +mamba/SM +mambo/SGMD +mamma/M +mammal/MS +mammalian/MS +mammary +mammogram/MS +mammography/M +mammon/M +mammoth/M +mammoths +mammy/SM +man's/F +man/USY +manacle/DSMG +manage/ZGDRSL +manageability/M +manageable/U +management/MS +manager/M +manageress/S +managerial +manana/MS +manatee/SM +mandala/SM +mandamus/MS +mandarin/MS +mandate/DSMG +mandatory +mandible/MS +mandibular +mandolin/MS +mandrake/MS +mandrel/SM +mandrill/MS +mane/MDS +manege/M +maneuver/MDGSBJ +maneuverability/M +manful/Y +manga/M +manganese/M +mange/DRMZ +manger/M +mangetout/S +manginess/M +mangle/MZGDRS +mango/M +mangoes +mangrove/MS +mangy/TRP +manhandle/GDS +manhole/SM +manhood/M +manhunt/SM +mania/SM +maniac/MS +maniacal/Y +manic/SM +manically +manicure/MGDS +manicurist/MS +manifest/MDYSG +manifestation/SM +manifesto/SM +manifold/GMDS +manikin/SM +manila/M +manioc/MS +manipulable +manipulate/XGNVDS +manipulation/M +manipulative/Y +manipulator/MS +mankind/M +manky +manlike +manliness/M +manly/UTR +manna/M +manned/U +mannequin/SM +manner/MDYS +mannerism/SM +mannerly/U +manning/U +mannish/YP +mannishness/M +manometer/SM +manor/SM +manorial +manpower/M +manque +manqué +mansard/MS +manse/SXMN +manservant/M +mansion/M +manslaughter/M +manta/SM +mantel/MS +mantelpiece/SM +mantelshelf +mantelshelves +mantes +mantilla/SM +mantis/MS +mantissa/SM +mantle's +mantle/EGDS +mantra/MS +manual/MYS +manufacture/DRSMZG +manufacturer/M +manufacturing/M +manumission/SM +manumit/S +manumitted +manumitting +manure/MGDS +manuscript/MS +many/M +manège/M +map's +map/AS +maple/SM +mapmaker/SM +mapped/A +mapper/MS +mapping/S +mar/S +marabou/MS +marabout/SM +maraca/MS +maraschino/MS +marathon/SMRZ +marathoner/M +maraud/ZGDRS +marauder/M +marble/MGDS +marbleize/GDS +marbling/M +march/ZGMDRS +marcher/M +marchioness/MS +mare/MS +margarine/M +margarita/MS +marge +margin/MS +marginal/YS +marginalia/M +marginalization/M +marginalize/GDS +maria/M +mariachi/MS +marigold/MS +marijuana/M +marimba/SM +marina/MS +marinade/DSMG +marinara/M +marinate/DSGN +marination/M +marine/MZRS +mariner/M +marionette/MS +marital/Y +maritime +marjoram/M +mark/AMDSG +markdown/SM +marked/U +markedly +marker/MS +market/MDRZGBS +marketability/M +marketable/U +marketeer/SM +marketer/M +marketing/M +marketplace/SM +marking/SM +markka/M +markkaa +marksman/M +marksmanship/M +marksmen +markup/MS +marl/M +marlin/MS +marlinespike/SM +marmalade/M +marmoreal +marmoset/SM +marmot/MS +maroon/MDGS +marque/MS +marquee/SM +marquess/MS +marquetry/M +marquis/MS +marquise/M +marquisette/M +marred/U +marriage/ASM +marriageability/M +marriageable +married/SM +marring +marrow/MS +marry/AGDS +marsh/MS +marshal/SMDG +marshland/SM +marshmallow/SM +marshy/RT +marsupial/MS +mart/MNSX +marten/M +martensite +martial/Y +martian/S +martin/MS +martinet/MS +martingale/MS +martini/SM +martyr/MDGS +martyrdom/M +marvel/MDGS +marvelous/Y +marzipan/M +masc +mascara/GMDS +mascot/MS +masculine/SM +masculinity/M +maser/SM +mash/MDRSZG +masher/M +mashup/MS +mask's +mask/UDSG +masker/MS +masochism/M +masochist/SM +masochistic +masochistically +mason/SM +masonic +masonry/M +masque/MS +masquerade/DRSMZG +masquerader/M +mass/MDSGV +massacre/MGDS +massage/DSMG +masseur/SM +masseuse/MS +massif/MS +massive/PY +massiveness/M +mast/MDS +mastectomy/SM +master's +master/ADGS +masterclass/S +masterful/Y +masterly +mastermind/SGMD +masterpiece/MS +masterstroke/SM +masterwork/MS +mastery/M +masthead/MS +mastic/M +masticate/GNDS +mastication/M +mastiff/SM +mastitis +mastodon/SM +mastoid/SM +masturbate/GNDS +masturbation/M +masturbatory +mat/SZGMDR +matador/SM +match/AMS +matchbook/SM +matchbox/MS +matched/U +matching +matchless +matchlock/SM +matchmaker/MS +matchmaking/M +matchstick/MS +matchwood/M +mate/MS +material/SMY +materialism/M +materialist/SM +materialistic +materialistically +materialization/M +materialize/DSG +materiel/M +maternal/Y +maternity/M +matey/S +mathematical/Y +mathematician/SM +mathematics/M +matinee/SM +mating/M +matins/M +matinée/SM +matriarch/M +matriarchal +matriarchs +matriarchy/SM +matrices +matricidal +matricide/MS +matriculate/DSGN +matriculation/M +matrimonial +matrimony/M +matrix/M +matron/MYS +matte/DRSMZG +matter/MDG +matting/M +mattock/SM +mattress/MS +maturate/GNDS +maturation/M +mature/YTGDRS +maturity/SM +matzo/SMH +matzoh/M +matzohs +matzot +matériel/M +maudlin +maul/MDRSZG +mauler/M +maunder/SDG +mausoleum/SM +mauve/M +maven/SM +maverick/SM +maw/SM +mawkish/PY +mawkishness/M +max/GMDS +maxi/MS +maxilla/M +maxillae +maxillary +maxim/SM +maximal/Y +maximization/M +maximize/GDS +maximum/SM +may/M +maybe/SM +mayday/MS +mayflower/MS +mayfly/SM +mayhem/M +mayn't +mayo/M +mayonnaise/M +mayor/SM +mayoral +mayoralty/M +mayoress/MS +maypole/SM +mayst +maze/MS +mazurka/MS +mañana/M +mdse +me/DSH +mead/M +meadow/MS +meadowlark/MS +meager/PY +meagerness/M +meal/MS +mealiness/M +mealtime/SM +mealy/TPR +mealybug/SM +mealymouthed +mean/MRYJPSTG +meander/SMDJG +meanderings/M +meanie/M +meaning/M +meaningful/PY +meaningfulness/M +meaningless/YP +meaninglessness/M +meanness/M +meant/U +meantime/M +meanwhile/M +meany/SM +meas +measles/M +measly/RT +measurable +measurably +measure's +measure/ADSG +measured/U +measureless +measurement/MS +meat/MS +meatball/MS +meathead/MS +meatiness/M +meatless +meatloaf/M +meatloaves +meatpacking/M +meaty/TPR +mecca/SM +mechanic/MS +mechanical/Y +mechanics/M +mechanism/SM +mechanistic +mechanistically +mechanization/M +mechanize/DSG +medal/SM +medalist/MS +medallion/SM +meddle/ZGDRS +meddler/M +meddlesome +media/SM +medial/AY +median/MS +mediate/DSGN +mediated/U +mediation/AM +mediator/MS +medic/SM +medicaid/M +medical/SMY +medicament/M +medicare/M +medicate/GNXDS +medication/M +medicinal/Y +medicine/MS +medico/MS +medieval +medievalist/MS +mediocre +mediocrity/SM +meditate/DSGNVX +meditation/M +meditative/Y +medium/MS +medley/MS +medulla/SM +medusa +medusae +meed/M +meek/RYPT +meekness/M +meerschaum/SM +meet/MJSG +meeting/M +meetinghouse/SM +meetup/MS +meg/S +mega +megabit/SM +megabucks/M +megabyte/MS +megachurch/MS +megacycle/SM +megadeath/M +megadeaths +megahertz/M +megalith/M +megalithic +megaliths +megalomania/M +megalomaniac/SM +megalopolis/MS +megaphone/DSMG +megapixel/SM +megastar/S +megaton/SM +megawatt/MS +meh +meiosis/M +meiotic +melamine/M +melancholia/M +melancholic/S +melancholy/M +melange/MS +melanin/M +melanoma/SM +meld/MDSG +melee/SM +meliorate/GNVDS +melioration/M +mellifluous/PY +mellifluousness/M +mellow/PTGDRYS +mellowness/M +melodic +melodically +melodious/YP +melodiousness/M +melodrama/MS +melodramatic/S +melodramatically +melodramatics/M +melody/SM +melon/SM +melt's +melt/ADSG +meltdown/SM +member's +member/EAS +membership/SM +membrane/SM +membranous +meme/MS +memento/MS +memo/MS +memoir/MS +memorabilia/M +memorability/M +memorable/U +memorably +memorandum/MS +memorial/SM +memorialize/DSG +memorization/M +memorize/DSG +memory/SM +memsahib/S +men/M +menace/MGDS +menacing/Y +menage/MS +menagerie/MS +mend/MDRSZG +mendacious/Y +mendacity/M +mendelevium/M +mender/M +mendicancy/M +mendicant/SM +mending/M +menfolk/MS +menfolks/M +menhaden/M +menial/MYS +meningeal +meninges +meningitis/M +meninx/M +menisci +meniscus/M +menopausal +menopause/M +menorah/M +menorahs +mensch/MS +menservants +menses/M +menstrual +menstruate/GNDS +menstruation/M +mensurable +mensuration/M +menswear/M +mental/Y +mentalist/SM +mentality/SM +menthol/M +mentholated +mention/GSMD +mentioned/U +mentor/MDSG +menu/MS +meow/MDSG +mercantile +mercantilism/M +mercenary/SM +mercer/MS +mercerize/GDS +merchandise/MZGDRS +merchandiser/M +merchandising/M +merchant/MBS +merchantman/M +merchantmen +merciful/UY +merciless/PY +mercilessness/M +mercurial/Y +mercuric +mercury/M +mercy/SM +mere/MYTS +meretricious/YP +meretriciousness/M +merganser/MS +merge/DRSZG +merger/M +meridian/MS +meringue/MS +merino/MS +merit/CSM +merited/U +meriting +meritocracy/SM +meritocratic +meritorious/PY +meritoriousness/M +mermaid/SM +merman/M +mermen +merrily +merriment/M +merriness/M +merry/TRP +merrymaker/MS +merrymaking/M +mesa/MS +mescal/MS +mescalin +mescaline/M +mesdames +mesdemoiselles +mesh/MDSG +mesmeric +mesmerism/M +mesmerize/ZGDRS +mesmerizer/M +mesomorph/M +mesomorphs +meson/SM +mesosphere/SM +mesquite/SM +mess/MDSG +message/MGDS +messeigneurs +messenger/SM +messiah/M +messiahs +messianic +messieurs +messily +messiness/M +messmate/SM +messy/PTR +mestizo/MS +met +meta +metabolic +metabolically +metabolism/SM +metabolite/SM +metabolize/DSG +metacarpal/SM +metacarpi +metacarpus/M +metadata +metal/SMD +metalanguage/MS +metallic +metallurgic +metallurgical +metallurgist/MS +metallurgy/M +metalwork/MRZG +metalworker/M +metalworking/M +metamorphic +metamorphism/M +metamorphose/GDS +metamorphosis/M +metaphor/MS +metaphoric +metaphorical/Y +metaphysical/Y +metaphysics/M +metastases +metastasis/M +metastasize/DSG +metastatic +metatarsal/MS +metatarsi +metatarsus/M +metatheses +metathesis/M +mete/MZGDRS +metempsychoses +metempsychosis/M +meteor/MS +meteoric +meteorically +meteorite/SM +meteoroid/SM +meteorologic +meteorological +meteorologist/SM +meteorology/M +meter/GMD +methadone/M +methamphetamine/M +methane/M +methanol/M +methinks +method/MS +methodical/YP +methodicalness/M +methodological/Y +methodology/SM +methotrexate +methought +meths +methyl/M +meticulous/YP +meticulousness/M +metier/MS +metric/S +metrical/Y +metricate/GNDS +metrication/M +metricize/GDS +metro/SM +metronome/MS +metropolis/MS +metropolitan +mettle/M +mettlesome +mew/SGMD +mewl/DSG +mews/M +mezzanine/MS +mezzo/SM +mfg +mfr/S +mg +mgr +mi/MNX +miasma/MS +mic/S +mica/M +mice +mick/S +mickey/MS +micro/SM +microaggression/SM +microbe/MS +microbial +microbiological +microbiologist/MS +microbiology/M +microbrewery/SM +microchip/MS +microcircuit/SM +microcode +microcomputer/MS +microcosm/MS +microcosmic +microdot/SM +microeconomics/M +microelectronic/S +microelectronics/M +microfiber/MS +microfiche/M +microfilm/GMDS +microfloppies +microgroove/SM +microlight/MS +microloan/MS +micromanage/GDSL +micromanagement/M +micrometeorite/SM +micrometer/MS +micron/MS +microorganism/MS +microphone/SM +microprocessor/MS +microscope/SM +microscopic +microscopical/Y +microscopy/M +microsecond/MS +microsurgery/M +microwave/DSMGB +microwaveable +mid +midair/M +midday/M +midden/MS +middle/MGS +middlebrow/SM +middleman/M +middlemen +middlemost +middleweight/MS +middy/SM +midfield/RZ +midge/SM +midget/MS +midi/MS +midland/MS +midlife/M +midmost +midnight/M +midpoint/MS +midrib/MS +midriff/MS +midsection/MS +midshipman/M +midshipmen +midships +midsize +midst/M +midstream/M +midsummer/M +midterm/MS +midtown/M +midway/MS +midweek/MS +midwife/MGDS +midwifery/SM +midwinter/M +midwived +midwives +midwiving +midyear/MS +mien/M +miff/DSG +might've +might/M +mightily +mightiness/M +mightn't +mighty/TRP +mignonette/SM +migraine/MS +migrant/MS +migrate/AGDS +migration/SM +migratory +mikado/MS +mike/MGDS +mil/SZMR +milady/SM +milch +mild/MRYTP +mildew/SMDG +mildness/M +mile/MS +mileage/SM +milepost/MS +miler/M +milestone/MS +milf/MS +milieu/SM +militancy/M +militant/MYS +militarily +militarism/M +militarist/SM +militaristic +militarization/CM +militarize/CDSG +military/M +militate/GDS +militia/SM +militiaman/M +militiamen +milk/MDRSZG +milker/M +milkiness/M +milkmaid/MS +milkman/M +milkmen +milkshake/SM +milksop/MS +milkweed/SM +milky/RTP +mill/MDRSZGJ +millage/M +millennia +millennial/M +millennium/MS +miller/M +millet/M +milliard/MS +millibar/MS +milligram/MS +milliliter/MS +millimeter/MS +milliner/MS +millinery/M +milling/M +million/HSM +millionaire/SM +millionairess/S +millionth/M +millionths +millipede/SM +millisecond/SM +millpond/SM +millrace/SM +millstone/SM +millstream/MS +millwright/SM +milometer/S +milquetoast/SM +milt/MDSG +mime/MGDS +mimeograph/GMD +mimeographs +mimetic +mimic/SM +mimicked +mimicker/SM +mimicking +mimicry/SM +mimosa/SM +min +minaret/MS +minatory +mince/DRSMZG +mincemeat/M +mincer/M +mind's +mind/ADRSZG +mindbogglingly +minded/P +mindful/YP +mindfulness/M +mindless/YP +mindlessness/M +mindset/MS +mine/MZGNDRSX +minefield/SM +miner/M +mineral/MS +mineralogical +mineralogist/MS +mineralogy/M +minestrone/M +minesweeper/SM +mingle/DSG +mingy +mini/MS +miniature/MS +miniaturist/MS +miniaturization/M +miniaturize/GDS +minibar/S +minibike/SM +minibus/MS +minicab/S +minicam/MS +minicomputer/SM +minifloppies +minim/SM +minimal/Y +minimalism/M +minimalist/MS +minimization/M +minimize/DSG +minimum/MS +mining/M +minion/M +miniseries/M +miniskirt/MS +minister/SGMD +ministerial +ministrant/MS +ministration/MS +ministry/SM +minivan/MS +mink/MS +minnesinger/MS +minnow/SM +minor/SMDG +minority/SM +minoxidil/M +minster/MS +minstrel/SM +minstrelsy/M +mint/MDRSZG +mintage/M +minter/M +minty/RT +minuend/MS +minuet/SM +minus/MS +minuscule/MS +minute/PDRSMYTG +minuteman/M +minutemen +minuteness/M +minutia/M +minutiae +minx/MS +miracle/MS +miraculous/Y +mirage/SM +mire/MGDS +mirror/GSMD +mirth/M +mirthful/PY +mirthfulness/M +mirthless/Y +miry/RT +misaddress/DSG +misadventure/MS +misaligned +misalignment/M +misalliance/MS +misanthrope/SM +misanthropic +misanthropically +misanthropist/MS +misanthropy/M +misapplication/M +misapply/DSGNX +misapprehend/GSD +misapprehension/MS +misappropriate/XDSGN +misappropriation/M +misbegotten +misbehave/GDS +misbehavior/M +misc +miscalculate/DSXGN +miscalculation/M +miscall/DSG +miscarriage/MS +miscarry/GDS +miscast/SG +miscegenation/M +miscellaneous/Y +miscellany/SM +mischance/SM +mischief/M +mischievous/YP +mischievousness/M +miscibility/M +miscible +miscommunication/S +misconceive/GDS +misconception/SM +misconduct/MDGS +misconstruction/MS +misconstrue/GDS +miscount/MDSG +miscreant/SM +miscue/DSMG +misdeal/GMS +misdealt +misdeed/MS +misdemeanor/MS +misdiagnose/GDS +misdiagnosis/M +misdid +misdirect/SDG +misdirection/M +misdo/JG +misdoes +misdoing/M +misdone +miser/SBMY +miserableness/M +miserably +miserliness/M +misery/SM +misfeasance/M +misfeature/S +misfile/GDS +misfire/MGDS +misfit/SM +misfitted +misfitting +misfortune/SM +misgiving/MS +misgovern/SDGL +misgovernment/M +misguidance/M +misguide/DSG +misguided/Y +mishandle/DSG +mishap/SM +mishear/GS +misheard +mishit/S +mishitting +mishmash/MS +misidentify/GDS +misinform/DGS +misinformation/M +misinterpret/SGD +misinterpretation/SM +misjudge/DSG +misjudgment/SM +mislabel/GSD +mislaid +mislay/GS +mislead/GS +misleading/Y +misled +mismanage/LGDS +mismanagement/M +mismatch/GMDS +misname/GDS +misnomer/MS +misogamist/MS +misogamy/M +misogynist/SM +misogynistic +misogynous +misogyny/M +misplace/GLDS +misplacement/M +misplay/GMDS +misprint/GMDS +misprision/M +mispronounce/DSG +mispronunciation/SM +misquotation/MS +misquote/MGDS +misread/GJS +misreading/M +misreport/MDGS +misrepresent/GDS +misrepresentation/MS +misrule/MGDS +miss's +miss/EDSGV +missal/ESM +missed/U +misshape/GDS +misshapen +missile/MS +missilery/M +mission/AMS +missionary/SM +missioner/SM +missis/MS +missive/MS +misspeak/GS +misspell/GDJS +misspelling/M +misspend/GS +misspent +misspoke +misspoken +misstate/GDSL +misstatement/SM +misstep/MS +missus/MS +mist's +mist/CDRSZG +mistakable/U +mistake/BMGS +mistaken/Y +mister's +mistily +mistime/GDS +mistiness/M +mistletoe/M +mistook +mistral/MS +mistranslated +mistreat/LDGS +mistreatment/M +mistress/MS +mistrial/MS +mistrust/MDSG +mistrustful/Y +misty/PRT +mistype/GS +misunderstand/SGJ +misunderstanding/M +misunderstood +misuse/DSMG +mite/MZRS +miter/MDG +mitigate/DSGN +mitigated/U +mitigation/M +mitochondria +mitochondrial +mitochondrion +mitoses +mitosis/M +mitotic +mitral +mitt/MNSX +mitten/M +mix/ZGMDRSB +mixed/U +mixer/M +mixture/SM +mizzen/MS +mizzenmast/SM +mkay +mks +ml +mm +mnemonic/MS +mnemonically +mo/CKHS +moan/MDRSZG +moaner/M +moat/MDS +mob's +mob/CS +mobbed/C +mobbing/C +mobile/MS +mobility/M +mobilization/CM +mobilizations +mobilize/CDSG +mobilizer/SM +mobster/SM +moccasin/SM +mocha/SM +mock/DRSZG +mocker/M +mockery/SM +mocking/Y +mockingbird/SM +mod/STM +modal/SM +modality/S +modded +modding +mode/MS +model/ZGSJMDR +modeler/M +modeling/M +modem/SM +moderate/MYGNPDS +moderateness/M +moderation/M +moderator/SM +modern/MYPS +modernism/M +modernist/SM +modernistic +modernity/M +modernization/M +modernize/DRSZG +modernizer/M +modernness/M +modest/Y +modesty/M +modicum/SM +modifiable +modification/M +modified/U +modifier/M +modify/DRSXZGN +modish/YP +modishness/M +modular +modulate/CGNDS +modulation/CM +modulations +modulator/MS +module/MS +modulo +modulus +moggy +mogul/SM +mohair/M +moi +moiety/SM +moil/MDSG +moire/SM +moist/XTPNRY +moisten/DRZG +moistener/M +moistness/M +moisture/M +moisturize/ZGDRS +moisturizer/M +molar/SM +molasses/M +mold/MDRJSZG +moldboard/SM +molder/GMD +moldiness/M +molding/M +moldy/TPR +mole/MS +molecular +molecularity/M +molecule/SM +molehill/SM +moleskin/M +molest/DRZGS +molestation/M +molested/U +molester/M +moll/MS +mollification/M +mollify/DSNG +mollusc/SM +molluscan/SM +mollusk/SM +molluskan/S +molly/SM +mollycoddle/DSMG +molt/MDNRSZG +molter/M +molybdenum/M +mom/SM +moment/MS +momenta +momentarily +momentariness/M +momentary/P +momentous/PY +momentousness/M +momentum/M +mommy/SM +monarch/M +monarchic +monarchical +monarchism/M +monarchist/MS +monarchistic +monarchs +monarchy/SM +monastery/SM +monastic/MS +monastical/Y +monasticism/M +monaural +monetarily +monetarism/M +monetarist/MS +monetary +monetize/CGDS +money/SMD +moneybag/MS +moneybox/S +moneygrubber/SM +moneygrubbing/M +moneylender/SM +moneymaker/SM +moneymaking/M +monger/MDGS +mongol/S +mongolism/M +mongoloid/MS +mongoose/MS +mongrel/SM +monies +moniker/SM +monism/M +monist/MS +monition/SM +monitor/SMDG +monitory +monk/MS +monkey/MDGS +monkeyshine/SM +monkish +monkshood/SM +mono/M +monochromatic +monochrome/MS +monocle/DSM +monoclonal +monocotyledon/SM +monocotyledonous +monocular +monodic +monodist/SM +monody/SM +monogamist/MS +monogamous/Y +monogamy/M +monogram/SM +monogrammed +monogramming +monograph/M +monographs +monolingual/MS +monolith/M +monolithic +monoliths +monologist/SM +monologue/SM +monologuist/SM +monomania/M +monomaniac/MS +monomaniacal +monomer/SM +mononucleosis/M +monophonic +monoplane/SM +monopolist/SM +monopolistic +monopolization/M +monopolize/DRSZG +monopolizer/M +monopoly/SM +monorail/MS +monosyllabic +monosyllable/MS +monotheism/M +monotheist/SM +monotheistic +monotone/MS +monotonic +monotonically +monotonous/PY +monotonousness/M +monotony/M +monounsaturated +monoxide/MS +monseigneur/M +monsieur/M +monsignor/SM +monsoon/SM +monsoonal +monster/SM +monstrance/ASM +monstrosity/SM +monstrous/Y +montage/SM +month/MY +monthly/SM +months +monument/MS +monumental/Y +moo/SGMD +mooch/ZGMDRS +moocher/M +mood/MS +moodily +moodiness/M +moody/TPR +moon/MDSG +moonbeam/MS +moonless +moonlight/SMDRZG +moonlighter/M +moonlighting/M +moonlit +moonscape/SM +moonshine/MZRS +moonshiner/M +moonshot/MS +moonstone/MS +moonstruck +moonwalk/MS +moor/MDJSG +moorhen/S +mooring/M +moorland/MS +moose/M +moot/DSG +mop/SZGMDR +mope/MS +moped/SM +moper/M +mopey +mopier +mopiest +mopish +mopped +moppet/MS +mopping +moraine/SM +moral/SMY +morale/M +moralist/MS +moralistic +moralistically +moralities +morality/UM +moralization/CM +moralize/CGDS +moralizer/MS +morass/MS +moratorium/SM +moray/SM +morbid/YP +morbidity/M +morbidness/M +mordancy/M +mordant/SMY +more/MS +moreish +morel/SM +moreover +mores/M +morgue/MS +moribund +morn/MJSG +morning/M +morocco/M +moron/SM +moronic +moronically +morose/YP +moroseness/M +morph/GD +morpheme/MS +morphemic +morphia/M +morphine/M +morphing/M +morphological +morphology/M +morphs +morrow/MS +morsel/MS +mortal/MYS +mortality/M +mortar/MDSG +mortarboard/SM +mortgage's +mortgage/AGDS +mortgagee/MS +mortgagor/MS +mortician/MS +mortification/M +mortify/NGDS +mortise/DSMG +mortuary/SM +mosaic/MS +mosey/SGD +mosh/DSG +mosque/MS +mosquito/M +mosquitoes +moss/MS +mossback/SM +mossy/TR +most/MY +mot/SM +mote's +mote/KCXSVN +motel/SM +motet/SM +moth/M +mothball/GMDS +mother/MDYSG +motherboard/SM +motherfucker/MS! +motherfucking/! +motherhood/M +motherland/MS +motherless +motherliness/M +moths +motif/SM +motile/S +motility/M +motion/KCM +motioned +motioning +motionless/YP +motionlessness/M +motivate/CDSG +motivated/U +motivation/SM +motivational +motivator/SM +motive/MS +motiveless +motley/MS +motlier +motliest +motocross/MS +motor/SGMD +motorbike/MGDS +motorboat/MS +motorcade/MS +motorcar/SM +motorcycle/DSMG +motorcyclist/MS +motorist/SM +motorization/M +motorize/DSG +motorman/M +motormen +motormouth/M +motormouths +motorway/SM +mottle/GDS +motto/M +mottoes +moue/MS +mound/SGMD +mount/EASGMD +mountable +mountain/SM +mountaineer/SMDG +mountaineering/M +mountainous +mountainside/SM +mountaintop/SM +mountebank/MS +mounted/U +mounter/MS +mounting/SM +mourn/SZGDR +mourned/U +mourner/M +mournful/YP +mournfulness/M +mourning/M +mouse/DRSMZG +mouser/M +mousetrap/SM +mousetrapped +mousetrapping +mousey +mousiness/M +moussaka/S +mousse/MGDS +mousy/PTR +mouth/GMD +mouthfeel +mouthful/MS +mouthiness/M +mouthpiece/MS +mouths +mouthwash/MS +mouthwatering +mouthy/PTR +mouton/M +movable/SM +move/AMZGDRSB +moveable/SM +moved/U +movement/SM +mover/AM +movie/SM +moviegoer/SM +moving/Y +mow/SZGMDR +mower/M +moxie/M +mozzarella/M +mp +mpg +mph +mt +mtg +mtge +mu/SM +much/M +mucilage/M +mucilaginous +muck/MDSG +muckrake/DRSZG +muckraker/M +mucky/TR +mucous +mucus/M +mud/M +muddily +muddiness/M +muddle/MGDS +muddleheaded +muddy/PTGDRS +mudflap/S +mudflat/MS +mudguard/SM +mudpack/S +mudroom/MS +mudslide/MS +mudslinger/SM +mudslinging/M +muenster/M +muesli +muezzin/MS +muff/MDSG +muffin/MS +muffle/ZGDRS +muffler/M +mufti/SM +mug/SM +mugful/MS +mugged +mugger/MS +mugginess/M +mugging/MS +muggins +muggle/MS +muggy/PTR +mugshot/MS +mugwump/MS +mujaheddin +mujahedin/M +mukluk/MS +mulatto/M +mulattoes +mulberry/SM +mulch/GMDS +mulct/SGMD +mule/MS +muleskinner/MS +muleteer/MS +mulish/PY +mulishness/M +mull/DSG +mullah/M +mullahs +mullein/M +mullet/MS +mulligan/SM +mulligatawny/M +mullion/SMD +multi +multicolored +multicultural +multiculturalism/M +multidimensional +multidisciplinary +multifaceted +multifamily +multifarious/PY +multifariousness/M +multiform +multigrain +multilateral/Y +multilayered +multilevel +multilingual +multilingualism/M +multimedia/M +multimillionaire/SM +multinational/SM +multiparty +multiplayer/M +multiple/MS +multiplex/ZGMDRS +multiplexer/M +multiplicand/MS +multiplication/M +multiplicative +multiplicity/SM +multiplier/M +multiply/NZGDRSX +multiprocessing +multiprocessor/SM +multipurpose +multiracial +multistage +multistory +multitask/GS +multitasking/M +multitude/SM +multitudinous +multivariate +multiverse/SM +multivitamin/MS +multiyear +mum +mumble/MZGDRS +mumbler/M +mumbletypeg/M +mummer/MS +mummery/M +mummification/M +mummify/GNDS +mummy/SM +mumps/M +mun +munch/GDS +munchies/M +munchkin/SM +mundane/SY +mung/DSG +municipal/SMY +municipality/SM +munificence/M +munificent/Y +munition/MDGS +mural/SM +muralist/SM +murder/ZGMDRS +murderer/M +murderess/MS +murderous/Y +murk/MS +murkily +murkiness/M +murky/PTR +murmur/ZGJMDRS +murmurer/M +murmuring/M +murmurous +murrain/M +muscat/MS +muscatel/SM +muscle/MGDS +musclebound +muscleman +musclemen +muscly +muscular/Y +muscularity/M +musculature/M +muse/MGDSJ +musette/MS +museum/MS +mush/MDRSZG +mushiness/M +mushroom/GSMD +mushy/PTR +music/SM +musical/MYS +musicale/MS +musicality/M +musician/SMY +musicianship/M +musicological +musicologist/MS +musicology/M +musing/MY +musk/M +muskeg/MS +muskellunge/MS +musket/MS +musketeer/MS +musketry/M +muskie/M +muskiness/M +muskmelon/SM +muskox/MN +muskrat/MS +musky/PTRS +muslin/M +muss/MDSG +mussel/MS +mussy/TR +must've +must/MRSZ +mustache/MDS +mustachio/SMD +mustang/MS +mustard/M +muster/GMD +mustily +mustiness/M +mustn't +musty/PTR +mutability/M +mutably +mutagen/MS +mutant/MS +mutate/XGNVDS +mutation/M +mutational +mute/MYTGDRSPB +muteness/M +mutilate/DSGNX +mutilation/M +mutilator/SM +mutineer/SM +mutinous/Y +mutiny/GDSM +mutt/MS +mutter/ZGJMDRS +mutterer/M +muttering/M +mutton/M +muttonchops/M +muttony +mutual/Y +mutuality/M +muumuu/MS +muzak +muzzily +muzzle/DSMG +muzzy/P +my +mycologist/SM +mycology/M +myelitis/M +myna/MS +mynah/MS +myocardial +myocardium +myopia/M +myopic +myopically +myriad/SM +myrmidon/MS +myrrh/M +myrtle/SM +mys +myself +mysterious/PY +mysteriousness/M +mystery/SM +mystic/SM +mystical/Y +mysticism/M +mystification/CM +mystify/CDSGN +mystique/M +myth/M +mythic +mythical +mythological +mythologist/SM +mythologize/DSG +mythology/SM +myths +myxomatosis +métier/MS +mêlée/MS +n/IKTH +naan/S +nab/S +nabbed +nabbing +nabob/SM +nacelle/SM +nacho/SM +nacre/M +nacreous +nadir/SM +nae +naff/RT +nag/SM +nagged +nagger/MS +nagging +nagware +nah +naiad/SM +naif/MS +nail/MDSG +nailbrush/MS +naive/RYT +naivete/M +naivety/M +naiveté/M +naked/PY +nakedness/M +name's +name/AGDS +nameable/U +named/U +namedrop +namedropping/M +nameless/Y +namely +nameplate/MS +namesake/SM +nanny/SM +nanobot/S +nanosecond/SM +nanotechnology/SM +nap/SM +napalm/MDSG +nape/MS +naphtha/M +naphthalene/M +napkin/MS +napless +napoleon/SM +napped +napper/MS +napping +nappy/TRSM +narc/MS +narcissism/M +narcissist/MS +narcissistic +narcissus/M +narcolepsy/M +narcoleptic +narcoses +narcosis/M +narcotic/SM +narcotization/M +narcotize/GDS +nark +narky +narrate/GNVDSX +narration/M +narrative/SM +narrator/SM +narrow/PTGMDRYS +narrowness/M +narwhal/MS +nary +nasal/SMY +nasality/M +nasalization/M +nasalize/DSG +nascence/AM +nascent/A +nastily +nastiness/M +nasturtium/SM +nasty/PTR +natal +natch +nation/MS +national/MYS +nationalism/M +nationalist/SM +nationalistic +nationalistically +nationality/SM +nationalization/MS +nationalize/CDSG +nationhood/M +nationwide +native/MS +nativity/SM +natl +natter/GMDS +nattily +nattiness/M +natty/PTR +natural's +natural/UPY +naturalism/M +naturalist/SM +naturalistic +naturalization/M +naturalize/DSG +naturalness/UM +naturals +nature's +nature/CS +naturism +naturist/S +naught/MS +naughtily +naughtiness/M +naughty/PTR +nausea/M +nauseate/GDS +nauseating/Y +nauseous/PY +nauseousness/M +nautical/Y +nautilus/MS +naval +nave/MS +navel/SM +navigability/M +navigable +navigate/DSGN +navigation/M +navigational +navigator/MS +navvy/S +navy/SM +nay/SM +naysayer/MS +ne'er +neanderthal/MS +neap/MS +near/DRYSPTG +nearby +nearness/M +nearshore +nearside +nearsighted/YP +nearsightedness/M +neat/NRYPXT +neaten/GD +neath +neatness/M +nebula/M +nebulae +nebular +nebulous/PY +nebulousness/M +necessarily/U +necessary/SM +necessitate/DSG +necessitous +necessity/SM +neck/MDSG +neckband/S +neckerchief/MS +necking/M +necklace/MGDSJ +neckline/MS +necktie/MS +necrology/M +necromancer/SM +necromancy/M +necrophilia +necrophiliac/S +necropolis/MS +necroses +necrosis/M +necrotic +nectar/M +nectarine/MS +nee +need/MDSG +needed/U +needful/Y +neediness/M +needle/MGDS +needlepoint/M +needless/YP +needlessness/M +needlewoman/M +needlewomen +needlework/M +needn't +needy/PTR +nefarious/YP +nefariousness/M +neg +negate/DSGNVX +negation/M +negative/MYGPDS +negativeness/M +negativism/M +negativity/M +neglect/SGMD +neglectful/YP +neglectfulness/M +negligee/MS +negligence/M +negligent/Y +negligible +negligibly +negotiability/M +negotiable/A +negotiate/ADSGN +negotiation/AM +negotiations +negotiator/MS +negritude/M +negro +negroid +neigh/MDG +neighbor/SMDYG +neighborhood/SM +neighborliness/M +neighs +neither +nelson/SM +nematode/SM +nemeses +nemesis/M +neoclassic +neoclassical +neoclassicism/M +neocolonialism/M +neocolonialist/MS +neocon/SM +neoconservative/SM +neodymium/M +neolithic +neologism/SM +neon/M +neonatal +neonate/MS +neophilia +neophyte/MS +neoplasm/MS +neoplastic +neoprene/M +nepenthe/M +nephew/SM +nephrite/M +nephritic +nephritis/M +nephropathy +nepotism/M +nepotist/SM +nepotistic +neptunium/M +nerd/MS +nerdy/RT +nerve's +nerve/UDSG +nerveless/YP +nervelessness/M +nerviness/M +nervous/YP +nervousness/M +nervy/TPR +nest/MDSG +nestle/GJDS +nestling/M +net/SM +netball +netbook/MS +nether +nethermost +netherworld/M +netiquette/S +netted +netter/S +netting/M +nettle/MGDS +nettlesome +network/SGMD +networking/M +neural/Y +neuralgia/M +neuralgic +neurasthenia/M +neurasthenic/MS +neuritic/MS +neuritis/M +neurological/Y +neurologist/SM +neurology/M +neuron/MS +neuronal +neuroses +neurosis/M +neurosurgeon/MS +neurosurgery/M +neurosurgical +neurotic/MS +neurotically +neurotransmitter/SM +neut +neuter/MDGS +neutral/SMY +neutralism/M +neutralist/SM +neutrality/M +neutralization/M +neutralize/DRSZG +neutralizer/M +neutrino/SM +neutron/SM +never +nevermore +nevertheless +nevi +nevus/M +new/STMRYP +newbie/MS +newborn/SM +newcomer/SM +newel/SM +newfangled +newfound +newline/S +newlywed/SM +newness/M +news/M +newsagent/S +newsboy/SM +newscast/SMRZ +newscaster/M +newsdealer/SM +newsflash/S +newsgirl/SM +newsgroup/MS +newshound/S +newsletter/MS +newsman/M +newsmen +newspaper/MS +newspaperman/M +newspapermen +newspaperwoman/M +newspaperwomen +newspeak +newsprint/M +newsreader/S +newsreel/MS +newsroom/MS +newsstand/SM +newsweekly/SM +newswoman/M +newswomen +newsworthiness/M +newsworthy/P +newsy/TR +newt/MS +newton/MS +next/M +nexus/MS +niacin/M +nib/SM +nibble/MZGDRS +nibbler/M +nice/PYTR +niceness/M +nicety/SM +niche/SM +nick/MDRSZG +nickel/MS +nickelodeon/SM +nicker/MDG +nickle/S +nickname/DSMG +nicotine/M +niece/SM +niff +niffy +nifty/TR +nigga/SM +niggard/SMY +niggardliness/M +niggaz +nigger/SM! +niggle/MZGDRS +niggler/M +nigh/RT +night/SMY +nightcap/SM +nightclothes/M +nightclub/SM +nightclubbed +nightclubbing +nightdress/MS +nightfall/M +nightgown/SM +nighthawk/SM +nightie/M +nightingale/SM +nightlife/M +nightlight/S +nightlong +nightmare/SM +nightmarish +nightshade/SM +nightshirt/SM +nightspot/MS +nightstand/SM +nightstick/SM +nighttime/M +nightwatchman +nightwatchmen +nightwear/M +nighty/SM +nihilism/M +nihilist/MS +nihilistic +nil/M +nimbi +nimble/TPR +nimbleness/M +nimbly +nimbus/M +nimby +nimrod/MS +nincompoop/SM +nine/MS +ninepin/MS +ninepins/M +nineteen/SMH +nineteenth/M +nineteenths +ninetieth/M +ninetieths +ninety/HSM +ninja/SM +ninny/SM +ninth/M +ninths +niobium/M +nip/SM +nipped +nipper/MS +nippiness/M +nipping +nipple/MS +nippy/TPR +nirvana/M +nisei/M +nit/SMR +nite/MS +niter/M +nitpick/SZGDR +nitpicker/M +nitpicking/M +nitrate/DSMGN +nitration/M +nitrification/M +nitrite/SM +nitro +nitrocellulose/M +nitrogen/M +nitrogenous +nitroglycerin/M +nitroglycerine/M +nitwit/MS +nix/GMDS +no/SM +nob/SY +nobble/GDS +nobelium/M +nobility/M +noble/RSPMT +nobleman/M +noblemen +nobleness/M +noblewoman/M +noblewomen +nobody/SM +nocturnal/Y +nocturne/MS +nod/SM +nodal +nodded +nodding +noddle/MS +noddy +node/MS +nodular +nodule/MS +noel/MS +noes +noggin/MS +nohow +noise/DSMG +noiseless/PY +noiselessness/M +noisemaker/MS +noisily +noisiness/M +noisome +noisy/PTR +nomad/SM +nomadic +nomenclature/MS +nominal/Y +nominate/ACGNVDS +nomination's/A +nomination/CSM +nominative/SM +nominator/CSM +nominee/MS +non +nonabrasive +nonabsorbent/SM +nonacademic +nonacceptance/M +nonacid +nonactive/MS +nonaddictive +nonadhesive +nonadjacent +nonadjustable +nonadministrative +nonage/MS +nonagenarian/MS +nonaggression/M +nonalcoholic +nonaligned +nonalignment/M +nonallergic +nonappearance/MS +nonassignable +nonathletic +nonattendance/M +nonautomotive +nonavailability/M +nonbasic +nonbeliever/MS +nonbelligerent/MS +nonbinding +nonbreakable +nonburnable +noncaloric +noncancerous +nonce/M +nonchalance/M +nonchalant/Y +nonchargeable +nonclerical/MS +nonclinical +noncollectable +noncom/MS +noncombat +noncombatant/MS +noncombustible +noncommercial/MS +noncommittal/Y +noncommunicable +noncompeting +noncompetitive +noncompliance/M +noncomplying +noncomprehending +nonconducting +nonconductor/MS +nonconforming +nonconformism +nonconformist/MS +nonconformity/M +nonconsecutive +nonconstructive +noncontagious +noncontinuous +noncontributing +noncontributory +noncontroversial +nonconvertible +noncooperation/M +noncorroding +noncorrosive +noncredit +noncriminal/SM +noncritical +noncrystalline +noncumulative +noncustodial +nondairy +nondeductible/M +nondelivery/SM +nondemocratic +nondenominational +nondepartmental +nondepreciating +nondescript +nondestructive +nondetachable +nondisciplinary +nondisclosure/M +nondiscrimination/M +nondiscriminatory +nondramatic +nondrinker/MS +nondrying +none +noneducational +noneffective +nonelastic +nonelectric +nonelectrical +nonempty +nonenforceable +nonentity/SM +nonequivalent/MS +nonessential +nonesuch/MS +nonetheless +nonevent/MS +nonexchangeable +nonexclusive +nonexempt/M +nonexistence/M +nonexistent +nonexplosive/MS +nonfactual +nonfading +nonfat +nonfatal +nonfattening +nonferrous +nonfiction/M +nonfictional +nonflammable +nonflowering +nonfluctuating +nonflying +nonfood/M +nonfreezing +nonfunctional +nongovernmental +nongranular +nonhazardous +nonhereditary +nonhuman +nonidentical +noninclusive +nonindependent +nonindustrial +noninfectious +noninflammatory +noninflationary +noninflected +nonintellectual/MS +noninterchangeable +noninterference/M +nonintervention/M +nonintoxicating +noninvasive +nonirritating +nonissue +nonjudgmental +nonjudicial +nonlegal +nonlethal +nonlinear +nonliterary +nonliving/M +nonmagnetic +nonmalignant +nonmember/MS +nonmetal/SM +nonmetallic +nonmigratory +nonmilitant +nonmilitary +nonnarcotic/SM +nonnative/MS +nonnegotiable +nonnuclear +nonnumerical +nonobjective +nonobligatory +nonobservance/M +nonobservant +nonoccupational +nonoccurence +nonofficial +nonoperational +nonoperative +nonparallel/MS +nonpareil/MS +nonparticipant/MS +nonparticipating +nonpartisan/SM +nonpaying +nonpayment/SM +nonperformance/M +nonperforming +nonperishable +nonperson/MS +nonphysical/Y +nonplus/S +nonplussed +nonplussing +nonpoisonous +nonpolitical +nonpolluting +nonporous +nonpracticing +nonprejudicial +nonprescription +nonproductive +nonprofessional/SM +nonprofit/SMB +nonproliferation/M +nonpublic +nonpunishable +nonracial +nonradioactive +nonrandom +nonreactive +nonreciprocal/SM +nonreciprocating +nonrecognition/M +nonrecoverable +nonrecurring +nonredeemable +nonrefillable +nonrefundable +nonreligious +nonrenewable +nonrepresentational +nonresident/MS +nonresidential +nonresidual/M +nonresistance/M +nonresistant +nonrestrictive +nonreturnable/MS +nonrhythmic +nonrigid +nonsalaried +nonscheduled +nonscientific +nonscoring +nonseasonal +nonsectarian +nonsecular +nonsegregated +nonsense/M +nonsensical/Y +nonsensitive +nonsexist +nonsexual +nonskid +nonslip +nonsmoker/SM +nonsmoking +nonsocial +nonspeaking +nonspecialist/MS +nonspecializing +nonspecific +nonspiritual/SM +nonstaining +nonstandard +nonstarter/MS +nonstick +nonstop +nonstrategic +nonstriking +nonstructural +nonsuccessive +nonsupport/GM +nonsurgical +nonsustaining +nonsympathizer/M +nontarnishable +nontaxable +nontechnical +nontenured +nontheatrical +nonthinking +nonthreatening +nontoxic +nontraditional +nontransferable +nontransparent +nontrivial +nontropical +nonuniform +nonunion +nonuser/MS +nonvenomous +nonverbal +nonviable +nonviolence/M +nonviolent/Y +nonvirulent +nonvocal +nonvocational +nonvolatile +nonvoter/MS +nonvoting +nonwhite/MS +nonworking +nonyielding +nonzero +noodle/MGDS +nook/MS +nookie +nooky +noon/M +noonday/M +noontide/M +noontime/M +noose/SM +nope +nor +nor'easter +norm/MS +normal/MY +normalcy/M +normality/M +normalization/M +normalize/DSG +normative +north/ZMR +northbound +northeast/MRZ +northeaster/MY +northeastern +northeastward/S +norther/MY +northerly/SM +northern/ZR +northerner/M +northernmost +northward/S +northwest/ZMR +northwester/MY +northwestern +northwestward/S +nose/MGDS +nosebag/S +nosebleed/MS +nosecone/SM +nosedive/DSMG +nosegay/SM +nosh/MDRSZG +nosher/M +nosily +nosiness/M +nostalgia/M +nostalgic +nostalgically +nostril/MS +nostrum/MS +nosy/RPT +not/B +notability/SM +notable/SM +notably +notarial +notarization/M +notarize/GDS +notary/SM +notate/GDS +notation/FCSM +notch/GMDS +note's +note/FCSDG +notebook/MS +notelet/S +notepad/S +notepaper/M +noteworthiness/M +noteworthy/P +nothing/PSM +nothingness/M +notice/MGDS +noticeable/U +noticeably +noticeboard/S +noticed/U +notifiable +notification/M +notifier/M +notify/NDRSXZG +notion/MS +notional/Y +notoriety/M +notorious/Y +notwithstanding +notwork/S +nougat/MS +nought/MS +noun/KMS +nourish/DSLG +nourishment/M +nous +nova/MS +novae +novel/SM +novelette/SM +novelist/SM +novelization/MS +novelize/DSG +novella/MS +novelty/SM +novena/MS +novene +novice/MS +novitiate/MS +now/M +nowadays/M +noway/S +nowhere/M +nowise +nowt +noxious +nozzle/MS +nu/SM +nuance/MDS +nub/SM +nubbin/MS +nubby/TR +nubile +nuclear/K +nucleate/DSGN +nucleation/M +nuclei +nucleic +nucleoli +nucleolus/M +nucleon/SM +nucleoside +nucleotide +nucleus/M +nude/MTRS +nudge/GDSM +nudism/M +nudist/SM +nudity/M +nugatory +nugget/SM +nuisance/MS +nuke/MGDS +null/S +nullification/M +nullify/NDSG +nullity/M +numb/ZTGPDRYS +number's +number/ASDG +numbered/U +numberless +numbness/M +numbskull/SM +numerable/I +numeracy/IM +numeral/SM +numerate/XGNDS +numeration/M +numerator/MS +numeric +numerical/Y +numerologist/MS +numerology/M +numerous/Y +numinous +numismatic/S +numismatics/M +numismatist/SM +numskull/MS +nun/SM +nuncio/SM +nunnery/SM +nuptial/MS +nurse/MZGDRS +nurselings +nursemaid/MS +nurser/M +nursery/SM +nurseryman/M +nurserymen +nursing/M +nursling/SM +nurture/DRSMZG +nurturer/M +nut/SM +nutcase/S +nutcracker/MS +nuthatch/MS +nuthouse/S +nutmeat/SM +nutmeg/SM +nutpick/SM +nutria/SM +nutrient/MS +nutriment/MS +nutrition/M +nutritional/Y +nutritionist/SM +nutritious/YP +nutritiousness/M +nutritive +nutshell/MS +nutted +nutter/S +nuttiness/M +nutting +nutty/RTP +nuzzle/DRSMZG +nuzzler/M +nybble/S +nylon/MS +nylons/M +nymph/M +nymphet/MS +nympho/S +nymphomania/M +nymphomaniac/SM +nymphs +née +o +o'clock +o'er +oaf/SM +oafish/PY +oafishness/M +oak/SMN +oakum/M +oar/SGMD +oarlock/SM +oarsman/M +oarsmen +oarswoman/M +oarswomen +oases +oasis/M +oat/SMN +oatcake/SM +oath/M +oaths +oatmeal/M +oats/M +ob/S +obbligato/MS +obduracy/M +obdurate/PY +obdurateness/M +obedience/EM +obedient/EY +obeisance/SM +obeisant +obelisk/MS +obese +obesity/M +obey/EDSG +obfuscate/GNXDS +obfuscation/M +obi/SM +obit/MS +obituary/SM +obj +object/SGVMD +objectify/NGDS +objection/SMB +objectionable/U +objectionably +objective/SMYP +objectiveness/M +objectivity/M +objector/MS +objurgate/XGNDS +objurgation/M +oblate/NX +oblation/M +obligate/DSXGN +obligation/M +obligatorily +obligatory +oblige/EGDS +obliging/Y +oblique/SMYP +obliqueness/M +obliquity/M +obliterate/DSGN +obliteration/M +oblivion/M +oblivious/YP +obliviousness/M +oblong/MS +obloquy/M +obnoxious/YP +obnoxiousness/M +oboe/MS +oboist/MS +obscene/RYT +obscenity/SM +obscurantism/M +obscurantist/SM +obscure/DRSYTG +obscurity/SM +obsequies +obsequious/PY +obsequiousness/M +obsequy/M +observably +observance/MS +observant/Y +observation/SM +observational +observatory/SM +observe/DRSBZG +observed/U +observer/M +obsess/DSGV +obsession/SM +obsessional/Y +obsessive/PSMY +obsessiveness/M +obsidian/M +obsolesce/DSG +obsolescence/M +obsolescent +obsolete/GDS +obstacle/MS +obstetric/S +obstetrical +obstetrician/SM +obstetrics/M +obstinacy/M +obstinate/Y +obstreperous/YP +obstreperousness/M +obstruct/DGVS +obstructed/U +obstruction/SM +obstructionism/M +obstructionist/MS +obstructive/YP +obstructiveness/M +obtain/DBLGS +obtainable/U +obtainment/M +obtrude/DSG +obtrusion/M +obtrusive/UPY +obtrusiveness/UM +obtuse/YTRP +obtuseness/M +obverse/SM +obviate/DSGN +obviation/M +obvious/PY +obviousness/M +ocarina/MS +occasion/GMDS +occasional/Y +occidental/SM +occlude/GDS +occlusion/SM +occlusive +occult/M +occultism/M +occultist/SM +occupancy/M +occupant/SM +occupation/AM +occupational/Y +occupations +occupied/U +occupier/SM +occupy/ADSG +occur/AS +occurred/A +occurrence/SM +occurring/A +ocean/SM +oceanfront/SM +oceangoing +oceanic/M +oceanographer/SM +oceanographic +oceanography/M +oceanology/M +ocelot/MS +och/R +ocher/M +ocker/S +octagon/MS +octagonal +octal +octane/MS +octave/MS +octavo/MS +octet/SM +octogenarian/SM +octopus/MS +ocular/MS +oculist/SM +odalisque/SM +odd/STRYLP +oddball/SM +oddity/SM +oddment/SM +oddness/M +odds/M +ode/SM +odious/YP +odiousness/M +odium/M +odometer/MS +odor/MDS +odoriferous +odorless +odorous +odyssey/MS +oedipal +oenology/M +oenophile/SM +oeuvre/MS +of +off/SZGDRJ +offal/M +offbeat/MS +offend/ZGDRS +offender/M +offense/MS +offensive's +offensive/IPY +offensiveness/IM +offensives +offer/JGMD +offering/M +offertory/SM +offhand +offhanded/PY +offhandedness/M +office/MZRS +officeholder/SM +officer/M +official/MYS +officialdom/M +officialese +officialism/M +officiant/SM +officiate/DSG +officiator/MS +officious/PY +officiousness/M +offing/M +offish +offline +offload/SDG +offprint/SM +offset/MS +offsetting +offshoot/MS +offshore/G +offside +offsite +offspring/M +offstage/S +offtrack +oft +often/TR +oftentimes +ofttimes +ogle/MZGDRS +ogler/M +ogre/MS +ogreish +ogress/MS +oh/M +ohm/SM +ohmmeter/MS +oho +ohs +oi +oik/S +oil/SGMD +oilcan/S +oilcloth/M +oilcloths +oilfield/S +oiliness/M +oilman +oilmen +oilskin/MS +oilskins/M +oily/RPT +oink/MDSG +ointment/SM +okapi/SM +okay/MDSG +okra/MS +old/TMNRP +oldie/SM +oldish +oldness/M +oldster/MS +ole/SMV +oleaginous +oleander/MS +oleo/M +oleomargarine/M +olfactory/SM +oligarch/M +oligarchic +oligarchical +oligarchs +oligarchy/SM +oligonucleotide/S +oligopoly/SM +olive/SM +olé/M +om/SMNX +ombudsman/M +ombudsmen +omega/SM +omelet/MS +omelette/MS +omen/M +omicron/MS +ominous/YP +ominousness/M +omission/MS +omit/S +omitted +omitting +omnibus/MS +omnipotence/M +omnipotent +omnipresence/M +omnipresent +omniscience/M +omniscient +omnivore/MS +omnivorous/PY +omnivorousness/M +on/Y +once/M +oncogene/SM +oncologist/SM +oncology/M +oncoming +one/SXMNP +oneness/M +onerous/PY +onerousness/M +oneself +onetime +ongoing +onion/M +onionskin/M +online +onlooker/SM +onlooking +onomatopoeia/M +onomatopoeic +onomatopoetic +onrush/MSG +onscreen +onset/MS +onshore +onside +onsite +onslaught/MS +onstage +onto +ontogeny/M +ontological +ontology/M +onus/MS +onward +onyx/MS +oodles/M +ooh/GD +oohs +oomph +oops +ooze/MGDS +oozy/TR +op/SMDG +opacity/M +opal/MS +opalescence/M +opalescent +opaque/PYTGDRS +opaqueness/M +opcode/S +ope/S +open/ZTGJPMDRYS +opencast +opened/U +opener/M +openhanded/P +openhandedness/M +openhearted +opening/M +openness/M +openwork/M +opera/MS +operable/I +operand/S +operate/DSGNVX +operatic +operatically +operation/M +operational/Y +operative/SM +operator/SM +operetta/SM +ophthalmic +ophthalmologist/SM +ophthalmology/M +opiate/SM +opine/GNXDS +opinion/M +opinionated +opium/M +opossum/MS +opp +opponent/SM +opportune/IY +opportunism/M +opportunist/SM +opportunistic +opportunistically +opportunity/SM +oppose/DSG +opposed/U +opposite/SMYNX +opposition/M +oppress/DSGV +oppression/M +oppressive/YP +oppressiveness/M +oppressor/MS +opprobrious/Y +opprobrium/M +opt/SGD +optic/MS +optical/Y +optician/SM +optics/M +optima +optimal/Y +optimism/SM +optimist/SM +optimistic +optimistically +optimization/MS +optimize/DRSG +optimum/SM +option/SMDG +optional/Y +optometrist/MS +optometry/M +opulence/M +opulent/Y +opus/MS +or +oracle/SM +oracular +oral/MYS +orange/SMP +orangeade/MS +orangery/SM +orangutan/SM +orate/GNXDS +oration/M +orator/SM +oratorical/Y +oratorio/MS +oratory/SM +orb/SM +orbicular +orbit/MDRZGS +orbital/SM +orbiter/M +orc/SM +orchard/SM +orchestra/MS +orchestral +orchestrate/DSXGN +orchestration/M +orchid/SM +ordain/SDLG +ordainment/M +ordeal/SM +order/EAMDGS +orderings +orderliness/EM +orderly/PSM +ordinal/SM +ordinance/SM +ordinarily +ordinariness/M +ordinary/SMP +ordinate/MNSX +ordination/M +ordnance/M +ordure/M +ore/SM +oregano/M +org +organ/MS +organdy/M +organelle/MS +organic/SM +organically/I +organism/MS +organismic +organist/MS +organization/ASM +organizational/Y +organize/AESDG +organized/U +organizer/MS +organza/M +orgasm/SM +orgasmic +orgiastic +orgy/SM +oriel/MS +orient's +orient/AEDGS +oriental/MS +orientalist/S +orientate/EDSGN +orientation/AEM +orientations +orienteering +orifice/MS +orig +origami/M +origin/SM +original/MYS +originality/M +originate/DSGN +origination/M +originator/SM +oriole/SM +orison/SM +ormolu/M +ornament/SGMD +ornamental +ornamentation/M +ornate/YP +ornateness/M +orneriness/M +ornery/PRT +ornithological +ornithologist/MS +ornithology/M +orotund +orotundity/SM +orphan/SMDG +orphanage/MS +orris/MS +orthodontia/M +orthodontic/S +orthodontics/M +orthodontist/SM +orthodox/U +orthodoxy/SM +orthogonal +orthogonality +orthographic +orthographically +orthography/SM +orthopedic/S +orthopedics/M +orthopedist/MS +orzo/M +oscillate/GNDSX +oscillation/M +oscillator/SM +oscillatory +oscilloscope/MS +osculate/DSXGN +osculation/M +osier/MS +osmium/M +osmosis/M +osmotic +osprey/SM +ossification/M +ossify/NGDS +ostensible +ostensibly +ostentation/M +ostentatious/Y +osteoarthritis/M +osteopath/M +osteopathic +osteopaths +osteopathy/M +osteoporosis/M +ostler/S +ostracism/M +ostracize/GDS +ostrich/MS +other/MSP +otherwise +otherworldly +otiose +otter/MS +ottoman/MS +oubliette/MS +ouch +ought +oughtn't +ounce/MS +our/S +ourselves +oust/ZGDRS +ouster/M +out/SJGMDR +outage/SM +outargue/GDS +outback/MS +outbalance/DSG +outbid/S +outbidding +outboard/MS +outboast/DSG +outbound +outbox/MS +outbreak/MS +outbuilding/MS +outburst/SM +outcast/MS +outclass/DSG +outcome/MS +outcrop/MS +outcropped +outcropping/SM +outcry/SM +outdated +outdid +outdistance/GDS +outdo/G +outdoes +outdone +outdoor/S +outdoors/M +outdoorsy +outdraw/GS +outdrawn +outdrew +outermost +outerwear/M +outface/GDS +outfall/S +outfield/SMRZ +outfielder/M +outfight/SG +outfit/SM +outfitted +outfitter/MS +outfitting +outflank/GSD +outflow/MS +outfought +outfox/GDS +outgo/MJG +outgoes +outgrew +outgrow/HGS +outgrown +outgrowth/M +outgrowths +outguess/GDS +outgun/S +outgunned +outgunning +outhit/S +outhitting +outhouse/SM +outing/M +outlaid +outlandish/PY +outlandishness/M +outlast/DSG +outlaw/SGMD +outlay/SGM +outlet/SM +outlier/S +outline/MGDS +outlive/GDS +outlook/MS +outlying +outmaneuver/GDS +outmatch/GDS +outmoded +outnumber/DSG +outpace/GDS +outpatient/MS +outperform/GSD +outplace/L +outplacement/M +outplay/GDS +outpoint/DGS +outpost/MS +outpouring/MS +outproduce/DSG +output/SM +outputted +outputting +outrace/GDS +outrage/MGDS +outrageous/Y +outran +outrank/GDS +outre +outreach/MDSG +outrider/MS +outrigger/SM +outright +outrun/S +outrunning +outré +outscore/GDS +outsell/GS +outset/SM +outshine/GS +outshone +outshout/GDS +outside/MZRS +outsider/M +outsize/MS +outskirt/MS +outsmart/GDS +outsold +outsource/DSG +outsourcing/M +outspend/SG +outspent +outspoken/YP +outspokenness/M +outspread/GS +outstanding/Y +outstation/MS +outstay/DGS +outstretch/DSG +outstrip/S +outstripped +outstripping +outta +outtake/MS +outvote/GDS +outward/YS +outwear/GS +outweigh/GD +outweighs +outwit/S +outwith +outwitted +outwitting +outwore +outwork/MDRSZG +outworn +ouzo/MS +ova +oval/MS +ovarian +ovary/SM +ovate/NX +ovation/M +oven/MS +ovenbird/SM +ovenproof +ovenware +over/MYS +overabundance/M +overabundant +overachieve/ZGDRS +overachiever/M +overact/GVSD +overage/SM +overaggressive +overall/SM +overalls/M +overambitious +overanxious +overarching +overarm/GSD +overate +overattentive +overawe/DSG +overbalance/MGDS +overbear/GS +overbearing/Y +overbid/SM +overbidding +overbite/MS +overblown +overboard +overbold +overbook/DGS +overbore +overborne +overbought +overbuild/SG +overbuilt +overburden/GSD +overbuy/GS +overcame +overcapacity/M +overcapitalize/DSG +overcareful +overcast/MGS +overcautious +overcharge/DSMG +overclock/GD +overcloud/SGD +overcoat/MS +overcome/GS +overcompensate/DSGN +overcompensation/M +overconfidence/M +overconfident +overconscientious +overcook/DGS +overcritical +overcrowd/SDG +overcrowding/M +overdecorate/DSG +overdependent +overdevelop/SDG +overdid +overdo/G +overdoes +overdone +overdose/MGDS +overdraft/SM +overdraw/GS +overdrawn +overdress/GMDS +overdrew +overdrive/SM +overdub/SM +overdubbed +overdubbing +overdue +overeager +overeat/GSN +overemotional +overemphasis/M +overemphasize/GDS +overenthusiastic +overestimate/MGNDS +overestimation/M +overexcite/DSG +overexercise/GDS +overexert/SDG +overexertion/M +overexpose/GDS +overexposure/M +overextend/DGS +overfed +overfeed/GS +overfill/DGS +overflew +overflight/MS +overflow/MDSG +overflown +overfly/GS +overfond +overfull +overgeneralize/DSG +overgenerous +overgraze/DSG +overgrew +overground +overgrow/HSG +overgrown +overgrowth/M +overhand/MDS +overhang/MSG +overhasty +overhaul/MDSG +overhead/MS +overhear/SG +overheard +overheat/DSG +overhung +overindulge/GDS +overindulgence/M +overindulgent +overjoy/GSD +overkill/M +overladen +overlaid +overlain +overland +overlap/SM +overlapped +overlapping +overlarge +overlay/GSM +overleaf +overlie +overload/GMDS +overlong +overlook/GMDS +overlord/MS +overly/SG +overmanned +overmanning +overmaster/SDG +overmodest +overmuch/S +overnice +overnight/MS +overoptimism/M +overoptimistic +overpaid +overparticular +overpass/MS +overpay/GS +overplay/GDS +overpopulate/GNDS +overpopulation/M +overpower/SDG +overpowering/Y +overpraise/DSG +overprecise +overprice/DSG +overprint/SMDG +overproduce/GDS +overproduction/M +overprotect/SDGV +overqualified +overran +overrate/GDS +overreach/GDS +overreact/SDG +overreaction/SM +overrefined +overridden +override/MGS +overripe/M +overrode +overrule/GDS +overrun/SM +overrunning +oversampling +oversaw +oversea/S +oversee/RSZ +overseeing +overseen +overseer/M +oversell/GS +oversensitive/P +oversensitiveness/M +oversexed +overshadow/DSG +overshare/DSG +overshoe/MS +overshoot/GS +overshot +oversight/SM +oversimple +oversimplification/M +oversimplify/DSNGX +oversize/D +oversleep/GS +overslept +oversold +overspecialization/M +overspecialize/GDS +overspend/SG +overspent +overspread/GS +overstaffed +overstate/DSLG +overstatement/MS +overstay/DSG +overstep/S +overstepped +overstepping +overstimulate/DSG +overstock/GSD +overstretch/GDS +overstrict +overstrung +overstuffed +oversubscribe/DSG +oversubtle +oversupply/GDS +oversuspicious +overt/Y +overtake/GS +overtaken +overtax/GDS +overthink/SG +overthought +overthrew +overthrow/SMG +overthrown +overtime/MS +overtire/GDS +overtone/MS +overtook +overture/MS +overturn/DSG +overuse/DSMG +overvaluation/S +overvalue/DSG +overview/MS +overweening/Y +overweight/M +overwhelm/SGD +overwhelming/Y +overwinter/SDG +overwork/GMDS +overwrite/GS +overwritten +overwrote +overwrought +overzealous +oviduct/SM +oviparous +ovoid/MS +ovular +ovulate/DSGN +ovulation/M +ovule/MS +ovum/M +ow +owe/DSG +owl/SM +owlet/MS +owlish/Y +own/ESGD +owner/MS +ownership/M +ox/MN +oxblood/M +oxbow/MS +oxcart/SM +oxford/SM +oxidant/MS +oxidase +oxidation/M +oxide/MS +oxidization/M +oxidize/ZGDRS +oxidizer/M +oxtail/S +oxyacetylene/M +oxygen/M +oxygenate/DSGN +oxygenation/M +oxymora +oxymoron/M +oyster/SM +oz +ozone/M +p/NRXTGJ +pH +pa/SMH +pablum/M +pabulum/M +pace/MZGDRS +pacemaker/SM +pacer/M +pacesetter/SM +pacey +pachyderm/MS +pachysandra/MS +pacific +pacifically +pacification/M +pacifier/M +pacifism/M +pacifist/SM +pacifistic +pacify/ZGDRSN +pack's +pack/AUGSD +package's +package/AGDS +packager/SM +packaging/M +packer/MS +packet/MS +packing's +packinghouse/SM +packsaddle/MS +pact/MS +pacy/RT +pad/SM +padded +padding/M +paddle/MZGDRS +paddler/M +paddock/MDGS +paddy/SM +padlock/MDSG +padre/SM +paean/SM +paella/MS +pagan/SM +paganism/M +page/MZGDRS +pageant/MS +pageantry/M +pageboy/SM +pager/M +paginate/DSGN +pagination/M +pagoda/MS +pah +paid/AU +pail/MS +pailful/SM +pain/MDSG +painful/PY +painfuller +painfullest +painfulness/M +painkiller/MS +painkilling +painless/PY +painlessness/M +painstaking/MY +paint/SZGJMDR +paintball +paintbox/MS +paintbrush/MS +painted/U +painter/MY +painting/M +paintwork +pair/AMDSG +paired/U +pairing/S +pairwise +paisley/SM +pajama/S +pajamas/M +pal/SMY +palace/MS +paladin/SM +palanquin/SM +palatable/U +palatal/SM +palatalization/M +palatalize/GDS +palate/MBS +palatial/Y +palatinate/MS +palatine/MS +palaver/GSMD +palazzi +palazzo +pale/MYTGPDRSJ +paleface/MS +paleness/M +paleographer/MS +paleography/M +paleolithic +paleontologist/SM +paleontology/M +palette/SM +palfrey/SM +palimony/M +palimpsest/MS +palindrome/MS +palindromic +paling/M +palisade/SM +palish +pall/MDSG +palladium/M +pallbearer/MS +pallet/MS +palliate/DSGNV +palliation/M +palliative/SM +pallid/YP +pallidness/M +pallor/M +palm/MDSG +palmate +palmetto/SM +palmist/SM +palmistry/M +palmtop/SM +palmy/TR +palomino/MS +palpable +palpably +palpate/DSGN +palpation/M +palpitate/XGNDS +palpitation/M +palsy/GDSM +paltriness/M +paltry/RPT +pampas/M +pamper/DSG +pamphlet/MS +pamphleteer/MS +pan/SM +panacea/SM +panache/M +panama/MS +panatella/S +pancake/DSMG +panchromatic +pancreas/MS +pancreatic +pancreatitis +panda/SM +pandemic/SM +pandemonium/M +pander/MDRZGS +panderer/M +pane/KM +panegyric/SM +panel/SGJMD +paneling/M +panelist/MS +panes +pang/MS +panhandle/DRSMZG +panhandler/M +panic/SM +panicked +panicking +panicky +panned +pannier/SM +panning +panoply/SM +panorama/SM +panoramic +panpipes/M +pansy/SM +pant/MDSG +pantaloons/M +pantechnicon/S +pantheism/M +pantheist/SM +pantheistic +pantheon/SM +panther/MS +pantie/M +panto/S +pantomime/MGDS +pantomimic +pantomimist/SM +pantry/SM +pantsuit/SM +panty/SM +pantyhose/M +pantyliner/M +pantywaist/SM +pap/SM +papa/MS +papacy/SM +papal +paparazzi/M +paparazzo +papaw/SM +papaya/MS +paper/SZGMDR +paperback/SM +paperbark/S +paperboard/M +paperboy/SM +paperclip/S +paperer/M +papergirl/SM +paperhanger/SM +paperhanging/M +paperless +paperweight/MS +paperwork/M +papery +papilla/M +papillae +papillary +papist/MS +papoose/MS +pappy/SM +paprika/M +papyri +papyrus/M +par/SZGMDRBJ +para/MS +parable/MS +parabola/SM +parabolic +paracetamol/S +parachute/DSMG +parachutist/MS +parade/MZGDRS +parader/M +paradigm/SM +paradigmatic +paradisaical +paradise/SM +paradox/MS +paradoxical/Y +paraffin/M +paragliding +paragon/MS +paragraph/GMD +paragraphs +parakeet/SM +paralegal/MS +parallax/MS +parallel/SGMD +paralleled/U +parallelism/MS +parallelogram/SM +paralyses +paralysis/M +paralytic/SM +paralyze/DSG +paralyzing/Y +paramecia +paramecium/M +paramedic/MS +paramedical/MS +parameter/MS +parametric +paramilitary/SM +paramount +paramountcy +paramour/SM +paranoia/M +paranoiac/MS +paranoid/SM +paranormal +parapet/MS +paraphernalia/M +paraphrase/DSMG +paraplegia/M +paraplegic/SM +paraprofessional/MS +parapsychologist/MS +parapsychology/M +paraquat/M +parasailing +parascending +parasite/SM +parasitic +parasitical/Y +parasitism/M +parasol/MS +parasympathetic/S +parathion/M +parathyroid/MS +paratroop/RZS +paratrooper/M +paratroops/M +paratyphoid/M +parboil/DSG +parcel/GMDS +parch/LGDS +parchment/SM +pardner/S +pardon/ZGMDRBS +pardonable/U +pardonably/U +pardoner/M +pare/S +paregoric/M +parent/GMDS +parentage/M +parental +parentheses +parenthesis/M +parenthesize/DSG +parenthetic +parenthetical/Y +parenthood/M +parenting/M +parer/M +pares/S +paresis/M +parfait/MS +pariah/M +pariahs +parietal +parimutuel/MS +paring/M +parish/MS +parishioner/MS +parity/ESM +park/MDSG +parka/SM +parking/M +parkland +parkour +parkway/MS +parky +parlance/M +parlay/GMDS +parley/GMDS +parliament/SM +parliamentarian/SM +parliamentary +parlor/MS +parlous +parmigiana +parmigiano +parochial/Y +parochialism/M +parodist/SM +parody/GDSM +parole/MGDS +parolee/MS +parotid +paroxysm/SM +paroxysmal +parquet/MDSG +parquetry/M +parred +parricidal +parricide/MS +parring +parrot/GMDS +parry/GDSM +parse/DRSG +parsec/MS +parsimonious/Y +parsimony/M +parsley/M +parsnip/MS +parson/MS +parsonage/MS +part's +part/CDSG +partake/ZGRS +partaken +partaker/M +parterre/SM +parthenogenesis/M +partial/MYS +partiality/M +participant/SM +participate/DSGN +participation/M +participator/MS +participatory +participial/M +participle/MS +particle/SM +particleboard/M +particular/SMY +particularity/SM +particularization/M +particularize/DSG +particulate/SM +parting/MS +partisan/SM +partisanship/M +partition/GMDS +partitive/MS +partizan/SM +partly +partner/MDSG +partnership/MS +partook +partridge/SM +parturition/M +partway +party/GDSM +parvenu/MS +pascal/MS +paschal +pasha/SM +pass/M +passably +passage/MS +passageway/MS +passbook/MS +passe/DRSBXZGNV +passel/MS +passenger/SM +passer/M +passerby/M +passersby +passim +passing/MY +passion/EM +passionate/EY +passionflower/SM +passionless +passive/PMYS +passiveness/M +passivity/M +passivization +passivize/DSG +passkey/MS +passphrase/S +passport/MS +password/MS +passé +past/AMS +pasta/SM +paste/DSMG +pasteboard/M +pastel/MS +pastern/MS +pasteurization/M +pasteurize/ZGDRS +pasteurized/U +pasteurizer/M +pastiche/MS +pastie +pastille/MS +pastime/MS +pastiness/M +pastor/MS +pastoral/MS +pastorate/MS +pastrami/M +pastry/SM +pasturage/M +pasture/DSMG +pastureland/M +pasty/PTRSM +pat/SM +patch/EGMDS +patchily +patchiness/M +patchouli +patchwork/SM +patchy/TPR +pate/MS +patella/MS +patellae +patent/GMDYS +paterfamilias/MS +paternal/Y +paternalism/M +paternalist/S +paternalistic +paternity/M +paternoster/MS +path/M +pathetic +pathetically +pathfinder/SM +pathless +pathogen/SM +pathogenic +pathological/Y +pathologist/SM +pathology/M +pathos/M +paths +pathway/MS +patience/M +patient/IMST +patienter +patiently +patina/MS +patine +patio/SM +patisserie/S +patois/M +patresfamilias +patriarch/M +patriarchal +patriarchate/MS +patriarchs +patriarchy/SM +patrician/SM +patricide/SM +patrimonial +patrimony/SM +patriot/SM +patriotic/U +patriotically +patriotism/M +patrol/MS +patrolled +patrolling +patrolman/M +patrolmen +patrolwoman/M +patrolwomen +patron/MS +patronage/MS +patroness/MS +patronize/ZGDRS +patronizer/M +patronizing/Y +patronymic/SM +patronymically +patroon/SM +patsy/SM +patted +patter/MDGS +pattern/SMDG +patting +patty/SM +paucity/M +paunch/MS +paunchy/RT +pauper/MS +pauperism/M +pauperize/DSG +pause/DSMG +pave/AGDS +paved/U +pavement/MS +pavilion/SM +paving/MS +pavlova/S +paw/SGMD +pawl/MS +pawn/MDSG +pawnbroker/MS +pawnbroking/M +pawnshop/MS +pawpaw/MS +pay's +pay/ASGBL +payback/SM +paycheck/MS +payday/MS +payed +payee/SM +payer/SM +payload/SM +paymaster/SM +payment/ASM +payoff/MS +payola/M +payout/MS +payphone/S +payroll/SM +payslip/SM +paywall/SM +payware +pct +pd +pea/SM +peace/SM +peaceable +peaceably +peaceful/PY +peacefulness/M +peacekeeper/SM +peacekeeping/M +peacemaker/MS +peacemaking/M +peacetime/M +peach/MS +peachy/TR +peacock/MS +peafowl/MS +peahen/MS +peak/MDSG +peaky +peal/AMDSG +peanut/MS +pear/MYS +pearl/SGMD +pearly/RT +peasant/SM +peasantry/M +peashooter/SM +peat/M +peaty/TR +pebble/MGDS +pebbly +pecan/SM +peccadillo/M +peccadilloes +peccary/SM +peck/MDRSZG +peckish +pecs +pectic +pectin/M +pectoral/MS +peculate/GNDS +peculation/M +peculator/SM +peculiar/Y +peculiarity/SM +pecuniary +pedagogic +pedagogical/Y +pedagogue/SM +pedagogy/M +pedal/SGMD +pedalo/S +pedant/MS +pedantic +pedantically +pedantry/M +peddle/ZGDRS +peddler/M +pederast/MS +pederasty/M +pedestal/MS +pedestrian/SM +pedestrianization +pedestrianize/GDS +pediatric/S +pediatrician/MS +pediatrics/M +pedicab/SM +pedicure/MGDS +pedicurist/MS +pedigree/MDS +pediment/MS +pedometer/MS +pedophile/S +pedophilia +peduncle/MS +pee/DRSMZ +peeing +peek/MDSG +peekaboo/M +peel/MDRSJZG +peeled/U +peeler/M +peeling/M +peen/MS +peep/MDRSZG +peepbo +peeper/M +peephole/MS +peepshow/MS +peer/MDG +peerage/SM +peeress/MS +peerless +peeve/DSMG +peevish/PY +peevishness/M +peewee/MS +peewit/S +peg/SM +pegboard/MS +pegged +pegging +peignoir/SM +pejoration/M +pejorative/SMY +peke/MS +pekinese/SM +pekingese/SM +pekoe/M +pelagic +pelf/M +pelican/MS +pellagra/M +pellet/GMDS +pellucid +pelmet/S +pelt/MDSG +pelvic +pelvis/MS +pemmican/M +pen/M +penal +penalization/M +penalize/DSG +penalty/SM +penance/MS +pence +penchant/SM +pencil/GMDJS +pend/CDSG +pendant/MS +pendent/MS +pendulous +pendulum/MS +penetrability/M +penetrable +penetrate/DSGNVX +penetrating/Y +penetration/M +penfriend/S +penguin/MS +penicillin/M +penile +peninsula/SM +peninsular +penis/MS +penitence/M +penitent/SMY +penitential +penitentiary/SM +penknife/M +penknives +penlight/SM +penman/M +penmanship/M +penmen +pennant/MS +penned +penniless +penning +pennon/MS +penny/SM +pennyweight/MS +pennyworth +penologist/MS +penology/M +pension/BZGMDRS +pensioner/M +pensive/PY +pensiveness/M +pent +pentacle/MS +pentagon/MS +pentagonal +pentagram/SM +pentameter/SM +pentathlete/MS +pentathlon/MS +penthouse/SM +penuche/M +penultimate/SM +penumbra/MS +penumbrae +penurious/PY +penuriousness/M +penury/M +peon/MS +peonage/M +peony/SM +people/MGDS +pep/SM +pepped +pepper/GMDS +peppercorn/SM +peppermint/SM +pepperoni/MS +peppery +peppiness/M +pepping +peppy/TPR +pepsin/M +peptic/MS +peptide/S +peradventure/M +perambulate/XGNDS +perambulation/M +perambulator/MS +percale/MS +perceive/BGDS +perceived/U +percent/MS +percentage/SM +percentile/SM +perceptible +perceptibly +perception/SM +perceptional +perceptive/PY +perceptiveness/M +perceptual/Y +perch/GMDS +perchance +percipience/M +percipient +percolate/GNDS +percolation/M +percolator/SM +percussion/AM +percussionist/MS +percussive +perdition/M +perdurable +peregrinate/DSXGN +peregrination/M +peregrine/MS +peremptorily +peremptory +perennial/SMY +perestroika/M +perfect/PTGMDRYS +perfecta/MS +perfectibility/M +perfectible +perfection/SM +perfectionism/M +perfectionist/SM +perfectness/M +perfidious/Y +perfidy/SM +perforate/GNXDS +perforation/M +perforce +perform/SDRZG +performance/SM +performative +performed/U +performer/M +perfume/DRSMZG +perfumer/M +perfumery/SM +perfunctorily +perfunctory +perfusion +pergola/SM +perhaps +pericardia +pericardial +pericarditis +pericardium/M +perigee/SM +perihelia +perihelion/M +peril/SGMD +perilous/Y +perimeter/SM +perinatal +perinea +perineum/M +period/MS +periodic +periodical/SMY +periodicity/M +periodontal +periodontics/M +periodontist/SM +peripatetic/MS +peripheral/MYS +periphery/SM +periphrases +periphrasis/M +periphrastic +periscope/SM +perish/BDRSZG +perishable/MS +peristalses +peristalsis/M +peristaltic +peristyle/SM +peritoneal +peritoneum/MS +peritonitis/M +periwig/SM +periwinkle/SM +perjure/DRSZG +perjurer/M +perjury/SM +perk/MDSG +perkily +perkiness/M +perky/TPR +perm/MDSG +permafrost/M +permanence/M +permanency/M +permanent/SMY +permeability/M +permeable +permeate/GNDS +permeation/M +permissible +permissibly +permission/MS +permissive/PY +permissiveness/M +permit/MS +permitted +permitting +permutation/SM +permute/DSG +pernicious/YP +perniciousness/M +peroration/MS +peroxide/MGDS +perpendicular/SMY +perpendicularity/M +perpetrate/DSGN +perpetration/M +perpetrator/MS +perpetual/SMY +perpetuate/DSGN +perpetuation/M +perpetuity/M +perplex/GDS +perplexed/Y +perplexity/SM +perquisite/SM +persecute/GNXDS +persecution/M +persecutor/SM +perseverance/M +persevere/DSG +persiflage/M +persimmon/SM +persist/SGD +persistence/M +persistent/Y +persnickety +person/UMS +persona/SM +personable +personae +personage/MS +personal/MYS +personality/SM +personalize/CDSG +personalty/M +personification/M +personify/GDSNX +personnel/M +perspective/MS +perspex +perspicacious/Y +perspicacity/M +perspicuity/M +perspicuous +perspiration/M +perspire/GDS +persuade/BZGDRS +persuaded/U +persuader/M +persuasion/SM +persuasive/PY +persuasiveness/M +pert/RYPT +pertain/GSD +pertinacious/Y +pertinacity/M +pertinence/M +pertinent/Y +pertness/M +perturb/DGS +perturbation/SM +perturbed/U +pertussis/M +peruke/MS +perusal/MS +peruse/GDS +perv/S +pervade/DSG +pervasive/PY +pervasiveness/M +perverse/PXYN +perverseness/M +perversion/M +perversity/M +pervert/SGMD +peseta/MS +peskily +peskiness/M +pesky/TPR +peso/MS +pessary/S +pessimal +pessimism/M +pessimist/SM +pessimistic +pessimistically +pest/MRSZ +pester/GD +pesticide/MS +pestiferous +pestilence/SM +pestilent +pestilential +pestle/MGDS +pesto/M +pet/SZMR +petabyte/MS +petal/SMD +petard/MS +petcock/SM +peter/GMD +petiole/SM +petite/MS +petition/ZGMDRS +petitioner/M +petrel/MS +petrifaction/M +petrify/DSG +petrochemical/SM +petrodollar/MS +petrol/M +petrolatum/M +petroleum/M +petrologist/SM +petrology/M +petted +petticoat/MS +pettifog/S +pettifogged +pettifogger/SM +pettifoggery/M +pettifogging +pettily +pettiness/M +petting/M +pettish/Y +petty/PTR +petulance/M +petulant/Y +petunia/MS +pew/SM +pewee/SM +pewit/SM +pewter/MS +peyote/M +pf +pfennig/MS +pg +phaeton/MS +phage/S +phagocyte/SM +phalanger/SM +phalanges +phalanx/MS +phalli +phallic +phallocentric +phallocentrism +phallus/M +phantasm/MS +phantasmagoria/MS +phantasmagorical +phantasmal +phantom/SM +pharaoh/M +pharaohs +pharisaic +pharisee/SM +pharmaceutic/MS +pharmaceutical/SM +pharmaceutics/M +pharmacist/MS +pharmacologic +pharmacological +pharmacologist/SM +pharmacology/M +pharmacopeia/SM +pharmacopoeia/MS +pharmacy/SM +pharyngeal +pharynges +pharyngitis/M +pharynx/M +phase/DSMG +phaseout/SM +phat +pheasant/MS +phenacetin/M +phenobarbital/M +phenol/M +phenom/MS +phenomena +phenomenal/Y +phenomenological +phenomenology +phenomenon/MS +phenotype +pheromone/MS +phew +phi/SM +phial/SM +philander/ZGDRS +philanderer/M +philandering/M +philanthropic +philanthropically +philanthropist/MS +philanthropy/SM +philatelic +philatelist/MS +philately/M +philharmonic/SM +philippic/MS +philistine/MS +philistinism/M +philodendron/SM +philological +philologist/MS +philology/M +philosopher/MS +philosophic +philosophical/Y +philosophize/DRSZG +philosophizer/M +philosophy/SM +philter/MS +phish/ZGDR +phisher/M +phlebitis/M +phlegm/M +phlegmatic +phlegmatically +phloem/M +phlox/M +phobia/MS +phobic/MS +phoebe/MS +phoenix/MS +phone/DSMG +phonecard/S +phoneme/MS +phonemic +phonemically +phonetic/S +phonetically +phonetician/SM +phonetics/M +phoneyed +phoneying +phonic/S +phonically +phonics/M +phoniness/M +phonograph/M +phonographic +phonographs +phonological/Y +phonologist/MS +phonology/M +phony/PTGDRSM +phooey +phosphate/MS +phosphodiesterase +phosphor/MS +phosphorescence/M +phosphorescent/Y +phosphoric +phosphorous +phosphorus/M +phosphorylation +photo/SGMD +photocell/MS +photocopier/M +photocopy/DRSMZG +photoelectric +photoelectrically +photoengrave/DRSJZG +photoengraver/M +photoengraving/M +photofinishing/M +photogenic +photogenically +photograph/MDRZG +photographer/M +photographic +photographically +photographs/A +photography/M +photojournalism/M +photojournalist/SM +photometer/MS +photon/MS +photosensitive +photostat/SM +photostatic +photostatted +photostatting +photosynthesis/M +photosynthesize/GDS +photosynthetic +phototropic +phototropism +phototypesetter +phototypesetting +phrasal +phrase's +phrase/AGDS +phrasebook/S +phraseology/M +phrasing/MS +phreaking +phrenologist/SM +phrenology/M +phyla +phylactery/SM +phylogeny/M +phylum/M +phys +physic/SM +physical/MYS +physicality +physician/SM +physicist/SM +physicked +physicking +physics/M +physio/S +physiognomy/SM +physiography/M +physiologic +physiological/Y +physiologist/MS +physiology/M +physiotherapist/MS +physiotherapy/M +physique/MS +pi/SMDRHZG +pianissimo/SM +pianist/MS +piano/SM +pianoforte/SM +pianola/S +piaster/MS +piazza/MS +pibroch/M +pibrochs +pic/SM +pica/M +picador/MS +picante +picaresque +picayune +piccalilli/M +piccolo/MS +pick/MDRSJZG +pickax/GMDS +picker/M +pickerel/MS +picket/ZGMDRS +pickings/M +pickle/MGDS +pickpocket/SM +pickup/MS +picky/PTR +picnic/MS +picnicked +picnicker/SM +picnicking +picot/SM +pictograph/M +pictographs +pictorial/MYS +picture/MGDS +picturesque/PY +picturesqueness/M +piddle/MGDS +piddly +pidgin/MS +pie/SM +piebald/MS +piece/DSMG +piecemeal +piecework/MRZ +pieceworker/M +piecrust/SM +pieing +pier/M +pierce/JGDS +piercing/MY +piety/M +piezoelectric +piffle/MG +pig/SML +pigeon/MS +pigeonhole/DSMG +pigged +piggery/S +pigging +piggish/PY +piggishness/M +piggy/TRSM +piggyback/MDSG +pigheaded/PY +pigheadedness/M +piglet/MS +pigment/MDS +pigmentation/M +pigpen/MS +pigskin/MS +pigsty/SM +pigswill +pigtail/MS +pike/MZGDRS +piker/M +pikestaff/SM +pikestaves +pilaf/SM +pilaster/MS +pilchard/MS +pile/MGDSJ +pileup/MS +pilfer/ZGDRS +pilferage/M +pilferer/M +pilgrim/MS +pilgrimage/MS +piling/M +pill/MDSG +pillage/MZGDRS +pillager/M +pillar/MDS +pillbox/MS +pillion/MS +pillock/S +pillory/GDSM +pillow/GMDS +pillowcase/MS +pillowslip/MS +pilot/DGSM +pilothouse/SM +pimento/MS +pimiento/MS +pimp/GMDYS +pimpernel/MS +pimple/DSM +pimply/RT +pin/SM +pinafore/MS +pinata/MS +pinball/M +pincer/MS +pinch/GMDS +pincushion/MS +pine's +pine/AGDS +pineapple/MS +pinewood/S +piney +pinfeather/SM +ping/GMD +pinhead/SM +pinhole/SM +pinion/SMDG +pink/TGPMDRS +pinkeye/M +pinkie/M +pinkish +pinkness/M +pinko/MS +pinky/SM +pinnacle/SM +pinnate +pinned/U +pinning/U +pinny/S +pinochle/M +pinon/MS +pinpoint/SGMD +pinprick/MS +pinsetter/SM +pinstripe/DSM +pint/MS +pinto/MS +pinup/MS +pinwheel/GSMD +piny/TR +pinyin/M +pinyon/SM +pioneer/SGMD +pious/YP +piousness/M +pip/SZGMDR +pipe/MS +pipeline/SM +piper/M +pipette/SM +pipework +piping/M +pipit/MS +pipped +pippin/SM +pipping +pipsqueak/SM +piquancy/M +piquant/Y +pique/MGDS +piracy/M +piranha/SM +pirate/DSMG +piratical/Y +pirogi/M +piroshki/M +pirouette/DSMG +pirozhki/M +piscatorial +pismire/SM +piss/ZGMDRS +pissoir/S +pistachio/SM +piste/S +pistil/SM +pistillate +pistol/SM +piston/SM +pit/SM +pita/MS +pitapat/SM +pitch/MDRSZG +pitchblende/M +pitcher/M +pitchfork/MDSG +pitchman/M +pitchmen +piteous/YP +piteousness/M +pitfall/SM +pith/M +pithead/S +pithily +pithiness/M +pithy/RTP +pitiable +pitiably +pitiful/Y +pitiless/PY +pitilessness/M +piton/MS +pitta/S +pittance/MS +pitted +pitting +pituitary/SM +pity/GDSM +pitying/Y +pivot/MDGS +pivotal +pix/M +pixel/MS +pixie/MS +pizazz/M +pizza/MS +pizzazz/M +pizzeria/SM +pizzicati +pizzicato/M +piñata/MS +piñon/SM +pj's +pk +pkg +pkt +pkwy +pl +placard/SMDG +placate/DSGN +placation/M +placatory +place's +place/AESDLG +placebo/SM +placed/U +placeholder/MS +placekick/MDRZGS +placekicker/M +placement/EASM +placenta/SM +placental/S +placer/SM +placid/Y +placidity/M +placings +placket/SM +plagiarism/SM +plagiarist/SM +plagiarize/DRSZG +plagiarizer/M +plagiary/M +plague/DSMG +plaice +plaid/MS +plain/MRYTSP +plainchant +plainclothes +plainclothesman/M +plainclothesmen +plainness/M +plainsman/M +plainsmen +plainsong/M +plainspoken +plaint/SMV +plaintiff/SM +plaintive/Y +plait/MDGS +plan/ZMRS +planar +plane's +plane/CGDS +planeload/MS +planer/M +planet/SM +planetarium/SM +planetary +plangency/M +plangent +plank/MDGS +planking/M +plankton/M +planned/U +planner/SM +planning/S +plant/MDRZGSJ +plantain/SM +plantar +plantation/MS +planter/M +planting/M +plantlike +plaque/SM +plash/MDSG +plasma/M +plaster/SZGMDR +plasterboard/M +plasterer/M +plastic/SM +plasticity/M +plasticize/DSG +plastique +plat/XGMDNS +plate/MS +plateau/SMDG +plateful/SM +platelet/SM +platen/M +platform/SGMD +plating/M +platinum/M +platitude/SM +platitudinous +platonic +platoon/SGMD +platted +platter/SM +platting +platy/M +platypus/MS +platys +plaudit/SM +plausibility/M +plausible +plausibly +play/AEGMDS +playable/EU +playact/SGD +playacting/M +playback/MS +playbill/MS +playbook/MS +playboy/SM +player/SM +playfellow/SM +playful/PY +playfulness/M +playgirl/MS +playgoer/MS +playground/SM +playgroup/S +playhouse/MS +playlist/MS +playmate/MS +playoff/SM +playpen/SM +playroom/SM +playschool/S +plaything/SM +playtime/M +playwright/SM +plaza/MS +plea/MS +plead/DRZGSJ +pleader/M +pleading/MY +pleasant/UTYP +pleasanter +pleasantness/UM +pleasantry/SM +please/EDSG +pleasing/YS +pleasurably +pleasure/MGDSB +pleasureful +pleat/MDGS +pleb/S +plebby +plebe/MS +plebeian/MS +plebiscite/MS +plectra +plectrum/MS +pledge/DSMG +plenary/SM +plenipotentiary/SM +plenitude/SM +plenteous +plentiful/Y +plenty/M +plenum/S +pleonasm/MS +plethora/M +pleura/M +pleurae +pleurisy/M +plexiglass/M +plexus/MS +pliability/M +pliable +pliancy/M +pliant/Y +pliers/M +plight/SMDG +plimsoll/S +plinth/M +plinths +plod/S +plodded +plodder/MS +plodding/S +plonk/DRSZG +plop/MS +plopped +plopping +plosive/S +plot/MS +plotted +plotter/SM +plotting +plover/SM +plow/GMDS +plowman/M +plowmen +plowshare/MS +ploy's +ploy/S +pluck/MDSG +pluckily +pluckiness/M +plucky/RPT +plug's +plug/US +plugged/U +plugging/U +plughole/S +plugin/SM +plum/GMDS +plumage/M +plumb/MDRSZGJ +plumbed/U +plumber/M +plumbing/M +plume/MS +plummet/SGMD +plummy +plump/MDRYSTGP +plumpness/M +plumy/RT +plunder/SZGMDR +plunderer/M +plunge/DRSMZG +plunger/M +plunk/MDSG +pluperfect/SM +plural/SM +pluralism/M +pluralist/MS +pluralistic +plurality/SM +pluralization/M +pluralize/GDS +plus/MS +plush/MRYTP +plushness/M +plushy/RT +plutocracy/SM +plutocrat/SM +plutocratic +plutonium/M +pluvial +ply/AGDSM +plywood/M +pm +pneumatic +pneumatically +pneumococcal +pneumococci +pneumococcus +pneumonia/M +poach/DRSZG +poacher/M +poaching/M +pock/GMDS +pocket/SMDG +pocketbook/SM +pocketful/SM +pocketknife/M +pocketknives +pockmark/MDGS +pod/SM +podcast/SMG +podded +podding +podiatrist/SM +podiatry/M +podium/SM +poem/MS +poesy/M +poet/MS +poetaster/MS +poetess/MS +poetic/S +poetical/Y +poetry/M +pogrom/SM +poi/M +poignancy/M +poignant/Y +poinciana/SM +poinsettia/SM +point/MDRSZG +pointblank +pointed/Y +pointer/M +pointillism/M +pointillist/SM +pointless/PY +pointlessness/M +pointy/TR +poise/MGDS +poison/SJZGMDR +poisoner/M +poisoning/M +poisonous/Y +poke/MZGDRS +poker/M +pokey/MS +poky/TR +pol/SGMD +polar +polarity/SM +polarization/CM +polarize/CDSG +pole/MS +poleaxe/GDS +polecat/MS +polemic/MS +polemical/Y +polemicist/SM +polemics/M +polestar/SM +police/DSMG +policeman/M +policemen +policewoman/M +policewomen +policy/SM +policyholder/MS +policymaker/S +polio/MS +poliomyelitis/M +polish/ZGMDRS +polished/U +polisher/M +politburo/MS +polite/RYTP +politeness/M +politesse/M +politic/S +political/Y +politician/SM +politicization/M +politicize/CDSG +politicking/M +politico/SM +politics/M +polity/SM +polka/MDSG +poll/GMDNS +pollack/MS +pollard/S +pollen/M +pollinate/GNDS +pollination/M +pollinator/SM +polling/M +polliwog/SM +pollock/M +pollster/SM +pollutant/MS +pollute/ZGNDRS +polluted/U +polluter/M +pollution/M +pollywog/MS +polo/M +polonaise/SM +polonium/M +poltergeist/MS +poltroon/SM +poly +polyacrylamide +polyamory/S +polyandrous +polyandry/M +polyclinic/SM +polyester/MS +polyethylene/M +polygamist/MS +polygamous +polygamy/M +polyglot/SM +polygon/SM +polygonal +polygraph/GMD +polygraphs +polyhedral +polyhedron/SM +polymath/M +polymaths +polymer/SM +polymeric +polymerization/M +polymerize/GDS +polymorphic +polymorphous +polynomial/MS +polyp/MS +polyphonic +polyphony/M +polypropylene/M +polys +polysemous +polystyrene/M +polysyllabic +polysyllable/MS +polytechnic/MS +polytheism/M +polytheist/SM +polytheistic +polythene +polyunsaturate/DS +polyurethane/MS +polyvinyl +pom/S +pomade/DSMG +pomander/SM +pomegranate/MS +pommel/SGMD +pommy/S +pomp/M +pompadour/SMD +pompano/MS +pompom/SM +pomposity/M +pompous/YP +pompousness/M +ponce/GDS +poncho/SM +poncy +pond/MS +ponder/SZGDR +ponderer/M +ponderous/YP +ponderousness/M +pone/MS +pong/GDS +pongee/M +poniard/MS +pontiff/SM +pontifical/Y +pontificate/DSMG +pontoon/SM +pony/GDSM +ponytail/MS +poo/SGD +pooch/MDSG +poodle/SM +poof/MS +poofter/S +pooh/GMD +poohs +pool/GMDS +poolroom/MS +poolside/S +poop/GMDS +poor/TRYP +poorboy/M +poorhouse/SM +poorness/M +pop/SM +popcorn/M +pope/MS +popgun/SM +popinjay/MS +poplar/SM +poplin/M +popover/SM +poppa/MS +poppadom/S +popped +popper/SM +poppet/S +popping +poppy/SM +poppycock/M +populace/MS +popular/Y +popularity/UM +popularization/M +popularize/DSG +populate/ACGDS +population/CM +populations +populism/M +populist/MS +populous/P +populousness/M +popup/MS +porcelain/SM +porch/MS +porcine +porcupine/SM +pore/MGDS +porgy/SM +pork/ZMR +porker/M +porky/RSMT +porn/M +porno/M +pornographer/MS +pornographic +pornographically +pornography/M +porosity/M +porous/P +porousness/M +porphyritic +porphyry/M +porpoise/MGDS +porridge/M +porringer/SM +port's/A +port/CAEGDS +portability/M +portable/MS +portage/DSMG +portal/SM +portcullis/MS +portend/SGD +portent/SM +portentous/YP +porter/ASM +porterhouse/SM +portfolio/MS +porthole/MS +portico/M +porticoes +portiere/MS +portion/KSGMD +portière/MS +portliness/M +portly/RPT +portmanteau/MS +portrait/MS +portraitist/SM +portraiture/M +portray/SGD +portrayal/MS +portulaca/M +pose's/A +pose/CAKEGDS +poser/EKSM +poseur/SM +posh/TR +posit/DSGV +position/CKEMS +positional/K +positioned/K +positioning/K +positive/MYPS +positiveness/M +positivism +positivist/S +positron/MS +poss +posse/MS +possess/AEVGSD +possession/ASM +possessive/SMYP +possessiveness/M +possessor/SM +possibility/SM +possible/SM +possibly +possum/SM +post/ZGMDRSJ +postage/M +postal +postbag/S +postbox/S +postcard/SM +postcode/S +postcolonial +postconsonantal +postdate/DSG +postdoc/MS +postdoctoral +poster/M +posterior/SM +posterity/M +postgraduate/SM +posthaste +posthumous/Y +posthypnotic +postie/S +postilion/SM +postillion/MS +postindustrial +posting/M +postlude/SM +postman/M +postmark/SMDG +postmaster/MS +postmen +postmenopausal +postmeridian +postmistress/MS +postmodern +postmodernism/M +postmodernist/MS +postmortem/SM +postnasal +postnatal +postoperative +postpaid +postpartum +postpone/DSGL +postponement/SM +postprandial +postscript/SM +postseason/SM +postsynaptic +postulate/XDSMGN +postulation/M +postural +posture/MGJDS +posturing/M +postwar +postwoman +postwomen +posy/SM +pot/CSM +potability/M +potable/SM +potash/M +potassium/M +potato/M +potatoes +potbelly/DSM +potboiler/SM +potency/M +potent/Y +potentate/MS +potential/MYS +potentiality/SM +potentiate/GDS +potful/SM +pothead/SM +pother/SMDG +potherb/SM +potholder/MS +pothole/DRSMZG +pothook/SM +potion/SM +potluck/MS +potpie/SM +potpourri/SM +potsherd/SM +potshot/MS +pottage/M +potted +potter/GSMD +pottery/SM +potting +potty/PRSMT +pouch/MDSG +pouf/S +pouffe/S +poulterer/MS +poultice/DSMG +poultry/M +pounce/DSMG +pound's +pound/KDSG +poundage/M +pounding/SM +pour/GDSJ +pout/ZGMDRS +pouter/M +poverty/M +pow +powder/GSMD +powdery +power/MDSG +powerboat/MS +powerful/Y +powerhouse/SM +powerless/PY +powerlessness/M +powwow/SGMD +pox/MS +pp +ppm +ppr +pr +practicability/M +practicably +practical/SMY +practicality/SM +practice/DSMGB +practiced/U +practicum/SM +practitioner/SM +praetor/SM +praetorian +pragmatic/MS +pragmatical/Y +pragmatism/M +pragmatist/MS +prairie/SM +praise/EDSMG +praiseworthiness/M +praiseworthy/P +praline/SM +pram/MS +prance/DRSMZG +prancer/M +prancing/Y +prang/DSG +prank/MS +prankster/SM +praseodymium/M +prat/S +prate/MZGDRS +prater/M +pratfall/SM +prattle/DRSMZG +prattler/M +prawn/MDSG +pray/ZGDRS +prayer/M +prayerful/Y +preach/DRSZGL +preacher/M +preachment/M +preachy/RT +preadolescence/SM +preamble/MGDS +prearrange/LGDS +prearrangement/M +preassigned +precancel/SMDG +precancerous +precarious/PY +precariousness/M +precast +precaution/MS +precautionary +precede/DSG +precedence/M +precedent/SM +precept/SM +preceptor/SM +precinct/MS +preciosity/M +precious/YP +preciousness/M +precipice/SM +precipitant/MS +precipitate/XMYGNDS +precipitation/M +precipitous/Y +precis/M +precise/DRSYTGNP +preciseness/M +precision/M +preclude/GDS +preclusion/M +precocious/YP +precociousness/M +precocity/M +precognition/M +precognitive +precolonial +preconceive/GDS +preconception/SM +precondition/MDGS +precook/GSD +precursor/SM +precursory +predate/DSG +predator/MS +predatory +predawn +predecease/GDS +predecessor/SM +predefined +predesignate/GDS +predestination/M +predestine/DSG +predetermination/M +predetermine/ZGDRS +predeterminer/M +predicable +predicament/MS +predicate/MGNVDS +predication/M +predicative/Y +predict/BGVSD +predictability/UM +predictable/U +predictably/U +prediction/SM +predictor/MS +predigest/GDS +predilection/SM +predispose/GDS +predisposition/MS +predominance/M +predominant/Y +predominate/YGDS +preemie/SM +preeminence/M +preeminent/Y +preempt/GVSD +preemption/M +preemptive/Y +preen/DSG +preexist/DGS +preexistence/M +pref +prefab/SM +prefabbed +prefabbing +prefabricate/DSGN +prefabrication/M +preface/DSMG +prefatory +prefect/SM +prefecture/MS +prefer/SBL +preferably +preference/MS +preferential/Y +preferment/M +preferred +preferring +prefigure/GDS +prefix/MDSG +preform/GSD +prefrontal +pregame/SM +pregnancy/SM +pregnant +preheat/GSD +prehensile +prehistorian/S +prehistoric +prehistorical/Y +prehistory/M +prehuman +prejudge/GDS +prejudgment/SM +prejudice/MGDS +prejudiced/U +prejudicial +prekindergarten/SM +prelacy/M +prelate/SM +prelim/SM +preliminary/SM +preliterate +prelude/MS +premarital +premature/Y +premed/SM +premedical +premeditate/DSGN +premeditated/U +premeditation/M +premenstrual +premier/SGMD +premiere/MS +premiership/MS +premise/DSMG +premium/SM +premix/GDS +premolar/SM +premonition/MS +premonitory +prenatal/Y +prenup/SM +prenuptial +preoccupation/SM +preoccupy/DSG +preoperative +preordain/GDS +prep/MS +prepackage/DSG +prepacked +prepaid +preparation/SM +preparatory +prepare/GDS +prepared/UP +preparedness/UM +prepay/GSL +prepayment/MS +preponderance/SM +preponderant/Y +preponderate/GDS +preposition/SM +prepositional/Y +prepossess/GDS +prepossessing/U +prepossession/SM +preposterous/Y +prepped +preppie/M +prepping +preppy/TRSM +prepubescence/M +prepubescent/SM +prepuce/MS +prequel/MS +prerecord/GSD +preregister/SGD +preregistration/M +prerequisite/MS +prerogative/SM +pres +presage/MGDS +presbyopia/M +presbyter/SM +presbytery/SM +preschool/SZMR +preschooler/M +prescience/M +prescient/Y +prescribe/DSG +prescript/SVM +prescription/SM +prescriptive/Y +preseason/SM +presence/SM +present/LMDRYZGSB +presentably +presentation/ASM +presenter/M +presentiment/SM +presentment/SM +preservation/M +preservationist/SM +preservative/SM +preserve/BDRSMZG +preserver/M +preset/S +presetting +preshrank +preshrink/GS +preshrunk +preside/GDS +presidency/SM +president/MS +presidential +presidia +presidium/M +presort/DGS +press's +press/ACGSD +pressed/U +presser/MS +pressie/S +pressing/SMY +pressman/M +pressmen +pressure/DSMG +pressurization/M +pressurize/CGDS +pressurizer/SM +prestidigitation/M +prestige/M +prestigious +presto/SM +presumably +presume/GDSB +presumption/SM +presumptive +presumptuous/YP +presumptuousness/M +presuppose/DSG +presupposition/MS +pretax +preteen/MS +pretend/DRZGS +pretender/M +pretense/SXMN +pretension/M +pretentious/UY +pretentiousness/M +preterit/SM +preterite/MS +preterm +preternatural/Y +pretest/DGS +pretext/MS +pretrial/S +prettify/GDS +prettily +prettiness/M +pretty/TGDRSMP +pretzel/MS +prevail/DGS +prevalence/M +prevalent +prevaricate/DSGNX +prevarication/M +prevaricator/SM +prevent/DBSGV +preventable/U +preventative/MS +prevention/M +preventive/SM +preview/MDRSZG +previous/Y +prevision/MS +prewar +prey/GMDS +prezzie/S +priapic +price's +price/AGDS +priceless +pricey +pricier +priciest +prick/MDRYSZG +pricker/M +prickle/MGDS +prickliness/M +prickly/PRT +pride/MGDS +prideful/Y +prier/M +priest/SMY +priestess/MS +priesthood/SM +priestliness/M +priestly/RTP +prig/MS +priggish/P +priggishness/M +prim/ZGDRYP +primacy/M +primal +primarily +primary/SM +primate/MS +prime/MS +primer/M +primeval +priming/M +primitive/SPMY +primitiveness/M +primmer +primmest +primness/M +primogenitor/SM +primogeniture/M +primordial/Y +primp/DSG +primrose/SM +primula/S +prince/SMY +princedom/SM +princeliness/M +princely/PRT +princess/MS +principal/SMY +principality/SM +principle/DSM +principled/U +print/AMDSG +printable/U +printer/MS +printing/SM +printmaking +printout/SM +prion/S +prior/MS +prioress/MS +prioritization +prioritize/DSG +priority/SM +priory/SM +prism/MS +prismatic +prison/SZMR +prisoner/M +prissily +prissiness/M +prissy/PTR +pristine +prithee +privacy/M +private/XMYTNRS +privateer/SM +privation/CSM +privatization/SM +privatize/DSG +privet/SM +privilege/DSMG +privileged/U +privily +privy/RSMT +prize/MGDS +prized/A +prizefight/ZGSMR +prizefighter/M +prizefighting/M +prizewinner/MS +prizewinning +pro/SM +probabilistic +probability/SM +probable/SM +probably +probate/MN +probation/ZMR +probational +probationary +probationer/M +probe/MGDSBJ +probity/M +problem/MS +problematic +problematical/Y +probosces +proboscis/MS +procaine/M +procedural +procedure/SM +proceed/GJDS +proceeding/M +proceeds/M +process's +process/AGDS +processed/U +procession/GD +processional/MS +processor/SM +proclamation/MS +proclivity/SM +procrastinate/DSGN +procrastination/M +procrastinator/MS +procreate/V +proctor/GMDS +procurement/M +prod/MS +prodigal/MYS +prodigality/M +prodigious/Y +prodigy/SM +produce's +produce/AZGDRS +producer/AM +producible/A +production/ASM +productive/UY +productiveness/M +productivity/M +prof/MS +profanation/MS +profane/PYGDS +profaneness/M +profanity/SM +professed/Y +profession/SM +professional/MYS +professionalism/M +professionalization +professionalize/DSG +professor/SM +professorial/Y +professorship/SM +proffer/GMDS +proficiency/M +proficient/MYS +profit/BGD +profitability/M +profitable/U +profitably/U +profiteer/MDGS +profiteering/M +profiterole/SM +profitless +profligacy/M +profligate/SMY +proforma +profound/RYTP +profoundness/M +profundity/SM +profuse/PY +profuseness/M +progenitor/SM +progeny/M +progesterone/M +progestin/S +prognathous +prognoses +prognosis/M +prognostic/MS +prognosticate/XGNDS +prognostication/M +prognosticator/MS +program/CAS +programed +programing +programmable/MS +programmatic +programmed/AC +programmer/MS +programming/SM +progress/MDSGV +progression/MS +progressive/PMYS +progressiveness/M +prohibit/DGVS +prohibition/SM +prohibitionist/MS +prohibitive/Y +prohibitory +project/GMDS +projectile/SM +projection/SM +projectionist/SM +projector/MS +prokaryotic +prole/S +proletarian/MS +proletariat/M +proliferate/DSGN +proliferation/M +prolific +prolifically +prolix/Y +prolixity/M +prologue/SM +prolongation/SM +prom/M +promenade/MGDS +promethium/M +prominence/M +prominent/Y +promiscuity/M +promiscuous/Y +promise/DSMG +promising/Y +promissory +promo/M +promontory/SM +promote/DRZG +promoter/M +promotional +prompt/JPSMDRYZTG +prompted/U +prompter/M +prompting/M +promptitude/M +promptness/M +promulgate/GNDS +promulgation/M +promulgator/MS +prone/P +proneness/M +prong/MDS +pronghorn/MS +pronominal/M +pronounce/DSLG +pronounceable/U +pronouncement/SM +pronto +pronunciation/MS +proof/ADGSM +proofread/SRZG +proofreader/M +prop/MS +propaganda/M +propagandist/MS +propagandize/GDS +propagate/DSGN +propagation/M +propagator/SM +propel/S +propellant/MS +propelled +propeller/SM +propelling +propensity/SM +proper/MRYT +property/DSM +prophecy/SM +prophesier/M +prophesy/DRSMZG +prophet/SM +prophetess/MS +prophetic +prophetical/Y +prophylactic/SM +prophylaxes +prophylaxis/M +propinquity/M +propitiate/DSGN +propitiation/M +propitiatory +propitious/Y +proponent/SM +proportion/ESM +proportional/YS +proportionality +proportionate/EY +proposal/MS +propped +propping +proprietary/SM +proprieties/M +proprietor/SM +proprietorial/Y +proprietorship/M +proprietress/MS +propriety/SM +propulsion/M +propulsive +prorate/DSG +prorogation/M +prorogue/GD +prosaic +prosaically +proscenium/SM +prosciutto/M +proscribe/DG +proscription/MS +prose/M +prosecute/DSXGN +prosecution/M +prosecutor/MS +proselyte/DSMG +proselytism/M +proselytize/DRSZG +proselytizer/M +prosody/SM +prospect/MDGVS +prospective/Y +prospector/SM +prospectus/MS +prosper/GSD +prosperity/M +prosperous/Y +prostate/MS +prostheses +prosthesis/M +prosthetic +prostitute/MGNDS +prostitution/M +prostrate/GNXDS +prostration/M +prosy/RT +protactinium/M +protagonist/SM +protean +protect/GVSD +protected/U +protection/SM +protectionism/M +protectionist/MS +protective/PY +protectiveness/M +protector/MS +protectorate/MS +protege/SM +protegee/S +protein/SM +protestant/S +protestation/MS +protestor/MS +protocol/MS +proton/SM +protoplasm/M +protoplasmic +prototype/MGS +prototypical +protozoa +protozoan/MS +protozoic +protract/GD +protrude/GDS +protrusile +protrusion/MS +protuberance/MS +protuberant +protégé/MS +protégée/S +proud/RYT +prov/NB +provability/M +provably +prove/EAGDS +proved/U +proven/U +provenance/SM +provender/M +provenience/M +proverbial/Y +provide/DRSZG +provided/U +providence/M +provident/Y +providential/Y +provider/M +province/MS +provincial/SMY +provincialism/M +provisional/Y +proviso/SM +provocateur/S +provocative/PY +provocativeness/M +provoke/DRSZG +provoked/U +provoker/M +provoking/Y +provolone/M +provost/SM +prow/MS +prowess/M +prowl/MDRSZG +prowler/M +proximal +proximate +proximity/M +proxy/SM +prude/MS +prudence/M +prudent/Y +prudential/Y +prudery/M +prudish/YP +prudishness/M +prune/MZGDRS +pruner/M +prurience/M +prurient/Y +pry/ZTGDRSM +précis/MDG +psalm/MS +psalmist/SM +psaltery/SM +psephologist/S +psephology +pseud/S +pseudo/S +pseudonym/SM +pseudonymous +pseudoscience/MS +pseudy +pshaw/MS +psi/SM +psittacosis/M +psoriasis/M +psst +psych/MDSG +psyche/M +psychedelia +psychedelic/SM +psychedelically +psychiatric +psychiatrist/SM +psychiatry/M +psychic/MS +psychical/Y +psycho/SM +psychoactive +psychoanalyses +psychoanalysis/M +psychoanalyst/SM +psychoanalytic +psychoanalytical/Y +psychoanalyze/DSG +psychobabble/M +psychodrama/MS +psychogenic +psychokinesis +psychokinetic +psychological/Y +psychologist/MS +psychology/SM +psychometric +psychoneuroses +psychoneurosis/M +psychopath/M +psychopathic +psychopathology +psychopaths +psychopathy/M +psychopharmacology +psychos/S +psychosis/M +psychosomatic +psychotherapist/MS +psychotherapy/SM +psychotic/SM +psychotically +psychotropic/MS +psychs +pt/C +ptarmigan/MS +pterodactyl/MS +ptomaine/SM +pub/SM +pubertal +puberty/M +pubes/M +pubescence/M +pubescent +pubic +pubis/M +public/AM +publican/AMS +publication/ASM +publicist/MS +publicity/M +publicize/GDS +publicly +publish/AGDS +publishable +published/U +publisher/MS +publishing/M +puce/M +puck/ZMRS +pucker/MDG +puckish/YP +puckishness/M +pud/S +pudding/SM +puddle/DSMG +puddling/M +pudenda +pudendum/M +pudginess/M +pudgy/PRT +pueblo/SM +puerile +puerility/M +puerperal +puff/ZGMDRS +puffball/SM +puffer/M +puffin/SM +puffiness/M +puffy/PRT +pug/SM +pugilism/M +pugilist/SM +pugilistic +pugnacious/YP +pugnaciousness/M +pugnacity/M +puke/MGDS +pukka +pulchritude/M +pulchritudinous +pule/GDS +pull/ZGMDRS +pullback/MS +puller/M +pullet/SM +pulley/SM +pullout/MS +pullover/SM +pulmonary +pulp/GMDS +pulpiness/M +pulpit/SM +pulpwood/M +pulpy/RPT +pulsar/SM +pulsate/XGNDS +pulsation/M +pulse/AMGDS +pulverization/M +pulverize/DSG +puma/MS +pumice/SM +pummel/SGD +pump/ZGMDRS +pumper/M +pumpernickel/M +pumpkin/MS +pun/SM +punch/MDRSZG +punchbag/S +puncheon/MS +puncher/M +punchline/S +punchy/TR +punctilio/M +punctilious/PY +punctiliousness/M +punctual/Y +punctuality/M +punctuate/GNDS +punctuation/M +puncture/DSMG +pundit/SM +punditry/M +pungency/M +pungent/Y +puniness/M +punish/BLGDS +punished/U +punishing/Y +punishment/MS +punitive/Y +punk/TMRS +punned +punnet/S +punning +punster/SM +punt/ZGMDRS +punter/M +puny/TRP +pup/SM +pupa/M +pupae +pupal +pupate/DSG +pupil/MS +pupped +puppet/MS +puppeteer/SM +puppetry/M +pupping +puppy/SM +purblind +purchase/DRSMZGB +purchaser/M +purdah/M +pure/PYTR +purebred/SM +puree/MDS +pureeing +pureness/M +purgative/SM +purgatorial +purgatory/SM +purge/MZGDRS +purger/M +purification/M +purifier/M +purify/NDRSZG +purine/MS +purism/M +purist/MS +puristic +puritan/SM +puritanical/Y +puritanism/M +purity/M +purl/GMDS +purlieu/SM +purloin/SGD +purple/MTRS +purplish +purport/SMDG +purported/Y +purpose/DSMYG +purposeful/YP +purposefulness/M +purposeless/PY +purr/GMDS +purse/MZGDRS +purser/M +pursuance/M +pursuant +pursue/ZGDRS +pursuer/M +pursuit/SM +purulence/M +purulent +purvey/DSG +purveyance/M +purveyor/SM +purview/M +pus/M +push/ZGMDRS +pushbike/S +pushcart/SM +pushchair/S +pusher/M +pushily +pushiness/M +pushover/MS +pushpin/S +pushup/MS +pushy/TRP +pusillanimity/M +pusillanimous/Y +puss/MS +pussy/TRSM +pussycat/MS +pussyfoot/DSG +pustular +pustule/SM +put/ISM +putative +putdown/SM +putout/MS +putrefaction/M +putrefactive +putrefy/GDS +putrescence/M +putrescent +putrid +putsch/MS +putt/ZGMDRS +putted/I +puttee/MS +putter/MDRZG +putterer/M +putting/I +putty/GDSM +putz/S +puzzle/MZGDRSL +puzzlement/M +puzzler/M +pvt +pwn/SGD +pyelonephritis +pygmy/SM +pylon/SM +pylori +pyloric +pylorus/M +pyorrhea/M +pyramid/GSMD +pyramidal +pyre/MS +pyrimidine/MS +pyrite/SM +pyrites/M +pyromania/M +pyromaniac/SM +pyrotechnic/S +pyrotechnical +pyrotechnics/M +pyruvate +python/SM +pyx/MS +pzazz +q +qr +qt/S +qty +qua +quack/GMDS +quackery/M +quad/MS +quadrangle/SM +quadrangular +quadrant/MS +quadraphonic +quadratic/MS +quadrature +quadrennial +quadrennium/MS +quadriceps/MS +quadrilateral/SM +quadrille/XMNS +quadrillion/M +quadriplegia/M +quadriplegic/SM +quadrivium/M +quadruped/MS +quadrupedal +quadruple/MGDS +quadruplet/MS +quadruplicate/MGNDS +quadruplication/M +quaff/GMDS +quagmire/SM +quahog/MS +quail/GMDS +quaint/PRYT +quaintness/M +quake/MGDS +quaky +qualification/EM +qualified/U +qualifier/SM +qualify/EGXNDS +qualitative/Y +quality/SM +qualm/MS +qualmish +quandary/SM +quango/S +quanta +quantifiable +quantification/M +quantifier/M +quantify/NDRSZG +quantitative/Y +quantity/SM +quantum/M +quarantine/MGDS +quark/MS +quarrel/SZGMDR +quarreler/M +quarrelsome/P +quarrelsomeness/M +quarry/DSMG +quart/MS +quarter/SGMDY +quarterback/GMDS +quarterdeck/MS +quarterfinal/SM +quarterly/SM +quartermaster/MS +quarterstaff/M +quarterstaves +quartet/SM +quarto/MS +quartz/M +quasar/MS +quash/GDS +quasi +quatrain/MS +quaver/MDSG +quavery +quay/MS +quayside/S +queasily +queasiness/M +queasy/TPR +queen/GMDYS +queenly/RT +queer/PTGMDRYS +queerness/M +quell/GDS +quench/ZGDRSB +quenchable/U +quencher/M +quenchless +querulous/YP +querulousness/M +query/DSMG +ques +quesadilla/MS +quest/IFAMS +quested +questing +question/SMDRZGBJ +questionable/U +questionably/U +questioned/U +questioner/M +questioning/MY +questionnaire/SM +queue/MDSG +quibble/DRSMZG +quibbler/M +quiche/SM +quick/MNRYXTP +quicken/DG +quickfire +quickie/SM +quicklime/M +quickness/M +quicksand/MS +quicksilver/M +quickstep/MS +quid/MS +quiescence/M +quiescent/Y +quiet/SMDNRYXTGP +quieten/DG +quietism +quietness/M +quietude/IEM +quietus/MS +quiff/S +quill/SM +quilt/SMDRZG +quilter/M +quilting/M +quin/S +quince/SM +quine/S +quinine/M +quinoa +quinsy/M +quint/SM +quintessence/SM +quintessential/Y +quintet/SM +quintuple/MGDS +quintuplet/MS +quip/MS +quipped +quipping +quipster/SM +quire's +quire/IAS +quirk/SMDG +quirkiness/M +quirky/RTP +quirt/SM +quisling/SM +quit/S +quitclaim/MS +quite +quittance/M +quitter/SM +quitting +quiver/SMDG +quivery +quixotic +quixotically +quiz/M +quizzed +quizzer/SM +quizzes +quizzical/Y +quizzing +quo/H +quoin/SM +quoit/SMDG +quondam +quorate/I +quorum/SM +quot/B +quota/SM +quotability/M +quotation/SM +quote's +quote/UDSG +quotidian +quotient/SM +qwerty +r/S +rabbet/GMDS +rabbi/SM +rabbinate/M +rabbinic +rabbinical +rabbit/GMDS +rabble/MS +rabid/PY +rabidness/M +rabies/M +raccoon/MS +race/MZGDRS +racecourse/SM +racegoer/S +racehorse/MS +raceme/MS +racer/M +racetrack/MS +raceway/MS +racial/Y +racialism/M +racialist/MS +racily +raciness/M +racing/M +racism/M +racist/SM +rack/GMDS +racket/SMDG +racketeer/SMDG +racketeering/M +raconteur/SM +racquet/SM +racquetball/SM +racy/PRT +rad/SM +radar/SM +radarscope/SM +raddled +radial/SMY +radiance/M +radiant/Y +radiate/DSGNX +radiation/M +radiator/SM +radical/SMY +radicalism/M +radicalization/M +radicalize/DSG +radicchio/M +radii +radio/MDGS +radioactive/Y +radioactivity/M +radiocarbon/M +radiogram/MS +radiographer/SM +radiography/M +radioisotope/MS +radiologist/SM +radiology/M +radioman/M +radiomen +radiometer/MS +radiometric +radiometry/M +radiophone/SM +radioscopy/M +radiosonde/SM +radiosurgery +radiotelegraph/M +radiotelegraphs +radiotelegraphy/M +radiotelephone/MS +radiotherapist/MS +radiotherapy/M +radish/MS +radium/M +radius/M +radon/M +raffia/M +raffish/YP +raffishness/M +raffle/DSMG +raft/ZGMDRS +rafter/M +rafting/M +rag/SGMD +raga/MS +ragamuffin/MS +ragbag/M +rage/MS +ragga +ragged/RYTP +raggedness/M +raggedy/RT +ragging +raging/Y +raglan/SM +ragout/SM +ragtag/S +ragtime/M +ragweed/M +ragwort +rah +raid/ZGMDRS +raider/M +rail's +rail/CGDS +railcard/S +railing/SM +raillery/SM +railroad/SZGMDR +railroader/M +railroading/M +railway/SM +railwayman +railwaymen +raiment/M +rain/GMDS +rainbow/SM +raincoat/SM +raindrop/SM +rainfall/SM +rainmaker/SM +rainmaking/M +rainproof +rainstorm/MS +rainwater/M +rainy/RT +raise/MZGDRS +raiser/M +raisin/SM +raja/MS +rajah/M +rajahs +rake/MGDS +rakish/YP +rakishness/M +rally/DSMG +ram/SM +ramble/DRSMZGJ +rambler/M +rambunctious/PY +rambunctiousness/M +ramekin/SM +ramie/M +ramification/M +ramify/DSXNG +ramjet/SM +rammed +ramming +ramp/GMS +rampage/DSMG +rampancy/M +rampant/Y +rampart/SM +ramrod/SM +ramrodded +ramrodding +ramshackle +ran/A +ranch/MDRSZG +rancher/M +ranching/M +rancid/P +rancidity/M +rancidness/M +rancor/M +rancorous/Y +rand/M +randiness/M +random/PSY +randomization/M +randomize/DSG +randomness/MS +randy/RTP +ranee/MS +rang/ZR +range's +range/CGDS +rangefinder/S +ranger/M +ranginess/M +rangy/RTP +rani/MS +rank/TGJPMDRYS +ranking/M +rankle/DSG +rankness/M +ransack/SGD +ransom/SZGMDR +ransomer/M +ransomware +rant/ZGMDJRS +ranter/M +rap/SZGMDR +rapacious/PY +rapaciousness/M +rapacity/M +rape/MS +raper/M +rapeseed/M +rapid/PMRYTS +rapidity/M +rapidness/M +rapier/SM +rapine/M +rapist/SM +rapped +rappel/SM +rappelled +rappelling +rapper/SM +rapping +rapport/MS +rapporteur/S +rapprochement/SM +rapscallion/MS +rapt/YP +raptness/M +raptor/S +rapture/MS +rapturous/Y +rare/YTGPDRS +rarebit/MS +rarefaction/M +rarefy/GDS +rareness/M +rarity/SM +rascal/SMY +rash/ZTMRSYP +rasher/M +rashness/M +rasp/GMDS +raspberry/SM +raspy/RT +raster +rat/SM +ratatouille/M +ratbag/S +ratchet/GMDS +rate/JXMZGNDRS +rated/U +ratepayer/S +rater/M +rather +rathskeller/SM +ratification/M +ratifier/M +ratify/NDRSZG +rating/M +ratio/MS +ratiocinate/GNDS +ratiocination/M +ration/MDG +rational/SMY +rationale/MS +rationalism/M +rationalist/SM +rationalistic +rationality/M +rationalization/MS +rationalize/DSG +ratlike +ratline/SM +rattan/SM +ratted +ratter/SM +ratting +rattle/DRSMZGJ +rattlebrain/SMD +rattler/M +rattlesnake/SM +rattletrap/SM +rattly +rattrap/SM +ratty/RT +raucous/YP +raucousness/M +raunchily +raunchiness/M +raunchy/TRP +ravage/DRSMZG +ravager/M +ravages/M +rave/JMZGDRS +ravel's +ravel/UDSG +raveling/S +raven/MDSG +ravenous/Y +ravine/SM +raving/M +ravioli/SM +ravish/DRSZGL +ravisher/M +ravishing/Y +ravishment/M +raw/PTMR +rawboned +rawhide/M +rawness/M +ray/SM +rayon/M +raze/GDS +razor/MS +razorback/MS +razz/GMDS +razzmatazz/M +rcpt +rd +re/DSMYTGVJ +reach/MDSGB +reachable/U +reacquire/DSG +react/V +reactant/SM +reactionary/SM +reactivity +read/ZGMRBJS +readability/SM +reader/M +readership/SM +readily +readiness/M +reading/M +readmitted +readout/SM +ready/DRSTGP +reafforestation +real/TMRYPS +realism/M +realist/SM +realistic/U +realistically/U +realities +reality/UM +realization/MS +realize/DSBG +realized/U +realm/MS +realness/M +realpolitik/M +realtor/SM +realty/M +ream/ZGMDRS +reamer/M +reap/ZGDRS +reaper/M +rear/GMDS +rearguard/MS +rearmost +rearward/S +reason/SMDRZGB +reasonable/UP +reasonableness/UM +reasonably/U +reasoner/M +reasoning/M +reassuring/Y +rebate/M +rebel/MS +rebellion/MS +rebellious/YP +rebelliousness/M +rebid/S +rebidding +rebirth/M +reboil/SDG +rebuild/SG +rebuke/DSMG +rebuking/Y +rebuttal/MS +rec'd +rec/M +recalcitrance/M +recalcitrant +recant/SDG +recantation/SM +recap/MS +recapitalization +recce/S +recd +receipt/SMDG +receivables/M +receive/DRSZGB +receiver/M +receivership/M +recent/RYTP +recentness/M +receptacle/SM +reception/MS +receptionist/SM +receptive/PY +receptiveness/M +receptivity/M +receptor/SM +recess/MDSGV +recessional/SM +recessionary +recessive/SM +recherche +recherché +recidivism/M +recidivist/SM +recipe/SM +recipient/SM +reciprocal/SMY +reciprocate/GNDS +reciprocation/M +reciprocity/M +recital/SM +recitalist/MS +recitative/MS +reciter/SM +reckless/YP +recklessness/M +reckon/SJDG +reckoning/M +reclamation/M +recline/DRSZG +recliner/M +recluse/SMV +recognizable/U +recognizably +recognize/DRSGB +recognized/U +recombination +recompense/DSMG +recompilation +recompile/GD +recon/S +reconcile/GDSB +reconciliation/S +recondite +reconfiguration +reconfigure/D +reconnaissance/MS +reconnoiter/DGS +reconstruct/V +reconstructed/U +recorded/U +recorder/MS +recording/MS +recoup/DG +recourse/M +recoverable/U +recovery/SM +recreant/MS +recreational +recriminate/DSGNX +recrimination/M +recriminatory +recrudesce/GDS +recrudescence/M +recrudescent +recruit/LSMDRZG +recruiter/M +recruitment/M +rectal/Y +rectangle/MS +rectangular +rectifiable +rectification/M +rectifier/M +rectify/XNDRSZG +rectilinear +rectitude/M +recto/MS +rector/SM +rectory/SM +rectum/SM +recumbent +recuperate/GNVDS +recuperation/M +recur/S +recurred +recurrence/SM +recurring +recursion/S +recuse/DSG +recyclable/SM +recycling/M +red/PSM +redact/SDG +redaction/M +redactor/SM +redbird/SM +redbreast/MS +redbrick +redcap/SM +redcoat/SM +redcurrant/S +redden/SDG +redder +reddest +reddish +redeem/RZB +redeemer/M +redemption/M +redemptive +redhead/SMD +redirection +redistrict/GD +redivide/GDS +redlining/M +redneck/SM +redness/M +redo/G +redolence/M +redolent +redoubt/SBM +redoubtably +redound/SDG +redraw/SG +redskin/SM +reduce/DRSZG +reducer/M +reducible +reductase/M +reduction/SM +reductionist +reductive +redundancy/SM +redundant/Y +redwood/SM +redye/DS +reediness/M +reedy/RTP +reef/ZGMDRS +reefer/M +reek/GMDS +reel's +reel/UGDS +reeve/G +reexport/SDG +ref/SZM +refashion/DGS +refection/M +refectory/SM +refer/B +referee/DSM +refereeing +reference/MGDS +referendum/MS +referent/SM +referential +referral/SM +referred +referrer/SM +referring +reffed +reffing +refill/BM +refined/U +refinement/SM +refiner/SM +refinery/S +refitting +reflate/XDSGN +reflationary +reflect/GVSD +reflection/MS +reflective/Y +reflector/MS +reflexive/SMY +reflexology +reforge/DSG +reform/MZ +reformat/V +reformatory/SM +reformatting +reformed/U +reformist/S +refortify/GDS +refract/SGVD +refraction/M +refractory/SM +refrain/SGMD +refresh/ZGLDRS +refresher/M +refreshing/Y +refreshment/SM +refreshments/M +refrigerant/SM +refrigerate/DSGN +refrigeration/M +refrigerator/MS +refuge/SM +refugee/SM +refulgence/M +refulgent +refund/B +refurbishment/MS +refusal/MS +refutation/MS +refute/BDRSZG +refuter/M +reg +regal/DYG +regalement/M +regalia/M +regard/ESMDG +regardless +regards/M +regather/DGS +regatta/SM +regency/SM +regeneracy/M +regenerate/V +regex/M +regexp/S +reggae/M +regicide/MS +regime/SM +regimen/SM +regiment/MDGS +regimental +regimentation/M +region/SM +regional/Y +regionalism/MS +register/GMDS +registered/U +registrant/MS +registrar/MS +registration/SM +registry/SM +regnant +regress/MDSGV +regression/MS +regret/SM +regretful/Y +regrettable +regrettably +regretted +regretting +regrind/GS +reground +regroup/DGS +regular/MYS +regularity/SM +regularization/M +regularize/DSG +regulate/CDSGNV +regulated/U +regulation/CM +regulations +regulator/MS +regulatory +regurgitate/DSGN +regurgitation/M +rehab/MS +rehabbed +rehabbing +rehabilitate/GNVDS +rehabilitation/M +rehang/SDG +rehears/GD +rehearsal/MS +rehearsed/U +rehi +rehung +reign/MDSG +reimburse/BDSGL +reimbursement/MS +rein/GD +reindeer/M +reinforce/LGDS +reinforcement/SM +reinitialize +reinstall/DG +reinstatement/M +reinsurance +reiterate/V +reject/GSMD +rejection/SM +rejoice/JGDS +rejoicing/M +rejoinder/SM +rejuvenate/DSGN +rejuvenation/M +rel +relate/DRSXZGNV +relatedness/M +relater/M +relation/M +relational +relationship/MS +relative/MYS +relativism/M +relativist/S +relativistic +relativity/M +relax/DRSZG +relaxant/MS +relaxation/SM +relaxer/M +relay/D +release/B +released/U +relegate/GNDS +relent/SGD +relentless/PY +relentlessness/M +relevance/M +relevancy/M +relevant/Y +reliability/UM +reliable/U +reliably/U +reliance/M +reliant +relic/MS +relief/SM +relieve/ZGDRS +reliever/M +religion/SM +religiosity +religious/MYP +religiousness/M +reline/DSG +relinquish/LDSG +relinquishment/M +reliquary/SM +relish/GMDS +relist/SGD +relocate/B +reluctance/M +reluctant/Y +rely/GDS +rem/M +remain/SGD +remainder/GMDS +remand/SGD +remapping +remark/B +remarkableness/M +remarkably +remarked/U +remediable +remedy/GDSM +remember/DG +remembered/U +remembrance/MS +reminder/M +reminisce/GDS +reminiscence/MS +reminiscent/Y +remiss/PY +remissness/M +remit/S +remittance/SM +remitted +remitting/U +remix/DSG +remnant/MS +remodel/GDS +remold/SGD +remonstrant/SM +remonstrate/DSG +remorse/M +remorseful/Y +remorseless/PY +remorselessness/M +remote/RSMYTP +remoteness/M +removal/SM +remunerate/GNVXDS +remuneration/M +renaissance/MS +renal +renascence/S +rend/GS +render/SGMDJ +rendering/M +rendezvous/GMDS +rendition/MS +renegade/DSMG +renege/DRSZG +reneger/M +renew/DSBG +renewal/MS +rennet/M +rennin/M +renounce/LDSG +renouncement/M +renovate/DSXGN +renovation/M +renovator/MS +renown/MD +rent/ZGMDRS +rental/SM +renter/M +renunciation/SM +reopen/SDG +reorg/MDSG +rep/SM +repaint/GDS +repair/BZR +repairer/M +repairman/M +repairmen +reparable +reparation/MS +reparations/M +repartee/M +repatriate/XDSMGN +repatriation/M +repeat/SMDRZGB +repeatable/U +repeatably +repeated/Y +repeater/M +repeating/M +repel/S +repelled +repellent/SM +repelling +repent/SDG +repentance/M +repentant/Y +repercussion/S +repertoire/MS +repertory/SM +repetition/MS +repetitious/YP +repetitiousness/M +repetitive/YP +repetitiveness/M +rephotograph/DG +replaceable +replant/GSD +replenish/LGDS +replenishment/M +replete/PDSGN +repleteness/M +repletion/M +replica/SM +replicate/DSGNX +replication/M +replicator/S +reportage/M +reported/Y +reportorial +reposeful +repository/SM +reprehend/DGS +reprehensibility/M +reprehensible +reprehensibly +reprehension/M +represent/GDS +representational +representative/MS +represented/U +repression/MS +repressive/PY +reprieve/DSMG +reprimand/GSMD +reprisal/SM +reprise/SMG +reproach/GMDSB +reproachful/Y +reprobate/MS +reproductive +reprogramming +reproving/Y +reptile/SM +reptilian/MS +republic/S +republicanism/M +repudiate/XGNDS +repudiation/M +repudiator/MS +repugnance/M +repugnant +repulsion/M +repulsive/YP +repulsiveness/M +repurchase/GDS +reputability/M +reputably/E +reputation/MS +repute/DSMGB +reputed/Y +request/GDR +requiem/SM +require/LDG +requirement/MS +requisite/XMNS +requisition/GMD +requital/M +requite/DRSZG +requited/U +requiter/M +reread/SG +rerecord/GDS +rerunning +resat +rescind/SDG +rescission/M +rescue/DRSMZG +rescuer/M +reseal/B +resell/SG +resemble/DSG +resend +resent/LSDG +resentful/YP +resentfulness/M +resentment/MS +reserpine/M +reservation/MS +reserved/UY +reservedness/M +reservist/SM +reservoir/SM +resetting +reshipping +residence/SM +residency/SM +resident/MS +residential +residua +residual/MS +residue/SM +residuum/M +resignation/SM +resigned/Y +resilience/M +resiliency/M +resilient/Y +resinous +resist/SMDRZG +resistance/SM +resistant/U +resistible +resistless +resistor/MS +resit/S +resitting +resold +resole/DSG +resolute/PY +resoluteness/M +resolve/RBM +resolved/U +resonance/SM +resonant/Y +resonate/GDS +resonator/SM +resorption/M +resound/SGD +resounding/Y +resourceful/YP +resourcefulness/M +resp +respect/ESGVMD +respectability/M +respectable +respectably +respectful/EY +respectfulness/M +respective/Y +respell/SGD +respiration/M +respirator/SM +respiratory +respire/DG +resplendence/M +resplendent/Y +respond/SGD +respondent/SM +response/MS +responsibility/SM +responsible +responsibly +responsive/UYP +responsiveness/UM +rest/GVMDS +restate/GDS +restaurant/SM +restaurateur/MS +restful/YP +restfuller +restfullest +restfulness/M +restitution/M +restive/YP +restiveness/M +restless/PY +restlessness/M +restoration/SM +restorative/SM +restorer/SM +restrained/U +restraint/MS +restrict/SDGV +restricted/U +restriction/MS +restrictive/YP +restrictiveness/M +restring/SG +restroom/SM +restructuring/SM +result/GSMD +resultant/SM +resume/DSMG +resumption/MS +resupply/DSG +resurgence/MS +resurgent +resurrect/GSD +resurrection/MS +resuscitate/GNDS +resuscitation/M +resuscitator/SM +retailer/MS +retain/SDRZG +retainer/M +retake/G +retaliate/DSGNVX +retaliation/M +retaliatory +retard/SMDRZG +retardant/SM +retardation/M +retarder/M +retch/DSG +reteach/GS +retention/M +retentive/YP +retentiveness/M +rethink/SGM +rethought +reticence/M +reticent/Y +reticulated +reticulation/MS +retina/SM +retinal +retinue/SM +retiree/SM +retirement/MS +retort/GMD +retrace/GDS +retract/DBG +retractile +retraction/S +retrain/DGS +retread/D +retrenchment/MS +retribution/MS +retributive +retrieval/SM +retrieve/DRSMZGB +retriever/M +retro/MS +retroactive/Y +retrofire/GDS +retrofit/SM +retrofitted +retrofitting +retrograde/DSG +retrogress/GVDS +retrogression/M +retrorocket/MS +retrospect/MDSGV +retrospection/M +retrospective/MYS +retrovirus/MS +retsina/M +returnable/SM +returnee/SM +rev/ZVM +revamping/M +reveal/GJSD +revealed/U +revealing/Y +reveille/M +revel/JMDRSZG +revelation/SM +reveler/M +revelry/SM +revenge/MGDS +revenuer/SM +reverb +reverberate/DSGNX +reverberation/M +revere/DSG +reverence/DSMG +reverend/SM +reverent/Y +reverential/Y +reverie/MS +revers/M +reversal/SM +reverse/Y +reversibility +reversible +reversibly +revert/GSD +revertible +revetment/SM +revile/DRSLZG +revilement/M +reviler/M +reviser/MS +revision/SM +revisionism/M +revisionist/SM +revival/MS +revivalism/M +revivalist/SM +revive/DSG +revivification/M +revocable +revoke/DSG +revolt/GD +revolting/Y +revolution/SM +revolutionary/SM +revolutionist/SM +revolutionize/DSG +revolve/BZGDRS +revolver/M +revue/MS +revulsion/M +revved +revving +rewarded/U +rewarding/U +rewarm/GSD +rewash/GDS +reweave/GS +rewedding +rewind/MB +rewound +rewrite/MGS +rhapsodic +rhapsodical +rhapsodize/GDS +rhapsody/SM +rhea/MS +rhenium/M +rheostat/SM +rhesus/MS +rhetoric/M +rhetorical/Y +rhetorician/SM +rheum/M +rheumatic/MS +rheumatically +rheumatism/M +rheumatoid +rheumy +rhinestone/SM +rhinitis/M +rhino/MS +rhinoceros/MS +rhinoplasty +rhinovirus/MS +rhizome/MS +rho/SM +rhodium/M +rhododendron/SM +rhomboid/SM +rhomboidal +rhombus/MS +rhubarb/MS +rhyme/MZGDRS +rhymer/M +rhymester/MS +rhythm/SM +rhythmic +rhythmical/Y +rial/MS +rib/SM +ribald +ribaldry/M +ribbed +ribber/SM +ribbing +ribbon/SM +riboflavin/M +rice/MZGDRS +ricer/M +rich/TMRSYP +richness/M +rick/GMDS +rickets/M +rickety/RT +rickrack/M +rickshaw/MS +ricochet/GMDS +ricotta/M +rid/S +riddance/M +ridden +ridding +riddle/DSMG +ride/MZGRS +rider/M +riderless +ridership/M +ridge/MGDS +ridgepole/SM +ridgy +ridicule/MGDS +ridiculous/YP +ridiculousness/M +riding/M +rife/TR +riff/GMDS +riffle/DSMG +riffraff/M +rifle/MZGDRS +rifleman/M +riflemen +rifler/M +rifling/M +rift/GMDS +rig/SM +rigamarole/SM +rigatoni/M +rigged +rigger/SM +rigging/M +right/MDRYSPTG +righteous/UP +righteously +righteousness/UM +rightful/PY +rightfulness/M +rightism/M +rightist/SM +rightmost +rightness/M +righto +rightsize/DSG +rightward/S +rigid/YP +rigidity/M +rigidness/M +rigmarole/MS +rigor/MS +rigorous/YP +rigorousness/M +rile/GDS +rill/MS +rim/SGMD +rime/MS +rimless +rimmed +rimming +rind/MS +ring/ZGMDRJ +ringer/M +ringgit/MS +ringleader/MS +ringlet/MS +ringlike +ringmaster/MS +ringside/M +ringtone/SM +ringworm/M +rink/MS +rinse/MGDS +riot/ZGMDRS +rioter/M +rioting/M +riotous/PY +rip/SXTMNR +riparian +ripcord/MS +ripe/YP +ripen/DG +ripened/U +ripeness/M +ripoff/SM +riposte/MGDS +ripped +ripper/SM +ripping +ripple/DSMG +ripply +ripsaw/SM +riptide/MS +rise/JMZGRS +risen +riser/M +risibility/M +risible +rising/M +risk/GMDS +riskily +riskiness/M +risky/RPT +risotto/MS +risque +risqué +rissole/S +rite/MS +ritual/SMY +ritualism/M +ritualistic +ritualistically +ritualized +ritzy/RT +riv/ZNR +rival/MDSG +rivaled/U +rivalry/SM +rive/CGDS +river/M +riverbank/SM +riverbed/MS +riverboat/SM +riverfront +riverside/MS +rivet/MDRSZG +riveter/M +riviera/S +rivulet/MS +riyal/MS +rm +roach/GMDS +road/IMS +roadbed/SM +roadblock/MDSG +roadhouse/SM +roadie/MS +roadkill/M +roadrunner/SM +roadshow/SM +roadside/SM +roadster/SM +roadway/SM +roadwork/SM +roadworthy +roam/ZGDRS +roamer/M +roaming/M +roan/MS +roar/ZGMDRS +roarer/M +roaring/M +roast/ZGMDRSJ +roaster/M +roasting/M +rob/S +robbed +robber/MS +robbery/SM +robbing +robe's +robe/EGDS +robin/MS +robocall/SGMD +robot/MS +robotic/S +robotics/M +robotize/GDS +robust/RYPT +robustness/M +rock/ZGMDRS +rockabilly/M +rockbound +rocker/M +rockery/S +rocket/MDSG +rocketry/M +rockfall/SM +rockiness/M +rocky/TRP +rococo/M +rod/SM +rode +rodent/MS +rodeo/MS +roe/SM +roebuck/SM +roentgen/MS +roger/GDS +rogue's +rogue/KS +roguery/M +roguish/YP +roguishness/M +roil/GDS +roister/ZGDRS +roisterer/M +role/MS +roll/MDRZGJS +rollback/SM +roller/M +rollerblading +rollerskating/M +rollick/SDG +rollicking/M +rollmop/S +rollover/SM +romaine/MS +roman/M +romance/MZGDRS +romancer/M +romantic/MS +romantically +romanticism/M +romanticist/SM +romanticize/DSG +romeo/MS +romp/MDRZGS +romper/M +rondo/SM +rood/MS +roof/MDRZGS +roofer/M +roofing/M +roofless +rooftop/SM +rook/MDGS +rookery/SM +rookie/SM +room/MDRZGS +roomer/M +roomette/SM +roomful/SM +roominess/M +roommate/SM +roomy/RTP +roost/SMDRZG +rooster/M +root/MDRZGS +rooter/M +rootkit/SM +rootless/P +rootlet/SM +rope/MZGDRS +roper/M +ropy/RT +rosary/SM +rose/MS +roseate +rosebud/SM +rosebush/MS +rosemary/M +rosette/SM +rosewater/M +rosewood/MS +rosily +rosin/SMDG +rosiness/M +roster/SM +rostrum/MS +rosy/RTP +rot/SM +rota/S +rotary/SM +rotate/DSGNX +rotation/M +rotational +rotatory +rote/M +rotgut/M +rotisserie/SM +rotogravure/MS +rotor/SM +rototiller/MS +rotted +rotten/TPRY +rottenness/M +rotter/S +rotting +rottweiler/S +rotund/P +rotunda/MS +rotundity/M +rotundness/M +roue/MS +rouge/DSMG +rough/MDNRYXTGP +roughage/M +roughcast +roughen/GD +roughhouse/MGDS +roughneck/GMDS +roughness/M +roughs +roughshod +roulette/M +round/PSMDRYZTG +roundabout/SM +roundel/S +roundelay/MS +roundhouse/SM +roundish +roundness/M +roundup/MS +roundworm/SM +rouse/DSG +roust/SDG +roustabout/SM +rout/MRZS +route's +route/ADSG +routeing +router/M +routine/MYS +routinize/GDS +roux +roué/MS +rove/ZGDRS +rover/M +row/SZGMDR +rowan/S +rowboat/MS +rowdily +rowdiness/M +rowdy/PRSMT +rowdyism/M +rowel/SMDG +rower/M +rowing/M +rowlock/S +royal/SMY +royalist/SM +royalties/M +royalty/SM +rpm +rps +rt +rte +rub/SM +rubato/SM +rubbed +rubber/SM +rubberize/GDS +rubberneck/MDRSZG +rubbernecker/M +rubbery +rubbing/S +rubbish/MDSG +rubbishy +rubble/M +rubdown/SM +rube/MS +rubella/M +rubicund +rubidium/M +ruble/SM +rubric/SM +ruby/RSMT +ruched +ruck/DGS +rucksack/MS +ruckus/MS +ructions +rudder/SM +rudderless +ruddiness/M +ruddy/RTP +rude/YTRP +rudeness/M +rudiment/SM +rudimentary +rue/DSMG +rueful/PY +ruefulness/M +ruff/MDYGS +ruffian/MYS +ruffle/DSMG +ruffled/U +rug/SM +rugby/M +rugged/PTRY +ruggedness/M +rugger +rugrat/SM +ruin/MDGS +ruination/M +ruinous/Y +rule/MZGJDRS +ruler/M +ruling/M +rum/SM +rumba/SMDG +rumble/DSJMG +rumbling/M +rumbustious +ruminant/MS +ruminate/XGNVDS +rumination/M +ruminative/Y +rummage/DSMG +rummer +rummest +rummy/M +rumor/SMDG +rumormonger/SM +rump/MYS +rumple/DSMG +rumpus/MS +run/ASM +runabout/MS +runaround/SM +runaway/MS +rundown/SM +rune/MS +rung/MS +runic +runlet/SM +runnel/SM +runner/SM +running/M +runny/RT +runoff/SM +runt/MS +runty/RT +runway/SM +rupee/SM +rupiah/M +rupiahs +rupture/MGDS +rural +ruse/MS +rush/MDRSZG +rusher/M +rushy +rusk/MS +russet/SM +rust/MDGS +rustic/SM +rustically +rusticate/GDS +rustication/M +rusticity/M +rustiness/M +rustle/DRSJMZG +rustler/M +rustproof/SDG +rusty/RPNT +rut/SM +rutabaga/SM +ruthenium/M +rutherfordium/M +ruthless/YP +ruthlessness/M +rutted +rutting +rutty/RT +rye/M +s/NYXB +sabbath/M +sabbaths +sabbatical/SM +saber/MS +sable/MS +sabot/MS +sabotage/DSMG +saboteur/SM +sabra/MS +sabre/MS +sac/SM +saccharin/M +saccharine +sacerdotal +sachem/SM +sachet/SM +sack/ZGMDRJS +sackcloth/M +sacker/M +sackful/MS +sacking/M +sacra +sacrament/MS +sacramental +sacred/YP +sacredness/M +sacrifice/DSMG +sacrificial/Y +sacrilege/MS +sacrilegious/Y +sacristan/MS +sacristy/SM +sacroiliac/MS +sacrosanct/P +sacrosanctness/M +sacrum/M +sad/PY +sadden/SDG +sadder +saddest +saddle's +saddle/UDSG +saddlebag/MS +saddler/S +saddlery +sades +sadhu/S +sadism/M +sadist/SM +sadistic +sadistically +sadness/M +sadomasochism/M +sadomasochist/MS +sadomasochistic +safari/SGMD +safe/MYTPRS +safeguard/SMDG +safekeeping/M +safeness/M +safety/SM +safflower/MS +saffron/MS +sag/SM +saga/MS +sagacious/Y +sagacity/M +sage/MYTRS +sagebrush/M +sagged +sagging +saggy/RT +sago/M +saguaro/MS +sahib/MS +said/U +sail/GMDSJ +sailboard/MRZGS +sailboarder/M +sailboarding/M +sailboat/MS +sailcloth/M +sailfish/MS +sailing/M +sailor/SM +sailplane/MS +saint/MDYS +sainthood/M +saintlike +saintliness/M +saintly/PRT +saith +sake/M +saki/M +salaam/SMDG +salable/U +salacious/PY +salaciousness/M +salacity/M +salad/MS +salamander/SM +salami/SM +salary/DSM +sale/ABMS +saleable/U +saleroom/S +salesclerk/SM +salesgirl/SM +saleslady/SM +salesman/M +salesmanship/M +salesmen +salespeople/M +salesperson/MS +salesroom/S +saleswoman/M +saleswomen +salience/M +salient/SMY +saline/SM +salinity/M +saliva/M +salivary +salivate/GNDS +salivation/M +sallow/RTP +sallowness/M +sally/DSMG +salmon/SM +salmonella/M +salmonellae +salon/MS +saloon/SM +salsa/MS +salt's +salt/CTGDS +saltbox/MS +saltcellar/SM +salted/U +salter +saltine/SM +saltiness/M +saltpeter/M +saltshaker/SM +saltwater/M +salty/RTP +salubrious/I +salutary +salutation/MS +salutatorian/MS +salutatory +salute/DSMG +salvage/DSMG +salvageable +salvation/M +salve/MZGDRS +salver/M +salvo/MS +samarium/M +samba/MDSG +same/SP +sameness/M +samey +samizdat/S +samosa/S +samovar/SM +sampan/SM +sample/DRSMZGJ +sampler/M +sampling/M +samurai/SM +sanatorium/SM +sanctification/M +sanctify/GDSN +sanctimonious/YP +sanctimoniousness/M +sanctimony/M +sanction/GSMD +sanctioned/U +sanctity/M +sanctuary/SM +sanctum/SM +sand/ZGMDRS +sandal/SM +sandalwood/M +sandbag/SM +sandbagged +sandbagger/SM +sandbagging +sandbank/MS +sandbar/SM +sandblast/ZGMDRS +sandblaster/M +sandbox/MS +sandcastle/MS +sander/M +sandhog/SM +sandiness/M +sandlot/SM +sandlotter/MS +sandman/M +sandmen +sandpaper/GMDS +sandpiper/MS +sandpit/S +sandstone/M +sandstorm/SM +sandwich/MDSG +sandy/RTP +sane/IYTR +saneness/M +sang/S +sangfroid/M +sangria/M +sanguinary +sanguine/Y +sanitarian/SM +sanitarium/SM +sanitary/IU +sanitation/M +sanitize/GDS +sanity/IM +sank +sans +sanserif +sap/SM +sapience/M +sapiens +sapient +sapless +sapling/MS +sapped +sapper/S +sapphire/SM +sappiness/M +sapping +sappy/PRT +saprophyte/SM +saprophytic +sapsucker/SM +sapwood/M +saran/M +sarcasm/MS +sarcastic +sarcastically +sarcoma/MS +sarcophagi +sarcophagus/M +sardine/MS +sardonic +sardonically +sarge/MS +sari/MS +sarky +sarnie/S +sarong/SM +sarsaparilla/MS +sartorial/Y +sash/MS +sashay/SGMD +sass/GMDS +sassafras/MS +sassy/RT +sat +satanic +satanical/Y +satanism/M +satanist/MS +satay +satchel/MS +sate/GDS +sateen/M +satellite/DSMG +satiable/I +satiate/GNDS +satiation/M +satiety/M +satin/M +satinwood/SM +satiny +satire/SM +satiric +satirical/Y +satirist/SM +satirize/DSG +satisfaction/EM +satisfactions +satisfactorily/U +satisfactory/U +satisfied/U +satisfy/EDSG +satisfying/U +satisfyingly +satori/M +satrap/SM +satsuma/S +saturate/DSGN +saturated/U +saturation/M +saturnine +satyr/MS +satyriasis/M +satyric +sauce/MZGDRS +saucepan/SM +saucer/M +saucily +sauciness/M +saucy/RPT +sauerkraut/M +sauna/MDSG +saunter/MDGS +saurian +sauropod/SM +sausage/MS +saute/MS +sauteed +sauteing +sauternes/M +sauté/MDSG +savage/DRSMYTGP +savageness/M +savagery/SM +savanna/MS +savant/SM +save/BJMZGDRS +saveable +saved/U +saver/M +saving/M +savings/M +savior/SM +savor/MDSG +savoriness/M +savory/PTRSM +savoy/MS +savvy/DRSMTG +saw/SGMD +sawbones/M +sawbuck/MS +sawdust/M +sawfly/SM +sawhorse/SM +sawmill/MS +sawyer/SM +sax/MS +saxifrage/SM +saxophone/MS +saxophonist/SM +say's +say/USG +saying/SM +scab/MS +scabbard/MS +scabbed +scabbiness/M +scabbing +scabby/PTR +scabies/M +scabrous +scad/MS +scaffold/SMG +scaffolding/M +scag/S +scagged +scalar/S +scalawag/MS +scald/MDSG +scale's +scale/CGDS +scaleless +scalene +scaliness/M +scallion/MS +scallop/GSMD +scallywag/MS +scalp/MDRSZG +scalpel/SM +scalper/M +scaly/RTP +scam/MS +scammed +scammer/S +scamming +scamp/MRSZ +scamper/GMD +scampi/M +scan/MS +scandal/SM +scandalize/DSG +scandalmonger/SM +scandalous/Y +scandium/M +scanned +scanner/SM +scanning +scansion/M +scant/CDSTG +scanter +scantily +scantiness/M +scantly +scantness/M +scanty/RSPT +scapegoat/SGMD +scapegrace/MS +scapula/M +scapulae +scapular/SM +scar/GMDS +scarab/SM +scarce/RYTP +scarceness/M +scarcity/SM +scare/MS +scarecrow/MS +scaremonger/SMG +scarf/MDSG +scarification/M +scarify/NDSG +scarily +scariness/M +scarlatina/M +scarlet/M +scarp/MDRSZG +scarper/DG +scarred +scarring +scarves +scary/RTP +scat/MS +scathing/Y +scatological +scatology/M +scatted +scatter/GJSMD +scatterbrain/SMD +scattering/M +scattershot +scatting +scatty +scavenge/ZGDRS +scavenger/M +scenario/MS +scenarist/MS +scene/MS +scenery/M +scenic +scenically +scent/CMS +scented/U +scenting +scentless +scepter/MS +sch +schadenfreude +schedule's +schedule/ADSG +scheduled/U +scheduler/S +schema +schemata +schematic/SM +schematically +schematize/GDS +scheme/DRSMZG +schemer/M +scherzo/MS +schilling/MS +schism/SM +schismatic/SM +schist/M +schizo/SM +schizoid/MS +schizophrenia/M +schizophrenic/SM +schlemiel/SM +schlep/SM +schlepp/GMDS +schlock/M +schlocky +schmaltz/M +schmaltzy/TR +schmo/M +schmoe/SM +schmooze/DRSZG +schmuck/MS +schnapps/M +schnauzer/SM +schnitzel/SM +schnook/MS +schnoz/MS +schnozzle/SM +scholar/MYS +scholarship/MS +scholastic +scholastically +scholasticism +school/SGMD +schoolbag/MS +schoolbook/SM +schoolboy/MS +schoolchild/M +schoolchildren/M +schooldays +schooled/U +schoolfellow/SM +schoolgirl/SM +schoolhouse/SM +schooling/M +schoolkid/S +schoolmarm/SM +schoolmarmish +schoolmaster/MS +schoolmate/SM +schoolmistress/MS +schoolroom/SM +schoolteacher/MS +schoolwork/M +schoolyard/SM +schooner/SM +schuss/GMDS +schussboomer/MS +schwa/MS +sci +sciatic +sciatica/M +science/FMS +scientific/U +scientifically/U +scientist/SM +scimitar/SM +scintilla/MS +scintillate/DSGN +scintillation/M +scion/MS +scissor/GDS +scleroses +sclerosis/M +sclerotic +scoff/MDRSZG +scoffer/M +scofflaw/MS +scold/MDSGJ +scolding/M +scoliosis/M +sconce/SM +scone/MS +scoop/MDSG +scoopful/MS +scoot/DRSZG +scooter/M +scope/MGDS +scorbutic +scorch/MDRSZG +scorcher/M +score/MZGDRS +scoreboard/SM +scorecard/MS +scorekeeper/MS +scoreless +scoreline/S +scorer/M +scorn/MDRSZG +scorner/M +scornful/Y +scorpion/MS +scotch/MDSG +scotchs +scoundrel/MS +scour/DRSZG +scourer/M +scourge/DSMG +scout/MDRSZG +scouting/M +scoutmaster/MS +scow/MS +scowl/MDSG +scrabble/MZGDRS +scrabbler/M +scrag/MS +scraggly/RT +scraggy/TR +scram/S +scramble's +scramble/UGDS +scrambler/MS +scrammed +scramming +scrap/MDRSZGJ +scrapbook/SM +scrape/SM +scraper/M +scrapheap/SM +scrapie +scrapped +scrapper/MS +scrapping +scrappy/TR +scrapyard/SM +scratch/GMDS +scratchcard/S +scratched/U +scratchily +scratchiness/M +scratchpad/S +scratchy/PRT +scrawl/SMDG +scrawly +scrawniness/M +scrawny/PTR +scream/SMDRZG +screamer/M +screaming/Y +scree/MDS +screech/GMDS +screechy/TR +screed/S +screen/SJMDG +screening/M +screenplay/SM +screensaver/SM +screenshot/S +screenwriter/SM +screenwriting/M +screw's +screw/UDSG +screwball/MS +screwdriver/MS +screwiness/M +screwworm/SM +screwy/PRT +scribal +scribble/MZGDRS +scribbler/M +scribe's +scribe/CKIS +scrim/MS +scrimmage/MGDS +scrimp/SDG +scrimshaw/MDGS +scrip/MS +script/FSMDG +scripted/U +scriptural +scripture/MS +scriptwriter/SM +scrivener/SM +scrod/M +scrofula/M +scrofulous +scrog/S +scroll/GSMD +scrooge/MS +scrota +scrotal +scrotum/M +scrounge/DRSZG +scrounger/M +scroungy/TR +scrub/MS +scrubbed +scrubber/SM +scrubbing +scrubby/RT +scruff/SM +scruffily +scruffiness/M +scruffy/RPT +scrum/S +scrumhalf +scrumhalves +scrummage/S +scrummed +scrumming +scrump/SGD +scrumptious/Y +scrumpy +scrunch/MDSG +scrunchie/M +scrunchy/SM +scruple/MGDS +scrupulosity/M +scrupulous/UPY +scrupulousness/UM +scrutineer/S +scrutinize/GDS +scrutiny/M +scuba/MDSG +scud/MS +scudded +scudding +scuff/MDSG +scuffle/MGDS +scull/MDRSZG +sculler/M +scullery/SM +scullion/SM +sculpt/SGD +sculptor/SM +sculptress/MS +sculptural +sculpture/DSMG +scum/MS +scumbag/MS +scummed +scumming +scummy/TR +scupper/MDGS +scurf/M +scurfy +scurrility/M +scurrilous/PY +scurrilousness/M +scurry/GDSM +scurvily +scurvy/TRM +scutcheon/SM +scuttle/MGDS +scuttlebutt/M +scuzzy/TR +scythe/DSMG +sea/SM +seabed/SM +seabird/MS +seaboard/SM +seaborne +seacoast/SM +seafarer/SM +seafaring/M +seafloor/SM +seafood/M +seafront/SM +seagoing +seagull/MS +seahorse/MS +seal's +seal/AUSDG +sealant/MS +sealer/SM +sealskin/M +seam/GMDNS +seaman/M +seamanship/M +seamless/Y +seamount/MS +seamstress/MS +seamy/RT +seance/SM +seaplane/SM +seaport/MS +sear/GMDS +search/AZGMDRS +searcher/AM +searching/Y +searchlight/MS +searing/Y +seascape/SM +seashell/SM +seashore/SM +seasick/P +seasickness/M +seaside/MS +season/SGMDBJ +seasonable/U +seasonably/U +seasonal/Y +seasonality +seasoned/U +seasoning/M +seat's +seat/UGDS +seating/M +seatmate/SM +seawall/MS +seaward/MS +seawater/M +seaway/SM +seaweed/MS +seaworthiness/M +seaworthy/P +sebaceous +seborrhea/M +sebum +sec'y +sec/SM +secant/SM +secateurs +secede/DSG +secession/M +secessionist/MS +seclude/GDS +seclusion/M +seclusive +second/SLZGMDRY +secondarily +secondary/SM +seconder/M +secondhand +secondment/S +secrecy/M +secret/SGVMDY +secretarial +secretariat/MS +secretary/SM +secretaryship/M +secrete/XNS +secretion/M +secretive/PY +secretiveness/M +secretory +sect/IMS +sectarian/MS +sectarianism/M +sectary/SM +section/AESM +sectional/MS +sectionalism/M +sectioned +sectioning +sector/ESM +secular +secularism/M +secularist/SM +secularization/M +secularize/DSG +secure/DRSYTG +secured/U +security/ISM +secy +sedan/MS +sedate/DRSYTGNVP +sedateness/M +sedation/M +sedative/SM +sedentary +sedge/M +sedgy +sediment/MS +sedimentary +sedimentation/M +sedition/M +seditious +seduce/DRSZG +seducer/M +seduction/SM +seductive/YP +seductiveness/M +seductress/MS +sedulous/Y +see/RSMZ +seed's +seed/AGDS +seedbed/MS +seedcase/MS +seeded/U +seeder/SM +seediness/M +seedless +seedling/MS +seedpod/MS +seedy/RPT +seeing/S +seek/ZGRS +seeker/M +seem/GDS +seeming/Y +seemliness/UM +seemly/URTP +seen/U +seep/GDS +seepage/M +seer/M +seersucker/M +seesaw/SMDG +seethe/DSG +segfault/S +segment/GSMD +segmentation/M +segmented/U +segregate/CDSGN +segregated/U +segregation/CM +segregationist/MS +segue/MGDS +segueing +seigneur/SM +seignior/SM +seigniorial +seine/MZGDRS +seiner/M +seismic +seismically +seismograph/ZMR +seismographer/M +seismographic +seismographs +seismography/M +seismologic +seismological +seismologist/MS +seismology/M +seize/GDS +seizure/MS +seldom +select/CSGVD +selection/SM +selective/Y +selectivity/M +selectman/M +selectmen +selectness/M +selector/MS +selenium/M +selenographer/MS +selenography/M +self/M +selfie/SM +selfish/UYP +selfishness/UM +selfless/PY +selflessness/M +selfsame +sell/ZGMRS +seller/M +selloff/MS +sellotape/DSG +sellout/MS +seltzer/MS +selvage/MS +selvedge/MS +selves +semantic/S +semantically +semanticist/MS +semantics/M +semaphore/DSMG +semblance/ASM +semen/M +semester/SM +semi/MS +semiannual/Y +semiarid +semiautomatic/MS +semibreve/S +semicircle/SM +semicircular +semicolon/MS +semiconducting +semiconductor/MS +semiconscious +semidarkness/M +semidetached +semifinal/SM +semifinalist/MS +semigloss/S +semimonthly/SM +seminal +seminar/MS +seminarian/SM +seminary/SM +semiofficial +semiotic/S +semiotics/M +semipermeable +semiprecious +semiprivate +semipro/S +semiprofessional/SM +semiquaver/S +semiretired +semiskilled +semisolid +semisweet +semitone/SM +semitrailer/MS +semitransparent +semitropical +semivowel/SM +semiweekly/SM +semiyearly +semolina/M +sempstress/MS +senate/SM +senator/MS +senatorial +send/ZGRS +sender/M +sendoff/MS +senescence/M +senescent +senile +senility/M +senior/SM +seniority/M +senna/M +senor/MS +senora/SM +senorita/SM +sensation/MS +sensational/Y +sensationalism/M +sensationalist/MS +sensationalize/GDS +sense/MGDS +senseless/PY +senselessness/M +sensibilities +sensibility/IM +sensible/P +sensibleness/M +sensibly/I +sensitive/SMYP +sensitiveness/M +sensitivities +sensitivity/IM +sensitization/CM +sensitize/CDSG +sensor/SM +sensory +sensual/Y +sensualist/SM +sensuality/M +sensuous/YP +sensuousness/M +sent/FAU +sentence/MGDS +sententious/Y +sentience/IM +sentient/I +sentiment/SM +sentimental/Y +sentimentalism/M +sentimentalist/MS +sentimentality/M +sentimentalization/M +sentimentalize/GDS +sentinel/MS +sentry/SM +sepal/MS +separability/IM +separable +separably/I +separate/XMYGNVDSP +separateness/M +separation/M +separatism/M +separatist/MS +separator/MS +sepia/M +sepsis/M +septa +septal +septet/SM +septic +septicemia/M +septicemic +septuagenarian/MS +septum/M +sepulcher/GMDS +sepulchral +seq +sequel/SM +sequence/MZGDRS +sequencing/M +sequential/FY +sequester/SDG +sequestrate/XGNDS +sequestration/M +sequin/SMD +sequinned +sequitur +sequoia/MS +seraglio/MS +serape/SM +seraph/M +seraphic +seraphs +sere/TR +serenade/MGDS +serendipitous +serendipity/M +serene/RPYT +sereneness/M +serenity/M +serf/MS +serfdom/M +serge/M +sergeant/MS +serial/SMY +serialization/SM +serialize/GDS +series/M +serif/MS +serigraph/M +serigraphs +serine +serious/PY +seriousness/M +sermon/SM +sermonize/GDS +serology/M +serotonin +serous +serpent/MS +serpentine/M +serrate/XND +serration/M +serried +serum/MS +servant/MS +serve's/AF +serve/FACGDS +server/SM +servery/S +service/EMS +serviceability/M +serviceable +serviced +serviceman/M +servicemen +servicewoman/M +servicewomen +servicing +serviette/MS +servile +servility/M +serving's +servings +servitor/MS +servitude/M +servo/MS +servomechanism/SM +servomotor/MS +sesame/SM +sesquicentennial/MS +session/MS +set/AISM +setback/MS +setscrew/SM +setsquare/S +sett/BJZGRS +settee/MS +setter/M +setting/M +settle's +settle/AUGDS +settlement/AM +settlements +settler/SM +setup/MS +seven/MHS +seventeen/SMH +seventeenth/M +seventeenths +seventh/M +sevenths +seventieth/M +seventieths +seventy/SMH +sever/ETGDS +several/MY +severance/SM +severe/YPR +severeness/M +severity/M +sew/ASGD +sewage/M +sewer/MS +sewerage/M +sewing/M +sewn/A +sex/GMDS +sexagenarian/SM +sexily +sexiness/M +sexism/M +sexist/MS +sexless +sexologist/SM +sexology/M +sexpot/MS +sextant/SM +sextet/MS +sexting +sexton/MS +sextuplet/SM +sexual/Y +sexuality/M +sexy/PTR +sf +sh +shabbily +shabbiness/M +shabby/PTR +shack/MDSG +shackle's +shackle/UGDS +shad/GMDSJ +shade/MS +shadily +shadiness/M +shading/M +shadow/SGMD +shadowbox/GDS +shadowy/RT +shady/RPT +shaft/MDSG +shag/MS +shagged +shagginess/M +shagging +shaggy/TPR +shah/M +shahs +shake/MZGRS +shakedown/SM +shaken/U +shakeout/MS +shaker/M +shakeup/MS +shakily +shakiness/M +shaky/RPT +shale/M +shall +shallot/MS +shallow/TPMRYS +shallowness/M +shalom +shalt +sham/GMDS +shaman/SM +shamanic +shamanism +shamanistic +shamble/MGDS +shambles/M +shambolic +shame/MS +shamefaced/Y +shameful/PY +shamefulness/M +shameless/YP +shamelessness/M +shammed +shammies +shamming +shampoo/ZGMDRS +shampooer/M +shamrock/MS +shan't +shandy/S +shanghai/DSG +shank/MS +shantung/M +shanty/SM +shantytown/SM +shape's +shape/AGDS +shaped/U +shapeless/YP +shapelessness/M +shapeliness/M +shapely/PTR +shard/MS +share/MZGDRSB +shareable +sharecrop/S +sharecropped +sharecropper/MS +sharecropping +shareholder/SM +shareholding/S +sharer/M +shareware/M +sharia/M +shariah +shark/MDSG +sharkskin/M +sharp/MDNRYSPXZTG +sharpen/ADGS +sharpener/MS +sharper/M +sharpie/M +sharpish +sharpness/M +sharpshooter/SM +sharpshooting/M +sharpy/SM +shat +shatter/GMDS +shatterproof +shave/MZGDRSJ +shaven/U +shaver/M +shaving/M +shawl/MS +shay/MS +she'd +she'll +she/DSM +sheaf/M +shear/MDRSZG +shearer/M +sheath/JM +sheathe/UGDS +sheathing/M +sheaths +sheave/DSMG +shebang/MS +shebeen/S +shed/MS +shedding +sheen/M +sheeny/TR +sheep/M +sheepdog/MS +sheepfold/SM +sheepherder/MS +sheepish/YP +sheepishness/M +sheepskin/MS +sheer/MDRSPTG +sheerness/M +sheet/MSG +sheeting/M +sheetlike +sheik/MS +sheikdom/MS +sheikh/M +sheikhdom/MS +sheikhs +sheila/S +shekel/SM +shelf/M +shell/MDRSG +shellac/MS +shellacked +shellacking/MS +shellfire/M +shellfish/MS +shelter/GMDS +shelve/GDS +shelving/M +shenanigan/SM +shepherd/SMDG +shepherdess/MS +sherbet/SM +sherd/MS +sheriff/SM +sherry/SM +shew/GDS +shewn +shh +shiatsu/M +shibboleth/M +shibboleths +shield/MDGS +shift/GMDS +shiftily +shiftiness/M +shiftless/PY +shiftlessness/M +shifty/RPT +shiitake/SM +shill/GMDSJ +shillelagh/M +shillelaghs +shilling/M +shim/MS +shimmed +shimmer/SMDG +shimmery +shimming +shimmy/DSMG +shin/ZGMDRS +shinbone/SM +shindig/SM +shine/MS +shiner/M +shingle/DSMG +shinguard/M +shininess/M +shinned +shinning +shinny/DSG +shinsplints/M +shiny/TRP +ship's +ship/ALS +shipboard/MS +shipbuilder/SM +shipbuilding/M +shipload/SM +shipmate/SM +shipment/AM +shipments +shipowner/MS +shipped/A +shipper/SM +shipping/M +shipshape +shipwreck/GMDS +shipwright/MS +shipyard/SM +shire/MS +shirk/ZGDRS +shirker/M +shirr/GMDSJ +shirring/M +shirt/GMDS +shirtfront/SM +shirting/M +shirtless +shirtsleeve/SM +shirttail/SM +shirtwaist/MS +shirty +shit/SM! +shitfaced/! +shithead/S! +shitload/! +shitted/! +shitting/! +shitty/RT! +shiv/ZMRS +shiver/MDG +shivery +shoal/GMDS +shoat/MS +shock/ZGMDRS +shocker/M +shocking/Y +shockproof +shod/U +shoddily +shoddiness/M +shoddy/PRMT +shoe/MS +shoehorn/GMDS +shoeing +shoelace/MS +shoemaker/SM +shoeshine/SM +shoestring/SM +shoetree/MS +shogun/MS +shogunate/M +shone +shoo/GDS +shook +shoot/ZGMRSJ +shooter/M +shooting/M +shootout/MS +shop/MS +shopaholic/MS +shopfitter/S +shopfitting +shopfront/S +shopkeeper/MS +shoplift/DRZGS +shoplifter/M +shoplifting/M +shoppe/MZGDRS +shopper/M +shopping/M +shoptalk/M +shopworn +shore/MGDS +shorebird/SM +shoreline/MS +shoring/M +short/XTGMDNRYSP +shortage/MS +shortbread/M +shortcake/MS +shortchange/DSG +shortcoming/MS +shortcrust +shortcut/MS +shorten/JGD +shortening/M +shortfall/MS +shorthand/MD +shorthorn/MS +shortie/M +shortish +shortlist/DGS +shortness/M +shortsighted/PY +shortsightedness/M +shortstop/MS +shortwave/MS +shorty/SM +shot/MS +shotgun/SM +shotgunned +shotgunning +should +should've +shoulder/MDGS +shouldn't +shout/ZGMDRS +shouter/M +shove/MGDS +shovel/MDSG +shovelful/SM +show/JZGMDRS +showbiz/M +showboat/MDGS +showcase/MGDS +showdown/MS +shower/MDG +showerproof +showery +showgirl/MS +showground/S +showily +showiness/M +showing/M +showjumping +showman/M +showmanship/M +showmen +shown +showoff/SM +showpiece/SM +showplace/SM +showroom/MS +showstopper/MS +showstopping +showtime +showy/TRP +shpt +shrank +shrapnel/M +shred/MS +shredded +shredder/MS +shredding +shrew/MS +shrewd/RYPT +shrewdness/M +shrewish +shriek/MDSG +shrift/M +shrike/MS +shrill/DRSPTG +shrillness/M +shrilly +shrimp/MDRSZG +shrine/MS +shrink/MSBG +shrinkage/M +shrive/GDS +shrivel/SGD +shriven +shroud/GMDS +shrub/MS +shrubbery/SM +shrubby/RT +shrug/MS +shrugged +shrugging +shrunk/N +shtick/MS +shuck/GMDS +shucks/S +shudder/MDSG +shuffle/AMGDS +shuffleboard/SM +shuffler/SM +shun/S +shunned +shunning +shunt/MSDG +shush/DSG +shut/S +shutdown/SM +shuteye/M +shutoff/SM +shutout/SM +shutter/SMDG +shutterbug/MS +shutting +shuttle/DSMG +shuttlecock/GMDS +shy/TGDRSMY +shyer +shyest +shyness/M +shyster/SM +sibilant/SM +sibling/SM +sibyl/MS +sibylline +sic/S +sicced +siccing +sick/PXTGDNRYS +sickbay/S +sickbed/SM +sicken/DG +sickening/Y +sickie/MS +sickish +sickle/MS +sickly/RT +sickness/MS +sicko/MS +sickout/SM +sickroom/MS +side's +side/AGDS +sidearm/SM +sidebar/SM +sideboard/SM +sideburns/M +sidecar/SM +sidekick/SM +sidelight/MS +sideline/DSMG +sidelong +sideman/M +sidemen +sidepiece/MS +sidereal +sidesaddle/MS +sideshow/MS +sidesplitting +sidestep/MS +sidestepped +sidestepping +sidestroke/DSMG +sideswipe/DSMG +sidetrack/SMDG +sidewalk/MS +sidewall/MS +sideways +sidewinder/SM +siding/MS +sidle/MGDS +siege/MS +sienna/M +sierra/MS +siesta/MS +sieve/MGDS +sift/ZGDRS +sifted/U +sifter/M +sigh/GMD +sighs +sight/GMDYSJ +sighting/M +sightless +sightly/UTR +sightread +sightseeing/M +sightseer/MS +sigma/MS +sign's/C +sign/AFCGDS +signage/M +signal/MDRYSZG +signaler/M +signalization/M +signalize/GDS +signalman/M +signalmen +signatory/SM +signature/MS +signboard/MS +signed/U +signer/CMS +signet/MS +significance/IM +significant/IY +signification/M +signify/XDSNG +signing's/C +signings +signor/FMS +signora/SM +signore +signori +signorina/MS +signorine +signpost/GSMD +silage/M +silence/DRSMZG +silencer/M +silent/MRYST +silhouette/DSMG +silica/M +silicate/MS +siliceous +silicon/SM +silicone/M +silicosis/M +silk/MNS +silkily +silkiness/M +silkscreen/SM +silkworm/MS +silky/TRP +sill/MS +silliness/M +silly/TRSMP +silo/MS +silt/GMDS +silty/TR +silvan +silver/GMDS +silverfish/MS +silversmith/M +silversmiths +silverware/M +silvery +sim/SM +simian/MS +similar/Y +similarity/ESM +simile/MS +similitude/EM +simmer/GMDS +simonize/DSG +simony/M +simpatico +simper/GMDS +simpering/Y +simple/TRP +simpleminded +simpleness/M +simpleton/SM +simplex +simplicity/M +simplification/M +simplify/DSXNG +simplistic +simplistically +simply +simulacra +simulacrum/S +simulate/EDSGN +simulation/EM +simulations +simulator/EMS +simulcast/GMDS +simultaneity/M +simultaneous/Y +sin/ASM +since +sincere/IYT +sincerer +sincerity/IM +sine/MS +sinecure/MS +sinew/MS +sinewy +sinful/PY +sinfulness/M +sing/BZGMDRYS +singalong/S +singe/MS +singeing +singer/M +singing/M +single/PMGDS +singleness/M +singles/M +singlet/S +singleton/SM +singletree/SM +singsong/SMDG +singular/SMY +singularity/SM +sinister +sink/BZGMRS +sinkable/U +sinker/M +sinkhole/SM +sinless +sinned +sinner/MS +sinning +sinology +sinuosity/M +sinuous/Y +sinus/MS +sinusitis/M +sinusoidal +sip/SM +siphon/GMDS +sipped +sipper/SM +sipping +sir/SXMN +sire/CMGDS +siree/M +siren/M +sirloin/SM +sirocco/SM +sirrah +sirree/M +sis/MS +sisal/M +sissified +sissy/RSMT +sister/ASM +sisterhood/MS +sisterliness/M +sisterly/P +sit/S +sitar/SM +sitarist/MS +sitcom/SM +site/MGDS +sitemap/SM +sitter/SM +sitting/SM +situate/DSXGN +situation/M +situational +six/MSH +sixfold +sixpence/MS +sixshooter/M +sixteen/SMH +sixteenth/M +sixteenths +sixth/M +sixths +sixtieth/M +sixtieths +sixty/SMH +sizable +size's +size/AGDS +sizeable +sizer +sizing/M +sizzle/DRSMZG +ska/M +skate/MZGDRS +skateboard/MDRSZG +skateboarder/M +skateboarding/M +skater/M +skating/M +skedaddle/MGDS +skeet/ZMR +skein/MS +skeletal +skeleton/SM +skeptic/SM +skeptical/Y +skepticism/M +sketch/MDRSZG +sketchbook/S +sketcher/M +sketchily +sketchiness/M +sketchpad/S +sketchy/RTP +skew/MDRZGS +skewbald/S +skewer/MDG +ski/SZGMDR +skibob/S +skid/MS +skidded +skidding +skidpan/S +skier/M +skiff/SM +skiffle +skiing/M +skill's +skill/CSD +skilled/U +skillet/SM +skillful/UY +skillfulness/M +skim/MS +skimmed +skimmer/SM +skimming +skimp/SDG +skimpily +skimpiness/M +skimpy/RTP +skin/MS +skincare/M +skinflick/MS +skinflint/MS +skinful +skinhead/MS +skinless +skinned +skinniness/M +skinning +skinny/RMTP +skint +skintight +skip/MS +skipped +skipper/SMDG +skipping +skirmish/ZGMDRS +skirt/SMDG +skit/MS +skitter/GSD +skittish/YP +skittishness/M +skittle/S +skive/DRSZG +skivvy/DSMG +skoal/SM +skua/S +skulduggery/M +skulk/SDRZG +skulker/M +skull/SM +skullcap/MS +skullduggery/M +skunk/SMDG +sky/GSM +skycap/SM +skydive/DRSZG +skydiver/M +skydiving/M +skyjack/JZGSDR +skyjacker/M +skyjacking/M +skylark/SGMD +skylight/MS +skyline/SM +skyrocket/GSMD +skyscraper/SM +skyward/S +skywriter/SM +skywriting/M +slab/MS +slabbed +slabbing +slack/PXZTGMDNRYS +slacken/DG +slacker/M +slackness/M +slacks/M +slag/MS +slagged +slagging +slagheap/S +slain +slake/GDS +slalom/MSDG +slam/MS +slammed +slammer/SM +slamming +slander/MZGDRS +slanderer/M +slanderous +slang/M +slangy/RT +slant/MSDG +slanting/Y +slantwise +slap/MS +slapdash +slaphappy +slapped +slapper/S +slapping +slapstick/M +slash/MDRSZG +slasher/M +slat/MDGS +slate/SM +slather/SDG +slatted +slattern/SMY +slaughter/MDRZGS +slaughterer/M +slaughterhouse/MS +slave/DRSMZG +slaveholder/MS +slaver/MDG +slavery/M +slavish/PY +slavishness/M +slaw/M +slay/DRZGJS +slayer/M +slaying/M +sleaze/SM +sleazebag/S +sleazeball/S +sleazily +sleaziness/M +sleazy/PRT +sled/MS +sledded +sledder/SM +sledding +sledge/DSMG +sledgehammer/GSMD +sleek/SDRYTGP +sleekness/M +sleep/SMRZG +sleeper/M +sleepily +sleepiness/M +sleepless/PY +sleeplessness/M +sleepover/SM +sleepwalk/ZGSDR +sleepwalker/M +sleepwalking/M +sleepwear/M +sleepy/RPT +sleepyhead/MS +sleet/SMDG +sleety +sleeve/DSM +sleeveless +sleigh/MDG +sleighs +sleight/SM +slender/PRT +slenderize/DSG +slenderness/M +slept +sleuth/MG +sleuths +slew/MDGS +slice/DRSMZG +slicer/M +slick/SMDRYZTGP +slicker/M +slickness/M +slid +slide/RSMZG +slider/M +slideshow/MS +slight/SMDRYTGP +slightness/M +slim/PS +slime/M +sliminess/M +slimline +slimmed +slimmer/S +slimmest +slimming/M +slimness/M +slimy/RTP +sling/SMG +slingback/S +slingshot/SM +slink/SG +slinky/RT +slip/MS +slipcase/MS +slipcover/MS +slipknot/MS +slippage/MS +slipped +slipper/SM +slipperiness/M +slippery/PRT +slipping +slippy +slipshod +slipstream/SM +slipway/SM +slit/MS +slither/SGMD +slithery +slitter +slitting +sliver/GSMD +slob/MS +slobbed +slobber/MDSG +slobbery +slobbing +sloe/MS +slog/MS +slogan/SM +sloganeering +slogged +slogging +sloop/SM +slop/MDGS +slope/SM +slopped +sloppily +sloppiness/M +slopping +sloppy/PTR +slops/M +slosh/DSG +slot/MS +sloth/M +slothful/YP +slothfulness/M +sloths +slotted +slotting +slouch/ZGMDRS +sloucher/M +slouchy/TR +slough/GMD +sloughs +sloven/SMY +slovenliness/M +slovenly/PTR +slow/DRYTGSP +slowcoach/S +slowdown/SM +slowness/M +slowpoke/SM +sludge/M +sludgy/RT +slue/MGDS +slug/MS +sluggard/MS +slugged +slugger/SM +slugging +sluggish/PY +sluggishness/M +sluice/DSMG +slum/MS +slumber/GSMD +slumberous +slumbrous +slumdog/SM +slumlord/MS +slummed +slummer +slumming +slummy/RT +slump/SMDG +slung +slunk +slur/MS +slurp/SMDG +slurred +slurring +slurry/M +slush/M +slushiness/M +slushy/RPT +slut/MS +sluttish +slutty/RT +sly/TRY +slyer +slyest +slyness/M +smack/SMDRZG +smacker/M +small/SMRTP +smallholder/S +smallholding/S +smallish +smallness/M +smallpox/M +smarmy/RT +smart/SMDNRYXTGP +smarten/DG +smartness/M +smartphone/SM +smarts/M +smartwatch/MS +smarty/SM +smartypants/M +smash/MDRSZG +smasher/M +smashup/SM +smattering/MS +smear/SMDG +smeary/RT +smell/SMDG +smelliness/M +smelly/RPT +smelt/SMDRZG +smelter/M +smidgen/MS +smilax/M +smile/DSMG +smiley/SM +smiling/Y +smirch/GMDS +smirk/SMDG +smite/SG +smith/M +smithereens/M +smiths +smithy/SM +smitten +smock/SMDG +smocking/M +smog/MS +smoggy/RT +smoke/DRSMZG +smokehouse/MS +smokeless +smoker/M +smokescreen/SM +smokestack/SM +smokey +smokiness/M +smoking/M +smoky/RTP +smolder/SGMD +smooch/MDSG +smoochy +smooth/PDRYTG +smoothie/M +smoothness/M +smooths +smoothy/SM +smorgasbord/SM +smote +smother/GSMD +smoulder/GMDS +smudge/DSMG +smudgy/TR +smug/YP +smugger +smuggest +smuggle/ZGDRS +smuggler/M +smuggling/M +smugness/M +smurf/S +smut/MS +smuttiness/M +smutty/TRP +smörgåsbord/MS +snack/SMDG +snaffle/DSMG +snafu/SM +snag/MS +snagged +snagging +snail/SMDG +snake/DSMG +snakebite/MS +snakelike +snakeskin +snaky/RT +snap's +snap/US +snapdragon/SM +snapped/U +snapper/MS +snappily +snappiness/M +snapping/U +snappish/YP +snappishness/M +snappy/TRP +snapshot/SM +snare/DSMG +snarf/SDG +snark/S +snarky/TR +snarl's +snarl/USDG +snarling/Y +snarly/TR +snatch/ZGMDRS +snatcher/M +snazzily +snazzy/TR +sneak/SMDRZG +sneaker/M +sneakily +sneakiness/M +sneaking/Y +sneaky/TRP +sneer/SJMDG +sneering/Y +sneeze/DSMG +snick/SDRZG +snicker/MDG +snide/RYT +sniff/SMDRZG +sniffer/M +sniffle/DSMG +sniffy/RT +snifter/SM +snigger/SMDG +snip/MDRZGS +snipe/SM +sniper/M +snipped +snippet/SM +snipping +snippy/RT +snips/M +snit/MS +snitch/MDSG +snivel/SMDRZG +sniveler/M +snob/MS +snobbery/M +snobbish/PY +snobbishness/M +snobby/RT +snog/S +snogged +snogging +snood/SM +snooker/MDSG +snoop/SMDRZG +snooper/M +snoopy/TR +snoot/SM +snootily +snootiness/M +snooty/PTR +snooze/DSMG +snore/DRSMZG +snorer/M +snorkel/ZGMDRS +snorkeler/M +snorkeling/M +snort/SMDRZG +snorter/M +snot/MS +snottily +snottiness/M +snotty/TPR +snout/SM +snow/MDGS +snowball/GSMD +snowbank/SM +snowbird/SM +snowblower/MS +snowboard/ZGMDRS +snowboarder/M +snowboarding/M +snowbound +snowdrift/SM +snowdrop/SM +snowfall/SM +snowfield/SM +snowflake/SM +snowiness/M +snowline +snowman/M +snowmen +snowmobile/DSMG +snowplow/SGMD +snowshed +snowshoe/SM +snowshoeing +snowstorm/SM +snowsuit/SM +snowy/PRT +snub/MS +snubbed +snubbing +snuff/SMDRYZG +snuffbox/MS +snuffer/M +snuffle/MGDS +snug/MYSP +snugged +snugger +snuggest +snugging +snuggle/MGDS +snugness/M +so +soak/MDGSJ +soaking/M +soap/MDGS +soapbox/MS +soapiness/M +soapstone/M +soapsuds/M +soapy/RPT +soar/MDGS +sob/SM +sobbed +sobbing/Y +sober/SDRYPTG +soberness/M +sobriety/IM +sobriquet/SM +soc +soccer/M +sociability/M +sociable/SM +sociably +social/SMY +socialism/M +socialist/SM +socialistic +socialite/SM +socialization/M +socialize/DSG +societal +society/SM +socioeconomic +socioeconomically +sociological/Y +sociologist/SM +sociology/M +sociopath/M +sociopaths +sociopolitical +sock/MDGS +socket/SM +sockeye/SM +sod/SM +soda/MS +sodded +sodden/Y +sodding +sodium/M +sodomite/MS +sodomize/GDS +sodomy/M +soever +sofa/MS +soft/NRYXTP +softback +softball/MS +softbound +softcover +soften/DRZG +softener/M +softhearted +softie/M +softness/M +software/M +softwood/SM +softy/SM +soggily +sogginess/M +soggy/RTP +soigne +soignee +soigné +soignée +soil/MDGS +soiled/U +soiree/SM +soirée/SM +sojourn/ZGMDRS +sojourner/M +sol/SM +solace/DSMG +solar +solaria +solarium/M +sold +solder/ZGSMDR +solderer/M +soldier/MDYSG +soldiery/M +sole/FSDGM +solecism/SM +solely +solemn/PTRY +solemness/M +solemnify/DSG +solemnity/SM +solemnization/M +solemnize/DSG +solemnness/M +solenoid/MS +solicit/GDS +solicitation/SM +solicited/U +solicitor/SM +solicitous/PY +solicitousness/M +solicitude/M +solid/PSMRYT +solidarity/M +solidi +solidification/M +solidify/DSNG +solidity/M +solidness/M +solidus/M +soliloquies +soliloquize/DSG +soliloquy/M +solipsism/M +solipsistic +solitaire/MS +solitariness/M +solitary/SMP +solitude/M +solo/MDGS +soloist/MS +solstice/MS +solubility/IM +soluble/MS +solute's +solute/AXN +solutes +solution's/AE +solvable/IU +solve/EADSG +solved/U +solvency/IM +solvent/IMS +solver/SM +somatic +somber/PY +somberness/M +sombre/PY +sombreness/M +sombrero/MS +some +somebody/SM +someday +somehow +someone/MS +someplace +somersault/MDGS +somerset/SM +somersetted +somersetting +something/SM +sometime/S +someway/S +somewhat/S +somewhere +somnambulism/M +somnambulist/SM +somnolence/M +somnolent +son/SM +sonar/SM +sonata/SM +sonatina/SM +song/MS +songbird/SM +songbook/SM +songfest/SM +songster/MS +songstress/MS +songwriter/SM +songwriting +sonic +sonnet/SM +sonny/SM +sonogram/SM +sonority/M +sonorous/YP +sonorousness/M +sonsofbitches +soon/RT +soot/M +sooth/MDRSZG +soothe +soother/M +soothing/Y +soothsayer/MS +soothsaying/M +sooty/RT +sop/SM +soph +sophism/M +sophist/MS +sophistic +sophistical +sophisticate/DSMGN +sophisticated/U +sophistication/M +sophistry/SM +sophomore/MS +sophomoric +soporific/MS +soporifically +sopped +sopping +soppy/RT +soprano/MS +sorbet/SM +sorcerer/MS +sorceress/MS +sorcery/M +sordid/PY +sordidness/M +sore/MYTRSP +sorehead/MS +soreness/M +sorghum/M +sorority/SM +sorrel/SM +sorrily +sorriness/M +sorrow/SMDG +sorrowful/YP +sorrowfulness/M +sorry/RTP +sort/FASGDM +sorta +sorted/U +sorter/SM +sortie/DSM +sortieing +sot/SM +sottish +sou'wester +sou/SMH +souffle/SM +soufflé/SM +sough/MDG +soughs +sought/U +souk/S +soul/MS +soulful/YP +soulfulness/M +soulless/YP +soulmate/SM +sound/JPSMDRYZTG +soundalike/S +soundbar/S +soundbite/S +soundboard/MS +soundcheck/S +sounder/M +sounding/M +soundless/Y +soundness/UM +soundproof/GDS +soundproofing/M +soundscape/S +soundtrack/SM +soup/MDGS +soupcon/MS +soupy/RT +soupçon/MS +sour/MDRYTGSP +source/ADSMG +sourdough/M +sourdoughs +sourish +sourness/M +sourpuss/MS +sousaphone/MS +souse/DSMG +south/M +southbound +southeast/ZMR +southeaster/MY +southeastern +southeastward/S +southerly/SM +southern/SZMR +southerner/M +southernmost +southpaw/SM +southward/MS +southwest/ZMR +southwester/MY +southwestern +southwestward/S +souvenir/SM +sovereign/SM +sovereignty/M +soviet/SM +sow's +sow/ASGD +sower/SM +sown/A +soy/M +soybean/MS +sozzled +spa/SM +space/DRSMZG +spacecraft/MS +spaceflight/MS +spaceman/M +spacemen +spaceport/SM +spacer/M +spaceship/SM +spacesuit/SM +spacewalk/SGMD +spacewoman/M +spacewomen +spacey +spacial +spacier +spaciest +spaciness/M +spacing/M +spacious/YP +spaciousness/M +spade/DSMG +spadeful/MS +spadework/M +spadices +spadix/M +spaghetti/M +spake +spam/MS +spammed +spammer/SM +spamming +span/MS +spandex/M +spangle/DSMG +spangly +spaniel/SM +spank/SMDGJ +spanking/M +spanned +spanner/SM +spanning +spar/MS +spare/DRSMYTGP +spareness/M +spareribs/M +sparing/UY +spark/SMDYG +sparkle/DRSMZG +sparkler/M +sparky/RT +sparred +sparring +sparrow/SM +sparrowhawk/S +sparse/RYTP +sparseness/M +sparsity/M +spartan +spasm/SM +spasmodic +spasmodically +spastic/SM +spat/MS +spate/SM +spathe/SM +spatial/Y +spatted +spatter/SGMD +spatting +spatula/SM +spavin/MD +spawn/SMDG +spay/DGS +speak/SRZGJ +speakeasy/SM +speaker/M +speakerphone/S +spear/SMDG +spearfish/GMDS +speargun +spearhead/GMDS +spearmint/M +spec/MS +special/SMY +specialism/S +specialist/MS +specialization/MS +specialize/GDS +specialty/SM +specie/SM +species/M +specif +specifiable +specific/MS +specifically +specification/M +specificity/M +specified/U +specify/XNZDRSG +specimen/SM +specious/YP +speciousness/M +speck/SMDG +speckle/MGDS +specs/M +spectacle/SM +spectacles/M +spectacular/MYS +spectate/DSG +spectator/SM +specter/AMS +spectra +spectral +spectrometer/MS +spectroscope/MS +spectroscopic +spectroscopy/M +spectrum/M +speculate/DSXGNV +speculation/M +speculative/Y +speculator/MS +sped +speech/MS +speechify/DSG +speechless/YP +speechlessness/M +speechwriter/S +speed/SMRZG +speedboat/SM +speeder/M +speedily +speediness/M +speeding/M +speedometer/MS +speedster/SM +speedup/MS +speedway/SM +speedwell/M +speedy/TPR +speleological +speleologist/MS +speleology/M +spell/JSMDRZG +spellbind/ZGRS +spellbinder/M +spellbound +spellcheck/MDRZGS +spellchecker/M +spelldown/SM +speller/M +spelling/M +spelunker/MS +spelunking/M +spend/BSRZG +spender/M +spending/M +spendthrift/MS +spent/U +sperm/SM +spermatozoa +spermatozoon/M +spermicidal +spermicide/MS +spew/MDRZGS +spewer/M +sphagnum/MS +sphere/SM +spherical/Y +spheroid/SM +spheroidal +sphincter/MS +sphinx/MS +spic/S +spice/DSMG +spicily +spiciness/M +spicule/MS +spicy/PRT +spider/SM +spiderweb/MS +spidery +spiel/SMDG +spiff/SDG +spiffy/TR +spigot/SM +spike/DSMG +spikiness/M +spiky/RPT +spill/SMDG +spillage/MS +spillover/SM +spillway/MS +spin/MS +spinach/M +spinal/SMY +spindle/MGDS +spindly/TR +spine/SM +spineless/YP +spinet/SM +spinnaker/SM +spinner/MS +spinneret/SM +spinney/S +spinning/M +spinoff/MS +spinster/SM +spinsterhood/M +spinsterish +spiny/RT +spiracle/SM +spiraea/MS +spiral/SGMDY +spire's +spire/IFAS +spirea/SM +spirit's +spirit/ISGD +spirited/Y +spiritless +spiritual/MYS +spiritualism/M +spiritualist/MS +spiritualistic +spirituality/M +spirituous +spirochete/SM +spiry +spit/MDGS +spitball/SM +spite/ASM +spiteful/PY +spitefuller +spitefullest +spitefulness/M +spitfire/SM +spitted +spitting +spittle/M +spittoon/MS +spiv/S +splash/GMDS +splashdown/MS +splashily +splashiness/M +splashy/RTP +splat/SM +splatted +splatter/GSMD +splatting +splay/SMDG +splayfeet +splayfoot/MD +spleen/SM +splendid/RYT +splendor/MS +splendorous +splenectomy +splenetic +splice/DRSMZG +splicer/M +spliff/S +spline/S +splint/SZGMDR +splinter/MDG +splintery +split/SM +splitting/MS +splodge/S +splosh/DSG +splotch/MDSG +splotchy/TR +splurge/DSMG +splutter/GMDS +spoil's +spoil/CSDRZG +spoilage/M +spoiled/U +spoiler/CM +spoilsport/MS +spoke/SM +spoken/U +spokesman/M +spokesmen +spokespeople +spokesperson/MS +spokeswoman/M +spokeswomen +spoliation/CM +sponge/DRSMZG +spongecake/M +sponger/M +sponginess/M +spongy/RPT +sponsor/MDGS +sponsorship/M +spontaneity/M +spontaneous/Y +spoof/SMDG +spook/SMDG +spookiness/M +spooky/RPT +spool/SMDG +spoon/SMDG +spoonbill/MS +spoonerism/MS +spoonful/SM +spoor/SMDG +sporadic +sporadically +spore/DSMG +sporran/S +sport/SMDGV +sportiness/M +sporting/Y +sportive/Y +sportscast/MRZGS +sportscaster/M +sportsman/M +sportsmanlike/U +sportsmanship/M +sportsmen +sportspeople +sportsperson +sportswear/M +sportswoman/M +sportswomen +sportswriter/SM +sporty/TPR +spot/CMS +spotless/PY +spotlessness/M +spotlight/GSMD +spotlit +spotted +spotter/MS +spottily +spottiness/M +spotting +spotty/TPR +spousal/MS +spouse/SM +spout/SMDG +sprain/GSMD +sprang +sprat/SM +sprawl/GSMD +spray's +spray/ASDG +sprayer/MS +spread/ZGBSMR +spreadeagled +spreader/M +spreadsheet/MS +spree/DSM +spreeing +sprig/SM +sprigged +sprightliness/M +sprightly/RTP +spring/GSM +springboard/MS +springbok/MS +springily +springiness/M +springlike +springtime/M +springy/RPT +sprinkle/DRSJMZG +sprinkler/M +sprinkling/M +sprint/ZGSMDR +sprinter/M +sprite/SM +spritz/ZGMDRS +spritzer/M +sprocket/MS +sprog/S +sprout/GSMD +spruce/DRSPMYTG +spruceness/M +sprung +spry/RYT +spryness/M +spud/MS +spume/DSMG +spumoni/M +spumy +spun +spunk/SM +spunky/TR +spur/MS +spurge/M +spurious/PY +spuriousness/M +spurn/SDG +spurred +spurring +spurt/SMDG +sputa +sputnik/MS +sputter/MDGS +sputum/M +spy/GDSM +spyglass/MS +spymaster/S +spyware/M +sq +sqq +squab/SM +squabble/MZGDRS +squabbler/M +squad/SM +squadron/MS +squalid/PTRY +squalidness/M +squall/SGMD +squally +squalor/M +squamous +squander/GDS +square/PDRSMYTG +squareness/M +squarish +squash/GMDS +squashy/TR +squat/SMP +squatness/M +squatted +squatter/MS +squattest +squatting +squaw/SM +squawk/SZGMDR +squawker/M +squeak/SZGMDR +squeaker/M +squeakily +squeakiness/M +squeaky/TRP +squeal/SZGMDR +squealer/M +squeamish/PY +squeamishness/M +squeegee/MDS +squeegeeing +squeeze/BMZGDRS +squeezebox/S +squeezer/M +squelch/GMDS +squelchy +squib/SM +squid/SM +squidgy +squiffy +squiggle/DSMG +squiggly +squint/STGMDR +squire/DSMG +squirm/SGMD +squirmy/RT +squirrel/SGMD +squirt/SGMD +squish/GMDS +squishy/RT +sriracha +ssh +st +stab/MYS +stabbed +stabber/MS +stabbing/MS +stability/IM +stabilization/CM +stabilize/CDSG +stabilizer/MS +stable/DRSMTG +stableman/M +stablemate/S +stablemen +stably/U +staccato/MS +stack/SMDG +stadium/MS +staff's +staff/ASDG +staffer/MS +staffing/M +stag/MDGSJ +stage/SM +stagecoach/MS +stagecraft/M +stagehand/MS +stagestruck +stagey +stagflation/M +stagger/MDGS +staggering/Y +staging/M +stagnancy/M +stagnant/Y +stagnate/DSGN +stagnation/M +stagy/RT +staid/PRYT +staidness/M +stain/SMDG +stained/U +stainless/M +stair/SM +staircase/MS +stairway/MS +stairwell/SM +stake/DSMG +stakeholder/MS +stakeout/SM +stalactite/MS +stalagmite/MS +stale/DRSTGP +stalemate/DSMG +staleness/M +stalk/SMDRJZG +stalker/M +stalking/M +stall's +stall/ISDG +stallholder/S +stallion/MS +stalwart/MYS +stamen/SM +stamina/M +stammer/ZGMDRS +stammerer/M +stammering/Y +stamp/SMDRZG +stampede/MGDS +stamper/M +stance/ISM +stanch/TGDRS +stanchion/SM +stand/SMRJZG +standalone +standard/MS +standardization/M +standardize/DSG +standby/M +standbys +standee/MS +stander/M +standing/M +standoff/MS +standoffish +standout/MS +standpipe/SM +standpoint/MS +standstill/MS +standup/M +stank +stanza/SM +staph/M +staphylococcal +staphylococci +staphylococcus/M +staple/DRSMZG +stapler/M +star/MDRZGS +starboard/M +starburst/S +starch/GMDS +starchily +starchiness/M +starchy/PTR +stardom/M +stardust/M +stare/SM +starer/M +starfish/MS +starfruit +stargaze/DRSZG +stargazer/M +stark/RYPZT +starkness/M +starless +starlet/MS +starlight/M +starling/SM +starlit +starred +starring +starry/TR +starstruck +start/ASMDG +starter/MS +startle/GDS +startling/Y +startup/MS +starvation/M +starve/DSJG +starveling/MS +stash/MDSG +stasis +stat/MS +state/DRSMYGNLX +statecraft/M +stated/U +statehood/M +statehouse/MS +stateless/P +statelessness/M +stateliness/M +stately/PRT +statement/AMS +statemented +statementing +stateroom/MS +stateside +statesman/M +statesmanlike +statesmanship/M +statesmen +stateswoman/M +stateswomen +statewide +static/SM +statically +station/MDRZG +stationary +stationer/M +stationery/M +stationmaster/S +statistic/MS +statistical/Y +statistician/SM +statuary/M +statue/SM +statuesque +statuette/MS +stature/MS +status/MS +statute/MS +statutorily +statutory +staunch/PDRSYTG +staunchness/M +stave/DSMG +stay/MDRZGS +std +stdio +stead/SM +steadfast/YP +steadfastness/M +steadily/U +steadiness/UM +steady/TGPDRSM +steak/SM +steakhouse/SM +steal/SMHG +stealth/M +stealthily +stealthiness/M +stealthy/TPR +steam/SMDRZG +steamboat/MS +steamer/M +steamfitter/SM +steamfitting/M +steaminess/M +steampunk +steamroll/ZGDRS +steamroller/MDG +steamship/MS +steamy/TPR +steed/SM +steel/SMDG +steeliness/M +steelmaker/S +steelworker/SM +steelworks/M +steely/PTR +steelyard/SM +steep/SMDNRYPXTG +steepen/GD +steeple/MS +steeplechase/MS +steeplejack/SM +steepness/M +steer/SMDBG +steerage/M +steering/M +steersman/M +steersmen +stegosauri +stegosaurus/MS +stein/SM +stellar +stem/MS +stemless +stemmed +stemming +stemware/M +stench/MS +stencil/GMDS +steno/SM +stenographer/SM +stenographic +stenography/M +stenosis +stent/SM +stentorian +step/IMS +stepbrother/SM +stepchild/M +stepchildren/M +stepdad/MS +stepdaughter/SM +stepfather/SM +stepladder/MS +stepmom/MS +stepmother/SM +stepparent/SM +steppe/DRSMZG +stepper/M +steppingstone/SM +stepsister/MS +stepson/MS +stereo/SM +stereophonic +stereoscope/MS +stereoscopic +stereotype/DSMG +stereotypical +sterile +sterility/M +sterilization/SM +sterilize/DRSZG +sterilizer/M +sterling/M +stern/SMRYPT +sternness/M +sternum/MS +steroid/MS +steroidal +stertorous +stet/S +stethoscope/MS +stetson/MS +stetted +stetting +stevedore/SM +stew/MDGS +steward/GMDS +stewardess/MS +stewardship/M +stick/SMRZG +sticker/M +stickily +stickiness/M +stickleback/SM +stickler/MS +stickpin/MS +stickup/MS +sticky/PTRSM +stiff/SMDNRYPXTG +stiffen/ZGDR +stiffener/M +stiffening/M +stiffness/M +stifle/DSJG +stifling/Y +stigma/SM +stigmata +stigmatic +stigmatization/M +stigmatize/GDS +stile/SM +stiletto/SM +still's +still/ITGSD +stillbirth/M +stillbirths +stillborn +stiller +stillness/M +stilt/SMD +stilted/Y +stimulant/SM +stimulate/DSGNV +stimulation/M +stimuli +stimulus/M +sting/ZGSMR +stinger/M +stingily +stinginess/M +stingray/SM +stingy/RTP +stink/ZGSMR +stinkbug/SM +stinker/M +stinky/RT +stint/GSMD +stipend/SM +stipendiary/S +stipple/DSMG +stippling/M +stipulate/XDSGN +stipulation/M +stir/MS +stirred +stirrer/SM +stirring/SY +stirrup/SM +stitch's +stitch/ADSG +stitchery/M +stitching/M +stoat/SM +stochastic +stock's +stock/AGSD +stockade/DSMG +stockbreeder/MS +stockbroker/SM +stockbroking/M +stockholder/SM +stockily +stockiness/M +stockinet/M +stockinette/M +stocking/SM +stockist/S +stockpile/MGDS +stockpot/SM +stockroom/MS +stocktaking/M +stocky/RTP +stockyard/MS +stodge +stodgily +stodginess/M +stodgy/RTP +stogie/M +stogy/SM +stoic/SM +stoical/Y +stoicism/M +stoke/DRSZG +stoker/M +stole/SM +stolen +stolid/RYTP +stolidity/M +stolidness/M +stolon/MS +stomach/MDRZG +stomachache/SM +stomacher/M +stomachs +stomp/GSMD +stone/DRSMZG +stonemason/MS +stoner/M +stonewall/GSD +stoneware/M +stonewashed +stonework/M +stonily +stoniness/M +stonkered +stonking +stony/TRP +stood +stooge/MS +stool/SM +stoop/GSMD +stop's +stop/US +stopcock/SM +stopgap/SM +stoplight/MS +stopover/MS +stoppable/U +stoppage/MS +stopped/U +stopper/GSMD +stopping/U +stopple/DSMG +stopwatch/MS +storage/M +store's +store/ADSG +storefront/MS +storehouse/MS +storekeeper/SM +storeroom/SM +stork/SM +storm/GSMD +stormily +storminess/M +stormy/RPT +story/DSM +storyboard/MS +storybook/SM +storyteller/MS +storytelling/M +stoup/SM +stout/TSMRYP +stouthearted +stoutness/M +stove/SM +stovepipe/SM +stow/DGS +stowage/M +stowaway/MS +straddle/DRSMZG +straddler/M +strafe/MGDS +straggle/DRSZG +straggler/M +straggly/TR +straight/SPXTMNRY +straightaway/SM +straightedge/SM +straighten/ZGDR +straightener/M +straightforward/YPS +straightforwardness/M +straightness/M +straightway +strain's +strain/FADSG +strainer/ASM +strait/MNSX +straiten/GD +straitjacket/SGMD +straitlaced +strand/MDSG +strange/PRYZT +strangeness/M +stranger/M +strangle/ZGDRS +stranglehold/SM +strangler/M +strangulate/GNDS +strangulation/M +strap's +strap/US +strapless/MS +strapped/U +strapping/M +strata +stratagem/SM +strategic/S +strategical/Y +strategics/M +strategist/SM +strategy/SM +strati +stratification/M +stratify/DSGN +stratosphere/SM +stratospheric +stratum/M +stratus/M +straw/GSMD +strawberry/SM +stray/GSMD +streak/MDRSZG +streaker/M +streaky/TR +stream/MDRSZG +streamer/M +streamline/DSG +street/MS +streetcar/MS +streetlamp/S +streetlight/SM +streetwalker/SM +streetwise +strength/M +strengthen/AGDS +strengthener/MS +strengths +strenuous/PY +strenuousness/M +strep/M +streptococcal +streptococci +streptococcus/M +streptomycin/M +stress/MDSG +stressed/U +stressful +stretch/BZGMDRS +stretcher/MDG +stretchmarks +stretchy/TR +strew/GSDH +strewn +stria/M +striae +striated +striation/MS +stricken +strict/RYPT +strictness/M +stricture/SM +stridden +stride/MGS +stridency/M +strident/Y +strife/M +strike/MZGRSJ +strikebound +strikebreaker/SM +strikebreaking +strikeout/MS +striker/M +striking/Y +string/MDRSZG +stringency/M +stringent/Y +stringer/M +stringiness/M +stringy/PTR +strip/GSMD +stripe/MS +stripey +stripling/MS +stripped +stripper/MS +stripping +striptease/MZGDRS +stripteaser/M +stripy +strive/GS +striven +strobe/MS +stroboscope/MS +stroboscopic +strode +stroke/MGDS +stroll/MDRSZG +stroller/M +strong/RYT +strongbox/MS +stronghold/MS +strongman/M +strongmen +strongroom/S +strontium/M +strop/SM +strophe/SM +strophic +stropped +stroppily +stropping +stroppy/TRP +strove +struck +structural/Y +structuralism +structuralist/S +structure's +structure/AGDS +structured/U +strudel/SM +struggle/MGDS +strum/SM +strummed +strumming +strumpet/MS +strung/UA +strut/SM +strutted +strutting +strychnine/M +stub/MS +stubbed +stubbing +stubble/M +stubbly +stubborn/RYPT +stubbornness/M +stubby/RT +stucco/MDG +stuccoes +stuck/U +stud/MYS +studbook/MS +studded +studding/M +student/SM +studentship/S +studied/U +studiedly +studio/MS +studious/PY +studiousness/M +studly/RT +study's +study/AGDS +stuff/GSMDJ +stuffily +stuffiness/M +stuffing/M +stuffy/RPT +stultification/M +stultify/DSNG +stumble/DRSMZG +stumbler/M +stump/GSMD +stumpy/TR +stun/S +stung +stunk +stunned +stunner/S +stunning/Y +stunt/GSMD +stuntman +stuntmen +stupefaction/M +stupefy/DSG +stupendous/Y +stupid/TMRYS +stupidity/SM +stupor/MS +sturdily +sturdiness/M +sturdy/TRP +sturgeon/SM +stutter/MDRSZG +stutterer/M +sty/SM +stye/MS +style's +style/ADSG +styli +stylish/PY +stylishness/M +stylist/SM +stylistic/S +stylistically +stylize/DSG +stylus/MS +stymie/MDS +stymieing +styptic/SM +suasion/EM +suave/RYTP +suaveness/M +suavity/M +sub/SM +subaltern/MS +subaqua +subarctic +subarea/MS +subatomic +subbasement/SM +subbed +subbing +subbranch/MS +subcategory/SM +subclass +subcommittee/SM +subcompact/SM +subconscious/PMY +subconsciousness/M +subcontinent/SM +subcontinental +subcontract/MDSG +subcontractor/MS +subculture/MS +subcutaneous/Y +subdivide/GDS +subdivision/SM +subdominant +subdue/DSG +subeditor/S +subfamily/SM +subfreezing +subgroup/MS +subhead/GJMS +subheading/M +subhuman/MS +subj +subject/GVMDS +subjection/M +subjective/Y +subjectivity/M +subjoin/GDS +subjugate/GNDS +subjugation/M +subjunctive/SM +sublease/MGDS +sublet/SM +subletting +sublieutenant/S +sublimate/GNDS +sublimation/M +sublime/YTGDRS +subliminal/Y +sublimity/M +sublingual +submarginal +submarine/MZRS +submariner/M +submerge/GDS +submergence/M +submerse/GNDS +submersible/MS +submersion/M +submicroscopic +submission/MS +submissive/PY +submissiveness/M +submit/AS +submitted/A +submitter +submitting/A +subnormal +suborbital +suborder/MS +subordinate/DSMGN +subordination/IM +suborn/SGD +subornation/M +subparagraph +subplot/MS +subpoena/GMDS +subprime +subprofessional/SM +subprogram/S +subroutine/SM +subscribe/UASDG +subscriber/MS +subscript/MS +subscription/MS +subsection/MS +subsequent/Y +subservience/M +subservient/Y +subset/SM +subside/GDS +subsidence/M +subsidiarity +subsidiary/SM +subsidization/M +subsidize/ZGDRS +subsidizer/M +subsidy/SM +subsist/SDG +subsistence/M +subsoil/M +subsonic +subspace +subspecies/M +substance/SM +substandard +substantial/IY +substantiate/GNDSX +substantiated/U +substantiation/FM +substantive/SMY +substation/MS +substituent +substitute/XMGNDS +substitution/M +substrata +substrate/MS +substratum/M +substructure/SM +subsume/DSG +subsumption +subsurface/M +subsystem/SM +subteen/SM +subtenancy/M +subtenant/SM +subtend/SDG +subterfuge/SM +subterranean +subtext/SM +subtitle/DSMG +subtle/TR +subtlety/SM +subtly +subtopic/SM +subtotal/SGMD +subtract/GSD +subtraction/SM +subtrahend/SM +subtropic/S +subtropical +subtropics/M +suburb/MS +suburban/SM +suburbanite/SM +suburbia/M +subvention/SM +subversion/M +subversive/SPMY +subversiveness/M +subvert/SDG +subway/MS +subzero +succeed/GDS +success/VMS +successful/UY +succession/SM +successive/Y +successor/SM +succinct/RYTP +succinctness/M +succor/SGMD +succotash/M +succubi +succubus +succulence/M +succulency/M +succulent/SM +succumb/GDS +such +suchlike +suck/MDRZGS +sucker/GMD +suckle/DSJG +suckling/M +sucrose/M +suction/SMDG +sudden/PY +suddenness/M +suds/M +sudsy/TR +sue/DSG +suede/M +suet/M +suety +suffer/DRZGSJ +sufferance/M +sufferer/M +suffering/M +suffice/DSG +sufficiency/IM +sufficient/IY +suffix/MDSG +suffixation/M +suffocate/GNDS +suffocation/M +suffragan/MS +suffrage/M +suffragette/SM +suffragist/MS +suffuse/DSGN +suffusion/M +sugar/GSMD +sugarcane/M +sugarcoat/GDS +sugarless +sugarplum/MS +sugary/RT +suggest/GVSDR +suggestibility/M +suggestible +suggestion/SM +suggestive/YP +suggestiveness/M +suicidal +suicide/SM +suit/BMDGS +suitability/UM +suitableness/M +suitably/U +suitcase/SM +suite/SM +suited/U +suiting/M +suitor/MS +sukiyaki/M +sulfa/M +sulfate/SM +sulfide/SM +sulfonamides +sulfur/MDSG +sulfuric +sulfurous +sulk/MDGS +sulkily +sulkiness/M +sulky/TRSMP +sullen/RYPT +sullenness/M +sullied/U +sully/GDS +sultan/MS +sultana/SM +sultanate/MS +sultrily +sultriness/M +sultry/RPT +sum/SM +sumac/M +summarily +summarize/GDS +summary/SM +summat +summation/FMS +summed +summer/MDSG +summerhouse/SM +summertime/M +summery +summing +summit/MS +summitry/M +summon/DRSZG +summoner/M +summons/GMDS +sumo/M +sump/MS +sumptuous/PY +sumptuousness/M +sun/SM +sunbath/ZGMDRS +sunbathe +sunbather/M +sunbathing/M +sunbaths +sunbeam/SM +sunbed/S +sunbelt/SM +sunblock/MS +sunbonnet/SM +sunburn/SGMD +sunburst/MS +sundae/MS +sundeck/S +sunder/DSG +sundial/SM +sundown/SM +sundress/S +sundries/M +sundry/S +sunfish/MS +sunflower/MS +sung/U +sunglasses/M +sunhat/S +sunk/N +sunlamp/SM +sunless +sunlight/M +sunlit +sunned +sunniness/M +sunning +sunny/TRP +sunrise/SM +sunroof/SM +sunscreen/MS +sunset/MS +sunshade/MS +sunshine/M +sunshiny +sunspot/SM +sunstroke/M +suntan/MS +suntanned +suntanning +suntrap/S +sunup/M +sup/SZMR +super/M +superabundance/MS +superabundant +superannuate/GNDS +superannuation/M +superb/RYT +supercargo/M +supercargoes +supercharge/ZGDRS +supercharger/M +supercilious/PY +superciliousness/M +supercity/SM +supercomputer/MS +superconducting +superconductive +superconductivity/M +superconductor/SM +superego/MS +supererogation/M +supererogatory +superficial/Y +superficiality/M +superfine +superfluity/M +superfluous/YP +superfluousness/M +superglue +supergrass/S +superhero/MS +superheroes +superhighway/SM +superhuman +superimpose/GDS +superimposition/M +superintend/DSG +superintendence/M +superintendency/M +superintendent/SM +superior/MS +superiority/M +superlative/SMY +superman/M +supermarket/SM +supermen +supermodel/SM +supermom/MS +supernal +supernatural/SY +supernova/MS +supernovae +supernumerary/SM +superpose/GDS +superposition/M +superpower/SM +supersaturate/GNDS +supersaturation/M +superscribe/GDS +superscript/MS +superscription/M +supersede/GDS +supersize/GDS +supersonic +superstar/MS +superstate/S +superstition/MS +superstitious/Y +superstore/MS +superstructure/MS +supertanker/MS +superuser/S +supervene/GDS +supervention/M +supervise/XGNDS +supervised/U +supervision/M +supervisor/MS +supervisory +superwoman/M +superwomen +supine/Y +supp/DRZG +supper/M +suppertime +suppl +supplant/SDG +supple/TLPR +supplement/MDGS +supplemental +supplementary +supplementation/M +suppleness/M +suppliant/SM +supplicant/MS +supplicate/GDS +supplication/M +supplier/M +supply/ZGDRSMXN +support/MDRSBZGV +supportable/UI +supported/U +supporter/M +suppose/GDS +supposed/Y +supposition/MS +suppository/SM +suppress/GDS +suppressant/MS +suppressible +suppression/M +suppressor/SM +suppurate/DSGN +suppuration/M +supra +supranational +supremacist/MS +supremacy/M +supreme/Y +supremo/S +supt +surcease/DSMG +surcharge/DSMG +surcingle/SM +sure/PYTR +surefire +surefooted +sureness/M +surety/SM +surf/MDRZGS +surface's +surface/AGDS +surfboard/MDSG +surfeit/MDSG +surfer/M +surfing/M +surge/DSMG +surgeon/MS +surgery/SM +surgical/Y +surliness/M +surly/PTR +surmise/MGDS +surmount/DGSB +surmountable/I +surname/MS +surpass/GDS +surpassed/U +surplice/MS +surplus/MS +surplussed +surplussing +surprise/DSMGJ +surprising/UY +surreal +surrealism/M +surrealist/SM +surrealistic +surrealistically +surrender/MDSG +surreptitious/PY +surreptitiousness/M +surrey/MS +surrogacy/M +surrogate/SM +surround/GSDJ +surrounding/M +surroundings/M +surtax/MDSG +surtitle/S +surveillance/M +survey's +survey/ADGS +surveying/M +surveyor/SM +survival/SM +survivalist/SM +survive/DSGB +survivor/SM +susceptibility/SM +susceptible/I +sushi/M +suspect/SMDG +suspected/U +suspend/SDRZG +suspender/M +suspense/XMN +suspenseful +suspension/M +suspicion/SM +suspicious/Y +suss/DSG +sustain/SDBG +sustainability +sustainable/U +sustenance/M +sutler/MS +suttee +suture/MGDS +suzerain/MS +suzerainty/M +svelte/TR +swab/MS +swabbed +swabbing +swaddle/DSG +swag/MS +swagged +swagger/SMDRG +swagging +swain/SM +swallow/GSMD +swallowtail/MS +swam +swami/SM +swamp/GSMD +swampland/M +swampy/RT +swan/MS +swank/TGSMDR +swankily +swankiness/M +swanky/RPT +swanned +swanning +swansdown/M +swansong/S +swap/MS +swapped +swapping +sward/SM +swarm/GSMD +swarthy/TR +swash/GMDS +swashbuckler/SM +swashbuckling/M +swastika/SM +swat/MS +swatch/MS +swath/GMDS +swathe/M +swaths +swatted +swatter/SMDG +swatting +sway/MDGS +swayback/MD +swayed/U +swear/ZGSR +swearer/M +swearword/MS +sweat/ZGSMDR +sweatband/MS +sweater/M +sweatpants/M +sweats/M +sweatshirt/SM +sweatshop/MS +sweatsuit/S +sweaty/RT +swede/SM +sweep/ZGSMRJ +sweeper/M +sweeping/MY +sweepings/M +sweepstakes/M +sweet/XTSMNRYP +sweetbread/SM +sweetbriar/SM +sweetbrier/SM +sweetcorn +sweetened/U +sweetener/MS +sweetening/M +sweetheart/SM +sweetie/SM +sweetish +sweetmeat/MS +sweetness/M +swell/TGSMDRJ +swellhead/MDS +swelling/M +swelter/SGMD +swept +sweptback +swerve/MGDS +swerving/U +swift/PTSMRY +swiftness/M +swig/MS +swigged +swigging +swill/GSMD +swim/MS +swimmer/SM +swimming/MY +swimsuit/SM +swimwear +swindle/DRSMZG +swindler/M +swine/SM +swineherd/SM +swing/ZGSMR +swingeing +swinger/M +swinish +swipe/DSMG +swirl/GSMD +swirly +swish/TGMDRS +switch/MDRSZGB +switchback/MS +switchblade/SM +switchboard/SM +switcher/M +swivel/MDGS +swiz +swizz +swizzle/DSG +swollen +swoon/SGMD +swoop/SGMD +swoosh/MDSG +sword/SM +swordfish/MS +swordplay/M +swordsman/M +swordsmanship/M +swordsmen +swore +sworn +swot/S +swotted +swotting +swum +swung +sybarite/SM +sybaritic +sycamore/MS +sycophancy/M +sycophant/SM +sycophantic +syllabic +syllabicate/GNDS +syllabication/M +syllabification/M +syllabify/DSNG +syllable/MS +syllabub/S +syllabus/MS +syllogism/MS +syllogistic +sylph/M +sylphic +sylphlike +sylphs +sylvan +symbioses +symbiosis/M +symbiotic +symbiotically +symbol/MS +symbolic +symbolical/Y +symbolism/M +symbolization/M +symbolize/DSG +symmetric/Y +symmetrical/Y +symmetry/SM +sympathetic/U +sympathetically/U +sympathies/M +sympathize/ZGDRS +sympathizer/M +sympathy/SM +symphonic +symphony/SM +symposium/MS +symptom/MS +symptomatic +symptomatically +syn/H +synagogal +synagogue/SM +synapse/MS +synaptic +sync/MDSG +synchronicity +synchronization/SM +synchronize/GDS +synchronous/Y +syncopate/DSGN +syncopation/M +syncope/M +syndicalism +syndicalist/S +syndicate/DSMGN +syndication/M +syndrome/SM +synergism/M +synergistic +synergy/SM +synfuel/MS +synod/SM +synonym/SM +synonymous +synonymy/M +synopses +synopsis/M +synoptic +synovial +syntactic +syntactical/Y +syntax/M +syntheses +synthesis/M +synthesize/ZGDRS +synthesizer/M +synthetic/SM +synthetically +synths +syphilis/M +syphilitic/SM +syringe/DSMG +syrup/SM +syrupy +sysadmin/S +sysop/S +system/SM +systematic/U +systematical/Y +systematization/M +systematize/GDS +systemic/MS +systemically +systole/SM +systolic +séance/SM +t/SDNXGBJ +ta +tab/SM +tabbed +tabbing +tabbouleh/M +tabby/SM +tabernacle/SM +tabla/MS +table/MGDS +tableau/M +tableaux +tablecloth/M +tablecloths +tableland/SM +tablespoon/SM +tablespoonful/SM +tablet/SM +tabletop/MS +tableware/M +tabloid/SM +taboo/MDSG +tabor/MS +tabular +tabulate/DSGNX +tabulation/M +tabulator/SM +tachograph +tachographs +tachometer/SM +tachycardia/M +tachyon +tacit/PY +tacitness/M +taciturn/Y +taciturnity/M +tack/ZGMDRS +tacker/M +tackiness/M +tackle/DRSMZG +tackler/M +tacky/RTP +taco/MS +tact/FM +tactful/YP +tactfulness/M +tactic/SM +tactical/Y +tactician/MS +tactile +tactility/M +tactless/PY +tactlessness/M +tad/SM +tadpole/MS +taffeta/M +taffrail/SM +taffy/SM +tag/SM +tagged +tagger/SM +tagging +tagliatelle +tagline/MS +taiga/MS +tail/ACSDMG +tailback/MS +tailboard/S +tailbone/S +tailcoat/MS +tailgate/MZGDRS +tailgater/M +tailless +taillight/MS +tailor/SGMD +tailoring/M +tailpiece/S +tailpipe/SM +tailspin/SM +tailwind/SM +taint/MDSG +tainted/U +take/AIMS +takeaway/S +taken/A +takeoff/MS +takeout/MS +takeover/SM +taker/MS +taking/SM +takings/M +talc/M +talcum/M +tale/MS +talebearer/MS +talent/SMD +talented/U +tali +talisman/MS +talk/ZGMDRS +talkative/PY +talkativeness/M +talker/M +talkie/RSMT +talky +tall/TRP +tallboy/MS +tallier/M +tallish +tallness/M +tallow/M +tallowy +tally/DRSMZG +tallyho/MDGS +talon/MS +talus/MS +tam/SM +tamale/SM +tamarack/MS +tamarind/MS +tambourine/MS +tame/BYZTGDRSP +tameable +tamed/U +tameness/M +tamer/M +tamoxifen +tamp/ZGDRS +tamper/ZGDR +tamperer/M +tampon/SM +tan/SM +tanager/MS +tanbark/M +tandem/SM +tandoori/M +tang/MS +tangelo/MS +tangent/MS +tangential/Y +tangerine/MS +tangibility/IM +tangible/IMS +tangibleness/M +tangibly/I +tangle's +tangle/UDSG +tango/MDSG +tangy/RT +tank/ZGMDRS +tankard/MS +tanker/M +tankful/MS +tanned/U +tanner/SM +tannery/SM +tannest +tannin/M +tanning/M +tansy/M +tantalization/M +tantalize/ZGDRS +tantalizer/M +tantalizing/Y +tantalum/M +tantamount +tantra/M +tantrum/SM +tap/SZGMDR +tapas +tape/MS +tapeline/MS +taper/MDG +tapestry/SM +tapeworm/MS +tapioca/M +tapir/MS +tapped/U +tapper/MS +tappet/MS +tapping +taproom/SM +taproot/SM +tar/SGMD +taramasalata +tarantella/MS +tarantula/SM +tarball/S +tardily +tardiness/M +tardy/TPR +tare/MS +target/MDGS +tariff/MS +tarmac/MS +tarmacadam +tarmacked +tarmacking +tarn/MS +tarnish/GMDS +tarnished/U +taro/MS +tarot/MS +tarp/MS +tarpaulin/MS +tarpon/MS +tarragon/SM +tarred +tarring +tarry/TGDRS +tarsal/MS +tarsi +tarsus/M +tart/PTGMDRYS +tartan/MS +tartar/MS +tartaric +tartness/M +tarty/T +taser/GMDS +task/GMDS +taskmaster/MS +taskmistress/MS +tassel/MDSG +taste/JMZGDRS +tasted/U +tasteful/EPY +tastefulness/EM +tasteless/PY +tastelessness/M +taster/M +tastily +tastiness/M +tasting/M +tasty/TRP +tat/SZR +tatami/MS +tater/M +tatted +tatter/MDSG +tatterdemalion/MS +tattie +tatting/M +tattle/MZGDRS +tattler/M +tattletale/MS +tattoo/MDRSZG +tattooer/M +tattooist/SM +tatty/TRS +tau/SM +taught/UA +taunt/ZGMDRS +taunter/M +taunting/Y +taupe/M +taut/PXTNRY +tauten/DG +tautness/M +tautological/Y +tautologous +tautology/SM +tavern/MS +tawdrily +tawdriness/M +tawdry/RTP +tawny/TRM +tax/BZGMDRS +taxa +taxation/M +taxer/M +taxi/GMDS +taxicab/SM +taxidermist/SM +taxidermy/M +taximeter/MS +taxiway/S +taxman +taxmen +taxon +taxonomic +taxonomical +taxonomist/MS +taxonomy/SM +taxpayer/MS +taxpaying +tb/S +tbsp +tea/SM +teabag/S +teacake/SM +teach/ZGRSBJ +teachable/U +teacher/M +teaching/M +teacup/MS +teacupful/MS +teak/MS +teakettle/SM +teal/MS +tealight/MS +team/GMDS +teammate/MS +teamster/MS +teamwork/M +teapot/MS +tear/GMDS +tearaway/S +teardrop/SM +tearful/Y +teargas/MS +teargassed +teargassing +tearjerker/MS +tearoom/SM +teary/TR +tease/MZGDRS +teasel/MS +teaser/M +teasing/Y +teaspoon/SM +teaspoonful/SM +teat/MS +teatime/S +tech/M +techie/S +technetium/M +technical/Y +technicality/SM +technician/SM +technicolor +technique/SM +techno +technobabble +technocracy/SM +technocrat/MS +technocratic +technological/Y +technologist/MS +technology/SM +technophobe/S +techs +tectonic/S +tectonics/M +ted/S +teddy/S +tedious/PY +tediousness/M +tedium/M +tee/DSMH +teeing +teem/GDS +teen/MS +teenage/RZ +teenager/M +teeny/TR +teenybopper/MS +teepee/MS +teeter/MDSG +teethe/GDS +teething/M +teetotal/RZ +teetotaler/M +teetotalism/M +tektite/SM +tel +telecast/SZGMR +telecaster/M +telecommunication/MS +telecommunications/M +telecommute/ZGDRS +telecommuter/M +telecommuting/M +teleconference/MGDS +teleconferencing/M +telegenic +telegram/MS +telegraph/MDRZG +telegrapher/M +telegraphese +telegraphic +telegraphically +telegraphist/SM +telegraphs +telegraphy/M +telekinesis/M +telekinetic +telemarketer/SM +telemarketing/M +telemeter/SM +telemetry/SM +teleological +teleology +telepathic +telepathically +telepathy/M +telephone/DRSMZG +telephoner/M +telephonic +telephonist/S +telephony/M +telephoto/SM +telephotography/M +teleplay/MS +teleport +teleportation +teleprinter/MS +teleprocessing/M +teleprompter/SM +telesales +telescope/DSMG +telescopic +telescopically +teletext/MS +telethon/MS +teletype/S +teletypewriter/MS +televangelism/M +televangelist/MS +televise/XGNDS +television/M +teleworker/S +teleworking +telex/MDSG +tell/AGS +teller/SM +telling/Y +telltale/SM +tellurium/M +telly/SM +telnet +temblor/MS +temerity/M +temp/MDRZTGS +temper/MDG +tempera/LSM +temperament/MS +temperamental/Y +temperance/IM +temperate/IY +temperateness/M +temperature/SM +tempest/SM +tempestuous/YP +tempestuousness/M +tempi +template's +template/S +temple/SM +tempo/SM +temporal/Y +temporarily +temporariness/M +temporary/FSM +temporize/ZGDRS +temporizer/M +tempt/SDRZG +temptation/MS +tempter/M +tempting/Y +temptress/MS +tempura/M +ten/BMH +tenability/M +tenable/U +tenably +tenacious/YP +tenaciousness/M +tenacity/M +tenancy/SM +tenant/SMDG +tenanted/U +tenantry/M +tench +tend/IEFDGS +tended/U +tendency/SM +tendentious/YP +tendentiousness/M +tender/SMDRYTGP +tenderfoot/MS +tenderhearted/P +tenderheartedness/M +tenderize/ZGDRS +tenderizer/M +tenderloin/SM +tenderness/M +tendinitis/M +tendon/SM +tendonitis/M +tendril/SM +tenement/SM +tenet/SM +tenfold +tenner/S +tennis/M +tenon/SMDG +tenor/SM +tenpin/SM +tenpins/M +tense/DRSMYTGNXP +tenseness/M +tensile +tension/ESM +tensity/IM +tensor/S +tent/DGSM +tentacle/DSM +tentative/PY +tentativeness/M +tenterhook/MS +tenth/MY +tenths +tenuity/M +tenuous/PY +tenuousness/M +tenure/DSMG +tepee/SM +tepid/YP +tepidity/M +tepidness/M +tequila/SM +terabit/SM +terabyte/MS +terahertz/M +terapixel/MS +terbium/M +tercentenary/SM +tercentennial/SM +teriyaki +term/MDYGS +termagant/MS +terminable/IC +terminal/MYS +terminate/DSGNX +termination/CSM +terminator/S +termini +terminological/Y +terminology/SM +terminus/M +termite/SM +tern/IMS +ternary/SM +terr +terrace/DSMG +terracotta/M +terrain/SM +terrapin/MS +terrarium/SM +terrazzo/MS +terrestrial/SMY +terrible/P +terribleness/M +terribly +terrier/M +terrific +terrifically +terrify/GDS +terrifying/Y +terrine/S +territorial/MS +territoriality +territory/SM +terror/SM +terrorism/M +terrorist/SM +terrorize/DSG +terry/RMZ +terrycloth/M +terse/RYTP +terseness/M +tertiary +tessellate/DSXGN +tessellation/M +test's/AFK +test/AKFCDGS +testable/CF +testament/MS +testamentary +testate/S +testator/MS +testatrices +testatrix/M +tested/U +tester/KSM +testes +testicle/MS +testicular +testifier/M +testify/ZGDRS +testily +testimonial/MS +testimony/SM +testiness/M +testings +testis/M +testosterone/M +testy/PRT +tetanus/M +tetchily +tetchy/PRT +tether/SMDG +tetra/SM +tetracycline/M +tetrahedral +tetrahedron/MS +tetrameter/SM +text/FMS +textbook/SM +texted +textile/MS +texting +textual/FY +textural +texture/MGDS +thalami +thalamus/M +thalidomide/M +thallium/M +than +thane/SM +thank/SDG +thankful/YP +thankfulness/M +thankless/PY +thanklessness/M +thanksgiving/SM +that'd +that'll +that/M +thatch/MDRSZG +thatcher/M +thatching/M +thaw/MDGS +the/JG +theater/SM +theatergoer/SM +theatrical/YS +theatricality/M +theatricals/M +theatrics/M +thee/S +theft/SM +their/S +theism/M +theist/SM +theistic +them +thematic +thematically +theme/DSM +themselves +then/M +thence +thenceforth +thenceforward +theocracy/SM +theocratic +theodolite/S +theologian/SM +theological/Y +theology/SM +theorem/MS +theoretic +theoretical/Y +theoretician/SM +theorist/SM +theorize/DSG +theory/SM +theosophic +theosophical +theosophist/SM +theosophy/M +therapeutic/S +therapeutically +therapeutics/M +therapist/SM +therapy/SM +there/M +thereabout/S +thereafter +thereat +thereby +therefor +therefore +therefrom +therein +theremin/SM +thereof +thereon +thereto +theretofore +thereunto +thereupon +therewith +therm/SM +thermal/MYS +thermionic +thermodynamic/S +thermodynamics/M +thermometer/MS +thermometric +thermonuclear +thermoplastic/SM +thermos/MS +thermostat/MS +thermostatic +thermostatically +thesauri +thesaurus/MS +these/S +thesis/M +thespian/SM +theta/SM +thew/MS +they +they'd +they'll +they're +they've +thiamine/M +thick/PMNRYXT +thicken/DRJZG +thickener/M +thickening/M +thicket/MS +thickheaded/M +thickness/MS +thicko/S +thickset +thief/M +thieve/DSG +thievery/M +thieving/M +thievish +thigh/M +thighbone/MS +thighs +thimble/MS +thimbleful/SM +thin/YSP +thine +thing/M +thingamabob/SM +thingamajig/SM +thingumabob/S +thingummy/S +thingy/S +think/SRBZG +thinkable/U +thinker/M +thinking's +thinned +thinner/MS +thinness/M +thinnest +thinning +third/SMY +thirst/SGMD +thirstily +thirstiness/M +thirsty/TPR +thirteen/SMH +thirteenth/M +thirteenths +thirtieth/M +thirtieths +thirty/HSM +this +thistle/MS +thistledown/M +thither +tho +thole/SM +thong/SM +thoracic +thorax/MS +thorium/M +thorn/SM +thorniness/M +thorny/PRT +thorough/RYPT +thoroughbred/MS +thoroughfare/MS +thoroughgoing +thoroughness/M +those +thou/MS +though +thought/SM +thoughtful/YP +thoughtfulness/M +thoughtless/PY +thoughtlessness/M +thousand/MHS +thousandfold +thousandth/M +thousandths +thraldom/M +thrall/SMDG +thralldom/M +thrash/JMDRSZG +thrasher/M +thrashing/M +thread/SMDRZG +threadbare +threader/M +threadlike +thready/TR +threat/SMNX +threaten/DG +threatening/Y +three/SM +threefold +threepence/M +threescore/MS +threesome/SM +threnody/SM +thresh/MDRSZG +thresher/M +threshold/SM +threw +thrice +thrift/SM +thriftily +thriftiness/M +thriftless +thrifty/PTR +thrill/SMDRZG +thriller/M +thrilling/Y +thrive/DSG +throat/SM +throatily +throatiness/M +throaty/RTP +throb/SM +throbbed +throbbing +throe/SM +thrombi +thrombolytic +thromboses +thrombosis/M +thrombotic +thrombus/M +throne's +throne/S +throng/GSMD +throttle/DRSMZG +throttler/M +through +throughout +throughput/M +throughway/MS +throw/SMRZG +throwaway/SM +throwback/SM +thrower/M +thrown +thru +thrum/SM +thrummed +thrumming +thrush/MS +thrust/GSM +thruway/MS +thud/MS +thudded +thudding +thug/MS +thuggery/M +thuggish +thulium/M +thumb/SMDG +thumbnail/SM +thumbprint/SM +thumbscrew/SM +thumbtack/SM +thump/SMDG +thumping/M +thunder/ZGMDRS +thunderbolt/SM +thunderclap/SM +thundercloud/MS +thunderer/M +thunderhead/SM +thunderous/Y +thundershower/SM +thunderstorm/SM +thunderstruck +thundery +thunk/S +thus +thwack/ZGSMDR +thwacker/M +thwart/GSMD +thy +thyme/M +thymine/M +thymus/MS +thyroid/MS +thyroidal +thyself +ti/MRZ +tiara/SM +tibia/M +tibiae +tibial +tic/SM +tick/MDRZGS +ticker/M +ticket/GSMD +ticking/M +tickle/DRSMZG +tickler/M +ticklish/YP +ticklishness/M +ticktacktoe/M +ticktock/MS +tidal/Y +tidbit/SM +tiddler/S +tiddly +tiddlywink/S +tiddlywinks/M +tide/MGJDS +tideland/SM +tidemark/S +tidewater/MS +tideway/MS +tidily/U +tidiness/UM +tidings/M +tidy/DRSMTGP +tie's +tie/AUSD +tieback/MS +tiebreak/RSZ +tiebreaker/M +tiepin/S +tier/MD +tiff/MDGS +tiger/SM +tigerish +tight/SNRYPXT +tighten/ZGDR +tightener/M +tightfisted +tightness/M +tightrope/MS +tights/M +tightwad/MS +tigress/MS +til +tilapia +tilde/SM +tile/MZGDRS +tiler/M +tiling/M +till's +till/EDRZGS +tillable +tillage/M +tiller/EM +tilt/MDGS +timber/SMDG +timberland/M +timberline/MS +timbre/SM +timbrel/SM +time/MYZGJDRS +timekeeper/MS +timekeeping/M +timeless/PY +timelessness/M +timeline/MS +timeliness/UM +timely/UPRT +timeout/SM +timepiece/MS +timer/M +timescale/S +timeserver/SM +timeserving/M +timeshare/S +timestamp/SMD +timetable/DSMG +timeworn +timezone +timid/RYTP +timidity/M +timidness/M +timing/M +timorous/PY +timorousness/M +timothy/M +timpani/M +timpanist/SM +tin/SM +tincture/MGDS +tinder/M +tinderbox/MS +tine/MS +tinfoil/M +ting/MDYG +tinge/SM +tingeing +tingle/DSMGJ +tingling/M +tininess/M +tinker/ZGSMDR +tinkerer/M +tinkle/DSMG +tinned +tinniness/M +tinning +tinnitus/M +tinny/PRT +tinplate/M +tinpot +tinsel/GSMD +tinsmith/M +tinsmiths +tint/MDGS +tintinnabulation/MS +tintype/MS +tinware/M +tiny/RTP +tip/SM +tipped +tipper/SM +tippet/SM +tippex/GDS +tipping +tipple/DRSMZG +tippler/M +tipsily +tipsiness/M +tipster/MS +tipsy/RPT +tiptoe/DSM +tiptoeing +tiptop/SM +tirade/SM +tiramisu/MS +tire's +tire/AGDS +tired/PRYT +tiredness/M +tireless/YP +tirelessness/M +tiresome/PY +tiresomeness/M +tissue/SM +tit/SM +titan/SM +titanic +titanium/M +titch/S +titchy +tithe/DRSMZG +tither/M +titian/M +titillate/DSGN +titillating/Y +titillation/M +titivate/DSGN +titivation/M +title/DSMG +titled/U +titleholder/MS +titlist/MS +titmice +titmouse/M +titter/SGMD +tittivate/DSGN +tittivation/M +tittle/SM +titty/S +titular +tizz +tizzy/SM +tn +tnpk +to/IU +toad/MS +toadstool/MS +toady/DSMG +toadyism/M +toast/SMDRZG +toaster/M +toastmaster/SM +toastmistress/MS +toasty/TRS +tobacco/MS +tobacconist/SM +toboggan/ZGSMDR +tobogganer/M +tobogganing/M +toccata/S +tocsin/SM +today/M +toddle/DRSMZG +toddler/M +toddy/SM +toe/DSM +toecap/SM +toehold/MS +toeing +toenail/MS +toerag/S +toff/S +toffee/SM +tofu/M +tog/SM +toga/MDS +together/P +togetherness/M +togged +togging +toggle/DSMG +togs/M +toil/MDRZGS +toiler/M +toilet/MDGS +toiletry/SM +toilette/M +toilsome +toke/MGDS +token/SM +tokenism/M +told/AU +tole/M +tolerable/I +tolerably/I +tolerance/IM +tolerances +tolerant/IY +tolerate/GNDS +toleration/M +toll/MDGS +tollbooth/M +tollbooths +tollgate/SM +tollway/SM +toluene/M +tom/SM +tomahawk/SGMD +tomato/M +tomatoes +tomb/MDGS +tombola/S +tomboy/MS +tomboyish +tombstone/MS +tomcat/MS +tome/MS +tomfoolery/SM +tomographic +tomography/M +tomorrow/MS +tomtit/MS +ton/SM +tonal/Y +tonality/SM +tone's +tone/IZGDRS +tonearm/SM +toneless/Y +toner/IM +tong/MDGS +tongue/MGDS +tongueless +tonic/SM +tonight/M +tonnage/SM +tonne/SM +tonsil/MS +tonsillectomy/SM +tonsillitis/M +tonsorial +tonsure/DSMG +tony/RT +too +took/A +tool's +tool/ADGS +toolbar/SM +toolbox/MS +toolkit +toolmaker/MS +toot/MDRZGS +tooter/M +tooth/MD +toothache/MS +toothbrush/MS +toothily +toothless +toothpaste/SM +toothpick/SM +toothsome +toothy/RT +tootle/GDS +tootsie/S +top/SM +topaz/MS +topcoat/SM +topdressing/SM +topee/S +topflight +topi/S +topiary/M +topic/SM +topical/Y +topicality/M +topknot/SM +topless +topmast/SM +topmost +topnotch +topographer/SM +topographic +topographical/Y +topography/SM +topological/Y +topology +topped +topper/MS +topping/SM +topple/GDS +topsail/SM +topside/SM +topsoil/M +topspin/M +toque/SM +tor/SM +torah/M +torahs +torch/GMDS +torchbearer/MS +torchlight/M +tore +toreador/MS +torment/SMDG +tormenting/Y +tormentor/MS +torn +tornado/M +tornadoes +torpedo/GMD +torpedoes +torpid/Y +torpidity/M +torpor/M +torque/MGDS +torrent/SM +torrential +torrid/YP +torridity/M +torridness/M +torsion/M +torsional +torso/SM +tort's +tort/FEAS +torte/SM +tortellini/M +tortilla/MS +tortoise/MS +tortoiseshell/SM +tortoni/M +tortuous/PY +tortuousness/M +torture/DRSMZG +torturer/M +torturous +torus +tosh +toss/MDRSZG +tossup/MS +tot/SGMD +total/GSMDY +totalitarian/SM +totalitarianism/M +totality/SM +totalizator/SM +tote/MS +totem/SM +totemic +totted +totter/ZGMDRS +totterer/M +totting +toucan/MS +touch/AGMDS +touchdown/SM +touche/BJ +touched/U +touchily +touchiness/M +touching/Y +touchline/S +touchpaper/S +touchscreen/MS +touchstone/MS +touchy/RPT +touché +tough/XTGMDNRYP +toughen/ZGDR +toughener/M +toughie/SM +toughness/M +toughs +toupee/MS +tour/CFSGDM +tourism/M +tourist/MS +touristic +touristy +tourmaline/M +tournament/SM +tourney/MS +tourniquet/MS +tousle/GDS +tout/MDGS +tow/SZGMDR +toward/S +towboat/MS +towel/JGSMD +towelette/SM +toweling/M +tower/GMD +towhead/MDS +towhee/MS +towline/MS +town/MS +townee/S +townhouse/MS +townie/MS +townsfolk/M +township/MS +townsman/M +townsmen +townspeople/M +townswoman/M +townswomen +towpath/M +towpaths +towrope/SM +toxemia/M +toxic +toxicity/SM +toxicological +toxicologist/SM +toxicology/M +toxin/SM +toy/SGMD +toyboy/S +tr +trabecula +trabecular +trabecule +trace/JDRSMZG +traceable/U +tracer/M +tracery/SM +trachea/M +tracheae +tracheal +tracheotomy/SM +tracing/M +track/ZGSMDR +trackball/SM +tracker/M +trackless +tracksuit/S +tract's +tract/CEKFAS +tractability/IM +tractable/I +tractably/I +traction/EFACKM +tractor/FCKMS +trad +trade/JDRSMZG +trademark/SGMD +trader/M +tradesman/M +tradesmen +tradespeople/M +tradeswoman/M +tradeswomen +trading/M +tradition/MS +traditional/Y +traditionalism/M +traditionalist/SM +traduce/DRSZG +traducer/M +traffic/SM +trafficked +trafficker/SM +trafficking/M +tragedian/SM +tragedienne/MS +tragedy/SM +tragic +tragically +tragicomedy/SM +tragicomic +trail/ZGSMDR +trailblazer/MS +trailblazing/M +trailer/M +train/ZGSMDRB +trained/U +trainee/SM +trainer/M +training/M +trainload/MS +trainman/M +trainmen +trainspotter/S +trainspotting +traipse/DSMG +trait/SM +traitor/SM +traitorous/Y +trajectory/SM +tram/MS +tramcar/S +tramlines +trammed +trammel/SGMD +trammeled/U +tramming +tramp/ZGSMDR +tramper/M +trample/DRSMZG +trampler/M +trampoline/MGDS +tramway/S +trance/MS +tranche/S +tranquil/RYT +tranquility/M +tranquilize/ZGDRS +tranquilizer/M +tranquillity/M +trans/I +transact/DGS +transaction/SM +transactor/MS +transatlantic +transceiver/SM +transcend/GSD +transcendence/M +transcendent +transcendental/Y +transcendentalism/M +transcendentalist/SM +transcontinental +transcribe/ZGDRS +transcriber/M +transcript/MS +transcription/SM +transducer/MS +transect/DSG +transept/MS +transfer/MBS +transferal/MS +transference/M +transferred +transferring +transfiguration/M +transfigure/GDS +transfinite +transfix/DSG +transform/BSZGMDR +transformation/SM +transformer/M +transfuse/DSXGN +transfusion/M +transgender/SD +transgenic +transgress/GDS +transgression/SM +transgressor/SM +transience/M +transiency/M +transient/SMY +transistor/SM +transistorize/DSG +transit/SGMD +transition/GSMD +transitional/Y +transitive/ISMY +transitiveness/M +transitivity/M +transitory +transl +translatable/U +translate/DSGNBX +translated/U +translation/M +translator/SM +transliterate/DSGNX +transliteration/M +translocation +translucence/M +translucency/M +translucent/Y +transmigrate/GNDS +transmigration/M +transmissible +transmission/MS +transmit/S +transmittable +transmittal/M +transmittance/M +transmitted +transmitter/SM +transmitting +transmogrification/M +transmogrify/DSNG +transmutation/SM +transmute/BDSG +transnational/MS +transoceanic +transom/SM +transpacific +transparency/SM +transparent/Y +transpiration/M +transpire/DSG +transplant/MDGS +transplantation/M +transpolar +transponder/SM +transport/BSZGMDR +transportation/M +transporter/M +transpose/DSG +transposition/MS +transsexual/SM +transsexualism/M +transship/SL +transshipment/M +transshipped +transshipping +transubstantiation/M +transverse/MYS +transvestism/M +transvestite/MS +trap/MS +trapdoor/MS +trapeze/SM +trapezium/SM +trapezoid/SM +trapezoidal +trappable +trapped +trapper/SM +trapping/S +trappings/M +trapshooting/M +trash/GMDS +trashcan/MS +trashiness/M +trashy/RPT +trauma/MS +traumatic +traumatically +traumatize/GDS +travail/SGMD +travel/MDRSZGJ +traveled/U +traveler/M +traveling/M +travelog/SM +travelogue/MS +traversal/SM +traverse/DSMG +travesty/GDSM +trawl/ZGSMDR +trawler/M +tray/MS +treacherous/PY +treacherousness/M +treachery/SM +treacle/M +treacly +tread/AGSM +treadle/DSMG +treadmill/MS +treas +treason/BM +treasonous +treasure/DRSMZG +treasurer/M +treasury/SM +treat/AGSMD +treatable +treated/U +treatise/SM +treatment/MS +treaty/SM +treble/MGDS +tree/MDS +treeing +treeless +treelike +treeline +treetop/SM +trefoil/SM +trek/MS +trekked +trekker/SM +trekking +trellis/GMDS +trematode/MS +tremble/DSMG +tremendous/Y +tremolo/SM +tremor/MS +tremulous/PY +tremulousness/M +trench's +trench/ADSG +trenchancy/M +trenchant/Y +trencher/MS +trencherman/M +trenchermen +trend/GSMD +trendily +trendiness/M +trendsetter/S +trendsetting +trendy/RSMPT +trepidation/M +trespass/MDRSZG +trespasser/M +tress/EMS +trestle/MS +trews +trey/MS +triad/SM +triage/M +trial/ASM +trialed +trialing +triangle/SM +triangular/Y +triangulate/GNDS +triangulation/M +triathlete/S +triathlon/SM +tribal +tribalism/M +tribe/SM +tribesman/M +tribesmen +tribeswoman/M +tribeswomen +tribulation/SM +tribunal/SM +tribune/MS +tributary/SM +tribute's +tribute/FS +trice/M +tricentennial/MS +triceps/MS +triceratops/M +trichina/M +trichinae +trichinosis/M +trick/GSMD +trickery/M +trickily +trickiness/M +trickle/MGDS +trickster/SM +tricky/TRP +tricolor/SM +tricycle/SM +trident/MS +tried/U +triennial/MYS +trier/SM +trifecta/SM +trifle/MZGDRS +trifler/M +trifocals/M +trig/M +trigger/MDSG +triglyceride/MS +trigonometric +trigonometrical +trigonometry/M +trike/SM +trilateral/S +trilby/SM +trill/GSMD +trillion/SMH +trillionth/M +trillionths +trillium/M +trilobite/SM +trilogy/SM +trim/PMYS +trimaran/MS +trimester/SM +trimmed/U +trimmer/SM +trimmest +trimming/SM +trimmings/M +trimness/M +trimonthly +trinitrotoluene/M +trinity/SM +trinket/SM +trio/MS +trip/MYS +tripartite +tripe/M +triple/MGDS +triplet/SM +triplex/MS +triplicate/MGDS +tripod/MS +tripodal +tripos +tripped +tripper/SM +tripping +triptych/M +triptychs +tripwire/S +trireme/SM +trisect/SDG +trisection/M +trite/FPYT +triteness/FM +triter +tritium/M +triumph/GMD +triumphal +triumphalism +triumphalist +triumphant/Y +triumphs +triumvir/MS +triumvirate/SM +trivalent +trivet/MS +trivia/M +trivial/Y +triviality/SM +trivialization/M +trivialize/GDS +trivium/M +trochaic +trochee/SM +trod/AU +trodden/A +troglodyte/SM +troika/MS +troll/SGMD +trolley/SM +trolleybus/MS +trollop/SM +trombone/MS +trombonist/MS +tromp/SGD +tron/S +troop/SZGMDR +trooper/M +troopship/MS +trope/SM +trophy/SM +tropic/MS +tropical/Y +tropics/M +tropism/SM +troposphere/SM +trot/MS +troth/M +trotted +trotter/SM +trotting +troubadour/MS +trouble/DSMG +troubled/U +troublemaker/MS +troubleshoot/DRZGS +troubleshooter/M +troubleshooting/M +troubleshot +troublesome/Y +trough/M +troughs +trounce/DRSZG +trouncer/M +troupe/MZGDRS +trouper/M +trouser/SM +trousers/M +trousseau/M +trousseaux +trout/SM +trove/SM +trow/DSG +trowel/MDSG +troy/S +truancy/M +truant/GMDS +truce/SM +truck/SZGMDR +trucker/M +trucking/M +truckle/MGDS +truckload/SM +truculence/M +truculent/Y +trudge/MGDS +true/MTGDRS +truelove/SM +truffle/MS +trug/S +truism/MS +truly/U +trump/SGMD +trumpery/M +trumpet/ZGMDRS +trumpeter/M +truncate/GNDS +truncation/M +truncheon/SM +trundle/MZGDRS +trundler/M +trunk/SGM +truss/GMDS +trust/ESGMD +trustee/MS +trusteeship/SM +trustful/EY +trustfulness/M +trusting/Y +trustworthiness/M +trustworthy/TPR +trusty/TRSM +truth/ZMR +truther/M +truthful/UYP +truthfulness/UM +truthiness +truths/U +try's +try/AGDS +trying/Y +tryout/SM +tryptophan +tryst/SMDG +tsarists +tsetse/MS +tsp +tsunami/SM +ttys +tub/SZGMDR +tuba/MS +tubal +tubby/TR +tube/MS +tubeless/M +tuber/M +tubercle/SM +tubercular +tuberculin/M +tuberculosis/M +tuberculous +tuberose/M +tuberous +tubful/MS +tubing/M +tubular +tubule/MS +tuck/MDRSZG +tucker/MDG +tuft/MDRSZG +tufter/M +tug/SM +tugboat/MS +tugged +tugging +tuition/IM +tularemia/M +tulip/SM +tulle/M +tum/S +tumble/DRSMZG +tumbledown +tumbler/M +tumbleweed/SM +tumbling/M +tumbrel/SM +tumbril/SM +tumescence/M +tumescent +tumid +tumidity/M +tummy/SM +tumor/SM +tumorous +tumult/SM +tumultuous/Y +tun/SZGMDR +tuna/MS +tundra/SM +tune/MS +tuneful/YP +tunefulness/M +tuneless/Y +tuner/M +tuneup/SM +tungsten/M +tunic/SM +tunnel/JSMDRZG +tunneler/M +tunny/SM +tuple/S +tuppence +tuppenny +tuque/SM +turban/SMD +turbid +turbidity/M +turbine/SM +turbo/SM +turbocharge/ZGDRS +turbocharger/M +turbofan/SM +turbojet/SM +turboprop/SM +turbot/SM +turbulence/M +turbulent/Y +turd/MS +turducken/SM +tureen/SM +turf/MDSG +turfy +turgid/Y +turgidity/M +turkey/SM +turmeric/SM +turmoil/MS +turn/AMDRSZG +turnabout/SM +turnaround/SM +turnbuckle/SM +turncoat/SM +turner/AM +turning/MS +turnip/SM +turnkey/MS +turnoff/MS +turnout/MS +turnover/MS +turnpike/MS +turnstile/SM +turntable/SM +turpentine/M +turpitude/M +turps +turquoise/SM +turret/SMD +turtle/SM +turtledove/SM +turtleneck/SMD +tush/MS +tusk/MDS +tussle/DSMG +tussock/MS +tussocky +tut/SM +tutelage/M +tutelary +tutor/SMDG +tutored/U +tutorial/SM +tutorship/M +tutted +tutti/SM +tutting +tutu/MS +tux/MS +tuxedo/SM +twaddle/MZGDRS +twaddler/M +twain/M +twang/SMDG +twangy/RT +twas +twat/S +tweak/SMDG +twee +tweed/SM +tweeds/M +tweedy/RT +tween +tweet's +tweet/ASDG +tweeter/SM +tweezers/M +twelfth/M +twelfths +twelve/SM +twelvemonth/M +twelvemonths +twentieth/M +twentieths +twenty/SMH +twerk/SDG +twerp/SM +twice +twiddle/MGDS +twiddly +twig/MS +twigged +twigging +twiggy/TR +twilight/M +twilit +twill/MD +twin/MDRSZG +twine/SM +twiner/M +twinge/DSMG +twinight +twink/SY +twinkle/MGJDS +twinkling/M +twinned +twinning +twinset/S +twirl/SMDRZG +twirler/M +twirly +twist's +twist/USDG +twister/MS +twisty/TR +twit/MS +twitch/GMDS +twitchy/RT +twitted +twitter/MDSG +twittery +twitting +twixt +two/SM +twofer/SM +twofold +twopence/SM +twopenny +twosome/SM +twp +tycoon/SM +tying/AU +tyke/MS +tympani/M +tympanic +tympanist/MS +tympanum/SM +type's +type/AGDS +typecast/GS +typeface/MS +typescript/MS +typeset/S +typesetter/MS +typesetting/M +typewrite/RSZG +typewriter/M +typewriting/M +typewritten +typewrote +typhoid/M +typhoon/MS +typhus/M +typical/UY +typicality/M +typification/M +typify/NGDS +typing/M +typist/SM +typo/MS +typographer/SM +typographic +typographical/Y +typography/M +typology/SM +tyrannic +tyrannical/Y +tyrannize/GDS +tyrannosaur/MS +tyrannosaurus/MS +tyrannous +tyranny/SM +tyrant/SM +tyro/MS +u/S +ubiquitous/Y +ubiquity/M +udder/SM +ufologist/SM +ufology/M +ugh +ugliness/M +ugly/RTP +uh +uhf +ukase/SM +ukulele/SM +ulcer/SM +ulcerate/XDSGN +ulceration/M +ulcerous +ulna/M +ulnae +ulnar +ulster/MS +ult +ulterior +ultimate/MY +ultimatum/MS +ultimo +ultra/SM +ultraconservative/SM +ultrahigh +ultralight/SM +ultramarine/M +ultramodern +ultrasonic +ultrasonically +ultrasound/MS +ultraviolet/M +ululate/DSGNX +ululation/M +um +umbel/SM +umber/M +umbilical +umbilici +umbilicus/M +umbra/SM +umbrage/M +umbrella/SM +umiak/SM +umlaut/MS +ump/SGMD +umpire/MGDS +umpteen/H +unabridged/MS +unacceptability +unacceptable +unaccommodating +unaccountably +unadventurous +unaesthetic +unalterably +unambitious +unanimity/M +unanimous/Y +unapparent +unappetizing +unappreciative +unassertive +unassuming/Y +unavailing/Y +unaware/S +unbeknown +unbeknownst +unbend/SG +unbent +unbid +unblinking/Y +unblushing/Y +unbosom/DG +unbound/D +unbreakable +unbroken +uncanny/T +uncap/S +uncaring +unceasing/Y +unchangeable +uncharacteristic +uncharitable +unchaste/RT +uncial/M +uncle/SM +unclean/DRPT +uncleanly/T +unclear/DRT +uncomfortable +uncommon/T +uncomplaining/Y +uncomplicated +uncomprehending/Y +uncompromising/Y +unconditional/Y +uncongenial +unconscionable +unconscionably +unconscious/M +unconstitutional/Y +uncontrollably +uncontroversial +uncool +uncooperative +uncouth/Y +uncrushable +unction/SM +unctuous/YP +unctuousness/M +uncut +undaunted/Y +undecided/SM +undemonstrative/Y +undeniably +under +underachieve/LZGDRS +underachiever/M +underact/SDG +underage +underappreciated +underarm/SM +underbelly/SM +underbid/S +underbidding +underbrush/M +undercarriage/MS +undercharge/MGDS +underclass/MS +underclassman/M +underclassmen +underclothes/M +underclothing/M +undercoat/GJSMD +undercoating/M +undercover +undercurrent/SM +undercut/SM +undercutting +underdeveloped +underdevelopment/M +underdog/SM +underdone +underemployed +underemployment/M +underestimate/DSMGNX +underestimation/M +underexpose/GDS +underexposure/MS +underfed +underfeed/GS +underfloor +underflow +underfoot +underfunded +underfur/M +undergarment/SM +undergo/G +undergoes +undergone +undergrad/S +undergraduate/SM +underground/MS +undergrowth/M +underhand +underhanded/PY +underhandedness/M +underlain +underlay/SM +underlie/S +underline/MGDS +underling/MS +underlip/SM +underlying +undermanned +undermentioned +undermine/GDS +undermost +underneath/M +underneaths +undernourished +undernourishment/M +underpaid +underpants/M +underpart/MS +underpass/MS +underpay/GSL +underpayment/SM +underpin/S +underpinned +underpinning/MS +underplay/DGS +underpopulated +underprivileged +underproduction/M +underrate/GDS +underrepresented +underscore/DSMG +undersea/S +undersecretary/SM +undersell/GS +undersexed +undershirt/SM +undershoot/SG +undershorts/M +undershot +underside/MS +undersign/DGS +undersigned/M +undersized +underskirt/SM +undersold +understaffed +understand/SGBJ +understandably +understanding/MY +understate/DSLG +understatement/SM +understood +understudy/GDSM +undertake/ZGJRS +undertaken +undertaker/M +undertaking/M +underthings/M +undertone/MS +undertook +undertow/SM +underused +underutilized +undervaluation/M +undervalue/DSG +underwater +underway +underwear/M +underweight/M +underwent +underwhelm/DGS +underwire/DS +underworld/MS +underwrite/ZGRS +underwriter/M +underwritten +underwrote +undesirable/MS +undies/M +undo +undoubted/Y +undramatic +undreamt +undue +undulant +undulate/DSXGN +undulation/M +undying +unearthliness/M +unease/M +uneasy/T +uneatable +uneconomic +unemployed/M +unending +unenterprising +unequal/DY +unerring/Y +unessential +uneven/Y +unexceptionably +unexcited +unexciting +unexpected/YP +unexpectedness/M +unfailing/Y +unfair/PTRY +unfaltering +unfamiliar +unfathomably +unfed +unfeeling/Y +unfeminine +unfit/S +unfitting +unfix/GDS +unflagging/Y +unflappability/M +unflappable +unflappably +unflattering +unflinching/Y +unforgettably +unforgivably +unfortunate/MS +unfriendly/T +unfrock/DG +unfruitful +unfunny +ungainliness/M +ungainly/RPT +ungenerous +ungentle +ungodly/T +ungraceful/Y +ungrudging +unguarded +unguent/SM +ungulate/MS +unhandy/T +unhappy/T +unhealthful +unhealthy/T +unhistorical +unholy/T +unhurt +unicameral +unicellular +unicorn/SM +unicycle/SM +unidirectional +unification/AM +uniform/SMDYG +uniformity/M +unify/AGDSN +unilateral/Y +unilateralism +unimportant +unimpressive +uninformative +uninhibited/Y +uninstall/BSZGDR +uninsured +unintelligent +unintended +uninteresting +uninterrupted/Y +uninterruptible +uninviting +union/ASM +unionism/M +unionist/MS +unique/YTRP +uniqueness/M +unisex/M +unison/M +unitary +unite/AEGSD +unitedly +unities +unitize/DSG +unity/EM +univalent +univalve/SM +universal/MYS +universality/M +universalize/DSG +universe/SM +university/SM +unjust/Y +unkempt +unkind/T +unkindly/T +unknowable/M +unknown/SM +unleaded/M +unless +unlike/PB +unlikely/T +unlit +unlock/DSG +unlovable +unlovely/TR +unloving +unlucky/T +unmanly/T +unmarried +unmeaning +unmentionable/MS +unmentionables/M +unmet +unmindful +unmissable +unmistakably +unmoral +unmovable +unmusical +unnecessary +unnerving/Y +unobservant +unoffensive +unofficial/Y +unoriginal +unpeople +unperceptive +unpersuasive +unpick/GDS +unpin/S +unpleasing +unpolitical +unpopular +unpractical +unprecedented/Y +unprofessional/Y +unpromising +unpropitious +unquestioning/Y +unquiet/TR +unread/B +unready +unreal +unreasoning +unregenerate +unrelated +unrelenting/Y +unrelieved/Y +unremarkable +unremitting/Y +unrepentant +unreported +unrepresentative +unrest/M +unripe/TR +unroll/GDS +unromantic +unruliness/M +unruly/RTP +unsafe/YTR +unsavory +unscathed +unsearchable +unseeing/Y +unseemly/T +unseen/M +unsentimental +unset +unshakable +unshakably +unshakeable +unshapely +unshockable +unshorn +unsightliness/M +unsightly/PT +unsmiling +unsociable +unsocial +unsold +unsound/PRYT +unspeakable +unspeakably +unspecific +unspectacular +unsporting +unstable +unsteady/TRP +unstinting/Y +unstrapping +unsubstantial +unsubtle +unsuitable +unsure +unsuspecting/Y +unsymmetrical +untactful +unthinkably +unthinking/Y +untidy/PTR +until +untimely/T +untiring/Y +untouchable/MS +untoward +untrue/RT +untrustworthy +untruth/M +unutterable +unutterably +unwarrantable +unwary/T +unwavering +unwed +unwelcome/G +unwell +unwieldiness/M +unwieldy/TRP +unwise/RYT +unworried +unworthy/T +unwound +unwrapping +unyielding +up/S +upbeat/MS +upbraid/SGD +upbringing/MS +upchuck/SGD +upcoming +upcountry/M +update/MGDRS +updraft/MS +upend/SGD +upfront +upgrade/MGDS +upheaval/MS +upheld +uphill/MS +uphold/ZGRS +upholder/M +upholster/ASGD +upholsterer/MS +upholstery/M +upkeep/M +upland/MS +uplift/JSMDG +upload/SDG +upmarket +upmost +upon +upped +upper/SM +uppercase/M +upperclassman/M +upperclassmen +upperclasswoman +upperclasswomen +uppercut/MS +uppercutting +uppermost +upping +uppish +uppity +upraise/DSG +uprear/GSD +upright/MYPS +uprightness/M +uprising/SM +upriver +uproar/SM +uproarious/Y +uproot/GSD +upscale +upset/SM +upsetting +upshot/SM +upside/SM +upsilon/MS +upstage/GDS +upstairs +upstanding +upstart/MDSG +upstate/M +upstream +upstroke/SM +upsurge/MGDS +upswing/MS +uptake/SM +uptempo +upthrust/GSM +uptick/SM +uptight +uptown/M +uptrend +upturn/GSMD +upward/SY +upwind +uracil/M +uranium/M +urban +urbane/RYT +urbanity/M +urbanization/M +urbanize/DSG +urbanologist/MS +urbanology/M +urchin/SM +urea/M +uremia/M +uremic +ureter/SM +urethane/M +urethra/M +urethrae +urethral +urge/MGDS +urgency/M +urgent/Y +uric +urinal/SM +urinalyses +urinalysis/M +urinary +urinate/GNDS +urination/M +urine/M +urn/SM +urogenital +urological +urologist/MS +urology/M +ursine +urticaria/M +usability/M +usable/UA +usage/SM +use/AEDSMG +used/U +useful/PY +usefulness/M +useless/YP +uselessness/M +user/MS +username/MS +usher/SMDG +usherette/SM +usu +usual's +usual/UY +usurer/SM +usurious +usurp/SDRZG +usurpation/M +usurper/M +usury/M +utensil/SM +uteri +uterine +uterus/M +utilitarian/MS +utilitarianism/M +utility/SM +utilization/M +utilize/GBDS +utmost/M +utopia/SM +utopian/MS +utter/SDYG +utterance/SM +uttermost/M +uveitis +uvula/SM +uvular/MS +uxorious +v/AS +vac/S +vacancy/SM +vacant/Y +vacate/DSG +vacation/ZGMDRS +vacationer/M +vacationist/SM +vaccinate/GNDSX +vaccination/M +vaccine/SM +vacillate/XGNDS +vacillation/M +vacuity/M +vacuole/MS +vacuous/YP +vacuousness/M +vacuum/GSMD +vagabond/SMDG +vagabondage/M +vagarious +vagary/SM +vagina/SM +vaginae +vaginal/Y +vagrancy/M +vagrant/MS +vague/RYTP +vagueness/M +vagus +vain/RYT +vainglorious/Y +vainglory/M +val +valance/MS +vale/MS +valediction/MS +valedictorian/SM +valedictory/SM +valence/MS +valency/SM +valentine/SM +valet/SMDG +valetudinarian/MS +valetudinarianism/M +valiance/M +valiant/Y +valid/Y +validate/IGNDS +validation/IM +validations +validity/IM +validness/M +valise/SM +valley/SM +valor/M +valorous/Y +valuable/MS +valuate/DSG +valuation/CAMS +value's +value/CAGSD +valueless +valuer/SM +valve/DSMG +valveless +valvular +vamoose/DSG +vamp/AMDGS +vampire/SM +van/SM +vanadium/M +vandal/SM +vandalism/M +vandalize/DSG +vane/MS +vanguard/MS +vanilla/SM +vanish/JDSG +vanity/SM +vanned +vanning +vanquish/ZGDRS +vanquisher/M +vantage/SM +vape/GDS +vapid/YP +vapidity/M +vapidness/M +vapor/SM +vaporization/M +vaporize/DRSZG +vaporizer/M +vaporous +vaporware +vapory +vaquero/MS +var/S +variability/IM +variable/ISM +variably/I +variance/SM +variant/MS +variate/NX +variation/M +varicolored +varicose +varied/U +variegate/DSGN +variegation/M +varietal/SM +variety/SM +various/Y +varlet/SM +varmint/MS +varnish/GMDS +varnished/U +varsity/SM +vary/DSG +varying/U +vascular +vase/MS +vasectomy/SM +vasoconstriction +vasomotor +vassal/SM +vassalage/M +vast/MRYTSP +vastness/M +vat/SM +vatted +vatting +vaudeville/M +vaudevillian/MS +vault/SMDRZG +vaulter/M +vaulting/M +vaunt/SMDG +vb +veal/M +vector/SGMD +veejay/SM +veep/MS +veer/MDGS +veg/SM +vegan/SM +veganism +vegeburger/S +veges +vegetable/SM +vegetarian/SM +vegetarianism/M +vegetate/GNVDS +vegetation/M +vegged +vegges +veggie/SM +veggieburger/S +vegging +vehemence/M +vehemency/M +vehement/Y +vehicle/MS +vehicular +veil's +veil/UDGS +vein/MDGS +vela +velar/SM +veld/MS +vellum/M +velocipede/MS +velocity/SM +velodrome/S +velour/MS +velum/M +velvet/M +velveteen/M +velvety +venal/Y +venality/M +venation/M +vend/DGS +vendetta/SM +vendible +vendor/MS +veneer/MDGS +venerability/M +venerable +venerate/DSGN +veneration/M +venereal +vengeance/M +vengeful/AY +venial +venireman/M +veniremen +venison/M +venom/M +venomous/Y +venous +vent's +vent/DGS +ventilate/GNDS +ventilation/M +ventilator/SM +ventral +ventricle/SM +ventricular +ventriloquism/M +ventriloquist/SM +ventriloquy/M +venture/DSMG +venturesome/PY +venturesomeness/M +venturous/PY +venturousness/M +venue/ASM +veracious/Y +veracity/M +veranda/SM +verandah/M +verandahs +verb/KMS +verbal/MYS +verbalization/M +verbalize/GDS +verbatim +verbena/SM +verbiage/MS +verbose/Y +verbosity/M +verboten +verdant/Y +verdict/SM +verdigris/GMDS +verdure/M +verge's +verge/FDSG +verger/MS +verifiable/U +verification/M +verified/U +verify/DSNG +verily +verisimilitude/M +veritable +veritably +verity/SM +vermicelli/M +vermiculite/M +vermiform +vermilion/M +vermin/M +verminous +vermouth/M +vernacular/MS +vernal +vernier/SM +veronica/M +verruca/SM +verrucae +versa +versatile +versatility/M +verse/AFNGMSDX +versed/U +versification/M +versifier/M +versify/ZGNDRS +version/AFIMS +versioned +versioning +verso/SM +versus +vert/A +vertebra/M +vertebrae +vertebral +vertebrate/IMS +vertex/MS +vertical/MYS +vertices +vertiginous +vertigo/M +verve/M +very/RT +vesicle/SM +vesicular +vesiculate +vesper/MS +vessel/MS +vest's +vest/ILDGS +vestal/MS +vestibule/MS +vestige/SM +vestigial/Y +vesting/M +vestment/IMS +vestry/SM +vestryman/M +vestrymen +vet/SM +vetch/MS +veteran/SM +veterinarian/MS +veterinary/SM +veto/MDG +vetoes +vetted +vetting +vex/GDS +vexation/SM +vexatious/Y +vhf +vi +via +viability/M +viable +viably +viaduct/SM +vial/MS +viand/SM +vibe/MS +vibes/M +vibraharp/SM +vibrancy/M +vibrant/Y +vibraphone/MS +vibraphonist/MS +vibrate/GNDSX +vibration/M +vibrato/MS +vibrator/SM +vibratory +viburnum/SM +vicar/SM +vicarage/SM +vicarious/YP +vicariousness/M +vice/CMS +viced +vicegerent/SM +vicennial +viceregal +viceroy/MS +vichyssoise/M +vicing +vicinity/M +vicious/YP +viciousness/M +vicissitude/SM +victim/MS +victimization/M +victimize/GDS +victor/MS +victorious/Y +victory/SM +victual/SMDG +vicuna/MS +vicuña/MS +videlicet +video/GSMD +videocassette/SM +videoconferencing +videodisc/MS +videophone/MS +videotape/DSMG +videotex +vie/DS +view/AMDRSZG +viewer/AM +viewership/M +viewfinder/SM +viewing/SM +viewpoint/MS +vigesimal +vigil/SM +vigilance/M +vigilant/Y +vigilante/SM +vigilantism/M +vigilantist/M +vignette/DSMG +vignettist/MS +vigor/M +vigorous/Y +vii +viii +viking/MS +vile/YTPR +vileness/M +vilification/M +vilify/DSNG +villa/SM +village/RSMZ +villager/M +villain/SM +villainous +villainy/SM +villein/SM +villeinage/M +villi +villus/M +vim/M +vinaigrette/M +vincible/I +vindicate/XDSGN +vindication/M +vindicator/MS +vindictive/PY +vindictiveness/M +vine/MS +vinegar/M +vinegary +vineyard/MS +vino/M +vinous +vintage/MS +vintner/MS +vinyl/SM +viol/MBS +viola/SM +violable/I +violate/GNDSX +violation/M +violator/SM +violence/M +violent/Y +violet/MS +violin/MS +violincello/S +violinist/SM +violist/MS +violoncellist/SM +violoncello/MS +viper/SM +viperous +virago/M +viragoes +viral +vireo/SM +virgin/MS +virginal/SM +virginity/M +virgule/MS +virile +virility/M +virologist/SM +virology/M +virtual/Y +virtualization +virtue/SM +virtuosity/M +virtuoso/SM +virtuous/YP +virtuousness/M +virulence/M +virulent/Y +virus/MS +visa/MDSG +visage/MS +viscera +visceral/Y +viscid +viscose/M +viscosity/M +viscount/SM +viscountcy/SM +viscountess/MS +viscous +viscus/M +vise/ACMGDS +visibility/IM +visible/I +visibly/I +vision/KGDSM +visionary/SM +visit's +visit/ASGD +visitant/MS +visitation/MS +visitor/MS +visor/SM +vista/SM +visual/SMY +visualization/SM +visualize/DRSZG +visualizer/M +vita/M +vitae +vital/SY +vitality/M +vitalization/AM +vitalize/CAGSD +vitals/M +vitamin/MS +vitiate/GNDS +vitiation/M +viticulture/M +viticulturist/MS +vitreous +vitrifaction/M +vitrification/M +vitrify/GNDS +vitrine/SM +vitriol/M +vitriolic +vitriolically +vittles/M +vituperate/GNVDS +vituperation/M +viva/MS +vivace +vivacious/PY +vivaciousness/M +vivacity/M +vivaria +vivarium/SM +vivid/RYTP +vividness/M +vivify/ADSG +viviparous +vivisect/DGS +vivisection/M +vivisectional +vivisectionist/SM +vixen/SM +vixenish/Y +viz +vizier/SM +vlf +vocab +vocable/MS +vocabulary/SM +vocal/SMY +vocalic +vocalist/SM +vocalization/MS +vocalize/DSG +vocation/FIKASM +vocational/Y +vocative/MS +vociferate/DSGN +vociferation/M +vociferous/YP +vociferousness/M +vodka/SM +vogue/SM +voguish +voice/IDSMG +voiced/U +voiceless/PY +voicelessness/M +voicemail/SM +void/MDSGB +voila +voile/M +voilà +vol/S +volatile +volatility/M +volatilize/DSG +volcanic +volcano/M +volcanoes +vole/MS +volition/M +volitional +volley/GSMD +volleyball/MS +volt/AMS +voltage/MS +voltaic +voltmeter/SM +volubility/M +voluble +volubly +volume/SM +voluminous/YP +voluminousness/M +voluntarily/I +voluntarism/M +voluntary/SM +volunteer/SGMD +volunteerism/M +voluptuary/SM +voluptuous/PY +voluptuousness/M +volute/SM +vomit/SMDG +voodoo/GSMD +voodooism/M +voracious/PY +voraciousness/M +voracity/M +vortex/MS +votary/SM +vote's +vote/CGVDS +voter/SM +vouch/DRSZG +voucher/M +vouchsafe/DSG +vow/SGMD +vowel/SM +voyage/MZGDRS +voyager/M +voyageur/SM +voyeur/MS +voyeurism/M +voyeuristic +vulcanization/M +vulcanize/GDS +vulgar/RYT +vulgarian/MS +vulgarism/MS +vulgarity/SM +vulgarization/M +vulgarize/ZGDRS +vulgarizer/M +vulnerabilities +vulnerability/IM +vulnerable/I +vulnerably/I +vulpine +vulture/SM +vulturous +vulva/M +vulvae +vuvuzela/MS +vying +w/DNXTGVJ +wabbit/S +wack/MRTS +wackiness/M +wacko/SM +wacky/RPT +wad/SZGMDR +wadded +wadding/M +waddle/DSMG +wade/MS +wader/M +waders/M +wadge/S +wadi/MS +wafer/SM +waffle/MZGDRS +waffler/M +waft/MDGS +wag/SZGMDR +wage/MS +waged/U +wager/ZGMDR +wagerer/M +wagged +waggery/SM +wagging +waggish/YP +waggishness/M +waggle/MGDS +wagon/ZSMR +wagoner/M +wagtail/SM +waif/MS +wail/MDRZGS +wailer/M +wailing/M +wain/MS +wainscot/SJMDG +wainscoting/M +wainscotted +wainscotting/MS +wainwright/MS +waist/SM +waistband/MS +waistcoat/MS +waistline/MS +wait/MDRZGS +waiter/M +waiting/M +waitperson/MS +waitress/MS +waitstaff/M +waive/DRSZG +waiver/M +wake/MGJDS +wakeful/PY +wakefulness/M +waken/GSD +waldo/S +waldoes +wale/MGDS +walk/MDRZGS +walkabout/S +walkaway/MS +walker/M +walkies +walking/M +walkout/SM +walkover/MS +walkway/SM +wall/MDGS +wallaby/SM +wallah +wallahs +wallboard/M +wallet/MS +walleye/DSM +wallflower/MS +wallop/MDSJG +walloping/M +wallow/MDSG +wallpaper/SMDG +wally/S +walnut/MS +walrus/MS +waltz/ZGMDRS +waltzer/M +wampum/M +wan/GPDY +wand/MS +wander/DRSJZG +wanderer/M +wanderings/M +wanderlust/SM +wane/MS +wangle/MZGDRS +wangler/M +wank/DRZGS +wanna +wannabe/SM +wannabee/S +wanner +wanness/M +wannest +want/MDGS +wanted/U +wanton/MDYSPG +wantonness/M +wapiti/MS +war/SM +warble/MZGDRS +warbler/M +warbonnet/SM +ward/AMDGS +warden/MS +warder/MS +wardress/S +wardrobe/SM +wardroom/SM +ware/MS +warehouse/DSMG +warez +warfare/M +warhead/MS +warhorse/SM +warily/U +wariness/UM +warlike +warlock/MS +warlord/MS +warm/PDRYHZTGS +warmblooded +warmer/M +warmhearted/P +warmheartedness/M +warmish +warmness/M +warmonger/SMG +warmongering/M +warmth/M +warmup/MS +warn/JDGS +warning/M +warp/MDGS +warpaint +warpath/M +warpaths +warplane/MS +warrant/GMDS +warranted/U +warranty/DSMG +warred +warren/MS +warring +warrior/SM +warship/SM +wart/MS +warthog/SM +wartime/M +warty/TR +wary/UPRT +was +wasabi +wash/BJMDRSZG +washable/SM +washbasin/SM +washboard/SM +washbowl/SM +washcloth/M +washcloths +washed/U +washer/M +washerwoman/M +washerwomen +washing/M +washout/MS +washrag/MS +washroom/MS +washstand/SM +washtub/MS +washy/TR +wasn't +wasp/MS +waspish/YP +waspishness/M +wassail/SMDG +wast +wastage/M +waste/DRSMZG +wastebasket/MS +wasteful/PY +wastefulness/M +wasteland/SM +wastepaper/M +waster/M +wastewater +wastrel/SM +watch/BZGMDRS +watchable/U +watchband/MS +watchdog/SM +watcher/M +watchful/YP +watchfulness/M +watchmaker/MS +watchmaking/M +watchman/M +watchmen +watchstrap/S +watchtower/SM +watchword/MS +water/GSMD +waterbed/MS +waterbird/SM +waterboard/MDJSG +waterboarding/M +waterborne +watercolor/MS +watercourse/SM +watercraft/M +watercress/M +waterfall/SM +waterfowl/SM +waterfront/MS +waterhole/SM +wateriness/M +waterlily/SM +waterline/MS +waterlogged +watermark/MDGS +watermelon/SM +watermill/MS +waterpower/M +waterproof/SMDG +waterproofing/M +waters/M +watershed/MS +waterside/MS +waterspout/SM +watertight +waterway/MS +waterwheel/SM +waterworks/M +watery/PTR +watt/MS +wattage/M +wattle/MGDS +wave/MZGDRS +waveband/S +waveform +wavelength/M +wavelengths +wavelet/SM +wavelike +waver/ZGMDR +waverer/M +wavering/Y +waviness/M +wavy/PRT +wax/GMDNS +waxiness/M +waxwing/SM +waxwork/SM +waxy/RPT +way/SM +waybill/SM +wayfarer/MS +wayfaring/SM +waylaid +waylay/RSZG +waylayer/M +wayside/SM +wayward/PY +waywardness/M +wazoo/S +we +we'd +we'll +we're +we've +weak/PNRYXT +weaken/DRZG +weakener/M +weakfish/MS +weakish +weakling/SM +weakness/MS +weal/MHS +wealth/M +wealthiness/M +wealthy/TRP +wean/DGS +weapon/MS +weaponize/GDS +weaponless +weaponry/M +wear/MRBJSZG +wearable/U +wearer/M +wearied/U +wearily +weariness/M +wearisome/Y +weary/TGDRSP +weasel/MDYSG +weather/SMDG +weatherboard/SG +weathercock/MS +weathering/M +weatherization/M +weatherize/DSG +weatherman/M +weathermen +weatherperson/MS +weatherproof/GSD +weatherstrip/S +weatherstripped +weatherstripping/M +weave/DRSMZG +weaver/M +weaving/M +web/SM +webbed +webbing/M +webcam/MS +webcast/SMG +webfeet +webfoot/M +webinar/SM +webisode/MS +weblog/MS +webmaster/SM +webmistress/MS +website/SM +wed/AS +wedded/A +wedder +wedding/SM +wedge/DSMG +wedgie/MS +wedlock/M +wee/RSMT +weed/MDRSZG +weeder/M +weedkiller/S +weedless +weedy/TR +weeing +week/MYS +weekday/SM +weekend/SZGMDR +weekly/SM +weeknight/SM +ween/DSG +weenie/MTRS +weensy/RT +weeny +weep/MRJSZG +weeper/M +weepie +weepy/TRSM +weevil/MS +weft/MS +weigh's +weigh/AGD +weighbridge/S +weighs/A +weight/MDSJG +weighted/U +weightily +weightiness/M +weightless/YP +weightlessness/M +weightlifter/MS +weightlifting/M +weighty/PTR +weir/MS +weird/PTRY +weirdie/MS +weirdness/M +weirdo/MS +welcome/MGDS +weld/MDRBSZG +welder/M +welfare/M +welkin/M +well/MDPSG +wellhead/SM +wellie +wellington/MS +wellness/M +wellspring/MS +welly/S +welsh/ZGDRS +welsher/M +welt/MDRSZG +welter/GMD +welterweight/SM +wen/M +wench/MS +wend/DSG +went +wept +were +weren't +werewolf/M +werewolves +west/M +westbound +westerly/SM +western/SZMR +westerner/M +westernization/M +westernize/GDS +westernmost +westward/S +wet/SMYP +wetback/SM +wetland/SM +wetness/M +wetter/SM +wettest +wetting +wetware/S +whack/SJZGMDR +whacker/M +whale/DRSMZG +whaleboat/MS +whalebone/M +whaler/M +whaling/M +wham/MS +whammed +whamming +whammy/SM +wharf/M +wharves +what/MS +whatchamacallit/MS +whatever +whatnot/M +whatshername +whatshisname +whatsit/S +whatsoever +wheal/SM +wheat/MN +wheatgerm +wheatmeal +whee +wheedle/DRSZG +wheedler/M +wheel/SMDRG +wheelbarrow/SM +wheelbase/SM +wheelchair/SM +wheelhouse/MS +wheelie/SM +wheelwright/MS +wheeze/DSMG +wheezily +wheeziness/M +wheezy/PRT +whelk/SMD +whelm/SDG +whelp/SMDG +when/MS +whence +whenever +whensoever +where/SM +whereabouts/M +whereas +whereat +whereby +wherefore/MS +wherein +whereof +whereon +wheresoever +whereto +whereupon +wherever +wherewith +wherewithal/M +wherry/SM +whet/S +whether +whetstone/SM +whetted +whetting +whew +whey/M +which +whichever +whiff/SMDG +whiffletree/MS +while/DSMG +whilom +whilst +whim/MS +whimper/MDGS +whimsical/Y +whimsicality/M +whimsy/SM +whine/DRSMZG +whiner/M +whinge/DRSZG +whingeing +whinny/GDSM +whiny/RT +whip/MS +whipcord/M +whiplash/MS +whipped +whipper/MS +whippersnapper/MS +whippet/MS +whipping/SM +whippletree/SM +whippoorwill/MS +whipsaw/MDGS +whir/MS +whirl/SMDG +whirligig/MS +whirlpool/MS +whirlwind/MS +whirlybird/SM +whirred +whirring +whisk/SMDRZG +whisker/MD +whiskery +whiskey/MS +whisky/SM +whiskys +whisper/MDRSZG +whisperer/M +whist/M +whistle/MZGDRS +whistler/M +whit/MDNRSXTGJ +white/SPM +whitebait +whiteboard/S +whitecap/SM +whitefish/MS +whitehead/MS +whiten/ZGDRJ +whitener/M +whiteness/M +whitening/M +whiteout/SM +whitetail/MS +whitewall/SM +whitewash/MDSG +whitewater/M +whitey/SM +whither +whiting/M +whitish +whittle/ZGDRS +whittler/M +whiz/M +whizkid/M +whizz/MDSG +whizzbang/MS +who'd +who'll +who're +who've +who/M +whoa +whodunit/MS +whoever +whole/SMP +wholefood/S +wholegrain +wholehearted/YP +wholeheartedness/M +wholemeal +wholeness/M +wholesale/MZGDRS +wholesaler/M +wholesome/UP +wholesomely +wholesomeness/UM +wholewheat +wholly +whom +whomever +whomsoever +whoop/SMDRZG +whoopee/S +whooper/M +whoosh/MDSG +whop/S +whopped +whopper/SM +whopping +whore/SMG +whorehouse/MS +whoreish +whorish +whorl/SMD +whose +whoso +whosoever +whup/S +whupped +whupping +why'd +why/M +whys +wick/MDRSZ +wicked/TPRY +wickedness/M +wicker/M +wickerwork/M +wicket/SM +wide/YTRP +widemouthed +widen/SDRZG +widener/M +wideness/M +widescreen/MS +widespread +widgeon/MS +widget/S +widow/SMDRZG +widower/M +widowhood/M +width/M +widths +wield/SDRZG +wielder/M +wiener/SM +wienie/SM +wife/MY +wifeless +wig/SM +wigeon/SM +wigged +wigging +wiggle/DRSMZG +wiggler/M +wiggly/TR +wight/SM +wiglet/SM +wigwag/SM +wigwagged +wigwagging +wigwam/SM +wiki/MS +wild/MRYSTP +wildcard/MS +wildcat/MS +wildcatted +wildcatter/MS +wildcatting +wildebeest/MS +wilderness/MS +wildfire/MS +wildflower/SM +wildfowl/M +wildlife/M +wildness/M +wilds/M +wile/MGDS +wilful/P +wilfulness/M +wiliness/M +will/MDS +willful/PY +willfulness/M +willies/M +willing/UPY +willingness/UM +williwaw/MS +willow/SM +willowy +willpower/M +willy/S +wilt/MDSG +wily/RTP +wimp/MDSG +wimpish +wimple/DSMG +wimpy/RT +win/SGMD +wince/DSMG +winch/MDSG +wind's +wind/UASG +windbag/SM +windblown +windbreak/SZMR +windbreaker/M +windburn/MD +windcheater/S +windchill/M +winded +winder/SM +windfall/MS +windflower/MS +windily +windiness/M +winding's +windjammer/SM +windlass/MS +windless +windmill/MDGS +window/SMDG +windowless +windowpane/SM +windowsill/SM +windpipe/MS +windproof +windrow/SM +windscreen/SM +windshield/SM +windsock/MS +windstorm/MS +windsurf/ZGDRS +windsurfer/M +windsurfing/M +windswept +windup/SM +windward/M +windy/RTP +wine/MS +wineglass/MS +winegrower/MS +winemaker/MS +winery/SM +wing/MDRZG +wingding/MS +wingless +winglike +wingnut/SM +wingspan/MS +wingspread/SM +wingtip/SM +wink/MDRSZG +winker/M +winkle/DSMG +winnable/U +winner/SM +winning/MYS +winnow/ZGSDR +winnower/M +wino/MS +winsome/YTRP +winsomeness/M +winter/GSMD +wintergreen/M +winterize/GDS +wintertime/M +wintry/TR +winy/RT +wipe/MZGDRS +wiper/M +wire's +wire/AGDS +wired/S +wirehair/MS +wireless/MS +wiretap/MS +wiretapped +wiretapper/SM +wiretapping/M +wiriness/M +wiring/M +wiry/RTP +wisdom/M +wise/MYTGDRS +wiseacre/SM +wisecrack/MDSG +wiseguy/S +wish/MDRSZG +wishbone/SM +wisher/M +wishful/Y +wishlist's +wisp/MS +wispy/RT +wist +wisteria/SM +wistful/YP +wistfulness/M +wit/SM +witch/MDSG +witchcraft/M +witchery/M +with +withal +withdraw/SG +withdrawal/MS +withdrawn +withdrew +withe/DRSMZG +wither/JGD +withering/Y +withers/M +withheld +withhold/SG +withholding/M +within/M +without +withstand/GS +withstood +witless/PY +witlessness/M +witness/MDSG +wits/M +witted +witter/SGD +witticism/SM +wittily +wittiness/M +witting/UY +witty/RPT +wive/GDS +wiz/S +wizard/SMY +wizardry/M +wizened +wk/Y +woad/M +wobble/MGDS +wobbliness/M +wobbly/RTP +wodge/S +woe/SM +woebegone +woeful/YP +woefuller +woefullest +woefulness/M +wog/S +wok/SMN +woke +wold/MS +wolf/MDSG +wolfhound/SM +wolfish +wolfram/M +wolverine/SM +wolves +woman/M +womanhood/M +womanish +womanize/DRSZG +womanizer/M +womankind/M +womanlike/M +womanliness/M +womanly/RPT +womb/MS +wombat/MS +womble/S +women/M +womenfolk/SM +womenfolks/M +won't +won/M +wonder/MDGLS +wonderful/YP +wonderfulness/M +wondering/Y +wonderland/MS +wonderment/M +wondrous/Y +wonk/MS +wonky/TR +wont/MD +wonted/U +woo/SZGDR +wood/MDNSG +woodbine/M +woodblock/MS +woodcarver/MS +woodcarving/SM +woodchuck/MS +woodcock/SM +woodcraft/M +woodcut/SM +woodcutter/SM +woodcutting/M +wooden/RYTP +woodenness/M +woodiness/M +woodland/SM +woodlice +woodlot/SM +woodlouse +woodman/M +woodmen +woodpecker/MS +woodpile/SM +woods/M +woodshed/SM +woodsiness/M +woodsman/M +woodsmen +woodsy/RTP +woodwind/MS +woodwork/MRZG +woodworker/M +woodworking/M +woodworm/S +woody/TPRSM +wooer/M +woof/MDRSZG +woofer/M +wool/MNX +woolen/M +woolgathering/M +wooliness +woolliness/M +woolly/RSMPT +woozily +wooziness/M +woozy/TRP +wop/S! +word's +word/ADSG +wordage/M +wordbook/SM +wordily +wordiness/M +wording/SM +wordless/Y +wordplay/M +wordsmith +wordsmiths +wordy/TPR +wore +work's +work/ADJSG +workable/U +workaday +workaholic/SM +workaround/S +workbasket/S +workbench/MS +workbook/MS +workday/SM +worker/MS +workfare/M +workflow/MS +workforce/M +workhorse/SM +workhouse/SM +working's +workingman/M +workingmen +workings/M +workingwoman/M +workingwomen +workload/MS +workman/M +workmanlike +workmanship/M +workmate/S +workmen +workout/SM +workplace/MS +workroom/MS +works/M +worksheet/MS +workshop/MS +workshy +workstation/MS +worktable/MS +worktop/S +workup/MS +workweek/SM +world/SM +worldlier +worldliness/UM +worldly/UTP +worldview/SM +worldwide +worm/MDSG +wormhole/MS +wormwood/M +wormy/TR +worn/U +worried/Y +worrier/M +worriment/M +worrisome +worry/ZGDRSMJ +worrying/Y +worrywart/SM +worse/M +worsen/DSG +worship/ZGSMDR +worshiper/M +worshipful +worst/SGMD +worsted/M +wort/M +worth/M +worthies +worthily/U +worthiness/UM +worthless/PY +worthlessness/M +worthwhile +worthy's +worthy/UPRT +wot +wotcha +would've +would/S +wouldn't +wouldst +wound/SGMDR +wove/A +woven/AU +wow/SGMD +wpm +wrack/GSMD +wraith/M +wraiths +wrangle/DRSMZGJ +wrangler/M +wrap's +wrap/US +wraparound/SM +wrapped/U +wrapper/SM +wrapping/MS +wrasse/MS +wrath/M +wrathful/Y +wreak/SGD +wreath/MDSG +wreathe +wreaths +wreck/SZGMDR +wreckage/M +wrecker/M +wren/MS +wrench/MDSG +wrest/SGMD +wrestle/MZGDRS +wrestler/M +wrestling/M +wretch/MS +wretched/TPRY +wretchedness/M +wriggle/MZGDRS +wriggler/M +wriggly +wright/MS +wring/SZGMR +wringer/M +wrinkle/MGDS +wrinkled/U +wrinkly/TRSM +wrist/SM +wristband/MS +wristwatch/MS +writ/MRBJSZG +write/S +writer/M +writhe/MGDS +writing/M +written/AU +wrong/STGMPDRY +wrongdoer/SM +wrongdoing/SM +wrongful/PY +wrongfulness/M +wrongheaded/YP +wrongheadedness/M +wrongness/M +wrote/A +wroth +wrought +wrung +wry/Y +wryer +wryest +wryness/M +wt +wunderkind/S +wurst/SM +wuss/MS +wussy/RSMT +x +xci +xcii +xciv +xcix +xcvi +xcvii +xenon/M +xenophobe/MS +xenophobia/M +xenophobic +xerographic +xerography/M +xerox/MDSG +xi/SM +xii +xiii +xiv +xix +xor +xref/S +xterm/M +xv +xvi +xvii +xviii +xx +xxi +xxii +xxiii +xxiv +xxix +xxv +xxvi +xxvii +xxviii +xxx +xxxi +xxxii +xxxiii +xxxiv +xxxix +xxxv +xxxvi +xxxvii +xxxviii +xylem/M +xylene +xylophone/SM +xylophonist/MS +y +y'all +ya +yacht/SMDG +yachting/M +yachtsman/M +yachtsmen +yachtswoman/M +yachtswomen +yahoo/SM +yak/SM +yakked +yakking +yam/SM +yammer/SZGMDR +yammerer/M +yang/M +yank/MDSG +yap/SM +yapped +yapping +yard/MS +yardage/MS +yardarm/MS +yardman/M +yardmaster/MS +yardmen +yardstick/MS +yarmulke/SM +yarn/MS +yarrow/M +yashmak/S +yaw/SGMD +yawl/MS +yawn/MDRSZG +yawner/M +yaws/M +yd +ye/RST +yea/SM +yeah/M +yeahs +year/MYS +yearbook/MS +yearling/MS +yearlong +yearly/SM +yearn/GSJD +yearning/M +yeast/SM +yeasty/RT +yegg/MS +yell/MDSG +yellow/MDRTGPS +yellowhammer/S +yellowish +yellowness/M +yellowy +yelp/MDSG +yen/SM +yeoman/M +yeomanry/M +yeomen +yep/SM +yes/MS +yeshiva/SM +yeshivot +yessed +yessing +yesterday/MS +yesteryear/M +yet +yeti/MS +yew/SM +yid/S +yield/JSGMD +yikes +yin/M +yip/SM +yipe +yipped +yippee +yipping +yo +yob/S +yobbo/S +yodel/SMDRZG +yodeler/M +yoga/M +yogi/MS +yogic +yogurt/SM +yoke's +yoke/UGDS +yokel/SM +yolk/MDS +yon +yonder +yonks +yore/M +you'd +you'll +you're +you've +you/SMH +young/TMR +youngish +youngster/MS +your/S +yourself +yourselves +youth/M +youthful/YP +youthfulness/M +youths +yow +yowl/MDSG +yr/S +ytterbium/M +yttrium/M +yuan/M +yucca/SM +yuck/MDSG +yucky/TR +yuk/SM +yukked +yukking +yukky +yule/M +yuletide/M +yum +yummy/TR +yup/SM +yuppie/MS +yuppify/GDS +yurt/MS +z/DNXTGJ +zaniness/M +zany/RSMPT +zap/SM +zapped +zapper/MS +zapping +zappy +zeal/M +zealot/MS +zealotry/M +zealous/YP +zealousness/M +zebra/SM +zebu/MS +zed/SM +zeitgeist/SM +zenith/M +zeniths +zenned +zeolite/S +zephyr/MS +zeppelin/MS +zero/MDHSG +zeroes +zest/MS +zestful/YP +zestfulness/M +zesty/RT +zeta/MS +zigzag/SM +zigzagged +zigzagging +zilch/M +zillion/MS +zinc/MS +zincked +zincking +zine/S +zinfandel/M +zing/MDRZG +zinger/M +zingy/RT +zinnia/MS +zip's +zip/US +zipped/U +zipper/MDGS +zipping/U +zippy/TR +zircon/MS +zirconium/M +zit/SM +zither/MS +zloty/SM +zlotys +zodiac/MS +zodiacal +zombie/MS +zonal/Y +zone's +zone/AGDS +zoning/M +zonked +zoo/SM +zookeeper/SM +zoological/Y +zoologist/SM +zoology/M +zoom/MDSG +zoophyte/SM +zoophytic +zooplankton +zorch +zoster +zounds +zucchini/MS +zwieback/M +zydeco/M +zygote/SM +zygotic +zymurgy/M +Ångström/M +éclair/SM +éclat/M +élan/M +émigré/SM +épée/MS +étude/SM diff --git a/extensions/spellcheck/locales/en-US/hunspell/en-US.aff b/extensions/spellcheck/locales/en-US/hunspell/en-US.aff new file mode 100644 index 000000000..900aae609 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.aff @@ -0,0 +1,203 @@ +SET ISO8859-1 +TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' +NOSUGGEST ! + +# ordinal numbers +COMPOUNDMIN 1 +# only in compounds: 1th, 2th, 3th +ONLYINCOMPOUND c +# compound rules: +# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.) +# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.) +COMPOUNDRULE 2 +COMPOUNDRULE n*1t +COMPOUNDRULE n*mp +WORDCHARS 0123456789 + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 90 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP alot a_lot +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion +REP size cise diff --git a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic new file mode 100644 index 000000000..429c95198 --- /dev/null +++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic @@ -0,0 +1,52349 @@ +52348 +0/nm +0th/pt +1/n1 +1st/p +1th/tc +2/nm +2nd/p +2th/tc +3/nm +3rd/p +3th/tc +4/nm +4th/pt +5/nm +5th/pt +6/nm +6th/pt +7/nm +7th/pt +8/nm +8th/pt +9/nm +9th/pt +A/SM +AA/M +AAA +AB/M +ABA +ABC/M +ABM/SM +ABS +AC/M +ACLU/M +ACT +ACTH/M +AD/M +ADC +ADD +ADM +ADP/M +AF +AFAIK +AFB +AFC/M +AFDC +AFN +AFT +AI/SM +AIDS/M +AK +AL +AM/M +AMA +AMD/M +ANSI/S +ANZUS/M +AOL/M +AP/M +APB +APC +API/SM +APO +APR +AR +ARC +ASAP +ASCII/SM +ASL/M +ASPCA +ATM/M +ATP/M +ATPase/M +ATV +AV +AVI +AWACS/M +AWOL/M +AZ/M +AZT/M +Aachen/M +Aaliyah/M +Aaron/M +Ab's +Abba/S +Abbas/M +Abbasid/M +Abbie/M +Abbott/M +Abby/M +Abdel/M +Abdul/M +Abe/M +AbeBooks +Abel/M +Abelard/M +Abelson/M +Aberdeen/M +Abernathy/M +Abidjan/M +Abie/M +Abigail/M +Abilene/M +Abner/M +Aborigine/MS +Abra/M +Abraham/M +Abram/MS +Abramo/M +Abrams/M +Absalom/M +Abuja/M +Abyssinia/M +Abyssinian/M +Ac/M +Acadia/M +Acapulco/M +Accenture/M +Accra/M +Acevedo/M +Achaean/M +Achebe/M +Achernar/M +Acheson/M +Achilles/M +Aconcagua/M +Acosta/M +Acropolis +Acrux/M +Actaeon/M +ActiveX/M +Acton/M +Acts/M +Acuff/M +Acura/M +Ada/SM +Adah/M +Adair/M +Adaline/M +Adam/SM +Adamo/M +Adams/M +Adan/M +Adana/M +Adar/M +AddThis/M +Adda/M +Addams/M +Adderley/M +Addi/M +Addie/M +Addison/M +Addy/M +Ade/M +Adel/M +Adela/M +Adelaida/M +Adelaide/M +Adelbert/M +Adele/M +Adelheid/M +Adelina/M +Adeline/M +Adelle/M +Aden/M +Adena/M +Adenauer/M +Adey/M +Adham/M +Adhara/M +Adi/M +Adidas/M +Adina/M +Adirondack/SM +Adirondacks/M +Adkins/M +Adlai/M +Adler/M +Adm +Admiralty +Adolf/M +Adolfo/M +Adolph/M +Adolphe/M +Adolphus/M +Adonis/MS +Adore's +Adrenalin/MS +Adria/M +Adrian/M +Adriana/M +Adriane/M +Adrianna/M +Adrianne/M +Adriano/M +Adriatic/M +Adrien/M +Adrienne/M +Advent/MS +Adventist/MS +Advil/M +Aegean/M +Aelfric/M +Aeneas/M +Aeneid/M +Aeolus/M +Aeroflot/M +Aeschylus/M +Aesculapius/M +Aesop/M +Afghan/SM +Afghani/M +Afghanistan/M +Afr +Africa/M +African/SM +Afrikaans/M +Afrikaner/SM +Afro/SM +Afrocentric +Afrocentrism/M +Afton/M +Ag/M +Agamemnon/M +Agana +Agassi/M +Agassiz/M +Agata/M +Agatha/M +Agathe/M +Aggie/M +Agilent +Aglaia/M +Agnes/M +Agnese/M +Agnew/M +Agni/M +Agosto/M +Agra/M +Agricola/M +Agrippa/M +Agrippina/M +Aguascalientes +Aguilar/M +Aguinaldo/M +Aguirre/M +Agustin/M +Ahab/M +Aharon/M +Ahmad/M +Ahmadabad/M +Ahmadinejad/M +Ahmed/M +Ahriman/M +Aida/M +Aidan/M +Aiken/M +Aila/M +Aileen/M +Ailey/M +Aime/M +Aimee/M +Ainsley/M +Ainslie/M +Ainu/M +Airedale/MS +Aires/M +Aisha/M +Ajax/M +Ajay/M +Akbar/M +Akhmatova/M +Akihito/M +Akim/M +Akita/M +Akiva/M +Akkad/M +Akron/M +Al/M +Ala/S +Alabama/M +Alabaman/MS +Alabamian/SM +Aladdin/M +Alain/M +Alameda/M +Alamo/M +Alamogordo/M +Alan/M +Alana/M +Aland/M +Alanna/M +Alanson/M +Alar/M +Alaric/M +Alasdair/M +Alaska/M +Alaskan/MS +Alastair/M +Alba/M +Albania/M +Albanian/MS +Albany/M +Albee/M +Alberio/M +Albert/M +Alberta/M +Albertan +Albertina/M +Albertine/M +Alberto/M +Albie/M +Albigensian/M +Albina/M +Albion/M +Albireo/M +Albrecht/M +Albuquerque/M +Alcatraz/M +Alcestis/M +Alcibiades/M +Alcindor/M +Alcmena/M +Alcoa/M +Alcott/M +Alcuin/M +Alcyone/M +Aldan/M +Aldebaran/M +Alden/M +Alderamin/M +Aldin/M +Aldis/M +Aldo/M +Aldon/M +Aldous/M +Aldrich/M +Aldridge/M +Aldrin/M +Aldus/M +Alec/M +Aleichem/M +Alejandra/M +Alejandro/M +Aleksandr/M +Alembert/M +Alena/M +Alene/M +Aleppo/M +Alessandra/M +Alessandro/M +Alethea/M +Aleut/MS +Aleutian/SM +Alex/M +Alexa/M +Alexander/MS +Alexandr/M +Alexandra/M +Alexandre/M +Alexandria/M +Alexandrian +Alexandrina/M +Alexandros +Alexei/M +Alexi/MS +Alexia/M +Alexina/M +Alexis/M +Alf/M +Alfie/M +Alfons/M +Alfonse/M +Alfonso/M +Alfonzo/M +Alford/M +Alfred/M +Alfreda/M +Alfredo/M +Algenib/M +Alger/M +Algeria/M +Algerian/SM +Algernon/M +Algieba/M +Algiers/M +Algol/M +Algonquian/SM +Algonquin/MS +Alhambra/M +Alhena/M +Ali/SM +Alia/M +Alice/M +Alicia/M +Alick/M +Alida/M +Alighieri/M +Alina/M +Aline/M +Alioth/M +Alisa/M +Alisha/M +Alison/M +Alissa/M +Alistair/M +Alister/M +Alix/M +Alkaid/M +Alla/M +Allah/M +Allahabad/M +Allan/M +Allard/M +Alleghenies/M +Allegheny/SM +Allegra/M +Allen/M +Allende/M +Allene/M +Allentown/M +Alleyn/M +Allhallows/M +Allie/MS +Allison/M +Allister/M +Allstate/M +Allyn/M +Allyson/M +Alma/M +Almach/M +Almaty/M +Almeria/M +Almighty/M +Almira/M +Almohad/M +Almoravid/M +Alnilam/M +Alnitak/M +Alon/M +Alonso/M +Alonzo/M +Aloysius/M +Alpert/M +Alphard/M +Alphecca/M +Alpheratz/M +Alphonse/M +Alphonso/M +Alpine/M +Alpo/M +Alps/M +Alric/M +Alsace/M +Alsatian/SM +Alsop/M +Alston/M +Alta/M +Altai/M +Altaic/M +Altair/M +Altamira/M +Althea/M +Altiplano/M +Altman/M +Altoids/M +Alton/M +Aludra/M +Alva/M +Alvan/M +Alvarado/M +Alvarez/M +Alvaro/M +Alvin/M +Alvina/M +Alvis/M +Alvy/M +Alwin/M +Alwyn/M +Alyce/M +Alyosha/M +Alys/M +Alyson/M +Alyss +Alyssa/M +Alzheimer/M +Am/MNR +Amabel/M +Amadeus/M +Amado/M +Amalia/M +Amalie/M +Amanda/M +Amara/M +Amarillo/M +Amaru/M +Amata/M +Amaterasu/M +Amati/M +Amazon/SM +Amazonian +Amber/M +Ambros/M +Ambrose +Ambrosio/M +Ambrosius/M +Ame/M +Amelia/M +Amelie/M +Amen/M +Amenhotep/M +Amerasian/M +America/SM +American/MS +Americana/M +Americanism/MS +Americanization/MS +Americanize/GDS +Amerigo/M +Amerind/SM +Amerindian/MS +Amery/M +Ameslan/M +Amharic/M +Amherst/M +Ami/M +Amie/M +Amiga/M +Amil/M +Amish/M +Amman/M +Amoco/M +Amory/M +Amos/M +Amparo/M +Ampere/M +Amritsar/M +Amsterdam/M +Amtrak/M +Amundsen/M +Amur/M +Amway/M +Amy/M +Ana/M +Anabaptist/M +Anabel/M +Anacin/M +Anacreon/M +Anaheim/M +Analects/M +Analise/M +Ananias/M +Anasazi/M +Anastasia/M +Anatol/M +Anatole/M +Anatolia/M +Anatolian/M +Anaxagoras/M +Anchorage/M +Andalusia/M +Andalusian/M +Andaman/M +Andean/M +Anders/N +Andersen/M +Anderson/M +Andes/M +Andi/M +Andie/M +Andorra/M +Andorran/SM +Andra/MS +Andre/MS +Andrea/SM +Andree/M +Andrei/M +Andrej/M +Andres/M +Andretti/M +Andrew/SM +Andrews/M +Andrey/M +Andria/M +Andrianampoinimerina/M +Android/M +Andromache/M +Andromeda/M +Andropov/M +Andros +Andrus/M +Andy/M +Anet/M +Angara/M +Ange/M +Angel/M +Angela/M +Angele/SM +Angeles/M +Angeli/M +Angelia/M +Angelica/M +Angelico/M +Angelika/M +Angelina/M +Angeline/M +Angelique/M +Angelita/M +Angelo/M +Angelou/M +Angevin/M +Angie/M +Angkor/M +Angle/MS +Anglia/M +Anglican/SM +Anglicanism/MS +Anglicism/MS +Anglicization +Anglicize +Anglo/M +Anglophile/M +Anglophobe +Angola/M +Angolan/MS +Angora/SM +Angstrom/M +Anguilla/M +Angus/M +Ania/M +Aniakchak/M +Anibal/M +Anita/M +Ankara/M +Ann/M +Anna/M +Annabel/M +Annabella/M +Annabelle/M +Annalise/M +Annam/M +Annapolis/M +Annapurna/M +Anne/M +Anneliese/M +Annelise/M +Annemarie/M +Annette/M +Anni/SM +Annie/M +Annmarie/M +Annunciation/SM +Anny/M +Anouilh/M +Ansel/M +Ansell/M +Anselm/M +Anselmo/M +Anshan/M +Ansley/M +Anson/M +Anstice/M +Antaeus/M +Antananarivo/M +Antarctic/M +Antarctica/M +Antares/M +Anthea/M +Anthony/M +Anthropocene +Antichrist/SM +Antietam/M +Antigone/M +Antigua/M +Antillean +Antilles/M +Antin/M +Antioch/M +Antipas/M +Antipodes +Antofagasta/M +Antoine/M +Antoinette/M +Anton/M +Antone/M +Antonella/M +Antoni/M +Antonia/M +Antonie/M +Antonietta/M +Antonin/M +Antonina/M +Antonino/M +Antoninus/M +Antonio/M +Antonius/M +Antony/M +Antwan/M +Antwerp/M +Anubis/M +Any's +Anya/M +Anzac/M +Apache/SM +Apalachicola/M +Apatosaurus +Apennines/M +Aphrodite/M +Apia/M +Apocalypse/M +Apocrypha/M +Apollinaire/M +Apollo/SM +Apollonian/M +Apostle/M +Appalachia/M +Appalachian/SM +Appalachians/M +Appaloosa/SM +Apple/M +Appleseed/M +Appleton/M +Appomattox/M +Apr/M +April/MS +Apuleius/M +Aquafresh/M +Aquarian +Aquarius/MS +Aquila/M +Aquinas/M +Aquino/M +Aquitaine/M +Ar/MY +Ara/M +Arab/SM +Arabella/M +Arabia/M +Arabian/MS +Arabic/M +Arabidopsis +Arabist/MS +Araby/M +Araceli/M +Arafat/M +Aragon +Araguaya/M +Aral/M +Aramaic/M +Aramco/M +Arapaho/MS +Arapahoes +Ararat/M +Araucanian/M +Arawak/M +Arawakan/M +Arbitron/M +Arcadia/M +Arcadian/M +Archambault/M +Archean/M +Archibald/M +Archie/M +Archimedes/M +Archy/M +Arctic/M +Arcturus/M +Arda/M +Ardabil +Arden/M +Ardis/M +Arequipa/M +Ares/M +Aretha/M +Argentina/M +Argentine/M +Argentinean +Argentinian/MS +Argo/SM +Argonaut/MS +Argonne/M +Argos/M +Argus/M +Ari/M +Ariadne/M +Arial/M +Ariana/M +Arianism/M +Arie/SM +Ariel/M +Arielle/M +Aries/MS +Arin/M +Ariosto/M +Aristarchus/M +Aristides/M +Aristophanes/M +Aristotelian/M +Aristotle/M +Arius/M +Ariz +Arizona/M +Arizonan/SM +Arizonian/MS +Arjuna/M +Ark/M +Arkansan/MS +Arkansas/M +Arkhangelsk/M +Arkwright/M +Arlen/M +Arlene/M +Arlette/M +Arley/M +Arlie/M +Arlin/M +Arline/M +Arlington/M +Arly/M +Armageddon/SM +Armagnac/M +Arman/M +Armand/M +Armando/M +Armani/M +Armenia/M +Armenian/SM +Armin/M +Arminius/M +Armonk/M +Armour/M +Armstrong/M +Arnaldo/M +Arne +Arneb/M +Arnhem/M +Arni/M +Arnie/M +Arno/M +Arnold/M +Arnoldo/M +Arnulfo/M +Aron/M +Arrhenius/M +Arron/M +Art/M +Artaxerxes/M +Arte/M +Artemas +Artemis/M +Artemus/M +Arthur/M +Arthurian/M +Artie/M +Artur/M +Arturo/M +Artus/M +Arty's +Aruba/M +Arv/M +Arvin/M +Aryan/MS +As/M +Asa/M +Asama/M +Ascella/M +Ascension/M +Ase/M +Asgard/M +Ashanti/M +Ashby/M +Ashcroft/M +Ashe/RM +Ashgabat +Ashikaga/M +Ashkenazim/M +Ashkhabad/M +Ashlee/M +Ashleigh/M +Ashley/M +Ashmolean/M +Ashton +Ashurbanipal/M +Asia/M +Asiago +Asian/MS +Asiatic/SM +Asimov/M +Asmara/M +Asoka/M +Aspell/M +Aspen/M +Asperger/M +Aspidiske/M +Asquith/M +Assad/M +Assam/M +Assamese/M +Assembly +Assisi/M +Assyria/M +Assyrian/SM +Astaire/M +Astana/M +Astarte/M +Aston/M +Astor/M +Astoria/M +Astra/M +Astrakhan/M +Astrid/M +AstroTurf/M +Asturias/M +Asuncion/M +Asuncin/M +Aswan/M +At/SM +Atacama/M +Atahualpa/M +Atalanta/M +Atari/M +Ataturk/M +Atatrk/M +Athabasca/M +Athabaska +Athabaskan/SM +Athanasius +Athena/M +Athene/M +Athenian/SM +Athens/M +Athlon/M +Atkins/M +Atkinson/M +Atlanta/M +Atlantes +Atlantic/M +Atlantis/M +Atlas/MS +Atman/M +Atonement +Atreus/M +Atria/M +Atropos/M +Attic/M +Attica/M +Attila/M +Attlee/M +Attn +Attucks/M +Atwood/M +Au/M +Aube +Aubert/M +Aubrey/M +Aubry/M +Auckland/M +Auden/M +Audi/M +Audie/M +Audion/M +Audra/M +Audre/M +Audrey/M +Audubon/M +Aug/M +Augean/M +Augie/M +Augsburg/M +August/MS +Augusta/M +Augustan/M +Auguste/M +Augustin/M +Augustine/M +Augustinian/MS +Augusto/M +Augustus/M +Aurangzeb/M +Aurea/M +Aurel/M +Aurelia/M +Aurelie/M +Aurelio/M +Aurelius/M +Aureomycin/M +Auriga/M +Aurora/M +Aurore/M +Auschwitz/M +Aussie/MS +Austen/M +Austerlitz/M +Austin/MS +Australasia/M +Australasian +Australia/M +Australian/SM +Australoid/M +Australopithecus/M +Austria/M +Austrian/SM +Austronesian/M +Autumn/M +Av/M +Ava/M +Avalon/M +Ave/M +Aveline/M +Aventine/M +Averell/M +Averil/M +Averill/M +Avernus/M +Averroes/M +Avery/M +Avesta/M +Avicenna/M +Avigdor/M +Avignon/M +Avila/M +Avior/M +Avis/M +Aviva/M +Avogadro/M +Avon/M +Avram/M +Avril/M +Axe/M +Axel +Axis +Axum/M +Ayala/M +Ayers/M +Aylmer/M +Aymara/M +Aymer/M +Ayn/M +Ayrshire/M +Ayurveda/M +Ayyubid/M +Azana/M +Azania/M +Azazel/M +Azerbaijan/M +Azerbaijani/MS +Azores/M +Azov/M +Aztec/SM +Aztecan/M +Aztlan/M +B/MNRT +BA/M +BASIC/SM +BB/M +BBB/M +BBC/M +BBQ +BBS +BBSes +BC/M +BFF +BIA +BIOS +BITNET +BLT/SM +BM/M +BMW/M +BO +BP/M +BPOE +BR +BS/M +BSA +BSD/SM +BTU +BTW +BYOB +Ba/M +Baal/SM +Baath/M +Baathist/M +Bab/SM +Babb/M +Babbage/M +Babbie/M +Babbitt/M +Babel/MS +Babette/M +Babylon/MS +Babylonia/M +Babylonian/SM +Bacall/M +Bacardi/M +Bacchanalia/M +Bacchic +Bacchus/M +Bach/M +Backus/M +Bacon/M +Bactria/M +Baden/M +Badlands/M +Baedeker/MS +Baez/M +Baffin/M +Baggies/M +Baghdad/M +Baguio/M +Baha'i/M +Baha'ullah/M +Bahama/SM +Bahamanian +Bahamas/M +Bahamian/MS +Bahia/M +Bahrain/M +Baikal/M +Bailey/M +Bailie/M +Baillie/M +Baily/M +Baird/M +Bakelite/M +Baker/M +Bakersfield/M +Baku/M +Bakunin/M +Balanchine/M +Balaton/M +Balboa/M +Bald's +Balder/M +Baldwin/SM +Balearic/M +Balfour/M +Bali/M +Balinese/M +Balkan/MS +Balkans/M +Balkhash/M +Ball/M +Ballard/M +Balthazar/M +Baltic/M +Baltimore/M +Baluchistan/M +Balzac/M +Bamako/M +Bambi/M +Banach/M +Bancorp +Bancroft/M +Bandung/M +Bangalore/M +Bangkok/M +Bangladesh/M +Bangladeshi/SM +Bangor/M +Bangui/M +Banjarmasin/M +Banjul/M +Banks/M +Banneker/M +Bannister/M +Banting/M +Bantu/MS +Baotou/M +Baptist/SM +Baptiste/M +Barabbas/M +Barack/M +Barbadian/SM +Barbados/M +Barbara/M +Barbarella/M +Barbarossa/M +Barbary/M +Barbe/MR +Barbee/M +Barber/M +Barbette/M +Barbey/M +Barbie/M +Barbour/M +Barbra/M +Barbuda/M +Barcelona/M +Barclay/SM +Barclays/M +Barde/M +Bardeen/M +Barents/M +Bari/M +Barker/M +Barkley/M +Barlow/M +Barnabas/M +Barnaby/M +Barnard/M +Barnaul/M +Barnes/M +Barnett/M +Barney/M +Barnum/M +Baroda/M +Barquisimeto/M +Barr/M +Barranquilla/M +Barrera/M +Barret/M +Barrett/M +Barri/MS +Barrie/M +Barron/M +Barry/M +Barrymore/M +Bart/M +Bartel/M +Barth/MS +Barthel/M +Bartholdi/M +Bartholomew/M +Bartlet/M +Bartlett/M +Bartok/M +Bartolomeo/M +Barton/M +Bartram/M +Barty/M +Bartk/M +Baruch/M +Bary/M +Baryshnikov/M +Basel/M +Basho/M +Basia/M +Basic +Basie/M +Basil/M +Basile/M +Basilio/M +Basilius/M +Basque/MS +Basra/M +Bass/M +Basseterre/M +Bastian/M +Bastien/M +Bastille/M +Basutoland/M +Bataan/M +Bates/M +Bathsheba/M +Batista/M +Batman/M +Battle/M +Batu/M +Baudelaire/M +Baudoin/M +Baudouin/M +Baudrillard/M +Bauer/M +Bauhaus/M +Baum/M +Bavaria/M +Bavarian/M +Bax +Baxter/M +Bayamon +Bayard +Bayer/M +Bayes/M +Bayesian/M +Bayeux/M +Baylor/M +Bayonne/M +Bayreuth/M +Baywatch/M +Be/MH +Bea/M +Beach/M +Beadle/M +Beale/M +Bean/M +Beard/M +Beardmore/M +Beardsley/M +Bearnaise/M +Beasley/M +Beatlemania/M +Beatles/M +Beatrice/M +Beatrix/M +Beatriz/M +Beatty/M +Beau/M +Beaufort/M +Beaujolais/M +Beaumarchais/M +Beaumont/M +Beauregard/M +Beauvoir/M +Bebe/M +Becca/M +Bechtel/M +Beck/MR +Becka/M +Becker/M +Becket/M +Beckett/M +Beckham/M +Beckie/M +Becky/M +Becquerel/M +Bede/M +Bedouin/SM +Beebe/M +Beecher/M +Beefaroni/M +Beelzebub/M +Beerbohm/M +Beethoven/M +Beeton/M +Begin/M +Behan/M +Behring/M +Beiderbecke/M +Beijing/M +Beirut/M +Bekesy/M +Bel/M +Bela/M +Belarus/M +Belau/M +Belem/M +Belfast/M +Belg +Belgian/SM +Belgium/M +Belgrade/M +Belinda/M +Belize/M +Belkin/M +Bell/M +Bella/M +Bellamy/M +Bellatrix/M +Belleek/M +Bellevue/M +Bellini/M +Bellow/M +Belmont/M +Belmopan/M +Belorussian/MS +Belshazzar/M +Beltane/M +Beltran/M +Belushi/M +Belva/M +Ben/M +Benacerraf/M +Benares/M +Benchley/M +Bender/M +Bendix/M +Benedetta/M +Benedetto/M +Benedick/M +Benedict/M +Benedicta/M +Benedictine/MS +Benedicto/M +Benedikt/M +Benelux/M +Benet/M +Benetton/M +Bengal/SM +Bengali/M +Benghazi/M +Bengt/M +Benin/M +Beninese/M +Benita/M +Benito/M +Benjamin/M +Benji/M +Benjie/M +Benjy/M +Benn/M +Bennett/M +Bennie/M +Benny/M +Benoit/M +Benson/M +Bentham/M +Bentley/M +Benton/M +Benz/M +Benzedrine/M +Beowulf/M +Ber/MG +Berber/SM +Berenice/M +Beretta/M +Berg/MNR +Bergen/M +Berger/M +Bergerac/M +Bergman/M +Bergson/M +Beria/M +Bering/M +Berk/M +Berke/M +Berkeley/M +Berkley/M +Berkshire/SM +Berkshires/M +Berle/M +Berlin/SZMR +Berliner/M +Berlioz/M +Berlitz/M +Bermuda/SM +Bermudan/SM +Bermudian/SM +Bern/M +Bernadette/M +Bernadine/M +Bernanke/M +Bernard/M +Bernardine +Bernardo/M +Bernays/M +Bernbach/M +Bernese +Bernhard/M +Bernhardt/M +Berni/M +Bernice/M +Bernie/M +Bernini/M +Bernoulli/M +Bernstein/M +Berra/M +Berri/M +Berry/M +Bert/M +Berta/M +Bertelsmann/M +Bertha/M +Berthe/M +Berti/M +Bertie/M +Bertillon/M +Berton/M +Bertram/M +Bertrand/M +Beryl/M +Berzelius/M +Bespin/M +Bess/M +Bessel/M +Bessemer/M +Bessie/M +Bessy/M +Best/M +Betelgeuse/M +Beth/M +Bethany/M +Bethe/M +Bethesda/M +Bethlehem/M +Bethune/M +Betsey/M +Betsy/M +Betta/M +Bette/M +Betti +Bettie/M +Bettina/M +Betty/M +Bettye/M +Beulah/M +Bevan +Beveridge +Beverley/M +Beverly/M +Bevin +Bevvy's +Beyer/M +Bharat/M +Bhopal/M +Bhutan/M +Bhutanese/M +Bhutto/M +Bi/M +Bialystok/M +Bianca/M +Bib +BibSonomy/M +BibTeX/M +Bibby/M +Bibi/M +Bible/MS +Biblical/M +Bic/M +Biddle/M +Biden/M +Bierce/M +Bigfoot/M +Biggles/M +Biko/M +Bil/MY +Bilbao/M +Bilbo/M +Bili/M +Bill/MJ +Billie/M +Billings/M +Billy/M +Bimini/M +Bink/M +Binky/M +Binnie/M +Bioko/M +Bird/M +Birdseye/M +Birgit/M +Birgitta/M +Birk/M +Birkenstock/M +Birmingham/M +Biro/M +Biron/M +Biscay/M +Biscayne/M +Bishkek/M +Bishop/M +Bismarck/M +Bismark/M +Bisquick/M +Bissau/M +BitTorrent/M +BizRate/M +Bizet/M +Bjerknes/M +Bjork/M +Bjorn/M +Bk/M +Black/MS +BlackBerry/M +Blackbeard/M +Blackburn/M +Blackfeet/M +Blackfoot/M +Blackpool/M +Blackshirt/M +Blackstone/M +Blackwell/M +Blaine/M +Blair/M +Blake/M +Blakeley/M +Blanca/M +Blanch's +Blanchard/M +Blanche/M +Blane/M +Blankenship/M +Blantyre/M +Blatz/M +Blavatsky/M +Blenheim/M +Blevins/M +Bligh/M +BlinkList/M +Blithe's +Bloch/M +Blockbuster/M +Bloemfontein/M +Blondel/M +Blondie/M +Bloom/MR +Bloomberg/M +Bloomer/M +Bloomfield/M +Bloomingdale/M +Bloomsbury/M +Blu +Blucher/M +Bluebeard/M +Bluetooth/M +Blvd +Blythe/M +Bo/MRZ +Boadicea +Boas/M +Bob/M +Bobbi/M +Bobbie/M +Bobbitt/M +Bobby/M +Boccaccio/M +Bodhidharma/M +Bodhisattva/M +Bodleian +Boeing/M +Boeotia/M +Boeotian/M +Boer/M +Boethius/M +Bogart/M +Bogota/M +Bogot/M +Bohemia/M +Bohemian/SM +Bohr/M +Boise/M +Bojangles/M +Boleyn/M +Bolivar/M +Bolivia/M +Bolivian/MS +Bollywood/M +Bologna/M +Bolshevik/SM +Bolsheviki +Bolshevism/M +Bolshevist/M +Bolshoi/M +Bolton/M +Boltzmann/M +Bombay/M +Bonaparte/M +Bonaventure/M +Bond/M +Bondy/M +Bonhoeffer/M +Boniface/M +Bonita/M +Bonn/MR +Bonner/M +Bonneville/M +Bonnie/M +Bono/M +Bonsai/M +Booker/M +Boole/M +Boolean/M +Boone/M +Bootes/M +Booth/M +Boothe/M +Bord/MN +Bordeaux/M +Borden/M +Bordon/M +Boreas/M +Borg/SM +Borges/M +Borgia/M +Borglum/M +Boris/M +Bork/M +Borlaug/M +Born/M +Borneo/M +Borobudur/M +Borodin/M +Boru/M +Bosch/M +Bose/M +Bosnia/M +Bosnian +Bosporus/M +Boston/MS +Bostonian/M +Boswell/M +Botox +Botswana/M +Botticelli/M +Boulder/M +Boulez/M +Bourbaki/M +Bourbon/SM +Bourke/M +Bournemouth/M +Bovary/M +Bowditch/M +Bowell/M +Bowen/M +Bowers/M +Bowery/M +Bowie/M +Bowman/M +Boyce/M +Boyd/M +Boyer/M +Boyle/M +Botes/M +Br/MNT +Brad/MNY +Bradbury/M +Braddock/M +Braden/M +Bradford/M +Bradley/M +Bradly/M +Bradshaw/M +Bradstreet/M +Brady/M +Bragg/M +Brahe/M +Brahma/MS +Brahmagupta/M +Brahman/MS +Brahmani +Brahmanism/SM +Brahmaputra/M +Brahms/M +Braille/MS +Brain/M +Bram/M +Brampton/M +Bran/M +Branch/M +Brande/MR +Brandeis/M +Branden/M +Brandenburg/M +Brander/M +Brandi/M +Brandie/M +Brando/M +Brandon/M +Brandt/M +Brandy/M +Brannon/M +Brant/M +Brantley/M +Braque/M +Brasilia/M +Bratislava/M +Brattain/M +Bray/M +Brazil/M +Brazilian/MS +Brazos/M +Brazzaville/M +Breakspear/M +Breathalyzer +Brecht/M +Breckenridge/M +Bree/M +Bremen/M +Bren/M +Brenda/M +Brendan/M +Brenden/M +Brendon/M +Brenna/M +Brennan/M +Brenner/M +Brent/M +Brenton/M +Brest/M +Bret/M +Breton/M +Brett/M +Brewer/M +Brewster/M +Brezhnev/M +Brian/M +Briana/M +Brianna/M +Brianne/M +Briant/M +Brice/M +Bridalveil/M +Bridgeport/M +Bridger/M +Bridges/M +Bridget/M +Bridgetown/M +Bridgett/M +Bridgette/M +Bridgman/M +Bridie/M +Brie/SM +Brien/M +Brigadoon/M +Brigg/MS +Briggs/M +Brigham/M +Bright/M +Brighton/M +Brigid/M +Brigida/M +Brigit/M +Brigitta/M +Brigitte/M +Brillo/M +Brinkley/M +Briny's +Brion/M +Brisbane/M +Bristol/M +Brit/SM +Brita/M +Britain/M +Britannia/M +Britannic/M +Britannica/M +Briticism/SM +British/MRZ +Britisher/M +Britney/M +Briton/MS +Britt/MN +Britta/M +Brittan/M +Brittany/SM +Britten/M +Brittney/M +Brno/M +Broadway/SM +Brobdingnag/M +Brobdingnagian/M +Brock/M +Brod/M +Broderick/M +Brodie/M +Brody/M +Brokaw/M +Bron/M +Bronson/M +Bronte/M +Brontosaurus +Bronx/M +Brooke/MS +Brooklyn/M +Brooks/M +Bros +Brose/M +Brown/MG +Browne/M +Brownian/M +Brownie/S +Browning/M +Brownshirt/M +Brownsville/M +Brubeck/M +Bruce/M +Bruckner/M +Bruegel +Brummel/M +Brunei/M +Bruneian/MS +Brunelleschi/M +Brunhilde/M +Bruno/M +Brunswick/M +Brussels/M +Brut/M +Brutus/M +Bryan/M +Bryant/M +Bryce/M +Bryn/M +Brynn/MR +Brynner/M +Bryon/M +Brzezinski/M +Btu/M +Buber/M +Buchanan/M +Bucharest/M +Buchenwald/M +Buchwald/M +Buck/M +Buckingham/M +Buckley/M +Buckner/M +Bucky/M +Bud/M +Budapest/M +Budd/M +Buddha/SM +Buddhism/SM +Buddhist/SM +Buddy/M +Budweiser/M +Buffalo/M +Buffy/M +Buford/M +Bugatti/M +Bugzilla/M +Buick/M +Bujumbura/M +Bukhara/M +Bukharin/M +Bulawayo/M +Bulfinch/M +Bulganin/M +Bulgar/M +Bulgari/M +Bulgaria/M +Bulgarian/SM +Bullock/M +Bullwinkle/M +Bultmann/M +Bumppo/M +Bunche/M +Bundesbank/M +Bundestag/M +Bunin/M +Bunker/M +Bunsen/M +Bunuel/M +Bunyan/M +Burbank/M +Burberry/M +Burch/M +Burger/M +Burgess/M +Burgoyne/M +Burgundian/M +Burgundy/SM +Burk/SM +Burke/M +Burkina/M +Burks/M +Burl/M +Burlington/M +Burma/M +Burmese/M +Burnaby/M +Burnard/M +Burnett/M +Burns/M +Burnside/M +Burr/M +Burris/M +Burroughs/M +Bursa/M +Burt/M +Burton/M +Burundi/M +Burundian/MS +Busch/M +Bush/M +Bushido/M +Bushnell/M +Butler/M +Butterfingers/M +Buxtehude/M +Buuel/M +Byblos/M +Byers/M +Byram/M +Byrd/M +Byrom/M +Byron/M +Byronic/M +Byzantine/MS +Byzantium/M +C/SMD +CA +CAD/M +CAI +CAM +CAP +CARE +CATV +CB +CBC/M +CBS/M +CCTV +CCU +CD/M +CDC +CDT +CEO/SM +CF +CFC/SM +CFO +CGI +CIA/M +CID +CNN/M +CNS/M +CO/M +COBOL/SM +COD +COL +COLA +CPA/M +CPI/M +CPO +CPR/M +CPU/M +CRT/SM +CST/M +CT/M +CV +CVS/M +CZ +Ca/M +Cabernet/M +Cabot/M +Cabral/M +Cabrera/M +Cabrini/M +Cad/M +Cadette +Cadillac/M +Cadiz/M +Caedmon/M +Caerphilly/M +Caesar/SM +Cage/M +Cagney/M +Cahokia/M +Caiaphas/M +Caicos/M +Cain/SM +Cairo/M +Caitlin/M +Cajun/MS +Cal/MY +Calais/M +Calcutta/M +Calder/M +Calderon/M +Caldwell/M +Cale/M +Caleb/M +Caledonia/M +Calgary/M +Calhoun/M +Cali/M +Caliban/M +Calif +California/M +Californian/SM +Caligula/M +Callaghan/M +Callahan/M +Callao/M +Callas/M +Calley/M +Calli/M +Callie/M +Calliope/M +Callisto/M +Cally/M +Caloocan/M +Calvary/M +Calvert/M +Calvin/M +Calvinism/MS +Calvinist/MS +Calvinistic +Camacho/M +Cambodia/M +Cambodian/SM +Cambrian/SM +Cambridge/M +Cambridgeshire/M +Camden/M +Camel/M +Camelopardalis/M +Camelot/MS +Camembert/MS +Cameron/M +Cameroon/SM +Cameroonian/MS +Cami/M +Camila/M +Camilla/M +Camille/M +Camino/M +Cammie/M +Cammy/M +Camoens/M +Campanella/M +Campbell/M +Campinas/M +Campos/M +Camry/M +Camus/M +Can/M +Canaan/M +Canaanite/MS +Canad +Canada/M +Canadian/SM +Canadianism +Canaletto/M +Canaries/M +Canaveral/M +Canberra/M +Cancer/SM +Cancun/M +Candace/M +Candi/M +Candice/M +Candida/M +Candide/M +Candra/M +Candy/M +Cannes/M +Cannon/M +Canon/M +Canopus/M +Cantabrigian/M +Canterbury/M +Canton/M +Cantonese/M +Cantor/M +Cantrell/M +Cantu/M +Canute/M +Capablanca/M +Capek/M +Capella/M +Capet/M +Capetian/M +Capetown/M +Caph/M +Capistrano/M +Capitol/SM +Capitoline/M +Capone/M +Capote/M +Capra/M +Capri/M +Capricorn/MS +Capt +Capuchin/M +Capulet/M +Cara/M +Caracalla/M +Caracas/M +Caravaggio/M +Carboloy/M +Carboniferous/M +Carborundum/M +Cardenas/M +Cardiff/M +Cardin/M +Cardozo/M +CareerBuilder/M +Caren/M +Carey/M +Cari/M +Caria +Carib/MS +Caribbean/MS +Carin/M +Carina/M +Carine/M +Carissa/M +Carita/M +Carl/GMN +Carla/M +Carlen/M +Carlene/M +Carleton/M +Carley/M +Carlie/M +Carlin/M +Carling/M +Carlisle/M +Carlo/MS +Carlos/M +Carlota +Carlotta/M +Carlsbad/M +Carlson/M +Carlton/M +Carly/M +Carlyle/M +Carmel +Carmela/M +Carmelita/M +Carmella/M +Carmelo/M +Carmen/M +Carmichael/M +Carmina/M +Carmine/M +Carnap/M +Carnation/M +Carnegie/M +Carney/M +Carnot/M +Caro/M +Carol/M +Carola/M +Carolan/M +Carole/M +Carolina/M +Caroline/M +Carolingian/M +Carolinian/M +Carolus/M +Carolyn/M +Carolyne/M +Caron/M +Carpathian/SM +Carpathians/M +Carpenter/M +Carr/M +Carranza/M +Carrie/RM +Carrier/M +Carrillo/M +Carrol/M +Carroll/M +Carson/M +Carter/M +Cartesian/M +Carthage/M +Carthaginian/MS +Cartier/M +Cartwright/M +Caruso/M +Carver/M +Cary/M +Caryl/M +Caryn/M +Casablanca/M +Casals/M +Casandra/M +Casanova/SM +Casar/M +Cascades/M +Case/M +Casey/M +Cash/M +Casi/M +Casio/M +Caspar/M +Casper/M +Caspian/M +Cass/M +Cassandra/SM +Cassatt/M +Cassi/M +Cassidy/M +Cassie/M +Cassini/M +Cassiopeia/M +Cassius/M +Cassy/M +Castaneda/M +Castile/M +Castilian +Castillo/M +Castlereagh/M +Castor/M +Castries/M +Castro/M +Catalan/SM +Catalina/M +Catalonia/M +Catarina/M +Catawba/M +Cate/M +Caterina/M +Caterpillar/M +Catharina/M +Catharine/M +Cathay/M +Cather/M +Catherine/M +Cathie/M +Cathleen/M +Catholic/MS +Catholicism/MS +Cathryn/M +Cathy/M +Cati/M +Catie/M +Catiline/M +Catlin/M +Cato/M +Catrina/M +Catriona/M +Catskill/SM +Catskills/M +Catt/M +Catullus/M +Caucasian/MS +Caucasoid +Caucasus/M +Cauchy/M +Cavendish/M +Cavour/M +Caxton/M +Caye/M +Cayenne/M +Cayman/M +Cayuga/SM +Cayuse +Caz/M +Cb +Cd/M +Ce/M +Ceausescu/M +Cebu/M +Cebuano/M +Cece/M +Cecelia/M +Cecil/M +Cecile/M +Cecilia/M +Cecilio/M +Cecily/M +Ced/M +Cedric/M +Ceil/M +Cele/M +Celebes/M +Celeste/M +Celestia/M +Celestina/M +Celestine/M +Celia/M +Celie/M +Celina/M +Celine/M +Celle/M +Cellini/M +Celsius/M +Celt/SM +Celtic/SM +Cenozoic/M +Centaurus/M +Centigrade +Central +Centro/M +Cepheid/M +Cepheus/M +Cerberus/M +Cerenkov/M +Ceres/M +Cerf/M +Cervantes/M +Cesar/M +Cesare/M +Cesarean/M +Cessna/M +Cetus/M +Ceylon/M +Ceylonese +Cezanne/M +Cf/M +Ch'in/M +Ch/NRS +Chablis/M +Chad/M +Chadian/MS +Chadwick/M +Chagall/M +Chaim/M +Chaitanya/M +Chaitin/M +Chaldea +Chaldean/M +Challenger/M +Chalmers +Chamberlain/M +Chambers/M +Champlain/M +Champollion/M +Chan/M +Chance/M +Chancellorsville/M +Chancey/M +Chanda/M +Chandigarh/M +Chandler/M +Chandon/M +Chandra/M +Chandragupta/M +Chandrasekhar/M +Chane/M +Chanel/M +Chaney/M +Chang/M +Changchun/M +Changsha/M +Channa/M +Chantal/M +Chantilly/M +Chaplin/M +Chaplinesque +Chapman/M +Chappaquiddick/M +Chapultepec/M +Chara +Charbray/M +Chardonnay/M +Charis +Charisse/M +Charity/M +Charlemagne/M +Charlene/M +Charles/M +Charleston/MS +Charley/M +Charlie/M +Charlot/M +Charlotta/M +Charlotte/M +Charlottetown/M +Charlton +Charmaine/M +Charmian/M +Charmin/M +Charolais/M +Charon/M +Chartism/M +Chartres/M +Charybdis/M +Chas +Chase/M +Chasity/M +ChatZilla/M +Chateaubriand/M +Chatham/M +Chattahoochee/M +Chattanooga/M +Chatterley/M +Chatterton/M +Chaucer/M +Chauncey/M +Chautauqua/M +Chavez/M +Chayefsky/M +Che/M +Chechen/M +Chechnya/M +Cheddar/M +Cheer/M +Cheerios/M +Cheetos/M +Cheever/M +Chekhov/M +Chekhovian +Chelsea/M +Chelyabinsk/M +Chen/M +Cheney/M +Chengdu/M +Chennai/M +Cheops/M +Chere/M +Cheri/M +Cherie/M +Cherise/M +Cherish's +Chernenko/M +Chernobyl/M +Chernomyrdin/M +Cherokee/MS +Cherry/M +Cheryl/M +Chesapeake/M +Cheshire/M +Chester/M +Chesterfield/M +Chesterton/M +Chet/M +Chev/M +Chevalier/M +Cheviot/M +Chevrolet/M +Chevron/M +Chevy/M +Cheyenne/SM +Chi/M +Chianti/MS +Chiba/M +Chibcha/M +Chicago/M +Chicagoan/M +Chicana/M +Chicano/M +Chickasaw/MS +Chiclets/M +Chico/M +Chihuahua/MS +Chile/M +Chilean/MS +Chilton/M +Chimborazo/M +Chimera/MS +Chimu/M +Chin/M +China/M +Chinatown/M +Chinese/M +Chinook/MS +Chipewyan/M +Chippendale/M +Chippewa/SM +Chiquita/M +Chirico/M +Chisholm/M +Chisinau/M +Chittagong/M +Chivas/M +Chloe/M +Chloris/M +Choctaw/SM +Choi/M +Chomsky/M +Chongqing/M +Chopin/M +Chopra/M +Chou/M +Chretien/M +Chris/M +Chrissie/M +Chrissy/M +Christ/MS +Christa/M +Christabel/M +Christchurch/M +Christel/M +Christen's +Christendom/MS +Christensen/M +Christi/M +Christian/SM +Christiana/M +Christiane/M +Christianity/SM +Christianize/DG +Christie/M +Christina/M +Christine/M +Christlike +Christmas/MS +Christmastide/MS +Christmastime/MS +Christoper/M +Christoph/MR +Christophe +Christopher/M +Christos/M +Chronicles +Chrysler/M +Chrysostom/M +Chrystal/M +Chuck/M +Chukchi/M +Chumash/M +Chung/M +Church/M +Churchill/M +Churriguera/M +Chuvash/M +Ci/M +Cicely/M +Cicero/M +Cid/M +Ciel/M +Cimabue/M +Cincinnati/M +Cinderella/MS +Cindi/M +Cindy/M +CinemaScope/M +Cinerama/M +Cingular/M +Cipro/M +Circe/M +Cirillo/M +Ciro/M +Cisco/M +Cissy/M +Citibank/M +Citigroup/M +Citroen/M +Cl/MV +Claiborne/M +Clair/M +Claire/M +Clairol/M +Clancy/M +Clapeyron/M +Clapton/M +Clara/M +Clare/M +Clarence/M +Clarendon/M +Clari/M +Claribel/M +Clarice/M +Clarinda/M +Clarissa/M +Clarisse/M +Clarita/M +Clark/M +Clarke/M +Clarkson/M +Clary/M +Claude/M +Claudette/M +Claudia/M +Claudian/M +Claudine/M +Claudio/M +Claudius/M +Claus/M +Clausewitz/M +Clausius/M +Clay/M +Clayborne/M +Clayton/M +Clea/M +Clearasil/M +Clem/XM +Clemence/M +Clemenceau/M +Clemens/M +Clement/MS +Clemente/M +Clementina/M +Clementine/M +Clements/M +Clemmie/M +Clemons/M +Clemson/M +Cleo/M +Cleon +Cleopatra/M +Clerc/M +Cletus/M +Cleve/M +Cleveland/M +Cliburn/M +Cliff/M +Clifford/M +Clifton/M +Cline/M +Clint/M +Clinton/M +Clio/M +Clive/M +Clo/M +Clorets/M +Clorox/M +Closure/M +Clotho/M +Clotilda/M +Clouseau/M +Clovis/M +Clyde/M +Clydesdale/M +Clytemnestra/M +Cm/M +Cmdr +Co/M +Cobain/M +Cobb/M +Cochabamba/M +Cochin/M +Cochise/M +Cochran/M +Cockney/M +Cocteau/M +Cod +Cody/M +Coffey/M +Cognac/M +Cohan/M +Cohen/M +Coimbatore/M +Cointreau/M +Coke/SM +Col/M +Colbert/M +Colby/M +ColdFusion/M +Cole/M +Coleen/M +Coleman/M +Coleridge/M +Colet +Coletta/M +Colette/M +Colfax/M +Colgate/M +Colin/M +Colleen/M +Collen/M +Collette/M +Collier/M +Collin/SM +Colline/M +Collins/M +Colman/M +Colo +Cologne/M +Colombia/M +Colombian/MS +Colombo/M +Colon/M +Coloradan/SM +Colorado/M +Coloradoan +Colosseum/M +Colt/M +Coltrane/M +Columbia/M +Columbine/M +Columbus/M +Com +Comanche/MS +Combs/M +Comcast/M +Comdr +Comintern/M +Commandment +Commons/M +Commonwealth +Communion/SM +Communism +Communist/SM +Como/M +Comoran +Comoros/M +Compaq/M +Composer/M +Compton/M +CompuServe/M +Computerworld/M +Comte/M +Conakry/M +Conan/M +Conant/M +Concepcion/M +Concepcin/M +Concetta/M +Conchita/M +Concord/SM +Concorde/M +Concordia/M +Condillac/M +Condorcet/M +Conestoga/M +Confederacy/M +Confederate/MS +Confucian/SM +Confucianism/MS +Confucius/M +Cong/M +Congo/M +Congolese/M +Congregational +Congregationalist/MS +Congress/MS +Congressional +Congreve/M +Conley/M +Conn/MR +Connecticut/M +Connemara/M +Conner/M +Connery/M +Connie/M +Connolly/M +Connor/SM +Connors/M +Conny/M +Conrad/M +Conrado/M +Conrail/M +Conroy/M +Conservative +Constable/M +Constance/M +Constancia/M +Constanta/M +Constantia +Constantin/M +Constantine/M +Constantino/M +Constantinople/M +Constitution +Consuela/M +Consuelo/M +Continent/M +Continental/M +Contreras/M +Conway/M +Cook/M +Cooke/M +Cooley/M +Coolidge/M +Cooper/M +Cooperstown/M +Coors/M +Copacabana/M +Copeland/M +Copenhagen/M +Copernican/M +Copernicus/M +Copland/M +Copley/M +Copperfield/M +Coppertone/M +Coppola/M +Coptic/M +Cora/M +Coralie/M +Corbet/M +Corbett/M +Corbie/M +Corbin/M +Corby +Cordelia/M +Cordell/M +Cordilleras/M +Cordoba/M +Cordy/M +Coretta/M +Corey/M +Corfu/M +Cori/M +Corina/M +Corine/M +Corinna/M +Corinne/M +Corinth/M +Corinthian/MS +Corinthians/M +Coriolanus/M +Coriolis/M +Cork +Corleone/M +Corliss/M +Cormack/M +Corneille/M +Cornelia/M +Cornelius/M +Cornell/M +Corney/M +Corning/M +Cornish/MS +Cornwall/M +Cornwallis/M +Corny's +Coronado/M +Corot/M +Corp +Correggio/M +Corrie/M +Corrine/M +Corry/M +Corsica/M +Corsican/M +Cort/M +Cortes/MS +Cortland/M +Corvallis/M +Corvette/M +Corvus/M +Cory/M +Cosby/M +Cosette/M +Cosimo/M +Cosme/M +Cosmo/M +Cossack/M +Costa/M +Costanza/M +Costco/M +Costello/M +Costner/M +Cote/M +Cotonou/M +Cotopaxi/M +Cotswold/M +Cotton/M +Coulomb/M +Coulter/M +Councillor/MS +Couperin/M +Courbet/M +Courtenay/M +Courtney/M +Cousteau/M +Coventry/SM +Coward/M +Cowell/M +Cowley/M +Cowper/M +Cox/M +Coy/M +Cozumel/M +Cpl +Cr/MT +Crabbe/M +Craft/M +Craggy's +Craig/M +Craigslist/M +Cranach/M +Crane/M +Cranmer/M +Crater/M +Crawford/M +Cray/M +Crayola/M +Creation/M +Creator/M +Crecy/M +Cree/DSM +Creek/SM +Creighton/M +Creole/SM +Creon/M +Cressida/M +Crest/M +Cretaceous/M +Cretan/SM +Crete/M +Crichton/M +Crick/M +Crimea/M +Crimean/M +Criollo/M +Cris/M +Crisco/M +Crissy/M +Crista/M +Cristal/M +Cristian/M +Cristiano/M +Cristina/M +Cristobal/M +Croat/SM +Croatia/M +Croatian/MS +Croce/M +Crockett/M +Croesus/M +Cromwell/M +Cromwellian/M +Cronin/M +Cronkite/M +Cronus/M +Crookes/M +Crosby/M +Cross/M +Crow/SM +Crowley/M +Crucifixion/MS +Cruikshank/M +Cruise/M +Crusades's +Crusoe/M +Crux/M +Cruz/M +Cryptozoic/M +Crystal/M +Csonka/M +Ct +Ctesiphon/M +Cthulhu/M +Cu/M +Cuba/M +Cuban/SM +Cuchulain/M +Cuisinart/M +Culbertson/M +Cullen/M +Culley/M +Cully/M +Culver/M +Cumberland/M +Cumbria/M +Cummings/M +Cunard/M +Cunningham/M +Cupid/M +Curacao/M +Curcio/M +Curie/M +Curitiba/M +Curr/M +Curran/M +Currey/M +Currie/M +Currier/M +Curry/RM +Curt/M +Curtice/M +Curtis/M +Custer/M +Cuvier/M +Cuzco/M +Cy +Cybele/M +Cybil/M +Cyclades/M +Cyclopes/M +Cyclops/M +Cygnus/M +Cymbeline/M +Cyndi/M +Cynthia/M +Cynthy/M +Cyprian/M +Cypriot/MS +Cyprus/M +Cyrano/M +Cyril/M +Cyrille/M +Cyrillic/M +Cyrus/M +Czech/M +Czechia/M +Czechoslovak +Czechoslovakia/M +Czechoslovakian/SM +Czechs +Czerny/M +D'Arcy +D/M +DA/M +DAR +DAT/M +DBMS/M +DC/M +DD/M +DDS/M +DDT/S +DE +DEA +DEC/SD +DH +DHS +DI +DJ +DMCA +DMD/M +DMZ +DNA/M +DOA +DOB +DOD +DOE +DOS/M +DOT +DP/SM +DPT +DRM +DST +DTP +DUI +DVD/S +DVR/SM +DWI +Dacey/M +Dachau/M +Dacia +Dacron/SM +Dada/M +Dadaism/M +Daedalus/M +Daffy's +Dag's +Dagmar/M +Dagny/M +Daguerre/M +Dagwood/M +Dahomey/M +Daimler/M +Daisy/M +Dakar/M +Dakota/SM +Dakotan/M +Dal/M +Dalai +Dale/M +Daley/M +Dali/M +Dalia/M +Dalian/M +Dalila/M +Dall/M +Dallas/M +Dalmatia/M +Dalmatian/SM +Dalton/M +Damara/M +Damaris/M +Damascus/M +Dame/MN +Damian/M +Damiano/M +Damien/M +Damion/M +Damocles/M +Damon/M +Dan/M +Dana/M +Danae/M +Dana/M +Dane/SM +Danelaw/M +Danette/M +Dangerfield/M +Dani/M +Dania/M +Danial/M +Danica/M +Daniel/SM +Daniela/M +Daniele/M +Daniella/M +Danielle/M +Daniels/M +Danish/M +Danna/M +Danni/M +Dannie/M +Danny/M +Danone/M +Dante/M +Danton/M +Danube/M +Danubian/M +Daphne/M +Dar/MNH +Dara/M +Darby/M +Darcey/M +Darci/M +Darcie/M +Darcy/M +Dardanelles/M +Dare/M +Daren/M +Darfur/M +Dari/M +Daria/M +Darin/M +Dario/M +Darius/M +Darjeeling/M +Darla/M +Darlene/M +Darling/M +Darnell/M +Daron/M +Darrel/M +Darrell/M +Darren/M +Darrin/M +Darrow/M +Darryl/M +Darsie/M +Darth/M +Dartmoor/M +Dartmouth/M +Darvon/M +Darwin/M +Darwinian/M +Darwinism/SM +Darwinist +Darya/M +Daryl/M +Dasha/M +Datamation +Daugherty/M +Daumier/M +Dav/M +Davao/M +Dave/M +Davenport/M +Davey/M +David/MS +Davida/M +Davide/M +Davidson/M +Davie/M +Davies/M +Davin/M +Davina/M +Davis/M +Davy/SM +Dawes/M +Dawkins +Dawn/M +Dawson/M +Day/M +Dayan +Dayna/M +Dayton/M +Daytona/M +De/RSMN +DeGeneres/M +DeKalb/M +Deadhead/M +DealTime/M +Dean/M +Deana/M +Deandre/M +Deane/M +Deann/M +Deanna/M +Deanne/M +Death/M +Deb/SM +Debbi/M +Debbie/M +Debby/M +Debi/M +Debian/M +Debora/M +Deborah/M +Debouillet/M +Debra/M +Debs/M +Debussy/M +Dec/M +Decalogue/M +Decatur/M +Decca/M +Deccan/M +December/SM +Decker/M +Dede/M +Dedekind/M +Dee/M +Deedee/M +Deena/M +Deere/M +Defoe/M +Degas/M +Deidre/M +Deimos/M +Deirdre/M +Deity +Dejesus/M +Del/M +Dela/M +Delacroix/M +Delacruz/M +Delaney/M +Delano/M +Delaware/MS +Delawarean/SM +Delbert/M +Deleon/M +Delgado/M +Delhi/M +Delia/M +Delibes/M +Delicious/M +Delilah/M +Delilahs +Delius/M +Dell/M +Della/M +Delmar/M +Delmarva/M +Delmer/M +Delmonico/M +Delmore/M +Deloitte/M +Delores/M +Deloria/M +Deloris/M +Delphi/M +Delphic/M +Delphine/M +Delphinus/M +Delta/M +Dem/G +Demavend/M +Demerol/M +Demeter/M +Demetri/M +Demetria/M +Demetrius/M +Deming/M +Democrat/SM +Democratic +Democritus/M +Demosthenes/M +Demott/M +Dempsey/M +Dena/M +Denali +Dene +Deneb/M +Denebola/M +Deng/M +Deni/SM +Denis/M +Denise/M +Denmark/M +Denney/M +Dennie/M +Dennis/M +Dennison/M +Denny/M +Denton/M +Denver/M +Deny's +Denys +Deon/M +Depp/M +Der/M +Derby/M +Derek/M +Derick/M +Derk/M +Dermot/M +Derrick/M +Derrida/M +Derry +Descartes/M +Desdemona/M +Deseret/M +Desi/M +Desiree/M +Desmond/M +Detroit/M +Deuteronomy/M +Deutschmark/SM +Dev/M +Deva/M +Devan/M +Devanagari/M +Devi/M +Devil/M +Devin/M +Devlin/M +Devon/M +Devonian/M +Dewar/M +Dewayne/M +Dewey/M +Dewitt/M +Dex/M +Dexedrine/M +Dexter/M +Dhabi +Dhaka/M +Dhaulagiri/M +Di/SM +DiCaprio/M +DiMaggio/M +Diaghilev/M +Dial/M +Dian/M +Diana/M +Diane/M +Diann/M +Dianna/M +Dianne/M +Dias +Diaspora/MS +Dick/XM +Dickens/M +Dickensian +Dickerson/M +Dickie/M +Dickinson/M +Dickson/M +Dicky/M +Dictaphone/SM +Diderot/M +Didi/M +Dido/M +Didrikson/M +Diefenbaker/M +Diego/M +Diem/M +Dierdre/M +Dieter/M +Dietrich/M +Digg/SM +Dijkstra/M +Dijon/M +Dilbert/MS +Dillard/M +Dillinger/M +Dillon/M +Dimitri/M +Dina/M +Dinah/M +Dinny/M +Dino/M +Diocletian/M +Diogenes/M +Dion/M +Dione +Dionisio/M +Dionne/M +Dionysian/M +Dionysus/M +Diophantine/M +Dior/M +Dipper/M +Dir +Dirac/M +Dirichlet/M +Dirk/M +Dis/M +Disney/M +Disneyland/M +Disraeli/M +Dita/M +DivX/M +Divine/M +Diwali/M +Dix/M +Dixie/M +Dixiecrat/M +Dixieland/SM +Dixon/M +Djibouti/M +Dmitri/M +Dnepr +Dnepropetrovsk/M +Dnieper/M +Dniester/M +Dobbin/M +Doberman/M +Dobro/M +Doctor +Doctorow/M +Dodge/M +Dodgson/M +Dodi/M +Dodie/M +Dodoma/M +Dodson/M +Doe/M +Doha/M +Dolby/M +Dole/M +Dolf/M +Dolley/M +Dollie/M +Dolly/M +Dolores/M +Dolph/M +Dom +Domenic/M +Domenico/M +Domesday/M +Domingo/M +Dominguez/M +Domini/M +Dominic/M +Dominica/M +Dominican/MS +Dominick/M +Dominik/M +Dominion +Dominique/M +Domitian/M +Don/SM +Dona/M +Donahue/M +Donal/M +Donald/M +Donaldson/M +Donatello/M +Donetsk/M +Donizetti/M +Donn/MR +Donna/M +Donne/M +Donnell/M +Donner/M +Donnie/M +Donny/M +Donovan/M +Dooley/M +Doolittle/M +Doonesbury/M +Doppler/M +Dora/M +Dorcas/M +Dore/M +Doreen/M +Dorey/M +Dori/SM +Doria/M +Dorian/M +Doric/M +Dorie/M +Doris/M +Dorise/M +Doritos/M +Doro/M +Dorotea/M +Dorothea/M +Dorothee/M +Dorothy/M +Dorrie/M +Dorris +Dorset/M +Dorsey/M +Dorthy/M +Dortmund/M +Dosi/M +Dostoevsky/M +Dot/M +Dotson/M +Dottie/M +Dotty's +Douala/M +Douay/M +Doubleday/M +Doug/M +Dougie/M +Douglas/M +Douglass/M +Douro/M +Dov/MR +Dover/M +Dow/M +Downs/M +Downy/M +Doy/M +Doyle/M +Dr +Draco/M +Draconian/M +Dracula/M +Drake/M +Dramamine/SM +Drambuie/M +Drano/M +Dravidian/M +Dre/M +Dreamweaver/M +Dreiser/M +Dresden/M +Drew/M +Dreyfus/M +Dristan/M +Drona/M +Dropbox/M +Dru/M +Drudge/M +Druid/M +Drusilla/M +Dryden/M +Dschubba/M +Du +DuPont/M +Duane/M +Dubai/M +Dubcek/M +Dubhe/M +Dublin/M +Dubrovnik/M +Duchamp/M +Dudley/M +Duff/M +Duffie/M +Duffy/M +Dugald/M +Duisburg/M +Duke/M +Dulce/M +Dulcie/M +Dulcinea/M +Dulles/M +Duluth/M +Dumas/M +Dumbledore/M +Dumbo/M +Dumpster/M +Dunant/M +Dunbar/M +Duncan/M +Dundee +Dunedin/M +Dunkirk/M +Dunlap/M +Dunn/M +Dunne/M +Dunstan +Dur/R +Duracell/M +Duran/M +Durand/M +Durant/M +Durante/M +Durban/M +Durer/M +Durex/M +Durham/MS +Durkheim/M +Duroc/M +Durocher/M +Durward/M +Duse/M +Dushanbe/M +Dusseldorf/M +Dustbuster/M +Dustin/M +Dusty/M +Dutch/M +Dutchman/M +Dutchmen/M +Dutchwoman +Duvalier/M +Dvina/M +Dvorak/M +Dvork/M +Dwayne/M +Dwight/M +Dy/M +Dyan/M +Dyer/M +Dylan/M +Dyna/M +Dyson/M +Dzerzhinsky/M +Dzungaria/M +Drer/M +Dsseldorf/M +E/SMY +EC +ECG/M +ECMAScript/M +EDP/M +EDT +EEC/M +EEG/M +EEO +EEOC +EFL +EFT +EKG/M +ELF/M +EM +EMT +ENE/M +EOE +EPA/M +ER +ERA +ESE/M +ESL +ESP/M +ESPN/M +ESR +EST/M +ET +ETA +ETD +EU +EULA/S +Eadie/M +Eakins/M +Eal/M +Eamon/M +Earhart/M +Earl/M +Earle/M +Earlene/M +Earline/M +Early's +Earnest/M +Earnestine/M +Earnhardt/M +Earp/M +East/SZMR +Easter/M +Eastern/R +Eastman/M +Easton/M +Eastwood/M +Eaton/M +Eb/MN +Eba/M +Ebba/M +Eben/M +Ebeneezer/M +Ebenezer/M +Eberhard/M +Ebert/M +Ebola/M +Ebonics/M +Ebony/M +Ebro/M +Ecclesiastes/M +Ecma/M +Eco/M +Ecstasy +Ecuador/M +Ecuadoran/SM +Ecuadorean +Ecuadorian/SM +Ed/MNX +Eda/M +Edam/SM +Edd/M +Edda/M +Eddie/M +Eddington/M +Eddy/M +Ede +Eden/M +Edgar/M +Edgard/M +Edgardo/M +Edi/MH +Edie/M +Edin/M +Edinburgh/M +Edison/M +Edith/M +Editha/M +Edlin/M +Edmond/M +Edmonton/M +Edmund/M +Edna/M +Edouard/M +Edsel/M +Eduard/M +Eduardo/M +Edvard/M +Edward/SM +Edwardian/M +Edwardo/M +Edwards/M +Edwin/M +Edwina/M +Edy/M +Edythe/M +Eeyore/M +Effie/M +Efrain/M +Efrem/M +Efren/M +Egan/M +Egbert +Eggo/M +Egon/M +Egor/M +Egypt/M +Egyptian/MS +Egyptology/M +Ehrenberg/M +Ehrlich/M +Eichmann/M +Eiffel/M +Eileen/M +Einstein/MS +Eire/M +Eisenhower/M +Eisenstein/M +Eisner/M +Ekaterina/M +El/Y +Elaina/M +Elaine/M +Elam/M +Elana/M +Elanor/M +Elastoplast/M +Elayne/M +Elba/M +Elbe/M +Elbert/M +Elbrus/M +Elden/M +Eldin/M +Eldon/M +Eldredge/M +Eldridge/M +Eleanor/M +Eleanora/M +Eleanore/M +Eleazar/M +Electra/M +Elena/M +Elene/M +Eleni/M +Eleonora/M +Eleonore/M +Elfreda/M +Elfrida/M +Elgar/M +Eli/M +Elia/S +Elias/M +Elie/M +Elihu/M +Elijah/M +Elinor/M +Eliot/M +Elisa/M +Elisabet/M +Elisabeth/M +Elisabetta/M +Elise/M +Eliseo/M +Elisha/M +Elissa/M +Eliza/M +Elizabeth/M +Elizabethan/SM +Elke/M +Ella/M +Elle/M +Ellen/M +Ellery/M +Ellesmere/M +Elli/SM +Ellie/M +Ellington/M +Elliot/M +Elliott/M +Ellis/M +Ellison/M +Ellsworth/M +Ellwood/M +Elly/M +Ellyn/M +Elma/M +Elmer/M +Elmira/M +Elmo/M +Elmore/M +Elnath/M +Elnora/M +Elohim/M +Eloisa/M +Eloise/M +Eloy/M +Elroy/M +Elsa/M +Elsbeth/M +Else's +Elsevier/M +Elsey/M +Elsie/M +Elsinore/M +Elspeth/M +Elston/M +Eltanin/M +Elton/M +Elul/M +Elva/M +Elvia/M +Elvin/M +Elvira/M +Elvis/M +Elway/M +Elwin/M +Elwood/M +Elwyn/M +Elyse/M +Elysee/M +Elysian/M +Elysium/SM +Elyssa/M +Elyse/M +Ema/M +Emacs/M +Emanuel/M +Emanuele/M +Emeline/M +Emerson/M +Emery/M +Emil/M +Emile/M +Emilia/M +Emilie/M +Emilio/M +Emily/M +Eminem/M +Eminence +Emlen/M +Emlyn/M +Emma/M +Emmaline/M +Emmanuel/M +Emmeline/M +Emmerich/M +Emmet/M +Emmett/M +Emmie/M +Emmy/M +Emory/M +Encarta/M +EndNote/M +Endymion/M +Eng/M +Engelbert/M +Engels/M +England/M +English/MRS +Englishman/M +Englishmen/M +Englishwoman/M +Englishwomen/M +Enid/M +Enif/M +Eniwetok/M +Enkidu/M +Ennis +Enoch/M +Enos/M +Enrica/M +Enrico/M +Enrique/M +Enron/M +Enterprise/M +Eocene/M +Epcot/M +Ephesian/MS +Ephesus/M +Ephraim/M +Ephrem/M +Epictetus/M +Epicurean/M +Epicurus/M +Epimethius/M +Epiphany/SM +Episcopal +Episcopalian/MS +Epistle +Epsom/M +Epson/M +Epstein/M +Equuleus/M +Er/M +Eran/M +Erasmus/M +Erastus/M +Erato/M +Eratosthenes/M +Erda/M +Erebus/M +Erector/M +Erewhon/M +Erhard/M +Eric/M +Erica/M +Erich/M +Erick/M +Ericka/M +Erickson/M +Ericson/M +Ericsson/M +Eridanus/M +Erie/M +Erik/M +Erika/M +Erin/M +Eris/MS +Eritrea/M +Eritrean/SM +Erl/M +Erlenmeyer/M +Erma/M +Erna/M +Ernest/M +Ernestine/M +Ernesto/M +Ernie/M +Ernst/M +Eros/MS +Errol/M +Erroll/M +Erse/M +Erskine +Erv/M +ErvIn/M +Erwin/M +Esau/M +Escher/M +Escherichia/M +Escondido +Esdras +Eskimo/MS +Esme/M +Esmeralda/M +Esperanto/M +Esperanza/M +Espinoza/M +Esq/M +Esquire/MS +Essa/M +Essen/M +Essene/M +Essequibo/M +Essex/M +Essie/M +Esta/M +Establishment +Esteban/M +Estela/M +Estella/M +Estelle/M +Ester/M +Esterhazy/M +Esterhzy/M +Estes/M +Estevan/M +Esther/M +Estonia/M +Estonian/SM +Estrada/M +Estrella/M +Ethan/M +Ethel/M +Ethelbert +Ethelred/M +Ethelyn/M +Ethernet/M +Ethiopia/M +Ethiopian/SM +Etienne/M +Etna/M +Eton/M +Etruria/M +Etruscan/M +Etta/M +Ettie/M +Ettore/M +Etty/M +Eu/M +Eucharist/MS +Eucharistic +Euclid/M +Euclidean/M +Eudora/M +Eugen/M +Eugene/M +Eugenia/M +Eugenie/M +Eugenio/M +Eugenius/M +Eula/M +Eulalie/M +Euler/M +Eumenides/M +Eunice/M +Euphemia/M +Euphrates/M +Eur +Eurasia/M +Eurasian/MS +Euripides/M +Eurodollar/SM +Europa/M +Europe/M +European/MS +Eurydice/M +Eustace/M +Eustachian/M +Eustacia/M +Euterpe/M +Ev/M +Eva/M +Evan/SM +Evangelical +Evangelina/M +Evangeline/M +Evangelist/M +Evans/M +Evansville/M +Eve/M +Evelina/M +Eveline/M +Evelyn/M +Evenki/M +EverReady/M +Everard/M +Everest/M +Everett/M +Everette/M +Everglades/M +Evert/M +Evey/M +Evian/M +Evie/M +Evin/M +Evita/M +Evy/M +Ewan/M +Ewart/M +Ewell/M +Ewen/M +Ewing/M +Excalibur/M +Excedrin/M +Excellency/SM +Exchequer +Exercycle/M +Exocet/M +Exodus/M +Expedia/M +Exxon/M +Eyck/M +Eyre/M +Eysenck/M +Ezekiel/M +Ezequiel/M +Ezra/M +F/MD +FAA +FAQ/SM +FBI/M +FCC +FD +FDA +FDIC/M +FDR/M +FHA/M +FICA/M +FIFO +FL +FM/SM +FNMA/M +FOFL +FORTRAN/M +FPO +FSF/M +FSLIC +FTC +FUD/S +FWD +FWIW +FY +FYI +Faber/M +Faberge/M +Faberg/M +Fabian/MS +Fabien/M +Fabio/M +Facebook/M +Fae/M +Faeroe/M +Fafnir/M +Fagin/M +Fahd/M +Fahrenheit/M +Fairbanks/M +Fairfax +Fairleigh/M +Fairlie/M +Faisal/M +Faisalabad/M +Faith/M +Falasha/M +Falkland/SM +Falklands/M +Falkner +Fallon/M +Fallopian/M +Falstaff/M +Falwell/M +Fania/M +Fannie/M +Fanny/M +Far's +Fara/M +Faraday/M +Farah/M +Fargo/M +Farley/M +Farmer/M +Farr/M +Farragut/M +Farrah/M +Farrakhan/M +Farrand/M +Farrel/M +Farrell/M +Farris/M +Farrow/M +Farsi/M +Fascist +Faso/M +Fassbinder/M +Fatah/M +Fates/M +Father/SM +Fatima/M +Fatimid/M +Faulkner/M +Faulknerian/M +Fauntleroy/M +Faust/M +Faustian/M +Faustina/M +Faustino/M +Faustus/M +Fawkes/M +Fay/M +Faye/M +Fayette/M +Fayre/M +Fe/M +Feb/M +February/SM +Fed/SM +FedEx/M +Federal/MS +Federalist/M +Federico/M +Feds/M +Felecia/M +Felice/M +Felicia/M +Felicity/M +Feliks/M +Felipe/M +Felix/M +Fellini/M +Feng/M +Fenian/M +Fennec/M +Feodor/M +Ferber/M +Ferd/M +Ferdie/M +Ferdinand/M +Ferdy/M +Fergus/M +Ferguson/M +Ferlinghetti/M +Fermat/M +Fermi/M +Fern/M +Fernanda/M +Fernande/M +Fernandez/M +Fernandina/M +Fernando/M +Ferne/M +Ferrari/M +Ferraro/M +Ferrel/M +Ferrell/M +Ferris/M +Fey's +Feynman/M +Fez/M +Fianna +Fiat/M +Fiberglas/M +Fibonacci/M +Fichte/M +Fidel/M +Fidelia/M +Fidelio/M +Fido/M +Fielding/M +Fields/M +Fifi/M +Figaro/M +Figueroa/M +Fiji/M +Fijian/MS +Filip/M +Filipino/MS +Filippo/M +Fillmore/M +FilmSpot/M +Filmer/M +Filofax/M +Fina/M +Finch/M +FindArticles/M +FindLaw/M +Findlay/M +Findley/M +Finland/M +Finlay/M +Finley/M +Finn/SM +Finnbogadottir/M +Finnegan/M +Finnish/M +Fiona/M +Firefox/M +Firestone/M +Fischer/M +Fisher/M +Fisk/M +Fitch/M +Fitz/M +Fitzgerald/M +Fitzpatrick/M +Fitzroy/M +Fizeau/M +Fla +Flanagan/M +Flanders/M +Flathead +Flatt/M +Flaubert/M +Fleischer/M +Flem/G +Fleming/M +Flemish/M +Flemming/M +Fletch/MR +Fletcher/M +Fleur/M +Flickr/M +Flin/M +Flinn/M +Flint/M +Flintstones/M +Flo/M +Flock/M +Flor/M +Flora/M +Flore/SM +Florence/M +Florencia/M +Florentine/M +Flores/M +Florette/M +Florian/M +Florida/M +Floridan/M +Floridian/SM +Florinda/M +Florine/M +Floris +Florrie/M +Florsheim/M +Flory/M +Flossie/M +Flossy's +Flowers/M +Floyd/M +Flynn/M +Fm/M +Foch/M +Fokker/M +Foley/M +Folgers/M +Folsom/M +Fomalhaut/M +Fonda/M +Fons +Foosball/M +Forbes/M +Ford/M +Foreman/M +Forest/MR +Forester/M +Forex/M +Formica/MS +Formosa/M +Formosan/M +Forrest/MR +Forrester/M +Forster/M +Fortaleza/M +Foss/M +Fosse/M +Foster/M +Fotomat/M +Foucault/M +Fourier/M +Fourneyron/M +Fourth +Fowler/M +Fox/MS +Fr/MD +Fragonard/M +Fran/SM +France/SM +Frances/M +Francesca/M +Francesco/M +Francine/M +Francis/M +Francisca/M +Franciscan/MS +Francisco/M +Franck/M +Franco/M +Francois/M +Francoise/M +Francophile +Franglais/M +Frank/SM +Frankel/M +Frankenstein/M +Frankfort/M +Frankfurt/MR +Frankfurter/M +Frankie/M +Frankish +Franklin/M +Franklyn/M +Franks/M +Franky/M +Frannie/M +Franny/M +Fransisco/M +Franz/MN +Franzen/M +Fraser/M +Frasier/M +Frau/MN +Fraulein +Frazer +Frazier/M +Fred/M +Freda/M +Freddie/M +Freddy/M +Frederic/M +Frederica/M +Frederich/M +Frederick/M +Frederico/M +Fredericton/M +Frederik/M +Frederique/M +Fredric/M +Fredrick/M +Fredrika/M +Free's +FreeBSD/M +Freeland/M +Freeman/M +Freemason/SM +Freemasonry/SM +Freetown/M +Freida/M +Fremont/M +French/MS +Frenchman/M +Frenchmen/M +Frenchwoman/M +Frenchwomen/M +Freon/M +Fresnel/M +Fresno/M +Freud/M +Freudian/M +Frey/M +Freya/M +Fri/M +Friday/SM +Frieda/M +Friedan/M +Friederike/M +Friedman/M +Friedrich +Friend/SM +Frigga/M +Frigidaire/M +Frisbee/M +Frisco/M +Frisian/MS +Frito/M +Fritz/M +Frobisher/M +Frodo/M +Froissart/M +Fromm/M +Fronde/M +FrontPage/M +Frontenac/M +Frost/M +Frostbelt/M +Frunze/M +Fry/M +Frye/M +Fuchs/M +Fuentes/M +Fugger/M +Fuji/M +Fujitsu/M +Fujiwara/M +Fujiyama/M +Fukuoka/M +Fukushima/M +Fukuyama/M +Fulani/M +Fulbright/M +Fuller/M +Fullerton/M +Fulton/M +Fulvia/M +Funafuti/M +Fundy/M +Furies/M +Furtwangler/M +Furtwngler/M +Fushun/M +Fuzhou/M +Fuzzbuster/M +G/MNRB +GA +GAO +GATT/M +GB/M +GCC/M +GDP/M +GE/M +GED +GHQ/M +GHz/M +GI +GIF +GIGO +GM/M +GMAT +GMO +GMT/M +GNP/M +GNU/M +GOP/M +GP/M +GPA +GPO +GPS +GPU +GSA +GTE/M +GU +GUI/M +Ga/M +GaAs +Gabby/M +Gabe/M +Gabi/M +Gable/M +Gabon/M +Gabonese/M +Gaborone/M +Gabriel/M +Gabriela/M +Gabriele/M +Gabriella/M +Gabrielle/M +Gaby/M +Gacrux/M +Gadsden/M +Gae/M +Gaea/M +Gael/SM +Gaelic/M +Gagarin/M +Gage/M +Gaia/M +Gail/M +Gaiman/M +Gaines/M +Gainsborough/M +Galahad/SM +Galapagos/M +Galatea/M +Galatia/M +Galatians/M +Galaxy +Galbraith/M +Gale/M +Galen/M +Galibi/M +Galilean/SM +Galilee/M +Galileo/M +Galina/M +Gall/M +Gallagher/M +Gallegos/M +Gallic/M +Gallicism/SM +Gallo/M +Galloway/M +Gallup/M +Galois/M +Galsworthy/M +Galvan/M +Galvani/M +Galveston/M +Galvin/M +Gama +Gamaliel/M +Gamay/M +Gambia/M +Gambian/SM +Gamble/M +GameCube/M +GameFAQs/M +GameSpot/M +Gamow/M +Gan/M +Gandalf/M +Gandhi/M +Gandhian/M +Ganesha/M +Ganges/M +Gangtok/M +Gannon/M +Gantry/M +Ganymede/M +Gap/M +Garbo/M +Garcia/M +Gard +Gardiner +Gardner/M +Gare/MH +Gareth/M +Garey/M +Garfield/M +Garfunkel/M +Gargantua/M +Garibaldi/M +Garland/M +Garner/M +Garrard/M +Garrett/M +Garrick/M +Garrison/M +Garry/M +Garth/M +Garvey/M +Garvin/M +Garwood/M +Gary/M +Garza/M +Gascony/M +Gaspar +Gaspard/M +Gasparo/M +Gasper/M +Gasser/M +Gaston/M +Gastroenterology +Gates/M +Gatling/M +Gatorade/M +Gatsby/M +Gatun/M +Gauguin/M +Gaul/SM +Gaulish +Gauss/M +Gaussian/M +Gautama/M +Gauthier/M +Gautier/M +Gav/MN +Gavan/M +Gaven/M +Gavin/M +Gawain/M +Gay/M +Gaye/M +Gayle/M +Gaylord/M +Gaynor/M +Gaza/M +Gaziantep/M +Gbps +Gd/M +Gdansk/M +Ge/M +Gecko/M +Geffen/M +Gehenna/M +Gehrig/M +Geiger/M +Gelbvieh/M +Geller/M +Gemini/MS +Gen/M +GenBank/M +Gena/M +Genaro/M +Gene/M +Genesis/M +Genet/M +Geneva/M +Genevieve/M +Genevra/M +Genghis/M +Genia/M +Genna/M +Genny/M +Geno/M +Genoa/SM +Gentoo/M +Gentry/M +Geo/M +Geoff/M +Geoffrey/M +Geordie +Georg/M +George/MS +Georgetown/M +Georgette/M +Georgi/M +Georgia/M +Georgian/MS +Georgiana/M +Georgianna/M +Georgie/M +Georgina/M +Georgy/M +Ger/M +Gerald/M +Geraldine/M +Gerard/M +Gerardo/M +Gerber/M +Gerda/M +Gere/M +Gerhard/M +Gerhardt/M +Geri/M +Geritol/M +Germain/M +Germaine/M +German/MS +Germanic/M +Germany/M +Gerome/M +Geronimo/M +Gerrard/M +Gerri/M +Gerry/M +Gershwin/M +Gert/M +Gertie/M +Gertrud/M +Gertrude/M +Gertrudis/M +Gerty/M +Gery/M +Gestapo/SM +Gethsemane/M +Getty/M +Gettysburg/M +Gewurztraminer/M +Gewrztraminer/M +Ghana/M +Ghanaian +Ghats/M +Ghazvanid/M +Ghent/M +Ghibelline/M +Giacometti/M +Giacomo/M +Gian/M +Gianna/M +Gianni/M +Giannini/M +Giauque/M +Gib/M +Gibb/SM +Gibbon/M +Gibbs/M +Gibraltar/MS +Gibson/M +Gide/M +Gideon/M +Gielgud/M +Gienah/M +Giff/M +Giffard/M +Gifford/M +Gigi/M +Gil/MY +Gila/M +Gilbert/M +Gilberte/M +Gilberto/M +Gilchrist/M +Gilda/M +Gilead/M +Giles/M +Gilgamesh/M +Gill/M +Gillan/M +Gilles +Gillespie/M +Gillette/M +Gilliam/M +Gillian/M +Gillie's +Gilligan/M +Gilly/M +Gilman +Gilmore/M +Gina/M +Ginevra/M +Ginger/M +Gingrich/M +Ginnie/M +Ginny/M +Gino/M +Ginsberg/M +Ginsburg/M +Ginsu/M +Giordano/M +Giorgi/M +Giorgio/M +Giorgione/M +Giotto/M +Giovanna/M +Giovanni/M +Giraud +Giraudoux/M +Gisela/M +Gisele/M +Giselle/M +Gish/M +GitHub/M +Giulia/M +Giuliani/M +Giulietta/M +Giulio/M +Giuseppe/M +Giusto/M +Giza/M +Gk +Gladstone/MS +Gladys/M +Glaser/M +Glasgow/M +Glass/M +Glastonbury/M +Glaswegian/SM +Glaxo/M +Gleason/M +Glen/M +Glenda/M +Glendale +Glendon/M +Glenlivet/M +Glenn/M +Glenna/M +Glennie/M +Gloria/M +Gloriana/M +Gloucester/M +Gloucestershire/M +Glover/M +Glyn/M +Glynis/M +Glynn/M +GmbH +Gnostic/M +Gnosticism/M +GnuPG +Goa/M +Gobi/M +God/M +Godard/M +Goddard/M +Godel/M +Godfrey/M +Godhead/M +Godiva/M +Godot/M +Godspeed/SM +Godthaab/M +Godunov/M +Godwin +Godzilla/M +Goebbels/M +Goering/M +Goethals/M +Goethe/M +Goff/M +Gog/M +Gogol/M +Goiania/M +Golan/M +Golconda/M +Golda/M +Goldberg/M +Golden/M +Goldie/M +Goldilocks/M +Golding/M +Goldman/M +Goldsmith/M +Goldwater/M +Goldwyn/M +Goldy/M +Golgi/M +Golgotha/M +Goliath/M +Gomez/M +Gomorrah/M +Gompers/M +Gomulka/M +Gondwanaland/M +Gonzales/M +Gonzalez/M +Gonzalo/M +Good/M +Goodall/M +Goodman/M +Goodrich/M +Goodwill/M +Goodwin/M +Goodyear/M +Google/M +Goolagong/M +Gopher +Goran/M +Gorbachev/M +Gordan/M +Gorden/M +Gordian/M +Gordie/M +Gordimer/M +Gordon/M +Gordy/M +Gore/M +Goren/M +Gorey/M +Gorgas/M +Gorgon/M +Gorgonzola/M +Gorky/M +Gospel/MS +Goteborg/M +Goth/M +Gotham/M +Gothic/MS +Goths +Gottfried/M +Gouda/SM +Gould/M +Gounod/M +Governor +Goya/M +Gr/B +Grable/M +Gracchus/M +Grace/M +Graceland/M +Gracia/M +Gracie/M +Graciela/M +Grady/M +Graeme/M +Graffias/M +Grafton/M +Graham/M +Grahame/M +Grail/M +Grammy/M +Grampians/M +Gran's +Granada/M +Grange/R +Grannie/M +Grant/M +Grantham/M +Grantley/M +Granville/M +Grass/M +Grata/M +Gratia/M +Graves/M +Gray/M +Grazia/M +Grecian/M +Greece/M +Greek/SM +Greeley/M +Green/SM +Greene/M +Greenland/M +Greenlandic +Greenpeace/M +Greensboro/M +Greensleeves/M +Greenspan/M +Greenwich/M +Greer/M +Greg/M +Gregg/M +Gregoire/M +Gregor/M +Gregorian/M +Gregorio/M +Gregorius/M +Gregory/M +Grenada/M +Grenadian/MS +Grenadines/M +Grendel/M +Grenoble/M +Grenville +Gresham/M +Greta/M +Gretchen/M +Grete/M +Gretel/M +Gretna/M +Gretta/M +Gretzky/M +Grey/M +Grieg/M +Grier/M +Griff/M +Griffin/M +Griffith/M +Griffiths +Grimes/M +Grimm/M +Grinch/M +Gris/M +Griselda +Griswold/M +Gromyko/M +Gropius/M +Gross/M +Grosz/M +Grotius/M +Grover/M +Grozny +Grumman/M +Grundy/M +Grunewald/M +Grus/M +Gruyere/SM +Gruyre/M +Grnewald/M +Guadalajara/M +Guadalcanal/M +Guadalquivir/M +Guadalupe/M +Guadeloupe/M +Guallatiri/M +Guam/M +Guamanian +Guangzhou/M +Guantanamo/M +Guarani/M +Guarnieri/M +Guatemala/M +Guatemalan/MS +Guayaquil/M +Gucci/M +Guelph/M +Guenevere/M +Guernsey/MS +Guerra/M +Guerrero/M +Guevara/M +Guggenheim/M +Guglielmo/M +Gui/M +Guiana/M +Guido/M +Guilbert/M +Guildford/M +Guillaume/M +Guillermo/M +Guinea/M +Guinean/MS +Guinevere/M +Guinness/M +Guiyang/M +Guizot/M +Gujarat/M +Gujarati/M +Gujranwala/M +Gullah/M +Gulliver/M +Gumbel/M +Gunilla/M +Gunter +Gunther/M +Guofeng/M +Gupta/M +Gurkha/M +Gus/M +Gussie/M +Gussy's +Gusta/M +Gustaf/M +Gustav/M +Gustave/M +Gustavo/M +Gustavus/M +Gusti/M +Gusty's +Gutenberg/M +Guthrie/M +Gutierrez/M +Guy/M +Guyana/M +Guyanese/M +Guzman/M +Gwalior/M +Gwen/M +Gwendolen/M +Gwendoline/M +Gwendolyn/M +Gwyn/M +Gwyneth/M +Gwynne/M +Gypsy/SM +Gdel/M +Gteborg/M +H/M +HBO/M +HDD +HDMI +HDTV +HF/M +HHS +HI +HIV/M +HM +HMO/M +HMS +HOV +HP/M +HPV +HQ/M +HR +HRH +HS +HSBC/M +HST +HT +HTML/M +HTTP +HTTPS +HUD/M +Ha/M +Haas/M +Habakkuk/M +Haber/M +Had's +Hadar/M +Hades/M +Hadleigh/M +Hadley/M +Hadria/M +Hadrian/M +Hafiz/M +Hagan/M +Hagar/M +Hagen +Haggai/M +Hagiographa/M +Hague/M +Hahn/M +Haida/SM +Haifa/M +Hailey/M +Haiphong/M +Haiti/M +Haitian/MS +Hakeem/M +Hakim/M +Hakka/M +Hakluyt/M +Hal/SMY +Haldane/M +Hale/M +Haleakala/M +Haley/M +Hali/M +Halifax/M +Hall/M +Halley/M +Halliburton/M +Hallie/M +Hallmark/M +Halloween/MS +Hallstatt/M +Hally/M +Halon/M +Hals/M +Halsey/M +Ham/M +Haman/M +Hamas/M +Hamburg/MS +Hamel/M +Hamhung/M +Hamid/M +Hamil/M +Hamilcar/M +Hamill/M +Hamilton/M +Hamiltonian/M +Hamish/M +Hamitic/M +Hamlet/M +Hamlin/M +Hammad/M +Hammarskjold/M +Hammerstein/M +Hammett/M +Hammond/M +Hammurabi/M +Hampshire/M +Hampton/M +Hamsun/M +Han/SM +Hana/M +Hanan/M +Hancock/M +Handel/M +Handy/M +Haney/M +Hangul/M +Hangzhou/M +Hank/M +Hanna/M +Hannah/M +Hanni/M +Hannibal/M +Hanoi/M +Hanover/M +Hanoverian/M +Hans/MN +Hansel/M +Hansen/M +Hanson/M +Hanuka +Hanukah/M +Hanukkah/M +Hanukkahs +Happy's +Hapsburg/M +Harald/M +Harare/M +Harbert/M +Harbin/M +Harcourt/M +Hardin/M +Harding/M +Hardy/M +Hargreaves/M +Harlan/M +Harland/M +Harlem/M +Harlequin/M +Harley/M +Harlin/M +Harlow/M +Harman/M +Harmon/M +Harmonia/M +Harmonie/M +Harold/M +Haroun/M +Harper/M +Harpy/SM +Harrell/M +Harri/SM +Harriet/M +Harriett/M +Harriette/M +Harrington/M +Harriot/M +Harriott/M +Harris/M +Harrisburg/M +Harrison/M +Harrods/M +Harry/M +Hart/M +Harte/M +Hartford/M +Hartley +Hartline/M +Hartman/M +Hartwell/M +Harv/M +Harvard/M +Harvey/M +Harwell/M +Hasbro/M +Hashim/M +Hasidim/M +Haskell/M +Haslett/M +Hassan/M +Hastie/M +Hastings/M +Hasty's +Hatfield/M +Hathaway/M +Hatsheput/M +Hatteras/M +Hatti/M +Hattie/M +Hatty/M +Hauptmann/M +Hausa/M +Hausdorff/M +Havana/MS +Havarti/M +Havel/M +Havoline/M +Haw +Hawaii/M +Hawaiian/SM +Hawking/M +Hawkins/M +Hawks +Hawthorne/M +Hay/SM +Hayden/M +Haydn/M +Haydon/M +Hayek/M +Hayes/M +Hayley/M +Haynes/M +Hays/M +Hayward/M +Haywood/M +Hayworth/M +Hayyim/M +Hazel/M +Hazlett/M +Hazlitt/M +He/M +Head/M +Hearst/M +Heath/MR +Heather/M +Heaviside/M +Heb +Hebe/M +Hebert/M +Hebraic/M +Hebraism/SM +Hebrew/MS +Hebrews/M +Hebrides/M +Hecate/M +Hector/M +Hecuba/M +Hedda/M +Hedi/M +Hedwig/M +Hedy/M +Heep/M +Hefner/M +Hegel/M +Hegelian/M +Hegira/M +Heidegger/M +Heidelberg/M +Heidi/M +Heifetz/M +Heimlich/M +Heine/M +Heineken/M +Heinlein/M +Heinrich/M +Heinz/M +Heisenberg/M +Heisman/M +Hejira's +Helaina/M +Helen/M +Helena/M +Helene/M +Helga/M +Helge/M +Helicon/M +Heliopolis/M +Helios/M +Hellene/SM +Hellenic/M +Hellenism/MS +Hellenist +Hellenistic/M +Hellenization/M +Hellenize/MD +Heller/M +Hellespont/M +Hellman/M +Helmholtz/M +Heloise/M +Helsinki/M +Helvetian +Helvetica +Helvetius/M +Hemingway/M +Hench/M +Henderson/M +Hendrick/MS +Hendricks/M +Hendrik/M +Hendrix/M +Henley/M +Hennessy/M +Henri/M +Henrietta/M +Henriette/M +Henrik/M +Henry/M +Hensley/M +Henson/M +Hepburn/M +Hephaestus/M +Hephzibah/M +Hepplewhite/M +Hera/M +Heracles/M +Heraclitus/M +Herakles/M +Herbart/M +Herbert/M +Herbie/M +Herby/M +Herc/M +Herculaneum/M +Hercule/MS +Herculean +Hercules/M +Herder/M +Hereford/SM +Herero/M +Heriberto/M +Herman/M +Hermann/M +Hermaphroditus/M +Hermes/M +Hermia/M +Hermine/M +Herminia/M +Hermione/M +Hermitage/M +Hermite/M +Hermon +Hermosillo/M +Hernandez/M +Hernando/M +Herod/M +Herodotus/M +Herold/M +Herr/MG +Herrera/M +Herrick/M +Herring/M +Hersch/M +Herschel/M +Hersey/M +Hersh/M +Hershel/M +Hershey/M +Herta/M +Hertfordshire/M +Hertha/M +Hertz/M +Hertzsprung/M +Herve/M +Hervey/M +Herzegovina/M +Herzl/M +Heshvan/M +Hesiod/M +Hesperus/M +Hess/M +Hesse/M +Hessian/M +Hester/M +Hestia/M +Heston/M +Hettie/M +Hetty/M +Hew's +Hewett/M +Hewitt/M +Hewlett/M +Heyerdahl/M +Heywood/M +Hezbollah/M +Hezekiah/M +Hf/M +Hg/M +Hi's +Hialeah/M +Hiawatha/M +Hibernia/M +Hibernian +Hickman/M +Hickok/M +Hicks/M +Hieronymus/M +Higashiosaka +Higgins/M +Highlander/SM +Highlands +Highness/M +Hilario/M +Hilary/M +Hilbert/M +Hilda/M +Hilde/M +Hildebrand/M +Hildegarde/M +Hildy/M +Hilfiger/M +Hill/M +Hillard/M +Hillary/M +Hillel/M +Hillery/M +Hilliard +Hillier/M +Hillsborough/M +Hilly's +Hillyer/M +Hilton/M +Himalaya/SM +Himalayan +Himalayas/M +Himmler/M +Hinayana/M +Hindemith/M +Hindenburg/M +Hindi/M +Hindu/SM +Hinduism/SM +Hindustan/M +Hindustani/SM +Hines/M +Hinton/M +Hinze/M +Hipparchus/M +Hippocrates/M +Hippocratic/M +Hiram/M +Hirobumi/M +Hirohito/M +Hiroshima/M +Hirsch/M +Hispanic/SM +Hispaniola/M +Hiss/M +Hitachi/M +Hitchcock/M +Hitler/MS +Hittite/SM +Hmong/M +Ho/M +Hobart/M +Hobbes/M +Hobbs/M +Hobie/M +Hockney/M +Hodge/SM +Hodges/M +Hodgkin/M +Hoff/M +Hoffa/M +Hoffman/M +Hofstadter/M +Hogan/M +Hogarth/M +Hogwarts/M +Hohenlohe/M +Hohenstaufen/M +Hohenzollern/M +Hohhot/M +Hohokam/M +Hokkaido/M +Hokusai/M +Holbein/M +Holcomb/M +Holden/M +Holder/M +Holiday/M +Holiness +Holland/ZSMR +Hollander/M +Hollerith/M +Holley/M +Hollie/M +Hollis/M +Holloway/M +Holly/M +Hollywood/M +Holman/M +Holmes/M +Holocaust/M +Holocene/M +Holst/M +Holstein/SM +Holt/M +Homer/M +Homeric/M +Hon +Honda/M +Honduran/MS +Honduras/M +Honecker/M +Honeywell/M +Hong +Honiara/M +Honolulu/M +Honorable +Honoria/M +Honshu/M +Hood/M +Hooke/RM +Hooker/M +Hooper/M +Hoosier/MS +Hooters/M +Hoover/MS +Hope/M +Hopewell/M +Hopi/SM +Hopkins/M +Hopper/M +Horace/M +Horacio/M +Horatia/M +Horatio/M +Horatius/M +Hormel/M +Hormuz/M +Horn/M +Hornblower/M +Horne/M +Horowitz/M +Horst/M +Hort/M +Hortense +Hortensia/M +Horthy/M +Horton/M +Horus/M +Hosea/M +Host/SM +Hotmail/M +Hotpoint/M +Hottentot/SM +Houdini/M +Houghton/M +House/M +Housman/M +Houston/M +Houyhnhnm/M +Hovhaness/M +Howard/M +Howe/M +Howell/MS +Howells/M +Howey/M +Howie/M +Howrah +Hoyle/M +Hoyt/M +Hrothgar/M +Hts +Huang/M +Hubbard/M +Hubble/M +Huber/M +Hubert/M +Huck/M +Huddersfield +Hudson/M +Huerta/M +Huey/M +Huff/M +Huffman/M +Huggins/M +Hugh/MS +Hughes/M +Hughie +Hugo/M +Huguenot/MS +Hugues/M +Hui/M +Huitzilopotchli/M +Hulda/M +Hull/M +Humbert/M +Humberto/M +Humboldt/M +Hume/M +Humfrey/M +Hummer/M +Humphrey/SM +Humvee/M +Hun/SM +Hung/M +Hungarian/SM +Hungary/M +Hunspell/M +Hunt/MR +Hunter/M +Huntington/M +Huntley/M +Huntsville/M +Hurley/M +Huron/M +Hurst/M +Hus/M +Husein/M +Hussein/M +Husserl/M +Hussite/M +Huston/M +Hutchinson/M +Hutton/M +Hutu/M +Huxley/M +Huygens/M +Hy/M +Hyacinthe/M +Hyades/M +Hyatt/M +Hyde/M +Hyderabad/M +Hydra/M +Hyman/M +Hymen/M +Hymie +Hyperion/M +Hyundai/M +Hz/M +Hloise/M +I'd +I'll +I'm +I've +I/M +IA +IBM/M +ICBM/SM +ICC +ICU +ID/SM +IDE +IE +IED +IEEE +IKEA/M +IL +IMDb/M +IMDbPro/M +IMF/M +IMHO +IMNSHO +IMO +IN +ING/M +INRI +INS +IOU/M +IP +IPA +IPO/SM +IQ/M +IRA/SM +IRC +IRS/M +ISBN +ISIS +ISO/M +ISP +ISS +IT +IUD +IV/SM +IVF +Ia +Iaccoca/M +Iago/M +Iain/M +Ian/M +Ianthe/M +Iapetus/M +Ibadan/M +Iberia/M +Iberian/M +Ibiza/M +Iblis/M +Ibo/M +Ibrahim/M +Ibsen/M +Icahn/M +Icarus/M +Ice +Iceland/MRZ +Icelander/M +Icelandic/M +Ichabod/M +Ida/M +Idaho/SM +Idahoan/MS +Idahoes +Ieyasu/M +Iggy/M +Ignace/M +Ignacio/M +Ignatius/M +Ignaz/M +Ignazio/M +Igor/M +Iguassu/M +Ijsselmeer/M +Ike/M +Ikey/M +Ikhnaton/M +Ila/M +Ileana/M +Ilene/M +Iliad/SM +Ilka/M +Ill +Illa/M +Illinois/M +Illinoisan/MS +Illuminati/M +Ilsa/M +Ilse/M +Ilyushin/M +Imam +Imelda/M +Imhotep/M +Immanuel +Imodium/M +Imogen/M +Imogene/M +Imus/M +In/MP +Ina/M +Inc +Inca/SM +Inchon/M +Incorporated +Ind +Independence/M +India/M +Indian/MS +Indiana/M +Indianan/SM +Indianapolis/M +Indianian +Indies/M +Indira/M +Indochina/M +Indochinese/M +Indonesia/M +Indonesian/SM +Indore/M +Indra/M +Indus/M +Indy/SM +Ines/M +Inez/M +Inga/M +Inge/RM +Ingeborg/M +Ingemar/M +Inger/M +Inglewood +Inglis/M +Ingmar/M +Ingram/M +Ingres/M +Ingrid/M +Inigo/M +Inna/M +Inness/M +Innis/M +Innocent/M +Innsbruck +Inonu/M +Inquisition/M +Inst +Instagram/M +Instamatic/M +Intel/M +Intelsat/M +Internationale/M +Internet/SM +Interpol/M +Inuit/MS +Inuktitut/M +Invar/M +Io/M +Iona +Ionesco/M +Ionian/MS +Ionic/SM +Iowa/SM +Iowan/MS +Iphigenia/M +Ipswich +Iqaluit/M +Iqbal/M +Iquitos/M +Ir/M +Ira/M +Iran/M +Iranian/SM +Iraq/M +Iraqi/MS +Ireland/M +Irena/M +Irene/M +Irina/M +Iris/M +Irish/MR +Irishman/M +Irishmen/M +Irishwoman/M +Irishwomen/M +Irkutsk/M +Irma/M +Iroquoian/SM +Iroquois/M +Irrawaddy/M +Irtish/M +Irv/MG +Irvin/M +Irvine/M +Irving/M +Irwin/M +Isa +Isaac/M +Isaak/M +Isabel/M +Isabella/M +Isabelle/M +Isadora/M +Isadore/M +Isaiah/M +Isak/M +Iscariot/M +Isfahan/M +Isherwood/M +Ishim/M +Ishmael/M +Ishtar/M +Isiah/M +Isidor/M +Isidora/M +Isidore/M +Isidoro/M +Isidro/M +Isis/M +Islam/MS +Islamabad/M +Islamic/M +Islamism/M +Islamist/M +Islamophobia +Islamophobic +Ismael/M +Ismail/M +Isobel/M +Isolde/M +Ispell/M +Israel/SM +Israeli/SM +Israelite/M +Issac/M +Issachar/M +Issy/M +Istanbul/M +Isuzu/M +It +Itaipu/M +Ital +Italian/SM +Italianate +Italy/M +Itasca/M +Ithaca/M +Ithacan/M +Ito/M +Iva/M +Ivan/M +Ivanhoe/M +Ivar/M +Ive/RSM +Iver/M +Ives/M +Ivie/M +Ivoire +Ivor/M +Ivorian +Ivory/M +Ivy/M +Iyar/M +Izaak/M +Izanagi/M +Izanami/M +Izhevsk/M +Izmir/M +Izod/M +Izvestia/M +Izzy/M +J/MDNX +JCS +JD +JFK/M +JP +JPEG/SM +JV +Jabez/M +Jacinta/M +Jack/M +Jacki/M +Jackie/M +Jacklin/M +Jacklyn/M +Jackson/M +Jacksonian/M +Jacksonville/M +Jacky/M +Jaclyn/M +Jacob/SM +Jacobean/M +Jacobi/M +Jacobin/M +Jacobite/M +Jacobo/M +Jacobs/M +Jacobson/M +Jacquard/M +Jacqueline/M +Jacquelyn/M +Jacques/M +Jacqui/M +Jacquie/M +Jacuzzi/M +Jada/M +Jae/M +Jagger/M +Jagiellon/M +Jaguar/M +Jahangir/M +Jaime/M +Jain/M +Jainism/M +Jaipur/M +Jakarta/M +Jake/M +Jakob/M +Jamaal/M +Jamaica/M +Jamaican/SM +Jamal/M +Jamar/M +Jame/SM +Jamel/M +James/M +Jameson +Jamestown/M +Jamey/M +Jami/M +Jamie/M +Jamil/M +Jamison/M +Jan/M +Jana/M +Janacek/M +Jane/M +Janek/M +Janell/M +Janelle/M +Janet/M +Janette/M +Janey/M +Janice/M +Janie/M +Janina +Janine/M +Janis/M +Janissary/M +Janjaweed/M +Janna/M +Jannie/M +Janos/M +Jansen/M +Jansenist/M +January/SM +Janus/M +Jany/M +Jap/SM +Japan/M +Japanese/MS +Japura/M +Jared/M +Jarlsberg/M +Jarred/M +Jarret/M +Jarrett/M +Jarrod/M +Jarvis/M +Jase/M +Jasmin/M +Jasmine/M +Jason/M +Jasper/M +Jataka/M +Java/SM +JavaScript/M +Javanese/M +Javier/M +Jaxartes/M +Jay/M +Jayapura/M +Jayawardene/M +Jaycee/MS +Jaycees/M +Jaye/M +Jayme/M +Jayne/M +Jayson/M +Jean/M +Jeana/M +Jeane/M +Jeanette/M +Jeanie/M +Jeanine/M +Jeanne/M +Jeannette/M +Jeannie/M +Jeannine/M +Jed/M +Jedediah/M +Jedi/M +Jedidiah/M +Jeep/M +Jeeves/M +Jeff/M +Jefferey/M +Jefferson/M +Jeffersonian/M +Jeffery/M +Jeffrey/M +Jeffry/M +Jehoshaphat/M +Jehovah/M +Jehu +Jekyll/M +Jemima/M +Jemmy/M +Jen/M +Jena/M +Jenifer/M +Jenkins/M +Jenn/MRJ +Jenna/M +Jenner/M +Jenni/M +Jennie/M +Jennifer/M +Jennings/M +Jenny/M +Jeno/M +Jensen/M +Jephthah/M +Jerald/M +Jere/M +Jeremiah/M +Jeremiahs +Jeremias/M +Jeremie/M +Jeremy/M +Jeri/M +Jericho/M +Jermaine/M +Jeroboam/M +Jerold/M +Jerome/M +Jerri/M +Jerrie/M +Jerrod/M +Jerrold/M +Jerry/M +Jersey/MS +Jerusalem/M +Jervis/M +Jess/M +Jessamine/M +Jessamyn/M +Jesse/M +Jessey/M +Jessi/M +Jessica/M +Jessie/M +Jessy/M +Jesuit/MS +Jesus/M +Jethro +Jetway/M +Jew/SM +Jewel/M +Jewell/M +Jewess/MS +Jewish/PM +Jewry/M +Jezebel/SM +Jidda/M +Jilin/M +Jill/M +Jillian/M +Jilly/M +Jim/M +Jimenez/M +Jimmie/M +Jimmy/M +Jinan/M +Jinnah/M +Jinny/M +Jivaro/M +Jo/MY +Joachim +Joan/M +Joana/M +Joane/M +Joanie/M +Joann/M +Joanna/M +Joanne/SM +Joaquin/M +Job/SM +Jobs/M +Joby/M +Jocasta/M +Jocelin/M +Jocelyn/M +Jocelyne/M +Jock/M +Jockey/M +Jocko/M +Jodi/M +Jodie/M +Jody/M +Joe/M +Joel/M +Joelle/M +Joey/M +Jogjakarta/M +Johan/M +Johann/M +Johanna/M +Johannes/M +Johannesburg/M +John/SM +Johnathan/M +Johnathon/M +Johnie/M +Johnnie/M +Johnny/M +Johns/M +Johnson/M +Johnston/M +Jojo/M +Jolene/M +Joli/M +Jolie/M +Joliet/M +Jolson/M +Joly/M +Jon/M +Jonah/M +Jonahs +Jonas/M +Jonathan/M +Jonathon/M +Jone/SM +Jones/M +Joni/M +Jonson/M +Joplin/M +Jordan/M +Jordana/M +Jordanian/MS +Jordon/M +Jorge/M +Jori/M +Jory/M +Joscelin/M +Jose/M +Josef/M +Josefa/M +Josefina/M +Joseph/M +Josepha/M +Josephine/M +Josephs +Josephson/M +Josephus/M +Josey/M +Josh/M +Joshua/M +Josiah/M +Josias/M +Josie/M +Josselyn/M +Josue/M +Joule/M +Jourdain/M +Jourdan/M +Jove/M +Jovian/M +Joy/M +Joya/M +Joyce/M +Joycean/M +Joye/M +Joyner/M +Jozef/M +Jpn +Jr/M +Juan/M +Juana/M +Juanita/M +Juarez/M +Jubal/M +Jud +Judaeo +Judah/M +Judaic +Judaical +Judaism/MS +Judas/MS +Judd/M +Jude/M +Judea/M +Judges +Judi/MH +Judith/M +Judson/M +Judy/M +Juggernaut/M +Jul +Jule/SM +Jules/M +Juli/M +Julia/M +Julian/M +Juliana/M +Juliane/M +Julianna/M +Julianne/M +Julie/M +Julienne's +Juliet/M +Juliette/M +Julio/M +Julius/M +Julliard/M +July/SM +Jun/M +June/SM +Juneau/M +Jung/M +Jungfrau/M +Jungian/M +Junia/M +Junie/M +Junior/SM +Junker/SM +Juno/M +Jupiter/M +Jurassic/M +Jurua/M +Justice/M +Justin/M +Justina/M +Justine/M +Justinian/M +Justus/M +Jutland/M +Juvenal/M +Jyoti/M +K/SMNRGJ +KB/M +KC +KFC/M +KGB/M +KIA +KKK/M +KO/M +KP +KS +KY +Kaaba/M +Kabul/M +Kafka/M +Kafkaesque/M +Kagoshima/M +Kahlil/M +Kahlua/M +Kai/M +Kaia/M +Kaifeng/M +Kaila/M +Kain/M +Kaine/M +Kaiser/MS +Kaitlin/M +Kaitlyn/M +Kaja/M +Kala/M +Kalahari/M +Kalamazoo/M +Kalashnikov/M +Kalb/M +Kalevala/M +Kalgoorlie/M +Kali/M +Kalil/M +Kalina/M +Kalle/M +Kalmyk/M +Kama/M +Kamchatka/M +Kamehameha/M +Kampala/M +Kampuchea/M +Kan/SM +Kanchenjunga/M +Kandahar/M +Kandinsky/M +Kandy +Kane/M +Kania/M +Kannada/M +Kano/M +Kanpur/M +Kansan/MS +Kansas/M +Kant/M +Kantian/M +Kanya/M +Kaohsiung/M +Kaposi/M +Kara/M +Karachi/M +Karaganda/M +Karakorum/M +Karamazov/M +Kare/M +Kareem/M +Karel/M +Karen/M +Karenina/M +Kari/M +Karim/M +Karin/M +Karina/M +Karine/M +Karl/MN +Karla/M +Karlen/M +Karloff/M +Karly/M +Karna/M +Karnataka/M +Karo/MY +Karol/M +Karolina/M +Karoline/M +Karoly/M +Karon/M +Karroo/M +Karyn/M +Kasai/M +Kasey/M +Kashmir/SM +Kaspar/M +Kasparov/M +Kasper/M +Kass +Kassandra/M +Kat/M +Kata/M +Katalin/M +Kate/M +Katelyn/M +Katerina/M +Kath/M +Katha/M +Katharina/M +Katharine/M +Kathe/M +Katherina/M +Katherine/M +Katheryn/M +Kathi/M +Kathiawar/M +Kathie/M +Kathleen/M +Kathmandu/M +Kathrine/M +Kathryn/M +Kathy/M +Kati/M +Katie/M +Katina/M +Katinka/M +Katmai/M +Katmandu/M +Katowice/M +Katrina/M +Katrine +Katrinka/M +Katy/M +Katya/M +Kauai/M +Kaufman/M +Kaunas/M +Kaunda/M +Kawabata/M +Kawasaki/M +Kay/M +Kaycee/M +Kaye/M +Kayla/M +Kaylee/M +Kayne/M +Kazakh/M +Kazakhs +Kazakhstan/M +Kazan/M +Kazantzakis/M +Kb/M +Kean +Keane/M +Kearney/M +Keaton/M +Keats/M +Keck/M +Keefe/RM +Keefer/M +Keeley/M +Keely/M +Keenan/M +Keene/M +Keewatin/M +Keillor/M +Keir/M +Keisha/M +Keith/M +Kellen/M +Keller/M +Kelley/M +Kelli/M +Kellie/M +Kellogg/M +Kelly/M +Kelsey/M +Kelvin/M +Kemerovo/M +Kemp/M +Kempis/M +Ken/M +Kendal/M +Kendall/M +Kendell/M +Kendra/M +Kendrick/MS +Kenmore/M +Kenn/M +Kenna/M +Kennan/M +Kennedy/M +Kenneth/M +Kennett/M +Kennith/M +Kenny/M +Kent/M +Kenton/M +Kentuckian/MS +Kentucky/M +Kenya/M +Kenyan/SM +Kenyatta/M +Kenyon/M +Keogh/M +Keokuk/M +Kepler/M +Ker/M +Kerala/M +Kerby/M +Kerensky/M +Keri/M +Kerk/M +Kermit/M +Kern/M +Kerouac/M +Kerr/M +Kerri/M +Kerrie/M +Kerry/M +Kerstin/M +Kerwin/M +Kettering/M +Kev/MN +Kevan/M +Keven/M +Kevin/M +Kevlar/M +Kevorkian/M +Kewpie/M +Key/M +Keynes/M +Keynesian/M +Khabarovsk/M +Khachaturian/M +Khalid/M +Khalil/M +Khan/M +Kharkov/M +Khartoum/M +Khayyam/M +Khazar/M +Khmer/M +Khoikhoi/M +Khoisan/M +Khomeini/M +Khorana/M +Khrushchev/M +Khufu/M +Khulna/M +Khwarizmi/M +Khyber/M +Ki/M +Kickapoo/M +Kidd/M +Kiel/M +Kierkegaard/M +Kieth/M +Kiev/M +Kigali/M +Kikuyu/M +Kilauea/M +Kile/M +Kiley/M +Kilian/M +Kilimanjaro/M +Killian/M +Kilroy/M +Kim/M +Kimball/M +Kimbell/M +Kimberley/M +Kimberly/M +Kimble/M +Kimmy/M +Kincaid/M +King/M +Kingsley +Kingston/M +Kingstown/M +Kinko/M +Kinney/M +Kinsey/M +Kinshasa/M +Kinsley/M +Kiowa/MS +Kip/M +Kipling/M +Kipp/M +Kira/M +Kirby/M +Kirchhoff/M +Kirchner/M +Kirghistan/M +Kirghiz/M +Kirghizia/M +Kiri/M +Kiribati/M +Kirinyaga/M +Kirk/M +Kirkland/M +Kirkpatrick/M +Kirov/M +Kirsten/M +Kisangani/M +Kishinev/M +Kislev/M +Kissinger/M +Kit/M +Kitakyushu/M +Kitchener/M +Kitts/M +Kitty/M +Kiwanis/M +Klan/M +Klansman/M +Klara/M +Klaus/M +Klee/M +Kleenex/MS +Klein/M +Klemens/M +Klement/M +Klimt/M +Kline/M +Klingon/M +Klondike/MS +Kmart/M +Knapp/M +Knesset/M +Kngwarreye/M +Knickerbocker/M +Knievel/M +Knight/M +Knopf/M +Knossos/M +Knowles/M +Knox/M +Knoxville/M +Knudsen/M +Knuth/M +Knuths +Kobe/M +Koch/M +Kochab/M +Kodachrome/M +Kodak/M +Kodaly/M +Kodiak/M +Koestler/M +Kohinoor/M +Kohl/M +Koizumi/M +Kojak/M +Kolyma/M +Kommunizma/M +Kong/M +Kongo/M +Konrad/M +Konstantin/M +Koo/M +Koontz/M +Koppel/M +Kora/M +Koran/MS +Koranic +Kore/M +Korea/M +Korean/SM +Koren/M +Kori/M +Kornberg/M +Kort/M +Kory/M +Korzybski/M +Kosciusko/M +Kosovo/M +Kossuth/M +Kosygin/M +Koufax/M +Kowloon/M +Kr/M +Kraft/M +Krakatau/M +Krakatoa/M +Krakow/M +Kramer/M +Krasnodar/M +Krasnoyarsk/M +Krebs/M +Kremlin/M +Kremlinologist +Kremlinology +Kresge/M +Kringle/M +Kris/M +Krishna/M +Krishnamurti/M +Krista/M +Kristen/M +Kristi/M +Kristian/M +Kristie/M +Kristin/M +Kristina/M +Kristine/M +Kristopher/M +Kristy/M +Kroc/M +Kroger/M +Kronecker/M +Kropotkin/M +Kruger/M +Krugerrand/M +Krupp/M +Krystal/M +Krystyna/M +Kshatriya/M +Kuala/M +Kublai/M +Kubrick/M +Kuhn/M +Kuibyshev/M +Kulthumm/M +Kunming/M +Kuomintang/M +Kurd/M +Kurdish/M +Kurdistan/M +Kurosawa/M +Kurt/M +Kurtis/M +Kusch/M +Kutuzov/M +Kuwait/M +Kuwaiti/SM +Kuznets/M +Kuznetsk/M +Kwakiutl/M +Kwan/M +Kwangchow/M +Kwangju/M +Kwanzaa/MS +Ky/MH +Kyla/M +Kyle/M +Kylie/M +Kym/M +Kyoto/M +Kyrgyzstan/M +Kyushu/M +L'Amour/M +L'Enfant +L'Oreal/M +L'Ouverture/M +L/MN +LA +LAN/M +LBJ/M +LC +LCD/M +LCM +LDC +LED/M +LG/M +LGBT +LIFO +LL +LLB/M +LLD/M +LNG +LOGO +LP/M +LPG +LPN/SM +LSAT +LSD/M +LVN +La/SM +Lab +Laban/M +Labrador/SM +Labradorean +Labradorian +Lacey/M +Lachesis/M +Lacy/M +Ladoga/M +Ladonna/M +Lady/M +Ladyship/MS +Laetitia/M +Lafayette/M +Lafitte/M +Lagos/M +Lagrange/M +Lagrangian/M +Lahore/M +Lainey/M +Laius/M +Lajos/M +Lakeisha/M +Lakers/M +Lakewood +Lakisha/M +Lakota/M +Lakshmi/M +Lalo/M +Lamaism/SM +Lamar/M +Lamarck/M +Lamaze/M +Lamb/M +Lambert/M +Lamborghini/M +Lambrusco/M +Lamentations +Lamond/M +Lamont/M +Lana/M +Lanai/M +Lancashire/M +Lancaster/M +Lance/M +Lancelot/M +Land/M +Landon/M +Landry/M +Landsat/M +Landsteiner/M +Lane/M +Laney/M +Lang/M +Langerhans/M +Langland/M +Langley/M +Langmuir/M +Langston/M +Lani/M +Lanie/M +Lanka/M +Lankan/M +Lanna/M +Lanny/M +Lansing/M +Lanzhou/M +Lao/SM +Laocoon/M +Laos/M +Laotian/SM +Laplace/M +Lapland/MR +Lapp/SM +Lara/M +Laramie/M +Lardner/M +Laredo/M +Lari/M +Larisa/M +Larissa/M +Larousse/M +Larry/M +Lars/MN +Larsen/M +Larson/M +Lascaux/M +Lassa/M +Lassen/M +Lassie/M +Lat/M +Latasha/M +Lateran/M +Latham/M +Latin/MRS +Latina +Latino/SM +Latisha/M +Latonya/M +Latoya/M +Latrobe/M +Latvia/M +Latvian/MS +Laud/MR +Lauder/M +Laue/M +Laughton +Launce/M +Laundromat/M +Laura/M +Laurasia/M +Laure/M +Laurel/M +Lauren/SM +Laurence/M +Laurent/M +Lauretta/M +Laurette/M +Lauri/M +Laurie/M +Lauryn/M +Laval/M +Lavern/M +Laverne/M +Lavina/M +Lavinia/M +Lavoisier/M +Lavonne/M +Lawanda/M +Lawrence/M +Lawry/M +Lawson/M +Lawton/M +Layamon/M +Layla/M +Layne/M +Layton/M +Lazar/M +Lazare/M +Lazaro/M +Lazarus/M +Le/SM +Lea/M +Leach/M +Leadbelly/M +Leah/M +Leakey/M +Lean/M +Leander/M +Leandra/M +Leann/M +Leanna/M +Leanne/M +Lear/M +Learjet/M +Leary/M +Leavenworth/M +Lebanese/M +Lebanon/M +Lebesgue/M +Leblanc/M +Leda/M +Lederberg/M +Lee/M +Leeds/M +Leela/M +Leena/M +Leese/M +Leeuwenhoek/M +Leeward/M +Left +Legendre/M +Leger/M +Leghorn/M +Lego/M +Legree/M +Lehman/M +Leia/M +Leibniz/M +Leica/M +Leicester/SM +Leiden/M +Leif/M +Leigh/M +Leighton/M +Leila/M +Leipzig/M +Lek/M +Lela/M +Leland/M +Lelia/M +Lem/M +Lemaitre/M +Lemuel/M +Lemuria/M +Len/M +Lena/M +Lenard/M +Lenin/M +Leningrad/M +Leninism/M +Leninist/M +Lennard/M +Lennie/M +Lennon/M +Lenny/M +Leno/M +Lenoir/M +Lenora/M +Lenore/M +Lent/SMN +Lenten/M +Leo/SM +Leola/M +Leon/M +Leona/M +Leonard/M +Leonardo/M +Leoncavallo/M +Leone/M +Leonel/M +Leonhard/M +Leonid/M +Leonidas/M +Leonie/M +Leonor/M +Leonora/M +Leonore/M +Leontine/M +Leopold/M +Leopoldo/M +Leora/M +Lepidus/M +Lepke/M +Lepus/M +Lerner/M +Leroi/M +Leroy/M +Les/M +Lesa/M +Lesley/M +Leslie/M +Lesotho/M +Lesseps/M +Lessie/M +Lester/M +Lestrade/M +Leta/M +Letha/M +Lethe/M +Leticia/M +Letitia/M +Letizia/M +Letterman/M +Lettie/M +Letty/M +Lev +Levant/M +Levesque/M +Levey/M +Levi/SM +Leviathan/M +Levin/M +Levine/M +Leviticus/M +Levitt/M +Levon/M +Levy/M +Lew/M +Lewes +Lewinsky/M +Lewis/M +Lexi/M +Lexie/M +Lexington/M +LexisNexis/M +Lexus/M +Lexy/M +Leyla/M +Lhasa/MS +Lhotse/M +Li/MY +Lia/M +Liam/M +Lian/M +Liana/M +Liane/M +Lianne/M +Libbey/M +Libbie/M +Libby/M +Liberace/M +Liberal +Liberia/M +Liberian/SM +Libra/MS +LibreOffice/M +Libreville/M +Librium/M +Libya/M +Libyan/SM +Lichtenstein/M +Lida/M +Lidia/M +Lie/M +Lieberman/M +Liebfraumilch/M +Liechtenstein/ZMR +Liechtensteiner/M +Lief's +Liege/M +Lieut +Lightning/M +Lil/MY +Lila/M +Lilah/M +Lilia/MS +Lilian/M +Liliana/M +Liliane/M +Lilith/M +Liliuokalani/M +Lilla/M +Lille/M +Lilli/M +Lillian/M +Lillie/M +Lilliput/M +Lilliputian/MS +Lilly/M +Lilongwe/M +Lily/M +Lima/M +Limbaugh/M +Limbo +Limburger/M +Limoges/M +Limousin/M +Limpopo/M +Lin/M +Lina/M +Linc/M +Lincoln/MS +Lincolnshire/M +Lind/M +Linda/M +Lindbergh/M +Lindi/M +Lindon/M +Lindsay/M +Lindsey/M +Lindy/M +Linea/M +LinkedIn/M +Linn/M +Linnaeus/M +Linnea/M +Linnell/M +Linotype/M +Linton/M +Linus/M +Linux/MS +Linwood/M +Lionel/M +Lipizzaner/M +Lippi/M +Lippmann/M +Lipscomb/M +Lipton/M +Lisa/M +Lisbeth/M +Lisbon/M +Lise/M +Lisette/M +Lisle/M +Lissa/M +Lissajous/M +Lissy/M +Lister/M +Listerine/M +Liston/M +Liszt/M +Lita/M +Lithuania/M +Lithuanian/MS +Little/M +Litton/M +Liv/M +LiveJournal/M +Liverpool/M +Liverpudlian/SM +Livia/M +Livingston/M +Livingstone/M +Livonia/M +Livvy/M +Livy/M +Liz/M +Liza/M +Lizabeth/M +Lizbeth/M +Lizette/M +Lizzie/M +Lizzy/M +Ljubljana/M +Llewellyn/M +Lloyd/M +Ln +Loafer/SM +Lobachevsky/M +Lochinvar/M +Locke/M +Lockean/M +Lockheed/M +Lockwood/M +Lodge/M +Lodovico/M +Lodz/M +Loewe/M +Loewi/M +Loews/M +Logan/M +Logitech/M +Lohengrin/M +Loire/M +Lois/M +Loki/M +Lola/M +Lolita/M +Lollard/M +Lollobrigida/M +Lolly's +Lombard/M +Lombardi/M +Lombardy/M +Lome/M +Lon/M +Lona/M +London/MRZ +Londoner/M +Long/M +Longfellow/M +Longstreet/M +Longueuil +Loni/M +Lonnie/M +Lonny/M +LookSmart/M +Lopez/M +Lora/M +Lorain/M +Loraine/M +Lorant/M +Lord/SM +Lordship/SM +Lorelei/M +Loren/M +Lorena/M +Lorene/M +Lorentz/M +Lorenz/M +Lorenza/M +Lorenzo/M +Loretta/M +Lorette/M +Lori/M +Loria/M +Lorie/M +Lorin/M +Lorinda/M +Lorna/M +Lorne/M +Lorraine/M +Lorre/M +Lorrie/M +Lory/M +Los +Lot/M +Lothario/SM +Lott/M +Lotta/M +Lotte/M +Lotti/M +Lottie/M +Lotty/M +Lou/M +Louella/M +Louie/M +Louis/M +Louisa/M +Louise/M +Louisiana/M +Louisianan/MS +Louisianian/MS +Louisville/M +Lourdes/M +Louvre/M +Love/M +Lovecraft/M +Lovelace/M +Lovell +Lowe/M +Lowell/M +Lowenbrau/M +Lowery/M +Lowlands +Loy/M +Loyang/M +Loyd/M +Loyola/M +Lr +Lt +Ltd +Lu/M +Luanda/M +Luann/M +Lubavitcher/M +Lubbock/M +Lubumbashi/M +Luca/SM +Lucas/M +Luce/M +Luci/MN +Lucia/M +Lucian/M +Luciana/M +Luciano/M +Lucie/M +Lucien/M +Lucienne/M +Lucifer/M +Lucile/M +Lucille/M +Lucina +Lucinda/M +Lucio/M +Lucite/SM +Lucius/M +Lucknow/M +Lucky's +Lucretia/M +Lucretius/M +Lucy/M +Luddite/MS +Ludhiana/M +Ludovico/M +Ludvig/M +Ludwig/M +Luella/M +Lufthansa/M +Luftwaffe/M +Luger/M +Lugosi/M +Luigi/M +Luis/M +Luisa/M +Luise/M +Lukas/M +Luke/M +Lula/M +Lully/M +Lulu/M +Lumiere/M +Lumire/M +Luna/M +Lupe/M +Lupercalia/M +Lupus/M +Lura/M +Luria/M +Lusaka/M +Lusitania/M +Luther/M +Lutheran/SM +Lutheranism/MS +Luvs/M +Luxembourg/ZMR +Luxembourger/M +Luxembourgian +Luz/M +Luzon/M +Lvov/M +Ly/MY +LyX/M +Lyallpur +Lycos/M +Lycra/M +Lycurgus/M +Lyda/M +Lydia/M +Lydian/SM +Lydie/M +Lydon/M +Lyell/M +Lyle/M +Lyly/M +Lyman/M +Lyme/M +Lyn/M +Lynch/M +Lynda/M +Lynde/M +Lyndon/M +Lyndsay/M +Lyndsey/M +Lynette/M +Lynn/M +Lynne/M +Lynnette/M +Lyon/SM +Lyons/M +Lyra/M +Lysenko/M +Lysistrata/M +Lysol/M +Lyssa/M +M/SMGB +MA/M +MASH +MB/M +MBA/M +MC +MCI/M +MD/M +MDT +ME +MEGO/S +MFA/M +MGM/M +MHz/M +MI/M +MIA +MIDI/M +MIPS +MIRV +MIT/M +MM +MN +MO +MOOC +MP/M +MPEG/SM +MRI/M +MS/M +MSG/M +MST/M +MSW +MT/M +MTV/M +MVP/M +MW +Maalox/M +Mab +Mabel/M +Mable/M +Mac/M +MacArthur/M +MacBride/M +MacDonald/M +MacLeish/M +Macao/M +Macau/M +Macaulay/M +Macbeth/M +Maccabees +Maccabeus/M +Mace/M +Macedon/M +Macedonia/M +Macedonian/SM +Mach/M +Machiavelli/M +Machiavellian/M +Macias/M +Macintosh/M +Mack/M +Mackenzie/M +Mackinac/M +Mackinaw/M +Macmillan/M +Macon/M +Macromedia/M +Macumba/M +Macy/M +Mada/M +Madagascan/SM +Madagascar/M +Madalyn/M +Madam +Maddalena/M +Madden/M +Maddi/M +Maddie/M +Maddox/M +Maddy/M +Madeira/SM +Madelaine/M +Madeleine/M +Madeline/M +Madelon/M +Madelyn/M +Madge/M +Madison/M +Madonna/SM +Madras/M +Madrid/M +Madurai/M +Mae/M +Maeterlinck/M +Mafia/MS +Mafioso/M +Magda/M +Magdalen +Magdalena/M +Magdalene/M +Magellan/M +Magellanic/M +Maggi/M +Maggie/M +Maggy/M +Maghreb/M +Magi +Maginot/M +Magnitogorsk/M +Magog/M +Magoo/M +Magritte/M +Magsaysay/M +Magus +Magyar/SM +Mahabharata/M +Mahala/M +Mahalia/M +Maharashtra/M +Mahavira/M +Mahayana/M +Mahayanist/M +Mahdi/M +Mahfouz/M +Mahican/SM +Mahler/M +Mahmoud/M +Mahmud/M +Mai/M +Maia/M +Maidenform/M +Maigret/M +Mailer/M +Maillol/M +Maiman/M +Maimonides/M +Maine/MZR +Mainer/M +Mair/M +Maire/M +Maisie/M +Maison/M +Maitreya/M +Maj +Majesty +Major/M +Majorca/M +Majuro/M +Makarios/M +Maker/M +Mal +Mala/M +Malabar/M +Malabo/M +Malacca/M +Malachi/M +Malagasy/M +Malamud/M +Malaprop/M +Malawi/M +Malawian/SM +Malay/MS +Malaya/M +Malayalam/M +Malayan/MS +Malaysia/M +Malaysian/MS +Malcolm/M +Maldive/MS +Maldives/M +Maldivian/MS +Maldonado/M +Male/M +Mali/M +Malia/M +Malian/SM +Malibu/M +Malina/M +Malinda/M +Malinowski/M +Malissa/M +Mallarme/M +Mallarm/M +Mallomars/M +Mallory/M +Malone/M +Malory/M +Malplaquet/M +Malraux/M +Malta/M +Maltese/M +Malthus/M +Malthusian/SM +Malva/M +Malvin/M +Malvina/M +Mame/M +Mameluke/M +Mamet/M +Mamie/M +Mammon/SM +Mamore/M +Man/M +Managua/M +Manama/M +Manasseh/M +Manchester/M +Manchu/SM +Manchuria/M +Manchurian/M +Mancini/M +Mancunian/MS +Manda/M +Mandalay/M +Mandarin/M +Mandel/M +Mandela/M +Mandelbrot/M +Mandi/M +Mandie/M +Mandingo/M +Mandrell/M +Mandy/M +Manet/M +Manfred/M +Manhattan/SM +Mani/M +Manichean/M +Manila/SM +Manitoba/M +Manitoulin/M +Manley/M +Mann/GM +Mannheim/M +Mannie/M +Manning/M +Manny/M +Mano/M +Manolo/M +Manon/M +Mansfield/M +Manson/M +Mantegna/M +Mantle/M +Manuel/M +Manuela/M +Manx/M +Manya/M +Mao/M +Maoism/SM +Maoist/SM +Maori/MS +MapQuest/M +Mapplethorpe/M +Maputo/M +Mar/SMN +Mara/M +Maracaibo/M +Marat/M +Maratha/M +Marathi/M +Marathon/M +Marc/M +Marceau/M +Marcel/M +Marcela/M +Marcelino/M +Marcella/M +Marcelle/M +Marcello/M +Marcellus +Marcelo/M +March/MS +Marci/M +Marcia/M +Marciano/M +Marcie/M +Marco/MS +Marconi/M +Marcos/M +Marcus/M +Marcuse +Marcy/M +Marduk/M +Maren/M +Marga/M +Margalit/M +Margaret/M +Margareta/M +Margarete/M +Margaretha/M +Margarethe/M +Margaretta/M +Margarita/M +Margarito/M +Margaux +Marge/M +Margery/M +Marget/M +Margie/M +Margit/M +Margo/M +Margot/M +Margret/M +Margrethe/M +Marguerite/M +Margy/M +Mari/SM +Maria/M +Mariam/M +Marian/M +Mariana/SM +Marianas/M +Marianna/M +Marianne/M +Mariano/M +Maribel/M +Maribeth/M +Maricela/M +Marie/M +Mariel/M +Marielle/M +Marietta/M +Mariette/M +Marika/M +Marilee/M +Marilyn/M +Marin/M +Marina/M +Marine/SM +Mario/M +Marion/M +Maris/M +Marisa/M +Mariska/M +Marisol/M +Marissa/M +Marita/M +Maritain/M +Maritza/M +Mariupol +Marius/M +Marj/M +Marja/M +Marjorie/M +Marjory/M +Mark/SM +Markab/M +Markham/M +Markos +Markov/M +Marks/M +Markus/M +Marla/M +Marlboro/M +Marlborough/M +Marlee/M +Marleen/M +Marlena/M +Marlene/M +Marley/M +Marlin/M +Marline/M +Marlo/M +Marlon/M +Marlow/M +Marlowe/M +Marmaduke/M +Marmara/M +Marne/M +Marney/M +Marni/M +Marnie/M +Maronite/M +Marple/M +Marquesas/M +Marquette/M +Marquez/M +Marquis/M +Marquita/M +Marrakesh/M +Marriott/M +Marris/M +Mars/MS +Marsala/M +Marseillaise/MS +Marseilles/M +Marsh/M +Marsha/M +Marshall/M +Marta/M +Martel/M +Martha/M +Marthe/M +Marti/M +Martial/M +Martian/SM +Martie/M +Martin/M +Martina/M +Martinez/M +Martinique/M +Martino/M +Marty/M +Martyn/M +Marv/M +Marva/M +Marvell/M +Marvin/M +Marx/M +Marxian +Marxism/SM +Marxist/SM +Mary/M +Marya/M +Maryann/M +Maryanne/M +Marybeth/M +Maryellen/M +Maryland/MR +Marylander/M +Marylin/M +Marylou/M +Marys +Masada/M +Masai/M +Masaryk/M +Mascagni/M +Masefield/M +Maserati/M +Maseru/M +Masha/M +Mashhad/M +Mason/MS +Masonic/M +Masonite/M +Mass/MS +Massachusetts/M +Massasoit/M +Massenet/M +Massey/M +Massimiliano/M +Massimo/M +Master/S +MasterCard/M +Masters/M +Mata/M +Mateo/M +MathML/M +Mathe/MR +Mather/M +Mathew/SM +Mathews/M +Mathewson/M +Mathias/M +Mathilda/M +Mathilde/M +Mathis/M +Matias/M +Matilda/M +Matilde/M +Matisse/M +Matt/M +Mattel/M +Matteo/M +Matterhorn/M +Matthew/SM +Matthews/M +Matthias/M +Matthieu/M +Matti/M +Mattias/M +Mattie/M +Matty/M +Maud/M +Maude/M +Maudie/M +Maugham/M +Maui/M +Maupassant/M +Maura/M +Maureen/M +Mauriac/M +Maurice/M +Mauricio/M +Maurie/M +Maurine/M +Mauritania/M +Mauritanian/SM +Mauritian/SM +Mauritius/M +Maurits/M +Maurizio/M +Mauro/M +Maurois/M +Maury +Mauryan/M +Mauser/M +Mavis/M +Max/M +Maxie/M +Maximilian/M +Maximilien/M +Maximo/M +Maxine/M +Maxwell/M +May/SMR +Maya/SM +Mayan/MS +Maybelle/M +Maye/M +Mayer/M +Mayfair/M +Mayflower/M +Maynard/M +Mayne/M +Mayo/M +Maypole +Mayra/M +Mays/M +Maytag/M +Mazama/M +Mazarin/M +Mazatlan/M +Mazda/M +Mazola/M +Mazzini/M +Mb/M +Mbabane/M +Mbini/M +Mbps +McAdam/M +McAfee/M +McBride/M +McCain/M +McCall/M +McCann/M +McCarthy/M +McCarthyism/M +McCartney/M +McCarty/M +McClain/M +McClellan/M +McClure/M +McConnell/M +McCormick/M +McCoy/M +McCray/M +McCullough/M +McDaniel/M +McDonald/M +McDonnell/M +McDowell/M +McEnroe/M +McFadden/M +McFarland/M +McGee/M +McGovern/M +McGowan/M +McGuffey/M +McGuire/M +McIntosh/M +McIntyre/M +McKay/M +McKee/M +McKenzie/M +McKinley/M +McKinney/M +McKnight/M +McLaughlin/M +McLean/M +McLeod/M +McLuhan/M +McMahon/M +McMillan/M +McNamara/M +McNaughton/M +McNeil/M +McPherson/M +McQueen/M +McVeigh/M +Md/M +Me +Mead/M +Meade/M +Meadows/M +Meagan/M +Meaghan/M +Meany/M +Meara/M +Mecca/MS +Medan/M +Medea/M +Medellin/M +Media/M +Medicaid/SM +Medicare/SM +Medici/M +Medina/M +Mediterranean/MS +Medline/M +Medusa/M +Meg/M +Megan/M +Meggie/M +Meghan/M +Mei/MR +Meier/M +Meighen/M +Meiji/M +Meir/M +Mejia/M +Mekong/M +Mel/MY +Mela/M +Melanesia/M +Melanesian/M +Melania/M +Melanie/M +Melba/M +Melbourne/M +Melchior/M +Melchizedek/M +Melendez/M +Melicent/M +Melina/M +Melinda/M +Melisa/M +Melisande/M +Melissa/M +Melita/M +Mella/M +Melli/M +Mellie/M +Mellon/M +Melly/M +Melodie/M +Melody/M +Melony/M +Melpomene/M +Melton/M +Melva/M +Melville/M +Melvin/M +Melvyn/M +Memling/M +Memphis/M +Menander/M +Menard/M +Mencius/M +Mencken/M +Mendel/M +Mendeleev/M +Mendelian/M +Mendelssohn/M +Mendez/M +Mendocino/M +Mendoza/M +Menelaus/M +Menelik/M +Menes/M +Mengzi +Menkalinan/M +Menkar/M +Menkent/M +Mennen/M +Mennonite/MS +Menominee/M +Menotti/M +Mensa/M +Mentholatum/M +Menuhin/M +Menzies/M +Mephisto +Mephistopheles/M +Merak/M +Mercado/M +Mercator/M +Mercedes/M +Mercer/M +Merci/M +Mercia/M +Merck/M +Mercurochrome/M +Mercury/SM +Meredith/M +Meriel/M +Merino/M +Merl/M +Merle/M +Merlin/M +Merlot/M +Merovingian/M +Merriam/M +Merrick/M +Merrie/M +Merrill/M +Merrily's +Merrimack/M +Merritt/M +Merry's +Mersey +Merthiolate/M +Merton/M +Merv/M +Mervin/M +Merwin/M +Merwyn/M +Meryl/M +Mesa/M +Mesabi/M +Meshed/M +Mesmer/M +Mesolithic/M +Mesopotamia/M +Mesopotamian +Mesozoic/M +Messerschmidt/M +Messiaen/M +Messiah/M +Messiahs +Messianic +Messieurs +Metacafe/M +Metallica/M +Metamucil/M +Methodism/SM +Methodist/SM +Methuselah/M +Metternich/M +Meuse/M +Mex +Mexicali/M +Mexican/MS +Mexico/M +Meyer/MS +Meyerbeer/M +Meyers/M +Mfume/M +Mg/M +Mgr +MiG/M +Mia/M +Miami/MS +Miaplacidus/M +Micaela/M +Micah/M +Micawber/M +Mich/M +Michael/M +Michaela/M +Michaelmas/MS +Michail/M +Michal/M +Micheal/M +Michel/M +Michelangelo/M +Michele/M +Michelin/M +Micheline/M +Michell/M +Michelle/M +Michelob/M +Michelson/M +Michigan/M +Michigander/MS +Michiganite +Mick/M +Mickey/M +Micki/M +Mickie/M +Micky/M +Micmac/SM +Micronesia/M +Micronesian/M +Microsoft/M +Midas/M +Middleton/M +Mideast +Mideastern +Midland/MS +Midway/M +Midwest/M +Midwestern/MR +Mignon/M +Miguel/M +Mikael/M +Mike/M +Mikel/M +Mikey/M +Mikhail/M +Mikkel/M +Mikoyan/M +Milagros/M +Milan/M +Milanese +Mildred/M +Milena/M +Miles/M +Milford/M +Milken/M +Mill/SMR +Millard/M +Millay/M +Miller/M +Millet/M +Milli/M +Millicent/M +Millie/M +Millikan/M +Mills/M +Milly/M +Milne/M +Milo/M +Milosevic/M +Milquetoast/M +Miltiades/M +Milton/M +Miltonic/M +Miltown/M +Milwaukee/M +Mimi/M +Mimosa/M +Min/M +Mina/M +Minamoto/M +Minda/M +Mindanao/M +Mindoro/M +Mindy/M +Minerva/M +Minette/M +Ming/M +Mingus/M +Minn +Minna +Minne/M +Minneapolis/M +Minnelli/M +Minnesota/M +Minnesotan/SM +Minnie/M +Minny/M +Minoan/MS +Minolta/M +Minos/M +Minot/M +Minotaur/M +Minsk/M +Minsky/M +Minta/M +Mintaka/M +Minuit/M +Minuteman/M +Miocene/M +Mir/M +Mira/M +Mirabeau/M +Mirabel/M +Mirabella/M +Mirabelle/M +Mirach/M +Miran/M +Miranda/M +Mireille/M +Mirella/M +Mirfak/M +Miriam/M +Mirna/M +Miro/M +Mirzam/M +Mischa/M +Misha/M +Miskito/M +Miss +Missie/M +Mississauga/M +Mississippi/M +Mississippian/SM +Missouri/M +Missourian/MS +Missy/M +Mistassini/M +Mister +Mistress +Misty/M +Mitch/M +Mitchel/M +Mitchell/M +Mitford/M +Mithra/M +Mithridates/M +Mitsubishi/M +Mitterrand/M +Mitty/M +Mitzi/M +Mixtec/M +Mizar/M +Mk +Mlle +Mme/S +Mn/M +Mnemosyne/M +Mo/M +Mobil/M +Mobile/M +Mobutu/M +Modesto/M +Modigliani/M +Moe/M +Moet/M +Mogadishu/M +Mogul/MS +Mohacs/M +Mohamed/M +Mohammad/M +Mohammedan/SM +Mohammedanism/SM +Mohandas/M +Mohave/SM +Mohawk/SM +Mohegan +Moho/M +Mohorovicic/M +Moira/M +Moise/MS +Moises/M +Moiseyev/M +Moishe/M +Mojave/SM +Moldavia/M +Moldavian +Moldova/M +Moldovan +Moliere/M +Molina/M +Moll/M +Mollie/M +Molly/M +Molnar/M +Moloch/M +Molokai/M +Molotov/M +Moluccas/M +Mombasa/M +Mon/SM +Mona/M +Monacan +Monaco/M +Mondale/M +Monday/SM +Mondrian/M +Monegasque/SM +Monera/M +Monet/M +Mongol/SM +Mongolia/M +Mongolian/SM +Mongolic/M +Mongoloid +Monica/M +Monika/M +Monique/M +Monk/M +Monmouth/M +Monongahela/M +Monro/M +Monroe/M +Monrovia/M +Monsanto/M +Monsieur/M +Monsignor/SM +Mont/M +Montague/M +Montaigne/M +Montana/M +Montanan/SM +Montcalm/M +Monte/M +Montenegrin/M +Montenegro/M +Monterrey/M +Montesquieu/M +Montessori/M +Monteverdi/M +Montevideo/M +Montezuma/M +Montgolfier/M +Montgomery/M +Monti/M +Monticello/M +Montoya/M +Montpelier/M +Montrachet/M +Montreal/M +Montserrat/M +Monty/M +Moody/M +Moog/M +Moon/M +Mooney/M +Moor/SM +Moore/M +Moorish/M +Mora/M +Morales/M +Moran/M +Moravia/M +Moravian/M +Mord/M +Mordecai +Mordred/M +More/M +Morena/M +Moreno/M +Morey/M +Morgan/SM +Morgana/M +Morgen/M +Moria/M +Moriarty/M +Morin/M +Morison/M +Morita/M +Moritz/M +Morley/M +Mormon/SM +Mormonism/SM +Morna/M +Moro/M +Moroccan/SM +Morocco/M +Moroni/M +Morpheus/M +Morphy/M +Morrie/M +Morris/M +Morrison/M +Morrow/M +Morse/M +Mort/MN +Morten/M +Mortimer/M +Morton/M +Morty/M +Mosaic/M +Moscow/M +Mose/SM +Moseley/M +Moselle/M +Moses/M +Moshe/M +Moslem/M +Mosley/M +Moss/M +Mosul/M +Motorola/M +Motown/M +Motrin/M +Mott/M +Moulton/M +Mount/M +Mountbatten/M +Mountie/MS +Moussorgsky/M +Mouthe/M +Mouton/M +Mowgli/M +Moyra/M +Mozambican/SM +Mozambique/M +Mozart/M +Mozilla/M +Mozillian/MS +Mr/SM +Ms/S +Msgr +Mt +Muawiya/M +Mubarak/M +Mueller/M +Muenster/MS +Mugabe/M +Muhammad/M +Muhammadan/MS +Muhammadanism/SM +Muir/M +Mujib/M +Mulder/M +Mullen/M +Muller/M +Mulligan/M +Mullikan/M +Mullins/M +Mulroney/M +Multan/M +Multics +Mumbai/M +Mumford/M +Munch/M +Munchhausen/M +Munich/M +Munoz/M +Munro/M +Munroe/M +Munster/M +Muppet/M +Murasaki/M +Murat/M +Murchison/M +Murcia +Murdoch/M +Murdock/M +Muriel/M +Murillo/M +Murine/M +Murmansk/M +Murphy/M +Murray/M +Murrow/M +Murrumbidgee/M +Murry/M +Muscat/M +Muscovite/M +Muscovy/M +Muse/M +Musharraf/M +Musial/M +Muskogee/M +Muslim/MS +Mussolini/M +Mussorgsky/M +Mutsuhito/M +Muzak/M +My's +MySQL/M +MySpace/M +MySpell/M +Myanmar/M +Mycenae/M +Mycenaean/M +Myer/SM +Myers/M +Mylar/MS +Myles/M +Myra/M +Myrdal/M +Myriam/M +Myrna/M +Myron/M +Myrtle/M +Mysore/M +Myst/M +Mnchhausen/M +N'Djamena +N/MD +NAACP/M +NAFTA/M +NASA/M +NASCAR/M +NASDAQ/M +NATO/M +NB +NBA/M +NBC/M +NBS +NC +NCAA/M +NCO +ND +NE/M +NEH +NF +NFC +NFL/M +NGO/SM +NH +NHL/M +NIH +NIMBY +NJ +NLRB +NM +NORAD/M +NOW +NP +NPR/M +NR +NRA +NRC +NS +NSA/M +NSC +NSF +NSFW +NSPR/M +NSS/M +NT +NV +NW/M +NWT +NY +NYC +NYSE +NZ +Na/M +Nabisco/M +Nabokov/M +Nada/M +Nader/M +Nadia/M +Nadine/M +Nadu/M +Nadya/M +Nagasaki/M +Nagoya/M +Nagpur/M +Nagy/M +Nahuatl/MS +Nahum/M +Naipaul/M +Nair/M +Nairobi/M +Naismith/M +Nam/M +Namath/M +Namibia/M +Namibian/MS +Nan/M +Nana/M +Nanak/M +Nance/M +Nanchang/M +Nanci/M +Nancy/M +Nanette/M +Nani/M +Nanjing/M +Nanni/M +Nannie/M +Nanon/M +Nanook/M +Nansen/M +Nantes/M +Nantucket/M +Naomi/M +Napa/M +Naphtali/M +Napier/M +Naples/M +Napoleon/MS +Napoleonic/M +Napster/M +Nara +Narcissus/M +Nari/M +Narmada/M +Narnia/M +Narraganset +Narragansett/M +Naruto/M +Nash/M +Nashua/M +Nashville/M +Nassau/M +Nasser/M +Nat/M +Nata/M +Natal's +Natale/M +Natalia/M +Natalie/M +Natalya/M +Natasha/M +Natchez/M +Nate/MN +Nathalie/M +Nathan/SM +Nathanael +Nathanial/M +Nathaniel/M +Nathans/M +Nation/M +Nationwide/M +Natividad/M +Nativity/M +Natty's +Nature +Naugahyde/M +Nauru/M +Nautilus/M +Navajo/SM +Navajoes +Navarre/M +Navarro/M +Navratilova/M +Navy +Nazarene/M +Nazareth/M +Nazca/M +Nazi/SM +Nazism/MS +Nb/M +Nd/M +Ndjamena/M +Ne/M +NeWS +NeWSes +Neal/M +Neale/M +Nealy/M +Neanderthal/SM +Neapolitan/M +Neb +Nebr +Nebraska/M +Nebraskan/MS +Nebuchadnezzar/M +Necko/M +Ned/M +Neda/M +Nedda/M +Neddy/M +Neel/M +Neely/M +Nefertiti/M +Negev/M +Negress/MS +Negritude +Negro/MS +Negroes +Negroid/SM +Negros/M +Nehemiah/M +Nehru/M +Neil/SM +Neill/M +Nelda/M +Nell/M +Nelle/M +Nelli/M +Nellie/M +Nelly/M +Nels/N +Nelsen/M +Nelson/M +Nembutal/M +Nemesis/M +Neogene/M +Neolithic +Nepal/M +Nepalese/M +Nepali/MS +Neptune/M +Nereid/M +Nerf/M +Nerissa/M +Nero/M +Neruda/M +Nescafe/M +Nessa/M +Nesselrode/M +Nessie/M +Nesta/M +Nester/M +Nestle/M +Nestor/M +Nestorius/M +NetBSD/M +Netflix/M +Netherlander/SM +Netherlands/M +Netscape/M +Netta/M +Nettie/M +Netzahualcoyotl/M +Nev/M +Neva/M +Nevada/M +Nevadan/SM +Nevadian +Nevil/M +Nevile/M +Neville/M +Nevin/MS +Nevis/M +Nevsky/M +Newark/M +Newcastle/M +Newfoundland/MRS +Newman/M +Newport/M +Newsweek/M +Newton/M +Newtonian/M +NexTag/M +Nexis/M +Nextel/M +Ngaliema/M +Nguyen/M +Ni/M +Niagara/M +Nial/M +Niall/M +Niamey/M +Nibelung/M +Nicaea/M +Nicaragua/M +Nicaraguan/SM +Niccolo/M +Nice/M +Nicene/M +Nichiren/M +Nichol/SM +Nicholas/M +Nichole/M +Nichols/M +Nicholson/M +Nick/M +Nickelodeon/M +Nicki/M +Nickie/M +Nicklaus/M +Nicko/M +Nickolas/M +Nicky/M +Nico/M +Nicobar/M +Nicodemus/M +Nicol/M +Nicola/SM +Nicolai +Nicolas/M +Nicole/M +Nicolette/M +Nicolis +Nicolle/M +Nicosia/M +Niebuhr/M +Niel/SM +Nielsen/M +Nietzsche/M +Nieves/M +Nigel/M +Niger/M +Nigeria/M +Nigerian/MS +Nigerien/M +Nightingale/M +Nijinsky/M +Nike/M +Niki/M +Nikita/M +Nikkei/M +Nikki/M +Niko/SM +Nikola/SM +Nikolai/M +Nikolaos/M +Nikolaus/M +Nikolayev/M +Nikon/M +Nile/SM +Nils +Nilson/M +Nimitz/M +Nimrod/M +Nina/M +Ninette/M +Nineveh/M +Ninon/M +Nintendo/M +Niobe/M +Nippon/M +Nipponese/M +Nirenberg/M +Nirvana/M +Nisan/M +Nisei/M +Nissan/M +Nita/M +Niue/M +Nivea/M +Niven/M +Nixon/M +Nkrumah/M +No/SM +NoDoz/M +Noah/M +Noam/M +Nobel/M +Nobelist/MS +Noble/M +Noe/M +Noel/SM +Noelle/M +Noemi/M +Nokia/M +Nola/M +Nolan/M +Noland/M +Noll/M +Nome/M +Nomi/M +Nona/M +Noni/M +Nonie/M +Nonna/M +Nootka/M +Nora/M +Norah/M +Norbert/M +Norberto/M +Nordic/MS +Noreen/M +Norfolk/M +Noriega/M +Norma/M +Norman/MS +Normand/M +Normandy/M +Norplant/M +Norrie/M +Norris/M +Norse/M +Norseman/M +Norsemen/M +Nortel/M +North/M +Northampton/M +Northeast/MS +Northern/MR +Northerner/M +Northrop/M +Northrup/M +Norths +Northwest/SM +Norton/M +Norw +Norway/M +Norwegian/SM +Norwich/M +Nosferatu/M +Nostradamus/M +Notre +Nottingham/M +Nouakchott/M +Noumea/M +Nov/M +Nova/M +Novartis/M +November/MS +Novgorod/M +Novocain/MS +Novocaine +Novokuznetsk/M +Novosibirsk/M +Nowell/M +Noxzema/M +Noyce/M +Noyes/M +Np/M +Nubia/M +Nubian/M +Nukualofa/M +Numbers/M +Nunavut/M +Nunez/M +Nunki/M +Nuremberg/M +Nureyev/M +NutraSweet/M +NyQuil/M +Nyasa/M +Nye/M +Nyerere/M +Nyssa/M +O'Brien/M +O'Casey/M +O'Connell/M +O'Connor/M +O'Donnell/M +O'Hara/M +O'Higgins/M +O'Keeffe/M +O'Neil/M +O'Neill/M +O'Rourke/M +O'Toole/M +O/SM +OAS/M +OB +OCR +OD/SM +OE +OED +OH +OHSA/M +OJ +OK/SMDG +OMB/M +ON +OPEC/M +OR +OS/M +OSHA/M +OSes +OT +OTB +OTC +OTOH +Oahu/M +Oakland/M +Oakley/M +Oates/M +Oaxaca/M +Ob/MD +Obadiah/M +Obama/M +Obamacare +Obed/M +Oberlin/M +Oberon/M +Obie +Occam/M +Occident +Occidental/MS +Oceania/M +Oceanside +Oceanus/M +Ochoa/M +Oct/M +Octavia/M +Octavian/M +Octavio/M +Octavius/M +October/SM +Odell/M +Oder/M +Odessa/M +Odets/M +Odette/M +Odie/M +Odin/M +Odis/M +Odo/M +Odom/M +Ody/M +Odysseus/M +Odyssey/M +Oedipal/M +Oedipus/M +Oersted/M +Ofelia/M +Offenbach/M +OfficeMax/M +Ogbomosho/M +Ogden/M +Ogilvy/M +Oglethorpe/M +Ohio/M +Ohioan/SM +Oise/M +Ojibwa/SM +Okayama +Okeechobee/M +Okefenokee/M +Okhotsk/M +Okinawa/M +Okinawan +Okla +Oklahoma/M +Oklahoman/M +Oktoberfest/M +Ola/M +Olaf/M +Olajuwon/M +Olav/M +Oldenburg/M +Oldfield/M +Oldsmobile/M +Olduvai/M +Olen/M +Olenek/M +Olga/M +Oligocene/M +Olimpia/M +Olin/M +Olive/MR +Oliver/M +Olivetti/M +Olivia/M +Olivier/M +Ollie/M +Olly/M +Olmec/M +Olmsted/M +Olsen/M +Olson/M +Olwen/M +Olympe/M +Olympia/SM +Olympiad/MS +Olympian/MS +Olympic/SM +Olympics/M +Olympus/M +Omaha/MS +Oman/M +Omani/MS +Omar/M +Omayyad/M +Omdurman/M +Omnipotent +Omsk/M +Onassis/M +Oneal/M +Onega/M +Onegin/M +Oneida/MS +Onion/M +Ono/M +Onondaga/MS +Onsager/M +Ont +Ontarian +Ontario/M +Oona/M +Oort/M +Opal/M +Opaline/M +Opel/M +OpenBSD/M +OpenOffice/M +Ophelia/M +Ophiuchus/M +Oppenheimer/M +Opposition +Oprah/M +Ora/M +Oracle/M +Oran/M +Orange/M +Oranjestad/M +Orazio/M +Orbison/M +Ordovician/M +Ore/N +Oreg +Oregon/M +Oregonian/SM +Orel +Oren/M +Oreo/M +Orestes/M +Oriana/M +Orient/M +Oriental/MS +Orientalism +Orin/M +Orinoco/M +Orion/M +Oriya/M +Orizaba/M +Orkney/M +Orlan/M +Orland/M +Orlando/M +Orleans/M +Orlon/MS +Orly/M +Orpheus/M +Orphic/M +Orr/MN +Orren/M +Orrin/M +Orson/M +Ortega/M +Orthodox +Ortiz/M +Orton/M +Orv/M +Orval/M +Orville/M +Orwell/M +Orwellian/M +Oryza/M +Os/M +Osage/MS +Osaka/M +Osbert/M +Osborn/M +Osborne/M +Osbourne/M +Oscar/MS +Osceola/M +Osgood/M +Oshawa/M +Oshkosh/M +Osiris/M +Oslo/M +Osman/M +Osmond/M +Osmund/M +Ossie/M +Ostrogoth/M +Ostwald/M +Osvaldo/M +Oswald/M +Othello/M +Otho/M +Otis/M +Ottawa/SM +Ottilie/M +Otto/M +Ottoman/M +Ouagadougou/M +Ouija/MS +Ovid/M +Owen/SM +Owens/M +Oxford/SM +Oxley/M +Oxnard/M +Oxonian/M +Oxus/M +Oxycontin/M +Oz/M +Ozark/MS +Ozarks/M +Ozymandias/M +Ozzie/M +Ozzy/M +P/MN +PA/M +PAC/M +PARC/S +PASCAL +PBS/M +PBX +PC/SM +PCB +PCMCIA +PCP/M +PD +PDA/SM +PDF/SM +PDQ +PDT +PE +PET/M +PFC +PG +PGP +PIN +PJ's +PLO/M +PM/SMDG +PMS/M +PO +POW/M +PP +PPS +PR +PRC/M +PRNewswire/M +PRO +PS/M +PST/M +PT +PTA/M +PTO +PVC/M +PW +PX +Pa/M +Paar/M +Pablo/M +Pablum/M +Pabst/M +Pace/M +Pacheco/M +Pacific/M +Pacino/M +Packard/M +Paco/M +Padang +Paderewski/M +Padgett/M +Padilla/M +Padraic/M +Padraig/M +Paganini/M +Page/M +Paglia/M +Pahlavi/M +Paige/M +Paine/M +Paiute/SM +Pakistan/M +Pakistani/SM +Palau/M +Palembang/M +Paleocene/M +Paleogene/M +Paleolithic/M +Paleozoic/M +Palermo/M +Palestine/M +Palestinian/SM +Palestrina/M +Paley/M +Palikir/M +Palin/M +Palisades/M +Palladio/M +Palmer/M +Palmerston/M +Palmolive/M +Palmyra/M +Paloma/M +Palomar/M +Pam/M +Pamela/M +Pamirs/M +Pampers/M +Pan/M +Panama/SM +Panamanian/MS +Panasonic/M +Pancho/M +Pandora/M +Pangaea/M +Pankhurst/M +Panmunjom/M +Pansy/M +Pantagruel/M +Pantaloon/M +Pantheon/M +Panza/M +Paola/M +Paolina/M +Paolo/M +Papageno/M +Papua/M +Paracelsus/M +Paraclete/M +Paradise +Paraguay/M +Paraguayan/MS +Paralympic/S +Paramaribo/M +Paramount/M +Parana/M +Paran/M +Parcheesi/M +Pareto/M +Paris/M +Parisian/MS +Park/SMR +Parke/M +Parker/M +Parkinson/M +Parkinsonism +Parkman/M +Parks/M +Parliament/M +Parmenides +Parmesan/MS +Parnassus/MS +Parnell/M +Parr/M +Parrish/M +Parsee/SM +Parsi/MS +Parsifal/M +Parsons/M +Parthenon/M +Parthia/M +Pasadena/M +Pascal/SM +Pascale/M +Pasquale/M +Passion/SM +Passover/MS +Pasternak/M +Pasteur/M +Pat/MN +Patagonia/M +Patagonian/M +Pate/M +Patel/M +Paten/M +Paterson/M +Patna/M +Paton +Patric/M +Patrica/M +Patrice/M +Patricia/M +Patricio/M +Patrick/M +Patrizia/M +Patsy/M +Patten/M +Patterson/M +Patti/M +Pattie/M +Patton/M +Patty/M +Paul/GM +Paula/M +Paule/M +Paulette/M +Pauli/M +Paulie/M +Paulina/M +Pauline/M +Pauling/M +Paulo/M +Pauly/M +Pavarotti/M +Pavel/M +Pavia/M +Pavlov/M +Pavlova/M +Pavlovian/M +Pawnee/SM +Paxton +PayPal/M +Payne/M +Payton/M +Pb/M +Pd/M +Peabody/M +Peace/M +Peadar/M +Peale/M +Pearce/M +Pearl/M +Pearle/M +Pearlie/M +Pearson/M +Peary/M +Pechora/M +Peck/M +Peckinpah/M +Pecos/M +Peder/M +Pedro/M +Peel/M +Peg/M +Pegasus/MS +Pegeen/M +Peggy/M +Pei/M +Peiping/M +Peirce/M +Pekinese/M +Peking/SM +Pekingese/SM +Pele/M +Pelee/M +Peloponnese/M +Pembroke/M +Pen/M +Pena/M +Penderecki/M +Penelope/M +Penn/M +Penna +Penney/M +Pennington/M +Pennsylvania/M +Pennsylvanian/MS +Penny/M +Pennzoil/M +Penrod/M +Pensacola/M +Pentagon/M +Pentateuch/M +Pentax/M +Pentecost/SM +Pentecostal/MS +Pentecostalism +Pentium/SM +Peoria/M +Pepe/M +Pepi/M +Pepin/M +Pepita/M +Pepsi/M +Pepys/M +Pequot/M +Perceval +Percheron/M +Percival/M +Percy/M +Perelman/M +Perez/M +Peri/M +Periclean/M +Pericles/M +Perkin/MS +Perkins/M +Perl/SM +Perla/M +Perle/M +Perm/M +Permalloy/M +Permian/M +Pernod/M +Peron/M +Perot/M +Perri/MR +Perrier/M +Perrine/M +Perry/M +Perseid/M +Persephone/M +Persepolis/M +Perseus/M +Pershing/M +Persia/M +Persian/SM +Persis +Perth/M +Peru/M +Peruvian/MS +Peshawar/M +Peta/M +Petain/M +Pete/RMZ +Peter/M +Peterborough/M +Peters/MN +Petersen/M +Peterson/M +Petey/M +Petr/M +Petra/M +Petrarch/M +Petronella/M +Petronilla/M +Petty/M +Peugeot/M +Peyton/M +Pfc +Pfizer/M +PhD/M +Phaedra/M +Phaethon/M +Phanerozoic/M +Pharaoh/M +Pharaohs +Pharisaic +Pharisaical +Pharisee/MS +Phebe +Phekda/M +Phelps/M +Phidias/M +Phil/MY +Philadelphia/M +Philby/M +Philemon/M +Philip/MS +Philippa/M +Philippe/M +Philippians/M +Philippine/SM +Philippines/M +Philips/M +Philistine/M +Phillida/M +Phillip/SM +Phillipa/M +Phillipe/M +Phillips/M +Phillis/M +Philly/M +Philomena/M +Phineas/M +Phipps/M +Phobos/M +Phoebe/M +Phoenicia/M +Phoenician/SM +Phoenix/M +Photoshop/M +Photostat/MS +Photostatted +Photostatting +Phrygia/M +Phyllida/M +Phyllis/M +Pia/M +Piaf/M +Piaget/M +Pianola/M +Picasso/M +Piccadilly/M +Pickering/M +Pickett/M +Pickford/M +Pickwick/M +Pict/M +Pictor +Piedmont/M +Pierce/M +Pierre/M +Pierrette/M +Pierrot/M +Pierson/M +Pieter/M +Pietra/M +Pietro/M +Pike/M +Pilate/MS +Pilates/M +Pilcomayo/M +Pilgrim/SM +Pillsbury/M +Pinatubo/M +Pinchas/M +Pincus/M +Pindar/M +Pinkerton/M +Pinocchio/M +Pinochet/M +Pinter/M +Pinyin +Piotr/M +Pippa/M +Pippin/M +Piraeus/M +Pirandello/M +Pisa/M +Pisces/M +Pisistratus/M +Pissaro/M +Pitcairn/M +Pitt/SM +Pittman/M +Pitts/M +Pittsburgh/M +Pius/M +Pizarro/M +Pkwy +Pl +Place +Planck/M +Plano +Plantagenet/M +Plasticine/M +Plataea/M +Plath/M +Plato/M +Platonic +Platonism/M +Platonist/M +Platte/M +Plautus/M +PlayStation/M +Playboy/M +Playtex/M +Pleiades/M +Pleistocene/M +Plexiglas/MS +Pliny/M +Pliocene/SM +Plutarch/M +Pluto/M +Plymouth/M +Pm/M +Po/M +Pocahontas/M +Pocono/SM +Poconos/M +Podgorica/M +Podhoretz/M +Podunk/M +Poe/M +Pogo/M +Poincare/M +Poincar/M +Poiret/M +Poirot/M +Poisson/M +Poitier/M +Pokemon/M +Pokmon/M +Pol/MY +Poland/M +Polanski/M +Polaris/M +Polaroid/MS +Pole/SM +Polish/M +Politburo/M +Polk/M +Pollard/M +Pollock/M +Pollux/M +Polly/M +Pollyanna/M +Polo/M +Poltava/M +Polyhymnia/M +Polynesia/M +Polynesian/MS +Polyphemus/M +Pomerania/M +Pomeranian/M +Pomona/M +Pompadour/M +Pompeian +Pompeii/M +Pompey/M +Ponce/M +Pontchartrain/M +Pontiac/M +Pontianak/M +Pooh/M +Poole/M +Poona/M +Pope/M +Popeye/M +Popocatepetl/M +Popper/M +Poppins/M +Popsicle/M +Porfirio/M +Porrima/M +Porsche/M +Port/MR +Porter/M +Portia/M +Portland/M +Porto/M +Portsmouth/M +Portugal/M +Portuguese/M +Poseidon/M +Post/M +PostScript/M +PostgreSQL/M +Potemkin/M +Potomac/M +Potsdam/M +Pottawatomie/M +Potter/M +Potts/M +Poul/M +Pound/M +Poussin/M +Powell/M +PowerPC/M +PowerPoint/M +Powers/M +Powhatan/M +Poynter/M +Poznan/M +Pr/M +Prada/M +Prado/M +Praetorian/M +Prague/M +Praia/M +Prakrit/M +Pratchett/M +Pratt/M +Pravda/M +Praxiteles/M +Preakness/M +Precambrian/M +Preminger/M +Premyslid/M +Prensa/M +Prentice/M +Prentiss/M +Pres +Presbyterian/SM +Presbyterianism/MS +Prescott/M +Presley/M +Preston/M +Pretoria/M +Priam/M +Pribilof/M +Price/M +Priestley/M +Prince/M +Princeton/M +Principe/M +Prinz +Pris +Prisca/M +Priscilla/M +Prism/M +Prius/M +Private +Prix +ProQuest/M +Procrustean/M +Procrustes/M +Procter/M +Procyon/M +Prof +Prohibition +Prokofiev/M +Promethean/M +Prometheus/M +Prophets +Proserpina/M +Proserpine/M +Protagoras/M +Proterozoic/M +Protestant/MS +Protestantism/SM +Proteus/M +Proudhon/M +Proust/M +Provencal/MS +Provence/M +Provenal/M +Proverbs +Providence/SM +Provo/M +Prozac/MS +Pru/M +Prudence/M +Prudential/M +Prudy/M +Prue/M +Pruitt/M +Prussia/M +Prussian/MS +Prut/M +Pryce/M +Pryor/M +Psalms/M +Psalter/MS +Pseudomonas/M +Psyche/M +Pt/M +Ptah/M +Ptolemaic/M +Ptolemy/SM +Pu/M +PubMed/M +Puccini/M +Puck/M +Puckett/M +Puebla/M +Pueblo/M +Puerto +Puget/M +Pugh/M +Pulaski/M +Pulitzer/M +Pullman/MS +Punch/M +Punic/M +Punjab/M +Punjabi/M +Purana/M +Purcell/M +Purdue/M +Purgatory +Purim/MS +Purina/M +Puritan/M +Puritanism/MS +Purus/M +Pusan/M +Pusey/M +Pushkin/M +Pushtu/M +Putin/M +Putnam/M +Puzo/M +Pvt +Pygmalion/M +Pygmy/SM +Pyle/M +Pym/M +Pynchon/M +Pyongyang/M +Pyotr/M +Pyrenees/M +Pyrex/MS +Pyrrhic/M +Pythagoras/M +Pythagorean/M +Pythias/M +Python/M +Ptain/M +Prto/M +Q +QA +QB +QC +QED +QM +QWERTY +Qaddafi/M +Qaeda/M +Qantas/M +Qatar/M +Qatari/MS +Qingdao/M +Qiqihar/M +Qom/M +Quaalude/M +Quaker/MS +Quakerism/SM +Quaoar/M +Quasimodo/M +Quaternary/M +Quayle/M +Que +Quebec/M +Quebecker +Quebecois/M +Quechua/M +Queen/MS +Queenie/M +Queens/M +Queensland/M +Quent/M +Quentin/M +Quetzalcoatl/M +Quezon/M +QuickList/M +QuickTime/M +Quillan/M +Quincey/M +Quincy/M +Quinlan/M +Quinn/M +Quint/M +Quinta/M +Quintana/M +Quintilian/M +Quintin/M +Quinton/M +Quintus/M +Quirinal/M +Quisling/M +Quito/M +Quixote/M +Quixotism/M +Qumran/M +Quonset/M +Qur'an +Qur'anic +Quran +Quranic +Qubecois/M +Qwest/M +R/MD +RAF/M +RAM/SM +RBI +RC +RCA/M +RCMP +RD +RDA +REIT +REM/SM +RF +RFC/S +RFD +RI +RIF +RIP +RISC +RN/M +RNA/M +ROFL +ROM/M +ROTC/M +RP +RR +RSFSR +RSI +RSV +RSVP +RTFM +RV/SM +Ra/M +Rab/M +Rabat/M +Rabelais/M +Rabelaisian/M +Rabi +Rabin/M +Rachael/M +Rachel/M +Rachelle/M +Rachmaninoff/M +Racine/M +Radcliffe/M +Rae/M +Raf/M +Rafa/M +Rafael/M +Rafe/M +Raff/M +Raffaello/M +Rafferty/M +Raffles/M +Rafi/M +Ragnar/M +Ragnarok/M +Ragnark/M +Rahel/M +Raimondo/M +Raimund/M +Raimundo/M +Raina/M +Raine/MR +Rainer/M +Rainier/M +Raleigh/M +Ralf/M +Ralph/M +Rama/M +Ramada/M +Ramadan/MS +Ramakrishna/M +Ramanujan/M +Ramayana/M +Rambo/M +Ramirez/M +Ramiro/M +Ramon/M +Ramona/M +Ramos/M +Ramsay/M +Ramses/M +Ramsey/M +Rana/M +Rance/M +Rand/M +Randa/M +Randal/M +Randall/M +Randell/M +Randi/M +Randolph/M +Randy/M +Rangoon/M +Rani/M +Rankin/M +Rankine/M +Raoul/M +Raphael/M +Rappaport/M +Rapunzel/M +Raquel/M +Rasalgethi/M +Rasalhague/M +Rasmussen/M +Rasputin/M +Rasta +Rastaban/M +Rastafarian/MS +Rastafarianism +Rather/M +Ratliff/M +Raul/M +Ravel/M +Ravi/M +Ravid/M +Raviv/M +Rawalpindi/M +Rawley/M +Ray/M +RayBan/M +Rayburn/M +Raye/M +Rayleigh/M +Raymond/M +Raymund/M +Raymundo/M +Rayna/M +Rayner/M +Raynor/M +Rb/M +Rd +Re/M +Rea/M +Reade/G +Reading/M +Reagan/M +Reaganomics/M +Realtor/M +Reasoner/M +Reba/M +Rebeca/M +Rebecca's +Rebecka/M +Rebekah/M +Recife/M +Reconstruction/M +Red/SM +Redd/M +Redeemer/M +Redford/M +Redgrave/M +Redmond/M +Ree/DSM +Reebok/M +Reece/M +Reed/M +Reena/M +Reese/M +Reeves/M +Reformation/MS +Refugio/M +Regan/M +Regen/M +Reggie/M +Regina/M +Reginae/M +Reginald/M +Regine/M +Regor/M +Regulus/M +Rehnquist/M +Reich/M +Reichstag's +Reid/M +Reiko/M +Reilly/M +Reina/M +Reinaldo/M +Reine/M +Reinhard/M +Reinhardt/M +Reinhold/M +Remanence +Remanent +Remarque/M +Rembrandt/M +Remington/M +Remus/M +Remy/M +Rena/M +Renae/M +Renaissance/SM +Renaldo/M +Renard/M +Renascence +Renata/M +Renate/M +Renato/M +Renaud/M +Renault/M +Rene/M +Renee/M +Renie/M +Rennie/M +Reno/M +Renoir/M +Rep +Representative +Republican/SM +Republicanism +Requiem/MS +Resistance +Restoration/M +Resurrection +Reta/M +Reuben/M +Reunion/M +Reuters/M +Reuther/M +Reuven/M +Rev +Reva/M +Revelation/SM +Revelations/M +Revere/M +Reverend/M +Revlon/M +Rex/M +Rey/M +Reyes/M +Reykjavik/M +Reyna/M +Reynaldo/M +Reynard/M +Reynold/MS +Reynolds/M +Rf/M +Rh/M +Rhea/M +Rhee/M +Rheingau/M +Rhenish/M +Rhett/M +Rhianna/M +Rhiannon/M +Rhine/M +Rhineland/M +Rhino/M +Rhoda/M +Rhode/S +Rhodes/M +Rhodesia/M +Rhodesian +Rhona/M +Rhonda/M +Rhone/M +Rhys/M +Ribbentrop/M +Ric/M +Rica/M +Ricard/M +Ricardo/M +Riccardo/M +Rice/M +Rich/M +Richard/MS +Richards/M +Richardson/M +Richart/M +Richelieu/M +Richie/M +Richmond/M +Richter/M +Richthofen/M +Rick/M +Rickard/M +Rickenbacker/M +Rickert/M +Rickey/M +Ricki/M +Rickie/M +Rickover/M +Ricky/M +Rico/M +Riddle/M +Ride/M +Riefenstahl/M +Riel/M +Riemann/M +Riesling/MS +Riga/M +Rigel/M +Riggs/M +Right +Rigoberto/M +Rigoletto/M +Rik/M +Riki/M +Rikki/M +Riley/M +Rilke/M +Rimbaud/M +Rina/M +Rinaldo/M +Ringling/M +Ringo/M +Rio/SM +Riordan/M +Rios/M +Ripley/M +Risa/M +Risorgimento/M +Rita/M +Ritalin/M +Ritchie/M +Ritz/M +Riva/SM +Rivas/M +Rivera/M +Rivers/M +Riverside +Riviera/MS +Riyadh/M +Rizal/M +Rn/M +Roach/M +Roanoke/M +Roarke/M +Rob/M +Robb/M +Robbie/M +Robbin/MS +Robbins/M +Robby/M +Roberson/M +Robert/MS +Roberta/M +Roberto/M +Roberts/M +Robertson/M +Robeson/M +Robespierre/M +Robin/M +Robina/M +Robinet/M +Robinette/M +Robinia/M +Robinson/M +Robitussin/M +Robles/M +Robson/M +Robt/M +Roby/M +Robyn/M +Rocco/M +Roch/M +Rocha/M +Rochambeau/M +Roche/M +Rochelle/M +Rochester/M +Rock/M +Rockefeller/M +Rockford/M +Rockies/M +Rockne/M +Rockwell/M +Rocky/SM +Rod/M +Roda/M +Rodd/M +Roddenberry/M +Roddy/M +Roderic/M +Roderick/M +Roderigo/M +Rodger/MS +Rodgers/M +Rodham/M +Rodi/M +Rodin/M +Rodney/M +Rodolfo/M +Rodolph/M +Rodolphe/M +Rodrick/M +Rodrigo/M +Rodriguez/M +Rodriquez/M +Roeg/M +Roentgen +Rog/MRZ +Rogelio/M +Roger/M +Rogers/M +Roget/M +Roi/SM +Rojas/M +Roku/M +Rolaids/M +Roland/M +Rolando/M +Roldan/M +Rolex/M +Rolf +Rolfe/M +Rolland/M +Rollerblade/M +Rollie/M +Rollin/MS +Rollins/M +Rollo +Rolodex/M +Rolph/M +Rolvaag/M +Rom +Roma/M +Romain/M +Roman/MS +Romanesque/MS +Romania/M +Romanian/MS +Romano/M +Romanov/M +Romans/M +Romansh/M +Romantic +Romanticism +Romany/SM +Rome/SM +Romeo/M +Romero/M +Rommel/M +Romney/M +Romola/M +Romulus/M +Romy/M +Ron/M +Rona/M +Ronald/M +Ronda/M +Ronni/M +Ronnie/M +Ronny/M +Ronstadt/M +Rontgen +Rooney/M +Roosevelt/M +Root/M +Roquefort/SM +Rorke/M +Rorschach/M +Rory/M +Ros +Rosa/M +Rosaleen/M +Rosales/M +Rosalia/M +Rosalie/M +Rosalind/M +Rosalinda/M +Rosaline/M +Rosalyn/M +Rosamond/M +Rosamund/M +Rosanna/M +Rosanne/M +Rosario/M +Rosco/M +Roscoe/M +Rose/M +Roseann/M +Roseanne/M +Roseau/M +Rosecrans/M +Rosella/M +Roselle/M +Rosemarie/M +Rosemary/M +Rosenberg/M +Rosendo/M +Rosenzweig/M +Rosetta/M +Rosicrucian/M +Rosie/M +Rosina/M +Rosita/M +Roslyn/M +Ross/M +Rossetti/M +Rossie/M +Rossini/M +Rostand/M +Rostov/M +Rostropovich/M +Roswell/M +Rosy's +Rotarian/M +Roth/M +Rothko/M +Rothschild/M +Rotterdam/M +Rottweiler/M +Rouault/M +Rourke/M +Rousseau/M +Routledge/M +Rove/RM +Rover/M +Rowan/M +Rowe/M +Rowen/M +Rowena/M +Rowland/M +Rowling/M +Roxana/M +Roxane/M +Roxanna/M +Roxanne/M +Roxie/M +Roxy/M +Roy/M +Royal/M +Royall/M +Royce/M +Roz/M +Rozelle/M +Rte +Ru/MH +Rubaiyat/M +Rubbermaid/M +Ruben/SM +Rubens/M +Rubi/M +Rubia/M +Rubicon/MS +Rubik/M +Rubin/M +Rubinstein/M +Ruby/M +Ruchbah/M +Rudd/M +Ruddy's +Rudiger/M +Rudolf/M +Rudolfo/M +Rudolph/M +Rudy/M +Rudyard/M +Rufe/M +Rufus/M +Rugby +Ruggiero/M +Ruhr/M +Ruiz/M +Rukeyser/M +Rumanian/SM +Rumpelstiltskin/M +Rumsfeld/M +Runnymede/M +Runyon/M +Rupert/M +Ruprecht/M +Rurik +Rush/M +Rushdie/M +Rushmore/M +Ruskin/M +Russ/M +Russel/M +Russell/M +Russia/M +Russian/SM +Russo/M +Rustbelt/M +Rustin/M +Rusty/M +Rutan/M +Rutger/MS +Rutgers/M +Ruth/M +Rutherford/M +Ruthie/M +Rutledge/M +Rutter/M +Ruy/M +Rwanda/MS +Rwandan/SM +Rwy +Rx +Ry +Ryan/M +Rydberg/M +Ryder/M +Ryukyu/M +S/MN +SA +SAC +SALT/M +SAM/M +SAP/M +SARS/M +SASE +SAT +SBA +SC/M +SCSI/M +SD +SDI +SE/M +SEATO +SEC/M +SF +SGML/M +SIDS/M +SJ +SJW +SK +SLR +SNP/SM +SO/S +SOB/M +SOP/M +SOS/M +SOSes +SPCA +SPF +SQL +SRO +SS +SSA +SSE/M +SSS +SST +SSW/M +ST +STD +STOL +SUSE/M +SUV +SVN/M +SW/M +SWAK +SWAT +Saab/M +Saar/M +Saarinen/M +Saatchi/M +Saba/M +Sabbath/M +Sabbaths +Sabik/M +Sabin/M +Sabina/M +Sabine/M +Sabre/M +Sabrina/M +Sacajawea/M +Saccharomyces/M +Sacco/M +Sacha/M +Sachs/M +Sacramento/M +Sada/M +Sadat/M +Saddam/M +Sadducee/M +Sade/M +Sadie/M +Sadr/M +Safavid/M +Safeway/M +Sagan/M +Saginaw/M +Sagittarius/MS +Sahara/M +Saharan/M +Sahel/M +Saigon/M +Saiph/M +Sakai/M +Sakha/M +Sakhalin/M +Sakharov/M +Saki/M +Saks/M +Sal/MY +Saladin/M +Salado/M +Salamis/M +Salas/M +Salazar/M +Saleem/M +Salem/M +Salerno/M +Salim/M +Salinas/M +Salinger/M +Salisbury/M +Salish/M +Salk/M +Sallee/M +Sallie/M +Sallust/M +Sally/M +Salome/M +Salomon/M +Salonika/M +Salton/M +Salvador/M +Salvadoran/SM +Salvadorean/MS +Salvadorian/MS +Salvatore/M +Salween/M +Salyut/M +Sam/M +Samantha/M +Samar/M +Samara/M +Samaria +Samaritan/MS +Samarkand/M +Sammie/M +Sammy/M +Samoa/M +Samoan/SM +Samoset/M +Samoyed/M +Sampson/M +Samson/M +Samsonite/M +Samsung/M +Samuel/M +Samuelson/M +San'a +San/M +Sana/M +Sanaa/M +Sanchez/M +Sancho/M +Sand/ZM +Sandburg/M +Sande/M +Sanders/M +Sanderson/M +Sandi/M +Sandie/M +Sandinista/M +Sandor/M +Sandoval/M +Sandra/M +Sandro/M +Sandy/M +Sanford/M +Sanforized/M +Sang/MR +Sanger/M +Sanhedrin/M +Sanka/M +Sankara/M +Sanskrit/M +Sanson/M +Sansone/M +Santa/M +Santana/M +Santayana/M +Santeria/M +Santiago/M +Santos/M +Sapphira +Sappho/M +Sapporo/M +Sara/M +Saracen/MS +Saragossa/M +Sarah/M +Sarajevo/M +Saran/M +Sarasota/M +Saratov/M +Sarawak/M +Sarbanes/M +Sardinia/M +Saree/M +Sargasso/M +Sarge/M +Sargent/M +Sargon/M +Sarina/M +Sarita/M +Sarnoff/M +Saroyan/M +Sarto/M +Sartre/M +Sascha/M +Sasha/M +Sask +Saskatchewan/M +Saskatoon/M +Sasquatch/MS +Sassanian/M +Sassoon/M +Sat/M +Satan/M +Satanism/M +Satanist/M +Saturday/MS +Saturn/M +Saturnalia/M +Saudi/MS +Saul/M +Saunders/M +Saunderson/M +Saundra/M +Saussure/M +Sauternes +Sauveur/M +Savage/M +Savannah/M +Savina/M +Savior/M +Savonarola/M +Savoy/M +Savoyard/M +Sawyer/M +Saxe/M +Saxon/MS +Saxony/M +Sayer/MS +Sayers/M +Sayre/M +Sb/M +Sc/M +Scala/M +Scan +Scandinavia/M +Scandinavian/MS +Scaramouch/M +Scarborough/M +Scarface/M +Scarlatti/M +Scarlett/M +Scheat/M +Schedar/M +Scheherazade/M +Schelling/M +Schenectady/M +Schiaparelli/M +Schick/M +Schiller/M +Schindler/M +Schlesinger/M +Schliemann/M +Schlitz/M +Schmidt/M +Schnabel/M +Schnauzer/M +Schneider/M +Schoenberg/M +Schopenhauer/M +Schrieffer/M +Schrodinger/M +Schroeder/M +Schrdinger/M +Schubert/M +Schultz/M +Schulz/M +Schumann/M +Schumpeter/M +Schuyler/M +Schuylkill/M +Schwartz/M +Schwarz/M +Schwarzenegger/M +Schwarzkopf/M +Schweitzer/M +Schweppes/M +Schwinger/M +Schwinn/M +Scientologist/SM +Scientology/M +Scipio/M +Scopes/M +Scorpio/SM +Scorpius/M +Scorsese/M +Scot/SM +Scotch/MS +Scotchman/M +Scotchmen/M +Scotchwoman/M +Scotchwomen/M +Scotia/M +Scotland/M +Scotsman/M +Scotsmen/M +Scotswoman/M +Scotswomen/M +Scott/M +Scotti/M +Scottie/SM +Scottish/M +Scottsdale/M +Scrabble/MS +Scranton/M +Scriabin/M +Scribner/M +Scripture/SM +Scrooge/M +Scruggs/M +Scud/M +Sculley/M +Scylla/M +Scythia/M +Scythian/M +Se/MHN +SeaMonkey/M +Seaborg/M +Seagram/M +Seamus/M +Sean/M +Sears/M +Seattle/M +Sebastian/M +Sebastiano/M +Sebastien/M +Sec +Seconal/M +Secretariat/M +Secretary +Seder/MS +Sedna/M +Seebeck/M +Seeger/M +Sega/M +Segovia/M +Segre/M +Segundo/M +Seiko/M +Seine/M +Seinfeld/M +Sejong/M +Sela/M +Selassie/M +Selby/M +Selectric/M +Selena/M +Selene/M +Seleucid/M +Seleucus/M +Selig/M +Selim/M +Selina/M +Seljuk/M +Selkirk/M +Sella/M +Selle/MZ +Sellers/M +Selma/M +Selznick/M +Semarang/M +Seminole/MS +Semiramis/M +Semite/MS +Semitic/SM +Semtex/M +Sena/M +Senate/MS +Sendai/M +Seneca/MS +Senegal/M +Senegalese/M +Senghor/M +Senior/M +Sennacherib/M +Sennett/M +Sensurround/M +Seoul/M +Sep +Sephardi/M +Sepoy/M +Sept/M +September/MS +Septuagint/MS +Sequoya/M +Serb/SM +Serbia/M +Serbian/MS +Serena/M +Serengeti/M +Sergei/M +Sergent/M +Sergio/M +Serpens/M +Serra/M +Serrano/M +Set/M +Seth/M +Seton/M +Seurat/M +Seuss/M +Sevastopol/M +Severn/M +Severus/M +Seville/M +Sevres/M +Seward/M +Sextans/M +Sexton/M +Seychelles/M +Seyfert/M +Seymour/M +Sgt +Shackleton/M +Shaffer/M +Shah/M +Shaka/M +Shaker +Shakespeare/M +Shakespearean/M +Shalom's +Shamus/M +Shana/M +Shandy/M +Shane/M +Shanghai/M +Shani/M +Shankara/M +Shanna/M +Shannon/M +Shanta/M +Shantung/M +Shapiro/M +Shara/M +SharePoint/M +Shari'a/M +Shari/M +Sharif/M +Sharlene/M +Sharma/M +Sharon/M +Sharp/M +Sharpe/M +Sharron/M +Shasta/M +Shaula/M +Shaun/M +Shauna/M +Shavian/M +Shavuot/M +Shaw/M +Shawn/M +Shawna/M +Shawnee/SM +Shayla/M +Shayna/M +Shayne/M +Shcharansky/M +Shea/M +Sheba/M +Shebeli/M +Sheela/M +Sheena/M +Sheetrock/M +Sheffield/M +Sheila/M +Sheilah/M +Shel/MY +Shelagh/M +Shelby/M +Sheldon/M +Shelia/M +Shell/M +Shelley/M +Shelly/M +Shelton/M +Shem/M +Shen/M +Shenandoah/M +Shenyang/M +Shenzhen/M +Sheol/M +Shep/M +Shepard/M +Shepherd/M +Sheppard/M +Sher/M +Sheratan/M +Sheraton/M +Sheree/M +Sheri/M +Sheridan/M +Sherlock/M +Sherm/M +Sherman/M +Sherpa/M +Sherri/M +Sherrie/M +Sherry/M +Sherwin/M +Sherwood/M +Sheryl/M +Shetland/SM +Shetlands/M +Shevardnadze/M +Shevat/M +Shi'ite/M +Shields/M +Shiite/MS +Shijiazhuang/M +Shikoku/M +Shillong/M +Shiloh/M +Shina/M +Shinto/MS +Shintoism/MS +Shintoist/MS +Shir/M +Shiraz/M +Shirl/M +Shirley/M +Shiva/M +Shockley/M +Sholom/M +Short/M +Shorthorn/M +Shoshana/M +Shoshone/SM +Shostakovitch/M +Shrek/M +Shreveport/M +Shriner/M +Shropshire/M +Shula/M +Shylock/M +Shylockian/M +Si/M +Siam/M +Siamese/M +Sian/M +Sib/M +Sibelius/M +Siberia/M +Siberian/MS +Sibley/M +Sibyl/M +Sibylla/M +Sibylle/M +Sicilian/SM +Sicily/M +Sid/M +Siddhartha/M +Sidney/M +Sidonia/M +Siegfried/M +Siemens/M +Sierpinski/M +Sierras +Sig +Sigismondo/M +Sigismund/M +Sigmund/M +Sigrid/M +Sigurd/M +Sihanouk/M +Sikh/M +Sikhism +Sikhs +Sikkim/M +Sikkimese/M +Sikorsky/M +Silas/M +Silesia/M +Silurian/SM +Silva/M +Silvan/M +Silvana/M +Silvano/M +Silvanus/M +Silvester/M +Silvia/M +Silvie/M +Silvio/M +Sim's +Simenon/M +Simeon/M +Simmental/M +Simmonds/M +Simmons/M +Simon/M +Simona/M +Simone/M +Simpson/SM +Simpsons/M +Sims/M +Sinai/M +Sinatra/M +Sinbad/M +Sinclair/M +Sindbad/M +Sindhi/M +Singapore/M +Singaporean/SM +Singer/M +Singh/M +Singleton/M +Sinhalese/M +Sinkiang/M +Siobhan/M +Sioux/M +Sir/SM +Sirius/M +Sissie/M +Sister/MS +Sistine/M +Sisyphean/M +Sisyphus/M +Siva/M +Sivan/M +Siward/M +Sjaelland/M +Skelly/M +Skinner/M +Skippy/M +Skipton/M +Skopje/M +Skye/M +Skylab/M +Skylar/M +Skyler/M +Skype/M +Slackware/M +Slade/M +Slashdot/M +Slater/M +Slav/SM +Slavic/M +Slavonic/M +Slinky/M +Sloan/M +Sloane/M +Slocum/M +Slovak/SM +Slovakia/M +Slovakian +Slovene/SM +Slovenia/M +Slovenian/MS +Slurpee/M +Sly's +Sm/M +Small/M +Smetana/M +Smirnoff/M +Smith/M +Smithson/M +Smithsonian/M +Smitty/M +Smokey/M +Smolensk/M +Smollett/M +Smuts/M +Smyrna +Sn/M +Snake/M +Snapple/M +Snead/M +Snell/M +Snickers/M +Snider/M +Snoopy/M +Snow/M +Snowbelt/M +Snowl/M +Snyder/M +Soave/M +Soc +Socorro/M +Socrates/M +Socratic/M +Soddy/M +Sodom/M +Sofia/M +Sofie/M +Soho/M +Sol/MY +Solaris/M +Solis/M +Solly/M +Solomon/M +Solon/M +Solzhenitsyn/M +Somali/SM +Somalia/M +Somalian/MS +Somerset +Somme/M +Somoza/M +Son/M +Sondheim/M +Sondra/M +Songbird/M +Songhai/M +Songhua/M +Sonia/M +Sonja/M +Sonny/M +Sonora/M +Sontag/M +Sony/M +Sonya/M +Sophi/M +Sophia/M +Sophie/M +Sophoclean/M +Sophocles/M +Sophronia/M +Sopwith/M +Sorbonne/M +Sorcha/M +Sosa/M +Soto/M +Souphanouvong/M +Sourceforge/M +Sousa/M +South/M +Southampton/M +Southeast/MS +Southern/ZR +Southerner/M +Southey/M +Souths +Southwest/MS +Soviet/M +Soweto/M +Soyinka/M +Soyuz/M +Sp +Spaatz/M +Spackle/M +Spahn/M +Spain/M +Spam/M +Span +Spanglish +Spaniard/SM +Spanish/M +Sparc +Sparks/M +Sparta/M +Spartacus/M +Spartan/MS +Spears/M +Speer/M +Spence/RM +Spencer/M +Spencerian/M +Spengler/M +Spenglerian/M +Spenser/M +Spenserian/M +Sperry/M +Sphinx/M +Spica/M +SpiderMonkey/M +Spielberg/M +Spillane/M +Spinoza/M +Spinx/M +Spiro/M +Spirograph/M +Spitsbergen/M +Spitz/M +Spock/M +Spokane/M +Springfield/M +Springsteen/M +Sprint/M +Sprite/M +Sputnik/M +Sq +Squanto/M +Squibb/M +Sr/M +Srinagar/M +Srivijaya/M +St +Sta +Stace/M +Stacey/M +Staci/M +Stacie/M +Stacy/M +Stael/M +Stafford/M +StairMaster/M +Stalin/M +Stalingrad/M +Stalinist/M +Stallone/M +Stamford/M +Stan/MY +Standford/M +Standish/M +Stanfield/M +Stanford/M +Stanislas/M +Stanislaus/M +Stanislavsky/M +Stanislaw/M +Stanley/M +Stanly/M +Stanton/M +Stanwood/M +Staples/M +Starbucks/M +Stark/M +Starkey/M +Starr/M +Statehouse/MS +Staten/M +States +Stateside +Staubach/M +Stavros +Ste +Steadicam/M +Stearn/M +Steele/M +Stefan/M +Stefania/M +Stefanie/M +Stefano/M +Steffen/M +Steffi/M +Stein/MR +Steinbeck/M +Steinem/M +Steiner/M +Steinmetz/M +Steinway/M +Stella/M +Stendhal/M +Stengel/M +Stephan/M +Stephani/M +Stephanie/M +Stephanus/M +Stephen/MS +Stephens/M +Stephenson/M +Sterling/M +Stern/M +Sterne/M +Sterno/M +Stetson/M +Steuben/M +Steve/M +Steven/MS +Stevens/M +Stevenson/M +Stevie/M +Stewart/M +Stieglitz/M +Stillman/M +Stilton/SM +Stimson/M +Stine/M +Stinky's +Stirling/M +Stockhausen/M +Stockholm/M +Stockton/M +Stoddard/M +Stoic/SM +Stoicism/MS +Stokes/M +Stolichnaya/M +Stolypin/M +Stone/M +Stonehenge/M +Stoppard/M +Stormy's +Stout/M +Stowe/M +Strabo/M +Stradivari +Stradivarius/M +Strasbourg/M +Strauss/M +Stravinsky/M +Streisand/M +Strickland/M +Strindberg/M +Stromboli/M +Strong/M +Stu/M +Stuart/MS +Studebaker/M +StumbleUpon/M +Stuttgart/M +Stuyvesant/M +Stygian/M +Styrofoam/SM +Styron/M +Styx/M +Suarez/M +Subaru/M +Sucre/M +Sucrets/M +Sudan/M +Sudanese/M +Sudetenland/M +Sudoku/M +Sudra/M +Sue/M +Suetonius/M +Suez/M +Suffolk/M +Sufi/M +Sufism/M +Suharto/M +Sui/M +Sukarno/M +Sukey/M +Suki/M +Sukkot +Sukkoth/M +Sukkoths +Sula/M +Sulawesi/M +Suleiman/M +Sulla/M +Sullivan/M +Sumatra/M +Sumatran/SM +Sumeria/M +Sumerian/SM +Summer/MS +Summers/M +Sumner/M +Sumter/M +Sun/SM +Sunbeam/M +Sunbelt/M +Sunbird/M +Sundanese/M +Sundas/M +Sunday/MS +Sunderland/M +Sung/M +Sunkist/M +Sunni/SM +Sunnite/MS +Sunny's +Sunnyvale/M +Superbowl/M +Superfund/M +Superglue/M +Superior/M +Superman/M +Supt +Surabaja +Surabaya/M +Surat/M +Suriname/M +Surinamese +Surya/M +Susan/M +Susana/M +Susann/M +Susanna/M +Susannah/M +Susanne/M +Susi/M +Susie/M +Susquehanna/M +Sussex/M +Susy/M +Sutherland/M +Sutton/M +Suva/M +Suwanee/M +Suzanna/M +Suzanne/M +Suzette/M +Suzhou/M +Suzi/M +Suzie/M +Suzuki/M +Suzy/M +Svalbard/M +Sven/M +Svend/M +Svengali/M +Sverdlovsk +Swahili/SM +Swammerdam/M +Swanee/M +Swansea/M +Swanson/M +Swazi/SM +Swaziland/M +Swed/N +Swede/SM +Sweden/M +Swedenborg/M +Swedish/M +Sweeney/M +Sweet/M +Swift/M +Swinburne/M +Swindon/M +Swiss/MS +Swissair/M +Switz +Switzerland/M +Sybil/M +Sybilla/M +Sybille/M +Syd/M +Sydney/M +Sykes/M +Sylvan's +Sylvester/M +Sylvia/M +Sylvie/M +Symantec/M +Symbian/M +Symon/M +Synge/M +Syracuse/M +Syria/M +Syriac/M +Syrian/MS +Szilard/M +Szymborska/M +Svres/M +T'ang/M +T/MDG +TA +TARP +TB/M +TBA +TD +TDD +TEFL +TELNET/S +TELNETTed +TELNETTing +TESL +TESOL +TEirtza/M +TGIF +THC +THz/M +TKO/M +TLC/M +TM +TN +TNT/M +TOEFL +TQM +TV/SM +TVA +TWA/M +TWX +TX +Ta/M +Tabasco/SM +Tabatha/M +Tabb/M +Taber/M +Tabernacle/MS +Tabitha/M +Tabor +Tabriz/MS +Tacitus/M +Tacoma/M +Tad/M +Taddeo/M +Tadzhik/M +Taegu/M +Taejon/M +Taft/M +Tagalog/SM +Tagore/M +Tagus/M +Tahiti/M +Tahitian/MS +Tahoe/M +Taichung/M +Tainan +Taine/M +Taipei/M +Taiping/M +Tait/M +Taiwan/M +Taiwanese/M +Taiyuan/M +Tajikistan/M +Taklamakan/M +Talbert/M +Talbot/M +Talia/M +Taliban/M +Taliesin/M +Tallahassee/M +Tallchief/M +Talley/M +Talleyrand/M +Tallinn/M +Tallulah/M +Talmud/MS +Talmudic +Talmudist +Talya/M +Tamar/M +Tamara/M +Tamarin/M +Tamas +Tameka/M +Tamera/M +Tamerlane/M +Tami/M +Tamika/M +Tamil/MS +Tammany/M +Tammi/M +Tammie/M +Tammuz/M +Tammy/M +Tampa/M +Tampax/M +Tamra/M +Tamworth/M +Tana +Tancred/M +Tandy/M +Taney/M +Tanganyika/M +Tangier/MS +Tangshan/M +Tani/M +Tania/M +Tanisha/M +Tann/MR +Tanner/M +Tannhauser/M +Tannhuser/M +Tantalus/M +Tanya/M +Tanzania/M +Tanzanian/SM +Tao/M +Taoism/MS +Taoist/MS +Tara/M +Tarantino/M +Tarawa/M +Tarazed/M +Tarbell/M +Target/M +Tarim/M +Tarkenton/M +Tarkington/M +Tartar/MS +Tartary/M +Tartuffe/M +Taryn/M +Tarzan/M +Tasha/M +Tashkent/M +Tasman/M +Tasmania/M +Tasmanian/M +Tass/M +Tatar/MS +Tate/M +Tatiana/M +Tatum/M +Taurus/MS +Tawney/M +Taylor/M +Tb/M +Tbilisi/M +Tc/M +Tchaikovsky/M +Te/M +TeX +TeXes +Teasdale/M +TechRepublic/M +Technicolor/M +Technorati/M +Tecumseh/M +Ted/M +Teddie/M +Teddy/M +Tedi/M +Teena/M +Teflon/MS +Tegucigalpa/M +Tehran +TelePrompTer +TelePrompter/M +Telemachus/M +Telemann/M +Teletype +Tell/MR +Teller/M +Telugu/M +Tempe +Templar/M +Templeton/M +Tenn/M +Tennessean/SM +Tennessee/M +Tennyson/M +Tenochtitlan/M +Teodor/M +Teodora/M +Teodoro/M +Teotihuacan/M +Tera/M +Terence/M +Teresa/M +Terese/M +Tereshkova/M +Teresita/M +Teri/M +Terkel/M +Terpsichore/M +Terr/M +Terra/M +Terran/M +Terrance/M +Terrell/M +Terrence/M +Terri/M +Terrie/M +Terrill/M +Territory +Terry/M +Tertiary/M +Terza/M +Tesco/M +Tesla/M +Tess/M +Tessa/M +Tessie/M +Tet/M +Tethys/M +Tetons/M +Teuton/MS +Teutonic/M +Tevet/M +Tex/M +Texaco/M +Texan/MS +Texas/M +Th/M +Thacher/M +Thackeray/M +Thad/M +Thaddeus/M +Thai/SM +Thailand/M +Thales/M +Thalia/M +Thames/M +Thanh/M +Thanksgiving/MS +Thant/M +Thar/M +Tharp/M +Thatcher/M +Thatcherism +Thaxter/M +Thea/M +Thebes/M +Theda/M +Theiler/M +Thekla/M +Thelma/M +Themistocles/M +Theo/M +Theobald/M +Theocritus/M +Theodor/M +Theodora/M +Theodore/M +Theodoric/M +Theodosia/M +Theodosius/M +Theosophy/M +Theravada/M +Theresa/M +Therese/M +Thermopylae/M +Thermos +Theron/M +Theseus/M +Thespian/M +Thespis/M +Thessalonian/SM +Thessaloniki/M +Thessalonki/M +Thessaly/M +Thia/M +Thibaut/M +Thieu/M +Thimbu/M +Thimphu +Thom/M +Thoma/SM +Thomas/M +Thomasin/M +Thomasina/M +Thomism/M +Thomistic/M +Thompson/M +Thomson/M +Thor/M +Thorazine/M +Thoreau/M +Thorin/M +Thorndike +Thornton/M +Thorny's +Thoroughbred/M +Thorpe/M +Thorstein/M +Thorsten/M +Thorvald/M +Thoth/M +Thrace/M +Thracian/M +Thu +Thucydides/M +Thule/M +Thunderbird/M +Thur/S +Thurber/M +Thurman/M +Thurmond/M +Thursday/SM +Thurstan/M +Thurston/M +Thutmose/M +Ti/M +Tia/M +Tianjin/M +Tiber/M +Tiberius/M +Tibet/M +Tibetan/MS +Ticketmaster/M +Ticonderoga/M +Tide/M +Tiebout/M +Tienanmen/M +Tientsin/M +Tierney/M +Tiffany/M +Tigris/M +Tijuana/M +Tilda/M +Tildi/M +Tildy/M +Tillich/M +Tillie/M +Tillman/M +Tilly/M +Tilsit/M +Tim/M +Timbuktu/M +Timex/M +Timi/M +Timmy/M +Timon/M +Timor/M +Timotheus/M +Timothy/M +Timur/M +Timurid/M +Tina/M +Tinderbox/M +Ting/M +Tinkerbell/M +Tinkertoy/M +Tinseltown/M +Tintoretto/M +Tippecanoe/M +Tipperary/M +Tirane +Tiresias/M +Tirol/M +Tirolean +Tish/M +Tisha/M +Tishri/M +Titan/SM +Titania/M +Titanic/M +Titian/M +Titicaca/M +Tito/M +Titus/M +Tl/M +Tlaloc/M +Tlingit/M +Tm/M +Tobago/M +Tobe/M +Tobey +Tobi/M +Tobias/M +Tobie/M +Tobin/M +Tobit/M +Toby/M +Tocantins/M +Tocqueville/M +Tod/M +Todd/M +Togo/M +Togolese/M +Tojo/M +Tokay/M +Tokugawa/M +Tokyo/M +Tokyoite +Toledo/MS +Tolkien/M +Tolstoy/M +Toltec/M +Tolyatti/M +Tom/M +Toma/SM +Tomas/M +Tomaso/M +Tombaugh/M +Tomi/M +Tomlin/M +Tommie/M +Tommy/M +Tompkins/M +Tomsk/M +Tonga/M +Tongan/MS +Toni/M +Tonia/M +Tonto/M +Tony/M +Tonya/M +Tootsie/M +Topeka/M +Topsy/M +Torah/M +Torahs +Tore's +Torey/M +Tori/M +Torin/M +Toronto/M +Torquemada/M +Torr/MX +Torrance/M +Torre/SM +Torrence/M +Torrens/M +Torres/M +Torrey/M +Torricelli/M +Torrie/M +Torry/M +Tortola/M +Tortuga/M +Torvalds/M +Tory/SM +Tosca/M +Toscanini/M +Toshiba/M +Toto/M +Toulouse/M +Tova/M +Tove/M +Townes/M +Townsend/M +Toynbee/M +Toyoda/M +Toyota/M +Tracey/M +Traci/M +Tracie/M +Tracy/M +Trafalgar/M +Trailways/M +Trajan/M +Tran/M +Transcaucasia/M +Transvaal/M +Transylvania/M +Transylvanian/M +Trappist/SM +Traver/MS +Travis/M +Travolta/M +Treasury/SM +Treblinka/M +Trekkie/M +Tremain/M +Tremaine/M +Tremayne/M +Trent/M +Trenton/M +Treo/M +Trev/M +Trevelyan/M +Trevino/M +Trevor/M +Trey/M +Triangulum/M +Triassic/M +Tricia/M +Trident/M +Trieste/M +Trimurti/M +Trina/M +Trinidad/M +Trinidadian/MS +Trinity/SM +TripAdvisor/M +Tripitaka/M +Tripoli/M +Tripp/M +Trippe/M +Tris +Trish/M +Trisha/M +Trista/M +Tristan/M +Triton/M +Trix/M +Trixie/M +Trobriand/M +Troilus/M +Trojan/MS +Trollope/M +Trondheim/M +Tropicana/M +Trotsky/M +Troy/M +Troyes +Truckee/M +Trude/M +Trudeau/M +Trudi/M +Trudy/M +Trueman/M +Truffaut/M +Trujillo/M +Truman/M +Trumbull/M +Trump/M +Truth/M +Tsimshian/M +Tsiolkovsky/M +Tsitsihar/M +Tsongkhapa/M +Tswana/M +Tu/M +Tuamotu/M +Tuareg/M +Tubman/M +Tucker/M +Tucson/M +Tucuman/M +Tudor/SM +Tue/S +Tues/M +Tuesday/MS +Tulane/M +Tull/M +Tully/M +Tulsa/M +Tulsidas/M +Tums/M +Tungus/M +Tunguska/M +Tunis/M +Tunisia/M +Tunisian/MS +Tunney/M +Tupi/M +Tupperware/M +Tupungato/M +Turgenev/M +Turin/M +Turing/M +Turk/SM +Turkestan/M +Turkey/M +Turkic/MS +Turkish/M +Turkmenistan/M +Turner/M +Turpin/M +Tuscaloosa/M +Tuscan/M +Tuscany/M +Tuscarora/MS +Tuscon/M +Tuskegee/M +Tussaud/M +Tut/M +Tutankhamen/M +Tutsi/M +Tutu/M +Tuvalu/M +Tuvaluan +Twain/M +Tweed/M +Tweedledee/M +Tweedledum/M +Twila/M +Twinkies/M +Twitter/M +Twizzlers/M +Twp +Twyla/M +Ty/M +Tybalt/M +Tycho/M +Tye/M +Tylenol/M +Tyler/M +Tynan/M +Tyndale/M +Tyndall/M +Tyne/M +Tyre/M +Tyree/M +Tyrolean +Tyrone/M +Tyrus/M +Tyson/M +U/M +UAR +UAW +UBS/M +UCLA/M +UFO/SM +UHF/M +UI/SM +UK/M +UL +UN/M +UNESCO/M +UNICEF/M +UNIX/M +UPC +UPI/M +UPS/M +URL/S +US/M +USA/M +USAF +USB +USCG +USDA/M +USIA +USMC +USN +USO +USP +USPS +USS +USSR/M +UT/M +UTC +UV/M +Ubangi/M +Ubiquity/M +Ubuntu/M +Ucayali/M +Uccello/M +Udall/M +Udell/M +Ufa/M +Uganda/M +Ugandan/MS +Ugo/M +Uighur/M +Ujungpandang/M +Ukraine/M +Ukrainian/SM +Ula/M +Ulick/M +Ulises/M +Ulla/M +Ulric/M +Ulrica/M +Ulrich/M +Ulrike/M +Ulster/M +Ultrasuede/M +Ulyanovsk/M +Ulysses/M +Umberto/M +Umbriel/M +Una/M +Underwood/M +Ungava/M +Unicode/M +Unilever/M +Union/SM +Unionist +Uniroyal/M +Unitarian/MS +Unitarianism/MS +Unitas/M +Unix/S +Unukalhai/M +Upanishads/M +Updike/M +Upjohn/M +Upton/M +Ur/M +Ural/SM +Urals/M +Urania/M +Uranus/M +Urbain/M +Urban/M +Urbano/M +Urdu/M +Urey/M +Uri/SM +Uriah/M +Uriel/M +Uris/M +Urquhart/M +Ursa/M +Ursula/M +Ursuline/M +Uruguay/M +Uruguayan/MS +Urumqi/M +Usenet/MS +Ustinov/M +Ut +Uta/M +Utah/M +Utahan/MS +Ute/SM +Utopia/SM +Utopian/SM +Utrecht/M +Utrillo/M +Uzbek/M +Uzbekistan/M +Uzi/SM +V/M +VA +VAT/M +VAX +VAXes +VCR/M +VD/M +VDT +VDU +VF +VFW/M +VG +VGA +VHF/M +VHS +VI/M +VIP/SM +VISTA +VJ +VLF/M +VOA +VP +VT +VTOL +Va/M +Vachel/M +Vaclav/M +Vader/M +Vaduz/M +Vail/M +Val/M +Valarie/M +Valdemar/M +Valdez/M +Valencia/SM +Valenti/M +Valentia/M +Valentin/M +Valentina/M +Valentine/M +Valentino/M +Valenzuela/M +Valera +Valeria/M +Valerian/M +Valerie/M +Valery/M +Valhalla/M +Valium/MS +Valkyrie/SM +Valle/M +Vallejo +Valletta/M +Valli/M +Valois/M +Valparaiso/M +Valvoline/M +Valry/M +Van/M +Vance/M +Vancouver/M +Vanda/M +Vandal/MS +Vanderbilt/M +Vandyke/M +Vanessa/M +Vang/M +Vania/M +Vanna/M +Vanni/M +Vanuatu/M +Vanya/M +Vanzetti/M +Varanasi/M +Varese/M +Vargas/M +Vaseline/SM +Vasili/M +Vasily/M +Vasquez/M +Vassar/M +Vassili/M +Vassily/M +Vatican/M +Vauban/M +Vaughan/M +Vaughn/M +Vazquez/M +Veblen/M +Veda/SM +Vedanta/M +Veep +Vega/SM +Vegas/M +Vegemite/M +Vela/M +Velasquez/M +Velazquez/M +Velcro/MS +Velez/M +Velma/M +Velveeta/M +Velsquez/M +Velzquez/M +Venetian/SM +Venezuela/M +Venezuelan/SM +Venice/M +Venkman/M +Venn/M +Ventolin/M +Venus/MS +Venusian/M +Vera/M +Veracruz/M +Verde/M +Verdi/M +Verdun/M +Vere/M +Verena/M +Verizon/M +Verlaine/M +Vermeer/M +Vermont/ZMR +Vermonter/M +Vern/M +Verna/M +Verne/M +Verney/M +Vernon/M +Vernor/M +Verona/M +Veronese/M +Veronica/M +Veronika/M +Veronique +Versailles/M +Vesalius/M +Vespasian/M +Vespucci/M +Vesta/M +Vesuvius/M +Vi/M +Viacom/M +Viagra/M +Vic/M +Vicente/M +Vichy/M +Vick/M +Vicki/M +Vickie/M +Vicksburg/M +Vicky/M +Vicodin/M +Victor/M +Victoria/M +Victorian/MS +Victorianism +Victrola/M +Vida/M +Vidal/M +Vienna/M +Viennese/M +Vientiane/M +Vietcong/M +Vietminh/M +Vietnam/M +Vietnamese/M +Vijayanagar/M +Vijayawada/M +Viking/MS +Vikki/M +Vila/M +Villa/M +Villarreal/M +Villon/M +Vilma/M +Vilnius/M +Vilyui/M +Vin/M +Vina/M +Vince/M +Vincent/M +Vindemiatrix/M +Vinnie/M +Vinny/M +Vinson/M +Viola/M +Violante/M +Violet/M +Violetta/M +Violette/M +Virgie/M +Virgil/M +Virgilio/M +Virginia/M +Virginian/SM +Virginie/M +Virgo/SM +Visa/M +Visakhapatnam/M +Visayans/M +Vishnu/M +Visigoth/M +Visigoths +Vistula/M +Vite/M +Vitim/M +Vito/M +Vitoria +Vittoria/M +Vittorio/M +Vitus/M +Viv/M +Vivaldi/M +Vivekananda/M +Vivi/MN +Vivian/M +Viviana/M +Vivie/M +Vivien/M +Vivienne/M +Vlad/M +Vladimir/M +Vladivostok/M +Vlaminck/M +Vlasic/M +VoIP +Vodafone/M +Vogue/M +Volcker/M +Voldemort/M +Volga/M +Volgograd/M +Volkswagen/M +Volstead/M +Volta/M +Voltaire/M +Volvo/M +Von/M +Vonda/M +Vonnegut/M +Voronezh/M +Vorster/M +Voyager/M +Vt +Vuitton/M +Vulcan/M +Vulg +Vulgate/SM +W/MDT +WA +WAC +WASP/SM +WATS/M +WC +WHO/M +WI +WMD +WNW/M +WP +WSW/M +WTO +WV +WW +WWI +WWII +WWW/M +WY +WYSIWYG +Wabash/M +Wac +Waco/M +Wade/M +Wadsworth/M +Wagner/M +Wagnerian/M +Wahhabi/M +Waikiki/M +Wainwright/M +Waite/M +Wake/M +Wakefield +Waksman/M +Wald/MN +Waldemar/M +Walden/M +Waldensian/M +Waldheim/M +Waldo/M +Waldorf/M +Wales/M +Walesa/M +Walgreen/M +Walker/M +Walkman/M +Wall/SMR +Wallace/M +Wallas/M +Wallenstein/M +Waller/M +Wallie/M +Wallis/M +Walloon/M +Walls/M +Wally/M +Walmart/M +Walpole/M +Walpurgisnacht/M +Walsh/M +Walt/MRZ +Walter/M +Walters/M +Walther/M +Walton/M +Wanamaker/M +Wanda/M +Wang/M +Wankel/M +Warcraft/M +Ward/M +Warde/M +Ware/MG +Warhol/M +Waring/M +Warner/M +Warren/M +Warsaw/M +Warwick/M +Warwickshire/M +Wasatch/M +Wash/M +Washington/M +Washingtonian/MS +Wassermann/M +Wat/MZ +Waterbury/M +Waterford/M +Watergate/M +Waterloo/MS +Waters/M +Watkins/M +Watson/M +Watt/SM +Watteau/M +Watts/M +Watusi/M +Waugh/M +Wave +Waverley/M +Waverly/M +Wayland/M +Waylon/M +Wayne/M +Weave/RM +Weaver/M +Web/MR +WebSphere/M +Webb/M +Weber/M +Webern/M +Webster/MS +Wed/M +Weddell/M +Wedgwood/M +Wednesday/MS +Weeks/M +Wehrmacht/M +Wei/M +Weider/M +Weierstrass/M +Weill/M +Weinberg/M +Weiss/M +Weissmuller/M +Weizmann/M +Welby/M +Weldon/M +Welland/M +Weller/M +Welles/M +Wellington/SM +Wells/M +Welsh/M +Welshman/M +Welshmen/M +Welshwoman +Wendel/M +Wendell/M +Wendi/M +Wendy/M +Werner/M +Wernher/M +Wes +Wesak/M +Wesley/M +Wesleyan/M +Wessex/M +Wesson/M +West/SM +Westbrook/M +Western/MRS +Westinghouse/M +Westley/M +Westminster/M +Weston/M +Westphalia/M +Weyden/M +Wezen/M +Wharton/M +Wheaties/M +Wheatstone/M +Wheeler/M +Wheeling/M +Whig/SM +Whipple/M +Whirlpool/M +Whistler/M +Whitaker/M +Whitby/M +White/SM +Whitefield/M +Whitehall/M +Whitehead/M +Whitehorse/M +Whiteley/M +Whitfield/M +Whitley/M +Whitman/M +Whitney/M +Whitsunday/MS +Whittaker/M +Whittier/M +WiFi/M +Wicca/M +Wichita/M +Wiemar/M +Wiesel/M +Wiesenthal/M +Wiggins/M +Wigner/M +Wii/M +WikiPatents/M +Wikibooks/M +Wikileaks +Wikimedia/M +Wikinews/M +Wikipedia/M +Wikiquote/M +Wikisource/M +Wiktionary/M +Wilberforce/M +Wilbert/M +Wilbur/M +Wilburn/M +Wilcox/M +Wilda/M +Wilde/MR +Wilden/M +Wilder/M +Wiles/M +Wiley/M +Wilford/M +Wilfred/M +Wilfredo/M +Wilfrid/M +Wilhelm/M +Wilhelmina/M +Wilhelmine +Wilkerson/M +Wilkes/M +Wilkins/M +Wilkinson/M +Will/M +Willa/M +Willamette/M +Willard/M +Willem/M +Willemstad/M +Willey/M +Willi/MS +William/SM +Williams/M +Williamson/M +Willie/M +Willis/M +Willy/M +Wilma/M +Wilmer/M +Wilmette/M +Wilmington/M +Wilson/M +Wilsonian/M +Wilton/M +Wiltshire/M +Wimbledon/M +Wimsey/M +Winchell/M +Winchester/MS +Windbreaker/M +Windex/M +Windham/M +Windhoek/M +Windows/M +Windsor/SM +Windward/M +Windy's +Winesap/M +Winfield/M +Winfred/M +Winfrey/M +Winifred/M +Winkle/M +Winn/M +Winna/M +Winne/M +Winnebago/M +Winnie/M +Winnifred/M +Winnipeg/M +Winny/M +Winona/M +Winslow/M +Winston/M +Winters/M +Winthrop/M +Wis +Wisc +Wisconsin/M +Wisconsinite/MS +Wise/M +Witt/M +Wittgenstein/M +Witty's +Witwatersrand/M +Wm/M +Wobegon/M +Wodehouse/M +Wolf/M +Wolfe/M +Wolff/M +Wolfgang/M +Wollongong/M +Wollstonecraft/M +Wolsey/M +Wolverhampton +Wonder/M +Wonderbra/M +Wong/M +Wood/SM +Woodard/M +Woodhull/M +Woodie/M +Woodrow/M +Woods/M +Woodstock/M +Woodward/M +Woolf/M +Woolite/M +Woolongong/M +Woolworth/M +Wooster/M +Wooten/M +Worcester/SM +Worcestershire/M +WordPress/M +Worden/M +Wordsworth/M +Workman/M +WorldCat/M +Worms/M +Worthington/M +Wotan/M +Wovoka/M +Wozniak/M +Wozzeck/M +Wrangell/M +Wren/M +Wright/M +Wrigley/M +Wroclaw/M +Wu/M +Wuhan/M +Wurlitzer/M +Wyatt/M +Wycherley/M +Wycliffe/M +Wye/H +Wyeth/M +Wylie/M +Wyn/M +Wyndham/M +Wynn/M +Wynne/M +Wyo +Wyoming/M +Wyomingite/SM +X/M +XBL/M +XEmacs/M +XL/M +XML +XPCOM/M +XPConnect/M +XPInstall/M +XS +XUL/M +XULRunner/M +XXL +Xanadu/M +Xanax/M +Xanthippe/M +Xavier/M +Xbox/M +Xe/SM +Xena/M +Xenakis/M +Xenia/M +Xenophon/M +Xerox/MS +Xerxes/M +Xhosa/M +Xi'an/M +Xian/SM +Xiaoping/M +Ximenes/M +Ximenez/M +Xingu/M +Xiongnu/M +Xmas/MS +Xochipilli/M +Xuzhou/M +Y/M +YMCA/M +YMHA +YMMV +YT +YWCA/M +YWHA +Yacc/M +Yahoo/M +Yahtzee/M +Yahweh/M +Yakima/M +Yakut/M +Yakutsk/M +Yale/M +Yalow/M +Yalta/M +Yalu/M +Yamagata/M +Yamaha/M +Yamoussoukro/M +Yancey/M +Yancy/M +Yang/M +Yangon/M +Yangtze/M +Yank/SM +Yankee/SM +Yaobang/M +Yaounde/M +Yaqui/M +Yardley/M +Yaren +Yaroslavl/M +Yasmin/M +Yataro/M +Yates/M +Yb/M +Yeager/M +Yeats/M +Yehudi/M +Yekaterinburg/M +Yelena/M +Yellowknife/M +Yellowstone/M +Yeltsin/M +Yemen/M +Yemeni/SM +Yemenite +Yenisei/M +Yerevan/M +Yerkes/M +Yesenia/M +Yetta/M +Yevtushenko/M +Yggdrasil/M +Yiddish/M +Ymir/M +Ynez/M +Yoda/M +Yoknapatawpha/M +Yoko/M +Yokohama/M +Yolanda/M +Yolande/M +Yong/M +Yonkers/M +York/MR +Yorke/M +Yorker/M +Yorkie/M +Yorkshire/MS +Yorktown/M +Yoruba/M +Yosemite/M +Yoshi/M +Yoshiko/M +Yossarian/M +YouTube/M +Young/M +Youngstown/M +Ypres/M +Ypsilanti/M +Ysabel/M +Yuan/M +Yucatan/M +Yugo/M +Yugoslav/MS +Yugoslavia/M +Yugoslavian/SM +Yukon/M +Yul/M +Yule/SM +Yuletide/MS +Yuma/SM +Yunnan/M +Yuri/M +Yves/M +Yvette/M +Yvon/M +Yvonne/M +Yvor/M +Z/SMNXT +ZDNet/M +Zaccaria/M +Zach +Zachariah/M +Zacharias +Zachary/M +Zachery/M +Zack/M +Zagreb/M +Zahara/M +Zaire/M +Zairian +Zak/M +Zambezi/M +Zambia/M +Zambian/SM +Zamboni/M +Zamenhof/M +Zamora/M +Zane/M +Zanuck/M +Zanzibar/M +Zapata/M +Zaporozhye/M +Zapotec/M +Zappa/M +Zara/M +Zarah/M +Zarathustra/M +Zaria/M +Zea/M +Zealand/M +Zeb/M +Zebedee/M +Zebulon/M +Zechariah/M +Zedekiah/M +Zedong/M +Zeffirelli/M +Zeke/M +Zelda/M +Zelig/M +Zelma/M +Zen/M +Zena/M +Zenger/M +Zenia/M +Zeno/M +Zephaniah/M +Zephyrus/M +Zeppelin/M +Zest/M +Zeus/M +Zhang/M +Zhao/M +Zhdanov +Zhengzhou/M +Zhivago/M +Zhou/M +Zhukov/M +Zia/M +Zibo/M +Ziegfeld/M +Ziegler/M +Ziff/M +Ziggy/M +Zika +Zimbabwe/M +Zimbabwean/SM +Zimmerman/M +Zinfandel/M +Zion/SM +Zionism/SM +Zionist/SM +Ziploc/M +Zita/M +Zn/M +Zoe/M +Zola/M +Zollverein/M +Zoloft/M +Zomba/M +Zora/M +Zorn/M +Zoroaster/M +Zoroastrian/MS +Zoroastrianism/SM +Zorro/M +Zosma/M +Zr/M +Zsigmondy/M +Zubenelgenubi/M +Zubeneschamali/M +Zukor/M +Zulu/SM +Zululand +Zune/M +Zuni/M +Zurich/M +Zwingli/M +Zworykin/M +Zyrtec/M +Zyuganov/M +Zzz +Zrich/M +a/S +aah +aardvark/SM +ab/SDY +aback +abacus/MS +abaft +abalone/SM +abandon/LSDG +abandonment/M +abase/LGDS +abasement/M +abash/GLDS +abashed/UY +abashment/M +abate/LGDS +abated/U +abatement/M +abattoir/MS +abbe/SM +abbess/MS +abbey/MS +abbot/MS +abbr +abbrev/S +abbreviate/DSGNX +abbreviation/M +abb/SM +abdicate/GNDSX +abdication/M +abdomen/SM +abdominal +abduct/DSG +abductee/MS +abduction/SM +abductor/MS +abeam +aberrant +aberration/MS +aberrational +abet/S +abetted +abetter/SM +abetting +abettor/SM +abeyance/M +abhor/S +abhorred +abhorrence/M +abhorrent/Y +abhorring +abidance/M +abide/GS +abiding/Y +ability/IEMS +abject/YP +abjection/M +abjectness/M +abjuration/SM +abjuratory +abjure/ZGDRS +abjurer/M +ablate/XGNVDS +ablation/M +ablative/MS +ablaze +able/UT +abler +abloom +ablution/SM +abnegate/GNDS +abnegation/M +abnormal/Y +abnormality/SM +aboard +abode/MS +abolish/GDS +abolition/M +abolitionism/M +abolitionist/SM +abominable +abominably +abominate/DSGNX +abomination/M +aboriginal/MS +aborigine/SM +aborning +abort/GVDS +abortion/MS +abortionist/MS +abortive/Y +abound/DSG +about +above/M +aboveboard +abracadabra/M +abrade/GDS +abrasion/MS +abrasive/MYPS +abrasiveness/M +abreast +abridge/DSLG +abridgement/MS +abridgment/MS +abroad +abrogate/XGNDS +abrogation/M +abrogator/MS +abrupt/TPRY +abruptness/M +abs/M +abscess/MDSG +abscissa/SM +abscission/M +abscond/ZGSDR +absconder/M +abseil/MDSG +absence/SM +absent/DYSG +absentee/MS +absenteeism/M +absentminded/YP +absentmindedness/M +absinthe/M +absolute/PMYTNS +absoluteness/M +absolution/M +absolutism/M +absolutist/MS +absolve/DSG +absorb/AGDS +absorbance/S +absorbancy/M +absorbency/M +absorbent/SM +absorbing/Y +absorption/M +absorptive +abstain/DRZGS +abstainer/M +abstemious/PY +abstemiousness/M +abstention/MS +abstinence/M +abstinent +abstract/GSPMDY +abstracted/YP +abstractedness/M +abstraction/SM +abstractness/MS +abstruse/YP +abstruseness/M +absurd/TPRY +absurdist/MS +absurdity/SM +absurdness/M +abundance/SM +abundant/Y +abuse's +abuse/EGVDS +abuser/MS +abusive/YP +abusiveness/M +abut/SL +abutment/MS +abutted +abutting +abuzz +abysmal/Y +abyss/MS +abyssal +ac +acacia/MS +academe/M +academia/M +academic/SM +academical/Y +academician/MS +academy/SM +acanthus/MS +accede/GDS +accelerate/GNXDS +acceleration/M +accelerator/SM +accent/MDSG +accented/U +accentual +accentuate/GNDS +accentuation/M +accept/DSBG +acceptability/M +acceptableness/M +acceptably/U +acceptance/SM +acceptation/MS +accepted/U +access/MDSG +accessibility/IM +accessible/I +accessibly/I +accession/MDGS +accessorize/DSG +accessory/SM +accident/MS +accidental/SMY +acclaim/MDGS +acclamation/M +acclimate/DSGN +acclimation/M +acclimatization/M +acclimatize/DSG +acclivity/SM +accolade/SM +accommodate/XGNDS +accommodating/Y +accommodation/M +accompanied/U +accompaniment/MS +accompanist/SM +accompany/DSG +accomplice/SM +accomplish/DSLG +accomplished/U +accomplishment/MS +accord/GMDS +accordance/M +accordant +according/Y +accordion/MS +accordionist/MS +accost/GMDS +account/MDSBG +accountability/M +accountable/U +accountancy/M +accountant/MS +accounted/U +accounting/M +accouter/SGD +accouterments/M +accoutre/DSG +accoutrements +accredit/SGD +accreditation/M +accredited/U +accretion/MS +accrual/MS +accrue/GDS +acct +acculturate/DSGN +acculturation/M +accumulate/XGNVDS +accumulation/M +accumulator/MS +accuracy/IM +accurate/IY +accurateness/M +accursed/P +accursedness/M +accusation/MS +accusative/MS +accusatory +accuse/ZGDRS +accuser/M +accusing/Y +accustom/DSG +accustomed/U +ace/DSMG +acerbate/DSG +acerbic +acerbically +acerbity/M +acetaminophen/M +acetate/MS +acetic +acetone/M +acetonic +acetyl +acetylene/M +ache/DSMG +achene/MS +achieve/BLZGDRS +achievement/SM +achiever/M +aching/Y +achoo/M +achromatic +achy/TR +acid/SMY +acidic +acidify/GDS +acidity/M +acidosis/M +acidulous +acknowledge/DSGL +acknowledged/U +acknowledgement/MS +acknowledgment/SM +acme/SM +acne/M +acolyte/MS +aconite/MS +acorn/MS +acoustic/S +acoustical/Y +acoustics/M +acquaint/AGSD +acquaintance/SM +acquaintanceship/M +acquainted/U +acquiesce/DSG +acquiescence/M +acquiescent/Y +acquire/ZGBDRSL +acquirement/M +acquisition/MS +acquisitive/YP +acquisitiveness/M +acquit/S +acquittal/MS +acquitted +acquitting +acre/SM +acreage/MS +acrid/PTRY +acridity/M +acridness/M +acrimonious/YP +acrimoniousness/M +acrimony/M +acrobat/MS +acrobatic/S +acrobatically +acrobatics/M +acronym/MS +acrophobia/M +acropolis/MS +across +acrostic/SM +acrylamide +acrylic/MS +act's +act/ASDGV +actin +acting/M +actinium/M +action/ASM +actionable +activate/ICANGSD +activation/ICAM +activator/MS +active's +active/ISY +activeness/M +activism/M +activist/MS +activity/ISM +actor/AMS +actress/MS +actual/Y +actuality/SM +actualization/M +actualize/GDS +actuarial +actuary/SM +actuate/GNDS +actuation/M +actuator/SM +acuity/M +acumen/M +acupressure/M +acupuncture/M +acupuncturist/SM +acute/PMYTRS +acuteness/M +acyclovir/M +acyl +ad/SM +adage/MS +adagio/MS +adamant/MY +adapt/BZGVDRS +adaptability/M +adaptation/MS +adapter/M +adaption/S +add/SDRBZG +addend/MS +addenda +addendum/M +adder/M +addible +addict/GVMDS +addiction/SM +addition/SM +additional/Y +additive/SM +addle/GDS +address's +address/AGDS +addressable +addressed/U +addressee/SM +adduce/GDS +adenine/M +adenocarcinoma +adenoid/SM +adenoidal +adept/MYPS +adeptness/M +adequacy/IM +adequate/IY +adequateness/M +adhere/GDS +adherence/M +adherent/SM +adhesion/M +adhesive/PSM +adhesiveness/M +adiabatic +adieu/MS +adios +adipose +adis +adj +adjacency/M +adjacent/Y +adjectival/Y +adjective/MS +adjoin/GDS +adjourn/DGLS +adjournment/SM +adjudge/GDS +adjudicate/GNVXDS +adjudication/M +adjudicator/SM +adjudicatory +adjunct/MS +adjuration/MS +adjure/GDS +adjust/AGDSL +adjustable +adjuster/SM +adjustment/AMS +adjutant/SM +adman/M +admen +admin/MS +administer/DGS +administrate/XDSGNV +administration/M +administrative/Y +administrator/MS +admirably +admiral/MS +admiralty/M +admiration/M +admire/BZGDRS +admirer/M +admiring/Y +admissibility/IM +admissible/I +admissibly +admission/AM +admissions +admit/AS +admittance/M +admitted/Y +admitting/A +admix/GDS +admixture/SM +admonish/LDSG +admonishment/MS +admonition/MS +admonitory +ado/M +adobe/MS +adolescence/SM +adolescent/SM +adopt/AGVDS +adoptable +adoptee/MS +adopter/MS +adoption/SM +adorableness/M +adorably +adoration/M +adore/BZGDRS +adorer/M +adoring/Y +adorn/LGDS +adorned/U +adornment/MS +adrenal/MS +adrenalin's +adrenaline/M +adrenergic +adrift +adroit/PY +adroitness/M +adsorb/SDG +adsorbent/MS +adsorption/SM +adulate/DSGN +adulation/M +adulator/MS +adulatory +adult/MS +adulterant/MS +adulterate/GNDS +adulterated/U +adulteration/M +adulterer/SM +adulteress/MS +adulterous +adultery/SM +adulthood/M +adumbrate/GNDS +adumbration/M +adv +advance/LDSMG +advancement/SM +advantage/EDSMG +advantageous/EY +advent/SM +adventitious/Y +adventure/DRSMZG +adventurer/M +adventuresome +adventuress/MS +adventurism +adventurist/S +adventurous/YP +adventurousness/M +adverb/SM +adverbial/SMY +adversarial +adversary/SM +adverse/PRYT +adverseness/M +adversity/SM +advert/SMDG +advertise/LZGDRS +advertised/U +advertisement/MS +advertiser/M +advertising/M +advertorial/SM +advice/M +advisability/IM +advisable/I +advisably +advise/LDRSZGB +advised/UY +advisement/M +adviser/M +advisor/SM +advisory/SM +advocacy/M +advocate/MGDS +advocator/MS +advt +adware/SM +adz/MS +adze/M +aegis/M +aeon/SM +aerate/DSGN +aeration/M +aerator/SM +aerial/SMY +aerialist/MS +aerie/MS +aerobatic/S +aerobatics/M +aerobic/S +aerobically +aerobics/M +aerodrome/MS +aerodynamic/S +aerodynamically +aerodynamics/M +aerogram/S +aerogramme/S +aeronautic/S +aeronautical +aeronautics/M +aerosol/MS +aerospace/M +aesthete/MS +aesthetic/S +aesthetically +aestheticism/M +aesthetics/M +afar +affability/M +affable +affably +affair/MS +affect's +affect/EGDS +affectation/SM +affected/UY +affecting/Y +affection/EM +affectionate/Y +affections +afferent +affiance/GDS +affidavit/SM +affiliate's +affiliate/EGNDS +affiliated/U +affiliation/EM +affiliations +affinity/SM +affirm/AGDS +affirmation/AMS +affirmative/MYS +affix/GMDS +afflatus/M +afflict/GDS +affliction/SM +affluence/M +affluent/Y +afford/GDSB +affordability +affordably +afforest/EGSD +afforestation/M +affray/MS +affront/GMDS +afghan/MS +aficionado/MS +afield +afire +aflame +afloat +aflutter +afoot +aforementioned +aforesaid +aforethought +afoul +afraid/U +afresh +aft/RZ +afterbirth/M +afterbirths +afterburner/MS +aftercare/M +aftereffect/MS +afterglow/SM +afterimage/MS +afterlife/M +afterlives +aftermarket/MS +aftermath/M +aftermaths +afternoon/MS +aftershave/SM +aftershock/SM +aftertaste/SM +afterthought/SM +afterward/S +afterword/MS +again +against +agape/M +agar/M +agate/MS +agave/M +age/DSMGJ +ageing/SM +ageism/M +ageist/SM +ageless/YP +agelessness/M +agency/SM +agenda/SM +agent/AMS +ageratum/M +agglomerate/DSMGNX +agglomeration/M +agglutinate/DSXGN +agglutination/M +aggrandize/GLDS +aggrandizement/M +aggravate/GNXDS +aggravating/Y +aggravation/M +aggregate/MGNDSX +aggregation/M +aggregator/SM +aggression/M +aggressive/PY +aggressiveness/M +aggressor/SM +aggrieve/DSG +aggro +aghast +agile/Y +agility/M +aging/M +agitate/XGNDS +agitation/M +agitator/MS +agitprop/M +agleam +aglitter +aglow +agnostic/MS +agnosticism/M +ago +agog +agonist/S +agonize/GDS +agonizing/Y +agony/SM +agoraphobia/M +agoraphobic/MS +agrarian/MS +agrarianism/M +agree/EBLDS +agreeableness/EM +agreeably/E +agreeing/E +agreement/ESM +agribusiness/MS +agricultural/Y +agriculturalist/MS +agriculture/M +agriculturist/MS +agronomic +agronomist/MS +agronomy/M +aground +ague/M +ah +aha +ahchoo +ahead +ahem +ahoy +aid/SMDG +aide/SM +aided/U +aigrette/MS +ail/SDLG +aileron/SM +ailment/SM +aim/SMDG +aimless/YP +aimlessness/M +ain't +air/SMDJG +airbag/MS +airbase/SM +airbed/S +airborne +airbrush/MDSG +airbus/MS +aircraft/M +aircraftman +aircraftmen +aircrew/S +airdrome/S +airdrop/SM +airdropped +airdropping +airfare/SM +airfield/SM +airflow/M +airfoil/SM +airfreight/M +airgun/S +airhead/SM +airily +airiness/M +airing/M +airless/P +airlessness/M +airletter/S +airlift/SGMD +airline/RSMZ +airliner/M +airlock/SM +airmail/GSMD +airman/M +airmen +airplane/MS +airplay/M +airport/SM +airship/SM +airshow/S +airsick/P +airsickness/M +airspace/M +airspeed +airstrike/MS +airstrip/SM +airtight +airtime/M +airwaves/M +airway/MS +airwoman +airwomen +airworthiness/M +airworthy/P +airy/PTR +aisle/MS +aitch/MS +ajar +aka +akimbo +akin +alabaster/M +alack +alacrity/M +alarm/GMDS +alarming/Y +alarmist/SM +alas +alb/SM +albacore/SM +albatross/MS +albeit +albinism/M +albino/MS +album/MNS +albumen/M +albumin/M +albuminous +alchemist/SM +alchemy/M +alcohol/SM +alcoholic/MS +alcoholically +alcoholism/M +alcove/MS +alder/MS +alderman/M +aldermen +alderwoman/M +alderwomen +ale/SMV +aleatory +alehouse/SM +alembic/SM +alert/GMDYPS +alertness/M +alewife/M +alewives +alfalfa/M +alfresco +alga/M +algae +algal +algebra/SM +algebraic +algebraically +algorithm/SM +algorithmic +alias/GMDS +alibi/GMDS +alien/BGMDS +alienable/IU +alienate/DSGN +alienation/M +alienist/SM +alight/GDS +align/ALGDS +aligned/U +aligner/MS +alignment/AMS +alike/U +aliment/MDSG +alimentary +alimony/M +aliveness/M +aliyah/M +aliyahs +alkali/MS +alkalies +alkaline +alkalinity/M +alkalize/DSG +alkaloid/SM +alkoxy +alkyd/MS +all/M +allay/GDS +allegation/MS +allege/GDS +alleged/Y +allegiance/MS +allegoric +allegorical/Y +allegorist/MS +allegory/SM +allegretto/MS +allegro/MS +allele/MS +alleluia/SM +allergen/SM +allergenic +allergic +allergically +allergist/SM +allergy/SM +alleviate/DSGN +alleviation/M +alley/MS +alleyway/SM +alliance/SM +alligator/MS +alliterate/DSXGNV +alliteration/M +alliterative/Y +allocate/ADSGN +allocation/AM +allocations +allot/LS +allotment/SM +allotted +allotting +allover +allow/EGDS +allowable/U +allowably +allowance/SM +alloy/GMDS +alloyed/U +allspice/M +allude/GDS +allure/MGLDS +allurement/MS +alluring/Y +allusion/SM +allusive/PY +allusiveness/M +alluvial/M +alluvium/SM +ally/GDSM +almanac/SM +almighty +almond/MS +almoner/SM +almost +alms/M +almshouse/MS +aloe/SM +aloft +aloha/MS +alone +along +alongshore +alongside +aloof/PY +aloofness/M +aloud +alp/SM +alpaca/MS +alpha/MS +alphabet/SM +alphabetic +alphabetical/Y +alphabetization/SM +alphabetize/ZGDRS +alphabetizer/M +alphanumeric +alphanumerical/Y +alpine/S +already +alright +also +alt/S +altar/MS +altarpiece/SM +alter/GDBS +alterable/U +alteration/MS +altercation/SM +altered/U +alternate/DSMYGNVX +alternation/M +alternative/MYS +alternator/SM +although +altimeter/MS +altitude/MS +alto/SM +altogether +altruism/M +altruist/SM +altruistic +altruistically +alum/SM +alumina/M +aluminum/M +alumna/M +alumnae +alumni +alumnus/M +alveolar/S +always +am/N +amalgam/SM +amalgamate/XGNDS +amalgamation/M +amanuenses +amanuensis/M +amaranth/M +amaranths +amaretto/M +amaryllis/MS +amass/GDS +amateur/SM +amateurish/YP +amateurishness/M +amateurism/M +amatory +amaze/LMGDS +amazement/M +amazing/Y +amazon/MS +amazonian +ambassador/SM +ambassadorial +ambassadorship/MS +ambassadress/MS +amber/M +ambergris/M +ambiance/MS +ambidexterity/M +ambidextrous/Y +ambience/MS +ambient +ambiguity/SM +ambiguous/UY +ambit +ambition/MS +ambitious/YP +ambitiousness/M +ambivalence/M +ambivalent/Y +amble/MZGDRS +ambler/M +ambrosia/M +ambrosial +ambulance/MS +ambulanceman +ambulancemen +ambulancewoman +ambulancewomen +ambulant +ambulate/DSXGN +ambulation/M +ambulatory/SM +ambuscade/MGDS +ambush/GMDS +ameba/MS +amebae +amebic +ameboid +ameliorate/GNVDS +amelioration/M +amen/B +amenability/M +amenably +amend/BLGDS +amendment/SM +amenity/SM +amerce/GLDS +amercement/SM +americium/M +amethyst/SM +amiability/M +amiable +amiably +amicability/M +amicable +amicably +amid +amide/MS +amidship/S +amidst +amigo/MS +amino +amir/SM +amiss +amity/M +ammeter/SM +ammo/M +ammonia/M +ammonium +ammunition/M +amnesia/M +amnesiac/MS +amnesic/SM +amnesty/GDSM +amniocenteses +amniocentesis/M +amnion/MS +amniotic +amoeba/MS +amoebae +amoebic +amok +among +amontillado/SM +amoral/Y +amorality/M +amorous/YP +amorousness/M +amorphous/PY +amorphousness/M +amortization/SM +amortize/DSGB +amount/GMDS +amour/MS +amoxicillin +amp/SMY +amperage/M +ampere/MS +ampersand/MS +amphetamine/SM +amphibian/MS +amphibious/Y +amphitheater/SM +amphora/M +amphorae +ampicillin +ample/TR +amplification/M +amplifier/M +amplify/NDRSXZG +amplitude/SM +ampoule/MS +ampule/MS +amputate/GNDSX +amputation/M +amputee/MS +amt +amuck +amulet/MS +amuse/LGDS +amusement/MS +amusing/Y +amylase/M +an/CS +anabolism/M +anachronism/SM +anachronistic +anachronistically +anaconda/SM +anaerobe/SM +anaerobic +anaerobically +anagram/MS +anal/Y +analgesia/M +analgesic/SM +analog/MS +analogical/Y +analogize/GDS +analogous/YP +analogousness/M +analogue/SM +analogy/SM +analysand/MS +analyses/A +analysis/AM +analyst/SM +analytic +analytical/Y +analyticalally +analyzable +analyze/ADSG +analyzer/SM +anapest/SM +anapestic/MS +anarchic +anarchically +anarchism/M +anarchist/MS +anarchistic +anarchy/M +anathema/SM +anathematize/DSG +anatomic +anatomical/Y +anatomist/SM +anatomize/DSG +anatomy/SM +ancestor/SM +ancestral/Y +ancestress/MS +ancestry/SM +anchor/MDGS +anchorage/MS +anchorite/MS +anchorman/M +anchormen +anchorpeople +anchorperson/SM +anchorwoman/M +anchorwomen +anchovy/SM +ancient/SPMRYT +ancientness/M +ancillary/SM +and +andante/SM +andiron/SM +androgen/M +androgenic +androgynous +androgyny/M +android/SM +anecdotal/Y +anecdote/MS +anemia/M +anemic +anemically +anemometer/SM +anemone/SM +anent +anesthesia/M +anesthesiologist/SM +anesthesiology/M +anesthetic/SM +anesthetist/MS +anesthetization/SM +anesthetize/GDS +aneurysm/SM +anew +angel/MS +angelfish/MS +angelic +angelica/M +angelical/Y +anger/GMDS +angina/M +angioplasty/SM +angiosperm/SM +angle/MZGDRS +angler/M +angleworm/MS +anglicism/S +anglicize/GDS +angling/M +anglophile/S +anglophone/S +angora/MS +angostura +angrily +angry/TR +angst/M +angstrom/MS +anguish/GMDS +angular +angularity/SM +angulation +anhydrous +aniline/M +animadversion/MS +animadvert/GSD +animal/MS +animalcule/SM +animate/ADSGN +animated/Y +animation/AM +animations +animator/MS +anime/M +animism/M +animist/SM +animistic +animosity/SM +animus/M +anion/MS +anionic +anise/M +aniseed/M +anisette/M +ankh/M +ankhs +ankle/MS +anklebone/MS +anklet/MS +annalist/SM +annals/M +anneal/GDS +annelid/MS +annex/GMDS +annexation/MS +annihilate/DSGN +annihilation/M +annihilator/SM +anniversary/SM +annotate/DSXGNV +annotation/M +annotator/MS +announce/DRSLZG +announced/U +announcement/MS +announcer/M +annoy/GDS +annoyance/MS +annoying/Y +annual/MYS +annualized +annuitant/SM +annuity/SM +annul/LS +annular +annulled +annulling +annulment/SM +annunciation/SM +anode/MS +anodize/GDS +anodyne/MS +anoint/GDLS +anointment/M +anomalous/Y +anomaly/SM +anon/S +anonymity/M +anonymization/MS +anonymize/DSG +anonymous/Y +anopheles/M +anorak/MS +anorectic/SM +anorexia/M +anorexic/MS +another +answer/BMDGS +answerable/U +answered/U +answerphone/S +ant/SMD +antacid/SM +antagonism/SM +antagonist/SM +antagonistic +antagonistically +antagonize/DSG +antarctic +ante/SM +anteater/MS +antebellum +antecedence/M +antecedent/SM +antechamber/SM +antedate/GDS +antediluvian +anteing +antelope/MS +antenatal +antenna/SM +antennae +anterior +anteroom/MS +anthem/MS +anther/MS +anthill/SM +anthologist/SM +anthologize/DSG +anthology/SM +anthracite/M +anthrax/M +anthropocentric +anthropoid/MS +anthropological/Y +anthropologist/SM +anthropology/M +anthropomorphic +anthropomorphically +anthropomorphism/M +anthropomorphize/DS +anthropomorphous +anti/SM +antiabortion +antiabortionist/MS +antiaircraft +antibacterial/MS +antibiotic/MS +antibody/SM +antic/MS +anticancer +antichrist/SM +anticipate/GNXDS +anticipated/U +anticipation/M +anticipatory +anticked +anticking +anticlerical +anticlimactic +anticlimactically +anticlimax/MS +anticline/SM +anticlockwise +anticoagulant/MS +anticommunism/M +anticommunist/SM +anticyclone/SM +anticyclonic +antidemocratic +antidepressant/MS +antidote/MS +antifascist/MS +antifreeze/M +antigen/SM +antigenic +antigenicity/M +antihero/M +antiheroes +antihistamine/SM +antiknock/M +antilabor +antilogarithm/SM +antimacassar/MS +antimalarial +antimatter/M +antimicrobial +antimissile +antimony/M +antinuclear +antioxidant/MS +antiparticle/SM +antipasti +antipasto/MS +antipathetic +antipathy/SM +antipersonnel +antiperspirant/SM +antiphon/SM +antiphonal/MYS +antipodal/S +antipodean/MS +antipodes/M +antipollution +antipoverty +antiquarian/SM +antiquarianism/M +antiquary/SM +antiquate/GDS +antique/DSMG +antiquity/SM +antirrhinum/S +antiscience +antisemitic +antisemitism/M +antisense +antisepsis/M +antiseptic/SM +antiseptically +antiserum/MS +antislavery +antisocial/Y +antispasmodic/MS +antisubmarine +antitank +antitheses +antithesis/M +antithetic +antithetical/Y +antitoxin/MS +antitrust +antivenin/MS +antivenom +antiviral/MS +antivirus/M +antivivisectionist/MS +antiwar +antler/MDS +antonym/SM +antonymous +antrum +antsy/TR +anus/MS +anvil/MS +anxiety/SM +anxious/YP +anxiousness/M +any +anybody/SM +anyhow +anymore +anyone/M +anyplace +anything/SM +anytime +anyway/S +anywhere +anywise +aorta/MS +aortic +apace +apart +apartheid/M +apartment/MS +apathetic +apathetically +apathy/M +apatite/M +apatosaurus/M +ape/DSMG +apelike +aperitif/MS +aperture/SM +apex/MS +aphasia/M +aphasic/MS +aphelia +aphelion/SM +aphid/MS +aphorism/MS +aphoristic +aphoristically +aphrodisiac/SM +apiarist/SM +apiary/SM +apical/Y +apiece +apish/Y +aplenty +aplomb/M +apocalypse/SM +apocalyptic +apocrypha/M +apocryphal/Y +apogee/MS +apolitical/Y +apologetic/U +apologetically +apologia/SM +apologist/MS +apologize/GDS +apology/SM +apoplectic +apoplexy/SM +apoptosis +apoptotic +apostasy/SM +apostate/SM +apostatize/GDS +apostle/MS +apostleship/M +apostolic +apostrophe/MS +apothecary/SM +apothegm/SM +apotheoses +apotheosis/M +app/SM +appall/GDS +appalling/Y +appaloosa/MS +apparatchik/S +apparatus/MS +apparel/MDGS +apparent/Y +apparition/SM +appeal/GMDS +appealing/UY +appear/AESDG +appearance/EAMS +appease/LZGDRS +appeasement/SM +appeaser/M +appellant/SM +appellate/XN +appellation/M +append/GDS +appendage/SM +appendectomy/SM +appendices +appendicitis/M +appendix/MS +appertain/GDS +appetite/SM +appetizer/MS +appetizing/Y +applaud/ZGDRS +applauder/M +applause/M +apple/MS +applejack/M +applesauce/M +applet/MS +appliance/SM +applicability/M +applicable/I +applicably +applicant/SM +application/AM +applicator/SM +applier/MS +applique/DSM +appliqueing +appliqu/SMG +appliqud +apply/ANXGDS +appoint/AELSVGD +appointee/SM +appointment/AESM +apportion/AGDLS +apportionment/AM +appose/GDS +apposite/YNVP +appositeness/M +apposition/M +appositive/SM +appraisal/AMS +appraise/ADSG +appraiser/MS +appreciable/I +appreciably/I +appreciate/DSXGNV +appreciated/U +appreciation/M +appreciative/Y +appreciator/MS +appreciatory +apprehend/GDS +apprehension/MS +apprehensive/YP +apprehensiveness/M +apprentice/DSMG +apprenticeship/MS +apprise/GDS +approach/GBMDS +approachable/UI +approbation/EM +approbations +appropriate/PYGNXDS +appropriated/U +appropriateness/IM +appropriation/M +appropriator/SM +approval/EM +approvals +approve/EGDS +approved/U +approving/EY +approx +approximate/DSXYGN +approximation/M +appurtenance/SM +appurtenant +apricot/MS +apron/MS +apropos +apse/SM +apt/IYPT +apter +aptitude/SM +aptness/IM +aqua/SM +aquaculture/M +aqualung/MS +aquamarine/SM +aquanaut/MS +aquaplane/MGDS +aquarium/MS +aquatic/SM +aquatically +aquatics/M +aquatint/S +aquavit/M +aqueduct/MS +aqueous +aquifer/SM +aquiline +arXiv/M +arabesque/MS +arability/M +arachnid/MS +arachnophobia +arbiter/SM +arbitrage/MZGDRS +arbitrager/M +arbitrageur/SM +arbitrament/SM +arbitrarily +arbitrariness/M +arbitrary/P +arbitrate/GNDS +arbitration/M +arbitrator/MS +arbor/MS +arboreal +arboretum/SM +arborvitae/SM +arbutus/MS +arc/SMDG +arcade/MS +arcane +arch/PZTGVMDRSY +archaeoastronomy/M +archaeologic +archaeological/Y +archaeologist/SM +archaeology/M +archaeomagnetic +archaeomagnetism +archaic +archaically +archaism/MS +archaist/MS +archangel/MS +archbishop/SM +archbishopric/SM +archdeacon/SM +archdiocesan +archdiocese/MS +archduchess/MS +archduke/MS +archenemy/SM +archeological/Y +archeologist/SM +archeology/M +archer/M +archery/M +archetypal +archetype/MS +archfiend/MS +archiepiscopal +archipelago/MS +archipelagoes +architect/SM +architectonic/S +architectonics/M +architectural/Y +architecture/MS +architrave/SM +archival +archive/DSMG +archivist/MS +archness/M +archway/SM +arctic/MS +ardent/Y +ardor/MS +arduous/YP +arduousness/M +are/SMB +area/SM +areal +aren't +arena/MS +argent/M +arginine +argon/M +argosy/SM +argot/MS +arguable/IU +arguably/U +argue/ZGDRS +arguer/M +argument/MS +argumentation/M +argumentative/PY +argumentativeness/M +argyle/MS +aria/SM +arid/Y +aridity/M +aright +arise/GS +arisen +aristocracy/SM +aristocrat/SM +aristocratic +aristocratically +arithmetic/M +arithmetical/Y +arithmetician/MS +ark/SM +arm's +arm/EAGDS +armada/MS +armadillo/SM +armament/AEM +armaments +armature/MS +armband/MS +armchair/MS +armed/U +armful/MS +armhole/SM +armistice/SM +armlet/MS +armload/S +armor/ZGMDRS +armored/U +armorer/M +armorial +armory/SM +armpit/MS +armrest/SM +army/SM +aroma/MS +aromatherapist/MS +aromatherapy/M +aromatic/MS +aromatically +arose +around +arousal/M +arouse/GDS +arpeggio/MS +arr +arraign/DGSL +arraignment/SM +arrange/AESDLG +arrangement/AESM +arranger/SM +arrant +arras/MS +array/EGMDS +arrears/M +arrest/AGMDS +arrhythmia/M +arrhythmic +arrhythmical +arrival/MS +arrive/GDS +arrogance/M +arrogant/Y +arrogate/GNDS +arrogation/M +arrow/MS +arrowhead/MS +arrowroot/M +arroyo/MS +arsed +arsenal/MS +arsenic/M +arsing +arson/M +arsonist/SM +art/SM +arterial +arteriole/MS +arteriosclerosis/M +artery/SM +artful/PY +artfulness/M +arthritic/MS +arthritis/M +arthropod/MS +arthroscope/SM +arthroscopic +arthroscopy +artichoke/SM +article/MDS +articulacy/I +articular +articulate/YGNPDSX +articulateness/IM +articulation/M +artifact/SM +artifice/RSMZ +artificer/M +artificial/Y +artificiality/M +artillery/M +artilleryman/M +artillerymen +artiness/M +artisan/MS +artist/MS +artiste/MS +artistic/I +artistically +artistry/M +artless/PY +artlessness/M +artsy/TR +artwork/MS +arty/PTR +arugula +arum/SM +aryl/SM +asap +asbestos/M +ascend/AGDS +ascendance/M +ascendancy/M +ascendant/SM +ascension/MS +ascent/MS +ascertain/GDSBL +ascertainment/M +ascetic/MS +ascetically +asceticism/M +ascot/MS +ascribe/GBDS +ascription/M +aseptic +aseptically +asexual/Y +asexuality/M +ash/MDNSG +ashamed/UY +ashcan/MS +ashlar/MS +ashore +ashram/MS +ashtray/SM +ashy/TR +aside/MS +asinine/Y +asininity/SM +ask/SDG +askance +asked/U +askew +aslant +asleep +asocial +asp/SMNX +asparagus/M +aspartame/M +aspect/MS +aspen/M +asperity/SM +aspersion/MS +asphalt/MDGS +asphodel/SM +asphyxia/M +asphyxiate/DSXGN +asphyxiation/M +aspic/MS +aspidistra/MS +aspirant/MS +aspirate/MGNDSX +aspiration/M +aspirator/SM +aspire/GDS +aspirin/MS +ass/MS +assail/GBDS +assailable/U +assailant/SM +assassin/SM +assassinate/GNXDS +assassination/M +assault/MDRGS +assay/ZGMDRS +assayer/M +assemblage/SM +assemble/ERZGSD +assembler/EM +assemblies +assembly/EAM +assemblyman/M +assemblymen +assemblywoman/M +assemblywomen +assent/GMDS +assert/AGVDS +assertion/AM +assertions +assertive/YP +assertiveness/M +assess/ALGDS +assessment/ASM +assessor/MS +asset/MS +asseverate/DSGN +asseveration/M +asshole/MS! +assiduity/M +assiduous/PY +assiduousness/M +assign's +assign/ALGDS +assignable +assignation/MS +assigned/U +assignee/M +assigner/MS +assignment/AMS +assignor/MS +assimilate/DSGN +assimilation/M +assist/GMDS +assistance/M +assistant/SM +assisted/U +assize/MS +assn +assoc +associate's +associate/EDSGNV +association/EM +associations +assonance/M +assonant/MS +assort/GLDS +assortment/MS +asst +assuage/GDS +assume/BGDS +assumption/SM +assumptive +assurance/ASM +assure/AGDS +assured/MYS +astatine/M +aster/EMS +asterisk/GMDS +astern +asteroid/MS +asthma/M +asthmatic/SM +asthmatically +astigmatic +astigmatism/SM +astir +astonish/DSLG +astonishing/Y +astonishment/M +astound/GDS +astounding/Y +astraddle +astrakhan/M +astral +astray +astride +astringency/M +astringent/SMY +astroarchaeology/SM +astrobiology/M +astrobleme/S +astrolabe/SM +astrologer/SM +astrological/Y +astrologist/MS +astrology/M +astronaut/MS +astronautic/S +astronautical +astronautics/M +astronomer/SM +astronomic +astronomical/Y +astronomy/M +astrophysical +astrophysicist/MS +astrophysics/M +astute/PYTR +astuteness/M +asunder +asylum/SM +asymmetric +asymmetrical/Y +asymmetry/SM +asymptomatic +asymptotic +asymptotically +asynchronicity +asynchronous/Y +at +atavism/M +atavist/SM +atavistic +ataxia/M +ataxic/MS +ate +atelier/SM +atheism/M +atheist/MS +atheistic +atherosclerosis/M +atherosclerotic +athirst +athlete/MS +athletic/S +athletically +athleticism +athletics/M +athwart +atilt +atishoo +atlas/MS +atmosphere/MS +atmospheric/S +atmospherically +atmospherics/M +atoll/MS +atom/SM +atomic +atomically +atomize/ZGDRS +atomizer/M +atonal/Y +atonality/M +atone/LGDS +atonement/M +atop +atria +atrial +atrioventricular +atrium/M +atrocious/PY +atrociousness/M +atrocity/SM +atrophy/DSMG +atropine/M +attach/ALGDS +attache/BM +attached/U +attachment/AM +attachments +attach/MS +attack/ZGMDRS +attacker/M +attain/AGDS +attainability/M +attainable/U +attainder/M +attainment/SM +attar/M +attempt's +attempt/ASDG +attend/SDRZG +attendance/SM +attendant/SM +attended/U +attendee/SM +attention/IM +attentions +attentive/IPY +attentiveness/IM +attenuate/DSGN +attenuation/M +attest/SDG +attestation/SM +attested/U +attic/SM +attire/DSMG +attitude/SM +attitudinal +attitudinize/GDS +attn +attorney/MS +attract/SGVDB +attractant/MS +attraction/MS +attractive/UY +attractiveness/M +attribute/DSMGNVBX +attributed/U +attribution/M +attributive/MYS +attrition/M +attune/DSG +atty +atwitter +atypical/Y +aubergine/S +auburn/M +auction/MDGS +auctioneer/SM +audacious/YP +audaciousness/M +audacity/M +audibility/IM +audible/MS +audibly/I +audience/MS +audio/MS +audiological +audiologist/SM +audiology/M +audiometer/SM +audiophile/SM +audiotape/SM +audiovisual/S +audiovisuals/M +audit/GMDS +audition/SMDG +auditor/MS +auditorium/SM +auditory +auger/MS +aught/MS +augment/DRZGS +augmentation/MS +augmentative +augmenter/M +augur/GMDS +augury/SM +august/PTRY +augustness/M +auk/SM +aunt/SM +auntie/SM +aura/MS +aural/Y +aurei +aureola/M +aureole/SM +aureus +auricle/SM +auricular +aurora/SM +auscultate/GNDSX +auscultation/M +auspice/SM +auspicious/IY +auspiciousness/M +austere/RYT +austerity/SM +austral +auteur's +auteurs +authentic/IU +authentically +authenticate/XGNDS +authenticated/U +authentication/M +authenticity/M +author/SMDG +authoress/MS +authorial +authoritarian/MS +authoritarianism/M +authoritative/YP +authoritativeness/M +authority/SM +authorization/MS +authorize/AGDS +authorized/U +authorship/M +autism/M +autistic +auto/MS +autobahn/SM +autobiographer/SM +autobiographic +autobiographical/Y +autobiography/SM +autoclave/MS +autocomplete/S +autocracy/SM +autocrat/SM +autocratic +autocratically +autocross +autodidact/SM +autograph/MDG +autographs +autoimmune +autoimmunity/M +automaker/SM +automate/GNDS +automatic/SM +automatically +automation/M +automatism/M +automatize/GDS +automaton/SM +automobile/DSMG +automotive +autonomic +autonomous/Y +autonomy/M +autopilot/SM +autopsy/GDSM +autosuggestion +autoworker/MS +autumn/SM +autumnal +aux +auxiliary/SM +auxin/M +av/RZ +avail/BGMDS +availability/UM +available/U +avalanche/SM +avant-garde +avarice/M +avaricious/Y +avast +avatar/MS +avaunt +avdp +ave +avenge/ZGDRS +avenger/M +avenue/MS +average/MYGDS +averred +averring +averse/XN +aversion/M +avert/GDS +avg +avian +aviary/SM +aviation/M +aviator/MS +aviatrices +aviatrix/MS +avid/Y +avidity/M +avionic/S +avionics/M +avitaminosis/M +avocado/SM +avocation/MS +avocational +avoid/SDGB +avoidable/U +avoidably/U +avoidance/M +avoirdupois/M +avouch/DSG +avow/EDGS +avowal/ESM +avowed/Y +avuncular/Y +aw +await/GDS +awake/GS +awaken/AGDS +awakening/SM +award/GMDS +awardee/S +aware/UP +awareness/UM +awash +away +awe/DSMG +aweigh +awesome/YP +awesomeness/M +awestruck +awful/YP +awfuller +awfullest +awfulness/M +awhile +awkward/RYPT +awkwardness/M +awl/SM +awn/GJSM +awning/M +awoke +awoken +awol +awry +ax/MDSG +axe/M +axial/Y +axiom/SM +axiomatic +axiomatically +axis/M +axle/MS +axletree/SM +axolotl/SM +axon/MS +ayah/M +ayahs +ayatollah/M +ayatollahs +aye/SM +azalea/SM +azimuth/M +azimuths +azure/SM +b/KDT +baa/SMDG +babble/MZGDRS +babbler/M +babe/SM +babel/MS +baboon/MS +babushka/SM +baby/TGDRSM +babyhood/M +babyish +babysat +babysit/S +babysitter/MS +babysitting/M +baccalaureate/SM +baccarat/M +bacchanal/MS +bacchanalia/M +bacchanalian/MS +baccy +bachelor/SM +bachelorhood/M +bacillary +bacilli +bacillus/M +back/SJZGMDR +backache/MS +backbench/S +backbit +backbite/ZGRS +backbiter/M +backbitten +backboard/SM +backbone/MS +backbreaking +backchat +backcloth +backcloths +backcomb/DSG +backdate/GDS +backdoor +backdrop/MS +backer/M +backfield/SM +backfire/MGDS +backgammon/M +background/MRZS +backgrounder/M +backhand/MDRSZG +backhanded/Y +backhander/M +backhoe/MS +backing/M +backlash/MS +backless +backlog/MS +backlogged +backlogging +backpack/ZGMDRS +backpacker/M +backpacking/M +backpedal/SDG +backrest/SM +backroom/S +backscratching/M +backseat/SM +backside/SM +backslapper/SM +backslapping/M +backslash/MS +backslid +backslide/RSZG +backslider/M +backspace/DSMG +backspin/M +backstabber/MS +backstabbing +backstage/M +backstair/S +backstop/SM +backstopped +backstopping +backstory/S +backstreet/S +backstretch/MS +backstroke/MGDS +backtalk/M +backtrack/SDG +backup/MS +backward/PSY +backwardness/M +backwash/M +backwater/SM +backwoods/M +backwoodsman/M +backwoodsmen +backyard/SM +bacon/M +bacteria/M +bacterial +bactericidal +bactericide/SM +bacteriologic +bacteriological +bacteriologist/SM +bacteriology/M +bacterium/M +bad/MYP +badder +baddest +baddie/M +baddy/SM +bade +badge/MZGRS +badger/GMD +badinage/M +badlands/M +badman/M +badmen +badminton/M +badmouth/GD +badmouths +badness/M +baffle/MZGDRSL +bafflement/M +baffler/M +bag/SM +bagatelle/SM +bagel/MS +bagful/MS +baggage/M +bagged +baggie/M +baggily +bagginess/M +bagging +baggy/PTRS +bagpipe/MZRS +bagpiper/M +baguette/MS +bah +baht/SM +bail/SBGMD +bailey/S +bailiff/S +bailiwick/MS +bailout/SM +bailsman/M +bailsmen +bairn/MS +bait/SGMD +baize/M +bake/DRSMZG +baked/U +baker/M +bakery/SM +bakeshop/MS +baklava/M +baksheesh/M +balaclava/MS +balalaika/MS +balance's +balance/UDSG +balboa/SM +balcony/SM +bald/STGPDRY +balderdash/M +baldfaced +baldness/M +baldric/SM +baldy/S +bale/DRSMZG +baleen/M +baleful/PY +balefulness/M +baler/M +balk/SGMD +balky/RT +ball/SGMD +ballad/SM +balladeer/MS +balladry/M +ballast/GSMD +ballcock/MS +ballerina/SM +ballet/SM +balletic +ballgame/MS +ballgirl/S +ballgown/S +ballistic/S +ballistics/M +balloon/SGMD +balloonist/MS +ballot/SMDG +ballpark/MS +ballplayer/MS +ballpoint/MS +ballroom/MS +balls/DSG +ballsy/RT +bally +ballyhoo/SMDG +balm/SM +balminess/M +balmy/RTP +baloney/M +balsa/MS +balsam/SM +balsamic +baluster/SM +balustrade/MS +bamboo/SM +bamboozle/DSG +ban/SM +banal/Y +banality/SM +banana/SM +band's +band/ESGD +bandage/DSMG +bandana/SM +bandanna/MS +bandbox/MS +bandeau/M +bandeaux +bandit/SM +banditry/M +bandleader/S +bandmaster/SM +bandoleer/SM +bandolier/SM +bandsman/M +bandsmen +bandstand/SM +bandwagon/SM +bandwidth +bandwidths +bandy/DRSTG +bane/SM +baneful +bang/SGMDR +bangle/SM +bani +banish/GLDS +banishment/M +banister/SM +banjo/MS +banjoist/SM +bank/SZGBMDR +bankbook/SM +bankcard/SM +banker/M +banking/M +banknote/SM +bankroll/SGMD +bankrupt/SGMD +bankruptcy/SM +banned +banner/SM +banning +bannock/MS +banns/M +banquet/ZGMDRS +banqueter/M +banquette/SM +banshee/MS +bantam/SM +bantamweight/SM +banter/GSMD +bantering/Y +banyan/SM +banzai/SM +baobab/SM +bap/S +baptism/MS +baptismal +baptist/S +baptistery/SM +baptistry/SM +baptize/ZGDRS +baptized/U +baptizer/M +bar's +bar/ECUTS +barb/SZGMDR +barbacoa +barbarian/SM +barbarianism/MS +barbaric +barbarically +barbarism/SM +barbarity/SM +barbarize/DSG +barbarous/Y +barbecue/DSMG +barbel/SM +barbell/MS +barber/GMD +barberry/SM +barbershop/MS +barbie/S +barbiturate/SM +barbwire/M +barcarole/SM +bard/SM +bardic +bare/DRSPYG +bareback/D +barefaced/Y +barefoot/D +barehanded +bareheaded +barelegged +bareness/M +barf/SGMDY +barfly/SM +bargain/MDRZGS +bargainer/M +barge/MGDS +bargeman/M +bargemen +barhop/S +barhopped +barhopping +barista/MS +baritone/MS +barium/M +bark's +bark/CSGD +barkeep/ZMRS +barkeeper/M +barker/SM +barley/M +barmaid/MS +barman/M +barmen +barmy/RT +barn/SM +barnacle/MDS +barney/S +barnstorm/SDRZG +barnstormer/M +barnyard/SM +barometer/MS +barometric +barometrically +baron/MS +baronage/MS +baroness/MS +baronet/MS +baronetcy/SM +baronial +barony/SM +baroque/M +barque/SM +barrack/MDGS +barracuda/SM +barrage/MGDS +barre/MGJDS +barred/UEC +barrel/GSMD +barrelled +barrelling +barren/TPSMR +barrenness/M +barrette/SM +barricade/MGDS +barrier/MS +barring/ECU +barrio/SM +barrister/MS +barroom/MS +barrow/SM +bartender/SM +barter/ZGSMDR +barterer/M +baryon/SM +basal/Y +basalt/M +basaltic +base's +base/CDSLTG +baseball/SM +baseboard/MS +baseless +baseline/MS +basely +baseman/M +basemen +basement/CMS +baseness/M +baser +bash/GMDS +bashful/PY +bashfulness/M +bashing/M +basic/MS +basically +basil/M +basilica/MS +basilisk/MS +basin/MS +basinful/MS +basis/M +bask/SGD +basket/SM +basketball/MS +basketry/M +basketwork/M +basque/S +bass/MS +basset/SM +bassinet/MS +bassist/MS +basso/MS +bassoon/MS +bassoonist/SM +basswood/MS +bast/M +bastard/MS +bastardization/MS +bastardize/GDS +bastardy/M +baste/ZGNXDRS +baster/M +bastion/M +bat/SM +batch/MDSG +bate/KACGSD +bath/ZGMDRS +bathe/M +bather/M +bathetic +bathhouse/MS +bathing/M +bathmat/MS +bathos/M +bathrobe/SM +bathroom/SM +baths +bathtub/MS +bathwater +bathyscaph/MS +bathyscaphe/M +bathyscaphs +bathysphere/MS +batik/MS +batiste/M +batman/M +batmen +baton/MS +batsman/M +batsmen +battalion/SM +batted +batten/GSMD +batter/JZGSMDR +batterer/M +battery/SM +batting/M +battle/LDRSMZG +battleax/MS +battleaxe/M +battledore/SM +battledress +battlefield/MS +battlefront/MS +battleground/MS +battlement/SM +battler/M +battleship/SM +batty/RT +bauble/SM +baud/SM +bauxite/M +bawd/SM +bawdily +bawdiness/M +bawdy/PRT +bawl/SGMD +bay/SMDG +bayberry/SM +bayonet/SMDG +bayou/MS +bazaar/SM +bazillion/S +bazooka/SM +bbl +bdrm +be +beach/MDSG +beachcomber/SM +beachfront +beachhead/MS +beachwear/M +beacon/SM +bead/SGMD +beading/M +beadle/SM +beady/RT +beagle/SM +beak/SZMDR +beaker/M +beam/SGMD +bean/SGMD +beanbag/MS +beanfeast/S +beanie/SM +beanpole/MS +beansprout/S +beanstalk/MS +bear/SZGBJMR +bearable/U +bearably/U +beard/MDGS +beardless +bearer/M +bearing/M +bearish/PY +bearishness/M +bearlike +bearskin/MS +beast/MS +beastliness/M +beastly/TPRM +beat/SZGBMNRJ +beatable/U +beaten/U +beater/M +beatific +beatifically +beatification/M +beatify/GXNDS +beating/M +beatitude/SM +beatnik/MS +beau/SM +beaut/MS +beauteous/Y +beautician/SM +beautification/M +beautifier/M +beautiful/Y +beautify/NDRSZG +beauty/SM +beaux +beaver/SGMD +bebop/MS +becalm/GSD +became +because +beck/SM +beckon/SGD +becloud/GDS +become/S +becoming/UY +becquerel/S +bed/SM +bedaub/GSD +bedazzle/GDSL +bedazzlement/M +bedbug/SM +bedchamber/S +bedclothes/M +bedded +bedder +bedding/M +bedeck/GSD +bedevil/LGDS +bedevilment/M +bedfellow/SM +bedhead/S +bedim/S +bedimmed +bedimming +bedizen/GDS +bedlam/SM +bedpan/SM +bedpost/SM +bedraggle/GDS +bedridden +bedrock/SM +bedroll/SM +bedroom/SM +bedside/SM +bedsit/S +bedsitter/S +bedsore/SM +bedspread/SM +bedstead/SM +bedtime/SM +bee/RSMZGJ +beebread/M +beech/MS +beechnut/MS +beef/SGMD +beefburger/SM +beefcake/MS +beefiness/M +beefsteak/MS +beefy/RPT +beehive/MS +beekeeper/MS +beekeeping/M +beeline/MS +been +beep/SZGMDR +beeper/M +beer/M +beery/TR +beeswax/M +beet/SM +beetle/MGDS +beetroot/S +beeves +befall/SGN +befell +befit/S +befitted +befitting/Y +befog/S +befogged +befogging +before +beforehand +befoul/DGS +befriend/SGD +befuddle/GLDS +befuddlement/M +beg/S +began +begat +beget/S +begetter/S +begetting +beggar/MDYGS +beggary/M +begged +begging +begin/S +beginner/SM +beginning/MS +begone +begonia/SM +begot +begotten +begrime/DSG +begrudge/DSG +begrudging/Y +beguile/DRSZGL +beguilement/M +beguiler/M +beguiling/Y +beguine/SM +begum/MS +begun +behalf/M +behalves +behave/GDS +behavior/SM +behavioral/Y +behaviorism/M +behaviorist/MS +behead/DGS +beheld +behemoth/M +behemoths +behest/MS +behind/MS +behindhand +behold/NRZGS +beholder/M +behoove/DSG +beige/M +being/M +bejewel/SDG +belabor/SDG +belated/Y +belay/GDS +belch/GMDS +beleaguer/GSD +belfry/SM +belie/DS +belief/EUM +beliefs +believable/U +believably/U +believe/EDRSZG +believer/EUMS +believing/U +belittle/LDSG +belittlement/M +bell/SGMD +belladonna/M +bellboy/SM +belle/MS +belled/A +belletrist/MS +belletristic +bellhop/SM +bellicose +bellicosity/M +belligerence/M +belligerency/M +belligerent/MYS +belling/A +bellman/M +bellmen +bellow/MDGS +bellwether/MS +belly/GDSM +bellyache/MGDS +bellybutton/SM +bellyful/MS +belong/JDGS +belonging/M +beloved/SM +below +belt/SGMD +beltway/SM +beluga/MS +belying +bemire/GDS +bemoan/DGS +bemuse/LGDS +bemused/Y +bemusement/M +bench/GMDS +benchmark/MS +bend/BSZGMR +bender/M +bendy/TR +beneath +benedictine +benediction/SM +benedictory +benefaction/SM +benefactor/MS +benefactress/MS +benefice/SM +beneficence/M +beneficent/Y +beneficial/Y +beneficiary/SM +benefit/SMDG +benevolence/SM +benevolent/Y +benighted/Y +benign/Y +benignant +benignity/M +bent/SM +bentwood/M +benumb/DSG +benzene/M +benzine/M +benzyl +bequeath/DG +bequeaths +bequest/MS +berate/GDS +bereave/DSLG +bereavement/MS +bereft +beret/MS +berg/SM +beriberi/M +berk/S +berkelium/M +berm/SM +berry/GDSM +berrylike +berserk +berth/GMD +berths +beryl/MS +beryllium/M +beseech/ZGRS +beseecher/M +beseeching/Y +beseem/DSG +beset/S +besetting +beside/S +besiege/ZGDRS +besieger/M +besmear/DSG +besmirch/GDS +besom/MS +besot/S +besotted +besotting +besought +bespangle/DSG +bespatter/GSD +bespeak/SG +bespectacled +bespoke +bespoken +best/SGMD +bestial/Y +bestiality/M +bestiary/SM +bestir/S +bestirred +bestirring +bestow/DGS +bestowal/SM +bestrew/SDG +bestrewn +bestridden +bestride/SG +bestrode +bestseller/MS +bestselling +bet/SM +beta/SM +betake/GS +betaken +betcha +betel/M +bethink/SG +bethought +betide/GDS +betimes +betoken/GDS +betook +betray/DRZGS +betrayal/SM +betrayer/M +betroth/DG +betrothal/SM +betrothed/M +betroths +better/MDGLS +betterment/M +betting +bettor/MS +between +betwixt +bevel/GMDS +beverage/SM +bevvy/S +bevy/SM +bewail/DGS +beware/GDS +bewhiskered +bewigged +bewilder/LSGD +bewildering/Y +bewilderment/M +bewitch/GLDS +bewitching/Y +bewitchment/M +bey/SM +beyond +bezel/MS +bf +bhaji +bi/SMRZ +biannual/Y +bias/GMDS +biased/U +biassed +biassing +biathlon/SM +bib/SM +bible/MS +biblical +bibliographer/MS +bibliographic +bibliographical/Y +bibliography/SM +bibliophile/SM +bibulous +bicameral +bicameralism/M +bicarb/MS +bicarbonate/MS +bicentenary/SM +bicentennial/SM +bicep/MS +biceps/M +bicker/MDRZGS +bickerer/M +biconcave +biconvex +bicuspid/MS +bicycle/DRSMZG +bicycler/M +bicyclist/SM +bid/SMG +biddable +bidden/U +bidder/MS +bidding/M +biddy/SM +bide/S +bidet/MS +bidirectional/Y +biennial/MYS +biennium/MS +bier/M +biff/SGD +bifocal/S +bifocals/M +bifurcate/XDSGN +bifurcation/M +big/P +bigamist/SM +bigamous +bigamy/M +bigger +biggest +biggie/MS +biggish +bighead/SM +bighearted/P +bigheartedness/M +bighorn/SM +bight/MS +bigmouth/M +bigmouths +bigness/M +bigot/MDS +bigotry/SM +bigwig/MS +bijou/M +bijoux +bike/DRSMZG +biker/M +bikini/MS +bilabial/MS +bilateral/Y +bilberry/S +bile/M +bilge/MS +bilingual/SMY +bilingualism/M +bilious/P +biliousness/M +bilirubin +bilk/SZGDR +bilker/M +bill/SBJGMD +billboard/MS +billet/GMDS +billfold/SM +billhook/S +billiard/S +billiards/M +billing/M +billingsgate/M +billion/MHS +billionaire/SM +billionth/M +billionths +billow/GMDS +billowy +billy/SM +billycan/S +bimbo/MS +bimetallic/SM +bimetallism/M +bimonthly/SM +bin/SM +binary/SM +bind's +bind/AUGS +binder/MS +bindery/SM +binding/MS +bindweed/M +binge/MGDS +bingeing +bingo/M +binman +binmen +binnacle/SM +binned +binning +binocular/MS +binomial/SM +bio/SM +biochemical/SMY +biochemist/MS +biochemistry/M +biodegradability/M +biodegrade/DSGB +biodiesel/M +biodiversity/M +bioethics/M +biofeedback/M +biog +biographer/SM +biographic +biographical/Y +biography/SM +bioinformatic/MS +biol +biologic +biological/Y +biologist/MS +biology/M +biomass/M +biomedical +bionic/S +bionically +bionics/M +biophysical +biophysicist/MS +biophysics/M +biopic/MS +biopsy/GDSM +bioreactor/S +biorhythm/MS +biosensor/S +biosphere/SM +biosyntheses +biosynthesis +biotech/M +biotechnological +biotechnology/M +biotin/M +bipartisan +bipartisanship/M +bipartite +biped/MS +bipedal +biplane/MS +bipolar +bipolarity/M +biracial +birch/GMDS +bird/SZGMDR +birdbath/M +birdbaths +birdbrain/SMD +birdcage/S +birder/M +birdhouse/MS +birdie/MDS +birdieing +birdlike +birdlime/M +birdseed/M +birdsong +birdwatcher/SM +birdying +biretta/SM +birth/ZGMDR +birthday/MS +birther/M +birthmark/MS +birthplace/MS +birthrate/MS +birthright/MS +births/A +birthstone/SM +biscuit/SM +bisect/DGS +bisection/MS +bisector/SM +bisexual/MYS +bisexuality/M +bishop/MS +bishopric/SM +bismuth/M +bison/M +bisque/M +bistro/MS +bit/CSMG +bitch/GMDS +bitchily +bitchiness/M +bitchy/PRT +bitcoin/SM +bite/RSMZ +biter/M +biting/Y +bitmap/S +bitten +bitter/PMRYTS +bittern/SM +bitterness/M +bitters/M +bittersweet/MS +bitty/TR +bitumen/M +bituminous +bivalent +bivalve/SM +bivouac/MS +bivouacked +bivouacking +biweekly/SM +biyearly +biz/M +bizarre/Y +bk +bl/DG +blab/SM +blabbed +blabber/DGS +blabbermouth/M +blabbermouths +blabbing +black/PXTGMDNRYS +blackamoor/MS +blackball/SGMD +blackberry/GSM +blackbird/SM +blackboard/MS +blackcurrant/S +blacken/DG +blackface +blackguard/SM +blackhead/MS +blacking/M +blackish +blackjack/MDGS +blackleg/S +blacklist/MDSG +blackmail/MDRSZG +blackmailer/M +blackness/M +blackout/SM +blacksmith/M +blacksmiths +blacksnake/SM +blackthorn/SM +blacktop/SM +blacktopped +blacktopping +bladder/MS +blade/MDS +blag/S +blagged +blagging +blah/M +blahs/M +blame/BMGDRS +blameable +blameless/YP +blamelessness/M +blameworthiness/M +blameworthy/P +blammo +blanch/GDS +blancmange/MS +bland/PTRY +blandish/DSLG +blandishment/SM +blandness/M +blank/TGPMDRYS +blanket/GMDS +blankness/M +blare/MGDS +blarney/SMDG +blase +blaspheme/ZGDRS +blasphemer/M +blasphemous/Y +blasphemy/SM +blast/ZGMDRS +blaster/M +blastoff/MS +blas +blat/S +blatancy/SM +blatant/Y +blather/SMDG +blaze/MZGDRS +blazer/M +blazon/MDGS +bldg +bleach/MDRSZG +bleached/U +bleacher/M +bleak/TPRY +bleakness/M +blear +blearily +bleariness/M +bleary/PRT +bleat/GMDS +bleed/ZGRS +bleeder/M +bleeding/M +bleep/ZGMDRS +bleeper/M +blemish/GMDS +blemished/U +blench/DSG +blend/ZGMDRS +blender/M +bless/GDSJ +blessed/YP +blessedness/M +blessing/M +bletch +blew +blight/ZGMDRS +blimey +blimp/MS +blimpish +blind/PZTGMDRYS +blinder/M +blindfold/SMDG +blinding/Y +blindness/M +blindside/DSG +blini/MS +blink/ZGMDRS +blinker/MDG +blintz/MS +blintze/M +blip/SM +bliss/M +blissful/YP +blissfulness/M +blister/GMDS +blistering/Y +blistery +blithe/PYTR +blitheness/M +blither/G +blithesome +blitz/GMDS +blitzkrieg/MS +blivet/S +blizzard/SM +bloat/ZGDRS +bloatware +blob/SM +blobbed +blobbing +bloc/SM +block's +block/UGDS +blockade/MZGDRS +blockader/M +blockage/MS +blockbuster/SM +blockbusting/M +blocker/MS +blockhead/SM +blockhouse/MS +blog/SM +blogged +blogger/MS +blogging +blogroll/SM +bloke/MS +blokish +blond/PTMRS +blonde/MS +blondish +blondness/M +blood/GMDS +bloodbath/M +bloodbaths +bloodcurdling +bloodhound/SM +bloodily +bloodiness/M +bloodless/YP +bloodlessness/M +bloodletting/M +bloodline/SM +bloodmobile/MS +bloodshed/M +bloodshot +bloodstain/SMD +bloodstock/M +bloodstream/SM +bloodsucker/SM +bloodsucking +bloodthirstily +bloodthirstiness/M +bloodthirsty/RPT +bloody/PTGDRS +bloom/ZGMDRS +bloomer/M +bloop/ZGMDRS +blooper/M +blossom/GMDS +blossomy +blot/SM +blotch/GMDS +blotchy/TR +blotted +blotter/MS +blotting +blotto +blouse/MGDS +bloviate/GNDS +bloviator/MS +blow/SZGMR +blower/M +blowfly/SM +blowgun/MS +blowhard/MS +blowhole/S +blowjob/SM +blowlamp/S +blown +blowout/SM +blowpipe/SM +blowsy/RT +blowtorch/MS +blowup/MS +blowy/TR +blowzy/RT +blubber/GSMD +blubbery +bludgeon/MDGS +blue/DRSPMTG +bluebell/MS +blueberry/SM +bluebird/MS +bluebonnet/SM +bluebottle/SM +bluefish/MS +bluegill/MS +bluegrass/M +blueing/M +blueish +bluejacket/SM +bluejay/SM +bluejeans/M +blueness/M +bluenose/MS +bluepoint/MS +blueprint/MDGS +bluestocking/SM +bluesy/RT +bluet/MS +bluff/ZTGPMDRYS +bluffer/M +bluffness/M +bluing/M +bluish +blunder/MDRZGS +blunderbuss/MS +blunderer/M +blunt/PTGDRYS +bluntness/M +blur/SM +blurb/MS +blurred +blurriness/M +blurring +blurry/TRP +blurt/GDS +blush/ZGMDRS +blusher/M +bluster/MDRSZG +blusterer/M +blusterous +blustery +blvd +boa/SM +boar/SM +board/ZGMDRS +boarder/M +boarding/M +boardinghouse/MS +boardroom/MS +boardwalk/MS +boast/ZGMDRS +boaster/M +boastful/PY +boastfulness/M +boat/SZGMDR +boater/M +boathouse/MS +boating/M +boatload/S +boatman/M +boatmen +boatswain/SM +boatyard/S +bob/SM +bobbed +bobbin/MS +bobbing +bobble/MGDS +bobby/SM +bobbysoxer/SM +bobcat/MS +bobolink/SM +bobsled/SM +bobsledded +bobsledder/MS +bobsledding +bobsleigh/M +bobsleighs +bobtail/SM +bobwhite/MS +bocce/M +bocci/M +boccie/M +bock/M +bod/SMDG +bodacious +bode/S +bodega/MS +bodge/GDS +bodice/MS +bodily +bodkin/MS +body/DSM +bodybuilder/SM +bodybuilding/M +bodyguard/MS +bodysuit/SM +bodywork/M +boffin/S +boffo +bog/SM +boga +bogey/GMDS +bogeyman/M +bogeymen +bogged +bogging +boggle/GDS +boggy/TR +bogie/MS +bogon +bogosity +bogus +bogyman/M +bogymen +bohemian/SM +bohemianism/M +boil/SJZGMDR +boiler/M +boilermaker/SM +boilerplate/M +boink/GDS +boisterous/YP +boisterousness/M +bola/SM +bold/PTRY +boldface/DM +boldness/M +bole/SM +bolero/MS +bolivar/MS +bolivares +boll/SM +bollard/S +bollix/GMDS +bollocking/S +bollocks +bologna/M +bolshevik/SM +bolshie +bolshy +bolster/GMDS +bolt's +bolt/USGD +bolthole/S +bolus/MS +bomb/SJZGMDR +bombard/GDLS +bombardier/MS +bombardment/SM +bombast/M +bombastic +bombastically +bomber/M +bombproof +bombshell/SM +bombsite/S +bonanza/MS +bonbon/MS +bonce/S +bond/SGMD +bondage/M +bondholder/MS +bonding/M +bondman/M +bondmen +bondsman/M +bondsmen +bondwoman/M +bondwomen +bone/DRSMZG +bonehead/SMD +boneless +boner/M +boneshaker/S +boneyard +bonfire/MS +bong/SGMD +bongo/MS +bonhomie/M +boniness/M +bonito/MS +bonk/SZGD +bonnet/MS +bonny/TR +bonobo/MS +bonsai/M +bonus/MS +bony/PTR +boo/SMDHG +boob/SGMD +booboo/MS +booby/SM +boodle/MS +booger/S +boogeyman/M +boogeymen +boogie/MDS +boogieing +boogieman/M +boohoo/GMDS +book/SBJGMD +bookbinder/SM +bookbindery/SM +bookbinding/M +bookcase/MS +bookend/MS +bookie/MS +booking/M +bookish +bookkeeper/MS +bookkeeping/M +booklet/MS +bookmaker/SM +bookmaking/M +bookmark/SMDG +bookmobile/SM +bookplate/MS +bookseller/MS +bookselling +bookshelf/M +bookshelves +bookshop/SM +bookstall/S +bookstore/MS +bookworm/SM +boom/SZGMDR +boombox/MS +boomerang/MDGS +boon/SM +boondocks/M +boondoggle/MZGDRS +boondoggler/M +boonies/M +boor/SM +boorish/PY +boorishness/MS +boost/ZGMDRS +booster/M +boot's +boot/ASGD +bootblack/SM +bootee/MS +booth/M +booths +bootie/M +bootlace/S +bootleg/MS +bootlegged +bootlegger/MS +bootlegging/M +bootless +bootstrap/MS +bootstrapped +bootstrapping +booty/SM +booze/MZGDRS +boozer/M +boozy/TR +bop/SM +bopped +bopping +borax/M +bordello/MS +border/GMDS +borderland/MS +borderline/MS +bore/DRSMZG +boredom/M +borehole/S +borer/M +boring/Y +born/IAU +borne +boron/M +borough/M +boroughs +borrow/SDRZGJ +borrower/M +borrowing/M +borsch/M +borscht/M +borstal/S +borzoi/SM +bosh/M +bosom's +bosom/US +bosomy +boss/DSGM +bossily +bossiness/M +bossism/M +bossy/RTP +bosun/SM +bot/S +botanic +botanical/Y +botanist/SM +botany/M +botch/DRSZGM +botcher/M +both +bother/SMDG +botheration +bothersome +botnet/SM +bottle/DRSMZG +bottleneck/MS +bottler/M +bottom/SMDG +bottomless +botulinum +botulism/M +boudoir/SM +bouffant/SM +bougainvillea/MS +bough/M +boughs +bought +bouillabaisse/SM +bouillon/MS +boulder/SM +boules +boulevard/SM +bounce/DRSMZG +bouncer/M +bouncily +bounciness/M +bouncy/RTP +bound/ASMGD +boundary/SM +bounden +bounder/SM +boundless/PY +boundlessness/M +bounteous/YP +bounteousness/M +bountiful/YP +bountifulness/M +bounty/SM +bouquet/SM +bourbon/SM +bourgeois/M +bourgeoisie/M +boustrophedon +bout/MS +boutique/SM +boutonniere/MS +boutonnire/MS +bouzouki/MS +bovine/SM +bovver +bow/ZGSMDR +bowdlerization/MS +bowdlerize/DSG +bowed/U +bowel/SM +bower/M +bowl/MDRZGS +bowleg/SM +bowlegged +bowler/M +bowlful/SM +bowline/SM +bowling/M +bowman/M +bowmen +bowsprit/SM +bowstring/SM +bowwow/SM +box/ZGMDNRS +boxcar/SM +boxer/M +boxing/M +boxlike +boxroom/S +boxwood/M +boxy/RT +boy/SM +boycott/SGMD +boyfriend/MS +boyhood/SM +boyish/YP +boyishness/M +boysenberry/SM +bozo/MS +bpm +bps +bra/SM +brace/MZGDRS +bracelet/MS +bracer/M +bracero/MS +bracken/M +bracket/GMDS +brackish/P +brackishness/M +bract/MS +brad/SM +bradawl/S +bradycardia +brae/SM +brag/SM +braggadocio/SM +braggart/SM +bragged +bragger/MS +bragging +braid/GMDS +braiding/M +braille/M +brain/GMDS +brainchild/M +brainchildren/M +braininess/M +brainless/Y +brainpower +brainstorm/SMDG +brainstorming/M +brainteaser/SM +brainwash/DSG +brainwashing/M +brainwave/S +brainy/PTR +braise/GDS +brake/MGDS +brakeman/M +brakemen +bramble/MS +brambly +bran/M +branch/GMDS +branchlike +brand/ZGMDRS +branded/U +brander/M +brandish/DSG +brandy/GDSM +brash/PTRY +brashness/M +brass/MS +brasserie/MS +brassiere/MS +brassily +brassiness/M +brassy/PTR +brat/SM +bratty/RT +bratwurst/SM +bravado/M +brave/GPMYDTRS +braveness/M +bravery/M +bravo/SM +bravura/SM +brawl/SDRZGM +brawler/M +brawn/M +brawniness/M +brawny/RTP +bray/DGSM +braze/DRSZG +brazen/SDYGP +brazenness/M +brazer/M +brazier/SM +breach/GMDS +bread/GMDHS +breadbasket/SM +breadboard/SM +breadbox/MS +breadcrumb/MS +breadfruit/SM +breadline/MS +breadth/M +breadths +breadwinner/SM +break/BMZGRS +breakable/MS +breakage/MS +breakaway/MS +breakdown/MS +breaker/M +breakeven/M +breakfast/MDGS +breakfront/MS +breakneck +breakout/MS +breakpoints +breakthrough/M +breakthroughs +breakup/SM +breakwater/SM +bream/MS +breast/SMDG +breastbone/MS +breastfed +breastfeed/GS +breastplate/SM +breaststroke/SM +breastwork/MS +breath/MDRSZGB +breathalyze/ZGDRS +breathe +breather/M +breathing/M +breathless/PY +breathlessness/M +breaths +breathtaking/Y +breathy/RT +bred/I +breech/MS +breed/SRZGM +breeder/M +breeding/IM +breeze/DSMG +breezeway/SM +breezily +breeziness/M +breezy/RTP +brethren +breve/SM +brevet/SM +brevetted +brevetting +breviary/SM +brevity/M +brew/MDRZGS +brewer/M +brewery/SM +brewpub/SM +briar/SM +bribe/DRSMZG +briber/M +bribery/M +brick/SMDG +brickbat/SM +brickie/S +bricklayer/MS +bricklaying/M +brickwork/M +brickyard/S +bridal/SM +bride/SM +bridegroom/SM +bridesmaid/MS +bridge/DSMG +bridgeable/U +bridgehead/SM +bridgework/M +bridle/DSMG +bridled/U +bridleway/S +brie/MZR +brief's +brief/CSDTGJ +briefcase/SM +briefer +briefing/CM +briefly +briefness/M +brier/M +brig/MS +brigade/SM +brigadier/MS +brigand/SM +brigandage/M +brigantine/MS +bright/SPNRYXT +brighten/DRZG +brightener/M +brightness/M +brights/M +brill +brilliance/M +brilliancy/M +brilliant/MYS +brilliantine/M +brim/MS +brimful +brimless +brimmed +brimming +brimstone/M +brindle/DM +brine/M +bring/SRZG +bringer/M +brininess/M +brink/SM +brinkmanship/M +briny/RTP +brioche/SM +briquet/SM +briquette/MS +brisk/SDRYTGP +brisket/SM +briskness/M +bristle/DSMG +bristly/TR +britches/M +brittle/PRMT +brittleness/M +bro/SMH +broach/MDSG +broad/SMNRYXTP +broadband/M +broadcast/AMDGS +broadcaster/MS +broadcasting/M +broadcloth/M +broaden/DG +broadloom/M +broadminded +broadness/M +broadsheet/SM +broadside/MGDS +broadsword/SM +brocade/DSMG +broccoli/M +brochette/SM +brochure/MS +brogan/SM +brogue/SM +broil/SMDRZG +broiler/M +broke +broken/YP +brokenhearted/Y +brokenness/M +broker/SMDG +brokerage/MS +brolly/S +bromide/SM +bromidic +bromine/M +bronc/SM +bronchi +bronchial +bronchitic +bronchitis/M +bronchus/M +bronco/SM +broncobuster/SM +brontosaur/MS +brontosaurus/MS +bronze/DSMG +brooch/MS +brood/SMDRZG +brooder/M +broodily +brooding/MY +broodmare/MS +broody/RMPT +brook/SMDG +brooklet/SM +broom/SM +broomstick/MS +broth/MRZ +brothel/MS +brother/MY +brotherhood/MS +brotherliness/M +broths +brougham/SM +brought +brouhaha/SM +brow/MS +browbeat/SNG +brown/SMDRPTG +brownfield +brownie/MS +brownish +brownness/M +brownout/SM +brownstone/MS +browse/DRSMZG +browser/M +brr +bruin/SM +bruise/DRSMZG +bruiser/M +bruising/M +bruit/SDG +brunch/MDSG +brunet/SM +brunette/MS +brunt/M +brush/MDSG +brushoff/SM +brushstroke/S +brushwood/M +brushwork/M +brusque/RPYT +brusqueness/M +brutal/Y +brutality/SM +brutalization/M +brutalize/GDS +brute/SM +brutish/PY +brutishness/M +bu +bub/SM +bubble/DSMG +bubblegum/M +bubbly/RMT +bubo/M +buboes +buccaneer/SGMD +buck/MDGS +buckaroo/SM +buckboard/MS +bucket/SGMD +bucketful/MS +buckeye/MS +buckle's +buckle/UDSG +buckler/MS +buckram/M +bucksaw/MS +buckshot/M +buckskin/MS +buckteeth +bucktooth/MD +buckwheat/M +buckyball/SM +bucolic/MS +bucolically +bud/SM +budded +budding/S +buddy/SM +budge/DSG +budgerigar/MS +budget/SGMD +budgetary +budgie/SM +buff/AMDGS +buffalo/MDG +buffaloes +buffer/SMDG +buffet/SMDGJ +buffoon/SM +buffoonery/M +buffoonish +bug's +bug/CS +bugaboo/SM +bugbear/SM +bugged/C +bugger/SMDG +buggery +bugging/C +buggy/RSMT +bugle/DRSMZG +bugler/M +build/SMRZGJ +builder/M +building/M +buildup/SM +built/AI +builtin +bulb/MS +bulbous +bulge/DSMG +bulgy/RT +bulimarexia/M +bulimia/M +bulimic/SM +bulk/MDGS +bulkhead/MS +bulkiness/M +bulky/RTP +bull/MDGS +bulldog/SM +bulldogged +bulldogging +bulldoze/ZGDRS +bulldozer/M +bullet/SM +bulletin/MDGS +bulletproof/SDG +bullfight/SMRZG +bullfighter/M +bullfighting/M +bullfinch/MS +bullfrog/MS +bullhead/MDS +bullheaded/PY +bullheadedness/M +bullhorn/MS +bullion/M +bullish/YP +bullishness/M +bullock/SM +bullpen/SM +bullring/MS +bullshit/MS! +bullshitted/! +bullshitter/SM! +bullshitting/! +bullwhip/S +bully/DSMG +bulrush/MS +bulwark/MS +bum/SM +bumbag/S +bumble/DRSZG +bumblebee/SM +bumbler/M +bumf +bummed +bummer/SM +bummest +bumming +bump/MDRZGS +bumper/M +bumph +bumpiness/M +bumpkin/MS +bumptious/PY +bumptiousness/M +bumpy/PRT +bun/SM +bunch/MDSG +bunchy/RT +bunco/SMDG +buncombe/M +bundle/DSMG +bung/MDGS +bungalow/MS +bungee/SM +bunghole/MS +bungle/DRSMZG +bungler/M +bunion/SM +bunk's +bunk/CDGS +bunker/SM +bunkhouse/SM +bunko/SMDG +bunkum/M +bunny/SM +bunt/MDGSJ +bunting/M +buoy/MDGS +buoyancy/M +buoyant/Y +bur/SMY +burble/DSMG +burbs/M +burden's +burden/USGD +burdensome +burdock/M +bureau/SM +bureaucracy/SM +bureaucrat/MS +bureaucratic +bureaucratically +bureaucratization/M +bureaucratize/GDS +burg/MRZS +burgeon/DSG +burger/M +burgh/MRZ +burgher/M +burghs +burglar/MS +burglarize/GDS +burglarproof +burglary/SM +burgle/DSG +burgomaster/SM +burgundy/SM +burial/ASM +burka/SM +burl/MDS +burlap/M +burlesque/MGDS +burliness/M +burly/RPT +burn/MDRZGSB +burnable/SM +burner/M +burnish/ZGMDRS +burnisher/M +burnoose/MS +burnous/MS +burnout/MS +burnt +burp/MDGS +burr/MDGS +burrito/MS +burro/SM +burrow/SMDRZG +burrower/M +bursa/M +bursae +bursar/SM +bursary/SM +bursitis/M +burst/SMG +bury/ADSG +bus/AMS +busboy/SM +busby/SM +bused +busgirl/MS +bush/MDSGJ +bushel/SGMD +bushiness/M +bushing/M +bushman/M +bushmaster/SM +bushmen +bushwhack/DRSZG +bushwhacker/M +bushy/RPT +busily +business/MS +businesslike +businessman/M +businessmen +businessperson/SM +businesswoman/M +businesswomen +busing/M +busk/DRZGS +buskin/SM +busload/S +buss/M +bust/MDRZGS +buster/M +bustle/DSMG +busty/RZT +busy/DRSTGP +busybody/SM +busyness/M +busywork/M +but/ACS +butane/M +butch/MRSZ +butcher/MDG +butchery/SM +butler/SM +butt/MDRZGS +butte/SM +butted/A +butter/MDG +butterball/MS +buttercream +buttercup/SM +butterfat/M +butterfingered +butterfingers/M +butterfly/GDSM +buttermilk/M +butternut/SM +butterscotch/M +buttery/TRSM +butting/A +buttock/SM +button's +button/USDG +buttonhole/DSMG +buttonwood/MS +buttress/MDSG +butty/S +buxom +buy/ZGSMR +buyback/SM +buyer/M +buyout/SM +buzz/MDRSZG +buzzard/MS +buzzer/M +buzzkill/SM +buzzword/SM +bx +bxs +by/M +bye/SM +bygone/SM +bylaw/SM +byline/SM +bypass/GMDS +bypath/M +bypaths +byplay/M +byproduct/MS +byre/S +byroad/SM +bystander/MS +byte/MS +byway/SM +byword/SM +byzantine +c/IES +cDNA +ca +cab/SMRZ +cabal/MS +cabala/M +caballero/MS +cabana/SM +cabaret/SM +cabbage/MS +cabbed +cabbie/M +cabbing +cabby/SM +cabdriver/SM +cabin/MS +cabinet/SM +cabinetmaker/MS +cabinetmaking/M +cabinetry/M +cabinetwork/M +cable/MGDS +cablecast/GMS +cablegram/MS +cabochon/SM +caboodle/M +caboose/SM +cabriolet/SM +cabstand/SM +cacao/MS +cache/MGDS +cachepot/SM +cachet/MS +cackle/MZGDRS +cackler/M +cacophonous +cacophony/SM +cacti +cactus/M +cad/SM +cadaver/SM +cadaverous +caddie/MDS +caddish/YP +caddishness/M +caddying +cadence/DSM +cadenza/SM +cadet/MS +cadge/ZGDRS +cadger/M +cadmium/M +cadre/MS +caducei +caduceus/M +caesarean/MS +caesura/SM +cafe/SM +cafeteria/MS +cafetiere/S +caff/CS +caffeinated +caffeine/M +caftan/MS +caf/SM +cage/DSMG +cagey +cagier +cagiest +cagily +caginess/M +cagoule/S +cahoot/MS +caiman/MS +cairn/MS +caisson/SM +caitiff/SM +cajole/ZGLDRS +cajolement/M +cajoler/M +cajolery/M +cake/DSMG +cakewalk/SM +cal +calabash/MS +calaboose/SM +calamari/SM +calamine/M +calamitous/Y +calamity/SM +calcareous +calciferous +calcification/M +calcify/GNDS +calcimine/DSMG +calcine/DSG +calcite/M +calcium/M +calculable/I +calculate/AGNVDSX +calculated/Y +calculating/Y +calculation/AM +calculator/SM +calculi +calculus/M +caldera/SM +caldron/SM +calendar/MDGS +calender's +calf/M +calfskin/M +caliber/SM +calibrate/GNDSX +calibration/M +calibrator/SM +calico/MS +calicoes +californium/M +caliper/SGMD +caliph/M +caliphate/MS +caliphs +calisthenic/S +calisthenics/M +calk/SGMD +call/ASGMD +calla/MS +callable +callback/MS +called/U +caller/MS +calligrapher/SM +calligraphic +calligraphist/MS +calligraphy/M +calling/SM +calliope/MS +callosity/SM +callous/PGDSY +callousness/M +callow/RPT +callowness/M +callus/MDSG +calm/PSTGMDRY +calmness/M +caloric +calorie/MS +calorific +calumet/MS +calumniate/GNDS +calumniation/M +calumniator/MS +calumnious +calumny/SM +calve/GDS +calypso/MS +calyx/MS +cam/SM +camaraderie/M +camber/MDSG +cambial +cambium/SM +cambric/M +camcorder/SM +came +camel/MS +camelhair/M +camellia/MS +cameo/MS +camera/MS +cameraman/M +cameramen +camerawoman/M +camerawomen +camerawork +camiknickers +camisole/SM +camomile/SM +camouflage/MZGDRS +camouflager/M +camp's +camp/CSGD +campaign/SMDRZG +campaigner/M +campanile/SM +campanologist/MS +campanology/M +camper/MS +campfire/SM +campground/SM +camphor/M +camping/M +campsite/SM +campus/MS +campy/TR +camshaft/SM +can't +can/SMDRZG +canal/MS +canalization/M +canalize/GDS +canape/MS +canap/MS +canard/MS +canary/SM +canasta/M +cancan/MS +cancel/DRSZG +canceler/M +cancellation/SM +cancelled/U +canceller/M +cancelling +cancer/MS +cancerous +candelabra/SM +candelabrum/M +candid/YP +candida +candidacy/SM +candidate/MS +candidature/SM +candidness/M +candle/MZGDRS +candlelight/M +candlelit +candlepower/M +candler/M +candlestick/MS +candlewick/SM +candor/M +candy/GDSM +candyfloss +cane/SM +canebrake/MS +caner/M +canine/MS +canister/SM +canker/GMDS +cankerous +cannabis/MS +canned +cannelloni/M +cannery/SM +cannibal/SM +cannibalism/M +cannibalistic +cannibalization/M +cannibalize/GDS +cannily/U +canniness/M +canning +cannon/GMDS +cannonade/MGDS +cannonball/SM +cannot +canny/UTR +canoe/MDS +canoeing +canoeist/SM +canola/M +canon/MS +canonical/Y +canonicalization/MS +canonicalize/GDS +canonization/SM +canonize/DSG +canoodle/DSG +canopy/GDSM +canst +cant's +cant/CZRDGS +cantabile +cantaloupe/SM +cantankerous/PY +cantankerousness/M +cantata/MS +canteen/MS +canter/CM +cantered +cantering +canticle/MS +cantilever/MDGS +canto/MS +canton/MLS +cantonal +cantonment/MS +cantor/MS +canvas/MGDS +canvasback/SM +canvass/MDRSZG +canvasser/M +canyon/MGS +cap/SMDRBZ +capabilities +capability/IM +capable/I +capably/I +capacious/PY +capaciousness/M +capacitance/M +capacities +capacitor/SM +capacity/IM +caparison/MDGS +cape/SM +caper/GMD +capeskin/M +capillarity/M +capillary/SM +capita +capital/MSY +capitalism/M +capitalist/SM +capitalistic +capitalistically +capitalization/M +capitalize/ADSG +capitation/CSM +capitol/SM +capitulate/ADSXGN +capitulation/AM +caplet/MS +capo/SM +capon/MS +capped/UA +capping/UA +cappuccino/SM +caprice/SM +capricious/PY +capriciousness/M +capsicum/SM +capsize/DSG +capstan/SM +capstone/MS +capsular +capsule/DSMG +capsulize/DSG +capt +captain/SMDG +captaincy/SM +caption/SMDG +captious/YP +captiousness/M +captivate/DSGN +captivation/M +captivator/SM +captive/SM +captivity/SM +captor/MS +capture/ADSMG +car/SMDRZG +carafe/MS +caramel/SM +caramelize/DSG +carapace/SM +carat/MS +caravan/SM +caravansarai/S +caravansary/SM +caravanserai/M +caravel/SM +caraway/SM +carbide/SM +carbine/SM +carbohydrate/SM +carbolic +carbon/MS +carbonaceous +carbonate/MGNDS +carbonation/M +carboniferous +carbonize/GDS +carborundum/M +carboxylic +carboy/MS +carbs +carbuncle/SM +carbuncular +carburetor/SM +carcass/MS +carcinogen/SM +carcinogenic/MS +carcinogenicity/M +carcinoma/MS +card/ESGMD +cardamom/SM +cardamon/S +cardboard/M +carder/MS +cardholder/S +cardiac +cardie/S +cardigan/SM +cardinal/SMY +cardio +cardiogram/SM +cardiograph/M +cardiographs +cardiologist/MS +cardiology/M +cardiomyopathy +cardiopulmonary +cardiovascular +cardsharp/MRZS +cardsharper/M +care/SM +careen/DGS +career/MDGS +careerism +careerist/SM +carefree +careful/YP +carefuller +carefullest +carefulness/M +caregiver/SM +careless/PY +carelessness/M +carer/M +caress/MDSG +caret/MS +caretaker/MS +careworn +carfare/M +cargo/M +cargoes +carhop/MS +caribou/SM +caricature/MGDS +caricaturist/SM +caries/M +carillon/SM +caring/M +carious +carjack/JSDRZG +carjacker/M +carjacking/M +carload/SM +carmine/SM +carnage/M +carnal/Y +carnality/M +carnation/IMS +carnelian/MS +carney/MS +carnie/M +carnitas +carnival/MS +carnivora +carnivore/SM +carnivorous/PY +carnivorousness/M +carny/SM +carob/MS +carol/ZGMDRS +caroler/M +carom/GMDS +carotene/M +carotid/SM +carousal/SM +carouse/DRSMZG +carousel/SM +carouser/M +carp/SZGMDR +carpal/MS +carpel/MS +carpenter/MDGS +carpentry/M +carper/M +carpet/MDGS +carpetbag/MS +carpetbagged +carpetbagger/MS +carpetbagging +carpeting/M +carpi +carpool/SMDG +carport/SM +carpus/M +carrel/MS +carriage/SM +carriageway/S +carrier/M +carrion/M +carrot/MS +carroty +carry/ZGDRSM +carryall/SM +carrycot/S +carryout +carryover/MS +carsick/P +carsickness/M +cart/SZGMDR +cartage/M +cartel/MS +carter/M +carthorse/SM +cartilage/SM +cartilaginous +cartload/SM +cartographer/SM +cartographic +cartography/M +carton/MS +cartoon/SMDG +cartoonist/MS +cartridge/MS +cartwheel/GMDS +carve/JZGDRS +carver/M +carvery/S +carving/M +caryatid/MS +casaba/MS +cascade/DSMG +cascara/SM +case/LDSJMG +casebook/S +cased/U +caseharden/DGS +casein/M +caseload/MS +casement/MS +casework/ZMR +caseworker/M +cash/GMDS +cashback/M +cashbook/MS +cashew/MS +cashier/GSMD +cashless +cashmere/M +casing/M +casino/MS +cask/SM +casket/MS +cassava/SM +casserole/DSMG +cassette/MS +cassia/MS +cassock/SM +cassowary/SM +cast/ASGM +castanet/MS +castaway/MS +caste/JMZRS +castellated +caster/M +castigate/DSGN +castigation/M +castigator/SM +casting/AM +castle/MGDS +castoff/SM +castor/MS +castrate/GNXDS +castration/M +casual/PMYS +casualness/M +casualty/SM +casuist/SM +casuistic +casuistry/M +cat/SM +cataclysm/MS +cataclysmal +cataclysmic +catacomb/SM +catafalque/MS +catalepsy/M +cataleptic/MS +catalog/ZGSMDR +cataloger/M +catalogue/DSMG +catalogued/U +catalpa/SM +catalyses +catalysis/M +catalyst/MS +catalytic/M +catalyze/GDS +catamaran/SM +catapult/GMDS +cataract/MS +catarrh/M +catastrophe/MS +catastrophic +catastrophically +catatonia/M +catatonic/SM +catbird/SM +catboat/SM +catcall/GSMD +catch/ZGJLMRS +catchall/MS +catcher/M +catchment/MS +catchpenny +catchphrase/SM +catchword/MS +catchy/RT +catechism/SM +catechist/SM +catechize/DSG +categorical/Y +categorization/MS +categorize/GDS +category/SM +cater/ZGJDRS +catercorner +caterer/M +caterpillar/MS +caterwaul/SMDG +catfish/MS +catgut/M +catharses +catharsis/M +cathartic/SM +cathedral/SM +catheter/SM +catheterize/DSG +cathode/SM +cathodic +catholic +catholicity/M +cation/MS +catkin/MS +catlike +catnap/MS +catnapped +catnapping +catnip/M +catsuit/S +catsup/MS +cattail/SM +catted +cattery/S +cattily +cattiness/M +catting +cattle/M +cattleman/M +cattlemen +catty/TPR +catwalk/SM +caucus/MDSG +caudal/Y +caught/U +cauldron/MS +cauliflower/SM +caulk/ZGMDRS +caulker/M +causal/Y +causality/SM +causation/M +causative +cause/MZGDRS +causeless +causer/M +causerie/SM +causeway/SM +caustic/SM +caustically +causticity/M +cauterization/M +cauterize/GDS +caution/SMDG +cautionary +cautious/IY +cautiousness/M +cavalcade/MS +cavalier/SMY +cavalry/SM +cavalryman/M +cavalrymen +cave/DRSMZG +caveat/MS +caveman/M +cavemen +cavern/MS +cavernous/Y +caviar/M +cavil/ZGJMDRS +caviler/M +caving/M +cavity/FSM +cavort/DGS +caw/SMDG +cay/CSM +cayenne/M +cayuse/MS +cc +cease/CMGDS +ceasefire/MS +ceaseless/YP +ceaselessness/M +ceca +cecal +cecum/M +cedar/MS +cede/FAGSD +ceder/MS +cedilla/SM +ceilidh +ceilidhs +ceiling/MS +celandine/M +celeb/S +celebrant/SM +celebrate/DSGNX +celebration/M +celebrator/SM +celebratory +celebrity/SM +celeriac +celerity/M +celery/M +celesta/MS +celestial/Y +celibacy/M +celibate/MS +cell/SMD +cellar/MS +cellist/SM +cellmate/SM +cello/MS +cellophane/M +cellphone/MS +cellular/SM +cellulite/M +cellulitis +celluloid/M +cellulose/M +cement/MDRZGS +cementer/M +cementum/M +cemetery/SM +cenobite/MS +cenobitic +cenotaph/M +cenotaphs +censer/MS +censor/MDGS +censored/U +censorial +censorious/PY +censoriousness/M +censorship/M +censure/BDRSMZG +censurer/M +census/MDSG +cent/SZMR +centaur/SM +centavo/SM +centenarian/MS +centenary/SM +centennial/MYS +center/MDG +centerboard/SM +centerfold/MS +centerpiece/MS +centigrade +centigram/SM +centiliter/MS +centime/SM +centimeter/MS +centipede/SM +central/SMY +centralism +centralist +centrality/M +centralization/CM +centralize/CGDS +centralizer/MS +centrifugal/Y +centrifuge/DSMG +centripetal/Y +centrism/M +centrist/MS +centurion/SM +century/SM +cephalic +ceramic/SM +ceramicist/SM +ceramics/M +ceramist/MS +cereal/MS +cerebellar +cerebellum/SM +cerebra +cerebral +cerebrate/GNDS +cerebration/M +cerebrovascular +cerebrum/MS +cerement/MS +ceremonial/SMY +ceremonious/UY +ceremoniousness/M +ceremony/SM +cerevisiae/MS +cerise/M +cerium/M +cermet/M +cert/S +certain/UY +certainty/USM +certifiable +certifiably +certificate/MGDS +certification's +certify/CDSNXG +certitude/IM +certitudes +cerulean/M +cervical +cervices +cervix/M +cesarean/MS +cesium/M +cessation/MS +cession/KAFSM +cesspit/S +cesspool/MS +cetacean/MS +cf +cg +ch/IFVT +chad/S +chafe/GDS +chaff/GMDS +chaffinch/MS +chagrin/GSMD +chain's +chain/UGDS +chainsaw/MDGS +chair/GMDS +chairlift/MS +chairman/M +chairmanship/SM +chairmen +chairperson/SM +chairwoman/M +chairwomen +chaise/MS +chalcedony/M +chalet/MS +chalice/SM +chalk/GMDS +chalkboard/SM +chalkiness/M +chalky/PRT +challenge/DRSMZG +challenged/U +challenger/M +challis/M +chamber/SMD +chamberlain/MS +chambermaid/MS +chambray/M +chameleon/SM +chamois/M +chamomile/MS +champ/ZGMDS +champagne/MS +champion/GMDS +championship/MS +chance/MGDS +chancel/SM +chancellery/SM +chancellor/MS +chancellorship/M +chancery/SM +chanciness/M +chancre/SM +chancy/PRT +chandelier/SM +chandler/MS +change/MZGDRS +changeability/M +changeable/P +changeableness/M +changeably +changed/U +changeless/Y +changeling/SM +changeover/SM +changer/M +changing/U +channel/GSMD +channelization/M +channelize/DSG +chanson/SM +chant/ZGMDRS +chanter/M +chanteuse/MS +chantey/SM +chanticleer/MS +chaos/M +chaotic +chaotically +chap/SM +chaparral/SM +chapati/S +chapatti/S +chapbook/MS +chapeau/SM +chapel/MS +chaperon/MDGS +chaperonage/M +chaperone/SM +chaperoned/U +chaplain/MS +chaplaincy/SM +chaplet/SM +chapped +chapping +chappy/S +chapter/SM +char/SM +charabanc/MS +character/MS +characterful +characteristic/SM +characteristically/U +characterization/MS +characterize/DSG +characterless +charade/SM +charbroil/GDS +charcoal/MS +charcuterie +chard/M +chardonnay/SM +charge/AESDGM +chargeable/A +charged/U +charger/SM +charily +chariness/M +chariot/SM +charioteer/MS +charisma/M +charismatic/MS +charitable/P +charitableness/M +charitably/U +charity/SM +charlady/S +charlatan/SM +charlatanism/M +charlatanry/M +charlie/S +charm/ZGMDRS +charmer/M +charming/Y +charmless +charred +charring +chart/GMDS +charted/U +charter's +charter/ASGD +charterer/MS +chartreuse/M +charwoman/M +charwomen +chary/TRP +chase/MZGDRS +chaser/M +chasm/MS +chassis/M +chaste/PYTR +chasten/DGS +chasteness/M +chastise/DRSZGL +chastisement/SM +chastiser/M +chastity/M +chasuble/SM +chat/SM +chateau/SM +chateaux +chatelaine/SM +chatline/S +chatroom/M +chatted +chattel/MS +chatter/MDRZGS +chatterbox/MS +chatterer/M +chattily +chattiness/M +chatting +chatty/TPR +chauffeur/GMDS +chauvinism/M +chauvinist/SM +chauvinistic +chauvinistically +cheap/PXTNRY +cheapen/DG +cheapness/M +cheapo +cheapskate/MS +cheat/ZGMDRS +cheater/M +check's/A +check/UAGDS +checkbook/SM +checkbox +checker/MDGS +checkerboard/SM +checkers/M +checklist/MS +checkmate/MGDS +checkoff/SM +checkout/SM +checkpoint/SM +checkroom/MS +checksum +checkup/MS +cheddar/M +cheek/GMDS +cheekbone/SM +cheekily +cheekiness/M +cheeky/TPR +cheep/GMDS +cheer/ZGMDRS +cheerer/M +cheerful/YP +cheerfuller +cheerfullest +cheerfulness/M +cheerily +cheeriness/M +cheerio/MS +cheerleader/SM +cheerless/PY +cheerlessness/M +cheery/TPR +cheese/MGDS +cheeseboard/S +cheeseburger/SM +cheesecake/SM +cheesecloth/M +cheeseparing/M +cheesiness/M +cheesy/TPR +cheetah/M +cheetahs +chef/SM +chem +chemical/SMY +chemise/MS +chemist/MS +chemistry/SM +chemo/M +chemotherapeutic +chemotherapy/M +chemurgy/M +chenille/M +cherish/DSG +cheroot/MS +cherry/SM +chert/M +cherub/MS +cherubic +cherubim +chervil/M +chess/M +chessboard/MS +chessman/M +chessmen +chest/MDS +chesterfield/SM +chestful/SM +chestnut/SM +chesty/TR +chevalier/SM +cheviot/M +chevron/MS +chew/SZGMDR +chewer/M +chewiness/M +chewy/PTR +chg +chge +chi/SM +chiaroscuro/M +chic/PTMR +chicane/MS +chicanery/SM +chichi/MS +chick/XMNS +chickadee/SM +chicken/MDG +chickenfeed/M +chickenhearted +chickenpox/M +chickenshit/MS! +chickpea/SM +chickweed/M +chicle/M +chicness/M +chicory/SM +chide/GDS +chiding/Y +chief/TMRYS +chiefdom/M +chieftain/MS +chieftainship/SM +chiffon/M +chiffonier/MS +chigger/MS +chignon/MS +chihuahua/SM +chilblain/SM +child/M +childbearing/M +childbirth/M +childbirths +childcare/M +childhood/SM +childish/YP +childishness/M +childless/P +childlessness/M +childlike +childminder/S +childminding +childproof/GSD +children/M +chili/M +chilies +chill/JPZTGMDRS +chiller/M +chilliness/M +chilling/Y +chillness/M +chilly/TPR +chimaera/MS +chime/MZGDRS +chimer/M +chimera/MS +chimeric +chimerical +chimney/MS +chimp/MS +chimpanzee/SM +chin/SM +china/M +chinaware/M +chinchilla/MS +chine/MS +chink/GMDS +chinless +chinned +chinning +chino/MS +chinstrap/MS +chintz/M +chintzy/RT +chinwag/S +chip/SM +chipboard +chipmunk/SM +chipolata/S +chipped +chipper/MS +chippie +chipping/S +chippy/S +chirography/M +chiropodist/MS +chiropody/M +chiropractic/SM +chiropractor/SM +chirp/GMDS +chirpily +chirpy/PTR +chirrup/GMDS +chisel/ZGMDRS +chiseler/M +chiselled +chiseller/MS +chiselling +chit/SM +chitchat/SM +chitchatted +chitchatting +chitin/M +chitinous +chitlins/M +chitosan +chitterlings/M +chivalrous/PY +chivalrousness/M +chivalry/M +chive/MS +chivvy/GDS +chivy/GDS +chlamydia/MS +chlamydiae +chloral/M +chlordane/M +chloride/MS +chlorinate/GNDS +chlorination/M +chlorine/M +chlorofluorocarbon/SM +chloroform/SGMD +chlorophyll/M +chloroplast/MS +chm +choc/S +chock/GMDS +chockablock +chocoholic/SM +chocolate/MS +chocolatey +chocolaty +choice/MTRS +choir/MS +choirboy/MS +choirmaster/SM +choke/MZGDRS +chokecherry/SM +choker/M +cholecystectomy +cholecystitis +choler/M +cholera/M +choleric +cholesterol/M +chomp/ZGMDRS +choose/ZGRS +chooser/M +choosiness/M +choosy/TPR +chop/SM +chophouse/SM +chopped +chopper/MDGS +choppily +choppiness/M +chopping +choppy/TPR +chopstick/SM +choral/MYS +chorale/MS +chord/MS +chordal +chordate/SM +chore/MS +chorea/M +choreograph/DRZG +choreographer/M +choreographic +choreographically +choreographs +choreography/M +chorister/SM +choroid/MS +chortle/MZGDRS +chortler/M +chorus/GMDS +chose +chosen +chow/SGMD +chowder/MS +chrism/M +christen/ASGD +christening/MS +christian/U +christology +chromatic +chromatically +chromatin/M +chromatography +chrome/MGDS +chromium/M +chromosomal +chromosome/MS +chronic +chronically +chronicle/DRSMZG +chronicler/M +chronograph/M +chronographs +chronological/Y +chronologist/MS +chronology/SM +chronometer/SM +chrysalis/MS +chrysanthemum/MS +chub/SM +chubbiness/M +chubby/TPR +chuck/GMDS +chuckhole/SM +chuckle/MGDS +chuffed +chug/SM +chugged +chugging +chukka/MS +chum/SM +chummed +chummily +chumminess/M +chumming +chummy/PTR +chump/MS +chunder/GDS +chunk/GMDS +chunkiness/M +chunky/PTR +chunter/DGS +church/MS +churchgoer/SM +churchgoing/M +churchman/M +churchmen +churchwarden/MS +churchwoman +churchwomen +churchyard/SM +churl/MS +churlish/PY +churlishness/M +churn/ZGMDRS +churner/M +chute/MS +chutney/MS +chutzpah/M +chyme/M +chteau/M +chteaux +chtelaine/SM +ciabatta/SM +ciao/S +cicada/MS +cicatrices +cicatrix/M +cicerone/SM +ciceroni +cider's +cider/S +cigar/MS +cigarette/MS +cigarillo/MS +cilantro/M +cilia +cilium/M +cinch/GMDS +cinchona/SM +cincture/SM +cinder/GMDS +cine +cinema/MS +cinematic +cinematographer/MS +cinematographic +cinematography/M +cinnabar/M +cinnamon/M +cipher's +cipher/CGDS +ciphertext/S +cir +circa +circadian +circle/MGDS +circlet/MS +circuit/MDGS +circuital +circuitous/YP +circuitousness/M +circuitry/M +circuity/M +circular/SMY +circularity/M +circularize/DSG +circulate/ADSG +circulation/SM +circulatory +circumcise/XDSGN +circumcised/U +circumcision/M +circumference/MS +circumferential +circumflex/MS +circumlocution/MS +circumlocutory +circumnavigate/XGNDS +circumnavigation/M +circumpolar +circumscribe/GDS +circumscription/MS +circumspect/Y +circumspection/M +circumstance/MGDS +circumstantial/Y +circumvent/DSG +circumvention/M +circus/MS +cirque/MS +cirrhosis/M +cirrhotic/SM +cirri +cirrus/M +cistern/MS +cit +citadel/MS +citation/AMS +cite's +cite/IAGSD +citified +citizen/MS +citizenry/M +citizenship/M +citric +citron/MS +citronella/M +citrous +citrus/MS +city/SM +citywide +civet/MS +civic/S +civically +civics/M +civil/UY +civilian/MS +civility/ISM +civilization/MS +civilize/GDS +civilized/U +civvies/M +ck +cl +clack/GMDS +clad/U +cladding/M +claim's +claim/CKEAGDS +claimable/AKE +claimant/MS +claimed/U +claimer/ECSM +clairvoyance/M +clairvoyant/MS +clam/SM +clambake/MS +clamber/ZGMDRS +clamberer/M +clammed +clammily +clamminess/M +clamming +clammy/PTR +clamor/GMDS +clamorous +clamp/GMDS +clampdown/MS +clan/SM +clandestine/Y +clang/ZGMDRS +clangor/M +clangorous/Y +clank/GMDS +clannish/P +clannishness/M +clansman/M +clansmen +clanswoman +clanswomen +clap/SM +clapboard/MDGS +clapped +clapper/MS +clapperboard/S +clapping/M +claptrap/M +claque/MS +claret/MS +clarification/M +clarify/XDSNG +clarinet/SM +clarinetist/SM +clarinettist/MS +clarion/MDGS +clarity/M +clash/GMDS +clasp's +clasp/UGDS +class/GMDS +classic/MS +classical/MY +classicism/M +classicist/MS +classifiable +classification/CAM +classifications +classified's +classified/U +classifieds +classifier/MS +classify/ACSDGN +classiness/M +classless/P +classmate/MS +classroom/MS +classwork/M +classy/TRP +clatter/GMDS +clausal +clause/MS +claustrophobia/M +claustrophobic +clavichord/SM +clavicle/MS +clavier/MS +claw's +claw/CSGD +clay/M +clayey +clayier +clayiest +clean/BJPZTGDRYS +cleaner/M +cleaning/M +cleanliness/UM +cleanly/UTPR +cleanness/UM +cleanse/ZGDRS +cleanser/M +cleanup/MS +clear/JPTGMDRYS +clearance/SM +clearheaded +clearing/M +clearinghouse/SM +clearness/M +clearway/S +cleat/MS +cleavage/MS +cleave/ZGDRS +cleaver/M +clef/SM +cleft/MS +clematis/MS +clemency/IM +clement/Y +clementine/S +clench/GMDS +clerestory/SM +clergy/SM +clergyman/M +clergymen +clergywoman/M +clergywomen +cleric/MS +clerical/Y +clericalism/M +clerk/GMDS +clerkship/M +clever/PTRY +cleverness/M +clevis/MS +clew/SGMD +cliche/MDS +clich/MS +clichd +click/BZGMDRS +clicker/M +client/MS +clientele/MS +clientle/MS +cliff/MS +cliffhanger/SM +cliffhanging +clifftop/S +clii +climacteric/M +climactic +climate/SM +climatic +climatically +climatologist/SM +climatology/M +climax/MDSG +climb/SMDRZGB +climber/M +climbing/M +clime/SM +clinch/MDRSZG +clincher/M +cling/SMRZG +clinger/M +clingfilm +clingy/RT +clinic/SM +clinical/Y +clinician/SM +clink/SMDRZG +clinker/M +cliometric/S +cliometrician/MS +cliometrics/M +clip/SM +clipboard/MS +clipped +clipper/SM +clipping/SM +clique/SM +cliquey +cliquish/YP +cliquishness/M +clit/SM +clitoral +clitorides +clitoris/MS +clix +cloaca/M +cloacae +cloak's +cloak/USDG +cloakroom/MS +clobber/SMDG +cloche/SM +clock/SMDG +clockwise +clockwork/SM +clod/MS +cloddish +clodhopper/MS +clog's +clog/US +clogged/U +clogging/U +cloisonne/M +cloisonn/M +cloister/SMDG +cloistral +clomp/SDG +clonal +clone/DSMG +clonk/SMDG +clop/MS +clopped +clopping +closable/I +close/DRSMYTGBJP +closefisted +closemouthed +closeness/M +closeout/MS +closet/SMDG +closeup/SM +closing/M +closure/ESM +clot/MS +cloth/M +clothe/UDSG +clotheshorse/MS +clothesline/SM +clothespin/SM +clothier/MS +clothing/M +cloths +clotted +clotting +cloture/SM +cloud/SMDG +cloudburst/SM +clouded/U +cloudiness/M +cloudless +cloudy/RPT +clout/SMDG +clove/RSMZ +cloven +clover/M +cloverleaf/SM +cloverleaves +clown/SMDG +clownish/YP +clownishness/M +cloy/DGS +cloying/Y +club/MS +clubbable +clubbed +clubber/S +clubbing +clubfeet +clubfoot/MD +clubhouse/SM +clubland +cluck/SMDG +clue/MGDS +clueless +clump/SMDG +clumpy/TR +clumsily +clumsiness/M +clumsy/TRP +clung +clunk/SMDRZG +clunker/M +clunky/TR +cluster/MDSG +clutch/GMDS +clutter/MDSG +cluttered/U +clvi +clvii +clxi +clxii +clxiv +clxix +clxvi +clxvii +cm +cnidarian/MS +co/ESD +coach/MDSG +coachload/S +coachman/M +coachmen +coachwork +coadjutor/MS +coagulant/MS +coagulate/GNDS +coagulation/M +coagulator/MS +coal/MDGS +coalesce/GDS +coalescence/M +coalescent +coalface/MS +coalfield/S +coalition/MS +coalitionist/MS +coalmine/S +coarse/RYTP +coarsen/SDG +coarseness/M +coast/SMDRZG +coastal +coaster/M +coastguard/S +coastline/MS +coat/MDGJS +coating/M +coatroom/S +coattail/SM +coauthor/MDGS +coax/DRSZG +coaxer/M +coaxial +coaxing/Y +cob/SM +cobalt/M +cobber/S +cobble/DRSMZG +cobbler/M +cobblestone/SM +cobnut/S +cobra/SM +cobweb/SM +cobwebbed +cobwebby/RT +coca/M +cocaine/M +cocci/S +coccus/M +coccyges +coccyx/M +cochineal/M +cochlea/SM +cochleae +cochlear +cock/MDGS +cockade/SM +cockamamie +cockatoo/SM +cockatrice/SM +cockchafer/S +cockcrow/SM +cockerel/SM +cockeyed +cockfight/MGS +cockfighting/M +cockily +cockiness/M +cockle/SM +cockleshell/SM +cockney/SM +cockpit/SM +cockroach/MS +cockscomb/SM +cocksucker/MS! +cocksure +cocktail/MS +cocky/RTP +coco/MS +cocoa/SM +coconut/SM +cocoon/SMDG +cod/SM +coda/MS +codded +codding +coddle/DSG +code's +code/CZGDRS +codec/SM +codeine/M +codependency/M +codependent/SM +coder/CM +codex/M +codfish/MS +codger/SM +codices +codicil/SM +codification/M +codifier/M +codify/XDRSNZG +codon/SM +codpiece/MS +codswallop +coed/MS +coeducation/M +coeducational +coefficient/MS +coelenterate/MS +coequal/MYS +coerce/DRSZGNV +coercer/M +coercion/M +coeval/SMY +coexist/DSG +coexistence/M +coexistent +coextensive +coffee/SM +coffeecake/SM +coffeehouse/MS +coffeemaker/SM +coffeepot/MS +coffer/SM +cofferdam/MS +coffin/SMDG +cog/SM +cogency/M +cogent/Y +cogitate/DSXGNV +cogitation/M +cogitator/MS +cognac/SM +cognate/MS +cognition/AM +cognitional +cognitive/Y +cognizable +cognizance/AM +cognizant +cognomen/SM +cognoscente/M +cognoscenti +cogwheel/SM +cohabit/SGD +cohabitant/MS +cohabitation/M +coheir/SM +cohere/DSG +coherence/IM +coherency/M +coherent/IY +cohesion/M +cohesive/YP +cohesiveness/M +coho/MS +cohort/SM +coif/MDGS +coiffed +coiffing +coiffure/DSMG +coil's/A +coil/UADGS +coin/MDRZGS +coinage/SM +coincide/DSG +coincidence/MS +coincident +coincidental/Y +coiner/M +coinsurance/M +coir +coital +coitus/M +coke/MGDS +col/S +cola/MS +colander/SM +cold/MRYTPS +coldblooded +coldness/M +coleslaw/M +coleus/MS +coley/S +coli +colic/M +colicky +coliseum/MS +colitis/M +coll +collaborate/DSXGNV +collaboration/M +collaborationist +collaborative/Y +collaborator/MS +collage/SM +collagen +collapse/MGDS +collapsible +collar/SMDG +collarbone/SM +collard/SM +collarless +collate/DSXGN +collateral/MY +collateralize +collation/M +collator/MS +colleague/MS +collect's +collect/ASGVD +collectable/MS +collected/U +collectedly +collectible/SM +collection/AMS +collective/MYS +collectivism/M +collectivist/SM +collectivization/M +collectivize/DSG +collector/MS +colleen/SM +college/SM +collegiality/M +collegian/MS +collegiate +collide/DSG +collie/RSMZ +collier/M +colliery/SM +collision/SM +collocate/MGNDSX +collocation/M +colloid/SM +colloidal +colloq +colloquial/Y +colloquialism/SM +colloquies +colloquium/MS +colloquy/M +collude/DSG +collusion/M +collusive +cologne/SM +colon/SM +colonel/SM +colonelcy/M +colones +colonial/SMY +colonialism/M +colonialist/MS +colonist/SM +colonization/ACM +colonize/CAGSD +colonizer/MS +colonnade/MDS +colonoscope/MS +colonoscopy/SM +colony/SM +colophon/SM +color's +color/AEGDS +colorant/SM +coloration/EM +coloratura/MS +colorblind/P +colorblindness/M +colored's +colored/U +coloreds +colorfast/P +colorfastness/M +colorful/PY +colorfulness/M +coloring's +colorist/S +colorization/M +colorize/DSG +colorless/PY +colorlessness/M +colorway/S +colossal/Y +colossi +colossus/M +colostomy/SM +colostrum/M +colt/MS +coltish +columbine/SM +column/SMD +columnar +columnist/SM +com/JL +coma/MS +comaker/SM +comatose +comb/MDRZGJS +combat/SMDGV +combatant/SM +combativeness/M +combed/U +comber/M +combination/SM +combine's +combine/ADSG +combined/U +combiner/MS +combings/M +combo/SM +combustibility/M +combustible/MS +combustion/M +combustive +come/IMZGRS +comeback/MS +comedian/MS +comedic +comedienne/MS +comedown/MS +comedy/SM +comeliness/M +comely/RPT +comer's +comestible/SM +comet/SM +comeuppance/SM +comfit's +comfit/ES +comfort/ESMDG +comfortable/P +comfortableness/M +comfortably/U +comforter/MS +comforting/Y +comfortless +comfy/RT +comic/SM +comical/Y +comicality/M +coming/M +comity/M +comm +comma/SM +command/SMDRLZG +commandant/MS +commandeer/GDS +commander/M +commandment/MS +commando/SM +commemorate/XGNVDS +commemoration/M +commemorator/MS +commence/ADSLG +commencement/AM +commencements +commend/ASDBG +commendably +commendation/AMS +commendatory +commensurable +commensurate/IY +comment/ZGSMD +commentary/SM +commentate/DSG +commentator/SM +commerce/M +commercial/SMY +commercialism/M +commercialization/M +commercialize/GDS +commie/SM +commingle/DSG +commiserate/GNVDSX +commiseration/M +commissar/SM +commissariat/SM +commissary/SM +commission's +commission/ACSGD +commissionaire/S +commissioner/SM +commit/AS +commitment/MS +committal/SM +committed/AU +committee/SM +committeeman/M +committeemen +committeewoman/M +committeewomen +committer/S +committing/A +commode's +commode/EIS +commodification +commodious/Y +commodity/SM +commodore/SM +common's +common/UPRYT +commonality/S +commonalty/M +commoner/MS +commonness/UM +commonplace/MS +commons +commonsense +commonweal/MH +commonwealth/M +commonwealths +commotion/SM +communal/Y +commune/XDSMGN +communicability/M +communicable/I +communicably +communicant/MS +communicate/GNVDSX +communication/M +communicative/U +communicator/SM +communion/M +communique/SM +communism/M +communist/SM +communistic +community/SM +commutation/MS +commutative +commutator/SM +commute/BDRSMZG +commuter/M +comp/MDYGS +compact/TGSMDRYP +compaction +compactness/M +compactor/SM +companion/SBM +companionably +companionship/M +companionway/MS +company/SM +comparability/M +comparable/I +comparably/I +comparative/MYS +compare/BDSMG +comparison/MS +compartment/SM +compartmental +compartmentalization/M +compartmentalize/DSG +compass/GMDS +compassion/M +compassionate/Y +compatibility/IM +compatible/IMS +compatibly/I +compatriot/MS +compeer/SM +compel/S +compelled +compelling/Y +compendious +compendium/SM +compensate/DSXGN +compensated/U +compensation/M +compensatory +compere/DSG +compete/DSG +competence/IM +competences +competencies +competency/IM +competent/IY +competition/SM +competitive/PY +competitiveness/M +competitor/SM +compilation/AM +compilations +compile/DRSZG +compiler/M +complacence/M +complacency/M +complacent/Y +complain/DRZGS +complainant/MS +complainer/M +complaint/SM +complaisance/M +complaisant/Y +complected +complement/SGMD +complementary +complete/PYTGNXDRS +completed/U +completeness/IM +completion/M +complex/MSY +complexion/MDS +complexional +complexity/SM +compliance/M +compliant/Y +complicate/GDS +complicated/Y +complication/M +complicit +complicity/M +compliment/MDGS +complimentary/U +comply/NDSXG +compo/S +component/SM +comport/LSGD +comportment/M +compose/AECGSD +composedly +composer/MS +composite/MYGNXPDS +composition/CM +compositor/SM +compost/SGMD +composure/EM +compote/SM +compound/GMDBS +compounded/U +comprehend/SDG +comprehensibility/IM +comprehensible/I +comprehensibly/I +comprehension/IM +comprehensions +comprehensive/PMYS +comprehensiveness/M +compress's +compress/CGDS +compressed/U +compressible +compression/CM +compressor/SM +comprise/GDS +compromise/MGDS +comptroller/MS +compulsion/MS +compulsive/YP +compulsiveness/M +compulsorily +compulsory/SM +compunction/SM +computation/SM +computational/Y +compute/ADSG +computer/MS +computerate +computerization/M +computerize/GDS +computing/M +compre/DSG +comrade/SMY +comradeship/M +con/GSM +concatenate/XDSGN +concatenation/M +concave/YP +concaveness/M +conceal/SDRZGBL +concealed/U +concealer/M +concealment/M +conceit/SMD +conceited/PY +conceitedness/M +conceivable/I +conceivably/I +conceive/DSGB +concentrate/DSMGNX +concentration/M +concentric +concentrically +concept/SM +conception/SM +conceptional +conceptual/Y +conceptualization/MS +conceptualize/DSG +concern/UMD +concerned/UY +concerning +concerns +concert's +concert/ESDG +concerted/Y +concertgoer/S +concertina/SGMD +concertize/DSG +concertmaster/MS +concerto/SM +concessionaire/MS +concessional +concessionary +conch/M +conchie/S +conchs +concierge/MS +conciliate/DSGN +conciliation/AM +conciliator/SM +conciliatory +concise/RPYTN +conciseness/M +concision/M +conclave/SM +conclude/DSG +conclusion/MS +conclusive/IYP +conclusiveness/IM +concoct/SDG +concoction/MS +concomitant/MYS +concord/M +concordance/SM +concordant +concordat/SM +concourse/SM +concrete/DSPMYGNX +concreteness/M +concretion/M +concubinage/M +concubine/MS +concupiscence/M +concupiscent +concur/S +concurred +concurrence/SM +concurrency +concurring +concuss/V +concussion/SM +condemn/SDRZG +condemnation/MS +condemnatory +condemner/M +condensate/MNXS +condensation/M +condense/DRSZG +condenser/M +condescending/Y +condescension/M +condign +condiment/MS +condition's +condition/AGSD +conditional/SMY +conditioned/U +conditioner/SM +conditioning/M +condo/SM +condolence/SM +condom/SM +condominium/MS +condone/DSG +condor/SM +conduce/DSGV +conduct/MDGV +conductance/M +conductibility/M +conductible +conduction/M +conductivity/M +conductor/MS +conductress/MS +conduit/SM +cone/M +coney/SM +confab/SM +confabbed +confabbing +confabulate/XDSGN +confabulation/M +confection/SZMR +confectioner/M +confectionery/SM +confederacy/SM +confederate/M +confer/SB +conferee/SM +conference/MGS +conferrable +conferral/M +conferred +conferrer/MS +conferring +confessed/Y +confession/SM +confessional/SM +confessor/MS +confetti/M +confidant/MS +confidante/SM +confide/DRSZG +confidence/SM +confident/Y +confidential/Y +confidentiality/M +confider/M +confiding/Y +configuration/S +configure/B +confined/U +confinement/MS +confirm/ASDG +confirmation/ASM +confirmatory +confirmed/U +confiscate/DSGNX +confiscation/M +confiscator/SM +confiscatory +conflagration/MS +conflate/XDSGN +conflation/M +conflict/SGMD +confluence/MS +confluent +conform/ZB +conformable/U +conformance/M +conformant +conformism/M +conformist/SM +conformity/M +confrere/MS +confrontation/SM +confrontational +confrre/SM +confuse/RZ +confused/Y +confusing/Y +confutation/M +confute/DSG +conga/SMDG +congeal/SLDG +congealment/M +conger/SM +congeries/M +congest/SDGV +congestion/M +conglomerate/DSXMGN +conglomeration/M +congrats/M +congratulate/XGNDS +congratulation/M +congratulatory +congregant/MS +congregate/GNDSX +congregation/M +congregational +congregationalism/M +congregationalist/MS +congress/MS +congressional +congressman/M +congressmen +congresspeople +congressperson/MS +congresswoman/M +congresswomen +congruence/M +congruent/Y +congruity/ISM +congruous +conic/SM +conical/Y +conifer/SM +coniferous +conjectural +conjecture/MGDS +conjoint +conjugal/Y +conjugate/DSXGN +conjugation/M +conjunct/VMS +conjunctiva/SM +conjunctive/SM +conjunctivitis/M +conjuration/MS +conjure/DRSZG +conjurer/M +conk/MDRZ +connect/AEDVGS +connectable +connected/U +connection/EMS +connective/MS +connectivity/M +connector/MS +conned +conning +conniption/MS +connivance/M +connive/DRSZG +conniver/M +connoisseur/SM +connotative +connubial +conquer/ASDG +conquerable/U +conquered/U +conqueror/MS +conquest/AM +conquistador/SM +cons/DSG +consanguineous +consanguinity/M +conscienceless +conscientious/PY +conscientiousness/M +conscious/UYP +consciousness/UM +consciousnesses +conscription/M +consecrate/ADSGN +consecrated/U +consecration/AM +consecrations +consecutive/Y +consensual +consensus/MS +consent/SMDG +consequence/SM +consequent/Y +consequential/IY +conservancy/SM +conservation/M +conservationism/M +conservationist/SM +conservatism/M +conservative/MYS +conservatoire/S +conservator/SM +conservatory/SM +consider/AGSD +considerable/I +considerably +considerate/IPYN +considerateness/IM +consideration/AIM +considerations +considered/U +consign/ASDG +consignee/MS +consignment/MS +consist/SDG +consistence/MS +consistency/ISM +consistent/IY +consistory/SM +consolable/I +consolation/MS +consolatory +consolidate/XDSGN +consolidated/U +consolidation/M +consolidator/MS +consoling/Y +consomme/M +consomm/M +consonance/SM +consonant/SMY +consortia +consortium/M +conspectus/MS +conspicuous/IPY +conspicuousness/IM +conspiracy/SM +conspirator/MS +conspiratorial/Y +conspire/GD +constable/SM +constabulary/SM +constancy/IM +constant/MYS +constellation/SM +consternation/M +constipate/GNDS +constipation/M +constituency/SM +constituent/SM +constitute/ADSGNV +constitution/AM +constitutional/MYS +constitutionalism +constitutionality/UM +constitutions +constrained/U +constraint/SM +constrict/GVSD +constriction/SM +constrictor/SM +construable +construct's +construct/CADVGS +construction/CAMS +constructional +constructionist/CSM +constructive/YP +constructiveness/M +constructor/MS +construe/GDS +consul/KSM +consular/K +consulate/SM +consulship/M +consult/GSD +consultancy/SM +consultant/MS +consultation/MS +consultative +consumable/SM +consume/BDRSZG +consumed/U +consumer/M +consumerism/M +consumerist/MS +consummate/YGNXDS +consummated/U +consumption/M +consumptive/SM +cont +contact/ASDG +contactable +contagion/MS +contagious/PY +contagiousness/M +contain/SBLDRZG +container/M +containerization/M +containerize/DSG +containment/M +contaminant/SM +contaminate/ACDSG +contaminated/U +contamination/CM +contaminator/SM +contd +contemn/SDG +contemplate/DSGNV +contemplation/M +contemplative/SMY +contemporaneity/M +contemporaneous/Y +contempt/M +contemptible +contemptibly +contemptuous/YP +contemptuousness/M +contender/MS +content/ESLMDG +contented/EY +contentedness/M +contention/SM +contentious/YP +contentiousness/M +contently +contentment/EM +conterminous/Y +contestable/I +contestant/MS +contested/U +contextualization +contextualize/DSG +contiguity/M +contiguous/Y +continence/IM +continent/SM +continental/SM +contingency/SM +contingent/SMY +continua +continual/Y +continuance/EMS +continuation/EMS +continue/EGDS +continuity/ESM +continuous/EY +continuum/M +contort/GD +contortion/MS +contortionist/SM +contraband/M +contrabassoon/S +contraception/M +contraceptive/SM +contract/MDG +contractible +contractile +contractility +contraction/S +contractual/Y +contradict/SDG +contradiction/SM +contradictory +contradistinction/MS +contraflow/S +contrail/MS +contraindicate/GNXDS +contraindication/M +contralto/SM +contraption/SM +contrapuntal/Y +contrarian/SM +contrarianism +contrariety/M +contrarily +contrariness/M +contrariwise +contrary/PSM +contrast/MDGS +contravene/GDS +contravention/SM +contretemps/M +contribute/XGND +contribution/M +contributor/MS +contributory +contrition/M +contrivance/MS +contrive/ZGDRS +contriver/M +control's +control/CS +controllable/U +controlled/UC +controller/MS +controlling/C +controversial/Y +controversy/SM +controvert/DSG +controvertible/I +contumacious/Y +contumacy/M +contumelious +contumely/SM +contuse/XDSGN +contusion/M +conundrum/SM +conurbation/MS +convalesce/DSG +convalescence/MS +convalescent/SM +convection/M +convectional +convective +convector/S +convene/ADSG +convener/MS +convenience/IMS +convenient/IY +convenor/MS +convent/SM +conventicle/MS +convention/SM +conventional/UY +conventionality/UM +conventionalize/GDS +conventioneer/S +convergence/MS +convergent +conversant +conversation/MS +conversational/Y +conversationalist/SM +converse/Y +convert's +convert/AGSD +converted/U +converter/SM +convertibility/M +convertible/SM +convertor/SM +convex/Y +convexity/M +convey/SBDG +conveyance/MGS +conveyor/MS +convict/GSMD +conviction/MS +convince/GDS +convinced/U +convincing/UY +convivial/Y +conviviality/M +convoke/DSG +convoluted +convolution/MS +convoy/SMDG +convulse/GNVXDS +convulsion/M +convulsive/Y +cony/SM +coo/GSMD +cook's +cook/ADGS +cookbook/MS +cooked/U +cooker/SM +cookery/SM +cookhouse/S +cookie/M +cooking/M +cookout/SM +cookware/SM +cooky/SM +cool/MDRYZTGPS +coolant/SM +cooler/M +coolie/SM +coolness/M +coon/MS! +coonskin/MS +coop/MDRZGS +cooper/MDG +cooperage/M +cooperate/DSGNV +cooperation/M +cooperative/PMYS +cooperativeness/M +cooperator/SM +coordinate/DSMYGN +coordinated/U +coordination/M +coordinator/MS +coot/MS +cootie/SM +cop/GJSMD +copacetic +copay/M +cope/MS +copier/SM +copilot/SM +coping/M +copious/PY +copiousness/M +copped +copper/SM +copperhead/SM +copperplate/M +coppery +copping +copra/M +copse/SM +copter/SM +copula/SM +copulate/GNVDS +copulation/M +copulative/SM +copy's +copy/ADSG +copybook/SM +copycat/MS +copycatted +copycatting +copyist/MS +copyleft +copyright/GSMD +copywriter/MS +coquetry/SM +coquette/DSMG +coquettish/Y +cor +coracle/SM +coral/SM +corbel/SM +cord/EASGDM +cordage/M +cordial/SMY +cordiality/M +cordillera/MS +cordite/M +cordless +cordon/SMDG +cordovan/M +corduroy/MS +corduroys/M +core/MZGDRS +coreligionist/S +corer/M +corespondent/MS +corgi/SM +coriander/M +cork's +cork/UDGS +corkage +corker/SM +corkscrew/SMDG +corm/MS +cormorant/SM +corn/MDRZGS +cornball/MS +cornbread/M +corncob/MS +corncrake/S +cornea/SM +corneal +corner/GMD +cornerstone/SM +cornet/SM +cornfield/S +cornflakes/M +cornflour +cornflower/SM +cornice/MS +cornily +corniness/M +cornmeal/M +cornrow/MDGS +cornstalk/SM +cornstarch/M +cornucopia/MS +corny/PRT +corolla/MS +corollary/SM +corona/SM +coronal/MS +coronary/SM +coronation/SM +coroner/MS +coronet/MS +corp +corpora +corporal/SM +corporate/XYN +corporation/IM +corporatism +corporeal/Y +corporeality/M +corps/MS +corpse/M +corpsman/M +corpsmen +corpulence/M +corpulent +corpus/M +corpuscle/MS +corpuscular +corr +corral/SM +corralled +corralling +correct/DRYTGVSBP +corrected/U +correction/SM +correctional +corrective/SM +correctness/IM +corrector +correlate/XDSMGNV +correlated/U +correlation/M +correlative/MS +correspond/SDG +correspondence/SM +correspondent/SM +corresponding/Y +corridor/SM +corrie/S +corrigibility/IM +corrigible/I +corroborate/GNVDSX +corroborated/U +corroboration/M +corroborator/SM +corroboratory +corrode/GDS +corrosion/M +corrosive/SMY +corrugate/GNXDS +corrugation/M +corrupt/DRYPSTG +corruptibility/IM +corruptible/I +corruptibly/I +corruption/MS +corruptness/M +corsage/MS +corsair/MS +corset/SGMD +cortege/MS +cortex/M +cortical +cortices +cortisone/M +cortge/SM +corundum/M +coruscate/GNDS +coruscation/M +corvette/SM +cos/M +cosh/DSG +cosign/ZGSDR +cosignatory/SM +cosigner/M +cosine/SM +cosmetic/SM +cosmetically +cosmetician/MS +cosmetologist/MS +cosmetology/M +cosmic +cosmically +cosmogonist/SM +cosmogony/SM +cosmological +cosmologist/SM +cosmology/SM +cosmonaut/SM +cosmopolitan/MS +cosmopolitanism/M +cosmos/MS +cosplay +cosponsor/GSMD +cosset/SGD +cossetted +cossetting +cost/MDYGSJ +costar/SM +costarred +costarring +costliness/M +costly/PTR +costume/MZGDRS +costumer/M +costumier/S +cot/SM +cotangent/MS +cote/MS +coterie/MS +coterminous +cotillion/SM +cottage/MZGRS +cottager/M +cottar/SM +cotter/SM +cotton/SGMD +cottonmouth/M +cottonmouths +cottonseed/MS +cottontail/MS +cottonwood/SM +cottony +cotyledon/MS +couch/MDSG +couchette/S +cougar/SM +cough/MDG +coughs +could +could've +couldn't +coulee/SM +coulis +coulomb/MS +coule/SM +council/MS +councilman/M +councilmen +councilor/MS +councilperson/SM +councilwoman/M +councilwomen +counsel/JMDGS +counselor/MS +count/EASMDG +countable/U +countably +countdown/MS +counted/U +countenance/EMGDS +counter/EMS +counteract/SGVD +counteraction/MS +counterargument/S +counterattack/GMDS +counterbalance/MGDS +counterblast/S +counterclaim/GSMD +counterclockwise +counterculture/SM +countered +counterespionage/M +counterexample/S +counterfactual +counterfeit/ZGMDRS +counterfeiter/M +counterfoil/MS +countering +counterinsurgency/SM +counterintelligence/M +counterman/M +countermand/GMDS +countermeasure/SM +countermelody/S +countermen +countermove/S +counteroffensive/SM +counteroffer/SM +counterpane/SM +counterpart/SM +counterpetition +counterpoint/MDGS +counterpoise/MGDS +counterproductive +counterrevolution/SM +counterrevolutionary/SM +countersign/GSMD +countersignature/MS +countersink/GSM +counterspy/SM +countersunk +countertenor/MS +countervail/GSD +counterweight/MS +countess/MS +countless +countrified +country/SM +countryman/M +countrymen +countryside/MS +countrywide +countrywoman/M +countrywomen +county/SM +countywide +coup's +coup/AS +coupe/SM +couple's +couple/UCGSD +couplet/MS +coupling/SM +coupon/SM +courage/M +courageous/YP +courageousness/M +courgette/S +courier/MDSG +course/EDGMS +coursebook/S +courser/MS +coursework +court-martial/SGD +court/SMDYG +courteous/EY +courteousness/M +courtesan/SM +courtesy/ESM +courthouse/MS +courtier/SM +courtliness/M +courtly/PRT +courtroom/MS +courtship/MS +courtyard/MS +couscous/M +cousin/SM +couture/M +couturier/MS +cove/MS +coven/SM +covenant/MDSG +cover's +cover/AEUGDS +coverage/M +coverall/MS +covering's +coverings +coverlet/MS +covert/SPMY +covertness/M +coverup/MS +covet/SDG +covetous/YP +covetousness/M +covey/SM +cow/ZGSMDR +coward/SMY +cowardice/M +cowardliness/M +cowbell/MS +cowbird/MS +cowboy/SM +cowcatcher/MS +cower/DG +cowgirl/MS +cowhand/MS +cowherd/MS +cowhide/MS +cowl/MGSJ +cowlick/MS +cowling/M +cowman/M +cowmen +coworker/MS +cowpat/S +cowpoke/MS +cowpox/M +cowpuncher/SM +cowrie/SM +cowshed/S +cowslip/SM +cox/GDS +coxcomb/MS +coxswain/MS +coy/TPRY +coyness/M +coyote/SM +coypu/SM +cozen/SDG +cozenage/M +cozily +coziness/M +cozy/RSMTP +cpd +cpl +cps +crab/MS +crabbed +crabber/SM +crabbily +crabbiness/M +crabbing +crabby/PRT +crabgrass/M +crablike +crabwise +crack/SMDRYZGJ +crackdown/MS +cracker/M +crackerjack/MS +crackhead/MS +crackle/DSJMG +crackling/M +crackpot/MS +crackup/SM +cradle/DSMG +craft/SMDG +craftily +craftiness/M +craftsman/M +craftsmanship/M +craftsmen +craftspeople +craftswoman/M +craftswomen +crafty/RTP +crag/MS +cragginess/M +craggy/RPT +cram/S +crammed +crammer/S +cramming +cramp/SMDG +cramping/M +crampon/SM +cranberry/SM +crane/DSMG +cranial +cranium/SM +crank/SMDG +crankcase/SM +crankily +crankiness/M +crankshaft/MS +cranky/PRT +cranny/DSM +crap/MS +crape/SM +crapped +crapper/S +crappie/M +crapping +crappy/RSPT +craps/M +crapshooter/MS +crash/MDSG +crass/RYTP +crassness/M +crate/DRSMZG +crater/MDG +cravat/SM +crave/DSGJ +craven/SMYP +cravenness/M +craving/M +craw/MS +crawdad/SM +crawl/SMDRZG +crawler/M +crawlspace/SM +crawly/TRSM +cray/S +crayfish/MS +crayola/S +crayon/GSMD +craze/DSMG +crazily +craziness/M +crazy/PRSMT +creak/SMDG +creakily +creakiness/M +creaky/RPT +cream/SMDRZG +creamer/M +creamery/SM +creamily +creaminess/M +creamy/RPT +crease/ICGMSD +create/AKVNGSDX +creation/KAM +creationism/SM +creationist/SM +creative/SMYP +creativeness/M +creativity/M +creator/MS +creature/SM +creche/SM +cred +credence/M +credential/SGMD +credenza/SM +credibility/IM +credible/I +credibly/I +credit/EGSBMD +creditably/E +creditor/SM +creditworthy/P +credo/SM +credulity/IM +credulous/IY +credulousness/M +creed/SM +creek/SM +creel/SM +creep/SMRZG +creeper/M +creepily +creepiness/M +creepy/TPR +cremains/M +cremate/GNDSX +cremation/M +crematoria +crematorium/MS +crematory/SM +creme/SM +crenelate/XGNDS +crenelation/M +creole/SM +creosote/MGDS +crepe/SM +crept +crepuscular +crescendo/CSM +crescent/MS +cress/M +crest/SMDG +crestfallen +crestless +cretaceous +cretin/SM +cretinism/M +cretinous +cretonne/M +crevasse/SM +crevice/MS +crew/MDGS +crewel/M +crewelwork/M +crewman/M +crewmen +crib/MS +cribbage/M +cribbed +cribber/MS +cribbing +crick/SMDG +cricket/MRSZG +cricketer/M +crier/M +crikey +crime/SM +crimeware/M +criminal/MYS +criminality/M +criminalize/CGDS +criminologist/MS +criminology/M +crimp/SMDG +crimson/SMDG +cringe/DSMG +crinkle/DSMG +crinkly/RT +crinoline/SM +cripes +cripple/DRSMZG +crippler/M +crippleware +crippling/Y +crises +crisis/M +crisp/SMDRYTGP +crispbread/S +crispiness/M +crispness/M +crispy/PRT +crisscross/GMDS +criteria +criterion/M +critic/SM +critical/UY +criticism/MS +criticize/ZGDRS +criticizer/M +critique/MGDS +critter/SM +croak/SMDG +croaky/RT +crochet/SMDRZG +crocheter/M +crocheting/M +crock/SMD +crockery/M +crocodile/SM +crocus/MS +croft/SRZG +croissant/MS +crone/SM +crony/SM +cronyism/M +crook/SMDG +crooked/PTRY +crookedness/M +crookneck/SM +croon/SMDRZG +crooner/M +crop/MS +cropland/SM +cropped +cropper/MS +cropping +croquet/M +croquette/SM +crosier/MS +cross's +cross/AUGTSD +crossbar/SM +crossbeam/MS +crossbones/M +crossbow/SM +crossbowman/M +crossbowmen +crossbred +crossbreed/SGM +crosscheck/SMDG +crosscurrent/MS +crosscut/SM +crosscutting +crosser +crossfire/MS +crosshatch/GDS +crossing/SM +crossly +crossness/M +crossover/MS +crosspatch/MS +crosspiece/SM +crossroad/MS +crossroads/M +crosstown +crosswalk/MS +crosswind/MS +crosswise +crossword/MS +crotch/MS +crotchet/SM +crotchety +crouch/GMDS +croup/M +croupier/M +croupy/ZTR +crouton/MS +crow/MDGS +crowbar/MS +crowd/SMDG +crowded/U +crowdfund/SDG +crowfeet +crowfoot/SM +crown/SMDG +crowned/U +crozier/MS +croton/MS +crucial/Y +crucible/SM +crucifix/MS +crucifixion/SM +cruciform/SM +crucify/DSG +crud/M +cruddy/TR +crude/RMYTP +crudeness/M +crudites/M +crudity/SM +crudits/M +cruel/RYPT +cruelness/M +cruelty/SM +cruet/SM +cruft/SD +crufty +cruise/DRSMZG +cruiser/M +cruller/MS +crumb/SMDYG +crumble/MGDS +crumbliness/M +crumbly/TPR +crumby/TR +crumminess/M +crummy/PTR +crumpet/MS +crumple/MGDS +crunch/GMDRS +crunchiness/M +crunchy/TRP +crupper/MS +crusade/MZGDRS +crusader/M +cruse/SM +crush/MDRSZG +crusher/M +crushing/Y +crust/SMDG +crustacean/SM +crustal +crustily +crustiness/M +crusty/TRP +crutch/MS +crux/MS +cry/ZGJDRSM +crybaby/SM +cryogenic/S +cryogenics/M +cryonic/S +cryosurgery/M +crypt/SM +cryptic +cryptically +cryptogram/SM +cryptographer/SM +cryptography/M +cryptologist/MS +cryptosystem/S +crystal/SM +crystalline +crystallization/M +crystallize/ADSG +crystallographic +crystallography +crche/MS +ct +ctn +ctr +cu +cub/ZGSMDR +cubbyhole/MS +cube/MS +cuber/M +cubic +cubical +cubicle/MS +cubism/M +cubist/SM +cubit/SM +cuboid/S +cuckold/MDSG +cuckoldry/M +cuckoo/SM +cucumber/SM +cud/SM +cuddle/DSMG +cuddly/TR +cudgel/SGMDJ +cue/DSMG +cuff/MDGS +cuisine/SM +cul-de-sac +culinary +cull/MDGS +cullender/MS +culminate/XDSGN +culmination/M +culotte/SM +culpability/M +culpable/I +culpably +culprit/SM +cult/MS +cultism/M +cultist/MS +cultivable +cultivar/SM +cultivate/BDSGN +cultivated/U +cultivation/M +cultivator/MS +cultural/Y +culture/MGDS +cultured/U +culvert/MS +cum/SM +cumber/SDG +cumbersome/P +cumbersomeness/M +cumbrous +cumin/M +cummerbund/MS +cumming +cumulative/Y +cumuli +cumulonimbi +cumulonimbus/M +cumulus/M +cuneiform/M +cunnilingus/M +cunning/MRYT +cunt/MS! +cup/SM +cupboard/SM +cupcake/MS +cupful/SM +cupid/SM +cupidity/M +cupola/SMD +cuppa/S +cupped +cupping +cupric +cur/SMY +curability/M +curacao +curacy/SM +curare/M +curate/DSMGV +curative/MS +curator/KMS +curatorial +curaao +curb/MDGS +curbing/M +curbside +curbstone/SM +curd/MS +curdle/DSG +cure's +cure/KZGBDRS +cured/U +curer/KM +curettage/M +curfew/SM +curia/M +curiae +curie/SM +curio/SM +curiosity/SM +curious/YP +curiousness/M +curium/M +curl's +curl/UDGS +curler/SM +curlew/SM +curlicue/DSMG +curliness/M +curling/M +curly/RPT +curmudgeon/MYS +currant/MS +currency/SM +current's +current/FSY +curricula +curricular +curriculum/M +curry/DSMG +currycomb/SGMD +curse's +curse/ADSGV +cursed/Y +cursive's +cursive/EAY +cursor/SM +cursorily +cursoriness/M +cursory/P +curt/RYTP +curtail/GDSL +curtailment/SM +curtain/GMDS +curtness/M +curtsy/GDSM +curvaceous/P +curvaceousness/M +curvature/SM +curve/DSMG +curvy/RT +cushion/MDSG +cushy/RT +cusp/MS +cuspid/SM +cuspidor/SM +cuss's +cuss/EFGSD +cussed/PY +custard/MS +custodial +custodian/MS +custodianship/M +custody/M +custom/SZMR +customarily +customary/U +customer/M +customhouse/SM +customization/M +customize/DSG +cut/TSMR +cutaneous +cutaway/MS +cutback/MS +cute/YP +cuteness/M +cutesy/TR +cutey/S +cuticle/MS +cutie/SM +cutlass/MS +cutler/SM +cutlery/M +cutlet/SM +cutoff/SM +cutout/SM +cutter/SM +cutthroat/SM +cutting/MYS +cuttlefish/MS +cutup/SM +cutworm/MS +cw +cwt +cyan/M +cyanide/M +cyber +cyberbully/SM +cybercafe/S +cybercaf/S +cybernetic/S +cybernetics/M +cyberpunk/SM +cybersex +cyberspace/MS +cyborg/SM +cyclamen/MS +cycle/ADSMG +cyclic +cyclical/Y +cyclist/MS +cyclometer/MS +cyclone/MS +cyclonic +cyclopaedia/MS +cyclopedia/MS +cyclopes +cyclops/M +cyclotron/MS +cygnet/MS +cylinder/MS +cylindrical +cymbal/MS +cymbalist/MS +cynic/SM +cynical/Y +cynicism/M +cynosure/MS +cypher/M +cypress/MS +cyst/MS +cystic +cystitis +cytokine/SM +cytologist/SM +cytology/M +cytoplasm/M +cytoplasmic +cytosine/M +czar/MS +czarina/SM +czarism +czarist/SM +d'Arezzo/M +d'Estaing/M +d/NXGJ +dB +dab/SM +dabbed +dabber/MS +dabbing +dabble/ZGDRS +dabbler/M +dace/SM +dacha/MS +dachshund/MS +dactyl/MS +dactylic/MS +dad/SM +dadaism/M +dadaist/MS +daddy/SM +dado/SM +dadoes +daemon/MS +daemonic +daffiness/M +daffodil/SM +daffy/PTR +daft/PTRY +daftness/M +dag/S +dagger/MS +dago/S +dagoes +daguerreotype/DSMG +dahlia/MS +dailiness/M +daily/PSM +daintily +daintiness/M +dainty/RSMTP +daiquiri/MS +dairy/GSM +dairying/M +dairymaid/MS +dairyman/M +dairymen +dairywoman/M +dairywomen +dais/MS +daisy/SM +dale/SM +dalliance/MS +dallier/M +dally/ZGDRS +dalmatian/MS +dam/SM +damage/MGDS +damageable +damaged/U +damages/M +damask/MDGS +dame/SM +dammed +damming +dammit +damn/SBGMD +damnably +damnation/M +damned/T +damp/SPXZTGMDNRY +dampen/ZGDR +dampener/M +damper/M +dampness/M +damsel/MS +damselfly/SM +damson/MS +dance/MZGDRS +dancer/M +dancing/M +dandelion/SM +dander/M +dandify/GDS +dandle/GDS +dandruff/M +dandy/TRSM +dang/SZGDR +danger/M +dangerous/Y +dangle/ZGDRS +dangler/M +danish/MS +dank/PTRY +dankness/M +danseuse/MS +dapper/TR +dapple/MGDS +dare/DRSMZG +daredevil/MS +daredevilry/M +darer/M +daresay +daring/MY +dark/PXTMNRY +darken/ZGDR +darkener/M +darkie/S +darkness/M +darkroom/MS +darling/MS +darn/SZGMDR +darned/TR +darner/M +dart/SZGMDR +dartboard/MS +darter/M +dash/ZGMDRS +dashboard/SM +dasher/M +dashiki/MS +dashing/Y +dastard/MYS +dastardliness/M +data +database/SM +datasheet/SM +datatype +date/DRSMZGV +datebook/S +dated/U +dateless +dateline/MGDS +dater/M +dative/MS +datum/M +daub/SZGMDR +dauber/M +daughter/SMY +daunt/GDS +daunting/Y +dauntless/YP +dauntlessness/M +dauphin/MS +davenport/MS +davit/MS +dawdle/ZGDRS +dawdler/M +dawn/SGMD +day/SM +daybed/MS +daybreak/M +daycare/M +daydream/MDRZGS +daydreamer/M +daylight/MS +daylights/M +daylong +daytime/M +daze/DSMG +dazed/Y +dazzle/MZGDRS +dazzler/M +dazzling/Y +db +dbl +dc +dd/SDG +dded/K +dding/K +deacon/MS +deaconess/MS +dead/XTMNRY +deadbeat/MS +deadbolt/SM +deaden/GD +deadhead/SDG +deadline/SM +deadliness/M +deadlock/GSMD +deadly/TPR +deadpan/MS +deadpanned +deadpanning +deadwood/M +deaf/PXTNR +deafen/GD +deafening/Y +deafness/M +deal/SJZGMR +dealer/M +dealership/SM +dealing/M +dealt +dean/M +deanery/SM +deanship/M +dear/SPTMRYH +dearest/S +dearie/M +dearness/M +dearth/M +dearths +deary/SM +death/MY +deathbed/SM +deathblow/MS +deathless/Y +deathlike +deaths +deathtrap/MS +deathwatch/MS +deaves +deb/SM +debacle/MS +debarkation/M +debarment/M +debate/BMZR +debater/M +debating/M +debauch/MDSG +debauchee/MS +debauchery/SM +debenture/MS +debilitate/DSGN +debilitation/M +debility/SM +debit/D +debonair/PY +debonairness/M +debouch/GDS +debridement +debris/M +debt/SM +debtor/MS +debugger/S +debut/GMD +debutante/SM +decade/MS +decadence/M +decadency/M +decadent/MYS +decaf/MS +decaffeinate/DSG +decagon/MS +decal/MS +decampment/M +decapitate/XGNDS +decapitator/MS +decathlete/S +decathlon/SM +decay/GD +deceased/M +decedent/MS +deceit/MS +deceitful/YP +deceitfulness/M +deceive/UGDS +deceiver/MS +deceiving/Y +decelerate/GNDS +deceleration/M +decelerator/SM +decency/ISM +decennial/SM +decent/IY +deception/MS +deceptive/YP +deceptiveness/M +decibel/MS +decidable/U +decide/BZGDRS +decided/Y +deciduous +deciliter/MS +decimal/SM +decimalization +decimate/DSGN +decimation/M +decimeter/MS +decipherable/UI +decision/IM +decisions +decisive/IPY +decisiveness/IM +deck/SGMD +deckchair/S +deckhand/SM +deckle/S +declamation/MS +declamatory +declaration/MS +declarative +declaratory +declare/DRSZGB +declared/U +declarer/M +declension/SM +declination/M +decline/DRSMZG +decliner/M +declivity/SM +decolletage/SM +decollete +decongestant/MS +deconstructionism +decor/MS +decorate/AGNVDS +decorating/M +decoration/AM +decorations +decorative/Y +decorator/MS +decorous/IY +decorousness/M +decorum/M +decoupage/DSMG +decoy/GMDS +decreasing/Y +decree/MDS +decreeing +decremented +decrements +decrepit +decrepitude/M +decriminalization/M +decry/GDS +decryption +dedicate/AGDS +dedication/SM +dedicator/SM +dedicatory +deduce/GDS +deducible +deduct/GVD +deductible/SM +deduction/SM +deductive/Y +deed/GD +deejay/MS +deem/ASGD +deep/SPXTMNRY +deepen/GD +deepness/M +deer/M +deerskin/M +deerstalker/S +def/Z +defacement/M +defacer/SM +defalcate/DSXGN +defalcation/M +defamation/M +defamatory +defame/ZGDRS +defamer/M +defaulter/SM +defeat/MDRZGS +defeated/U +defeater/M +defeatism/M +defeatist/MS +defecate/GNDS +defecation/M +defect/MDGVS +defection/MS +defective/MPYS +defectiveness/M +defector/MS +defendant/SM +defended/U +defenestration/S +defense/DSMGV +defenseless/YP +defenselessness/M +defensible/I +defensibly/I +defensive/MYP +defensiveness/M +deference/M +deferential/Y +deferral/MS +deferred +deferring +deffer +deffest +defiant/Y +defibrillation +defibrillator/S +deficiency/SM +deficient +deficit/SM +defilement/M +definable/IU +define/AGDS +defined/U +definer/MS +definite/IYVP +definiteness/IM +definition/AM +definitions +definitive/Y +deflate/GNDS +deflation/M +deflationary +deflect/DGVS +deflection/MS +deflector/SM +defogger/SM +defoliant/SM +defoliate/DSGN +defoliation/M +defoliator/MS +deformity/SM +defraud/DRZGS +defrauder/M +defrayal/M +defrock/DG +defroster/MS +deft/PTRY +deftness/M +defunct +defy/GDS +deg +degeneracy/M +degenerate/MVX +degrade/B +degree/MS +dehydrator/SM +dehydrogenase/M +deicer/MS +deification/M +deify/NGDS +deign/GDS +deist/MS +deistic +deity/SM +deject/GDS +dejected/Y +dejection/M +delay/ZDR +delectable +delectably +delectation/M +delegate/GD +delete/XGNDS +deleterious +deletion/M +delft/M +delftware/M +deli/SM +deliberate/XYVP +deliberateness/M +delicacy/ISM +delicate/IY +delicateness/M +delicatessen/SM +delicious/PY +deliciousness/M +delighted/Y +delightful/Y +deliminator +delineate/GNXDS +delineation/M +delinquency/SM +delinquent/SMY +deliquesce/DSG +deliquescent +delirious/YP +deliriousness/M +delirium/SM +deliver/ADGS +deliverable/S +deliverables/U +deliverance/M +delivered/U +deliverer/SM +dell/SM +delphinium/MS +delta/MS +delude/GDS +deluge/MGDS +delusion/MS +delusional +delusive/Y +deluxe +delve/ZGDRS +delver/M +demagogic +demagogically +demagogue/SM +demagoguery/M +demagogy/M +demand/GMDS +demanding/U +demarcate/DSGNX +demarcation/M +demean/GDS +demeanor/M +demented/Y +dementia/M +demesne/MS +demigod/MS +demigoddess/MS +demijohn/SM +demimondaine/SM +demimonde/M +demise/MGDS +demitasse/MS +demo/GMD +democracy/SM +democrat/MS +democratic/U +democratically +democratization/M +democratize/GDS +demode +demographer/SM +demographic/SM +demographically +demographics/M +demography/M +demolish/DSG +demolition/MS +demon/MS +demonetization/M +demoniac +demoniacal/Y +demonic +demonically +demonize/GDS +demonology/SM +demonstrability +demonstrable/I +demonstrably +demonstrate/XGNVDS +demonstration/M +demonstrative/MYSP +demonstrativeness/M +demonstrator/MS +demote/GD +demotic +demount +demulcent/SM +demur/TMRS +demure/PY +demureness/M +demurral/SM +demurred +demurrer/SM +demurring +den/M +denationalization +denaturation +denature/DG +dendrite/SM +dengue/M +deniability +deniable/U +denial/MS +denier/M +denigrate/DSGN +denigration/M +denim/MS +denitrification +denizen/MS +denominational +denotative +denouement/MS +denounce/LDSG +denouncement/SM +dense/PYTR +denseness/M +density/SM +dent/ISGMD +dental/Y +dentifrice/SM +dentin/M +dentine/M +dentist/MS +dentistry/M +dentition/M +denture/IMS +denuclearize/GDS +denudation/M +denude/GDS +denunciation/SM +deny/ZGDRS +deodorant/SM +deodorization/M +deodorize/DRSZG +deodorizer/M +departed/M +department/MS +departmental/Y +departmentalization/M +departmentalize/GDS +departure/SM +dependability/M +dependable/U +dependably +dependence/IM +dependency/SM +dependent/IMYS +depict/GDS +depiction/MS +depilatory/SM +deplete/GNDS +depletion/M +deplorably +deplore/BGDS +deploy/ALGDS +deployment/AM +deployments +deponent/MS +deportation/MS +deportee/MS +deportment/M +deposit/AGMDS +depositor/MS +depository/SM +deprave/GDS +depravity/SM +deprecate/GNDS +deprecating/Y +deprecation/M +deprecatory +depreciate/DSGN +depreciation/M +depredation/SM +depressant/SM +depressing/Y +depression/SM +depressive/SM +depressor/MS +depressurization +deprive/GDS +deprogramming +depth/M +depths +deputation/MS +depute/DSG +deputize/DSG +deputy/SM +derailleur/SM +derailment/SM +derangement/M +derby/SM +derelict/MS +dereliction/M +deride/GDS +derision/M +derisive/PY +derisiveness/M +derisory +derivation/MS +derivative/MS +derive/B +dermal +dermatitis/M +dermatological +dermatologist/SM +dermatology/M +dermis/M +derogate/DSGN +derogation/M +derogatorily +derogatory +derrick/SM +derriere/SM +derringer/SM +derrire/SM +derv +dervish/MS +desalinate/GNDS +desalination/M +desalinization/M +desalinize/GDS +descant/M +descend/FGDS +descendant/MS +descender +describable/I +describe/BZGDR +describer/M +description/SM +descriptive/PY +descriptiveness/M +descriptor/S +descry/GDS +desecrate/DSGN +desecration/M +deselection +desert/SDRZGM +deserter/M +desertification +desertion/SM +deserved/UY +deserving/U +deshabille/M +desiccant/SM +desiccate/DSGN +desiccation/M +desiccator/SM +desiderata +desideratum/M +designate/DSGNX +designated/U +designation/M +designee +desirability/UM +desirableness/M +desirably/U +desire/B +desired/U +desirous +desist/SDG +desk/SM +deskill/G +desktop/SM +desolate/PDSYGN +desolateness/M +desolation/M +despair/SMDG +despairing/Y +desperado/M +desperadoes +desperate/YNP +desperateness/M +desperation/M +despicable +despicably +despise/DSG +despite +despoilment/M +despondence/M +despondency/M +despondent/Y +despotic +despotically +despotism/M +dessert/SM +dessertspoon/S +dessertspoonful/S +destination/SM +destine/DSG +destiny/SM +destitute/N +destitution/M +destroy/SZGDR +destroyer/M +destruct/GVMDS +destructibility/IM +destructible/I +destruction/M +destructive/PY +destructiveness/M +desuetude/M +desultorily +desultory +detach/BLGDS +detachment/MS +detain/LGDS +detainee/MS +detainment/M +detect/SDGVB +detectable/U +detected/U +detection/M +detective/SM +detector/SM +detente/SMNX +detention/M +deter/SL +detergent/SM +deteriorate/DSGN +deterioration/M +determent/M +determinable/I +determinant/SM +determinate +determine/AGDS +determined/U +determinedly +determiner/SM +determinism/M +deterministic +deterred/U +deterrence/M +deterrent/MS +deterring +detestably +detestation/M +dethrone/DSLG +dethronement/M +detonate/GNDSX +detonation/M +detonator/SM +detox/MDSG +detoxification/M +detoxify/DSGN +detract/GD +detriment/SM +detrimental/Y +detritus/M +deuce/SM +deuterium/M +devastate/GNDS +devastating/Y +devastation/M +devastator/MS +develop/ASGDL +developed/U +developer/SM +development/ASM +developmental/Y +deviance/M +deviancy/M +deviant/SM +deviate/DSMGNX +deviating/U +deviation/M +devil/SMDGL +devilish/YP +devilishness/M +devilment/M +devilry/SM +deviltry/SM +devious/YP +deviousness/M +devoid +devolution/M +devolve/DSG +devoted/Y +devotee/SM +devotion/MS +devotional/SM +devour/SDG +devout/PRYT +devoutness/M +dew/M +dewberry/SM +dewclaw/SM +dewdrop/SM +dewiness/M +dewlap/SM +dewy/RTP +dexterity/M +dexterous/YP +dexterousness/M +dextrose/M +dharma +dhoti/SM +dhow/MS +diabetes/M +diabetic/SM +diabolic +diabolical/Y +diacritic/MS +diacritical +diadem/SM +diaereses +diaeresis/M +diagnose/DSG +diagnosis/M +diagnostic/S +diagnostically +diagnostician/SM +diagnostics/M +diagonal/SMY +diagram/SM +diagrammatic +diagrammatically +diagrammed +diagramming +dial/AMDGS +dialect/SM +dialectal +dialectic/SM +dialectical +dialectics/M +dialing/S +dialog/SDG +dialogue/DRSMG +dialyses +dialysis/M +dialyzes +diam +diamante +diamant +diameter/SM +diametric +diametrical/Y +diamond/SM +diamondback/MS +diapason/SM +diaper/SMDG +diaphanous +diaphragm/SM +diaphragmatic +diarist/SM +diarrhea/M +diary/SM +diaspora/SM +diastase/M +diastole/M +diastolic +diathermy/M +diatom/SM +diatomaceous +diatomic +diatonic +diatribe/SM +dibble/DSMG +dibs/M +dice/GDS +dices/I +dicey +dichotomous +dichotomy/SM +dicier +diciest +dick/MRXZS +dicker/DG +dickey/SM +dickhead/S +dicky/SM +dickybird/S +dicotyledon/MS +dicotyledonous +dict +dicta +dictate/DSMGNX +dictation/M +dictator/SM +dictatorial/Y +dictatorship/SM +diction/M +dictionary/SM +dictum/M +did/AU +didactic +didactically +diddle/DRSZG +diddler/M +diddly +diddlysquat +diddums +didgeridoo/S +didn't +dido/MS +didoes +didst +die/DSM +diehard/SM +dielectric/MS +diereses +dieresis/M +diesel/SMDG +diet/MDRZGS +dietary/SM +dieter/M +dietetic/S +dietetics/M +dietician/MS +dietitian/MS +diff/DRZGS +differ/DG +difference/IM +differences +different/IY +differential/SM +differentiate/DSGN +differentiated/U +differentiation/M +difficult/Y +difficulty/SM +diffidence/M +diffident/Y +diffract/GSD +diffraction/M +diffuse/DSYGNVP +diffuseness/M +diffusion/M +dig/SM +digerati/M +digest/SMDGV +digested/U +digestibility/M +digestible/I +digestion/IM +digestions +digestive/S +digger/SM +digging/S +diggings/M +digicam/S +digit/SM +digital/Y +digitalis/M +digitization +digitize/GDS +dignified/U +dignify/DSG +dignitary/SM +dignity/ISM +digraph/M +digraphs +digress/GVDS +digression/MS +dihydro +dike/MGDS +diktat/S +dilapidated +dilapidation/M +dilatation/M +dilate/DSGN +dilation/M +dilator/SM +dilatory +dildo/S +dilemma/MS +dilettante/SM +dilettantish +dilettantism/M +diligence/M +diligent/Y +dill/MS +dilly/SM +dillydally/DSG +dilute/DSGNX +diluted/U +dilution/M +dim/PSRY +dime/MS +dimension/SM +dimensional +dimensionless +diminish/GDS +diminished/U +diminuendo/SM +diminuendoes +diminution/SM +diminutive/SM +dimity/M +dimmed/U +dimmer/SM +dimmest +dimming +dimness/M +dimple/DSMG +dimply +dimwit/SM +dimwitted +din/ZGSMDR +dinar/SM +dine/S +diner/M +dinette/MS +ding/MDG +dingbat/MS +dingdong/SGMD +dinghy/SM +dingily +dinginess/M +dingle/SM +dingo/M +dingoes +dingus/MS +dingy/RPT +dink/R +dinky/RSMT +dinned +dinner/SMDG +dinnertime/M +dinnerware/M +dinning +dinosaur/SM +dint/M +diocesan/MS +diocese/MS +diode/SM +diorama/SM +dioxide/SM +dioxin/SM +dip/SM +diphtheria/M +diphthong/SM +diploid/SM +diploma/SM +diplomacy/M +diplomat/MS +diplomata +diplomatic/U +diplomatically +diplomatist/MS +diplopia +dipole/SM +dipped +dipper/SM +dipping +dippy/RT +dipso/S +dipsomania/M +dipsomaniac/MS +dipstick/SM +dipterous +diptych/M +diptychs +dire/YTR +direct/ASDGVT +directer +direction/IM +directional +directionless +directions +directive/SM +directly +directness/IM +director/MS +directorate/SM +directorial +directorship/SM +directory/SM +direful +dirge/SM +dirigible/MS +dirk/MS +dirndl/SM +dirt/M +dirtball/S +dirtily +dirtiness/M +dirty/DRSTGP +dis/M +disable/DSGL +disablement/M +disambiguate/N +disappointing/Y +disarming/Y +disastrous/Y +disbandment/M +disbarment/M +disbelieving/Y +disbursal/M +disburse/DSGL +disbursement/MS +disc/M +discern/LSDG +discernible/I +discernibly +discerning/Y +discernment/M +discharged/U +disciple/SM +discipleship/M +disciplinarian/SM +disciplinary +discipline/DSMG +disciplined/U +disclose/DSBG +disclosed/U +disco/MG +discography/SM +discoloration/S +discombobulate/DSGN +discombobulation/M +discomfit/DG +discomfiture/M +discommode/DG +disconcerting/Y +disconnected/PY +disconnectedness/M +disconsolate/Y +discordance/M +discordant/Y +discotheque/SM +discourage/LGDS +discouragement/SM +discouraging/Y +discover/ASDG +discovered/U +discoverer/MS +discovery/ASM +discreet/PRYT +discreetness/M +discrepancy/SM +discrepant +discrete/PYN +discreteness/M +discretion/IM +discretionary +discriminant +discriminate/GNDS +discriminating/U +discrimination/M +discriminator/MS +discriminatory +discursiveness/M +discus/MS +discussant/SM +discussion/SM +disdain/SMDG +disdainful/Y +disembowel/SDLG +disembowelment/M +disfigurement/SM +disfranchisement/M +disgorgement/M +disgruntle/LGDS +disgruntlement/M +disguise/GD +disguised/U +disgusted/Y +disgusting/Y +dish/MDSG +dishabille/M +disharmonious +dishcloth/M +dishcloths +disheartening/Y +dishevel/DGLS +dishevelment/M +dishpan/SM +dishrag/SM +dishtowel/MS +dishware/M +dishwasher/MS +dishwater/M +dishy +disillusion/GLD +disillusionment/M +disinfectant/MS +disinfection/M +disinterested/PY +disinterestedness/M +disjointed/YP +disjointedness/M +disjunctive +disjuncture +disk/MS +diskette/MS +dislodge/GDS +dismal/Y +dismantlement/M +dismay/SMDG +dismayed/U +dismember/LGD +dismemberment/M +dismissive/Y +disorder/Y +disorganization/M +disparage/DSGL +disparagement/M +disparaging/Y +disparate/Y +dispatcher/MS +dispel/S +dispelled +dispelling +dispensary/SM +dispensation/MS +dispense/BZGDRS +dispenser/M +dispersal/M +disperse/GNDS +dispersion/M +dispirit/GDS +displeasure/M +disposable/SM +disposal/SM +disposed/I +disposition/ISM +dispossession/M +disproof/SM +disproportional +disprove/B +disputable/I +disputably/I +disputant/MS +disputation/SM +disputatious/Y +dispute/DRSMZGB +disputed/U +disputer/M +disquiet/GSMD +disquisition/MS +disregardful +disrepair/M +disrepute/MB +disrupt/GVSD +disruption/SM +disruptive/Y +dissect/SDG +dissed +dissemblance/M +dissemble/ZGDRS +dissembler/M +disseminate/GNDS +dissemination/M +dissension/SM +dissent/SMDRZG +dissenter/M +dissentious +dissertation/SM +dissidence/M +dissident/MS +dissimilar +dissimilitude/S +dissing +dissipate/GNDS +dissipation/M +dissociate/GNDS +dissociation/M +dissoluble/I +dissolute/YNP +dissoluteness/M +dissolve/AGDS +dissolved/U +dissonance/SM +dissonant +dissuade/GDS +dissuasive +dist +distaff/SM +distal/Y +distance/DSMG +distant/Y +distaste/SM +distemper/M +distention/SM +distillate/SMNX +distillation/M +distillery/SM +distinct/IYTVP +distincter +distinction/SM +distinctive/YP +distinctiveness/M +distinctness/IM +distinguish/GDSB +distinguishable/I +distinguished/U +distort/GDR +distortion/MS +distract/DG +distracted/Y +distraction/S +distrait +distraught +distress/DG +distressful +distressing/Y +distribute/AGNVDS +distributed/U +distribution/AM +distributional +distributions +distributive/Y +distributor's +distributor/AS +distributorship/S +district's +district/AS +disturb/ZGSDR +disturbance/SM +disturbed/U +disturber/M +disturbing/Y +disunion/M +disyllabic +ditch/MDSG +dither/SMDRZG +ditherer/M +ditransitive +ditsy +ditto/SMDG +dittoes +ditty/SM +ditz/MS +ditzy/R +diuretic/MS +diurnal/Y +div +diva/MS +divalent +divan/SM +dive/MZTGDRS +diver/M +diverge/DSG +divergence/MS +divergent +diverse/XYNP +diverseness/M +diversification/M +diversify/GNDS +diversion/M +diversionary +diversity/SM +divert/SDG +diverticulitis/M +divest/SLDG +divestiture/MS +divestment/M +divide/DRSMZGB +divided/U +dividend/MS +divider/M +divination/M +divine/DRSMYZTG +diviner/M +diving/M +divinity/SM +divisibility/IM +divisible/I +division/MS +divisional +divisive/PY +divisiveness/M +divisor/SM +divorce/DSLMG +divorcee/MS +divorcement/MS +divorce/MS +divot/SM +divulge/GDS +divvy/DSMG +dixieland/M +dizzily +dizziness/M +dizzy/DRSPTG +djellaba/MS +djellabahs +djinn +do/SJMRHZG +doable +dob/S +dobbed +dobbin/SM +dobbing +doberman/MS +dobro +doc/SM +docent/SM +docile/Y +docility/M +dock/MDRZGS +docket/SMDG +dockland/S +dockside +dockworker/MS +dockyard/MS +doctor/SMDG +doctoral +doctorate/MS +doctrinaire/MS +doctrinal +doctrine/MS +docudrama/SM +document/GMDS +documentary/SM +documentation/SM +documented/U +dodder/SMDG +doddery +doddle +dodge/DRSMZG +dodgem/S +dodger/M +dodgy/RT +dodo/MS +doe/SM +doer/M +does/AU +doeskin/MS +doesn't +doff/DGS +dog/SM +dogcart/SM +dogcatcher/SM +doge/MS +dogear/SMDG +dogfight/SM +dogfish/MS +dogged/PY +doggedness/M +doggerel/M +doggie/M +dogging +doggone/TGDRS +doggoned/TR +doggy/RSMT +doghouse/SM +dogie/SM +dogleg/SM +doglegged +doglegging +doglike +dogma/SM +dogmatic +dogmatically +dogmatism/M +dogmatist/SM +dognapper +dogsbody/S +dogsled/S +dogtrot/MS +dogtrotted +dogtrotting +dogwood/MS +doh/M +doily/SM +doing/USM +doldrums/M +dole's +dole/FGDS +doleful/YP +dolefulness/M +doll/MDGS +dollar/SM +dollhouse/SM +dollop/SGMD +dolly/SM +dolmen/SM +dolomite/M +dolor/M +dolorous/Y +dolphin/MS +dolt/MS +doltish/YP +doltishness/M +domain/SM +dome/MGDS +domestic/SM +domestically +domesticate/DSGN +domesticated/U +domestication/M +domesticity/M +domicile/DSMG +domiciliary +dominance/M +dominant/SMY +dominate/DSGN +domination/M +dominatrices +dominatrix/M +domineer/SGD +domineering/Y +dominion/SM +domino/M +dominoes +don't +don/SM +dona/MS +donate/DSXGN +donation/M +donator/MS +done/FAU +dong/MDGS +dongle/SM +donkey/SM +donned +donning +donnish +donnybrook/MS +donor/SM +donuts +doodad/SM +doodah +doodahs +doodle/DRSMZG +doodlebug/SM +doodler/M +doohickey/SM +doolally +doom/MDGS +doomsayer/MS +doomsday/M +doomster/S +door's +door/IS +doorbell/MS +doorjamb/S +doorkeeper/MS +doorknob/MS +doorknocker/S +doorman/M +doormat/SM +doormen +doorplate/SM +doorpost/S +doorstep/MS +doorstepped +doorstepping +doorstop/MS +doorway/SM +dooryard/MS +dopa/M +dopamine +dope/MZGDRS +doper/M +dopey +dopier +dopiest +dopiness/M +doping/M +doppelganger/S +doppelgnger/S +dork/MS +dorky/RT +dorm/MRZS +dormancy/M +dormant +dormer/M +dormice +dormitory/SM +dormouse/M +dorsal/Y +dory/SM +dosage/SM +dose/MGDS +dosh +dosimeter/SM +doss/DRSZG +dosshouse/S +dossier/MS +dost +dot/ZGSMDR +dotage/M +dotard/SM +dotcom/SM +dote/S +doter/M +doting/Y +dotted +dotting +dotty/RT +double's +double/ADSG +doubleheader/MS +doublespeak/M +doublet/MS +doubloon/SM +doubly +doubt/SMDRZG +doubter/M +doubtful/PY +doubtfulness/M +doubting/Y +doubtless/Y +douche/DSMG +dough/M +doughnut/SM +doughty/RT +doughy/TR +dour/RYTP +dourness/M +douse/DSG +dove/MS +dovecot/S +dovecote/SM +dovetail/MDSG +dovish +dowager/MS +dowdily +dowdiness/M +dowdy/RSPT +dowel/SMDG +dower/SMDG +down/MDRZGS +downbeat/SM +downcast +downdraft/MS +downer/M +downfall/SMN +downfield +downgrade/DSMG +downhearted/PY +downheartedness/M +downhill/MS +download/MDBSG +downmarket +downplay/DSG +downpour/MS +downrange +downright +downriver +downscale +downshift/SGD +downside/MS +downsize/GDS +downsizing/M +downspout/MS +downstage +downstairs/M +downstate/M +downstream +downswing/MS +downtime/M +downtown/M +downtrend/MS +downtrodden +downturn/MS +downward/S +downwind +downy/RT +dowry/SM +dowse/DRSZG +dowser/M +doxology/SM +doyen/SM +doyenne/MS +doz/XGDNS +doze/M +dozen/MH +dozily +dozy/RTP +dpi +dpt +drab/MYSP +drabber +drabbest +drabness/M +drachma/MS +draconian +draft's +draft/ASDG +draftee/SM +drafter/SM +draftily +draftiness/M +drafting/M +draftsman/M +draftsmanship/M +draftsmen +draftswoman/M +draftswomen +drafty/RTP +drag/MS +dragged +dragging +draggy/TR +dragnet/SM +dragon/SM +dragonfly/SM +dragoon/SMDG +dragster/S +drain/SMDRZG +drainage/M +drainboard/SM +drainer/M +drainpipe/MS +drake/SM +dram/MS +drama/SM +dramatic/S +dramatically +dramatics/M +dramatist/SM +dramatization/SM +dramatize/DSG +drank +drape/DRSMZG +draper/M +drapery/SM +drastic +drastically +drat +dratted +draughtboard/S +draw/MRZGSJ +drawback/MS +drawbridge/MS +drawer/M +drawing/M +drawl/SMDG +drawn/A +drawstring/MS +dray/MS +dread/SMDG +dreadful/PY +dreadfulness/M +dreadlocks/M +dreadnought/MS +dream/SMDRZG +dreamboat/MS +dreamed/U +dreamer/M +dreamily +dreaminess/M +dreamland/M +dreamless +dreamlike +dreamworld/SM +dreamy/RPT +drear +drearily +dreariness/M +dreary/RPT +dredge/DRSMZG +dredger/M +dregs/M +drench/GDS +dress/AUGSDM +dressage/M +dresser/MS +dressiness/M +dressing/SM +dressmaker/SM +dressmaking/M +dressy/TPR +drew/A +dribble/MZGDRS +dribbler/M +driblet/MS +drier/M +drift/SMDRZG +drifter/M +driftnet/S +driftwood/M +drill/SMDRZG +driller/M +drillmaster/SM +drily +drink/SMRBJZG +drinkable/U +drinker/M +drip/MS +dripped +dripping/SM +drippy/TR +drive/RSMZGJ +drivel/SZGMDR +driveler/M +driven +driver/M +driveshaft/SM +driveway/MS +drizzle/MGDS +drizzly +drogue/SM +droid/S +droll/RPT +drollery/SM +drollness/M +drolly +dromedary/SM +drone/DSMG +drool/SMDG +droop/GSMD +droopiness/M +droopy/TPR +drop/MS +dropkick/MS +droplet/SM +dropout/SM +dropped +dropper/SM +dropping/S +droppings/M +dropsical +dropsy/M +dross/M +drought/SM +drove/RSMZ +drover/M +drown/GSJD +drowning/M +drowse/MGDS +drowsily +drowsiness/M +drowsy/RTP +drub/S +drubbed +drubber/SM +drubbing/MS +drudge/MGDS +drudgery/M +drug/MS +drugged +druggie/SM +drugging +druggist/SM +druggy +drugstore/MS +druid/SM +druidism/M +drum/MS +drumbeat/SM +drumlin/SM +drummed +drummer/SM +drumming +drumstick/SM +drunk/STMNR +drunkard/MS +drunken/PY +drunkenness/M +drupe/SM +druthers/M +dry/ZTGDRSMY +dryad/SM +dryer/SM +dryness/M +drys +drywall/M +dual +dualism/M +duality/M +dub/SM +dubbed +dubber/SM +dubbin/M +dubbing +dubiety/M +dubious/YP +dubiousness/M +ducal +ducat/SM +duchess/MS +duchy/SM +duck/MDGS +duckbill/SM +duckboards +duckling/SM +duckpins/M +duckweed/M +ducky/TRSM +duct's/K +duct/CKIFS +ductile +ductility/M +ducting +ductless +dud/GSMD +dude/MS +dudgeon/M +due's +due/IS +duel/MDRJZGS +dueler/M +duelist/SM +duenna/MS +duet/MS +duff/MDRZGS +duffer/M +dug +dugout/MS +duh +duke/MS +dukedom/SM +dulcet +dulcimer/MS +dull/DRPTGS +dullard/SM +dullness/M +dully +duly/U +dumb/RYPT +dumbbell/SM +dumbfound/SDG +dumbness/M +dumbo/S +dumbstruck +dumbwaiter/SM +dumdum/MS +dummy/SM +dump/MDRZGS +dumpiness/M +dumpling/SM +dumpsite/S +dumpster/SM +dumpy/PTR +dun/SM +dunce/SM +dunderhead/MS +dune/MS +dung/MDGS +dungaree/MS +dungeon/SM +dunghill/MS +dunk/MDGS +dunned +dunner +dunnest +dunning +dunno +duo/SM +duodecimal +duodena +duodenal +duodenum/M +duopoly/S +dupe/MZGDRS +duper/M +duple +duplex/MS +duplicate's +duplicate/AGNDS +duplication/AM +duplicator/MS +duplicitous +duplicity/M +durability/M +durable +durably +durance/M +duration/M +duress/M +durian/SM +during +durst +durum/M +dusk/M +duskiness/M +dusky/RTP +dust/MDRZGS +dustbin/SM +dustcart/S +duster/M +dustiness/M +dustless +dustman +dustmen +dustpan/SM +dustsheet/S +dusty/RTP +dutch +duteous/Y +dutiable +dutiful/YP +dutifulness/M +duty/SM +duvet/SM +dwarf/SGMD +dwarfish +dwarfism/M +dweeb/SM +dwell/SJZGR +dweller/M +dwelling/M +dwelt/I +dwindle/DSG +dyadic +dybbuk/SM +dybbukim +dye/DRSMZG +dyeing/A +dyer/M +dyestuff/M +dying/M +dyke/MS +dynamic/MS +dynamical/Y +dynamics/M +dynamism/M +dynamite/MZGDRS +dynamiter/M +dynamo/SM +dynastic +dynasty/SM +dysentery/M +dysfunction/MS +dysfunctional +dyslectic/SM +dyslexia/M +dyslexic/SM +dyspepsia/M +dyspeptic/MS +dysphagia +dysphoria +dysphoric +dysprosium/M +dystonia +dz +dbridement +dbutante/SM +dcolletage/SM +dcollet +dmod +drailleur/MS +dshabill/M +dtente/M +e'en +e'er +e/FDST +eBay/M +eBook/MS +eCommerce/M +eMusic/M +ea +each +eager/PTRY +eagerness/M +eagle/MS +eaglet/MS +ear/SMDY +earache/SM +earbud/SM +eardrum/SM +earful/SM +earl/MS +earldom/SM +earliness/M +earlobe/SM +early/RTP +earmark/SMDG +earmuff/SM +earn/DRZTGJS +earned/U +earner/M +earnest/SMYP +earnestness/M +earnings/M +earphone/MS +earpiece/S +earplug/SM +earring/SM +earshot/M +earsplitting +earth's +earth/UDYG +earthbound +earthen +earthenware/M +earthiness/M +earthling/MS +earthly/RT +earthquake/SM +earths/U +earthshaking +earthward/S +earthwork/MS +earthworm/MS +earthy/RTP +earwax/M +earwig/SM +ease/EDSM +easel/SM +easement/SM +easily/U +easiness/UM +easing +east/M +eastbound +easterly/SM +eastern/ZR +easterner/M +easternmost +eastward/S +easy/URTP +easygoing +eat/ZGBSNR +eatable/SM +eaten/U +eater/M +eatery/SM +eave/MS +eavesdrop/S +eavesdropped +eavesdropper/SM +eavesdropping +ebb/SMDG +ebony/SM +ebullience/M +ebullient/Y +ebullition/M +eccentric/SM +eccentrically +eccentricity/SM +eccl +ecclesial +ecclesiastic/SM +ecclesiastical/Y +echelon/SM +echinoderm/SM +echo's +echo/ADG +echoes/A +echoic +echolocation/M +echos +eclair/SM +eclat/M +eclectic/SM +eclectically +eclecticism/M +eclipse/DSMG +ecliptic/M +eclogue/SM +ecocide/M +ecol +ecologic +ecological/Y +ecologist/MS +ecology/M +econ +econometric +economic/S +economical/UY +economics/M +economist/SM +economize/DRSZG +economizer/M +economy/SM +ecosystem/MS +ecotourism/M +ecotourist/MS +ecru/M +ecstasy/SM +ecstatic +ecstatically +ecu/S +ecumenical/Y +ecumenicism/M +ecumenism/M +eczema/M +ed/ACSM +edamame +eddy/DSMG +edelweiss/M +edema/SM +edge/MZGJDRS +edger/M +edgeways +edgewise +edgily +edginess/M +edging/M +edgy/RTP +edibility/M +edible/SMP +edibleness/M +edict/SM +edification/M +edifice/SM +edifier/M +edify/DRSZGN +edifying/U +edit's +edit/ADGS +editable +edited/U +edition/MS +editor/SM +editorial/SMY +editorialize/DSG +editorship/M +educ +educability/M +educable/I +educate/ADSGNV +educated/U +education/AM +educational/Y +educationalist/S +educationist/S +educations +educator/MS +educe/DSGB +edutainment/M +eek +eel/SM +eerie/RT +eerily +eeriness/M +eff/GSD +efface/DSLG +effacement/M +effect/SMDGV +effective/IPY +effectiveness/IM +effectual/IY +effectuate/DSG +effeminacy/M +effeminate/Y +effendi/SM +efferent +effervesce/GDS +effervescence/M +effervescent/Y +effete/YP +effeteness/M +efficacious/Y +efficacy/IM +efficiency/ISM +efficient/IY +effigy/SM +efflorescence/M +efflorescent +effluence/M +effluent/MS +effluvia +effluvium/M +effort/SM +effortless/YP +effortlessness/M +effrontery/M +effulgence/M +effulgent +effuse/DSGNVX +effusion/M +effusive/YP +effusiveness/M +egad +egalitarian/SM +egalitarianism/M +egg/GSMD +eggbeater/MS +eggcup/SM +egghead/SM +eggnog/M +eggplant/MS +eggshell/SM +eglantine/SM +ego/SM +egocentric/MS +egocentrically +egocentricity/M +egoism/M +egoist/SM +egoistic +egoistical/Y +egomania/M +egomaniac/MS +egotism/M +egotist/SM +egotistic +egotistical/Y +egregious/PY +egregiousness/M +egress/MS +egret/SM +eh +eider/SM +eiderdown/MS +eigenvalue/S +eight/SM +eighteen/MHS +eighteenth/M +eighteenths +eighth/M +eighths +eightieth/M +eightieths +eighty/SMH +einsteinium/M +eisteddfod/S +either +ejaculate/GNXDS +ejaculation/M +ejaculatory +eject/SDG +ejection/MS +ejector/SM +eke/DSG +elaborate/YGNDSPX +elaborateness/M +elaboration/M +elan/M +eland/SM +elapse/DSG +elastic/MS +elastically +elasticated +elasticity/M +elasticize/DSG +elate/DSGN +elated/Y +elation/M +elbow/SMDG +elbowroom/M +elder/SMY +elderberry/SM +eldercare/M +eldest +eldritch +elect's +elect/ASDGV +electable +election/AMS +electioneer/DGS +elective/MS +elector/MS +electoral/Y +electorate/MS +electric/S +electrical/Y +electrician/MS +electricity/M +electrification/M +electrifier/M +electrify/ZGNDRS +electrocardiogram/MS +electrocardiograph/M +electrocardiographs +electrocardiography/M +electrocute/DSXGN +electrocution/M +electrode/SM +electrodynamics +electroencephalogram/MS +electroencephalograph/M +electroencephalographic +electroencephalographs +electroencephalography/M +electrologist/SM +electrolysis/M +electrolyte/MS +electrolytic +electromagnet/MS +electromagnetic +electromagnetically +electromagnetism/M +electromotive +electron/MS +electronic/S +electronica/M +electronically +electronics/M +electroplate/DSG +electroscope/SM +electroscopic +electroshock/M +electrostatic/S +electrostatics/M +electrotype/MS +eleemosynary +elegance/IM +elegant/IY +elegiac/MS +elegiacal +elegy/SM +elem +element/MS +elemental/Y +elementary +elephant/SM +elephantiasis/M +elephantine +elev +elevate/XDSGN +elevation/M +elevator/MS +eleven/SMH +elevens/S +eleventh/M +elevenths +elf/M +elfin +elfish +elicit/SDG +elicitation/M +elicitor/MS +elide/DSG +eligibility/IM +eligible +eliminate/XDSGN +elimination/M +eliminator/S +elision/MS +elite/SM +elitism/M +elitist/MS +elixir/SM +elk/SM +ell/SM +ellipse/MS +ellipsis/M +ellipsoid/SM +ellipsoidal +elliptic +elliptical/Y +elm/SM +elocution/M +elocutionary +elocutionist/SM +elodea/SM +elongate/DSGNX +elongation/M +elope/DSGL +elopement/MS +eloquence/M +eloquent/Y +else +elsewhere +elucidate/DSGNX +elucidation/M +elude/DSG +elusive/YP +elusiveness/M +elver/SM +elves +elvish +em's +em/S +emaciate/GNDS +emaciation/M +email/SMDG +emanate/XDSGN +emanation/M +emancipate/DSGN +emancipation/M +emancipator/MS +emasculate/GNDS +emasculation/M +embalm/SZGDR +embalmer/M +embank/SLGD +embankment/SM +embargo/MDG +embargoes +embark/AEGDS +embarkation/EM +embarkations +embarrass/GLDS +embarrassed/U +embarrassing/Y +embarrassment/SM +embassy/SM +embattled +embed/S +embedded +embedding +embellish/LGDS +embellishment/SM +ember/SM +embezzle/ZGLDRS +embezzlement/M +embezzler/M +embitter/GLDS +embitterment/M +emblazon/GDLS +emblazonment/M +emblem/SM +emblematic +emblematically +embodiment/EM +embody/AEGSD +embolden/DGS +embolism/MS +embolization +emboss/DRSZG +embosser/M +embouchure/M +embower/SGD +embrace/DSMG +embraceable +embrasure/MS +embrocation/MS +embroider/SDRZG +embroiderer/M +embroidery/SM +embroil/DGLS +embroilment/M +embryo/SM +embryological +embryologist/MS +embryology/M +embryonic +emcee/DSM +emceeing +emend/SDG +emendation/MS +emerald/MS +emerge/ADSG +emergence/AM +emergency/SM +emergent +emerita +emeritus +emery/M +emetic/SM +emf/S +emigrant/SM +emigrate/DSXGN +emigration/M +emigre/SM +eminence/MS +eminent/Y +emir/MS +emirate/MS +emissary/SM +emission/SM +emit/S +emitted +emitter/MS +emitting +emo/SM +emoji/SM +emollient/MS +emolument/MS +emote/XDSGNV +emoticon/SM +emotion/M +emotional/UY +emotionalism/M +emotionalize/GDS +emotionless +emotive/Y +empanel/GDS +empathetic +empathize/DSG +empathy/M +emperor/MS +emphases +emphasis/M +emphasize/AGDS +emphatic/U +emphatically +emphysema/M +empire/SM +empiric +empirical/Y +empiricism/M +empiricist/SM +emplacement/SM +employ's +employ/ADGLS +employable/U +employee/SM +employer/SM +employment/UAM +employments +emporium/SM +empower/SDGL +empowerment/M +empress/MS +emptily +emptiness/M +empty/TGPDRSM +empyrean/M +emu/SM +emulate/DSGNVX +emulation/M +emulator/SM +emulsification/M +emulsifier/M +emulsify/NDRSZG +emulsion/MS +en/SM +enable/DRSZG +enabler/M +enact/ASLDG +enactment/ASM +enamel/JSZGMDR +enameler/M +enamelware/M +enamor/SGD +enc +encamp/LSGD +encampment/MS +encapsulate/XGNDS +encapsulation/M +encase/LDSG +encasement/M +encephalitic +encephalitis/M +enchain/DGS +enchant/ELDGS +enchanter/MS +enchanting/Y +enchantment/EM +enchantments +enchantress/MS +enchilada/SM +encipher/SGD +encircle/DSGL +encirclement/M +encl +enclave/MS +enclose/GDS +enclosed/U +enclosure/SM +encode/DRSZG +encoder/M +encomium/MS +encompass/GDS +encore/DSMG +encounter/GSMD +encourage/DSLG +encouragement/SM +encouraging/Y +encroach/GLDS +encroachment/SM +encrust/DGS +encrustation/SM +encrypt/DGS +encryption +encumber/EGSD +encumbered/U +encumbrance/MS +ency +encyclical/SM +encyclopaedia +encyclopedia/MS +encyclopedic +encyst/LSGD +encystment/M +end/GVSJMD +endanger/SGDL +endangerment/M +endear/SGLD +endearing/Y +endearment/SM +endeavor/GSMD +endemic/MS +endemically +endgame/S +ending/M +endive/SM +endless/PY +endlessness/M +endmost +endocarditis +endocrine/MS +endocrinologist/MS +endocrinology/M +endogenous/Y +endometrial +endometriosis +endometrium +endorphin/MS +endorse/LZGDRS +endorsement/MS +endorser/M +endoscope/MS +endoscopic +endoscopy/M +endothelial +endothermic +endow/SDLG +endowment/MS +endpoint/SM +endue/DSG +endurable/U +endurance/M +endure/DSBG +endways +enema/SM +enemy/SM +energetic +energetically +energize/ZGDRS +energizer/M +energy/SM +enervate/GNDS +enervation/M +enfeeble/GDSL +enfeeblement/M +enfilade/DSMG +enfold/SGD +enforce/LZGDRS +enforceable/U +enforced/U +enforcement/M +enforcer/M +enfranchise/EGDSL +enfranchisement/EM +engage/EADSG +engagement/EMS +engagingly +engender/SGD +engine/SM +engineer/MDGS +engineering/M +engorge/LGDS +engorgement/M +engram/SM +engrave/ZGJDRS +engraver/M +engraving/M +engross/GLDS +engrossment/M +engulf/SLGD +engulfment/M +enhance/LZGDRS +enhancement/SM +enigma/SM +enigmatic +enigmatically +enjambment/SM +enjoin/SGD +enjoy/GBLSD +enjoyably +enjoyment/SM +enlarge/LZGDRS +enlargeable +enlargement/MS +enlarger/M +enlighten/SGLD +enlightened/U +enlightenment/M +enlist/ADGSL +enlistee/SM +enlistment/AM +enlistments +enliven/SLDG +enlivenment/M +enmesh/DSGL +enmeshment/M +enmity/SM +ennoble/DSGL +ennoblement/M +ennui/M +enormity/SM +enormous/PY +enormousness/M +enough/M +enplane/DSG +enqueue/DSG +enquirer/S +enquiringly +enrage/GDS +enrapture/DSG +enrich/DSLG +enrichment/M +enroll/DLSG +enrollment/MS +ensconce/DSG +ensemble/SM +enshrine/GLDS +enshrinement/M +enshroud/DGS +ensign/MS +ensilage/M +enslave/DSGL +enslavement/M +ensnare/DSLG +ensnarement/M +ensue/DSG +ensure/ZGDRS +ensurer/M +entail/DSGL +entailment/M +entangle/EDSLG +entanglement/EM +entanglements +entente/SM +enter/ASGD +enteric +enteritis/M +enterprise/MGS +enterprising/Y +entertain/ZGDRSL +entertainer/M +entertaining/MY +entertainment/MS +enthrall/GDSL +enthrallment/M +enthrone/GDSL +enthronement/SM +enthuse/DSG +enthusiasm/MS +enthusiast/MS +enthusiastic/U +enthusiastically +entice/GDSL +enticement/MS +enticing/Y +entire/Y +entirety/M +entitle/DSGL +entitlement/SM +entity/SM +entomb/DSGL +entombment/M +entomological +entomologist/MS +entomology/M +entourage/SM +entr'acte +entrails/M +entrance/LDSMG +entrancement/M +entrancing/Y +entrant/SM +entrap/LS +entrapment/M +entrapped +entrapping +entreat/GSD +entreating/Y +entreaty/SM +entree/MS +entrench/DSGL +entrenchment/MS +entrepreneur/SM +entrepreneurial +entrepreneurship +entropy/M +entrust/SGD +entry/ASM +entryphone/S +entryway/MS +entre/MS +entwine/DSG +enumerable +enumerate/DSGNX +enumeration/M +enumerator/SM +enunciate/DSGN +enunciation/M +enure/DSG +enuresis/M +envelop/SLDRZG +envelope/SM +enveloper/M +envelopment/M +envenom/SDG +enviable/U +enviably +envious/PY +enviousness/M +environment/MS +environmental/Y +environmentalism/M +environmentalist/SM +environs/M +envisage/GDS +envision/DGS +envoy/SM +envy/DSMG +envying/Y +enzymatic +enzyme/SM +eolian +eon/SM +eosinophil/S +eosinophilic +epaulet/SM +epee/MS +ephedrine/M +ephemera/M +ephemeral/Y +epic/MS +epicenter/MS +epicure/SM +epicurean/MS +epidemic/SM +epidemically +epidemiological +epidemiologist/SM +epidemiology/M +epidermal +epidermic +epidermis/MS +epidural/S +epiglottis/MS +epigram/SM +epigrammatic +epigraph/M +epigraphs +epigraphy/M +epilepsy/M +epileptic/SM +epilogue/MS +epinephrine/M +epiphany/SM +episcopacy/M +episcopal +episcopate/M +episode/SM +episodic +episodically +epistemic +epistemological +epistemology +epistle/SM +epistolary +epitaph/M +epitaphs +epithelial +epithelium/M +epithet/SM +epitome/SM +epitomize/GDS +epoch/M +epochal +epochs +eponymous +epoxy/DSMG +epsilon/SM +equability/M +equable +equably +equal/SMDYG +equality/IM +equalization/M +equalize/ZGDRS +equalizer/M +equanimity/M +equate/DSGNBX +equation/M +equator/SM +equatorial +equerry/SM +equestrian/SM +equestrianism/M +equestrienne/SM +equidistant/Y +equilateral/SM +equilibrium/EM +equine/SM +equinoctial +equinox/MS +equip/AS +equipage/MS +equipment/M +equipoise/M +equipped/UA +equipping/A +equitable/I +equitably/I +equitation/M +equity/ISM +equiv +equivalence/MS +equivalency/SM +equivalent/MYS +equivocal/UY +equivocalness/M +equivocate/GNXDS +equivocation/M +equivocator/SM +er/C +era/SM +eradicable/I +eradicate/DSGN +eradication/M +eradicator/MS +erase/DRSBZG +eraser/M +erasure/SM +erbium/M +ere +erect/PSGDY +erectile +erection/SM +erectness/M +erector/MS +erelong +eremite/MS +erg/SM +ergo +ergonomic/S +ergonomically +ergonomics/M +ergosterol/M +ergot/M +ermine/SM +erode/DSG +erodible +erogenous +erosion/M +erosive +erotic/S +erotica/M +erotically +eroticism/M +err/GSD +errand/SM +errant/I +errata/SM +erratic +erratically +erratum/M +erroneous/Y +error/SM +ersatz/MS +erst +erstwhile +eruct/SDG +eructation/SM +erudite/YN +erudition/M +erupt/SDGV +eruption/MS +erysipelas/M +erythrocyte/SM +erythromycin +escalate/CDSGN +escalation/CM +escalations +escalator/MS +escallop/SGMD +escalope/S +escapade/MS +escape/LMGDS +escapee/MS +escapement/SM +escapism/M +escapist/MS +escapologist/S +escapology +escargot/MS +escarole/MS +escarpment/MS +eschatological +eschatologist/SM +eschatology +eschew/SDG +escort/SMDG +escritoire/MS +escrow/SM +escudo/SM +escutcheon/SM +esophageal +esophagi +esophagus/MS +esoteric +esoterically +esp +espadrille/MS +espalier/MDSG +especial/Y +espionage/M +esplanade/MS +espousal/M +espouse/GDS +espresso/MS +esprit/M +espy/DSG +esquire/SM +essay/SMDRZG +essayer/M +essayist/SM +essence/SM +essential/IMS +essentially +establish/AESDGL +establishment/AEM +establishments +estate/SM +esteem/ESMDG +ester/SM +esthetic/S +estimable/I +estimate/MGNDSX +estimation/M +estimator/SM +estoppel +estrange/LDSG +estrangement/MS +estrogen/M +estrous +estrus/MS +estuary/SM +eta/SM +etc +etch/DRSZGJ +etcher/M +etching/M +eternal/YP +eternalness/M +eternity/SM +ethane/M +ethanol/M +ether/M +ethereal/Y +ethic/SM +ethical/UY +ethics/M +ethnic/SM +ethnically +ethnicity/M +ethnocentric +ethnocentrism/M +ethnographer/S +ethnographic +ethnographically +ethnography +ethnological/Y +ethnologist/SM +ethnology/M +ethological +ethologist/MS +ethology/M +ethos/M +ethyl/M +ethylene/M +etiolated +etiologic +etiological +etiology/SM +etiquette/M +etude/SM +etymological/Y +etymologist/SM +etymology/SM +eucalypti +eucalyptus/MS +euchre/DSMG +euclidean +eugenic/S +eugenically +eugenicist/MS +eugenics/M +eulogist/MS +eulogistic +eulogize/ZGDRS +eulogizer/M +eulogy/SM +eunuch/M +eunuchs +euphemism/SM +euphemistic +euphemistically +euphonious/Y +euphony/M +euphoria/M +euphoric +euphorically +eureka +euro/MS +europium/M +eutectic +euthanasia/M +euthanize/DSG +euthenics/M +evacuate/XDSGN +evacuation/M +evacuee/MS +evade/DRSZG +evader/M +evaluate/AGNVDSX +evaluation/AM +evanescence/M +evanescent +evangelic +evangelical/SMY +evangelicalism/M +evangelism/M +evangelist/MS +evangelistic +evangelize/GDS +evaporate/GNDS +evaporation/M +evaporator/SM +evasion/SM +evasive/YP +evasiveness/M +eve/ASM +even/MDRYTGSJP +evenhanded/Y +evening/M +evenness/UM +evensong/M +event/SM +eventful/UY +eventfulness/M +eventide/M +eventual/Y +eventuality/SM +eventuate/GDS +ever +everglade/SM +evergreen/SM +everlasting/MYS +evermore +every +everybody/M +everyday +everyone/M +everyplace +everything/M +everywhere +evict/SDG +eviction/MS +evidence/MGDS +evident/Y +evil/MRYTSP +evildoer/SM +evildoing/M +eviller +evillest +evilness/M +evince/DSG +eviscerate/DSGN +evisceration/M +evocation/MS +evocative/Y +evoke/DSG +evolution/M +evolutionary +evolutionist/SM +evolve/DSG +ewe/RSMZ +ewer/M +ex/MS +exabyte/MS +exacerbate/GNDS +exacerbation/M +exact/SBPDRYTG +exacta/S +exacting/PY +exaction/SM +exactitude/M +exactness/IM +exactor/MS +exaggerate/XDSGN +exaggerated/Y +exaggeration/M +exaggerator/MS +exalt/SDG +exaltation/M +exam/MS +examination/AMS +examine/AGDS +examiner/MS +example/MGDS +exampled/U +exasperate/DSGN +exasperated/Y +exasperating/Y +exasperation/M +excavate/GNDSX +excavation/M +excavator/SM +exceed/GSD +exceeding/Y +excel/S +excelled +excellence/M +excellency/SM +excellent/Y +excelling +excelsior/M +except/GSD +exception/BSM +exceptionable/U +exceptional/UY +exceptionalism +excerpt/MDGS +excess/VMS +excessive/Y +exchange/DSMG +exchangeable +exchequer/SM +excise/XDSMGN +excision/M +excitability/M +excitably +excitation/M +excite/BDRSLZG +excited/Y +excitement/SM +exciter/M +exciting/Y +excl +exclaim/DGS +exclamation/SM +exclamatory +exclude/GDS +exclusion/MS +exclusionary +exclusive/PMYS +exclusiveness/M +exclusivity/M +excommunicate/GNDSX +excommunication/M +excoriate/DSGNX +excoriation/M +excrement/M +excremental +excrescence/MS +excrescent +excreta/M +excrete/XGNDS +excretion/M +excretory +excruciating/Y +exculpate/DSGN +exculpation/M +exculpatory +excursion/MS +excursionist/MS +excursive/YP +excursiveness/M +excusable/I +excusably/I +excuse/DSBMG +excused/U +exec/MS +execrable +execrably +execrate/DSGN +execration/M +execute/BXGNVDS +execution/ZMR +executioner/M +executive/SM +executor/MS +executrices +executrix/M +exegeses +exegesis/M +exegetic +exegetical +exemplar/SM +exemplary +exemplification/M +exemplify/GDSXN +exempt/SGD +exemption/SM +exercise/DRSMZG +exerciser/M +exert/SDG +exertion/MS +exeunt +exfoliate/GNDS +exhalation/MS +exhale/DSG +exhaust/GVMDS +exhaustible/I +exhaustion/M +exhaustive/YP +exhaustiveness/M +exhibit/GMDS +exhibition/MS +exhibitionism/M +exhibitionist/MS +exhibitor/SM +exhilarate/DSGN +exhilaration/M +exhort/SDG +exhortation/MS +exhumation/MS +exhume/DSG +exigence/MS +exigency/SM +exigent +exiguity/M +exiguous +exile/DSMG +exist/SDG +existence/MS +existent +existential/Y +existentialism/M +existentialist/MS +exit/MDGS +exobiology/M +exodus/MS +exogenous +exon/MS +exonerate/GNDS +exoneration/M +exoplanet/MS +exorbitance/M +exorbitant/Y +exorcise/DSG +exorcism/SM +exorcist/SM +exoskeleton/SM +exosphere/SM +exothermic +exotic/SM +exotica +exotically +exoticism/M +exp +expand/BGSD +expanse/XMNVS +expansible +expansion/M +expansionary +expansionism/M +expansionist/MS +expansive/YP +expansiveness/M +expat/S +expatiate/GNDS +expatiation/M +expatriate/DSMGN +expatriation/M +expect/GSD +expectancy/M +expectant/Y +expectation/SM +expectorant/SM +expectorate/DSGN +expectoration/M +expedience/IM +expediences +expediencies +expediency/IM +expedient/SMY +expedite/DRSZGNX +expediter/M +expedition/M +expeditionary +expeditious/PY +expeditiousness/M +expel/S +expelled +expelling +expend/GSBD +expendable/SM +expenditure/SM +expense/MS +expensive/IYP +expensiveness/IM +experience/IMD +experiences +experiencing +experiential +experiment/MDRSZG +experimental/Y +experimentalism +experimentation/M +experimenter/M +expert/SPMY +expertise/M +expertness/M +expiate/GNDS +expiation/M +expiatory +expiration/M +expire/DSG +expired/U +expiry/M +explain/ADGS +explainable +explained/U +explanation/MS +explanatory +expletive/MS +explicable/I +explicate/XGNDS +explication/M +explicit/PY +explicitness/M +explode/GDS +exploit/ZGBMDRS +exploitation/M +exploitative +exploited/U +exploiter/M +exploration/MS +exploratory +explore/ZGDRS +explored/U +explorer/M +explosion/SM +explosive/SPMY +explosiveness/M +expo/MS +exponent/MS +exponential/Y +exponentiation +export/BSZGMDR +exportation/M +exporter/M +expose/DSMG +exposed/U +exposition/SM +expositor/SM +expository +expostulate/GNXDS +expostulation/M +exposure/MS +expound/ZGDRS +expounder/M +express/GVMDSY +expressed/U +expressible/I +expression/SM +expressionism/M +expressionist/SM +expressionistic +expressionless/Y +expressive/PY +expressiveness/M +expressway/SM +expropriate/GNXDS +expropriation/M +expropriator/SM +expulsion/MS +expunge/GDS +expurgate/DSGNX +expurgated/U +expurgation/M +exquisite/YP +exquisiteness/M +ext +extant +extemporaneous/PY +extemporaneousness/M +extempore +extemporization/M +extemporize/GDS +extend/SZGDRB +extender/M +extendible +extensible +extension/SM +extensional +extensive/YP +extensiveness/M +extent/SM +extenuate/DSGN +extenuation/M +exterior/MS +exterminate/DSXGN +extermination/M +exterminator/MS +external/MYS +externalization/SM +externalize/DSG +extinct/GDS +extinction/MS +extinguish/ZGBDRS +extinguishable/I +extinguisher/M +extirpate/GNDS +extirpation/M +extol/S +extolled +extolling +extort/SGD +extortion/MRZ +extortionate/Y +extortioner/M +extortionist/MS +extra/SM +extracellular +extract/MDGS +extraction/SM +extractor/MS +extracurricular +extradite/GNBXDS +extradition/M +extrajudicial +extralegal +extramarital +extramural +extraneous/Y +extraordinaire +extraordinarily +extraordinary +extrapolate/XGNDS +extrapolation/M +extrasensory +extraterrestrial/MS +extraterritorial +extraterritoriality/M +extravagance/MS +extravagant/Y +extravaganza/MS +extravehicular +extreme/PMYTRS +extremeness/M +extremism/M +extremist/MS +extremity/SM +extricable/I +extricate/GNDS +extrication/M +extrinsic +extrinsically +extroversion/M +extrovert/SMD +extrude/GDS +extrusion/SM +extrusive +exuberance/M +exuberant/Y +exudation/M +exude/DSG +exult/SDG +exultant/Y +exultation/M +exurb/SM +exurban +exurbanite/SM +exurbia/M +eye/DSMG +eyeball/GMDS +eyebrow/SM +eyedropper/SM +eyeful/SM +eyeglass/MS +eyeing +eyelash/MS +eyeless +eyelet/SM +eyelid/SM +eyeliner/MS +eyeopener/MS +eyeopening +eyepiece/MS +eyesight/M +eyesore/MS +eyestrain/M +eyeteeth +eyetooth/M +eyewash/M +eyewitness/MS +f/CIAVTR +fa/M +fab +fable/DSM +fabric/SM +fabricate/DSGNX +fabrication/M +fabricator/SM +fabulous/Y +facade/SM +face's +face/ACSDG +facecloth/M +facecloths +faceless +facelift/SM +facet/SMDG +facetious/YP +facetiousness/M +facial/SMY +facile/Y +facilitate/GNDS +facilitation/M +facilitator/MS +facility/SM +facing/SM +facsimile/DSM +facsimileing +fact/MS +faction/SM +factional +factionalism/M +factious +factitious +factoid/SM +factor's +factor/ASDG +factorial/MS +factorization +factorize/GDS +factory/SM +factotum/SM +factual/Y +faculty/SM +fad/GSMD +faddish/P +faddist/MS +faddy/P +fade/MS +fading/U +faerie/SM +faff/DGS +fag/SM +fagged +fagging +faggot/SMG +fagot/SMG +faience/M +fail/MDGJS +failing/M +faille/M +failure/SM +fain/RT +faint/SMDRYTGP +fainthearted +faintness/M +fair/MRYTGJPS +fairground/MS +fairing/M +fairness/UM +fairway/SM +fairy/SM +fairyland/SM +faith/M +faithful's +faithful/UPY +faithfulness/UM +faithfuls +faithless/PY +faithlessness/M +faiths +fajita/SM +fajitas/M +fake/MZGDRS +faker/M +fakir/SM +falcon/SMRZ +falconer/M +falconry/M +fall/MNGS +fallacious/Y +fallacy/SM +fallback +fallibility/IM +fallible/P +fallibleness/M +fallibly/I +falloff/SM +fallout/M +fallow/SMDG +false/PRYT +falsehood/SM +falseness/M +falsetto/SM +falsie/SM +falsifiable +falsification/M +falsifier/M +falsify/DRSZGNX +falsity/SM +falter/GSJMD +faltering/Y +fame's +fame/D +familial +familiar/MYS +familiarity/UM +familiarization/M +familiarize/GDS +family/SM +famine/SM +famish/DSG +famous/IY +fan/SM +fanatic/SM +fanatical/Y +fanaticism/M +fanboy/SM +fanciable +fancier/M +fanciful/YP +fancifulness/M +fancily +fanciness/M +fancy/DRSMZTGP +fancywork/M +fandango/MS +fandom +fanfare/SM +fang/MDS +fanlight/SM +fanned +fanning +fanny/SM +fantail/MS +fantasia/SM +fantasist/S +fantasize/GDS +fantastic +fantastical/Y +fantasy/DSMG +fanzine/MS +far +farad/SM +faradize/DG +faraway +farce/SM +farcical/Y +fare/MGDS +farewell/SM +farfetched +farina/M +farinaceous +farm/MDRZGSJ +farmer/M +farmhand/SM +farmhouse/SM +farming/M +farmland/MS +farmstead/MS +farmyard/MS +faro/M +farrago/M +farragoes +farrier/MS +farrow/SMDG +farseeing +farsighted/P +farsightedness/M +fart/MDGS +farther +farthermost +farthest +farthing/SM +fascia/SM +fascicle/SM +fascinate/GNDSX +fascinating/Y +fascination/M +fascism/M +fascist/MS +fascistic +fashion/ZGBMDRS +fashionable/U +fashionably/U +fashioner/M +fashionista/MS +fast/MDRTGSP +fastback/SM +fastball/SM +fasten/UAGDS +fastener/SM +fastening/MS +fastidious/PY +fastidiousness/M +fastness/MS +fat/GSPMD +fatal/Y +fatalism/M +fatalist/SM +fatalistic +fatalistically +fatality/SM +fatback/M +fate/MS +fateful/YP +fatefulness/M +fathead/MDS +father/SGMDY +fatherhood/M +fatherland/MS +fatherless +fathom/SMDGB +fathomable/U +fathomless +fatigue/MDSG +fatigues/M +fatness/M +fatso/S +fatten/SDG +fatter +fattest +fattiness/M +fatty/RSMTP +fatuity/M +fatuous/YP +fatuousness/M +fatwa/SM +faucet/SM +fault/CSMDG +faultfinder/SM +faultfinding/M +faultily +faultiness/M +faultless/PY +faultlessness/M +faulty/PRT +faun/MS +fauna/SM +fauvism/M +fauvist/SM +faux +fave/S +favor/ESMDG +favorable/U +favorably/U +favorite/SM +favoritism/M +fawn/MDRZGS +fawner/M +fax/GMDS +fay/TSMR +faze/GDS +fazed/U +faence/M +fealty/M +fear/MDGS +fearful/YP +fearfulness/M +fearless/PY +fearlessness/M +fearsome +feasibility/M +feasible/IU +feasibly +feast/SMDRZG +feaster/M +feat/MS +feather/SGMD +featherbedding/M +featherbrained +featherless +featherweight/MS +feathery/TR +feature/DSMG +featureless +febrile +fecal +feces/M +feckless/PY +fecund +fecundate/GNDS +fecundation/M +fecundity/M +fed/SM +federal/SMY +federalism/M +federalist/MS +federalization/M +federalize/GDS +federate/FXDSGN +federation/FM +fedora/SM +fee/SM +feeble/RTP +feebleness/M +feebly +feed/MRZGSJ +feedback/M +feedbag/SM +feeder/M +feeding/M +feedlot/SM +feel/MRZGSJ +feeler/M +feelgood +feeling/MY +feet +feign/SDG +feigned/U +feint/SMDG +feisty/TR +feldspar/M +felicitate/GNXDS +felicitation/M +felicitous/Y +felicity/ISM +feline/SM +fell/MDRZTGS +fella/S +fellatio/M +fellow/SM +fellowman/M +fellowmen +fellowship/MS +felon/SM +felonious +felony/SM +felt/MDGS +fem +female/PSM +femaleness/M +feminine/SMY +femininity/M +feminism/M +feminist/SM +feminize/DSG +femoral +femur/SM +fen/SM +fence/DRSMZG +fencer/M +fencing/M +fend/CDRZGS +fender/CM +fenestration/M +fennel/M +feral +ferment/FCMS +fermentation/M +fermented +fermenting +fermium/M +fern/MS +ferny/RT +ferocious/PY +ferociousness/M +ferocity/M +ferret/GSMD +ferric +ferromagnetic +ferrous +ferrule/MS +ferry/DSMG +ferryboat/SM +ferryman/M +ferrymen +fertile/I +fertility/IM +fertilization/M +fertilize/DRSZG +fertilized/U +fertilizer/M +ferule/SM +fervency/M +fervent/Y +fervid/Y +fervor/M +fess/FKGSD +fest/MRZVS +festal +fester/GMD +festival/SM +festive/YP +festiveness/M +festivity/SM +festoon/GMDS +feta/M +fetal +fetch/DRSZG +fetcher/M +fetching/Y +fete/MGDS +fetid/P +fetidness/M +fetish/MS +fetishism/M +fetishist/SM +fetishistic +fetlock/MS +fetter's +fetter/USGD +fettle/M +fettuccine/M +fetus/MS +feud/MDGS +feudal +feudalism/M +feudalistic +fever/SMD +feverish/YP +feverishness/M +few/TPMR +fewness/M +fey +fez/M +fezzes +ff +fiance/CM +fiancee/MS +fiances +fianc/SM +fiance/MS +fiasco/SM +fiascoes +fiat/MS +fib/ZSMR +fibbed +fibber/SM +fibbing +fiber/M +fiberboard/M +fiberfill/M +fiberglass/M +fibril/SM +fibrillate/GNDS +fibrillation/M +fibrin/M +fibroid +fibrosis/M +fibrous +fibula/M +fibulae +fibular +fiche/SM +fichu/SM +fickle/RPT +fickleness/M +fiction/MS +fictional/Y +fictionalization/SM +fictionalize/DSG +fictitious/Y +fictive +ficus/M +fiddle/DRSMZG +fiddler/M +fiddlesticks +fiddly/TR +fidelity/IM +fidget/SGMD +fidgety +fiduciary/SM +fie +fief/MS +fiefdom/MS +field/ISMRZ +fielded +fielder/IM +fielding +fieldsman +fieldsmen +fieldwork/MRZ +fieldworker/M +fiend/SM +fiendish/Y +fierce/PRYT +fierceness/M +fieriness/M +fiery/RPT +fiesta/SM +fife/MZRS +fifer/M +fifteen/MHS +fifteenth/M +fifteenths +fifth/MY +fifths +fiftieth/M +fiftieths +fifty/SMH +fig/FSM +fight/SMRZG +fightback +fighter/IMS +fighting/IM +figment/MS +figuration/FM +figurative/Y +figure's +figure/EFGSD +figurehead/SM +figurine/MS +filament/MS +filamentous +filbert/MS +filch/DSG +file/KCSRDGZM +filename/S +filer/KCM +filesystem/SM +filet +filial +filibuster/MDRSZG +filibusterer/M +filigree/DSM +filigreeing +filing's +filings +fill's +fill/AIDGS +filled/U +filler/MS +fillet/MDGS +filling/SM +fillip/MDGS +filly/SM +film/MDGS +filminess/M +filmmaker/SM +filmography +filmstrip/MS +filmy/TPR +filo +filter/MDRBSZG +filtered/U +filterer/M +filth/M +filthily +filthiness/M +filthy/RPT +filtrate's +filtrate/IGNDS +filtration/IM +fin/SMR +finagle/DRSZG +finagler/M +final/SMY +finale/MS +finalist/SM +finality/M +finalization/M +finalize/DSG +finance's +finance/ADSG +financial/YS +financier/MS +financing/M +finch/MS +find/JMRZGS +finder/M +finding/M +findings/M +fine's/F +fine/CAFTGDS +finely +fineness/M +finery/AM +finespun +finesse/DSMG +finger/MDGSJ +fingerboard/SM +fingering/M +fingerling/SM +fingermark/S +fingernail/SM +fingerprint/SGMD +fingertip/MS +finial/MS +finical +finickiness/M +finicky/RPT +finis/MS +finish's +finish/ADSG +finished/U +finisher/MS +finite/IY +fink/MDGS +finned +finny +fir/ZGSJMDRH +fire/MS +firearm/SM +fireball/MS +firebomb/MDSJG +firebox/MS +firebrand/SM +firebreak/SM +firebrick/SM +firebug/SM +firecracker/SM +firedamp/M +firefight/MRSZG +firefighter/M +firefighting/M +firefly/SM +fireguard/S +firehouse/SM +firelight/ZMR +fireman/M +firemen +fireplace/SM +fireplug/MS +firepower/M +fireproof/DSG +firer/M +firescreen/S +fireside/MS +firestorm/MS +firetrap/MS +firetruck/MS +firewall/MS +firewater/M +firewood/M +firework/SM +firm/MDRYPTGS +firmament/SM +firmness/M +firmware/M +first/SMY +firstborn/SM +firsthand +firth/M +firths +fiscal/MYS +fish/MDRSZG +fishbowl/SM +fishcake/SM +fisher/M +fisherman/M +fishermen +fishery/SM +fishhook/SM +fishily +fishiness/M +fishing/M +fishmonger/MS +fishnet/SM +fishpond/MS +fishtail/DGS +fishwife/M +fishwives +fishy/TRP +fissile +fission/BM +fissure/SM +fist/MS +fistfight/MS +fistful/SM +fisticuffs/M +fistula/SM +fistulous/M +fit/KAMS +fitful/YP +fitfulness/M +fitly +fitment/S +fitness/UM +fitted/UA +fitter/MS +fittest +fitting/SMY +five/MZRS +fix/ZGBJMDRS +fixate/GNVDSX +fixation/M +fixative/MS +fixed/Y +fixer/M +fixings/M +fixity/M +fixture/MS +fizz/MDSG +fizzle/DSMG +fizzy/RT +fjord/SM +fl/JDG +flab/M +flabbergast/SGD +flabbily +flabbiness/M +flabby/RPT +flaccid/Y +flaccidity/M +flack/SM +flag/MS +flagella +flagellant/S +flagellate/GNDS +flagellation/M +flagellum/M +flagged +flagging/U +flagman/M +flagmen +flagon/MS +flagpole/SM +flagrance/M +flagrancy/M +flagrant/Y +flagship/SM +flagstaff/MS +flagstone/MS +flail/SGMD +flair/SM +flak/M +flake/DSMG +flakiness/M +flaky/TRP +flamage +flambe/MS +flambeed +flambeing +flamboyance/M +flamboyancy/M +flamboyant/Y +flamb/MD +flame/DRSJMZG +flamenco/MS +flameproof/DGS +flamethrower/SM +flamingo/MS +flammability/IM +flammable/SM +flan/MS +flange/MS +flank/SZGMDR +flanker/M +flannel/SGMD +flannelette/M +flap/MS +flapjack/MS +flapped +flapper/SM +flapping +flare/DSMG +flareup/SM +flash/ZTGMDRS +flashback/SM +flashbulb/SM +flashcard/SM +flashcube/SM +flasher/M +flashgun/SM +flashily +flashiness/M +flashing/M +flashlight/MS +flashpoint/SM +flashy/RTP +flask/SM +flat/MYPS +flatbed/SM +flatboat/SM +flatbread +flatcar/SM +flatfeet +flatfish/MS +flatfoot/SMD +flatiron/SM +flatland/M +flatlet/S +flatmate/S +flatness/M +flatted +flatten/SDG +flatter/SDRZG +flatterer/M +flattering/Y +flattery/M +flattest +flatting +flattish +flattop/SM +flatulence/M +flatulent +flatus/M +flatware/M +flatworm/SM +flaunt/MDSG +flaunting/Y +flavor/MDSGJ +flavored/U +flavorful +flavoring/M +flavorless +flavorsome +flaw/MDGS +flawless/PY +flawlessness/M +flax/MN +flay/DGS +flea/MS +fleabag/SM +fleabite/S +fleapit/S +fleck/SGMD +fledged/U +fledgling/MS +flee/S +fleece/MZGDRS +fleecer/M +fleeciness/M +fleecy/RTP +fleeing +fleet/STGMDRYP +fleetingly/M +fleetingness/M +fleetness/M +flesh/GMDSY +fleshly/TR +fleshpot/MS +fleshy/RT +flew +flex/AMS +flexed +flexibility/IM +flexible/I +flexibly/I +flexing +flexion +flextime/M +flibbertigibbet/SM +flick/SZGMDR +flicker/GMD +flier/M +flight/MS +flightiness/M +flightless +flighty/PTR +flimflam/SM +flimflammed +flimflamming +flimsily +flimsiness/M +flimsy/TRP +flinch/GMDS +fling/GM +flint/SM +flintlock/SM +flinty/TR +flip/MS +flippancy/M +flippant/Y +flipped +flipper/MS +flippest +flipping +flippy/S +flirt/SGMD +flirtation/MS +flirtatious/YP +flirtatiousness/M +flirty +flit/MS +flitted +flitting +float/SMDRZG +floater/M +flock/SMDG +flocking/M +floe/MS +flog/S +flogged +flogger/SM +flogging/MS +flood/SMDRG +floodgate/MS +floodlight/MDSG +floodlit +floodplain/MS +floodwater/MS +floor/SMDG +floorboard/MS +flooring/M +floorwalker/SM +floozie/M +floozy/SM +flop/MS +flophouse/MS +flopped +floppily +floppiness/M +flopping +floppy/PRSMT +flora/SM +floral +florescence/IM +florescent/I +floret/SM +florid/PY +floridness/M +florin/SM +florist/SM +floss/MDSG +flossy/RT +flotation/SM +flotilla/MS +flotsam/M +flounce/DSMG +flouncy +flounder/MDSG +flour/SMDG +flourish/GMDS +floury +flout/SMDRZG +flouter/M +flow/MDGS +flowchart/SM +flower's +flower/CSDG +flowerbed/MS +floweriness/M +flowering/S +flowerless +flowerpot/MS +flowery/PTR +flown +flt +flu/M +flub/MS +flubbed +flubbing +fluctuate/GNDSX +fluctuation/M +flue/MS +fluency/M +fluent/Y +fluff/SMDG +fluffiness/M +fluffy/RPT +fluid/SMY +fluidity/M +fluidize/GS +fluke/SM +fluky/RT +flume/SM +flummox/DSG +flung +flunk/SMDG +flunky/SM +fluoresce/DSG +fluorescence/M +fluorescent +fluoridate/GNDS +fluoridation/M +fluoride/SM +fluorine/M +fluorite/M +fluorocarbon/MS +fluoroscope/SM +fluoroscopic +flurry/GDSM +flush/MDRSTG +fluster/MDSG +flute/DSMG +fluting/M +flutist/MS +flutter/MDSG +fluttery +fluvial +flux's/A +flux/IMS +fluxed +fluxing +fly/ZTGBDRSM +flyaway +flyblown +flyby/M +flybys +flycatcher/MS +flyer/SM +flying/M +flyleaf/M +flyleaves +flyover/MS +flypaper/SM +flypast/S +flysheet/S +flyspeck/GMDS +flyswatter/MS +flytrap/S +flyway/SM +flyweight/SM +flywheel/MS +fo'c'sle/MS +foal/MDGS +foam/MDGS +foaminess/M +foamy/RTP +fob/SM +fobbed +fobbing +focal/Y +foci +focus's +focus/ADSG +focused/U +fodder/SM +foe/SM +fog's +fog/CS +fogbound +fogged/C +foggily +fogginess/M +fogging/C +foggy/RTP +foghorn/MS +fogy/SM +fogyish +foible/SM +foil/MDGS +foist/SDG +fol +fold's +fold/AUSGD +foldaway +folder/SM +foldout/MS +foliage/M +folic +folio/SM +folk/MS +folklore/M +folkloric +folklorist/MS +folksiness/M +folksinger/SM +folksinging/M +folksy/PTR +folktale/MS +folkway/MS +foll +follicle/MS +follow/SDRZGJ +follower/M +following/M +followup/S +folly/SM +foment/SGD +fomentation/M +fond/RYTP +fondant/MS +fondle/DSG +fondness/M +fondue/SM +font/MS +fontanel/MS +fontanelle/MS +foo +foobar +food/MS +foodie/SM +foodstuff/SM +fool/MDGS +foolery/SM +foolhardily +foolhardiness/M +foolhardy/TPR +foolish/YP +foolishness/M +foolproof +foolscap/M +foot/MDRZGSJ +footage/M +football/MRZGS +footballer/M +footbridge/SM +footfall/MS +foothill/MS +foothold/MS +footie +footing/M +footless +footlights/M +footling/MS +footlocker/SM +footloose +footman/M +footmen +footnote/MGDS +footpath/M +footpaths +footplate/S +footprint/SM +footrace/MS +footrest/MS +footsie/SM +footslogging +footsore +footstep/MS +footstool/SM +footwear/M +footwork/M +footy +fop/SM +foppery/M +foppish/P +foppishness/M +for/H +fora +forage/DRSMZG +forager/M +foray/SMDG +forbade +forbear/SMG +forbearance/M +forbid/S +forbidden +forbidding/YS +forbore +forborne +force/DSMG +forced/U +forceful/PY +forcefulness/M +forceps/M +forcible +forcibly +ford/MDGSB +fore/MS +forearm/GSMD +forebear/MS +forebode/GJDS +foreboding/M +forecast/MRZGS +forecaster/M +forecastle/MS +foreclose/DSG +foreclosure/MS +forecourt/SM +foredoom/DGS +forefather/MS +forefeet +forefinger/SM +forefoot/M +forefront/SM +foregather/GDS +forego/G +foregoes +foregone +foreground/GMDS +forehand/MS +forehead/MS +foreign/ZRP +foreigner/M +foreignness/M +foreknew +foreknow/GS +foreknowledge/M +foreknown +foreleg/SM +forelimb/MS +forelock/MS +foreman/M +foremast/MS +foremen +foremost +forename/MDS +forenoon/MS +forensic/MS +forensically +forensics/M +foreordain/GSD +forepart/MS +foreperson/SM +foreplay/M +forequarter/MS +forerunner/MS +foresail/MS +foresaw +foresee/RSBZ +foreseeable/U +foreseeing +foreseen/U +foreseer/M +foreshadow/GDS +foreshore/S +foreshorten/DSG +foresight/MD +foresightedness/M +foreskin/MS +forest's +forest/ACGDS +forestall/SGD +forestation/ACM +forester/MS +forestland/M +forestry/M +foretaste/DSMG +foretell/GS +forethought/M +foretold +forever/M +forevermore +forewarn/DSG +forewent +forewoman/M +forewomen +foreword/MS +forfeit/GSMD +forfeiture/SM +forgather/SDG +forgave +forge/DRSMZGVJ +forger/M +forgery/SM +forget/S +forgetful/YP +forgetfulness/M +forgettable/U +forgetting +forging/M +forgivable/U +forgive/BRSZGP +forgiven +forgiveness/M +forgiver/M +forgiving/U +forgo/RZG +forgoer/M +forgoes +forgone +forgot +forgotten/U +fork/MDGS +forkful/SM +forklift/MS +forlorn/Y +form's +form/CAIFDGS +forma/K +formal/SMY +formaldehyde/M +formalin +formalism/M +formalist/MS +formalities +formality/IM +formalization/M +formalize/GDS +format/SMV +formation/CFASM +formatted/A +formatting/M +formed/U +former/FIAM +formerly +formfitting +formic +formidable +formidably +formless/PY +formlessness/M +formula/MS +formulae +formulaic +formulate/ADSGNX +formulated/U +formulation/AM +formulator/SM +fornicate/GNDS +fornication/M +fornicator/MS +forsake/GS +forsaken +forsook +forsooth +forswear/SG +forswore +forsworn +forsythia/SM +fort/MS +forte/SM +forthcoming/M +forthright/YP +forthrightness/M +forthwith +fortieth/M +fortieths +fortification/M +fortified/U +fortifier/M +fortify/DRSNZGX +fortissimo +fortitude/M +fortnight/MYS +fortress/MS +fortuitous/YP +fortuitousness/M +fortuity/M +fortunate/UY +fortune/MS +fortuneteller/SM +fortunetelling/M +forty/SMH +forum/SM +forward/MDRYZTGSP +forwarder/M +forwardness/M +forwent +fossa +fossil/SM +fossilization/M +fossilize/GDS +foster/GSD +fought +foul/MDRYTGSP +foulard/M +foulmouthed +foulness/M +found/FSDG +foundation/SM +founded/U +founder/GMDS +foundling/SM +foundry/SM +fount/SM +fountain/SM +fountainhead/MS +four/MHS +fourfold +fourposter/SM +fourscore/M +foursome/SM +foursquare +fourteen/SMH +fourteenth/M +fourteenths +fourth/MY +fourths +fowl/MDGS +fox/GMDS +foxfire/M +foxglove/SM +foxhole/MS +foxhound/SM +foxhunt/GS +foxily +foxiness/M +foxtrot/MS +foxtrotted +foxtrotting +foxy/RTP +foyer/SM +fps +fr +fracas/MS +frack/SDRZG +fractal/SM +fraction/ISM +fractional/Y +fractious/YP +fractiousness/M +fracture/MGDS +frag/S +fragile/RT +fragility/M +fragment/GMDS +fragmentary/M +fragmentation/M +fragrance/MS +fragrant/Y +frail/RYTP +frailness/M +frailty/SM +frame/DRSMZG +framed/U +framer/M +framework/SM +franc/SM +franchise's +franchise/EDSG +franchisee/SM +franchiser/SM +franchisor/SM +francium/M +francophone +frangibility/M +frangible +frank/SMDRYTGP +frankfurter/MS +frankincense/M +frankness/M +frantic +frantically +frappe/SM +frapp/M +frat/MS +fraternal/Y +fraternity/FSM +fraternization/M +fraternize/ZGDRS +fraternizer/M +fratricidal +fratricide/MS +fraud's +fraud/S +fraudster/S +fraudulence/M +fraudulent/Y +fraught +fray's +fray/CDGS +frazzle/MGDS +freak/SMDG +freakish/YP +freakishness/M +freakout/MS +freaky/RT +freckle/DSMG +freckly +free/YTDRS +freebase/MGDS +freebee/SM +freebie/SM +freebooter/SM +freeborn +freedman/M +freedmen +freedom/SM +freegan/S +freehand +freehold/ZMRS +freeholder/M +freeing +freelance/DRSMZG +freelancer/M +freeload/SDRZG +freeloader/M +freeman/M +freemasonry +freemen +freephone +freesia/S +freestanding +freestone/SM +freestyle/SM +freethinker/SM +freethinking/M +freeware/M +freeway/MS +freewheel/DGS +freewill +freezable +freeze's +freeze/UAGS +freezer/MS +freezing's +freight/MDRZGS +freighter/M +french +frenetic +frenetically +frenzied/Y +frenzy/DSM +freq +frequencies +frequency/IM +frequent/DRYSZTG +frequented/U +frequenter/M +fresco/M +frescoes +fresh/PNRYXZT +freshen/ZGDR +freshener/M +freshet/MS +freshman/M +freshmen +freshness/M +freshwater/M +fret/MS +fretful/YP +fretfulness/M +fretsaw/MS +fretted +fretting +fretwork/M +friable +friar/SM +friary/SM +fricassee/DSM +fricasseeing +fricative/SM +friction/SM +frictional +fridge/SM +friedcake/MS +friend's +friend/UGSDY +friendless +friendlies +friendliness/UM +friendly's +friendly/UPTR +friendship/MS +frieze/SM +frig/S +frigate/MS +frigged +frigging +fright/SXGMDN +frighten/DG +frightening/Y +frightful/PY +frightfulness/M +frigid/YP +frigidity/M +frigidness/M +frill/SMD +frilly/TR +fringe's +fringe/IDSG +frippery/SM +frisk/SDG +friskily +friskiness/M +frisky/TRP +frisson/S +fritter/MDSG +fritz/M +frivolity/SM +frivolous/PY +frivolousness/M +frizz/MDSYG +frizzle/MGDS +frizzy/TR +fro +frock's +frock/CUS +frog/MS +frogging/S +frogman/M +frogmarch/GDS +frogmen +frogspawn +frolic/SM +frolicked +frolicker/SM +frolicking +frolicsome +from +frond/SM +front's +front/FSDG +frontage/MS +frontal/Y +frontbench/ZRS +frontier/MS +frontiersman/M +frontiersmen +frontierswoman +frontierswomen +frontispiece/MS +frontward/S +frosh/M +frost's +frost/CSDG +frostbit +frostbite/MGS +frostbitten +frostily +frostiness/M +frosting/SM +frosty/TPR +froth/MDG +frothiness/M +froths +frothy/TPR +froufrou/M +froward/P +frowardness/M +frown/SMDG +frowsy/TR +frowzily +frowziness/M +frowzy/TPR +froze/AU +frozen/UA +fructify/DSG +fructose/M +frugal/Y +frugality/M +fruit/SMDG +fruitcake/MS +fruiterer/S +fruitful/YP +fruitfulness/M +fruitiness/M +fruition/M +fruitless/PY +fruitlessness/M +fruity/TPR +frump/SM +frumpish +frumpy/TR +frustrate/GNXDS +frustrating/Y +frustration/M +frustum/MS +fry/GDSM +fryer/SM +ft +ftp/ZGS +fuchsia/MS +fuck/SMGDRZ! +fucker/M! +fuckhead/SM! +fuddle/DSMG +fudge/DSMG +fuehrer/MS +fuel's +fuel/ADGS +fug +fugal +fuggy +fugitive/MS +fugue/SM +fuhrer/SM +fulcrum/MS +fulfill/LDGS +fulfilled/U +fulfilling/U +fulfillment/M +full/MDRZTGSP +fullback/MS +fuller/M +fullness/M +fully +fulminate/DSXGN +fulmination/M +fulsome/PY +fulsomeness/M +fum/S +fumble/DRSMZG +fumbler/M +fumbling/Y +fume/MGDS +fumigant/MS +fumigate/GNDS +fumigation/M +fumigator/SM +fumy/RT +fun/M +function/MDGS +functional/Y +functionalism +functionalist/S +functionality/S +functionary/SM +fund/AMDGS +fundamental/SMY +fundamentalism/M +fundamentalist/SM +funded/U +funding/M +fundraiser/MS +fundraising +funeral/MS +funerary +funereal/Y +funfair/S +fungal +fungi +fungible/MS +fungicidal +fungicide/MS +fungoid +fungous +fungus/M +funicular/SM +funk/MDGS +funkiness/M +funky/PRT +funnel/MDGS +funner +funnest +funnily +funniness/M +funny/TPRSM +funnyman/M +funnymen +fur/SM +furbelow/M +furbish/ADSG +furious/Y +furl's +furl/UDGS +furlong/SM +furlough/GMD +furloughs +furn +furnace/SM +furnish/ADSG +furnished/U +furnishings/M +furniture/M +furor/SM +furred +furrier/M +furriness/M +furring/M +furrow/MDSG +furry/ZTRP +further/SGD +furtherance/M +furthermore +furthermost +furthest +furtive/YP +furtiveness/M +fury/SM +furze/M +fuse's/A +fuse/CAIFGDS +fusee/SM +fuselage/SM +fusibility/M +fusible +fusileer/SM +fusilier/SM +fusillade/MS +fusion/IFKSM +fuss/MDSG +fussbudget/MS +fussily +fussiness/M +fusspot/SM +fussy/TRP +fustian/M +fustiness/M +fusty/TRP +fut +futile/Y +futility/M +futon/SM +future/MS +futurism/M +futurist/MS +futuristic +futurity/SM +futurologist/MS +futurology/M +futz/DSG +fuzz/MDSG +fuzzball/S +fuzzily +fuzziness/M +fuzzy/PTR +fwd +fwy +fte/SM +g/SNXVB +gab/SM +gabardine/SM +gabbed +gabbiness/M +gabbing +gabble/DSMG +gabby/RTP +gaberdine/SM +gabfest/MS +gable/DSM +gad/S +gadabout/SM +gadded +gadder/SM +gadding +gadfly/SM +gadget/SM +gadgetry/M +gadolinium/M +gaff/MDRZGS +gaffe/SM +gaffer/M +gag/SM +gaga +gagged +gagging +gaggle/SM +gaiety/M +gaily +gain's +gain/ADGS +gainer/SM +gainful/Y +gainsaid +gainsay/ZGRS +gainsayer/M +gait/MRZS +gaiter/M +gal/SM +gala/MS +galactic +galaxy/SM +gale's +gale/AS +galena/M +gall/MDGS +gallant/SMY +gallantry/M +gallbladder/MS +galleon/SM +galleria/MS +gallery/SM +galley/SM +gallimaufry/SM +gallium/M +gallivant/GSD +gallon/SM +gallop/SMDG +gallows/M +gallstone/MS +galoot/SM +galore +galosh/MS +galumph/DG +galumphs +galvanic +galvanism/M +galvanization/M +galvanize/DSG +galvanometer/MS +gambit/SM +gamble/DRSMZG +gambler/M +gambling/M +gambol/SMDG +game/MYTGDRSP +gamecock/MS +gamekeeper/MS +gameness/M +gamesmanship/M +gamester/MS +gamete/SM +gametic +gamey +gamify/DSNG +gamin/SM +gamine/SM +gaminess/M +gaming/M +gamma/SM +gammon/M +gammy +gamut/SM +gamy/RTP +gander/SM +gang/MDGS +gangbusters/M +gangland/M +ganglia +gangling +ganglion/M +ganglionic +gangplank/SM +gangrene/DSMG +gangrenous +gangsta/S +gangster/SM +gangway/MS +ganja +gannet/SM +gantlet/MS +gantry/SM +gap/GSMD +gape/MS +gar/SLM +garage/DSMG +garb/MDGS +garbage/M +garbageman +garbanzo/SM +garble/DSG +garcon/SM +garden/SZGMDR +gardener/M +gardenia/MS +gardening/M +garfish/MS +gargantuan +gargle/DSMG +gargoyle/SM +garish/PY +garishness/M +garland/MDGS +garlic/M +garlicky +garment/MS +garner/SGD +garnet/SM +garnish/GLMDS +garnishee/DSM +garnisheeing +garnishment/SM +garotte/MGDS +garret/SM +garrison/MDSG +garrote/MZGDRS +garroter/M +garrotte/MGDS +garrulity/M +garrulous/PY +garrulousness/M +garter/SM +garon/SM +gas's +gas/CS +gasbag/SM +gaseous +gash/MDSG +gasholder/S +gasket/SM +gaslight/MS +gasman +gasmen +gasohol/M +gasoline/M +gasometer/S +gasp/MDGS +gassed/C +gasses +gassing/C +gassy/RT +gastric +gastritis/M +gastroenteritis/M +gastroenterologist/M +gastroenterology +gastrointestinal +gastronome/S +gastronomic +gastronomical/Y +gastronomy/M +gastropod/SM +gasworks/M +gate/MGDS +gateau +gateaux +gatecrash/DRSZG +gatecrasher/M +gatehouse/SM +gatekeeper/MS +gatepost/MS +gateway/MS +gather/SJZGMDR +gatherer/M +gathering/M +gator/SM +gauche/RPYT +gaucheness/M +gaucherie/M +gaucho/SM +gaudily +gaudiness/M +gaudy/RPT +gauge/DSMG +gaunt/RPT +gauntlet/MS +gauntness/M +gauze/M +gauziness/M +gauzy/RPT +gave +gavel/SM +gavotte/MS +gawd +gawk/DGS +gawkily +gawkiness/M +gawky/RPT +gawp/DGS +gay/TSPMR +gayness/M +gaze/MZGDRS +gazebo/SM +gazelle/MS +gazer/M +gazette/MGDS +gazetteer/MS +gazillion/S +gazpacho/M +gazump/DGS +gear/MDGS +gearbox/MS +gearing/M +gearshift/MS +gearwheel/SM +gecko/SM +geddit +gee/DS +geeing +geek/MS +geeky/RT +geese +geezer/MS +geisha/M +gel/SM +gelatin/M +gelatinous +gelcap/M +geld/DJGS +gelding/M +gelid +gelignite/M +gelled +gelling +gem/SM +gemmology/M +gemological +gemologist/MS +gemology/M +gemstone/MS +gendarme/MS +gender/MDS +gene/MS +genealogical/Y +genealogist/MS +genealogy/SM +genera +general/SMY +generalissimo/MS +generalist/MS +generality/SM +generalization/MS +generalize/GDS +generalship/M +generate/ACDSGNV +generation's/A +generation/CSM +generational +generator/SM +generic/SM +generically +generosity/SM +generous/PY +generousness/M +genes/S +genesis/M +genetic/S +genetically +geneticist/MS +genetics/M +genial/FY +geniality/FM +geniculate +genie/SM +genii +genital/FY +genitalia/M +genitals/M +genitive/MS +genitourinary +genius/MS +genned +genning +genocidal +genocide/MS +genome/MS +genomics +genre/SM +gent/AMS +genteel/YP +genteelness/M +gentian/SM +gentile/SM +gentility/M +gentle/TGDRSP +gentlefolk/MS +gentlefolks/M +gentleman/MY +gentlemanly/U +gentlemen +gentleness/M +gentlewoman/M +gentlewomen +gently +gentrification/M +gentrify/DSGN +gentry/SM +genuflect/DGS +genuflection/MS +genuine/PY +genuineness/M +genus/M +geocache/DSG +geocentric +geocentrically +geochemistry/M +geode/SM +geodesic/SM +geodesy/M +geodetic +geoengineering +geog +geographer/SM +geographic +geographical/Y +geography/SM +geologic +geological/Y +geologist/MS +geology/SM +geom +geomagnetic +geomagnetism/M +geometer +geometric +geometrical/Y +geometry/SM +geophysical +geophysicist/SM +geophysics/M +geopolitical +geopolitics/M +geostationary +geosynchronous +geosyncline/MS +geothermal +geothermic +geranium/MS +gerbil/MS +geriatric/S +geriatrician/S +geriatrics/M +germ/MS +germane +germanium/M +germicidal +germicide/MS +germinal/M +germinate/GNDS +germination/M +gerontological +gerontologist/MS +gerontology/M +gerrymander/GMDS +gerrymandering/M +gerund/MS +gestalt/S +gestapo/MS +gestate/GNDS +gestation/M +gestational +gesticulate/DSGNX +gesticulation/M +gestural +gesture/MGDS +gesundheit +get/S +getaway/SM +getting +getup/M +gewgaw/SM +geyser/SM +ghastliness/M +ghastly/TPR +ghat/MS +ghee +gherkin/MS +ghetto/SM +ghettoize/GDS +ghost/SMDYG +ghostliness/M +ghostly/RTP +ghostwrite/ZGRS +ghostwriter/M +ghostwritten +ghostwrote +ghoul/SM +ghoulish/YP +ghoulishness/M +giant/SM +giantess/MS +gibber/GDS +gibberish/M +gibbet/GMDS +gibbon/MS +gibbous +gibe/MGDS +giblet/SM +giddily +giddiness/M +giddy/RTP +gift/MDGS +gig/SM +gigabit/SM +gigabyte/MS +gigahertz/M +gigajoule/SM +gigantic +gigantically +gigapixel/MS +gigawatt/SM +gigged +gigging +giggle/DRSMZG +giggler/M +giggly/RT +gigolo/SM +gild/MDRZGS +gilder/M +gilding/M +gill/MS +gillie/S +gillion/S +gilt/MS +gimbals/M +gimcrack/SM +gimcrackery/M +gimlet/GSMD +gimme/SM +gimmick/MS +gimmickry/M +gimmicky +gimp/MDGS +gimpy +gin/SM +ginger/GSMDY +gingerbread/M +gingersnap/SM +gingery +gingham/M +gingivitis/M +ginkgo/SM +ginkgoes +ginned +ginning +ginormous +ginseng/M +giraffe/MS +gird/DRZGS +girder/M +girdle/DSMG +girl/MS +girlfriend/MS +girlhood/SM +girlie +girlish/YP +girlishness/M +girly/S +giro/S +girt/MDGS +girth/M +girths +gist/M +git/S +gite/S +give/ZGJRS +giveaway/MS +giveback/MS +given/SM +giver/M +gizmo/SM +gizzard/MS +glace/S +glaceed +glaceing +glacial/Y +glaciate/XGNDS +glaciation/M +glacier/MS +glac/SDG +glad/MYSP +gladden/GDS +gladder +gladdest +glade/SM +gladiator/SM +gladiatorial +gladiola/SM +gladioli +gladiolus/M +gladness/M +gladsome +glam +glamor/SGMD +glamorization/M +glamorize/DSG +glamorous/Y +glamour/GMDS +glance/DSMG +gland/SM +glandes +glandular +glans/M +glare/DSMG +glaring/Y +glasnost/M +glass/MDSG +glassblower/MS +glassblowing/M +glassful/SM +glasshouse/S +glassily +glassiness/M +glassware/M +glassy/RTP +glaucoma/M +glaze/DSMG +glazier/SM +glazing/M +gleam/SMDGJ +glean/SDRZGJ +gleaner/M +gleanings/M +glee/M +gleeful/YP +gleefulness/M +glen/MS +glenohumeral +glenoid +glib/YP +glibber +glibbest +glibness/M +glide/DRSMZG +glider/M +gliding/M +glimmer/MDGJS +glimmering/M +glimpse/MGDS +glint/SMDG +glissandi +glissando/M +glisten/MDSG +glister/DSG +glitch/GMDS +glitter/MDSG +glitterati +glittery +glitz/M +glitzy/TR +gloaming/SM +gloat/SMDG +gloating/Y +glob/MDGS +global/Y +globalism/M +globalist/MS +globalization/M +globalize/GDS +globe/SM +globetrotter/MS +globetrotting +globular +globule/MS +globulin/M +glockenspiel/SM +gloom/M +gloomily +gloominess/M +gloomy/TRP +glop/M +gloppy +glorification/M +glorify/GDSN +glorious/IY +glory/DSMG +gloss/MDSG +glossary/SM +glossily +glossiness/M +glossolalia/M +glossy/PTRSM +glottal +glottis/MS +glove/DSMG +glow/MDRZGS +glower/GMD +glowing/Y +glowworm/MS +glucagon +glucose/M +glue/MGDS +glued/U +gluey +gluier +gluiest +glum/YP +glummer +glummest +glumness/M +glut/MNS +gluten/M +glutenous +glutinous/Y +glutted +glutting +glutton/MS +gluttonous/Y +gluttony/M +glycerin/M +glycerine/M +glycerol/M +glycogen/M +glyph +gm +gnarl/SMDG +gnarly/TR +gnash/MDSG +gnat/MS +gnaw/DGS +gneiss/M +gnocchi +gnome/SM +gnomic +gnomish +gnu/SM +go/JMRHZG +goad/MDGS +goal/MS +goalie/SM +goalkeeper/MS +goalkeeping/M +goalless +goalmouth +goalmouths +goalpost/MS +goalscorer/S +goaltender/MS +goat/MS +goatee/SM +goatherd/MS +goatskin/MS +gob/SM +gobbed +gobbet/SM +gobbing +gobble/DRSMZG +gobbledygook/M +gobbler/M +goblet/SM +goblin/SM +gobsmacked +gobstopper/S +god/SM +godawful +godchild/M +godchildren/M +goddam/D +goddammit +goddamn/D +goddaughter/MS +goddess/MS +godfather/SM +godforsaken +godhead/M +godhood/M +godless/PY +godlessness/M +godlike +godliness/UM +godly/URTP +godmother/SM +godparent/SM +godsend/SM +godson/SM +godspeed +goer/M +goes +gofer/SM +goggle/DSMG +goggles/M +going/M +goiter/SM +gold/MNS +goldbrick/ZGSMDR +goldbricker/M +golden/TR +goldenrod/M +goldfield/S +goldfinch/MS +goldfish/MS +goldmine/SM +goldsmith/M +goldsmiths +golf/MDRZGS +golfer/M +golliwog/S +golly/SM +gonad/SM +gonadal +gondola/MS +gondolier/SM +gone/ZR +goner/M +gong/MDGS +gonk/S +gonna +gonorrhea/M +gonorrheal +gonzo +goo/M +goober/SM +good/MYSP +goodby/M +goodbye/MS +goodbys +goodhearted +goodie/M +goodish +goodly/TR +goodness/M +goodnight +goods/M +goodwill/M +goody/SM +gooey +goof/MDGS +goofball/SM +goofiness/M +goofy/RPT +google/DSMG +googly/S +gooier +gooiest +gook/MS +goon/MS +goop/M +goose/DSMG +gooseberry/SM +goosebumps/M +gooseflesh/M +goosestep/S +goosestepped +goosestepping +gopher/SM +gore/MGDS +gorge's +gorge/EDSG +gorgeous/YP +gorgeousness/M +gorgon/SM +gorilla/MS +gorily +goriness/M +gormandize/DRSZG +gormandizer/M +gormless +gorp/MS +gorse/M +gory/RTP +gosh +goshawk/MS +gosling/SM +gospel/MS +gossamer/M +gossip/MDRZGS +gossiper/M +gossipy +got +gotcha/S +goths +gotta +gotten +gouache/S +gouge/DRSMZG +gouger/M +goulash/MS +gourd/SM +gourde/MS +gourmand/SM +gourmet/SM +gout/M +gouty/TR +gov +govern/DGSBL +governable/U +governance/M +governed/U +governess/MS +government/MS +governmental +governor/SM +governorship/M +govt +gown/MDGS +gr +grab/MS +grabbed +grabber/MS +grabbing +grabby/TR +grace/EDSMG +graceful/EPY +gracefulness/EM +graceless/PY +gracelessness/M +gracious/UY +graciousness/M +grackle/MS +grad/MRZSB +gradate/XGNDS +gradation/CM +grade's +grade/CADSG +graded/U +grader/M +gradient/MS +gradual/PY +gradualism/M +gradualness/M +graduate/XMGNDS +graduation/M +graffiti +graffito/M +graft/SMDRZG +grafter/M +graham/S +grail +grain/ISMD +graininess/M +grainy/PTR +gram/KMS +grammar/MS +grammarian/SM +grammatical/UY +grammatically/K +gramophone/MS +grampus/MS +gran/S +granary/SM +grand/SMRYPT +grandad/MS +grandam/MS +grandaunt/MS +grandchild/M +grandchildren/M +granddad/SM +granddaddy/SM +granddaughter/SM +grande +grandee/MS +grandeur/M +grandfather/GMDYS +grandiloquence/M +grandiloquent +grandiose/Y +grandiosity/M +grandma/MS +grandmother/MYS +grandnephew/MS +grandness/M +grandniece/MS +grandpa/MS +grandparent/MS +grandson/MS +grandstand/SGMD +granduncle/SM +grange/SM +granite/M +granitic +grannie/M +granny/SM +granola/M +grant/SMDRZG +grantee/MS +granter/M +grantsmanship/M +granular +granularity/M +granulate/GNDS +granulation/M +granule/MS +grape/SM +grapefruit/MS +grapeshot/M +grapevine/SM +graph/MDG +graphic/MS +graphical/Y +graphite/M +graphologist/MS +graphology/M +graphs +grapnel/MS +grapple/MGDS +grasp/SMDBG +grass/MDSG +grasshopper/MS +grassland/MS +grassroots +grassy/TR +grate/DRSMZGJ +grateful/UYP +gratefulness/UM +grater/M +gratification/M +gratify/GNXDS +gratifying/Y +gratin/S +grating/MY +gratis +gratitude/IM +gratuitous/YP +gratuitousness/M +gratuity/SM +gravamen/MS +grave/DRSMYTGP +gravedigger/SM +gravel/SGMDY +graven +graveness/M +graveside/MS +gravestone/SM +graveyard/MS +gravid +gravimeter/MS +gravitas +gravitate/GNDS +gravitation/M +gravitational +gravity/M +gravy/SM +gray/MDRTGSP +graybeard/SM +grayish +grayness/M +graze/DRSMZG +grazer/M +grease/DRSMZG +greasepaint/M +greasily +greasiness/M +greasy/PTR +great/SMRYPT +greatcoat/SM +greathearted +greatness/M +grebe/SM +greed/M +greedily +greediness/M +greedy/PTR +green/GPSMDRYT +greenback/MS +greenbelt/MS +greenery/M +greenfield +greenfly/S +greengage/MS +greengrocer/SM +greenhorn/SM +greenhouse/SM +greenish +greenmail/M +greenness/M +greenroom/SM +greensward/M +greenwood/M +greet/ZGJSDR +greeter/M +greeting/M +gregarious/PY +gregariousness/M +gremlin/SM +grenade/SM +grenadier/MS +grenadine/M +grep/S +grepped +grepping +grew/A +grey/MDRTGS +greybeard's +greybeards +greyhound/SM +greyness's +gribble/S +grid/MS +griddle/SM +griddlecake/SM +gridiron/SM +gridlock/SMD +grief/SM +grievance/MS +grieve/ZGDRS +griever/M +grievous/PY +grievousness/M +griffin/SM +griffon/SM +grill/SGMDJ +grille/MS +grim/DYPG +grimace/DSMG +grime/SM +griminess/M +grimmer +grimmest +grimness/M +grimy/TRP +grin/MS +grind/SZGMRJ +grinder/M +grindstone/MS +gringo/MS +grinned +grinning +grip/MDRSZG +gripe/SM +griper/M +grippe/MZGDR +gripper/M +grisliness/M +grisly/RTP +grist/MY +gristle/M +gristmill/MS +grit/MS +grits/M +gritted +gritter/SM +grittiness/M +gritting +gritty/RTP +grizzle/DSG +grizzly/TRSM +groan/SGMD +groat/SM +grocer/MS +grocery/SM +grog/M +groggily +grogginess/M +groggy/PRT +groin/SM +grok/S +grokked +grokking +grommet/SM +groom/SZGMDR +groomer/M +grooming/M +groomsman/M +groomsmen +groove/MGDS +groovy/RT +grope/DRSMZG +groper/M +grosbeak/MS +grosgrain/M +gross/PTGMDRSY +grossness/M +grotesque/SPMY +grotesqueness/M +grotto/M +grottoes +grotty/TR +grouch/GMDS +grouchily +grouchiness/M +grouchy/RTP +ground/ZGMDRJS +groundbreaking/MS +groundcloth +groundcloths +grounder/M +groundhog/MS +grounding/M +groundless/Y +groundnut/MS +groundsheet/S +groundskeeper/S +groundsman +groundsmen +groundswell/SM +groundwater/M +groundwork/M +group/JSZGMDR +grouper/M +groupie/MS +grouping/M +groupware/M +grouse/MZGDRS +grouser/M +grout/SGMD +grove/SM +grovel/ZGDRS +groveler/M +grovelled +grovelling +grow/AHSG +grower/MS +growing/I +growl/SZGMDR +growler/M +grown/AI +grownup/MS +growth/AM +growths +grub/MS +grubbed +grubber/MS +grubbily +grubbiness/M +grubbing +grubby/TRP +grubstake/M +grudge/MGDS +grudging/Y +grue/S +gruel/GJM +grueling/Y +gruesome/RYTP +gruesomeness/M +gruff/TPRY +gruffness/M +grumble/DRSMZGJ +grumbler/M +grump/SM +grumpily +grumpiness/M +grumpy/PRT +grunge/MS +grungy/RT +grunion/SM +grunt/SGMD +gt +guacamole/M +guanine/M +guano/M +guarani/MS +guaranies +guarantee/MDS +guaranteeing +guarantor/MS +guaranty/GDSM +guard/SZGMDR +guarded/Y +guarder/M +guardhouse/SM +guardian/SM +guardianship/M +guardrail/SM +guardroom/SM +guardsman/M +guardsmen +guava/SM +gubernatorial +guerilla/SM +guerrilla/SM +guess/ZGBMDRS +guesser/M +guesstimate/DSMG +guesswork/M +guest/SGMD +guestbook/SM +guesthouse/S +guestroom/S +guff/M +guffaw/MDGS +guidance/M +guide/DRSMZG +guidebook/SM +guided/U +guideline/SM +guidepost/SM +guider/M +guild/SZMR +guilder/M +guildhall/MS +guile/M +guileful +guileless/YP +guilelessness/M +guillemot/S +guillotine/DSMG +guilt/M +guiltily +guiltiness/M +guiltless +guilty/PRT +guinea/MS +guise/ESM +guitar/MS +guitarist/SM +gulag/SM +gulch/MS +gulden/MS +gulf/MS +gull/MDSG +gullet/MS +gullibility/M +gullible +gully/SM +gulp/MDRSZG +gulper/M +gum/SM +gumball/S +gumbo/SM +gumboil/SM +gumboot/S +gumdrop/SM +gummed +gumming +gummy/TR +gumption/M +gumshoe/MDS +gumshoeing +gun/SM +gunboat/SM +gunfight/MRZS +gunfighter/M +gunfire/M +gunge +gungy +gunk/M +gunky +gunman/M +gunmen +gunmetal/M +gunned +gunnel/MS +gunner/MS +gunnery/M +gunning +gunny/M +gunnysack/MS +gunpoint/M +gunpowder/M +gunrunner/MS +gunrunning/M +gunship/MS +gunshot/MS +gunslinger/SM +gunsmith/M +gunsmiths +gunwale/MS +guppy/SM +gurgle/MGDS +gurney/MS +guru/MS +gush/MDRSZG +gusher/M +gushing/Y +gushy/TR +gusset/MSDG +gussy/DSG +gust/EMDSG +gustatory +gustily +gusto/M +gusty/RT +gut/SM +gutless/P +gutlessness/M +gutsy/RT +gutted +gutter/SMDG +guttersnipe/MS +gutting +guttural/MS +gutty/RT +guv/S +guvnor/S +guy/SGMD +guzzle/DRSZG +guzzler/M +gym/SM +gymkhana/MS +gymnasium/MS +gymnast/MS +gymnastic/S +gymnastically +gymnastics/M +gymnosperm/SM +gymslip/S +gynecologic +gynecological +gynecologist/SM +gynecology/M +gyp/SM +gypped +gypper/SM +gypping +gypster/SM +gypsum/M +gypsy/SM +gyrate/DSGNX +gyration/M +gyrator/SM +gyrfalcon/MS +gyro/MS +gyroscope/MS +gyroscopic +gyve/MGDS +h'm +h/NRSXZGVJ +ha/SH +haberdasher/SM +haberdashery/SM +habiliment/SM +habit's +habit/ISB +habitability/M +habitat/SM +habitation/MS +habitual/YP +habitualness/M +habituate/GNDS +habituation/M +habitue/SM +habitu/SM +hacienda/SM +hack/MDRZGS +hacker/M +hacking/M +hackish +hackle/MS +hackney/SMDG +hacksaw/SM +hacktivist/MS +hackwork/M +had +haddock/SM +hadn't +hadst +hafnium/M +haft/MS +hag/SM +haggard/YP +haggardness/M +haggis/MS +haggish +haggle/MZGDRS +haggler/M +hagiographer/SM +hagiography/SM +hah +hahnium/M +haiku/M +hail/MDGS +hailstone/MS +hailstorm/MS +hair/MDS +hairball/MS +hairband/S +hairbreadth/M +hairbreadths +hairbrush/MS +haircloth/M +haircut/SM +hairdo/MS +hairdresser/SM +hairdressing/M +hairdrier/MS +hairdryer/MS +hairgrip/S +hairiness/M +hairless +hairlike +hairline/SM +hairnet/SM +hairpiece/MS +hairpin/SM +hairsbreadth/M +hairsbreadths +hairsplitter/SM +hairsplitting/M +hairspray/S +hairspring/MS +hairstyle/MS +hairstylist/SM +hairy/TRP +haj +hajj/M +hajjes +hajji/SM +hake/MS +halal/M +halberd/SM +halcyon +hale/ITGDRS +half/M +halfback/SM +halfhearted/PY +halfheartedness/M +halfpence +halfpenny/SM +halftime/MS +halftone/MS +halfway +halfwit/SM +halibut/SM +halite/M +halitosis/M +hall/MS +hallelujah/M +hallelujahs +hallmark/GMDS +halloo/MDSG +hallow/DSG +hallowed/U +hallucinate/GNXDS +hallucination/M +hallucinatory +hallucinogen/SM +hallucinogenic/SM +hallway/SM +halo/MDGS +halogen/SM +halon +halt/MDRZGS +halter/GMD +halterneck/S +halting/Y +halve/DSG +halyard/MS +ham/SM +hamburg/SZMR +hamburger/M +hamlet/MS +hammed +hammer/MDRSJZG +hammerer/M +hammerhead/SM +hammerlock/SM +hammertoe/MS +hamming +hammock/SM +hammy/TR +hamper/GMDS +hampered/U +hamster/MS +hamstring/GSM +hamstrung +hand's +hand/UDGS +handbag/SM +handball/MS +handbarrow/SM +handbill/MS +handbook/MS +handbrake/S +handcar/SM +handcart/MS +handclasp/MS +handcraft/SMDG +handcuff/MDGS +handed/P +handful/SM +handgun/SM +handheld/MS +handhold/MS +handicap/MS +handicapped +handicapper/MS +handicapping +handicraft/MS +handily +handiness/M +handiwork/M +handkerchief/MS +handle/MZGDRS +handlebar/MS +handler/M +handmade +handmaid/XMNS +handmaiden/M +handout/SM +handover/S +handpick/GDS +handrail/MS +handsaw/SM +handset/SM +handshake/JMGS +handsome/PYTR +handsomeness/M +handspring/MS +handstand/SM +handwork/M +handwoven +handwriting/M +handwritten +handy/UTR +handyman/M +handymen +hang/MDRJZGS +hangar/MS +hangdog +hanger/M +hanging/M +hangman/M +hangmen +hangnail/MS +hangout/SM +hangover/MS +hangup/MS +hank/MRZS +hanker/GJD +hankering/M +hankie/M +hanky/SM +hansom/MS +hap/MY +haphazard/YP +haphazardness/M +hapless/YP +haplessness/M +haploid/MS +happen/SDGJ +happening/M +happenstance/SM +happily/U +happiness/UM +happy/URTP +harangue/MGDS +harass/LZGDRS +harasser/M +harassment/M +harbinger/SM +harbor/GMDS +harbormaster/S +hard/NRYXTP +hardback/MS +hardball/M +hardboard/M +hardbound +hardcore +hardcover/SM +harden/ZGDR +hardened/U +hardener/M +hardhat/MS +hardheaded/PY +hardheadedness/M +hardhearted/PY +hardheartedness/M +hardihood/M +hardily +hardiness/M +hardliner/MS +hardness/M +hardscrabble +hardship/SM +hardstand/SM +hardtack/M +hardtop/SM +hardware/M +hardwired +hardwood/SM +hardworking +hardy/PTR +hare/MGDS +harebell/MS +harebrained +harelip/SM +harelipped +harem/SM +haricot/S +hark/DGS +harlequin/SM +harlot/SM +harlotry/M +harm/MDGS +harmed/U +harmful/YP +harmfulness/M +harmless/PY +harmlessness/M +harmonic/SM +harmonica/MS +harmonically +harmonies +harmonious/PY +harmoniousness/M +harmonium/MS +harmonization/M +harmonize/ZGDRS +harmonizer/M +harmony/EM +harness's +harness/UDSG +harp/MDGS +harpist/SM +harpoon/ZGSMDR +harpooner/M +harpsichord/MS +harpsichordist/SM +harpy/SM +harridan/MS +harrier/M +harrow/SMDG +harrumph/GD +harrumphs +harry/DRSZG +harsh/RYTP +harshness/M +hart/MS +harvest/SMDRZG +harvested/U +harvester/M +hash/AMDSG +hashish/M +hashtag/SM +hasn't +hasp/MS +hassle/DSMG +hassock/SM +hast/DNXG +haste/SM +hasten/DG +hastily +hastiness/M +hasty/RTP +hat/ZGSMDR +hatband/S +hatbox/MS +hatch/MDSG +hatchback/MS +hatcheck/SM +hatched/U +hatchery/SM +hatchet/SM +hatching/M +hatchway/SM +hate/MS +hateful/PY +hatefulness/M +hatemonger/MS +hater/M +hatpin/S +hatred/SM +hatstand/S +hatted +hatter/SM +hatting +hauberk/SM +haughtily +haughtiness/M +haughty/PRT +haul/MDRZGS +haulage/M +hauler/M +haulier/S +haunch/MS +haunt/SMDRZG +haunter/M +haunting/Y +hauteur/M +have/MGS +haven't +haven/SM +haversack/SM +havoc/M +haw/GSMD +hawk/MDRZGS +hawker/M +hawkish/P +hawkishness/M +hawser/SM +hawthorn/MS +hay/GSMD +haycock/SM +hayloft/SM +haymaking +haymow/SM +hayrick/MS +hayride/MS +hayseed/MS +haystack/SM +haywire +hazard/SMDG +hazardous/Y +haze/MZGJDRS +hazel/SM +hazelnut/MS +hazer/M +hazily +haziness/M +hazing/M +hazmat +hazy/RTP +hdqrs +he'd +he'll +he/M +head/MDRZGJS +headache/MS +headband/MS +headbanger/S +headbanging +headboard/SM +headbutt/DSG +headcase/S +headcheese +headcount/S +headdress/MS +header/M +headfirst +headgear/M +headhunt/DRSZG +headhunter/M +headhunting/M +headily +headiness/M +heading/M +headlamp/MS +headland/MS +headless +headlight/MS +headline/MZGDRS +headliner/M +headlock/MS +headlong +headman/M +headmaster/SM +headmen +headmistress/MS +headphone/MS +headpiece/MS +headpin/SM +headquarter/SDG +headquarters/M +headrest/MS +headroom/M +headscarf +headscarves +headset/SM +headship/SM +headshrinker/SM +headsman/M +headsmen +headstall/SM +headstand/SM +headstone/SM +headstrong +headteacher/S +headwaiter/SM +headwaters/M +headway/M +headwind/SM +headword/SM +heady/RTP +heal/DRHZGS +healed/U +healer/M +health/M +healthcare +healthful/PY +healthfulness/M +healthily/U +healthiness/UM +healthy/UTRP +heap/MDGS +hear/AHGJS +heard/AU +hearer/SM +hearing/AM +hearken/SGD +hearsay/M +hearse's +hearse/AS +heart/SM +heartache/MS +heartbeat/MS +heartbreak/SMG +heartbroken +heartburn/M +hearten/ESGD +heartfelt +hearth/M +hearthrug/S +hearths +hearthstone/SM +heartily +heartiness/M +heartland/MS +heartless/PY +heartlessness/M +heartrending/Y +heartsick/P +heartsickness/M +heartstrings/M +heartthrob/MS +heartwarming +heartwood/M +hearty/RSMPT +heat's +heat/ADGS +heated/U +heatedly +heater/SM +heath/MNRX +heathen/M +heathendom/M +heathenish +heathenism/M +heather/M +heaths +heating/M +heatproof +heatstroke/M +heatwave/S +heave/DRSMZG +heaven/SMY +heavenly/TR +heavens/M +heavenward/S +heaver/M +heavily +heaviness/M +heavy/RSMTP +heavyhearted +heavyset +heavyweight/MS +heck/M +heckle/DRSMZG +heckler/M +heckling/M +hectare/SM +hectic +hectically +hectogram/SM +hectometer/MS +hector/SMDG +hedge/DRSMZG +hedgehog/MS +hedgehop/S +hedgehopped +hedgehopping +hedger/M +hedgerow/SM +hedonism/M +hedonist/MS +hedonistic +heed/MDGS +heeded/U +heedful/Y +heedless/PY +heedlessness/M +heehaw/SMDG +heel/MDGS +heelless +heft/MDGS +heftily +heftiness/M +hefty/PRT +hegemonic +hegemony/M +hegira/SM +heifer/SM +height/XSMN +heighten/DG +heinous/YP +heinousness/M +heir/MS +heiress/MS +heirloom/SM +heist/SMDG +held +helical +helices +helicopter/SGMD +heliocentric +heliotrope/SM +helipad/S +heliport/MS +helium/M +helix/M +hell/M +hellbent +hellcat/MS +hellebore/M +hellfire +hellhole/MS +hellion/MS +hellish/YP +hellishness/M +hello/SM +helluva +helm/MS +helmet/SMD +helmsman/M +helmsmen +helot/SM +help/MDRZGSJ +helper/M +helpful/UY +helpfulness/M +helping/M +helpless/PY +helplessness/M +helpline/SM +helpmate/SM +helve/SM +hem/SM +hematite/M +hematologic +hematological +hematologist/MS +hematology/M +heme/M +hemisphere/SM +hemispheric +hemispherical +hemline/SM +hemlock/SM +hemmed +hemmer/SM +hemming +hemoglobin/M +hemophilia/M +hemophiliac/MS +hemorrhage/MGDS +hemorrhagic +hemorrhoid/MS +hemostat/MS +hemp/MN +hemstitch/MDSG +hen/M +hence +henceforth +henceforward +henchman/M +henchmen +henna/SMDG +henpeck/GSD +hentai +hep +heparin/M +hepatic +hepatitis/M +hepatocyte/S +hepper +heppest +heptagon/MS +heptagonal +heptathlon/SM +herald/SMDG +heralded/U +heraldic +heraldry/M +herb/MS +herbaceous +herbage/M +herbal/S +herbalist/MS +herbicidal +herbicide/MS +herbivore/SM +herbivorous +herculean +herd/MDRZGS +herder/M +herdsman/M +herdsmen +here/M +hereabout/S +hereafter/SM +hereby +hereditary +heredity/M +herein +hereinafter +hereof +hereon +heresy/SM +heretic/SM +heretical +hereto +heretofore +hereunto +hereupon +herewith +heritable/I +heritage/MS +hermaphrodite/SM +hermaphroditic +hermetic +hermetical/Y +hermit/SM +hermitage/MS +hernia/SM +hernial +herniate/GNDS +herniation/M +hero/M +heroes +heroic/S +heroically +heroics/M +heroin/SM +heroine/SM +heroism/M +heron/SM +herpes/M +herpetologist/SM +herpetology/M +herring/MS +herringbone/M +herself +hertz/M +hesitance/M +hesitancy/M +hesitant/Y +hesitate/DSGNX +hesitating/UY +hesitation/M +hessian +hetero/SM +heterodox +heterodoxy/M +heterogeneity/M +heterogeneous/Y +heterosexual/MYS +heterosexuality/M +heuristic/MS +heuristically +heuristics/M +hew/ZGSDR +hewer/M +hex/GMDS +hexadecimal/S +hexagon/MS +hexagonal +hexagram/SM +hexameter/SM +hexane's +hexanes +hey +heyday/SM +hf +hgt +hgwy +hi/SD +hiatus/MS +hibachi/MS +hibernate/GNDS +hibernation/M +hibernator/MS +hibiscus/MS +hiccough/DG +hiccoughs +hiccup/GSMD +hick/MS +hickey/SM +hickory/SM +hid +hidden +hide/MZGJDRS +hideaway/SM +hidebound +hideous/YP +hideousness/M +hideout/MS +hider/M +hiding/M +hie/S +hieing +hierarchic +hierarchical/Y +hierarchy/SM +hieroglyph/M +hieroglyphic/MS +hieroglyphs +high/MRYZTP +highball/SM +highborn +highboy/MS +highbrow/SM +highchair/MS +highfalutin +highhanded/PY +highhandedness/M +highland/MRZS +highlander/M +highlight/SMDRZG +highlighter/M +highness/M +highroad/MS +highs +hightail/DSG +highway/MS +highwayman/M +highwaymen +hijab/SM +hijack/SJZGMDR +hijacker/M +hijacking/M +hike/MZGDRS +hiker/M +hiking/M +hilarious/PY +hilariousness/M +hilarity/M +hill/MS +hillbilly/SM +hilliness/M +hillock/MS +hillside/SM +hilltop/MS +hilly/PRT +hilt/MS +him/S +himself +hind/MRZS +hinder/GD +hindered/U +hindmost +hindquarter/MS +hindrance/SM +hindsight/M +hinge's +hinge/UDSG +hint/MDRZGS +hinter/M +hinterland/SM +hip/SPM +hipbath +hipbaths +hipbone/MS +hiphuggers +hipness/M +hipped +hipper +hippest +hippie/M +hipping +hippo/SM +hippodrome/SM +hippopotami +hippopotamus/MS +hippy/SM +hipster/MS +hiragana +hire's +hire/AGDS +hireling/MS +hirsute/P +hirsuteness/M +hiss/MDSG +hist +histamine/MS +histogram/MS +histologist/SM +histology/M +historian/MS +historic +historical/Y +historicity/M +historiographer/MS +historiography/M +history/SM +histrionic/S +histrionically +histrionics/M +hit/SM +hitch's +hitch/UDSG +hitcher/MS +hitchhike/DRSMZG +hitchhiker/M +hither +hitherto +hitter/SM +hitting +hive/MGDS +hiya +hm +hmm +ho/SMDRYZ +hoagie/MS +hoard/SZGMDRJ +hoarder/M +hoarding/M +hoarfrost/M +hoariness/M +hoarse/YTRP +hoarseness/M +hoary/TRP +hoax/MDRSZG +hoaxer/M +hob/SM +hobbit/S +hobble/MZGDRS +hobbler/M +hobby/SM +hobbyhorse/MS +hobbyist/SM +hobgoblin/MS +hobnail/SGMD +hobnob/S +hobnobbed +hobnobbing +hobo/MS +hoboes +hock/MDSG +hockey/M +hockshop/MS +hod/SM +hodgepodge/SM +hoe/SM +hoecake/SM +hoedown/SM +hoeing +hoer/M +hog/SM +hogan/SM +hogback/SM +hogged +hogging +hoggish/Y +hogshead/SM +hogtie/DS +hogtying +hogwash/M +hoick/SGD +hoist/SGMD +hoke/GDS +hokey +hokier +hokiest +hokum/M +hold/MRJSZG +holdall/S +holdem +holder/M +holding/M +holdout/SM +holdover/SM +holdup/MS +hole/MGDS +holey +holiday/SMDG +holidaymaker/S +holiness/UM +holism +holistic +holistically +holler/MDGS +hollow/MDRYPSTG +hollowness/M +holly/SM +hollyhock/MS +holmium/M +holocaust/SM +hologram/MS +holograph/M +holographic +holographs +holography/M +hols +holster/SMDG +holy/URPT +homage/MS +hombre/MS +homburg/SM +home/MYZGDRS +homebody/SM +homeboy/SM +homecoming/SM +homegrown +homeland/MS +homeless/MP +homelessness/M +homelike +homeliness/M +homely/PRT +homemade +homemaker/SM +homemaking/M +homeopath/M +homeopathic +homeopaths +homeopathy/M +homeostasis/M +homeostatic +homeowner/MS +homepage/MS +homer/GMD +homeroom/MS +homeschooling/M +homesick/P +homesickness/M +homespun/M +homestead/SMDRZG +homesteader/M +homestretch/MS +hometown/MS +homeward/S +homework/MRZG +homewrecker/SM +homey/SMP +homeyness/M +homicidal +homicide/MS +homie/RSMT +homiletic +homily/SM +hominess/M +hominid/SM +hominoid/S +hominy/M +homo/MS +homoerotic +homogeneity/M +homogeneous/Y +homogenization/M +homogenize/DSG +homograph/M +homographs +homologous +homonym/SM +homophobia/M +homophobic +homophone/MS +homosexual/SM +homosexuality/M +hon/SZTGMDR +honcho/MS +hone/MS +honer/M +honest/EYT +honester +honesty/EM +honey/SGMD +honeybee/SM +honeycomb/MDSG +honeydew/SM +honeylocust/M +honeymoon/ZGMDRS +honeymooner/M +honeypot/S +honeysuckle/SM +honk/MDRSZG +honker/M +honkie/M +honky/SM +honor/ESGMDB +honorableness/M +honorably/E +honorarily +honorarium/MS +honorary +honoree/SM +honorer/SM +honorific/MS +hooch/M +hood/MDSG +hoodie/MS +hoodlum/SM +hoodoo/MDSG +hoodwink/DGS +hooey/M +hoof/MDRSZG +hook's +hook/UDSG +hookah/M +hookahs +hooker/MS +hookup/MS +hookworm/MS +hooky/M +hooligan/MS +hooliganism/M +hoop/MDSG +hoopla/M +hooray/MS +hoosegow/SM +hoot/MDRSZG +hootch/M +hootenanny/SM +hooter/M +hoover/DSG +hooves +hop/SGMD +hope/MS +hopeful/PSMY +hopefulness/M +hopeless/YP +hopelessness/M +hopped +hopper/MS +hopping +hopscotch/MDSG +hora/MS +horde/DSMG +horehound/SM +horizon/SM +horizontal/SMY +hormonal +hormone/SM +horn/MDS +hornblende/M +hornet/MS +hornless +hornlike +hornpipe/MS +horny/TR +horologic +horological +horologist/MS +horology/M +horoscope/SM +horrendous/Y +horrible/P +horribleness/M +horribly +horrid/Y +horrific +horrifically +horrify/DSG +horrifying/Y +horror/MS +horse's +horse/UDSG +horseback/M +horsebox/S +horseflesh/M +horsefly/SM +horsehair/M +horsehide/M +horselaugh/M +horselaughs +horseless +horseman/M +horsemanship/M +horsemen +horseplay/M +horsepower/M +horseradish/MS +horseshit/! +horseshoe/DSM +horseshoeing +horsetail/SM +horsetrading +horsewhip/SM +horsewhipped +horsewhipping +horsewoman/M +horsewomen +horsey +horsy/TR +hortatory +horticultural +horticulturalist/S +horticulture/M +horticulturist/MS +hosanna/SM +hose/MGDS +hosepipe/S +hosier/MS +hosiery/M +hosp +hospholipase +hospice/MS +hospitable/I +hospitably/I +hospital/SM +hospitality/M +hospitalization/SM +hospitalize/DSG +host/MDSG +hostage/MS +hostel/ZGMDRS +hosteler/M +hostelry/SM +hostess/MDSG +hostile/MYS +hostilities/M +hostility/SM +hostler/MS +hot/SYP +hotbed/MS +hotblooded +hotbox/MS +hotcake/SM +hotdog/MS +hotdogged +hotdogging +hotel/SM +hotelier/MS +hotfoot/MDGS +hothead/DSM +hotheaded/YP +hotheadedness/M +hothouse/SM +hotkey/S +hotline/MS +hotlink/S +hotness/M +hotplate/SM +hotpot/S +hots/M +hotshot/MS +hotted +hotter +hottest +hottie/S +hotting +hound/SGMD +hour/MYS +hourglass/MS +houri/SM +house's +house/ADSG +houseboat/SM +housebound +houseboy/SM +housebreak/RSZG +housebreaker/M +housebreaking/M +housebroke +housebroken +houseclean/DSG +housecleaning/M +housecoat/SM +housefly/SM +houseful/SM +household/SMRZ +householder/M +househusband/SM +housekeeper/MS +housekeeping/M +houselights/M +housemaid/SM +houseman/M +housemaster/S +housemate/S +housemen +housemistress/S +housemother/SM +houseparent/SM +houseplant/MS +houseproud +houseroom +housetop/SM +housewares/M +housewarming/SM +housewife/MY +housewives +housework/M +housing/MS +hove +hovel/SM +hover/SGD +hovercraft/MS +how'd +how're +how/SM +howbeit +howdah/M +howdahs +howdy +however +howitzer/SM +howl/MDRSZG +howler/M +howsoever +hoyden/MS +hoydenish +hp +hr/S +ht +huarache/SM +hub/SM +hubbub/SM +hubby/SM +hubcap/SM +hubris/M +huckleberry/SM +huckster/SGMD +hucksterism/M +huddle/DSMG +hue/DSM +huff/MDSG +huffily +huffiness/M +huffy/PRT +hug/STMR +huge/YP +hugeness/M +hugged +hugging +huh +hula/MS +hulk/MSG +hull/MDRSZG +hullabaloo/SM +huller/M +hum/SM +human/SMRYTP +humane/PY +humaneness/M +humanism/M +humanist/SM +humanistic +humanitarian/MS +humanitarianism/M +humanities/M +humanity/ISM +humanization/CM +humanize/CDSG +humanizer/SM +humankind/M +humanness/M +humanoid/SM +humble/DRSZTGJP +humbleness/M +humbler/M +humbly +humbug/SM +humbugged +humbugging +humdinger/MS +humdrum/M +humeral +humeri +humerus/M +humid/Y +humidification/M +humidifier/CM +humidify/CZGDRS +humidity/M +humidor/SM +humiliate/DSGNX +humiliating/Y +humiliation/M +humility/M +hummed +hummer/SM +humming +hummingbird/SM +hummock/SM +hummocky +hummus/M +humongous +humor/SMDG +humoresque +humorist/MS +humorless/YP +humorlessness/M +humorous/PY +humorousness/M +hump/MDSG +humpback/MDS +humph/DG +humphs +humus/M +hunch/MDSG +hunchback/SMD +hundred/SMH +hundredfold +hundredth/M +hundredths +hundredweight/SM +hung +hunger/SMDG +hungover +hungrily +hungriness/M +hungry/PRT +hunk/MRSZ +hunker/DG +hunky/RT +hunt/MDRSZG +hunter/M +hunting/M +huntress/MS +huntsman/M +huntsmen +hurdle/DRSMZG +hurdler/M +hurdling/M +hurl/MDRSZG +hurler/M +hurling/M +hurrah/GMD +hurrahs +hurray +hurricane/MS +hurried/UY +hurry/DSMG +hurt/MSG +hurtful/YP +hurtfulness/M +hurtle/DSG +husband/GMDS +husbandman/M +husbandmen +husbandry/M +hush/MDSG +husk/MDRSZG +husker/M +huskily +huskiness/M +husky/PRSMT +hussar/SM +hussy/SM +hustings/M +hustle/DRSMZG +hustler/M +hut/SM +hutch/MS +huzza/GSMD +huzzah/MDG +huzzahs +hwy +hyacinth/M +hyacinths +hybrid/SM +hybridism/M +hybridization/M +hybridize/DSG +hydra/SM +hydrangea/SM +hydrant/MS +hydrate's +hydrate/CGNDS +hydration/CM +hydraulic/S +hydraulically +hydraulics/M +hydro/M +hydrocarbon/MS +hydrocephalus/M +hydrodynamic/S +hydrodynamics/M +hydroelectric +hydroelectrically +hydroelectricity/M +hydrofoil/MS +hydrogen/M +hydrogenate/CGDS +hydrogenation/M +hydrogenous +hydrologist/MS +hydrology/M +hydrolyses +hydrolysis/M +hydrolyze/DSG +hydrometer/SM +hydrometry/M +hydrophobia/M +hydrophobic +hydrophone/SM +hydroplane/GDSM +hydroponic/S +hydroponically +hydroponics/M +hydrosphere/M +hydrotherapy/M +hydrous +hydroxide/SM +hyena/SM +hygiene/M +hygienic/U +hygienically +hygienist/MS +hygrometer/SM +hying +hymen/SM +hymeneal +hymn/MDSG +hymnal/MS +hymnbook/SM +hype/MGDRS +hyperactive +hyperactivity/M +hyperbola/SM +hyperbole/M +hyperbolic +hypercritical/Y +hyperglycemia/M +hyperinflation +hyperlink/GSMD +hypermarket/S +hypermedia/M +hyperparathyroidism +hypersensitive/P +hypersensitiveness/M +hypersensitivity/SM +hyperspace/S +hypertension/M +hypertensive/SM +hypertext/M +hyperthyroid/M +hyperthyroidism/M +hypertrophy/DSMG +hyperventilate/GNDS +hyperventilation/M +hyphen/MDSG +hyphenate/XDSMGN +hyphenation/M +hypnoses +hypnosis/M +hypnotherapist/S +hypnotherapy/M +hypnotic/SM +hypnotically +hypnotism/M +hypnotist/MS +hypnotize/GDS +hypo/MS +hypoallergenic +hypochondria/M +hypochondriac/SM +hypocrisy/SM +hypocrite/MS +hypocritical/Y +hypodermic/MS +hypoglycemia/M +hypoglycemic/SM +hypotenuse/MS +hypothalami +hypothalamus/M +hypothermia/M +hypotheses +hypothesis/M +hypothesize/DSG +hypothetical/Y +hypothyroid/M +hypothyroidism/M +hyssop/M +hysterectomy/SM +hysteresis +hysteria/M +hysteric/SM +hysterical/Y +hysterics/M +i/US +iPad/M +iPhone/M +iPod/MS +iTunes/M +iamb/MS +iambi +iambic/SM +iambus/MS +ibex/MS +ibid +ibidem +ibis/MS +ibuprofen/M +ice's +ice/CDSG +iceberg/SM +iceboat/SM +icebound +icebox/MS +icebreaker/SM +icecap/SM +iceman/M +icemen +ichthyologist/MS +ichthyology/M +icicle/SM +icily +iciness/M +icing/SM +icky/RT +icon/MS +iconic +iconoclasm/M +iconoclast/SM +iconoclastic +iconography/M +ictus/M +icy/TPR +id/SMY +idea/MS +ideal/SMY +idealism/M +idealist/SM +idealistic +idealistically +idealization/MS +idealize/DSG +idem +idempotent +identical/Y +identifiable/U +identification/M +identified/U +identify/ZGNDRSX +identikit/S +identity/SM +ideogram/SM +ideograph/M +ideographs +ideological/Y +ideologist/SM +ideologue/MS +ideology/SM +ides/M +idiocy/SM +idiom/SM +idiomatic/U +idiomatically +idiopathic +idiosyncrasy/SM +idiosyncratic +idiosyncratically +idiot/SM +idiotic +idiotically +idle/MZTGDRSP +idleness/M +idler/M +idol/MS +idolater/SM +idolator/SM +idolatress/MS +idolatrous +idolatry/M +idolization/M +idolize/GDS +idyll/SM +idyllic +idyllically +if/SM +iffiness/M +iffy/RTP +igloo/SM +igneous +ignitable +ignite/AGDS +ignition/MS +ignoble +ignobly +ignominious/Y +ignominy/SM +ignoramus/MS +ignorance/M +ignorant/Y +ignore/GDS +iguana/MS +ii +iii +ilea +ileitis/M +ileum/M +ilia +ilium/M +ilk/SM +ill/SMP +illegal/MYS +illegality/SM +illegibility/M +illegible +illegibly +illegitimacy/M +illegitimate/Y +illiberal/Y +illiberality/M +illicit/YP +illicitness/M +illimitable +illiteracy/M +illiterate/MYS +illness/MS +illogical/Y +illogicality/M +illuminate/GNXDS +illuminating/Y +illumination/M +illumine/DSBG +illus/V +illusion/EMS +illusionist/SM +illusory +illustrate/GNVXDS +illustration/M +illustrative/Y +illustrator/SM +illustrious/PY +illustriousness/M +image/DSMG +imagery/M +imaginable/U +imaginably/U +imaginal +imaginary +imagination/MS +imaginative/UY +imagine/DSBJG +imago/M +imagoes +imam/MS +imbalance/DSM +imbecile/MS +imbecilic +imbecility/SM +imbibe/ZGDRS +imbiber/M +imbrication/M +imbroglio/SM +imbue/DSG +imitable/I +imitate/DSGNVX +imitation/M +imitative/PY +imitativeness/M +imitator/SM +immaculate/PY +immaculateness/M +immanence/M +immanency/M +immanent/Y +immaterial/YP +immateriality/M +immaterialness/M +immature/Y +immaturity/M +immeasurable +immeasurably +immediacies/M +immediacy/SM +immediate/PY +immediateness/M +immemorial/Y +immense/Y +immensity/SM +immerse/XDSGNV +immersible +immersion/M +immigrant/SM +immigrate/DSGN +immigration/M +imminence/M +imminent/Y +immobile +immobility/M +immobilization/M +immobilize/ZGDRS +immoderate/Y +immodest/Y +immodesty/M +immolate/DSGN +immolation/M +immoral/Y +immorality/SM +immortal/MYS +immortality/M +immortalize/DSG +immovability/M +immovable +immovably +immune +immunity/M +immunization/SM +immunize/GDS +immunodeficiency/M +immunodeficient +immunoglobulin/S +immunologic +immunological +immunologist/MS +immunology/M +immure/DSG +immutability/M +immutable +immutably +imp/SMR +impact/SMDG +impair/SDGL +impaired/U +impairment/MS +impala/SM +impale/DSGL +impalement/M +impalpable +impalpably +impanel/SDG +impart/SDG +impartial/Y +impartiality/M +impassably +impasse/BSMV +impassibility/M +impassible +impassibly +impassioned +impassive/YP +impassiveness/M +impassivity/M +impasto/M +impatience/MS +impatiens/M +impatient/Y +impeach/ZGBLDRS +impeachable/U +impeacher/M +impeachment/SM +impeccability/M +impeccable +impeccably +impecunious/PY +impecuniousness/M +impedance/M +impede/DSG +impeded/U +impediment/SM +impedimenta/M +impel/S +impelled +impeller/MS +impelling +impend/SDG +impenetrability/M +impenetrable +impenetrably +impenitence/M +impenitent/Y +imperative/SMY +imperceptibility/M +imperceptible +imperceptibly +imperceptive +imperf +imperfect/SMYP +imperfection/MS +imperfectness/M +imperial/MYS +imperialism/M +imperialist/SM +imperialistic +imperialistically +imperil/GSLD +imperilment/M +imperious/PY +imperiousness/M +imperishable +imperishably +impermanence/M +impermanent/Y +impermeability/M +impermeable +impermeably +impermissible +impersonal/Y +impersonate/GNXDS +impersonation/M +impersonator/SM +impertinence/MS +impertinent/Y +imperturbability/M +imperturbable +imperturbably +impervious/Y +impetigo/M +impetuosity/M +impetuous/YP +impetuousness/M +impetus/MS +impiety/SM +impinge/LDSG +impingement/M +impious/PY +impiousness/M +impish/YP +impishness/M +implacability/M +implacable +implacably +implant/BSGMD +implantation/M +implausibility/SM +implausible +implausibly +implement/GBMDRS +implementable/U +implementation/SM +implemented/U +implicate/DSG +implication/M +implicit/PY +implicitness/M +implode/DSG +implore/DSG +imploring/Y +implosion/MS +implosive +imply/XDSGN +impolite/YP +impoliteness/MS +impolitic +imponderable/MS +import/ZGBSMDR +importance/M +important/Y +importation/MS +importer/M +importunate/Y +importune/GDS +importunity/M +impose/ADSG +imposer/MS +imposing/U +imposingly +imposition/MS +impossibility/SM +impossible/S +impossibly +impost/ZSMR +imposter/M +impostor/SM +imposture/MS +impotence/M +impotency/M +impotent/Y +impound/DGS +impoverish/DSLG +impoverishment/M +impracticability +impracticable +impracticably +impractical/Y +impracticality/M +imprecate/DSXGN +imprecation/M +imprecise/PYN +impreciseness/M +imprecision/M +impregnability/M +impregnable +impregnably +impregnate/GNDS +impregnation/M +impresario/SM +impress/MDSGV +impressed/U +impressibility/M +impressible +impression/BSM +impressionability/M +impressionism/M +impressionist/SM +impressionistic +impressive/PY +impressiveness/M +imprimatur/SM +imprint/MDRZGS +imprinter/M +imprison/SDLG +imprisonment/SM +improbability/SM +improbable +improbably +impromptu/SM +improper/Y +impropriety/SM +improve/GBDSL +improved/U +improvement/MS +improvidence/M +improvident/Y +improvisation/SM +improvisational +improvise/ZGDRS +improviser/M +improvisor/SM +imprudence/M +imprudent/Y +impudence/M +impudent/Y +impugn/ZGSDR +impugner/M +impulse/MGNVDS +impulsion/M +impulsive/PY +impulsiveness/M +impunity/M +impure/RYT +impurity/SM +imputation/SM +impute/BDSG +in/ASM +inaccuracy/S +inaction/M +inadequacy/S +inadvertence/M +inadvertent/Y +inalienability/M +inalienably +inamorata/SM +inane/RYT +inanimate/PY +inanimateness/M +inanity/SM +inappropriate/Y +inarticulate/Y +inasmuch +inaudible +inaugural/SM +inaugurate/XGNDS +inauguration/M +inboard/MS +inbound +inbox/MS +inbreed/S +inc/TGD +incalculably +incandescence/M +incandescent/Y +incantation/SM +incapacitate/GDS +incarcerate/XDSGN +incarceration/M +incarnadine/DSG +incarnate/AXGNDS +incarnation/AM +incendiary/SM +incense/MGDS +incentive's +incentive/ES +incentivize/DSG +inception/SM +incessant/Y +incest/M +incestuous/PY +incestuousness/M +inch/MDSG +inchoate +inchworm/SM +incidence/SM +incident/SM +incidental/MYS +incinerate/DSGN +incineration/M +incinerator/MS +incipience/M +incipient/Y +incise/XGNVDS +incision/M +incisive/PY +incisiveness/M +incisor/MS +incitement/MS +inciter/MS +incl +inclement +inclination/EM +inclinations +incline's +incline/EGDS +include/GDS +inclusion/MS +inclusive/YP +inclusiveness/M +incognito/MS +incombustible +incommode/GD +incommodious +incommunicado +incompatibility/S +incompetent/MS +incomplete/Y +inconceivability/M +incongruous/PY +incongruousness/M +inconsolably +inconstant/Y +incontestability/M +incontestably +incontinent +incontrovertibly +inconvenience/GD +incorporate/ADSGN +incorporated/U +incorporation/AM +incorporeal +incorrect/Y +incorrigible/P +incorrigibly +increasing/Y +increment/SMD +incremental/Y +incrementalism +incrementalist/SM +incriminate/GNDS +incrimination/M +incriminatory +incrustation/SM +incubate/GNDS +incubation/M +incubator/SM +incubus/MS +inculcate/DSGN +inculcation/M +inculpate/DSG +incumbency/SM +incumbent/SM +incunabula +incunabulum/M +incur/SB +incurable/MS +incurably +incurious +incurred +incurring +incursion/MS +ind +indebted/P +indebtedness/M +indeed +indefatigable +indefatigably +indefeasible +indefeasibly +indefinably +indelible +indelibly +indemnification/M +indemnify/GDSXN +indemnity/SM +indentation/MS +indention/M +indenture/DG +indescribably +indestructibly +indeterminably +indeterminacy/M +indeterminate/Y +index/ZGMDRS +indexation/SM +indexer/M +indicate/XDSGNV +indication/M +indicative/SMY +indicator/MS +indict/GDSBL +indictment/SM +indie/S +indigence/M +indigenous +indigent/SMY +indignant/Y +indignation/M +indigo/M +indirect/Y +indiscipline +indiscreet/Y +indiscretion/S +indiscriminate/Y +indispensability/M +indispensable/MS +indispensably +indissolubility +indissolubly +indistinguishably +indite/GDS +indium/M +individual/MYS +individualism/M +individualist/MS +individualistic +individualistically +individuality/M +individualization/M +individualize/GDS +individuate/DSGN +individuation/M +indivisibly +indoctrinate/GNDS +indoctrination/M +indolence/M +indolent/Y +indomitable +indomitably +indubitable +indubitably +induce/DRSZGL +inducement/SM +inducer/M +induct/DGV +inductance/M +inductee/SM +induction/MS +inductive/Y +indue/DG +indulge/DSG +indulgence/SM +indulgent/Y +industrial/Y +industrialism/M +industrialist/SM +industrialization/M +industrialize/DSG +industrious/YP +industriousness/M +industry/SM +indwell/SG +inebriate/MGNDS +inebriation/M +inedible +ineffability/M +ineffable +ineffably +inelastic +ineligible/MS +ineligibly +ineluctable +ineluctably +inept/YP +ineptitude/M +ineptness/M +inequality/S +inert/YP +inertia/M +inertial +inertness/M +inescapable +inescapably +inestimably +inevitability/M +inevitable/M +inevitably +inexact/Y +inexhaustibly +inexorability +inexorable +inexorably +inexpedient +inexpert/Y +inexpiable +inexplicably +inexpressibly +inexpressive +inextricably +inf/ZT +infallible +infamy/SM +infancy/M +infant/MS +infanticide/MS +infantile +infantry/SM +infantryman/M +infantrymen +infarct/MS +infarction/M +infatuate/DSXGN +infatuation/M +infect/AESDG +infected/U +infection/ASM +infectious/PY +infectiousness/M +infelicitous +inference/SM +inferential +inferior/MS +inferiority/M +infernal/Y +inferno/MS +inferred +inferring +infest/GDS +infestation/MS +infidel/MS +infidelity/S +infiltrator/SM +infinite/MV +infinitesimal/SMY +infinitival +infinitive/MS +infinitude/M +infinity/SM +infirm +infirmary/SM +infirmity/SM +infix +inflame/DSG +inflammable +inflammation/SM +inflammatory +inflatable/SM +inflate/DSGNB +inflation/EM +inflationary +inflect/SDG +inflection/MS +inflectional +inflict/SDGV +infliction/M +inflight +inflow/SM +influence/MGDS +influenced/U +influential/Y +influenza/M +info/M +infomercial/SM +inform/Z +informal/Y +informant/SM +information/EM +informational +informative/PY +informativeness/M +informed/U +infotainment/M +infra +infrared/M +infrasonic +infrastructural +infrastructure/SM +infrequence/M +infrequent/Y +infringement/MS +infuriate/GDS +infuriating/Y +infuser/SM +ingenious/PY +ingeniousness/M +ingenue/SM +ingenuity/M +ingenuous/EY +ingenuousness/M +ingest/SDG +ingestion/M +inglenook/SM +ingot/SM +ingrain/G +ingrate/SM +ingratiate/GNDS +ingratiating/Y +ingratiation/M +ingredient/MS +ingress/MS +inguinal +ingnue/SM +inhabit/DG +inhabitable/U +inhabitant/SM +inhabited/U +inhalant/SM +inhalation/MS +inhalator/MS +inhaler/SM +inharmonious +inhere/DSG +inherent/Y +inherit/EGSD +inheritance/EM +inheritances +inheritor/SM +inhibit/GSD +inhibition/SM +inhibitor/SM +inhibitory +inhuman/Y +inhumane/Y +inimical/Y +inimitably +iniquitous/Y +iniquity/SM +initial/SGMDY +initialism +initialization +initialize/DSG +initialized/AU +initiate/XMGNVDS +initiated/U +initiation/M +initiative/SM +initiator/MS +initiatory +inject/SDG +injection/SM +injector/SM +injure/DRSZG +injured/U +injurer/M +injurious +ink/MD +inkblot/SM +inkiness/M +inkjet/SM +inkling/SM +inkstand/SM +inkwell/MS +inky/RTP +inland/M +inline +inmate/SM +inmost +inn/SGMRJ +innards/M +innate/PY +innateness/M +innermost +innersole/SM +innerspring +innervate/GNDS +innervation/M +inning/M +innit +innkeeper/MS +innocence/M +innocent/MYS +innocuous/PY +innocuousness/M +innovate/XDSGNV +innovation/M +innovator/MS +innovatory +innuendo/SM +innuendoes +innumerably +innumerate +inoculate/AGDS +inoculation/MS +inoperative +inordinate/Y +inorganic +inquire/ZGDR +inquirer/M +inquiring/Y +inquiry/SM +inquisition/MS +inquisitional +inquisitive/YP +inquisitiveness/M +inquisitor/SM +inquisitorial +inrush/MS +insane/T +insatiability/M +insatiably +inscribe/ZGDR +inscriber/M +inscription/MS +inscrutability/M +inscrutable/P +inscrutableness/M +inscrutably +inseam/SM +insecticidal +insecticide/MS +insectivore/MS +insectivorous +insecure/Y +inseminate/DSGN +insemination/M +insensate +insensible +insensitive/Y +inseparable/MS +insert's +insert/AGSD +insertion/AM +insertions +insetting +inshore +inside/RSMZ +insider/M +insidious/YP +insidiousness/M +insight/MS +insightful +insignia/SM +insinuate/GNVDSX +insinuation/M +insinuator/SM +insipid/PY +insipidity/M +insist/SGD +insistence/M +insistent/Y +insisting/Y +insofar +insole/SM +insolence/M +insolent/Y +insoluble +insolubly +insolvency/S +insomnia/M +insomniac/SM +insomuch +insouciance/M +insouciant +inspect/AGDS +inspection/SM +inspector/MS +inspectorate/MS +inspiration/MS +inspirational +inspired/U +inspiring/U +inst +instability/S +installation/MS +installer/UMS +installment/SM +instance/GD +instant/MRYS +instantaneous/Y +instantiate/DSG +instar +instate/AGDS +instead +instigate/DSGN +instigation/M +instigator/MS +instillation/M +instinct/VMS +instinctive/Y +instinctual +institute/XMZGNDRS +instituter/M +institution/M +institutional/Y +institutionalization/M +institutionalize/DSG +institutor/MS +instr +instruct/SDGV +instructed/U +instruction/MS +instructional +instructive/Y +instructor/MS +instrument/MDSG +instrumental/MYS +instrumentalist/SM +instrumentality/M +instrumentation/M +insubordinate +insufferable +insufferably +insular +insularity/M +insulate/GNDS +insulation/M +insulator/MS +insulin/M +insult/SMDG +insulting/Y +insuperable +insuperably +insurance/SM +insure/DRSZGB +insured/SM +insurer/M +insurgence/SM +insurgency/SM +insurgent/MS +insurmountably +insurrection/SM +insurrectionist/SM +int +intact +intaglio/MS +integer/MS +integral/SMY +integrate/AEVNGSD +integration/EAM +integrator +integrity/M +integument/SM +intellect/MS +intellectual/MYS +intellectualism/M +intellectualize/GDS +intelligence/M +intelligent/Y +intelligentsia/M +intelligibility/M +intelligible/U +intelligibly/U +intended/SM +intense/YTVR +intensification/M +intensifier/M +intensify/DRSZGN +intensity/S +intensive/MYPS +intensiveness/M +intent/SMYP +intention/MS +intentional/UY +intentness/M +inter/ESL +interact/SGVD +interaction/SM +interactive/Y +interactivity +interbred +interbreed/GS +intercede/GDS +intercept/GMDS +interception/MS +interceptor/SM +intercession/SM +intercessor/MS +intercessory +interchange/DSMG +interchangeability +interchangeable +interchangeably +intercity +intercollegiate +intercom/SM +intercommunicate/DSGN +intercommunication/M +interconnect/GDS +interconnection/SM +intercontinental +intercourse/M +intercultural +interdenominational +interdepartmental +interdependence/M +interdependent/Y +interdict/GMDS +interdiction/M +interdisciplinary +interest/ESMD +interested/U +interesting/Y +interface/MGDS +interfaith +interfere/GDS +interference/M +interferon/M +interfile/GDS +intergalactic +intergovernmental +interim/M +interior/SM +interj +interject/GDS +interjection/SM +interlace/GDS +interlard/DGS +interleave/DSG +interleukin/M +interline/GDSJ +interlinear +interlining/M +interlink/DSG +interlock/GMDS +interlocutor/SM +interlocutory +interlope/ZGDRS +interloper/M +interlude/MGDS +intermarriage/SM +intermarry/GDS +intermediacy/S +intermediary/SM +intermediate/XMYGNPDS +intermediation/ES +intermediator/MS +interment/EM +interments +intermezzi +intermezzo/MS +interminably +intermingle/DSG +intermission/SM +intermittent/Y +intermix/GDS +internal/SY +internalization/M +internalize/GDS +international/SMY +internationalism/M +internationalist/SM +internationalization +internationalize/DSG +interne/GDL +internecine +internee/SM +interneship/S +internet +internist/MS +internment/M +internship/MS +interoffice +interpenetrate/DSGN +interpersonal +interplanetary +interplay/M +interpolate/XDSGN +interpolation/M +interpose/GDS +interposition/M +interpret/AGVDS +interpretation/AMS +interpretative +interpreted/U +interpreter/MS +interracial +interred/E +interregnum/SM +interrelate/XDSGN +interrelation/M +interrelationship/MS +interring/E +interrogate/DSGNVX +interrogation/M +interrogative/MYS +interrogator/SM +interrogatory/SM +interrupt/ZGMDRS +interrupter/M +interruptible/U +interruption/MS +interscholastic +intersect/GDS +intersection/SM +intersession/SM +intersex +intersexual/MS +intersexualism +intersexuality +intersperse/GNDS +interspersion/M +interstate/MS +interstellar +interstice/MS +interstitial +intertwine/GDS +interurban +interval/SM +intervene/GDS +intervention/SM +interventionism/M +interventionist/SM +interview/ZGMDRS +interviewee/MS +interviewer/M +intervocalic +interwar +interweave/GS +interwove +interwoven +intestacy/M +intestate +intestinal +intestine/MS +intimacy/SM +intimate/MYGNDSX +intimation/M +intimidate/GNDS +intimidating/Y +intimidation/M +intonation/SM +intoxicant/SM +intoxicate/DSGN +intoxication/M +intracranial +intramural +intramuscular +intranet/MS +intransigence/M +intransigent/MYS +intrastate +intrauterine +intravenous/MSY +intrepid/Y +intrepidity/M +intricacy/SM +intricate/Y +intrigue/DRSMZG +intriguer/M +intriguing/Y +intrinsic +intrinsically +intro/SM +introduce/AGDS +introduction/AM +introductions +introductory +introit/SM +introspect/GVDS +introspection/M +introspective/Y +introversion/M +introvert/MDS +intrude/DRSZG +intruder/M +intrusion/SM +intrusive/YP +intrusiveness/M +intuit/SDGV +intuition/S +intuitive/PY +intuitiveness/M +inundate/XDSGN +inundation/M +inure/DSG +invade/DRSZG +invader/M +invalid/GMDYS +invalidism/M +invaluable +invaluably +invariant +invasion/MS +invasive +invective/M +inveigh/GD +inveighs +inveigle/ZGDRS +inveigler/M +invent/ASGVD +invention/AMS +inventive/PY +inventiveness/M +inventor/MS +inventory/DSMG +inverse/SMY +invert/SMDG +invest/ASDGL +investigate/GNVDSX +investigation/M +investigator/SM +investigatory +investiture/MS +investment/AEM +investor/SM +inveteracy/M +inveterate +invidious/YP +invidiousness/M +invigilate/GNDS +invigilator/S +invigorate/ADSG +invigorating/Y +invigoration/M +invincibility/M +invincibly +inviolability/M +inviolably +inviolate +invitation/SM +invitational/SM +invite/DSMG +invited/U +invitee/SM +inviting/Y +invoke/DSG +involuntariness/M +involuntary/P +involution/M +involve/LDSG +involvement/SM +inward/SY +ioctl +iodide/SM +iodine/M +iodize/DSG +ion/USM +ionic +ionization/UM +ionize/UDSG +ionizer/MS +ionosphere/MS +ionospheric +iota/MS +ipecac/SM +irascibility/M +irascible +irascibly +irate/YP +irateness/M +ire/M +ireful +irenic +irides +iridescence/M +iridescent/Y +iridium/M +iris/MS +irk/SGD +irksome/YP +irksomeness/M +iron/MDSG +ironclad/MS +ironic/U +ironical/Y +ironically/U +ironing/M +ironmonger/S +ironmongery +ironstone/M +ironware/M +ironwood/MS +ironwork/M +irony/SM +irradiate/DSGN +irradiation/M +irrational/SMY +irrationality/M +irreclaimable +irreconcilability/M +irreconcilable +irreconcilably +irrecoverable +irrecoverably +irredeemable +irredeemably +irreducible +irreducibly +irrefutable +irrefutably +irregardless +irregular/MYS +irregularity/SM +irrelevance/MS +irrelevancy/MS +irrelevant/Y +irreligion +irreligious +irremediable +irremediably +irremovable +irreparable +irreparably +irreplaceable +irrepressible +irrepressibly +irreproachable +irreproachably +irresistible +irresistibly +irresolute/PYN +irresoluteness/M +irresolution/M +irrespective +irresponsibility/M +irresponsible +irresponsibly +irretrievable +irretrievably +irreverence/M +irreverent/Y +irreversible +irreversibly +irrevocable +irrevocably +irrigable +irrigate/DSGN +irrigation/M +irritability/M +irritable +irritably +irritant/SM +irritate/DSXGN +irritating/Y +irritation/M +irrupt/DGVS +irruption/SM +ischemia +ischemic +isinglass/M +isl +island/SZMR +islander/M +isle/MS +islet/SM +ism/CM +isms +isn't +isobar/MS +isobaric +isolate/DSMGN +isolation/M +isolationism/M +isolationist/SM +isomer/MS +isomeric +isomerism/M +isometric/S +isometrically +isometrics/M +isomorphic +isosceles +isotherm/SM +isotope/SM +isotopic +isotropic +issuance/M +issue/ADSMG +issuer/MS +isthmian +isthmus/MS +it'd +it'll +it/USM +ital +italic/SM +italicization/M +italicize/GDS +italics/M +itch/MDSG +itchiness/M +itchy/RPT +item/MS +itemization/M +itemize/GDS +iterate/AXGNVDS +iteration/AM +iterator/S +itinerant/SM +itinerary/SM +itself +iv/U +ivory/SM +ivy/DSM +ix +j/F +jab/SM +jabbed +jabber/SMDRZG +jabberer/M +jabbing +jabot/SM +jacaranda/MS +jack/MDGS +jackal/SM +jackass/MS +jackboot/SMD +jackdaw/MS +jacket/SMD +jackhammer/MS +jackknife/MGDS +jackknives +jackpot/MS +jackrabbit/MS +jackstraw/MS +jacquard/M +jade/MGDS +jaded/PY +jadedness/M +jadeite/M +jag/SM +jagged/TPRY +jaggedness/M +jaggies +jaguar/SM +jail/MDRZGS +jailbird/SM +jailbreak/SM +jailer/M +jailhouse/S +jalapeno/MS +jalapeo/MS +jalopy/SM +jalousie/MS +jam/SM +jamb/MS +jambalaya/M +jamboree/MS +jammed +jamming +jammy/RT +jangle/DRSMZG +jangler/M +janitor/SM +janitorial +japan/SM +japanned +japanning +jape/MGDS +jar/SM +jardiniere/SM +jardinire/SM +jarful/MS +jargon/M +jarred +jarring/Y +jasmine/SM +jasper/M +jato/MS +jaundice/DSMG +jaunt/SGMD +jauntily +jauntiness/M +jaunty/RPT +java/M +javelin/SM +jaw/SGMD +jawbone/DSMG +jawbreaker/MS +jawline/S +jay/SM +jaybird/SM +jaywalk/DRSZG +jaywalker/M +jaywalking/M +jazz/MDSG +jazzy/TR +jct +jealous/Y +jealousy/SM +jean/MS +jeans/M +jeep/MS +jeer/MDSG +jeering/MY +jeez +jejuna +jejune +jejunum/M +jell/DSG +jello/SM +jelly/GDSM +jellybean/MS +jellyfish/MS +jellylike +jellyroll/SM +jemmy/GDS +jennet/MS +jenny/SM +jeopardize/GDS +jeopardy/M +jeremiad/MS +jerk/MDSG +jerkily +jerkin/MS +jerkiness/M +jerkwater +jerky/TRMP +jeroboam/S +jerrican/S +jerrybuilt +jerrycan/S +jersey/MS +jest/MDRSZG +jester/M +jesting/Y +jet/SM +jetliner/SM +jetport/MS +jetsam/M +jetted +jetting +jettison/MDSG +jetty/SM +jew +jewel/SZGMDR +jeweler/M +jewellery +jewelry/SM +jg +jib/SGMD +jibbed +jibbing +jibe/MS +jiff/MS +jiffy/SM +jig's +jig/AS +jigged/A +jigger's +jigger/ASDG +jigging/A +jiggle/DSMG +jiggly +jigsaw/SMDG +jihad/SM +jihadist/SM +jilt/MDSG +jimmy/DSMG +jimsonweed/M +jingle/DSMG +jingly +jingoism/M +jingoist/SM +jingoistic +jink/DSG +jinn/MS +jinni/M +jinricksha/SM +jinrikisha/SM +jinx/MDSG +jitney/SM +jitterbug/MS +jitterbugged +jitterbugger/M +jitterbugging +jitters/M +jittery/RT +jive/MGDS +job/SM +jobbed +jobber/SM +jobbing +jobholder/MS +jobless/P +joblessness/M +jobshare/S +jobsworth +jobsworths +jock/MS +jockey/SGMD +jockstrap/MS +jocose/PY +jocoseness/M +jocosity/M +jocular/Y +jocularity/M +jocund/Y +jocundity/M +jodhpurs/M +joey/S +jog/SM +jogged +jogger/SM +jogging/M +joggle/DSMG +john/MS +johnny/SM +johnnycake/MS +join's +join/AFDSG +joiner/FMS +joinery/M +joint's +joint/EGSD +jointly/F +joist/SM +jojoba +joke/MZGDRS +joker/M +jokey +jokier +jokiest +joking/Y +jollification/SM +jollily +jolliness/M +jollity/M +jolly/TGPDRSM +jolt/MDRSZG +jolter/M +jonquil/SM +josh/MDRSZG +josher/M +jostle/MGDS +jot/SM +jotted +jotter/MS +jotting/MS +joule/SM +jounce/MGDS +jouncy +journal/MS +journalese/M +journalism/M +journalist/SM +journalistic +journey/ZGMDRS +journeyer/M +journeyman/M +journeymen +journo/S +joust/SZGMDR +jouster/M +jousting/M +jovial/Y +joviality/M +jowl/MS +jowly/TR +joy/SGMD +joyful/YP +joyfuller +joyfullest +joyfulness/M +joyless/PY +joylessness/M +joyous/YP +joyousness/M +joyridden +joyride/RSMZG +joyrider/M +joyriding/M +joyrode +joystick/SM +jr +jubilant/Y +jubilation/M +jubilee/SM +judder/GDS +judge's +judge/ADSG +judgement/SM +judgemental +judgeship/M +judgment/SM +judgmental/Y +judicatory/SM +judicature/M +judicial/Y +judiciary/SM +judicious/IYP +judiciousness/IM +judo/M +jug/SM +jugful/MS +jugged +juggernaut/SM +jugging +juggle/MZGDRS +juggler/M +jugglery/M +jugular/SM +juice/DRSMZG +juicer/M +juicily +juiciness/M +juicy/PTR +jujitsu/M +jujube/MS +jukebox/MS +julep/SM +julienne +jumble/MGDS +jumbo/SM +jump/MDRSZG +jumper/M +jumpily +jumpiness/M +jumpsuit/MS +jumpy/TRP +jun +junco/SM +junction/FISM +juncture/FMS +jungle/MS +junior/MS +juniper/SM +junk/MDRSZG +junker/M +junket/MDRSZG +junketeer/MS +junketer/M +junkie/M +junky/TRSM +junkyard/MS +junta/SM +juridic +juridical/Y +jurisdiction/SM +jurisdictional +jurisprudence/M +jurist/MS +juristic +juror/FSM +jury/ISM +juryman/M +jurymen +jurywoman/M +jurywomen +just/RYPT +justice/IMS +justifiable/U +justifiably/U +justification/M +justified/U +justify/XGDSN +justness/M +jut/SM +jute/M +jutted +jutting +juvenile/SM +juxtapose/DSG +juxtaposition/SM +k/IFGS +kHz +kW +kWh +kabbala +kabbalah +kabob/SM +kaboom +kabuki/M +kaddish/MS +kaffeeklatch/MS +kaffeeklatsch/MS +kahuna/S +kaiser/MS +kale/M +kaleidoscope/MS +kaleidoscopic +kaleidoscopically +kamikaze/MS +kana +kangaroo/MS +kanji +kaolin/M +kapok/M +kappa/SM +kaput +karakul/M +karaoke/MS +karat/SM +karate/M +karma/M +karmic +kart/MS +katakana +katydid/SM +kayak/SMDG +kayaking/M +kayo/MDSG +kazoo/SM +kbps +kc +kebab/SM +kebob/SM +kedgeree +keel/MDSG +keelhaul/DGS +keen/MDRYSTGP +keenness/M +keep/MRSZG +keeper/M +keeping/M +keepsake/MS +keg/SM +kelp/M +kelvin/SM +ken/SM +kenned +kennel/SGMD +kenning +keno/M +kepi/MS +kept +keratin/M +keratitis +kerbside +kerchief/SM +kerfuffle/S +kernel/SM +kerosene/M +kestrel/MS +ketch/MS +ketchup/M +kettle/SM +kettledrum/SM +key/SGMD +keybinding/S +keyboard/ZGSMDR +keyboarder/M +keyboardist/SM +keyhole/MS +keylogger/MS +keylogging/SM +keynote/MZGDRS +keynoter/M +keypad/SM +keypunch/ZGMDRS +keypuncher/M +keystone/MS +keystroke/SM +keyword/MS +kg +khaki/SM +khan/MS +kibble/DSMG +kibbutz/MS +kibbutzim +kibitz/ZGDRS +kibitzer/M +kibosh/M +kick/MDRSZG +kickback/SM +kickball/M +kickboxing +kicker/M +kickoff/MS +kickstand/MS +kicky/RT +kid/SM +kidded +kidder/SM +kiddie/SM +kidding +kiddish +kiddo/SM +kidnap/S +kidnapped +kidnapper/MS +kidnapping/MS +kidney/SM +kidskin/M +kielbasa/MS +kielbasi +kike/S +kill/JMDRSZG +killdeer/SM +killer/M +killing/M +killjoy/SM +kiln/MDSG +kilo/MS +kilobyte/SM +kilocycle/SM +kilogram/SM +kilohertz/M +kiloliter/MS +kilometer/MS +kiloton/SM +kilowatt/SM +kilt/MDRS +kilter/M +kimono/MS +kin/M +kinase +kind's +kind/UPRYT +kinda +kindergarten/MS +kindergartner/SM +kindergrtner/SM +kindhearted/PY +kindheartedness/M +kindle/AGDS +kindliness/M +kindling/M +kindly/URT +kindness/UM +kindnesses +kindred/M +kinds +kine/S +kinematic/S +kinematics/M +kinetic/S +kinetically +kinetics/M +kinfolk/SM +kinfolks/M +king/MYS +kingdom/SM +kingfisher/SM +kingly/RT +kingmaker/S +kingpin/SM +kingship/M +kink/MDSG +kinkily +kinkiness/M +kinky/TPR +kinsfolk/M +kinship/M +kinsman/M +kinsmen +kinswoman/M +kinswomen +kiosk/SM +kip/SM +kipped +kipper/MDGS +kipping +kirsch/MS +kismet/M +kiss/MDRSBZG +kisser/M +kissoff/SM +kissogram/S +kit/SGMD +kitbag/MS +kitchen/SM +kitchenette/MS +kitchenware/M +kite/MS +kith/M +kitsch/M +kitschy +kitted +kitten/MS +kittenish +kitting +kitty/SM +kiwi/MS +kiwifruit/MS +kl +klaxon/S +kleptocracy +kleptomania/M +kleptomaniac/SM +kludge/GDS +kluge/DS +klutz/MS +klutziness/M +klutzy/TRP +km +kn +knack/SZMR +knacker/GD +knackwurst/MS +knapsack/MS +knave/SM +knavery/M +knavish/Y +knead/SZGDR +kneader/M +knee/MDS +kneecap/SM +kneecapped +kneecapping +kneeing +kneel/SG +knell/SGMD +knelt +knew +knicker/S +knickerbockers/M +knickers/M +knickknack/MS +knife/DSMG +knight/MDYSG +knighthood/MS +knightliness/M +knish/MS +knit/MS +knitted +knitter/SM +knitting/M +knitwear/M +knives +knob/MS +knobbly +knobby/TR +knock/SZGMDR +knockabout +knockdown/SM +knocker/M +knockoff/SM +knockout/SM +knockwurst/SM +knoll/SM +knot/MS +knothole/SM +knotted +knotting +knotty/TR +know/SB +knowing/UYS +knowledge/M +knowledgeable +knowledgeably +known +knuckle/DSMG +knuckleduster/S +knucklehead/MS +knurl/SGMD +koala/SM +koan/S +kohl +kohlrabi/M +kohlrabies +kola/MS +kook/MS +kookaburra/SM +kookiness/M +kooky/TPR +kopeck/MS +kopek/SM +korma +kosher/DSG +kowtow/GMDS +kph +kraal/SM +kraut/SM! +krill/M +krona/M +krone/RM +kronor +kronur +krypton/M +krna/M +krnur +kt +kuchen/SM +kudos/M +kudzu/SM +kumquat/MS +kvetch/ZGMDRS +kvetcher/M +kw +l/SDXTGJ +la/M +lab/SM +label's +label/ASDG +labeled/U +labelled/U +labia +labial/SM +labile +labium/M +labor/SMDRZG +laboratory/SM +laborer/M +laborious/PY +laboriousness/M +laborsaving +laburnum/MS +labyrinth/M +labyrinthine +labyrinths +lac/M +lace's +lace/UGDS +lacerate/DSGNX +laceration/M +lacewing/SM +lacework/M +lachrymal +lachrymose +lack/MDSG +lackadaisical/Y +lackey/SM +lackluster +laconic +laconically +lacquer/GMDS +lacrimal +lacrosse/M +lactate/GNDS +lactation/M +lacteal +lactic +lactose/M +lacuna/M +lacunae +lacy/RT +lad/SGMDNJ +ladder/GSMD +laddie/SM +laddish/P +lade/S +laden/U +lading/M +ladle/DSMG +lady/SM +ladybird/SM +ladybug/MS +ladyfinger/MS +ladylike/U +ladylove/MS +ladyship/MS +laetrile/M +lag/SZMR +lager/M +laggard/MYS +lagged +lagging/M +lagniappe/SM +lagoon/SM +laid/IA +lain +lair/MS +laird/SM +laity/M +lake/MS +lakefront/S +lakeside +lallygag/S +lallygagged +lallygagging +lam/SM +lama/MS +lamasery/SM +lamb/MDSG +lambada/MS +lambast/GDS +lambaste/S +lambda/SM +lambency/M +lambent/Y +lambkin/SM +lambskin/SM +lambswool +lame/MYZTGDRSP +lamebrain/MDS +lameness/M +lament/BSMDG +lamentably +lamentation/MS +lamina/M +laminae +laminar +laminate/MGNDS +lamination/M +lammed +lamming +lamp/MS +lampblack/M +lamplight/MRZ +lamplighter/M +lampoon/SGMD +lamppost/SM +lamprey/MS +lampshade/SM +lanai/SM +lance/DRSMZG +lancer/M +lancet/SM +land/MDRSGJ +landau/SM +landfall/MS +landfill/MS +landholder/SM +landholding/MS +landing/M +landlady/SM +landless/M +landline/MS +landlocked +landlord/MS +landlubber/MS +landmark/MS +landmass/MS +landmine/S +landowner/MS +landownership +landowning/SM +landscape/MZGDRS +landscaper/M +landslid +landslide/MGS +landslip/S +landsman/M +landsmen +landward/S +lane/MS +language/MS +languid/PY +languidness/M +languish/DSG +languor/SM +languorous/Y +lank/RYTP +lankiness/M +lankness/M +lanky/RTP +lanolin/M +lantern/MS +lanthanum/M +lanyard/MS +lap/SM +laparoscopic +laparoscopy +laparotomy +lapboard/SM +lapdog/SM +lapel/SM +lapidary/SM +lapin/SM +lapped +lappet/SM +lapping +lapse/AKGMSD +laptop/SM +lapwing/MS +larboard/SM +larcenist/SM +larcenous +larceny/SM +larch/MS +lard/MDRSZG +larder/M +lardy/RT +large/RSPMYT +largehearted +largeness/M +largess/M +largish +largo/SM +lariat/SM +lark/MDSG +larkspur/SM +larva/M +larvae +larval +laryngeal +larynges +laryngitis/M +larynx/M +lasagna/MS +lascivious/YP +lasciviousness/M +lase/ZGDRS +laser/M +lash/MDSGJ +lashing/M +lass/MS +lassie/SM +lassitude/M +lasso/SMDG +last/MDYSG +lasting/Y +lat/S +latch's +latch/UDSG +latchkey/SM +late/YTRP +latecomer/MS +latency/M +lateness/M +latent +lateral/MDYSG +latest/M +latex/M +lath/MDRSZG +lathe/M +lather/GMD +lathery +laths +latices +latish +latitude/MS +latitudinal +latitudinarian/MS +latrine/MS +latte/RSM +latter/MY +lattice/MDS +latticework/SM +laud/MDSGB +laudably +laudanum/M +laudatory +laugh/BMDG +laughably +laughing/MY +laughingstock/SM +laughs +laughter/M +launch/AGMDS +launcher/SM +launchpad/SM +launder/DRZGS +launderer/M +launderette/SM +laundress/MS +laundromat/MS +laundry/SM +laundryman/M +laundrymen +laundrywoman/M +laundrywomen +laureate/MS +laureateship/M +laurel/SM +lav/SGD +lava/M +lavage/M +lavaliere/SM +lavatorial +lavatory/SM +lave/S +lavender/SM +lavish/PTGDRSY +lavishness/M +law/SM +lawbreaker/SM +lawbreaking/M +lawful/UPY +lawfulness/UM +lawgiver/MS +lawless/PY +lawlessness/M +lawmaker/MS +lawmaking/M +lawman/M +lawmen +lawn/MS +lawnmower/SM +lawrencium/M +lawsuit/MS +lawyer/SM +lax/TRYP +laxative/MS +laxity/M +laxness/M +lay/AICSGM +layabout/S +layaway/M +layer/CSM +layered +layering/M +layette/MS +layman/M +laymen +layoff/SM +layout/SM +layover/MS +laypeople +layperson/MS +layup/SM +laywoman/M +laywomen +laze/MGDS +lazily +laziness/M +lazy/DRSTGP +lazybones/M +lb/S +lbw +lea/SM +leach/DSG +lead/MDNRSZG +leader/M +leaderless +leadership/SM +leading/M +leaf/MDSG +leafage/M +leafless +leaflet/GMDS +leafstalk/MS +leafy/RT +league/DSMG +leak/MDSG +leakage/MS +leakiness/M +leaky/PRT +lean/MDRSTGJP +leaning/M +leanness/M +leap/MDRSZG +leaper/M +leapfrog/MS +leapfrogged +leapfrogging +leapt +learn/AUGDS +learnedly +learner/MS +learning's +lease/ADSMG +leaseback/SM +leasehold/MRSZ +leaseholder/M +leaser/SM +leash's +leash/UDSG +least/M +leastwise +leather/MS +leatherette/M +leatherneck/MS +leathery +leave/DRSMZGJ +leaven/SGMD +leavened/U +leavening/M +leaver/M +leavings/M +lech/MDRSZG +lecher/M +lecherous/PY +lecherousness/M +lechery/M +lecithin/M +lectern/MS +lector/SM +lecture/MZGDRS +lecturer/M +lectureship/SM +ledge/RSMZ +ledger/M +lee/RSMZ +leech/MDSG +leek/MS +leer/MDG +leeriness/M +leery/RPT +leeward/SM +leeway/M +left/MRST +leftism/M +leftist/SM +leftmost +leftover/SM +leftward/S +lefty/SM +leg/SM +legacy/SM +legal/SMY +legalese/M +legalism/MS +legalistic +legalistically +legality/SM +legalization/M +legalize/GDS +legate/CXMNS +legatee/MS +legation's/AC +legato/SM +legend/SM +legendarily +legendary +legerdemain/M +legged +leggin/SM +legginess/M +legging/MS +leggy/RPT +leghorn/MS +legibility/M +legible +legibly +legion/SM +legionary/SM +legionnaire/SM +legislate/DSGNV +legislation/M +legislative/Y +legislator/MS +legislature/SM +legit +legitimacy/M +legitimate/DSYG +legitimatize/GDS +legitimization/M +legitimize/DSG +legless +legman/M +legmen +legroom/SM +legume/MS +leguminous +legwarmer/S +legwork/M +lei/SM +leisure/DMY +leisureliness/M +leisurewear/M +leitmotif/MS +leitmotiv/MS +lemma/S +lemme/JG +lemming/M +lemon/SM +lemonade/SM +lemongrass +lemony +lemur/SM +lend/RSZG +lender/M +length/MNX +lengthen/GD +lengthily +lengthiness/M +lengths +lengthwise +lengthy/PRT +lenience/M +leniency/M +lenient/Y +lenitive +lens/MS +lent +lentil/MS +lento +leonine +leopard/SM +leopardess/MS +leotard/SM +leper/SM +lepidopterist/MS +leprechaun/MS +leprosy/M +leprous +lepta +lepton/MS +lesbian/SM +lesbianism/M +lesion/MS +less/MNRX +lessee/MS +lessen/GD +lesson/MS +lessor/MS +let/ISM +letdown/SM +lethal/Y +lethargic +lethargically +lethargy/M +letter/ZGMDRS +letterbomb/S +letterbox/S +lettered/U +letterer/M +letterhead/MS +lettering/M +letterpress/M +letting/S +lettuce/MS +letup/SM +leucine +leucotomy/S +leukemia/M +leukemic/SM +leukocyte/MS +levee/SM +level/PSZGMDRY +leveler/M +levelheaded/P +levelheadedness/M +levelness/M +lever/SGMD +leverage's +leverage/CDSG +leviathan/MS +levier/M +levitate/DSGN +levitation/M +levity/M +levy/DRSMZG +lewd/RYPT +lewdness/M +lexer/S +lexical +lexicographer/MS +lexicographic +lexicographical +lexicography/M +lexicon/SM +lexis +lg +liabilities +liability/AM +liable/A +liaise/GDS +liaison/MS +liar/MS +lib/M +libation/SM +libber/MS +libel/SZGMDR +libeler/M +libelous +liberal/MYPS +liberalism/M +liberality/M +liberalization/SM +liberalize/GDS +liberalness/M +liberate/CDSGN +liberation/CM +liberator/MS +libertarian/SM +libertine/MS +liberty/SM +libidinal +libidinous +libido/MS +librarian/MS +librarianship +library/SM +librettist/MS +libretto/SM +lice +license/MGDS +licensed/U +licensee/MS +licentiate/SM +licentious/YP +licentiousness/M +lichen/MS +licit/Y +lick/MDJSG +licking/M +licorice/SM +lid/SM +lidded +lidless +lido/MS +lie/DSM +lied/MR +lief/RT +liege/SM +lien/MS +lieu/M +lieutenancy/M +lieutenant/MS +life/MZR +lifebelt/S +lifeblood/M +lifeboat/MS +lifebuoy/MS +lifeforms +lifeguard/SM +lifeless/YP +lifelessness/M +lifelike +lifeline/MS +lifelong +lifer/M +lifesaver/SM +lifesaving/M +lifespan/S +lifestyle/SM +lifetime/MS +lifework/MS +lift/MDRSZG +lifter/M +liftoff/SM +ligament/MS +ligate/GNDS +ligation/M +ligature/MGDS +light's/C +light/CASTGD +lighted/U +lighten/SDRZG +lightener/M +lighter/SM +lightface/MD +lightheaded +lighthearted/YP +lightheartedness/M +lighthouse/MS +lighting's +lightly +lightness/M +lightning/MDS +lightproof +lightship/MS +lightweight/SM +ligneous +lignin +lignite/M +lii +likability/M +likable/P +likableness/M +like/EMGDST +likeability/M +likeable/P +likeableness/M +likelihood/UM +likelihoods +likeliness/UM +likely/UPRT +liken/SGD +likeness/UM +likenesses +liker +likewise +liking/M +lilac/SM +lilliputian +lilo/S +lilt/MDSG +lily/SM +limb/MS +limber/UDSG +limberness/M +limbless +limbo/SM +lime/MGDS +limeade/SM +limelight/M +limerick/SM +limescale +limestone/M +limey/S +limit's +limit/CSZGDR +limitation/CM +limitations +limited/U +limiter's +limiting/S +limitless/P +limitlessness/M +limn/DSG +limnological +limnologist/MS +limnology/M +limo/MS +limousine/MS +limp/MDRYSPTG +limpet/MS +limpid/YP +limpidity/M +limpidness/M +limpness/M +limy/RT +linage/M +linchpin/SM +linden/MS +line/MZGDRSJ +lineage/MS +lineal/Y +lineament/SM +linear/Y +linearity/M +linebacker/MS +lined/U +linefeed +lineman/M +linemen +linen/SM +linens/M +liner/M +linesman/M +linesmen +lineup/MS +ling/M +linger/ZGJDRS +lingerer/M +lingerie/M +lingering/Y +lingo/M +lingoes +lingual +linguine/M +linguini/SM +linguist/SM +linguistic/S +linguistical/Y +linguistics/M +liniment/SM +lining/M +link/MDRSG +linkage/MS +linkman +linkmen +linkup/MS +linnet/MS +lino +linoleum/M +linseed/M +lint's +lint/CDG +lintel/MS +lints +linty/TR +lion/MS +lioness/MS +lionhearted +lionization/M +lionize/GDS +lip/SM +lipid/SM +liposuction/M +lipped +lippy +lipread/GRS +lipreader/M +lipreading/M +lipstick/MDSG +liq +liquefaction/M +liquefy/DSG +liqueur/SM +liquid/MS +liquidate/XGNDS +liquidation/M +liquidator/MS +liquidity/M +liquidize/ZGDRS +liquidizer/M +liquor/MDGS +lira/M +lire +lisle/M +lisp/MDRSZG +lisper/M +lissome +list/MDNSJXG +listed/U +listen/BMDRZG +listener/M +listeria +listing/M +listless/YP +listlessness/M +lit/ZR +litany/SM +litchi/MS +lite +liter/M +literacy/M +literal/SMYP +literalness/M +literariness/M +literary/P +literate/SMY +literati/M +literature/M +lithe/RPYT +litheness/M +lithesome +lithium/M +lithograph/MDRZG +lithographer/M +lithographic +lithographically +lithographs +lithography/M +lithosphere/SM +litigant/SM +litigate/DSGN +litigation/M +litigator/MS +litigious/P +litigiousness/M +litmus/M +litotes/M +litter/MDRSZG +litterateur/MS +litterbug/MS +litterer/M +little/MTRP +littleness/M +littoral/SM +littrateur/SM +liturgical/Y +liturgist/SM +liturgy/SM +livability/M +livable/U +live/ATGDSB +livelihood/SM +liveliness/M +livelong/S +lively/PRT +liven/SGD +liver's +liver/S +liveried +liverish +liverwort/MS +liverwurst/M +livery/CSM +liveryman/CM +liverymen/C +livestock/M +liveware +livid/Y +living/MS +lix/K +lizard/MS +ll +llama/SM +llano/SM +lo +load's +load/AUGSD +loadable +loader/MS +loading's +loaf/MDRSZG +loafer/M +loam/M +loamy/TR +loan/MDRSZG +loaner/M +loansharking/M +loanword/MS +loath/JZGDRS +loathe +loather/M +loathing/M +loathsome/PY +loathsomeness/M +loaves +lob/SMD +lobar +lobbed +lobber/MS +lobbing +lobby/GDSM +lobbyist/MS +lobe/MS +lobotomize/DSG +lobotomy/SM +lobster/MS +local/SMY +locale/MS +locality/SM +localization/M +localize/DSG +locate/AESDNGX +location/EAM +locator/MS +locavore/SM +loci +lock/MDRSBZG +locker/M +locket/MS +lockjaw/M +lockout/MS +locksmith/M +locksmiths +lockstep/M +lockup/MS +loco/S +locomotion/M +locomotive/MS +locoweed/SM +locum/S +locus/M +locust/SM +locution/MS +lode/MS +lodestar/MS +lodestone/MS +lodge/DRSJMZG +lodger/M +lodging/M +lodgings/M +loft/MDSG +loftily +loftiness/M +lofty/PRT +log/SM +loganberry/SM +logarithm/SM +logarithmic +logbook/SM +loge/MS +logged +logger/SM +loggerhead/SM +loggia/SM +logging/M +logic/M +logical/Y +logicality/M +logician/MS +login/SM +logistic/S +logistical/Y +logistics/M +logjam/SM +logo/MS +logoff/SM +logon/SM +logotype/SM +logout/SM +logrolling/M +logy/RT +loin/MS +loincloth/M +loincloths +loiter/ZGSDR +loiterer/M +loitering/M +lolcat/SM +loll/DSG +lollipop/SM +lollop/GSD +lolly/S +lollygag/S +lollygagged +lollygagging +lollypop/MS +lone/YZR +loneliness/M +lonely/PTR +loner/M +lonesome/YP +lonesomeness/M +long's +long/KDSTG +longboat/MS +longbow/MS +longer +longevity/M +longhair/MS +longhand/M +longhorn/MS +longhouse/S +longing/MYS +longish +longitude/MS +longitudinal/Y +longshoreman/M +longshoremen +longsighted +longstanding +longtime +longueur/SM +longways +loo +loofah/M +loofahs +look/MDRSZG +lookalike/MS +looker/M +lookout/MS +lookup +loom/MDSG +loon/MS +loonie/M +loony/RSMT +loop/MDSG +loophole/MS +loopy/RT +loos/NRX +loose/UDSTG +loosely +loosen/UGSD +looseness/M +loot/MDRSZG +looter/M +looting/M +lop/S +lope/MGDS +lopped +lopping +lopsided/YP +lopsidedness/M +loquacious/PY +loquaciousness/M +loquacity/M +lord/MDYSG +lordliness/M +lordly/TPR +lordship/SM +lore/M +lorgnette/SM +loris/MS +lorn +lorry/SM +lose/ZGRSJ +loser/M +losing/M +loss/MS +lossless +lost +lot/SM +lotion/SM +lottery/SM +lotto/M +lotus/MS +louche +loud/RYTP +loudhailer/SM +loudmouth/MD +loudmouths +loudness/M +loudspeaker/MS +lough +loughs +lounge/MZGDRS +lounger/M +lour/DSG +louse's +louse/CDSG +lousily +lousiness/M +lousy/TPR +lout/MS +loutish/PY +louver/MDS +lovableness/M +lovably +love/MYZGDRSB +lovebird/SM +lovechild/M +loved/U +loveless +loveliness/M +lovelorn +lovely/RSMTP +lovemaking/M +lover/M +loveseat/SM +lovesick +lovey/S +loving/Y +low/SZTGMDRYP +lowborn +lowboy/MS +lowbrow/SM +lowdown/M +lower/GD +lowercase/M +lowermost +lowish +lowland/SZMR +lowlander/M +lowlife/SM +lowliness/M +lowly/TPR +lowness/M +lox/M +loyal/ETY +loyaler +loyalism/M +loyalist/SM +loyalties +loyalty/EM +lozenge/SM +ltd +luau/MS +lubber/MYS +lube/MGDS +lubricant/SM +lubricate/DSGN +lubrication/M +lubricator/MS +lubricious/Y +lubricity/M +lucid/PY +lucidity/M +lucidness/M +luck/MDSG +luckily/U +luckiness/UM +luckless +lucky/UPTR +lucrative/YP +lucrativeness/M +lucre/M +lucubrate/GNDS +lucubration/M +ludicrous/YP +ludicrousness/M +ludo +luff/DSG +lug/SM +luge/S +luggage/M +lugged +lugger/MS +lugging +lughole/S +lugsail/SM +lugubrious/YP +lugubriousness/M +lukewarm/YP +lukewarmness/M +lull/MDSG +lullaby/SM +lulu/S +lumbago/M +lumbar +lumber/MDRZGS +lumberer/M +lumbering/M +lumberjack/SM +lumberman/M +lumbermen +lumberyard/SM +luminary/SM +luminescence/M +luminescent +luminosity/M +luminous/Y +lummox/MS +lump/MDNSG +lumpectomy/S +lumpiness/M +lumpish +lumpy/TRP +lunacy/SM +lunar +lunatic/SM +lunch/GMDS +lunchbox/S +luncheon/SM +luncheonette/SM +lunchroom/MS +lunchtime/MS +lung/MDSG +lunge/SM +lungfish/MS +lungful/S +lunkhead/MS +lupine/MS +lupus/M +lurch/GMDS +lure/MGDS +lurgy +lurid/PY +luridness/M +lurk/DRSZG +luscious/PY +lusciousness/M +lush/MRSYPT +lushness/M +lust/MDRSG +luster/M +lusterless +lustful/Y +lustily +lustiness/M +lustrous/Y +lusty/PTR +lutanist/SM +lute/MS +lutenist/SM +lutetium/M +luxuriance/M +luxuriant/Y +luxuriate/DSGN +luxuriation/M +luxurious/PY +luxuriousness/M +luxury/SM +lvi +lvii +lxi +lxii +lxiv +lxix +lxvi +lxvii +lyceum/MS +lychee/MS +lychgate/S +lye/MG +lying/M +lymph/M +lymphatic/SM +lymphocyte/SM +lymphoid +lymphoma/SM +lynch/JZGDRS +lyncher/M +lynching/M +lynx/MS +lyre/MS +lyrebird/MS +lyric/SM +lyrical/Y +lyricism/M +lyricist/SM +lysosomal +lysosomes +m/KAS +mRNA +ma'am +ma/SMH +mac/SGMD +macabre +macadam/M +macadamia/SM +macadamize/GDS +macaque/MS +macaroni/MS +macaroon/MS +macaw/SM +mace/MS +macerate/DSGN +maceration/M +mach/M +machete/SM +machinate/GNDSX +machination/M +machine/DSMGB +machinery/M +machinist/MS +machismo/M +macho/M +mack/MS +mackerel/SM +mackinaw/SM +mackintosh/MS +macrame/M +macram/M +macro/SM +macrobiotic/S +macrobiotics/M +macrocosm/SM +macroeconomic/S +macroeconomics/M +macrology/S +macron/MS +macrophages +macroscopic +mad/SMYP +madam/SM +madame/M +madcap/MS +madden/DGS +maddening/Y +madder/MS +maddest +madding +made/AU +mademoiselle/MS +madhouse/SM +madman/M +madmen +madness/M +madras/MS +madrasa/SM +madrasah/M +madrasahs +madrassa/SM +madrigal/SM +madwoman/M +madwomen +maelstrom/SM +maestro/SM +mafia/SM +mafiosi +mafioso/M +mag/SM +magazine/SM +mage/MS +magenta/M +maggot/MS +maggoty +magi/M +magic/SM +magical/Y +magician/SM +magicked +magicking +magisterial/Y +magistracy/M +magistrate/SM +magma/M +magnanimity/M +magnanimous/Y +magnate/SM +magnesia/M +magnesium/M +magnet/MS +magnetic +magnetically +magnetism/M +magnetite/M +magnetizable +magnetization/CM +magnetize/CGDS +magneto/SM +magnetometer/SM +magnetosphere +magnification/M +magnificence/M +magnificent/Y +magnifier/M +magnify/ZGXDRSN +magniloquence/M +magniloquent +magnitude/SM +magnolia/MS +magnum/MS +magpie/MS +magus/M +maharaja/SM +maharajah/M +maharajahs +maharanee/MS +maharani/SM +maharishi/SM +mahatma/SM +mahjong/M +mahogany/SM +mahout/MS +maid/MNSX +maiden/MY +maidenhair/M +maidenhead/SM +maidenhood/M +maidservant/SM +mail/JMDRSZG +mailbag/SM +mailbomb/GSD +mailbox/MS +mailer/M +mailing/M +maillot/SM +mailman/M +mailmen +mailshot/S +maim/DSG +main/MYS +mainframe/SM +mainland/MS +mainline/MGDS +mainmast/MS +mainsail/MS +mainspring/MS +mainstay/MS +mainstream/SMDG +maintain/ZGBDRS +maintainability +maintenance/M +maintop/SM +maisonette/MS +maize/SM +majestic +majestically +majesty/SM +majolica/M +major/SGMDY +majordomo/MS +majorette/MS +majoritarian/SM +majoritarianism +majority/SM +make's/A +make/UAGS +makeover/MS +maker/SM +makeshift/SM +makeup/MS +makeweight/S +making/MS +makings/M +malachite/M +maladjusted +maladjustment/M +maladministration +maladroit/PY +maladroitness/M +malady/SM +malaise/M +malamute/MS +malapropism/SM +malaria/M +malarial +malarkey/M +malathion/M +malcontent/MS +male/MPS +malediction/SM +malefaction/M +malefactor/SM +malefic +maleficence/M +maleficent +maleness/M +malevolence/M +malevolent/Y +malfeasance/M +malformation/SM +malformed +malfunction/MDSG +malice/M +malicious/PY +maliciousness/M +malign/DSG +malignancy/SM +malignant/Y +malignity/M +malinger/ZGSDR +malingerer/M +mall/MS +mallard/SM +malleability/M +malleable +mallet/MS +mallow/MS +malnourished +malnutrition/M +malocclusion/M +malodorous +malpractice/SM +malt/MDSG +malted/MS +maltose/M +maltreat/GLDS +maltreatment/M +malty/TR +malware/SM +mam/S +mama/MS +mamba/SM +mambo/SGMD +mamma/M +mammal/MS +mammalia +mammalian/MS +mammary +mammogram/MS +mammography/M +mammon/M +mammoth/M +mammoths +mammy/SM +man's/F +man/UFY +manacle/DSMG +manage/ZGDRSL +manageability/M +manageable/U +management/MS +manager/M +manageress/S +managerial +manana/MS +manatee/SM +mandala/SM +mandamus/MS +mandarin/MS +mandate/DSMG +mandatory +mandible/MS +mandibular +mandolin/MS +mandrake/MS +mandrel/SM +mandrill/MS +mane/MDS +manege/M +maneuver/MDGSBJ +maneuverability/M +manful/Y +manga/M +manganese/M +mange/DRMZ +manger/M +mangetout/S +manginess/M +mangle/MZGDRS +mango/M +mangoes +mangrove/MS +mangy/TRP +manhandle/GDS +manhole/SM +manhood/M +manhunt/SM +mania/SM +maniac/MS +maniacal/Y +manic/SM +manically +manicure/MGDS +manicurist/MS +manifest/MDYSG +manifestation/SM +manifesto/SM +manifold/GMDS +manikin/SM +manila/M +manioc/MS +manipulable +manipulate/XGNVDS +manipulation/M +manipulative/Y +manipulator/MS +mankind/M +manky +manlike +manliness/M +manly/URT +manna/M +manned/U +mannequin/SM +manner/MDYS +mannerism/SM +mannerly/U +manning/U +mannish/YP +mannishness/M +manometer/SM +manor/SM +manorial +manpower/M +manque +manqu +mans +mansard/MS +manse/SXMN +manservant/M +mansion/M +manslaughter/M +manta/SM +mantel/MS +mantelpiece/SM +mantelshelf +mantelshelves +mantes +mantilla/SM +mantis/MS +mantissa/SM +mantle's +mantle/EGDS +mantra/MS +manual/MYS +manufacture/DRSMZG +manufacturer/M +manufacturing/M +manumission/SM +manumit/S +manumitted +manumitting +manure/MGDS +manuscript/MS +many/M +mange/M +map's +map/AS +maple/SM +mapmaker/SM +mapped/A +mapper/MS +mapping/S +mar/S +marabou/MS +marabout/SM +maraca/MS +maraschino/MS +marathon/SMRZ +marathoner/M +maraud/ZGDRS +marauder/M +marble/MGDS +marbleize/GDS +marbling/M +march/ZGMDRS +marcher/M +marchioness/MS +mare/MS +margarine/M +margarita/MS +marge +margin/MS +marginal/YS +marginalia/M +marginalization/M +marginalize/GDS +maria/M +mariachi/MS +marigold/MS +marijuana/M +marimba/SM +marina/MS +marinade/DSMG +marinara/M +marinate/DSGN +marination/M +marine/MZRS +mariner/M +marionette/MS +marital/Y +maritime +marjoram/M +mark/AMDSG +markdown/SM +marked/U +markedly +marker/MS +market/MDRZGBS +marketability/M +marketable/U +marketeer/SM +marketer/M +marketing/M +marketplace/SM +marking/SM +markka/M +markkaa +marksman/M +marksmanship/M +marksmen +markup/MS +marl/M +marlin/MS +marlinespike/SM +marmalade/M +marmoreal +marmoset/SM +marmot/MS +maroon/MDGS +marque/MS +marquee/SM +marquess/MS +marquetry/M +marquis/MS +marquise/M +marquisette/M +marred/U +marriage/ASM +marriageability/M +marriageable +married/SM +marring +marrow/MS +marry/AGDS +marsh/MS +marshal/SMDG +marshland/SM +marshmallow/SM +marshy/RT +marsupial/MS +mart/MNSX +marten/M +martensite +martial/Y +martian/S +martin/MS +martinet/MS +martingale/MS +martini/SM +martyr/MDGS +martyrdom/M +marvel/MDGS +marvelous/Y +marzipan/M +masc +mascara/GMDS +mascot/MS +masculine/SM +masculinity/M +maser/SM +mash/MDRSZG +masher/M +mashup/MS +mask's +mask/UDSG +masker/MS +masochism/M +masochist/SM +masochistic +masochistically +mason/SM +masonic +masonry/M +masque/MS +masquerade/DRSMZG +masquerader/M +mass/MDSGV +massacre/MGDS +massage/DSMG +masseur/SM +masseuse/MS +massif/MS +massive/PY +massiveness/M +mast/MDS +mastectomy/SM +master's +master/ADGS +masterclass/S +masterful/Y +masterly +mastermind/SGMD +masterpiece/MS +masterstroke/SM +masterwork/MS +mastery/M +masthead/MS +mastic/M +masticate/GNDS +mastication/M +mastiff/SM +mastitis +mastodon/SM +mastoid/SM +masturbate/GNDS +masturbation/M +masturbatory +mat/SZGMDR +matador/SM +match/AMS +matchbook/SM +matchbox/MS +matched/U +matching +matchless +matchlock/SM +matchmaker/MS +matchmaking/M +matchstick/MS +matchwood/M +mate/MS +material/SMY +materialism/M +materialist/SM +materialistic +materialistically +materialization/M +materialize/DSG +materiel/M +maternal/Y +maternity/M +matey/S +mathematical/Y +mathematician/SM +mathematics/M +matinee/SM +mating/M +matins/M +matine/SM +matriarch/M +matriarchal +matriarchs +matriarchy/SM +matrices +matricidal +matricide/MS +matriculate/DSGN +matriculation/M +matrimonial +matrimony/M +matrix/M +matron/MYS +matte/DRSMZG +matter/MDG +matting/M +mattock/SM +mattress/MS +maturate/GNDS +maturation/M +mature/YTGDRS +maturity/SM +matzo/SMH +matzoh/M +matzohs +matzot +matriel/M +maudlin +maul/MDRSZG +mauler/M +maunder/SDG +mausoleum/SM +mauve/M +maven/SM +maverick/SM +maw/SM +mawkish/PY +mawkishness/M +max/GMDS +maxi/MS +maxilla/M +maxillae +maxillary +maxim/SM +maximal/Y +maximization/M +maximize/GDS +maximum/SM +may/M +maybe/SM +mayday/MS +mayflower/MS +mayfly/SM +mayhem/M +mayn't +mayo/M +mayonnaise/M +mayor/SM +mayoral +mayoralty/M +mayoress/MS +maypole/SM +mayst +maze/MS +mazurka/MS +maana/M +mdse +me/DSH +mead/M +meadow/MS +meadowlark/MS +meager/PY +meagerness/M +meal/MS +mealiness/M +mealtime/SM +mealy/TPR +mealybug/SM +mealymouthed +mean/MRYJPSTG +meander/SMDJG +meanderings/M +meanie/M +meaning/M +meaningful/PY +meaningfulness/M +meaningless/YP +meaninglessness/M +meanness/M +meant/U +meantime/M +meanwhile/M +meany/SM +meas +measles/M +measly/RT +measurable +measurably +measure's +measure/ADSG +measured/U +measureless +measurement/MS +meat/MS +meatball/MS +meathead/MS +meatiness/M +meatless +meatloaf/M +meatloaves +meatpacking/M +meaty/TPR +mecca/SM +mechanic/MS +mechanical/Y +mechanics/M +mechanism/SM +mechanistic +mechanistically +mechanization/M +mechanize/DSG +medal/SM +medalist/MS +medallion/SM +meddle/ZGDRS +meddler/M +meddlesome +media/SM +medial/AY +median/MS +mediate/DSGN +mediated/U +mediation/AM +mediator/MS +medic/SM +medicaid/M +medical/SMY +medicament/M +medicare/M +medicate/GNXDS +medication/M +medicinal/Y +medicine/MS +medico/MS +medieval +medievalist/MS +mediocre +mediocrity/SM +meditate/DSGNVX +meditation/M +meditative/Y +medium/MS +medley/MS +medulla/SM +medusa +medusae +meed/M +meek/RYPT +meekness/M +meerschaum/SM +meet/MJSG +meeting/M +meetinghouse/SM +meetup/MS +meg/S +mega +megabit/SM +megabucks/M +megabyte/MS +megachurch/MS +megacycle/SM +megadeath/M +megadeaths +megahertz/M +megajoule/M +megalith/M +megalithic +megaliths +megalomania/M +megalomaniac/SM +megalopolis/MS +megaphone/DSMG +megapixel/SM +megastar/S +megaton/SM +megawatt/MS +meh +meiosis/M +meiotic +melamine/M +melancholia/M +melancholic/S +melancholy/M +melange/MS +melanin/M +melanoma/SM +meld/MDSG +melee/SM +meliorate/GNVDS +melioration/M +mellifluous/PY +mellifluousness/M +mellow/PTGDRYS +mellowness/M +melodic +melodically +melodious/YP +melodiousness/M +melodrama/MS +melodramatic/S +melodramatically +melodramatics/M +melody/SM +melon/SM +melt's +melt/ADSG +meltdown/SM +member's +member/EAS +membership/SM +membrane/SM +membranous +meme/MS +memento/MS +memo/MS +memoir/MS +memorabilia/M +memorability/M +memorable/U +memorably +memorandum/MS +memorial/SM +memorialize/DSG +memorization/M +memorize/DSG +memory/SM +memsahib/S +men/M +menace/MGDS +menacing/Y +menage/MS +menagerie/MS +mend/MDRSZG +mendacious/Y +mendacity/M +mendelevium/M +mender/M +mendicancy/M +mendicant/SM +mending/M +menfolk/MS +menfolks/M +menhaden/M +menial/MYS +meningeal +meninges +meningitis/M +meninx/M +menisci +meniscus/M +menopausal +menopause/M +menorah/M +menorahs +mensch/MS +menservants +menses/M +menstrual +menstruate/GNDS +menstruation/M +mensurable +mensuration/M +menswear/M +mental/Y +mentalist/SM +mentality/SM +menthol/M +mentholated +mention/GSMD +mentioned/U +mentor/MDSG +menu/MS +meow/MDSG +mercantile +mercantilism/M +mercenary/SM +mercer/MS +mercerize/GDS +merchandise/MZGDRS +merchandiser/M +merchandising/M +merchant/MBS +merchantman/M +merchantmen +merciful/UY +merciless/PY +mercilessness/M +mercurial/Y +mercuric +mercury/M +mercy/SM +mere/MYTS +meretricious/YP +meretriciousness/M +merganser/MS +merge/DRSZG +merger/M +meridian/MS +meringue/MS +merino/MS +merit/CSM +merited/U +meriting +meritocracy/SM +meritocratic +meritorious/PY +meritoriousness/M +mermaid/SM +merman/M +mermen +merrily +merriment/M +merriness/M +merry/TRP +merrymaker/MS +merrymaking/M +mesa/MS +mescal/MS +mescalin +mescaline/M +mesdames +mesdemoiselles +mesh/MDSG +mesmeric +mesmerism/M +mesmerize/ZGDRS +mesmerizer/M +mesomorph/M +mesomorphs +meson/SM +mesosphere/SM +mesothelioma/M +mesquite/SM +mess/MDSG +message/MGDS +messeigneurs +messenger/SM +messiah/M +messiahs +messianic +messieurs +messily +messiness/M +messmate/SM +messy/PTR +mestizo/MS +met +meta +metabolic +metabolically +metabolism/SM +metabolite/SM +metabolize/DSG +metacarpal/SM +metacarpi +metacarpus/M +metadata/M +metal/SMD +metalanguage/MS +metallic +metallurgic +metallurgical +metallurgist/MS +metallurgy/M +metalwork/MRZG +metalworker/M +metalworking/M +metamorphic +metamorphism/M +metamorphose/GDS +metamorphosis/M +metaphor/MS +metaphoric +metaphorical/Y +metaphysical/Y +metaphysics/M +metastases +metastasis/M +metastasize/DSG +metastatic +metatarsal/MS +metatarsi +metatarsus/M +metatheses +metathesis/M +mete/MZGDRS +metempsychoses +metempsychosis/M +meteor/MS +meteoric +meteorically +meteorite/SM +meteoroid/SM +meteorologic +meteorological +meteorologist/SM +meteorology/M +meter/GMD +methadone/M +methamphetamine/M +methane/M +methanol/M +methinks +method/MS +methodical/YP +methodicalness/M +methodological/Y +methodology/SM +methotrexate +methought +methoxy +meths +methyl/M +meticulous/YP +meticulousness/M +metier/MS +metric/S +metrical/Y +metricate/GNDS +metrication/M +metricize/GDS +metro/SM +metronome/MS +metropolis/MS +metropolitan +mettle/M +mettlesome +mew/SGMD +mewl/DSG +mews/M +mezzanine/MS +mezzo/SM +mfg +mfr/S +mg +mgr +mi/MNX +miasma/MS +mic/S +mica/M +mice +mick/S +mickey/MS +micro/SM +microaggression/SM +microbe/MS +microbial +microbiological +microbiologist/MS +microbiology/M +microbrewery/SM +microchip/MS +microcircuit/SM +microcode +microcomputer/MS +microcosm/MS +microcosmic +microdot/SM +microeconomics/M +microelectronic/S +microelectronics/M +microfiber/MS +microfiche/M +microfilm/GMDS +microfloppies +microgroove/SM +microlight/MS +microloan/MS +micromanage/GDSL +micromanagement/M +micrometeorite/SM +micrometer/MS +micron/MS +microorganism/MS +microphone/SM +microprocessor/MS +microscope/SM +microscopic +microscopical/Y +microscopy/M +microsecond/MS +microsurgery/M +microwave/DSMGB +microwaveable +mid +midair/M +midday/M +midden/MS +middle/MGS +middlebrow/SM +middleman/M +middlemen +middlemost +middleweight/MS +middy/SM +midfield/RZ +midge/SM +midget/MS +midi/MS +midland/MS +midlife/M +midmost +midnight/M +midpoint/MS +midrib/MS +midriff/MS +midsection/MS +midshipman/M +midshipmen +midships +midsize +midst/M +midstream/M +midsummer/M +midterm/MS +midtown/M +midway/MS +midweek/MS +midwife/MGDS +midwifery/SM +midwinter/M +midwived +midwives +midwiving +midyear/MS +mien/M +miff/DSG +might've +might/M +mightily +mightiness/M +mightn't +mighty/TRP +mignonette/SM +migraine/MS +migrant/MS +migrate/AGDS +migration/SM +migrator/MS +migratory +mikado/MS +mike/MGDS +mil/SZMR +milady/SM +milch +mild/MRYTP +mildew/SMDG +mildness/M +mile/MS +mileage/SM +milepost/MS +miler/M +milestone/MS +milf/MS +milieu/SM +militancy/M +militant/MYS +militarily +militarism/M +militarist/SM +militaristic +militarization/CM +militarize/CDSG +military/M +militate/GDS +militia/SM +militiaman/M +militiamen +milk/MDRSZG +milker/M +milkiness/M +milkmaid/MS +milkman/M +milkmen +milkshake/SM +milksop/MS +milkweed/SM +milky/RTP +mill/MDRSZGJ +millage/M +millennia +millennial/M +millennium/MS +miller/M +millet/M +milliard/MS +millibar/MS +milligram/MS +milliliter/MS +millimeter/MS +milliner/MS +millinery/M +milling/M +million/HSM +millionaire/SM +millionairess/S +millionth/M +millionths +millipede/SM +millisecond/SM +millpond/SM +millrace/SM +millstone/SM +millstream/MS +millwright/SM +milometer/S +milquetoast/SM +milt/MDSG +mime/MGDS +mimeograph/GMD +mimeographs +mimetic +mimic/SM +mimicked +mimicker/SM +mimicking +mimicry/SM +mimosa/SM +min +minaret/MS +minatory +mince/DRSMZG +mincemeat/M +mincer/M +mind's +mind/ADRSZG +mindbogglingly +minded/P +mindful/YP +mindfulness/M +mindless/YP +mindlessness/M +mindset/MS +mine/MZGNDRSX +minefield/SM +miner/M +mineral/MS +mineralogical +mineralogist/MS +mineralogy/M +minestrone/M +minesweeper/SM +mingle/DSG +mingy +mini/MS +miniature/MS +miniaturist/MS +miniaturization/M +miniaturize/GDS +minibar/S +minibike/SM +minibus/MS +minicab/S +minicam/MS +minicomputer/SM +minifloppies +minim/SM +minimal/Y +minimalism/M +minimalist/MS +minimization/M +minimize/DSG +minimum/MS +mining/M +minion/M +miniseries/M +miniskirt/MS +minister/SGMD +ministerial +ministrant/MS +ministration/MS +ministry/SM +minivan/MS +mink/MS +minnesinger/MS +minnow/SM +minor/SMDG +minority/SM +minoxidil/M +minster/MS +minstrel/SM +minstrelsy/M +mint/MDRSZG +mintage/M +minter/M +minty/RT +minuend/MS +minuet/SM +minus/MS +minuscule/MS +minute/PDRSMYTG +minuteman/M +minutemen +minuteness/M +minutia/M +minutiae +minx/MS +miracle/MS +miraculous/Y +mirage/SM +mire/MGDS +mirror/GSMD +mirth/M +mirthful/PY +mirthfulness/M +mirthless/Y +miry/RT +misaddress/DSG +misadventure/MS +misaligned +misalignment/M +misalliance/MS +misandrist/MS +misandry +misanthrope/SM +misanthropic +misanthropically +misanthropist/MS +misanthropy/M +misapplication/M +misapply/DSGNX +misapprehend/GSD +misapprehension/MS +misappropriate/XDSGN +misappropriation/M +misbegotten +misbehave/GDS +misbehavior/M +misc +miscalculate/DSXGN +miscalculation/M +miscall/DSG +miscarriage/MS +miscarry/GDS +miscast/SG +miscegenation/M +miscellaneous/Y +miscellany/SM +mischance/SM +mischief/M +mischievous/YP +mischievousness/M +miscibility/M +miscible +miscommunication/S +misconceive/GDS +misconception/SM +misconduct/MDGS +misconstruction/MS +misconstrue/GDS +miscount/MDSG +miscreant/SM +miscue/DSMG +misdeal/GMS +misdealt +misdeed/MS +misdemeanor/MS +misdiagnose/GDS +misdiagnosis/M +misdid +misdirect/SDG +misdirection/M +misdo/JG +misdoes +misdoing/M +misdone +miser/SBMY +miserableness/M +miserably +miserliness/M +misery/SM +misfeasance/M +misfeature/S +misfile/GDS +misfire/MGDS +misfit/SM +misfitted +misfitting +misfortune/SM +misgiving/MS +misgovern/SDGL +misgovernment/M +misguidance/M +misguide/DSG +misguided/Y +mishandle/DSG +mishap/SM +mishear/GS +misheard +mishit/S +mishitting +mishmash/MS +misidentify/GDS +misinform/DGS +misinformation/M +misinterpret/SGD +misinterpretation/SM +misjudge/LDSG +misjudgement/SM +misjudgment/SM +mislabel/GSD +mislaid +mislay/GS +mislead/GS +misleading/Y +misled +mismanage/LGDS +mismanagement/M +mismatch/GMDS +misname/GDS +misnomer/MS +misogamist/MS +misogamy/M +misogynist/SM +misogynistic +misogynous +misogyny/M +misplace/GLDS +misplacement/M +misplay/GMDS +misprint/GMDS +misprision/M +mispronounce/DSG +mispronunciation/SM +misquotation/MS +misquote/MGDS +misread/GJS +misreading/M +misreport/MDGS +misrepresent/GDS +misrepresentation/MS +misrule/MGDS +miss's +miss/EDSGV +missal/ESM +missed/U +misshape/GDS +misshapen +missile/MS +missilery/M +mission/AMS +missionary/SM +missioner/SM +missis/MS +missive/MS +misspeak/GS +misspell/GDJS +misspelling/M +misspend/GS +misspent +misspoke +misspoken +misstate/GDSL +misstatement/SM +misstep/MS +missus/MS +mist's +mist/CDRSZG +mistakable/U +mistake/BMGS +mistaken/Y +mister's +mistily +mistime/GDS +mistiness/M +mistletoe/M +mistook +mistral/MS +mistranslated +mistreat/LDGS +mistreatment/M +mistress/MS +mistrial/MS +mistrust/MDSG +mistrustful/Y +misty/PRT +mistype/GS +misunderstand/SGJ +misunderstanding/M +misunderstood +misuse/DSMG +mite/MZRS +miter/MDG +mitigate/XDSGN +mitigated/U +mitigation/M +mitochondria +mitochondrial +mitochondrion +mitoses +mitosis/M +mitotic +mitral +mitt/MNSX +mitten/M +mix/ZGMDRSB +mixed/U +mixer/M +mixture/SM +mizzen/MS +mizzenmast/SM +mkay +mks +ml +mm +mnemonic/MS +mnemonically +mo/CKHS +moan/MDRSZG +moaner/M +moat/MDS +mob's +mob/CS +mobbed/C +mobbing/C +mobile/MS +mobility/M +mobilization/CM +mobilizations +mobilize/CDSG +mobilizer/SM +mobster/SM +moccasin/SM +mocha/SM +mock/DRSZG +mocker/M +mockery/SM +mocking/Y +mockingbird/SM +mod/STM +modal/SM +modality/S +modded +modding +mode/MS +model/ZGSJMDR +modeler/M +modeling/M +modeller/MS +modelling/MS +modem/SM +moderate/MYGNPDS +moderateness/M +moderation/M +moderator/SM +modern/MYPS +modernism/M +modernist/SM +modernistic +modernity/M +modernization/M +modernize/DRSZG +modernizer/M +modernness/M +modest/Y +modesty/M +modicum/SM +modifiable +modification/M +modified/U +modifier/M +modify/DRSXZGN +modish/YP +modishness/M +modular +modulate/CGNDS +modulation/CM +modulations +modulator/MS +module/MS +modulo +modulus +moggy +mogul/SM +mohair/M +moi +moiety/SM +moil/MDSG +moire/SM +moist/XTPNRY +moisten/DRZG +moistener/M +moistness/M +moisture/M +moisturize/ZGDRS +moisturizer/M +molar/SM +molasses/M +mold/MDRJSZG +moldboard/SM +molder/GMD +moldiness/M +molding/M +moldy/TPR +mole/MS +molecular +molecularity/M +molecule/SM +molehill/SM +moleskin/M +molest/DRZGS +molestation/M +molested/U +molester/M +moll/MS +mollification/M +mollify/DSNG +mollusc/SM +molluscan/SM +mollusk/SM +molluskan/S +molly/SM +mollycoddle/DSMG +molt/MDNRSZG +molter/M +molybdenum/M +mom/SM +moment/MS +momenta +momentarily +momentariness/M +momentary/P +momentous/PY +momentousness/M +momentum/M +mommy/SM +monarch/M +monarchic +monarchical +monarchism/M +monarchist/MS +monarchistic +monarchs +monarchy/SM +monastery/SM +monastic/MS +monastical/Y +monasticism/M +monaural +monetarily +monetarism/M +monetarist/MS +monetary +monetize/CGDS +money/SMD +moneybag/MS +moneybox/S +moneygrubber/SM +moneygrubbing/M +moneylender/SM +moneymaker/SM +moneymaking/M +monger/MDGS +mongol/S +mongolism/M +mongoloid/MS +mongoose/MS +mongrel/SM +monies +moniker/SM +monism/M +monist/MS +monition/SM +monitor/SMDG +monitory +monk/MS +monkey/MDGS +monkeyshine/SM +monkish +monkshood/SM +mono/M +monochromatic +monochrome/MS +monocle/DSM +monoclonal +monocotyledon/SM +monocotyledonous +monocular +monodic +monodist/SM +monody/SM +monogamist/MS +monogamous/Y +monogamy/M +monogram/SM +monogrammed +monogramming +monograph/M +monographs +monolingual/MS +monolith/M +monolithic +monoliths +monologist/SM +monologue/SM +monologuist/SM +monomania/M +monomaniac/MS +monomaniacal +monomer/SM +mononucleosis/M +monophonic +monoplane/SM +monopolist/SM +monopolistic +monopolization/M +monopolize/DRSZG +monopolizer/M +monopoly/SM +monorail/MS +monosyllabic +monosyllable/MS +monotheism/M +monotheist/SM +monotheistic +monotone/MS +monotonic +monotonically +monotonous/PY +monotonousness/M +monotony/M +monounsaturated +monoxide/MS +monseigneur/M +monsieur/M +monsignor/SM +monsoon/SM +monsoonal +monster/SM +monstrance/ASM +monstrosity/SM +monstrous/Y +montage/SM +month/MY +monthly/SM +months +monument/MS +monumental/Y +moo/SGMD +mooch/ZGMDRS +moocher/M +mood/MS +moodily +moodiness/M +moody/TPR +moon/MDSG +moonbeam/MS +moonless +moonlight/SMDRZG +moonlighter/M +moonlighting/M +moonlit +moonscape/SM +moonshine/MZRS +moonshiner/M +moonshot/MS +moonstone/MS +moonstruck +moonwalk/MS +moor/MDJSG +moorhen/S +mooring/M +moorland/MS +moose/M +moot/DSG +mop/SZGMDR +mope/MS +moped/SM +moper/M +mopey +mopier +mopiest +mopish +mopped +moppet/MS +mopping +moraine/SM +moral/SMY +morale/M +moralist/MS +moralistic +moralistically +moralities +morality/UM +moralization/CM +moralize/CGDS +moralizer/MS +morass/MS +moratorium/SM +moray/SM +morbid/YP +morbidity/M +morbidness/M +mordancy/M +mordant/SMY +more/MS +moreish +morel/SM +moreover +mores/M +morgue/MS +moribund +morn/MJSG +morning/M +morocco/M +moron/SM +moronic +moronically +morose/YP +moroseness/M +morph/GD +morpheme/MS +morphemic +morphia/M +morphine/M +morphing/M +morphological +morphology/M +morphs +morrow/MS +morsel/MS +mortal/MYS +mortality/M +mortar/MDSG +mortarboard/SM +mortgage's +mortgage/AGDS +mortgagee/MS +mortgagor/MS +mortician/MS +mortification/M +mortify/NGDS +mortise/DSMG +mortuary/SM +mosaic/MS +mosey/SGD +mosh/DSG +mosque/MS +mosquito/M +mosquitoes +moss/MS +mossback/SM +mossy/TR +most/MY +mot/SM +mote's +mote/KCXSVN +motel/SM +motet/SM +moth/M +mothball/GMDS +mother/MDYSG +motherboard/SM +motherfucker/MS! +motherfucking/! +motherhood/M +motherland/MS +motherless +motherliness/M +moths +motif/SM +motile/S +motility/M +motion/KCM +motioned +motioning +motionless/YP +motionlessness/M +motivate/CDSG +motivated/U +motivation/SM +motivational +motivator/SM +motive/MS +motiveless +motley/MS +motlier +motliest +motocross/MS +motor/SGMD +motorbike/MGDS +motorboat/MS +motorcade/MS +motorcar/SM +motorcycle/DSMG +motorcyclist/MS +motorist/SM +motorization/M +motorize/DSG +motorman/M +motormen +motormouth/M +motormouths +motorsport/SM +motorway/SM +mottle/GDS +motto/M +mottoes +moue/MS +mound/SGMD +mount/EASGMD +mountable +mountain/SM +mountaineer/SMDG +mountaineering/M +mountainous +mountainside/SM +mountaintop/SM +mountebank/MS +mounted/U +mounter/MS +mounting/SM +mourn/SZGDR +mourned/U +mourner/M +mournful/YP +mournfulness/M +mourning/M +mouse/DRSMZG +mouser/M +mousetrap/SM +mousetrapped +mousetrapping +mousey +mousiness/M +moussaka/S +mousse/MGDS +mousy/PTR +mouth/GMD +mouthfeel +mouthful/MS +mouthiness/M +mouthpiece/MS +mouths +mouthwash/MS +mouthwatering +mouthy/PTR +mouton/M +movable/SM +move/AMZGDRSB +moveable/SM +moved/U +movement/SM +mover/AM +movie/SM +moviegoer/SM +moving/Y +mow/SZGMDR +mower/M +moxie/M +mozzarella/M +mp +mpg +mph +mt +mtg +mtge +mu/SM +much/M +mucilage/M +mucilaginous +muck/MDSG +muckrake/DRSZG +muckraker/M +mucky/TR +mucous +mucus/M +mud/M +muddily +muddiness/M +muddle/MGDS +muddleheaded +muddy/PTGDRS +mudflap/S +mudflat/MS +mudguard/SM +mudpack/S +mudroom/MS +mudslide/MS +mudslinger/SM +mudslinging/M +muenster/M +muesli +muezzin/MS +muff/MDSG +muffin/MS +muffle/ZGDRS +muffler/M +mufti/SM +mug/SM +mugful/MS +mugged +mugger/MS +mugginess/M +mugging/MS +muggins +muggle/MS +muggy/PTR +mugshot/MS +mugwump/MS +mujaheddin +mujahedin/M +mukluk/MS +mulatto/M +mulattoes +mulberry/SM +mulch/GMDS +mulct/SGMD +mule/MS +muleskinner/MS +muleteer/MS +mulish/PY +mulishness/M +mull/DSG +mullah/M +mullahs +mullein/M +mullet/MS +mulligan/SM +mulligatawny/M +mullion/SMD +multi +multicast +multicolored +multicultural +multiculturalism/M +multidimensional +multidisciplinary +multifaceted +multifamily +multifarious/PY +multifariousness/M +multiform +multigrain +multilateral/Y +multilayered +multilevel +multilingual +multilingualism/M +multimedia/M +multimillionaire/SM +multinational/SM +multiparty +multiplayer/M +multiple/MS +multiplex/ZGMDRS +multiplexer/M +multiplicand/MS +multiplication/M +multiplicative +multiplicity/SM +multiplier/M +multiply/NZGDRSX +multiprocessing +multiprocessor/SM +multipurpose +multiracial +multistage +multistory +multitask/GS +multitasking/M +multitude/SM +multitudinous +multivariate +multiverse/SM +multivitamin/MS +multiyear +mum +mumble/MZGDRS +mumbler/M +mumbletypeg/M +mummer/MS +mummery/M +mummification/M +mummify/GNDS +mummy/SM +mumps/M +mun +munch/GDS +munchies/M +munchkin/SM +mundane/SY +mung/DSG +municipal/SMY +municipality/SM +munificence/M +munificent/Y +munition/MDGS +mural/SM +muralist/SM +murder/ZGMDRS +murderer/M +murderess/MS +murderous/Y +murine +murk/MS +murkily +murkiness/M +murky/PTR +murmur/ZGJMDRS +murmurer/M +murmuring/M +murmurous +murrain/M +muscat/MS +muscatel/SM +muscle/MGDS +musclebound +muscleman +musclemen +muscly +muscular/Y +muscularity/M +musculature/M +musculus +muse/MGDSJ +musette/MS +museum/MS +mush/MDRSZG +mushiness/M +mushroom/GSMD +mushy/PTR +music/SM +musical/MYS +musicale/MS +musicality/M +musician/SMY +musicianship/M +musicological +musicologist/MS +musicology/M +musing/MY +musk/M +muskeg/MS +muskellunge/MS +musket/MS +musketeer/MS +musketry/M +muskie/M +muskiness/M +muskmelon/SM +muskox/MN +muskrat/MS +musky/PTRS +muslin/M +muss/MDSG +mussel/MS +mussy/TR +must've +must/MRSZ +mustache/MDS +mustachio/SMD +mustang/MS +mustard/M +muster/GMD +mustily +mustiness/M +mustn't +musty/PTR +mutability/M +mutably +mutagen/MS +mutant/MS +mutate/XGNVDS +mutation/M +mutational +mute/MYTGDRSPB +muteness/M +mutilate/DSGNX +mutilation/M +mutilator/SM +mutineer/SM +mutinous/Y +mutiny/GDSM +mutt/MS +mutter/ZGJMDRS +mutterer/M +muttering/M +mutton/M +muttonchops/M +muttony +mutual/Y +mutuality/M +muumuu/MS +muzak +muzzily +muzzle/DSMG +muzzy/P +my +mycologist/SM +mycology/M +myelitis/M +myna/MS +mynah/MS +myocardial +myocardium +myopia/M +myopic +myopically +myriad/SM +myrmidon/MS +myrrh/M +myrtle/SM +mys +myself +mysterious/PY +mysteriousness/M +mystery/SM +mystic/SM +mystical/Y +mysticism/M +mystification/CM +mystify/CDSGN +mystique/M +myth/M +mythic +mythical +mythological +mythologist/SM +mythologize/DSG +mythology/SM +myths +myxomatosis +mtier/MS +mle/MS +n/IKTH +naan/S +nab/S +nabbed +nabbing +nabob/SM +nacelle/SM +nacho/SM +nacre/M +nacreous +nadir/SM +nae +naff/RT +nag/SM +nagged +nagger/MS +nagging +nagware +nah +naiad/SM +naif/MS +nail/MDSG +nailbrush/MS +naive/RYT +naivete/M +naivety/M +naivet/M +naked/PY +nakedness/M +name's +name/AGDS +nameable/U +named/U +namedrop +namedropping/M +nameless/Y +namely +nameplate/MS +namesake/SM +namespace/SM +nanny/SM +nano +nanobot/S +nanosecond/SM +nanotechnology/SM +nap/SM +napalm/MDSG +nape/MS +naphtha/M +naphthalene/M +napkin/MS +napless +napoleon/SM +napped +napper/MS +napping +nappy/TRSM +narc/MS +narcissism/M +narcissist/MS +narcissistic +narcissus/M +narcolepsy/M +narcoleptic +narcoses +narcosis/M +narcotic/SM +narcotization/M +narcotize/GDS +nark +narky +narrate/GNVDSX +narration/M +narrative/SM +narrator/SM +narrow/PTGMDRYS +narrowness/M +narwhal/MS +nary +nasal/SMY +nasality/M +nasalization/M +nasalize/DSG +nascence/AM +nascent/A +nastily +nastiness/M +nasturtium/SM +nasty/PTR +natal +natch +nation/MS +national/MYS +nationalism/M +nationalist/SM +nationalistic +nationalistically +nationality/SM +nationalization/MS +nationalize/CDSG +nationhood/M +nationwide +native/MYS +nativity/SM +natl +natter/GMDS +nattily +nattiness/M +natty/PTR +natural's +natural/UPY +naturalism/M +naturalist/SM +naturalistic +naturalization/M +naturalize/DSG +naturalness/UM +naturals +nature's +nature/CS +naturism +naturist/S +naught/MS +naughtily +naughtiness/M +naughty/PTR +nausea/M +nauseate/GDS +nauseating/Y +nauseous/PY +nauseousness/M +nautical/Y +nautilus/MS +naval +nave/MS +navel/SM +navigability/M +navigable +navigate/DSGN +navigation/M +navigational +navigator/MS +navvy/S +navy/SM +nay/SM +naysayer/MS +nave/RYT +navety/M +navet/M +ne'er +neanderthal/MS +neap/MS +near/DRYSPTG +nearby +nearness/M +nearshore +nearside +nearsighted/YP +nearsightedness/M +neat/NRYPXT +neaten/GD +neath +neatness/M +nebula/M +nebulae +nebular +nebulous/PY +nebulousness/M +necessarily/U +necessary/SM +necessitate/DSG +necessitous +necessity/SM +neck/MDSG +neckband/S +neckerchief/MS +necking/M +necklace/MGDSJ +neckline/MS +necktie/MS +necrology/M +necromancer/SM +necromancy/M +necrophilia +necrophiliac/S +necropolis/MS +necroses +necrosis/M +necrotic +nectar/M +nectarine/MS +nee +need/MDSG +needed/U +needful/Y +neediness/M +needle/MGDS +needlepoint/M +needless/YP +needlessness/M +needlewoman/M +needlewomen +needlework/M +needn't +needy/PTR +nefarious/YP +nefariousness/M +neg +negate/DSGNVX +negation/M +negative/MYGPDS +negativeness/M +negativism/M +negativity/M +neglect/SGMD +neglectful/YP +neglectfulness/M +negligee/MS +negligence/M +negligent/Y +negligible +negligibly +negotiability/M +negotiable/A +negotiate/ADSGN +negotiation/AM +negotiations +negotiator/MS +negritude/M +negro +negroid +neigh/MDG +neighbor/SMDYG +neighborhood/SM +neighborliness/M +neighs +neither +nelson/SM +nematode/SM +nemeses +nemesis/M +neoclassic +neoclassical +neoclassicism/M +neocolonialism/M +neocolonialist/MS +neocon/SM +neoconservative/SM +neodymium/M +neolithic +neologism/SM +neon/M +neonatal +neonate/MS +neophilia +neophyte/MS +neoplasm/MS +neoplastic +neoprene/M +nepenthe/M +nephew/SM +nephrite/M +nephritic +nephritis/M +nephropathy +nepotism/M +nepotist/SM +nepotistic +neptunium/M +nerd/MS +nerdy/RT +nerve's +nerve/UDSG +nerveless/YP +nervelessness/M +nerviness/M +nervous/YP +nervousness/M +nervy/TPR +nest/MDSG +nestle/GJDS +nestling/M +net/SM +netball +netbook/MS +nether +nethermost +netherworld/M +netiquette/S +netted +netter/S +netting/M +nettle/MGDS +nettlesome +network/SGMD +networking/M +neural/Y +neuralgia/M +neuralgic +neurasthenia/M +neurasthenic/MS +neuritic/MS +neuritis/M +neurological/Y +neurologist/SM +neurology/M +neuron/MS +neuronal +neurophysiology's +neuroscience's +neurosciences +neuroscientist/MS +neuroses +neurosis/M +neurosurgeon/MS +neurosurgery/M +neurosurgical +neurotic/MS +neurotically +neurotransmitter/SM +neut +neuter/MDGS +neutral/SMY +neutralism/M +neutralist/SM +neutrality/M +neutralization/M +neutralize/DRSZG +neutralizer/M +neutrino/SM +neutron/SM +never +nevermore +nevertheless +nevi +nevus/M +new/STMRYP +newbie/MS +newborn/SM +newcomer/SM +newel/SM +newfangled +newfound +newline/S +newlywed/SM +newness/M +news/M +newsagent/S +newsboy/SM +newscast/SMRZ +newscaster/M +newsdealer/SM +newsflash/S +newsgirl/SM +newsgroup/MS +newshound/S +newsletter/MS +newsman/M +newsmen +newspaper/MS +newspaperman/M +newspapermen +newspaperwoman/M +newspaperwomen +newspeak +newsprint/M +newsreader/S +newsreel/MS +newsroom/MS +newsstand/SM +newsweekly/SM +newswires +newswoman/M +newswomen +newsworthiness/M +newsworthy/P +newsy/TR +newt/MS +newton/MS +next/M +nexus/MS +niacin/M +nib/SM +nibble/MZGDRS +nibbler/M +nice/PYTR +niceness/M +nicety/SM +niche/SM +nick/MDRSZG +nickel/MS +nickelodeon/SM +nicker/MDG +nickle/S +nickname/DSMG +nicotine/M +niece/SM +niff +niffy +nifty/TR +nigga/SM +niggard/SMY +niggardliness/M +niggaz +nigger/SM! +niggle/MZGDRS +niggler/M +nigh/RT +night/SMY +nightcap/SM +nightclothes/M +nightclub/SM +nightclubbed +nightclubbing +nightdress/MS +nightfall/M +nightgown/SM +nighthawk/SM +nightie/M +nightingale/SM +nightlife/M +nightlight/S +nightlong +nightmare/SM +nightmarish +nightshade/SM +nightshirt/SM +nightspot/MS +nightstand/SM +nightstick/SM +nighttime/M +nightwatchman +nightwatchmen +nightwear/M +nighty/SM +nihilism/M +nihilist/MS +nihilistic +nil/M +nimbi +nimble/TPR +nimbleness/M +nimbly +nimbus/M +nimby +nimrod/MS +nincompoop/SM +nine/MS +ninepin/MS +ninepins/M +nineteen/SMH +nineteenth/M +nineteenths +ninetieth/M +ninetieths +ninety/HSM +ninja/SM +ninny/SM +ninth/M +ninths +niobium/M +nip/SM +nipped +nipper/MS +nippiness/M +nipping +nipple/MS +nippy/TPR +nirvana/M +nisei/M +nit/SMR +nite/MS +niter/M +nitpick/SZGDR +nitpicker/M +nitpicking/M +nitrate/DSMGN +nitration/M +nitrification/M +nitrite/SM +nitro +nitrocellulose/M +nitrogen/M +nitrogenous +nitroglycerin/M +nitroglycerine/M +nitwit/MS +nix/GMDS +no/SM +nob/SY +nobble/GDS +nobelium/M +nobility/M +noble/RSPMT +nobleman/M +noblemen +nobleness/M +noblewoman/M +noblewomen +nobody/SM +nocturnal/Y +nocturne/MS +nod/SM +nodal +nodded +nodding +noddle/MS +noddy +node/MS +nodular +nodule/MS +noel/MS +noes +noggin/MS +nohow +noise/DSMG +noiseless/PY +noiselessness/M +noisemaker/MS +noisily +noisiness/M +noisome +noisy/PTR +nomad/SM +nomadic +nomenclature/MS +nominal/Y +nominate/CASDXVNG +nomination/ACM +nominative/SM +nominator/CSM +nominee/MS +non +nonabrasive +nonabsorbent/SM +nonacademic +nonacceptance/M +nonacid +nonactive/MS +nonaddictive +nonadhesive +nonadjacent +nonadjustable +nonadministrative +nonage/MS +nonagenarian/MS +nonaggression/M +nonalcoholic +nonaligned +nonalignment/M +nonallergic +nonappearance/MS +nonassignable +nonathletic +nonattendance/M +nonautomotive +nonavailability/M +nonbasic +nonbeliever/MS +nonbelligerent/MS +nonbinding +nonbreakable +nonburnable +noncaloric +noncancerous +nonce/M +nonchalance/M +nonchalant/Y +nonchargeable +nonclerical/MS +nonclinical +noncollectable +noncom/MS +noncombat +noncombatant/MS +noncombustible +noncommercial/MS +noncommittal/Y +noncommunicable +noncompeting +noncompetitive +noncompliance/M +noncomplying +noncomprehending +nonconducting +nonconductor/MS +nonconforming +nonconformism +nonconformist/MS +nonconformity/M +nonconsecutive +nonconstructive +noncontagious +noncontinuous +noncontributing +noncontributory +noncontroversial +nonconvertible +noncooperation/M +noncorroding +noncorrosive +noncredit +noncriminal/SM +noncritical +noncrystalline +noncumulative +noncustodial +nondairy +nondeductible/M +nondelivery/SM +nondemocratic +nondenominational +nondepartmental +nondepreciating +nondescript +nondestructive +nondetachable +nondisciplinary +nondisclosure/M +nondiscrimination/M +nondiscriminatory +nondramatic +nondrinker/MS +nondrying +none +noneducational +noneffective +nonelastic +nonelectric +nonelectrical +nonempty +nonenforceable +nonentity/SM +nonequivalent/MS +nonessential +nonesuch/MS +nonetheless +nonevent/MS +nonexchangeable +nonexclusive +nonexempt/M +nonexistence/M +nonexistent +nonexplosive/MS +nonfactual +nonfading +nonfat +nonfatal +nonfattening +nonferrous +nonfiction/M +nonfictional +nonflammable +nonflowering +nonfluctuating +nonflying +nonfood/M +nonfreezing +nonfunctional +nongovernmental +nongranular +nonhazardous +nonhereditary +nonhuman +nonidentical +noninclusive +nonindependent +nonindustrial +noninfectious +noninflammatory +noninflationary +noninflected +nonintellectual/MS +noninterchangeable +noninterference/M +nonintervention/M +nonintoxicating +noninvasive +nonirritating +nonissue +nonjudgmental +nonjudicial +nonlegal +nonlethal +nonlinear +nonliterary +nonliving/M +nonmagnetic +nonmalignant +nonmember/MS +nonmetal/SM +nonmetallic +nonmigratory +nonmilitant +nonmilitary +nonnarcotic/SM +nonnative/MS +nonnegotiable +nonnuclear +nonnumerical +nonobjective +nonobligatory +nonobservance/M +nonobservant +nonoccupational +nonoccurence +nonofficial +nonoperational +nonoperative +nonparallel/MS +nonpareil/MS +nonparticipant/MS +nonparticipating +nonpartisan/SM +nonpaying +nonpayment/SM +nonperformance/M +nonperforming +nonperishable +nonperson/MS +nonphysical/Y +nonplus/S +nonplussed +nonplussing +nonpoisonous +nonpolitical +nonpolluting +nonporous +nonpracticing +nonprejudicial +nonprescription +nonproductive +nonprofessional/SM +nonprofit/SMB +nonproliferation/M +nonpublic +nonpunishable +nonracial +nonradioactive +nonrandom +nonreactive +nonreciprocal/SM +nonreciprocating +nonrecognition/M +nonrecoverable +nonrecurring +nonredeemable +nonrefillable +nonrefundable +nonreligious +nonrenewable +nonrepresentational +nonresident/MS +nonresidential +nonresidual/M +nonresistance/M +nonresistant +nonrestrictive +nonreturnable/MS +nonrhythmic +nonrigid +nonsalaried +nonscheduled +nonscientific +nonscoring +nonseasonal +nonsectarian +nonsecular +nonsegregated +nonsense/M +nonsensical/Y +nonsensitive +nonsexist +nonsexual +nonskid +nonslip +nonsmoker/SM +nonsmoking +nonsocial +nonspeaking +nonspecialist/MS +nonspecializing +nonspecific +nonspiritual/SM +nonstaining +nonstandard +nonstarter/MS +nonstick +nonstop +nonstrategic +nonstriking +nonstructural +nonsuccessive +nonsupport/GM +nonsurgical +nonsustaining +nonsympathizer/M +nontarnishable +nontaxable +nontechnical +nontenured +nontheatrical +nonthinking +nonthreatening +nontoxic +nontraditional +nontransferable +nontransparent +nontrivial +nontropical +nonuniform +nonunion +nonuser/MS +nonvenomous +nonverbal +nonviable +nonviolence/M +nonviolent/Y +nonvirulent +nonvocal +nonvocational +nonvolatile +nonvoter/MS +nonvoting +nonwhite/MS +nonworking +nonyielding +nonzero +noodle/MGDS +nook/MS +nookie +nooky +noon/M +noonday/M +noontide/M +noontime/M +noose/SM +nope +nor +nor'easter +norm/MS +normal/MY +normalcy/M +normality/M +normalization/M +normalize/DSG +normative +north/ZMR +northbound +northeast/MRZ +northeaster/MY +northeastern +northeastward/S +norther/MY +northerly/SM +northern/ZR +northerner/M +northernmost +northward/S +northwest/ZMR +northwester/MY +northwestern +northwestward/S +nose/MGDS +nosebag/S +nosebleed/MS +nosecone/SM +nosedive/DSMG +nosegay/SM +nosh/MDRSZG +nosher/M +nosily +nosiness/M +nostalgia/M +nostalgic +nostalgically +nostril/MS +nostrum/MS +nosy/RPT +not/B +notability/SM +notable/SM +notably +notarial +notarization/M +notarize/GDS +notary/SM +notate/GDS +notation/FCSM +notch/GMDS +note's +note/FCSDG +notebook/MS +notelet/S +notepad/S +notepaper/M +noteworthiness/M +noteworthy/P +nothing/PSM +nothingness/M +notice/MGDS +noticeable/U +noticeably +noticeboard/S +noticed/U +notifiable +notification/M +notifier/M +notify/NDRSXZG +notion/MS +notional/Y +notoriety/M +notorious/Y +notwithstanding +notwork/S +nougat/MS +nought/MS +noun/KMS +nourish/DSLG +nourishment/M +nous +nova/MS +novae +novel/SM +novelette/SM +novelist/SM +novelization/MS +novelize/DSG +novella/MS +novelty/SM +novena/MS +novene +novice/MS +novitiate/MS +now/M +nowadays/M +noway/S +nowhere/M +nowise +nowt +noxious +nozzle/MS +nu/SM +nuance/MDS +nub/SM +nubbin/MS +nubby/TR +nubile +nuclear/K +nucleate/DSGN +nucleation/M +nuclei +nucleic +nucleoli +nucleolus/M +nucleon/SM +nucleoside +nucleotide +nucleus/M +nude/MTRS +nudge/GDSM +nudism/M +nudist/SM +nudity/M +nugatory +nugget/SM +nuisance/MS +nuke/MGDS +null/S +nullification/M +nullify/NDSG +nullity/M +numb/ZTGPDRYS +number's +number/ASDG +numbered/U +numberless +numbness/M +numbskull/SM +numerable/I +numeracy/IM +numeral/SM +numerate/XGNDS +numeration/M +numerator/MS +numeric +numerical/Y +numerologist/MS +numerology/M +numerous/Y +numinous +numismatic/S +numismatics/M +numismatist/SM +numskull/MS +nun/SM +nuncio/SM +nunnery/SM +nuptial/MS +nurse/MZGDRS +nurselings +nursemaid/MS +nurser/M +nursery/SM +nurseryman/M +nurserymen +nursing/M +nursling/SM +nurture/DRSMZG +nurturer/M +nut/SM +nutcase/S +nutcracker/MS +nuthatch/MS +nuthouse/S +nutmeat/SM +nutmeg/SM +nutpick/SM +nutria/SM +nutrient/MS +nutriment/MS +nutrition/M +nutritional/Y +nutritionist/SM +nutritious/YP +nutritiousness/M +nutritive +nutshell/MS +nutted +nutter/S +nuttiness/M +nutting +nutty/RTP +nuzzle/DRSMZG +nuzzler/M +nybble/S +nylon/MS +nylons/M +nymph/M +nymphet/MS +nympho/S +nymphomania/M +nymphomaniac/SM +nymphs +ne +o +o'clock +o'er +oaf/SM +oafish/PY +oafishness/M +oak/SMN +oakum/M +oar/SGMD +oarlock/SM +oarsman/M +oarsmen +oarswoman/M +oarswomen +oases +oasis/M +oat/SMN +oatcake/SM +oath/M +oaths +oatmeal/M +oats/M +ob/S +obbligato/MS +obduracy/M +obdurate/PY +obdurateness/M +obedience/EM +obedient/EY +obeisance/SM +obeisant +obelisk/MS +obese +obesity/M +obey/EDSG +obfuscate/GNXDS +obfuscation/M +obi/SM +obit/MS +obituary/SM +obj +object/SGVMD +objectify/NGDS +objection/SMB +objectionable/U +objectionably +objective/SMYP +objectiveness/M +objectivity/M +objector/MS +objurgate/XGNDS +objurgation/M +oblate/NX +oblation/M +obligate/DSXGN +obligation/M +obligatorily +obligatory +oblige/EGDS +obliging/Y +oblique/SMYP +obliqueness/M +obliquity/M +obliterate/DSGN +obliteration/M +oblivion/M +oblivious/YP +obliviousness/M +oblong/MS +obloquy/M +obnoxious/YP +obnoxiousness/M +oboe/MS +oboist/MS +obscene/RYT +obscenity/SM +obscurantism/M +obscurantist/SM +obscure/DRSYTG +obscurity/SM +obsequies +obsequious/PY +obsequiousness/M +obsequy/M +observably +observance/MS +observant/Y +observation/SM +observational +observatory/SM +observe/DRSBZG +observed/U +observer/M +obsess/DSGV +obsession/SM +obsessional/Y +obsessive/PSMY +obsessiveness/M +obsidian/M +obsolesce/DSG +obsolescence/M +obsolescent +obsolete/GDS +obstacle/MS +obstetric/S +obstetrical +obstetrician/SM +obstetrics/M +obstinacy/M +obstinate/Y +obstreperous/YP +obstreperousness/M +obstruct/DGVS +obstructed/U +obstruction/SM +obstructionism/M +obstructionist/MS +obstructive/YP +obstructiveness/M +obtain/DBLGS +obtainable/U +obtainment/M +obtrude/DSG +obtrusion/M +obtrusive/UPY +obtrusiveness/UM +obtuse/YTRP +obtuseness/M +obverse/SM +obviate/DSGN +obviation/M +obvious/PY +obviousness/M +ocarina/MS +occasion/GMDS +occasional/Y +occidental/SM +occlude/GDS +occlusion/SM +occlusive +occult/M +occultism/M +occultist/SM +occupancy/M +occupant/SM +occupation/AM +occupational/Y +occupations +occupied/U +occupier/SM +occupy/ADSG +occur/AS +occurred/A +occurrence/SM +occurring/A +ocean/SM +oceanfront/SM +oceangoing +oceanic/M +oceanographer/SM +oceanographic +oceanography/M +oceanology/M +ocelot/MS +och/R +ocher/M +ocker/S +octagon/MS +octagonal +octal +octane/MS +octave/MS +octavo/MS +octet/SM +octogenarian/SM +octopi +octopus/MS +ocular/MS +oculist/SM +odalisque/SM +odd/STRYLP +oddball/SM +oddity/SM +oddment/SM +oddness/M +odds/M +ode/SM +odious/YP +odiousness/M +odium/M +odometer/MS +odor/MDS +odoriferous +odorless +odorous +odyssey/MS +oedipal +oenology/M +oenophile/SM +oeuvre/MS +of +off/SZGDRJ +offal/M +offbeat/MS +offend/ZGDRS +offender/M +offense/MS +offensive's +offensive/IPY +offensiveness/IM +offensives +offer/JGMD +offering/M +offertory/SM +offhand +offhanded/PY +offhandedness/M +office/MZRS +officeholder/SM +officer/M +official/MYS +officialdom/M +officialese +officialism/M +officiant/SM +officiate/DSG +officiator/MS +officious/PY +officiousness/M +offing/M +offish +offline +offload/SDG +offprint/SM +offset/MS +offsetting +offshoot/MS +offshore/G +offside +offsite +offspring/M +offstage/S +offtrack +oft +often/TR +oftentimes +ofttimes +ogle/MZGDRS +ogler/M +ogre/MS +ogreish +ogress/MS +oh/M +ohm/SM +ohmmeter/MS +oho +ohs +oi +oik/S +oil/SGMD +oilcan/S +oilcloth/M +oilcloths +oilfield/S +oiliness/M +oilman +oilmen +oilskin/MS +oilskins/M +oily/RPT +oink/MDSG +ointment/SM +okapi/SM +okay/MDSG +okra/MS +old/TMNRP +oldie/SM +oldish +oldness/M +oldster/MS +ole/SMV +oleaginous +oleander/MS +oleo/M +oleomargarine/M +olfactory/SM +oligarch/M +oligarchic +oligarchical +oligarchs +oligarchy/SM +oligo +oligonucleotide/S +oligopoly/SM +olive/SM +ol/M +om/SMNX +ombudsman/M +ombudsmen +omega/SM +omelet/MS +omelette/MS +omen/M +omicron/MS +ominous/YP +ominousness/M +omission/MS +omit/S +omitted +omitting +omnibus/MS +omnipotence/M +omnipotent +omnipresence/M +omnipresent +omniscience/M +omniscient +omnivore/MS +omnivorous/PY +omnivorousness/M +on/Y +once/M +oncogene/SM +oncologist/SM +oncology/M +oncoming +one/SXMNP +oneness/M +onerous/PY +onerousness/M +oneself +onetime +ongoing +onion/M +onionskin/M +online +onlooker/SM +onlooking +onomatopoeia/M +onomatopoeic +onomatopoetic +onrush/MSG +onscreen +onset/MS +onshore +onside +onsite +onslaught/MS +onstage +onto +ontogeny/M +ontological +ontology/M +onus/MS +onward +onyx/MS +oodles/M +ooh/GD +oohs +oomph +oops +ooze/MGDS +oozy/TR +op/SMDG +opacity/M +opal/MS +opalescence/M +opalescent +opaque/PYTGDRS +opaqueness/M +opcode/S +ope/S +open/ZTGJPMDRYS +opencast +opened/U +opener/M +openhanded/P +openhandedness/M +openhearted +opening/M +openness/M +openwork/M +opera/MS +operable/I +operand/S +operate/DSGNVX +operatic +operatically +operation/M +operational/Y +operative/SM +operator/SM +operetta/SM +ophthalmic +ophthalmologist/SM +ophthalmology/M +opiate/SM +opine/GNXDS +opinion/M +opinionated +opium/M +opossum/MS +opp +opponent/SM +opportune/IY +opportunism/M +opportunist/SM +opportunistic +opportunistically +opportunity/SM +oppose/DRSBG +opposed/U +opposite/SMYNX +opposition/M +oppress/DSGV +oppression/M +oppressive/YP +oppressiveness/M +oppressor/MS +opprobrious/Y +opprobrium/M +opt/SGD +optic/MS +optical/Y +optician/SM +optics/M +optima +optimal/Y +optimism/SM +optimist/SM +optimistic +optimistically +optimization/MS +optimize/DRSG +optimum/SM +option/SMDG +optional/Y +optometrist/MS +optometry/M +opulence/M +opulent/Y +opus/MS +or +oracle/SM +oracular +oral/MYS +orange/SMP +orangeade/MS +orangery/SM +orangutan/SM +orate/GNXDS +oration/M +orator/SM +oratorical/Y +oratorio/MS +oratory/SM +orb/SM +orbicular +orbit/MDRZGS +orbital/SM +orbiter/M +orc/SM +orchard/SM +orchestra/MS +orchestral +orchestrate/DSXGN +orchestration/M +orchid/SM +ordain/SDLG +ordainment/M +ordeal/SM +order/EAMDGS +orderings +orderliness/EM +orderly/PSM +ordinal/SM +ordinance/SM +ordinarily +ordinariness/M +ordinary/SMP +ordinate/MNSX +ordination/M +ordnance/M +ordure/M +ore/SM +oregano/M +org +organ/MS +organdy/M +organelle/MS +organic/SM +organically/I +organism/MS +organismic +organist/MS +organization/ASM +organizational/Y +organize/AESDG +organized/U +organizer/MS +organza/M +orgasm/SM +orgasmic +orgiastic +orgy/SM +oriel/MS +orient's +orient/AEDGS +oriental/MS +orientalist/S +orientate/EDSGN +orientation/AEM +orientations +orienteering +orifice/MS +orig +origami/M +origin/SM +original/MYS +originality/M +originate/DSGN +origination/M +originator/SM +oriole/SM +orison/SM +ormolu/M +ornament/SGMD +ornamental +ornamentation/M +ornate/YP +ornateness/M +orneriness/M +ornery/PRT +ornithological +ornithologist/MS +ornithology/M +orotund +orotundity/SM +orphan/SMDG +orphanage/MS +orris/MS +orthodontia/M +orthodontic/S +orthodontics/M +orthodontist/SM +orthodox/U +orthodoxy/SM +orthogonal +orthogonality +orthographic +orthographically +orthography/SM +orthopedic/S +orthopedics/M +orthopedist/MS +orzo/M +oscillate/GNDSX +oscillation/M +oscillator/SM +oscillatory +oscilloscope/MS +osculate/DSXGN +osculation/M +osier/MS +osmium/M +osmosis/M +osmotic +osprey/SM +ossification/M +ossify/NGDS +ostensible +ostensibly +ostentation/M +ostentatious/Y +osteoarthritis/M +osteopath/M +osteopathic +osteopaths +osteopathy/M +osteoporosis/M +ostler/S +ostracism/M +ostracize/GDS +ostrich/MS +other/MSP +otherwise +otherworldly +otiose +otter/MS +ottoman/MS +oubliette/MS +ouch +ought +oughtn't +ounce/MS +our/S +ourselves +oust/ZGDRS +ouster/M +out/SJGMDR +outage/SM +outargue/GDS +outback/MS +outbalance/DSG +outbid/S +outbidding +outboard/MS +outboast/DSG +outbound +outbox/MS +outbreak/MS +outbuilding/MS +outburst/SM +outcast/MS +outclass/DSG +outcome/MS +outcrop/MS +outcropped +outcropping/SM +outcry/SM +outdated +outdid +outdistance/GDS +outdo/G +outdoes +outdone +outdoor/S +outdoors/M +outdoorsy +outdraw/GS +outdrawn +outdrew +outermost +outerwear/M +outface/GDS +outfall/S +outfield/SMRZ +outfielder/M +outfight/SG +outfit/SM +outfitted +outfitter/MS +outfitting +outflank/GSD +outflow/MS +outfought +outfox/GDS +outgo/MJG +outgoes +outgrew +outgrow/HGS +outgrown +outgrowth/M +outgrowths +outguess/GDS +outgun/S +outgunned +outgunning +outhit/S +outhitting +outhouse/SM +outing/M +outlaid +outlandish/PY +outlandishness/M +outlast/DSG +outlaw/SGMD +outlay/SGM +outlet/SM +outlier/MS +outline/MGDS +outlive/GDS +outlook/MS +outlying +outmaneuver/GDS +outmatch/GDS +outmoded +outnumber/DSG +outpace/GDS +outpatient/MS +outperform/GSD +outplace/L +outplacement/M +outplay/GDS +outpoint/DGS +outpost/MS +outpouring/MS +outproduce/DSG +output/SM +outputted +outputting +outrace/GDS +outrage/MGDS +outrageous/Y +outran +outrank/GDS +outre +outreach/MDSG +outrider/MS +outrigger/SM +outright +outrun/S +outrunning +outr +outscore/GDS +outsell/GS +outset/SM +outshine/GS +outshone +outshout/GDS +outside/MZRS +outsider/M +outsize/MS +outskirt/MS +outsmart/GDS +outsold +outsource/DSG +outsourcing/M +outspend/SG +outspent +outspoken/YP +outspokenness/M +outspread/GS +outstanding/Y +outstation/MS +outstay/DGS +outstretch/DSG +outstrip/S +outstripped +outstripping +outta +outtake/MS +outvote/GDS +outward/YS +outwear/GS +outweigh/GD +outweighs +outwit/S +outwith +outwitted +outwitting +outwore +outwork/MDRSZG +outworn +ouzo/MS +ova +oval/MS +ovarian +ovary/SM +ovate/NX +ovation/M +oven/MS +ovenbird/SM +ovenproof +ovenware +over/MYS +overabundance/M +overabundant +overachieve/ZGDRS +overachiever/M +overact/GVSD +overage/SM +overaggressive +overall/SM +overalls/M +overambitious +overanxious +overarching +overarm/GSD +overate +overattentive +overawe/DSG +overbalance/MGDS +overbear/GS +overbearing/Y +overbid/SM +overbidding +overbite/MS +overblown +overboard +overbold +overbook/DGS +overbore +overborne +overbought +overbuild/SG +overbuilt +overburden/GSD +overbuy/GS +overcame +overcapacity/M +overcapitalize/DSG +overcareful +overcast/MGS +overcautious +overcharge/DSMG +overclock/GD +overcloud/SGD +overcoat/MS +overcome/GS +overcompensate/DSGN +overcompensation/M +overconfidence/M +overconfident +overconscientious +overcook/DGS +overcritical +overcrowd/SDG +overcrowding/M +overdecorate/DSG +overdependent +overdevelop/SDG +overdid +overdo/G +overdoes +overdone +overdose/MGDS +overdraft/SM +overdraw/GS +overdrawn +overdress/GMDS +overdrew +overdrive/SM +overdub/SM +overdubbed +overdubbing +overdue +overeager +overeat/GSN +overemotional +overemphasis/M +overemphasize/GDS +overenthusiastic +overestimate/MGNDS +overestimation/M +overexcite/DSG +overexercise/GDS +overexert/SDG +overexertion/M +overexpose/GDS +overexposure/M +overextend/DGS +overfed +overfeed/GS +overfill/DGS +overflew +overflight/MS +overflow/MDSG +overflown +overfly/GS +overfond +overfull +overgeneralize/DSG +overgenerous +overgraze/DSG +overgrew +overground +overgrow/HSG +overgrown +overgrowth/M +overhand/MDS +overhang/MSG +overhasty +overhaul/MDSG +overhead/MS +overhear/SG +overheard +overheat/DSG +overhung +overindulge/GDS +overindulgence/M +overindulgent +overjoy/GSD +overkill/M +overladen +overlaid +overlain +overland +overlap/SM +overlapped +overlapping +overlarge +overlay/GSM +overleaf +overlie +overload/GMDS +overlong +overlook/GMDS +overlord/MS +overly/SG +overmanned +overmanning +overmaster/SDG +overmodest +overmuch/S +overnice +overnight/MS +overoptimism/M +overoptimistic +overpaid +overparticular +overpass/MS +overpay/GS +overplay/GDS +overpopulate/GNDS +overpopulation/M +overpower/SDG +overpowering/Y +overpraise/DSG +overprecise +overprice/DSG +overprint/SMDG +overproduce/GDS +overproduction/M +overprotect/SDGV +overqualified +overran +overrate/GDS +overreach/GDS +overreact/SDG +overreaction/SM +overrefined +overridden +override/MGS +overripe/M +overrode +overrule/GDS +overrun/SM +overrunning +oversampling +oversaw +oversea/S +oversee/RSZ +overseeing +overseen +overseer/M +oversell/GS +oversensitive/P +oversensitiveness/M +oversexed +overshadow/DSG +overshare/DSG +overshoe/MS +overshoot/GS +overshot +oversight/SM +oversimple +oversimplification/M +oversimplify/DSNGX +oversize/D +oversleep/GS +overslept +oversold +overspecialization/M +overspecialize/GDS +overspend/SG +overspent +overspread/GS +overstaffed +overstate/DSLG +overstatement/MS +overstay/DSG +overstep/S +overstepped +overstepping +overstimulate/DSG +overstock/GSD +overstretch/GDS +overstrict +overstrung +overstuffed +oversubscribe/DSG +oversubtle +oversupply/GDS +oversuspicious +overt/Y +overtake/GS +overtaken +overtax/GDS +overthink/SG +overthought +overthrew +overthrow/SMG +overthrown +overtime/MS +overtire/GDS +overtone/MS +overtook +overture/MS +overturn/DSG +overuse/DSMG +overvaluation/S +overvalue/DSG +overview/MS +overweening/Y +overweight/M +overwhelm/SGD +overwhelming/Y +overwinter/SDG +overwork/GMDS +overwrite/GS +overwritten +overwrote +overwrought +overzealous +oviduct/SM +oviparous +ovoid/MS +ovular +ovulate/DSGN +ovulation/M +ovule/MS +ovum/M +ow +owe/DSG +owl/SM +owlet/MS +owlish/Y +own/ESGD +owner/MS +ownership/M +ox/MN +oxblood/M +oxbow/MS +oxcart/SM +oxford/SM +oxidant/MS +oxidase +oxidation/M +oxide/MS +oxidization/M +oxidize/ZGDRS +oxidizer/M +oxtail/S +oxyacetylene/M +oxygen/M +oxygenate/DSGN +oxygenation/M +oxymora +oxymoron/M +oyster/SM +oz +ozone/M +p/NRXTGJ +pH +pa/SMH +pablum/M +pabulum/M +pace/MZGDRS +pacemaker/SM +pacer/M +pacesetter/SM +pacey +pachyderm/MS +pachysandra/MS +pacific +pacifically +pacification/M +pacifier/M +pacifism/M +pacifist/SM +pacifistic +pacify/ZGDRSN +pack's +pack/AUGSD +package's +package/AGDS +packager/SM +packaging/M +packer/MS +packet/MS +packing's +packinghouse/SM +packsaddle/MS +pact/MS +pacy/RT +pad/SM +padded +padding/M +paddle/MZGDRS +paddler/M +paddock/MDGS +paddy/SM +padlock/MDSG +padre/SM +paean/SM +paella/MS +pagan/SM +paganism/M +page/MZGDRS +pageant/MS +pageantry/M +pageboy/SM +pager/M +paginate/DSGN +pagination/M +pagoda/MS +pah +paid/AU +pail/MS +pailful/SM +pain/MDSG +painful/PY +painfuller +painfullest +painfulness/M +painkiller/MS +painkilling +painless/PY +painlessness/M +painstaking/MY +paint/SZGJMDR +paintball +paintbox/MS +paintbrush/MS +painted/U +painter/MY +painting/M +paintwork +pair/AMDSG +paired/U +pairing/S +pairwise +paisley/SM +pajama/S +pajamas/M +pal/SMY +palace/MS +paladin/SM +palanquin/SM +palatable/U +palatal/SM +palatalization/M +palatalize/GDS +palate/MBS +palatial/Y +palatinate/MS +palatine/MS +palaver/GSMD +palazzi +palazzo +pale/MYTGPDRSJ +paleface/MS +paleness/M +paleographer/MS +paleography/M +paleolithic +paleontologist/SM +paleontology/M +palette/SM +palfrey/SM +palimony/M +palimpsest/MS +palindrome/MS +palindromic +paling/M +palisade/SM +palish +pall/MDSG +palladium/M +pallbearer/MS +pallet/MS +palliate/DSGNV +palliation/M +palliative/SM +pallid/YP +pallidness/M +pallor/M +palm/MDSG +palmate +palmetto/SM +palmist/SM +palmistry/M +palmtop/SM +palmy/TR +palomino/MS +palpable +palpably +palpate/DSGN +palpation/M +palpitate/XGNDS +palpitation/M +palsy/GDSM +paltriness/M +paltry/RPT +pampas/M +pamper/DSG +pamphlet/MS +pamphleteer/MS +pan/SM +panacea/SM +panache/M +panama/MS +panatella/S +pancake/DSMG +panchromatic +pancreas/MS +pancreatic +pancreatitis +panda/SM +pandemic/SM +pandemonium/M +pander/MDRZGS +panderer/M +pane/KM +panegyric/SM +panel/SGJMD +paneling/M +panelist/MS +panes +pang/MS +panhandle/DRSMZG +panhandler/M +panic/SM +panicked +panicking +panicky +panned +pannier/SM +panning +panoply/SM +panorama/SM +panoramic +panpipes/M +pansy/SM +pant/MDSG +pantaloons/M +pantechnicon/S +pantheism/M +pantheist/SM +pantheistic +pantheon/SM +panther/MS +pantie/M +panto/S +pantomime/MGDS +pantomimic +pantomimist/SM +pantry/SM +pantsuit/SM +panty/SM +pantyhose/M +pantyliner/M +pantywaist/SM +pap/SM +papa/MS +papacy/SM +papal +paparazzi/M +paparazzo +papaw/SM +papaya/MS +paper/SZGMDR +paperback/SM +paperbark/S +paperboard/M +paperboy/SM +paperclip/S +paperer/M +papergirl/SM +paperhanger/SM +paperhanging/M +paperless +paperweight/MS +paperwork/M +papery +papilla/M +papillae +papillary +papist/MS +papoose/MS +pappy/SM +paprika/M +papyri +papyrus/M +par/SZGMDRBJ +para/MS +parable/MS +parabola/SM +parabolic +paracetamol/S +parachute/DSMG +parachutist/MS +parade/MZGDRS +parader/M +paradigm/SM +paradigmatic +paradisaical +paradise/SM +paradox/MS +paradoxical/Y +paraffin/M +paragliding +paragon/MS +paragraph/GMD +paragraphs +parakeet/SM +paralegal/MS +parallax/MS +parallel/SGMD +paralleled/U +parallelism/MS +parallelization/MS +parallelize/GDS +parallelogram/SM +paralyses +paralysis/M +paralytic/SM +paralyze/DSG +paralyzing/Y +paramecia +paramecium/M +paramedic/MS +paramedical/MS +parameter/MS +parametric +paramilitary/SM +paramount +paramountcy +paramour/SM +paranoia/M +paranoiac/MS +paranoid/SM +paranormal +parapet/MS +paraphernalia/M +paraphrase/DSMG +paraplegia/M +paraplegic/SM +paraprofessional/MS +parapsychologist/MS +parapsychology/M +paraquat/M +parasailing +parascending +parasite/SM +parasitic +parasitical/Y +parasitism/M +parasol/MS +parasympathetic/S +parathion/M +parathyroid/MS +paratroop/RZS +paratrooper/M +paratroops/M +paratyphoid/M +parboil/DSG +parcel/GMDS +parch/LGDS +parchment/SM +pardner/S +pardon/ZGMDRBS +pardonable/U +pardonably/U +pardoner/M +pare/S +paregoric/M +parent/GMDS +parentage/M +parental +parentheses +parenthesis/M +parenthesize/DSG +parenthetic +parenthetical/Y +parenthood/M +parenting/M +parer/M +pares/S +paresis/M +parfait/MS +pariah/M +pariahs +parietal +parimutuel/MS +paring/M +parish/MS +parishioner/MS +parity/ESM +park/MDSG +parka/SM +parking/M +parkland +parkour +parkway/MS +parky +parlance/M +parlay/GMDS +parley/GMDS +parliament/SM +parliamentarian/SM +parliamentary +parlor/MS +parlous +parmigiana +parmigiano +parochial/Y +parochialism/M +parodist/SM +parody/GDSM +parole/MGDS +parolee/MS +parotid +paroxysm/SM +paroxysmal +parquet/MDSG +parquetry/M +parred +parricidal +parricide/MS +parring +parrot/GMDS +parry/GDSM +parse/DRSG +parsec/MS +parsimonious/Y +parsimony/M +parsley/M +parsnip/MS +parson/MS +parsonage/MS +part's +part/CDSG +partake/ZGRS +partaken +partaker/M +parterre/SM +parthenogenesis/M +partial/MYS +partiality/M +participant/SM +participate/DSGN +participation/M +participator/MS +participatory +participial/M +participle/MS +particle/SM +particleboard/M +particular/SMY +particularity/SM +particularization/M +particularize/DSG +particulate/SM +parting/MS +partisan/SM +partisanship/M +partition/GMDS +partitions/A +partitive/MS +partizan/SM +partly +partner/MDSG +partnership/MS +partook +partridge/SM +parturition/M +partway +party/GDSM +parvenu/MS +pascal/MS +paschal +pasha/SM +pass/M +passably +passage/MS +passageway/MS +passbook/MS +passe/DRSBXZGNV +passel/MS +passenger/SM +passer/M +passerby/M +passersby +passim +passing/MY +passion/EM +passionate/EY +passionflower/SM +passionless +passive/PMYS +passiveness/M +passivity/M +passivization +passivize/DSG +passkey/MS +passphrase/S +passport/MS +password/MS +pass +past/AMS +pasta/SM +paste/DSMG +pasteboard/M +pastel/MS +pastern/MS +pasteurization/M +pasteurize/ZGDRS +pasteurized/U +pasteurizer/M +pastiche/MS +pastie +pastille/MS +pastime/MS +pastiness/M +pastor/MS +pastoral/MS +pastorate/MS +pastrami/M +pastry/SM +pasturage/M +pasture/DSMG +pastureland/M +pasty/PTRSM +pat/SM +patch/EGMDS +patchily +patchiness/M +patchouli +patchwork/SM +patchy/TPR +pate/MS +patella/MS +patellae +patent/GMDYS +paterfamilias/MS +paternal/Y +paternalism/M +paternalist/S +paternalistic +paternity/M +paternoster/MS +path/M +pathetic +pathetically +pathfinder/SM +pathless +pathogen/SM +pathogenic +pathological/Y +pathologist/SM +pathology/M +pathos/M +paths +pathway/MS +patience/M +patient/IMST +patienter +patiently +patina/MS +patine +patio/SM +patisserie/S +patois/M +patresfamilias +patriarch/M +patriarchal +patriarchate/MS +patriarchs +patriarchy/SM +patrician/SM +patricide/SM +patrimonial +patrimony/SM +patriot/SM +patriotic/U +patriotically +patriotism/M +patrol/MS +patrolled +patrolling +patrolman/M +patrolmen +patrolwoman/M +patrolwomen +patron/MS +patronage/MS +patroness/MS +patronize/ZGDRS +patronizer/M +patronizing/Y +patronymic/SM +patronymically +patroon/SM +patsy/SM +patted +patter/MDGS +pattern/SMDG +patting +patty/SM +paucity/M +paunch/MS +paunchy/RT +pauper/MS +pauperism/M +pauperize/DSG +pause/DSMG +pave/AGDS +paved/U +pavement/MS +pavilion/SM +paving/MS +pavlova/S +paw/SGMD +pawl/MS +pawn/MDSG +pawnbroker/MS +pawnbroking/M +pawnshop/MS +pawpaw/MS +pay's +pay/ASGBL +payback/SM +paycheck/MS +payday/MS +payed +payee/SM +payer/SM +payload/SM +paymaster/SM +payment/ASM +payoff/MS +payola/M +payout/MS +payphone/S +payroll/SM +payslip/SM +paywall/SM +payware +pct +pd +pea/SM +peace/SM +peaceable +peaceably +peaceful/PY +peacefulness/M +peacekeeper/SM +peacekeeping/M +peacemaker/MS +peacemaking/M +peacetime/M +peach/MS +peachy/TR +peacock/MS +peafowl/MS +peahen/MS +peak/MDSG +peaky +peal/AMDSG +peanut/MS +pear/MYS +pearl/SGMD +pearly/RT +peasant/SM +peasantry/M +peashooter/SM +peat/M +peaty/TR +pebble/MGDS +pebbly +pecan/SM +peccadillo/M +peccadilloes +peccary/SM +peck/MDRSZG +peckish +pecs +pectic +pectin/M +pectoral/MS +peculate/GNDS +peculation/M +peculator/SM +peculiar/Y +peculiarity/SM +pecuniary +pedagogic +pedagogical/Y +pedagogue/SM +pedagogy/M +pedal/SGMD +pedalo/S +pedant/MS +pedantic +pedantically +pedantry/M +peddle/ZGDRS +peddler/M +pederast/MS +pederasty/M +pedestal/MS +pedestrian/SM +pedestrianization +pedestrianize/GDS +pediatric/S +pediatrician/MS +pediatrics/M +pedicab/SM +pedicure/MGDS +pedicurist/MS +pedigree/MDS +pediment/MS +pedometer/MS +pedophile/S +pedophilia +peduncle/MS +pee/DRSMZ +peeing +peek/MDSG +peekaboo/M +peel/MDRSJZG +peeled/U +peeler/M +peeling/M +peen/MS +peep/MDRSZG +peepbo +peeper/M +peephole/MS +peepshow/MS +peer/MDG +peerage/SM +peeress/MS +peerless +peeve/DSMG +peevish/PY +peevishness/M +peewee/MS +peewit/S +peg/SM +pegboard/MS +pegged +pegging +peignoir/SM +pejoration/M +pejorative/SMY +peke/MS +pekinese/SM +pekingese/SM +pekoe/M +pelagic +pelf/M +pelican/MS +pellagra/M +pellet/GMDS +pellucid +pelmet/S +pelt/MDSG +pelvic +pelvis/MS +pemmican/M +pen/M +penal +penalization/M +penalize/DSG +penalty/SM +penance/MS +pence +penchant/SM +pencil/GMDJS +pend/CDSG +pendant/MS +pendent/MS +pendulous +pendulum/MS +penetrability/M +penetrable +penetrate/DSGNVX +penetrating/Y +penetration/M +penfriend/S +penguin/MS +penicillin/M +penile +peninsula/SM +peninsular +penis/MS +penitence/M +penitent/SMY +penitential +penitentiary/SM +penknife/M +penknives +penlight/SM +penman/M +penmanship/M +penmen +pennant/MS +penned +penniless +penning +pennon/MS +penny/SM +pennyweight/MS +pennyworth +penologist/MS +penology/M +pension/BZGMDRS +pensioner/M +pensive/PY +pensiveness/M +pent +pentacle/MS +pentagon/MS +pentagonal +pentagram/SM +pentameter/SM +pentathlete/MS +pentathlon/MS +penthouse/SM +penuche/M +penultimate/SM +penumbra/MS +penumbrae +penurious/PY +penuriousness/M +penury/M +peon/MS +peonage/M +peony/SM +people/MGDS +pep/SM +pepped +pepper/GMDS +peppercorn/SM +peppermint/SM +pepperoni/MS +peppery +peppiness/M +pepping +peppy/TPR +pepsin/M +peptic/MS +peptide/S +peradventure/M +perambulate/XGNDS +perambulation/M +perambulator/MS +percale/MS +perceive/BGDS +perceived/U +percent/MS +percentage/SM +percentile/SM +perceptible +perceptibly +perception/SM +perceptional +perceptive/PY +perceptiveness/M +perceptual/Y +perch/GMDS +perchance +percipience/M +percipient +percolate/GNDS +percolation/M +percolator/SM +percussion/AM +percussionist/MS +percussive +perdition/M +perdurable +peregrinate/DSXGN +peregrination/M +peregrine/MS +peremptorily +peremptory +perennial/SMY +perestroika/M +perfect/PTGMDRYS +perfecta/MS +perfectibility/M +perfectible +perfection/SM +perfectionism/M +perfectionist/SM +perfectness/M +perfidious/Y +perfidy/SM +perforate/GNXDS +perforation/M +perforce +perform/SDRZG +performance/SM +performative +performed/U +performer/M +perfume/DRSMZG +perfumer/M +perfumery/SM +perfunctorily +perfunctory +perfusion +pergola/SM +perhaps +pericardia +pericardial +pericarditis +pericardium/M +perigee/SM +perihelia +perihelion/M +peril/SGMD +perilous/Y +perimeter/SM +perinatal +perinea +perineum/M +period/MS +periodic +periodical/SMY +periodicity/M +periodontal +periodontics/M +periodontist/SM +peripatetic/MS +peripheral/MYS +periphery/SM +periphrases +periphrasis/M +periphrastic +periscope/SM +perish/BDRSZG +perishable/MS +peristalses +peristalsis/M +peristaltic +peristyle/SM +peritoneal +peritoneum/MS +peritonitis/M +periwig/SM +periwinkle/SM +perjure/DRSZG +perjurer/M +perjury/SM +perk/MDSG +perkily +perkiness/M +perky/TPR +perm/MDSG +permafrost/M +permalink/SM +permanence/M +permanency/M +permanent/SMY +permeability/M +permeable +permeate/GNDS +permeation/M +permissible +permissibly +permission/MS +permissive/PY +permissiveness/M +permit/MS +permitted +permittee +permitting +permutation/SM +permute/DSG +pernicious/YP +perniciousness/M +peroration/MS +peroxide/MGDS +perpendicular/SMY +perpendicularity/M +perpetrate/DSGN +perpetration/M +perpetrator/MS +perpetual/SMY +perpetuate/DSGN +perpetuation/M +perpetuity/M +perplex/GDS +perplexed/Y +perplexity/SM +perquisite/SM +persecute/GNXDS +persecution/M +persecutor/SM +perseverance/M +persevere/DSG +persiflage/M +persimmon/SM +persist/SGD +persistence/M +persistent/Y +persnickety +person/UMS +persona/SM +personable +personae +personage/MS +personal/MYS +personality/SM +personalize/CDSG +personalty/M +personification/M +personify/GDSNX +personnel/M +perspective/MS +perspex +perspicacious/Y +perspicacity/M +perspicuity/M +perspicuous +perspiration/M +perspire/GDS +persuade/BZGDRS +persuaded/U +persuader/M +persuasion/SM +persuasive/PY +persuasiveness/M +pert/RYPT +pertain/GSD +pertinacious/Y +pertinacity/M +pertinence/M +pertinent/Y +pertness/M +perturb/DGS +perturbation/SM +perturbed/U +pertussis/M +peruke/MS +perusal/MS +peruse/GDS +perv/S +pervade/DSG +pervasive/PY +pervasiveness/M +perverse/PXYN +perverseness/M +perversion/M +perversity/M +pervert/SGMD +peseta/MS +peskily +peskiness/M +pesky/TPR +peso/MS +pessary/S +pessimal +pessimism/M +pessimist/SM +pessimistic +pessimistically +pest/MRSZ +pester/GD +pesticide/MS +pestiferous +pestilence/SM +pestilent +pestilential +pestle/MGDS +pesto/M +pet/SZMR +petabyte/MS +petal/SMD +petard/MS +petcock/SM +peter/GMD +petiole/SM +petite/MS +petition/ZGMDRS +petitioner/M +petrel/MS +petrifaction/M +petrify/DSG +petrochemical/SM +petrodollar/MS +petrol/M +petrolatum/M +petroleum/M +petrologist/SM +petrology/M +petted +petticoat/MS +pettifog/S +pettifogged +pettifogger/SM +pettifoggery/M +pettifogging +pettily +pettiness/M +petting/M +pettish/Y +petty/PTR +petulance/M +petulant/Y +petunia/MS +pew/SM +pewee/SM +pewit/SM +pewter/MS +peyote/M +pf +pfennig/MS +pg +phaeton/MS +phage/S +phagocyte/SM +phalanger/SM +phalanges +phalanx/MS +phalli +phallic +phallocentric +phallocentrism +phallus/M +phantasm/MS +phantasmagoria/MS +phantasmagorical +phantasmal +phantom/SM +pharaoh/M +pharaohs +pharisaic +pharisee/SM +pharmaceutic/MS +pharmaceutical/SM +pharmaceutics/M +pharmacist/MS +pharmacologic +pharmacological +pharmacologist/SM +pharmacology/M +pharmacopeia/SM +pharmacopoeia/MS +pharmacy/SM +pharyngeal +pharynges +pharyngitis/M +pharynx/M +phase/DSMG +phaseout/SM +phat +pheasant/MS +phenacetin/M +phenobarbital/M +phenol/M +phenom/MS +phenomena +phenomenal/Y +phenomenological +phenomenology +phenomenon/MS +phenotype +pheromone/MS +phew +phi/SM +phial/SM +philander/ZGDRS +philanderer/M +philandering/M +philanthropic +philanthropically +philanthropist/MS +philanthropy/SM +philatelic +philatelist/MS +philately/M +philharmonic/SM +philippic/MS +philistine/MS +philistinism/M +philodendron/SM +philological +philologist/MS +philology/M +philosopher/MS +philosophic +philosophical/Y +philosophize/DRSZG +philosophizer/M +philosophy/SM +philter/MS +phish/ZGDR +phisher/M +phlebitis/M +phlebotomist/MS +phlebotomize/GDS +phlegm/M +phlegmatic +phlegmatically +phloem/M +phlox/M +pho +phobia/MS +phobic/MS +phoebe/MS +phoenix/MS +phone/DSMG +phonecard/S +phoneme/MS +phonemic +phonemically +phonetic/S +phonetically +phonetician/SM +phonetics/M +phoneyed +phoneying +phonic/S +phonically +phonics/M +phoniness/M +phonograph/M +phonographic +phonographs +phonological/Y +phonologist/MS +phonology/M +phony/PTGDRSM +phooey +phosphate/MS +phosphodiesterase +phosphor/MS +phosphorescence/M +phosphorescent/Y +phosphoric +phosphorous +phosphorus/M +phosphorylate/DSGN +photo/SGMD +photocell/MS +photocopier/M +photocopy/DRSMZG +photoelectric +photoelectrically +photoengrave/DRSJZG +photoengraver/M +photoengraving/M +photofinishing/M +photogenic +photogenically +photograph/MDRZG +photographer/M +photographic +photographically +photographs/A +photography/M +photojournalism/M +photojournalist/SM +photometer/MS +photon/MS +photosensitive +photostat/SM +photostatic +photostatted +photostatting +photosynthesis/M +photosynthesize/GDS +photosynthetic +phototropic +phototropism +phototypesetter +phototypesetting +phrasal +phrase's +phrase/AGDS +phrasebook/S +phraseology/M +phrasing/MS +phreaking +phrenologist/SM +phrenology/M +phyla +phylactery/SM +phylogeny/M +phylum/M +phys +physic/SM +physical/MYS +physicality +physician/SM +physicist/SM +physicked +physicking +physics/M +physio/S +physiognomy/SM +physiography/M +physiologic +physiological/Y +physiologist/MS +physiology/M +physiotherapist/MS +physiotherapy/M +physique/MS +pi/SMDRHZG +pianissimo/SM +pianist/MS +piano/SM +pianoforte/SM +pianola/S +piaster/MS +piazza/MS +pibroch/M +pibrochs +pic/SM +pica/M +picador/MS +picante +picaresque +picayune +piccalilli/M +piccolo/MS +pick/MDRSJZG +pickax/GMDS +picker/M +pickerel/MS +picket/ZGMDRS +pickings/M +pickle/MGDS +pickpocket/SM +pickup/MS +picky/PTR +picnic/MS +picnicked +picnicker/SM +picnicking +picot/SM +pictograph/M +pictographs +pictorial/MYS +picture/MGDS +picturesque/PY +picturesqueness/M +piddle/MGDS +piddly +pidgin/MS +pie/SM +piebald/MS +piece/DSMG +piecemeal +piecework/MRZ +pieceworker/M +piecrust/SM +pieing +pier/M +pierce/JGDS +piercing/MY +piety/M +piezoelectric +piffle/MG +pig/SML +pigeon/MS +pigeonhole/DSMG +pigged +piggery/S +pigging +piggish/PY +piggishness/M +piggy/TRSM +piggyback/MDSG +pigheaded/PY +pigheadedness/M +piglet/MS +pigment/MDS +pigmentation/M +pigpen/MS +pigskin/MS +pigsty/SM +pigswill +pigtail/MS +pike/MZGDRS +piker/M +pikestaff/SM +pikestaves +pilaf/SM +pilaster/MS +pilchard/MS +pile/MGDSJ +pileup/MS +pilfer/ZGDRS +pilferage/M +pilferer/M +pilgrim/MS +pilgrimage/MS +piling/M +pill/MDSG +pillage/MZGDRS +pillager/M +pillar/MDS +pillbox/MS +pillion/MS +pillock/S +pillory/GDSM +pillow/GMDS +pillowcase/MS +pillowslip/MS +pilot/DGSM +pilothouse/SM +pimento/MS +pimiento/MS +pimp/GMDYS +pimpernel/MS +pimple/DSM +pimply/RT +pin/SM +pinafore/MS +pinata/MS +pinball/M +pincer/MS +pinch/GMDS +pincushion/MS +pine's +pine/AGDS +pineapple/MS +pinewood/S +piney +pinfeather/SM +ping/GMD +pinhead/SM +pinhole/SM +pinion/SMDG +pink/TGPMDRS +pinkeye/M +pinkie/M +pinkish +pinkness/M +pinko/MS +pinky/SM +pinnacle/SM +pinnate +pinned/U +pinning/U +pinny/S +pinochle/M +pinon/MS +pinpoint/SGMD +pinprick/MS +pinsetter/SM +pinstripe/DSM +pint/MS +pinto/MS +pinup/MS +pinwheel/GSMD +piny/TR +pinyin/M +pinyon/SM +pioneer/SGMD +pious/YP +piousness/M +pip/SZGMDR +pipe/MS +pipeline/SM +piper/M +pipette/SM +pipework +piping/M +pipit/MS +pipped +pippin/SM +pipping +pipsqueak/SM +piquancy/M +piquant/Y +pique/MGDS +piracy/M +piranha/SM +pirate/DSMG +piratical/Y +pirogi/M +piroshki/M +pirouette/DSMG +pirozhki/M +piscatorial +pismire/SM +piss/ZGMDRS +pissoir/S +pistachio/SM +piste/S +pistil/SM +pistillate +pistol/SM +piston/SM +pit/SM +pita/MS +pitapat/SM +pitch/MDRSZG +pitchblende/M +pitcher/M +pitchfork/MDSG +pitchman/M +pitchmen +piteous/YP +piteousness/M +pitfall/SM +pith/M +pithead/S +pithily +pithiness/M +pithy/RTP +pitiable +pitiably +pitiful/Y +pitiless/PY +pitilessness/M +piton/MS +pitta/S +pittance/MS +pitted +pitting +pituitary/SM +pity/GDSM +pitying/Y +pivot/MDGS +pivotal +pix/M +pixel/MS +pixie/MS +pizazz/M +pizza/MS +pizzazz/M +pizzeria/SM +pizzicati +pizzicato/M +piata/MS +pion/SM +pj's +pk +pkg +pkt +pkwy +pl +placard/SMDG +placate/DSGN +placation/M +placatory +place's +place/AESDLG +placebo/SM +placed/U +placeholder/MS +placekick/MDRZGS +placekicker/M +placement/EASM +placenta/SM +placental/S +placer/SM +placid/Y +placidity/M +placings +placket/SM +plagiarism/SM +plagiarist/SM +plagiarize/DRSZG +plagiarizer/M +plagiary/M +plague/DSMG +plaice +plaid/MS +plain/MRYTSP +plainchant +plainclothes +plainclothesman/M +plainclothesmen +plainness/M +plainsman/M +plainsmen +plainsong/M +plainspoken +plaint/SMV +plaintext +plaintiff/SM +plaintive/Y +plait/MDGS +plan/ZMRS +planar +plane's +plane/CGDS +planeload/MS +planer/M +planet/SM +planetarium/SM +planetary +plangency/M +plangent +plank/MDGS +planking/M +plankton/M +planned/U +planner/SM +planning/S +plant/MDRZGSJ +plantain/SM +plantar +plantation/MS +planter/M +planting/M +plantlike +plaque/SM +plash/MDSG +plasma/M +plaster/SZGMDR +plasterboard/M +plasterer/M +plastic/SM +plasticity/M +plasticize/DSG +plastique +plat/XGMDNS +plate/MS +plateau/SMDG +plateful/SM +platelet/SM +platen/M +platform/SGMD +plating/M +platinum/M +platitude/SM +platitudinous +platonic +platoon/SGMD +platted +platter/SM +platting +platy/M +platypus/MS +platys +plaudit/SM +plausibility/M +plausible +plausibly +play/AEGMDS +playable/EU +playact/SGD +playacting/M +playback/MS +playbill/MS +playbook/MS +playboy/SM +player/SM +playfellow/SM +playful/PY +playfulness/M +playgirl/MS +playgoer/MS +playground/SM +playgroup/S +playhouse/MS +playlist/MS +playmate/MS +playoff/SM +playpen/SM +playroom/SM +playschool/S +plaything/SM +playtime/M +playwright/SM +plaza/MS +plea/MS +plead/DRZGSJ +pleader/M +pleading/MY +pleasant/UTYP +pleasanter +pleasantness/UM +pleasantry/SM +please/EDSG +pleasing/YS +pleasurably +pleasure/MGDSB +pleasureful +pleat/MDGS +pleb/S +plebby +plebe/MS +plebeian/MS +plebiscite/MS +plectra +plectrum/MS +pledge/DSMG +plenary/SM +plenipotentiary/SM +plenitude/SM +plenteous +plentiful/Y +plenty/M +plenum/S +pleonasm/MS +plethora/M +pleura/M +pleurae +pleurisy/M +plexiglass/M +plexus/MS +pliability/M +pliable +pliancy/M +pliant/Y +pliers/M +plight/SMDG +plimsoll/S +plinth/M +plinths +plod/S +plodded +plodder/MS +plodding/S +plonk/DRSZG +plop/MS +plopped +plopping +plosive/S +plot/MS +plotted +plotter/SM +plotting +plover/SM +plow/GMDS +plowman/M +plowmen +plowshare/MS +ploy's +ploy/S +pluck/MDSG +pluckily +pluckiness/M +plucky/RPT +plug's +plug/US +plugged/U +plugging/U +plughole/S +plugin/SM +plum/GMDS +plumage/M +plumb/MDRSZGJ +plumbed/U +plumber/M +plumbing/M +plume/MS +plummet/SGMD +plummy +plump/MDRYSTGP +plumpness/M +plumy/RT +plunder/SZGMDR +plunderer/M +plunge/DRSMZG +plunger/M +plunk/MDSG +pluperfect/SM +plural/SM +pluralism/M +pluralist/MS +pluralistic +plurality/SM +pluralization/M +pluralize/GDS +plus/MS +plush/MRYTP +plushness/M +plushy/RT +plutocracy/SM +plutocrat/SM +plutocratic +plutonium/M +pluvial +ply/AGDSM +plywood/M +pm +pneumatic +pneumatically +pneumococcal +pneumococci +pneumococcus +pneumonia/M +poach/DRSZG +poacher/M +poaching/M +pock/GMDS +pocket/SMDG +pocketbook/SM +pocketful/SM +pocketknife/M +pocketknives +pockmark/MDGS +pod/SM +podcast/SMG +podded +podding +podiatrist/SM +podiatry/M +podium/SM +poem/MS +poesy/M +poet/MS +poetaster/MS +poetess/MS +poetic/S +poetical/Y +poetry/M +pogrom/SM +poi/M +poignancy/M +poignant/Y +poinciana/SM +poinsettia/SM +point/MDRSZG +pointblank +pointed/Y +pointer/M +pointillism/M +pointillist/SM +pointless/PY +pointlessness/M +pointy/TR +poise/MGDS +poison/SJZGMDR +poisoner/M +poisoning/M +poisonous/Y +poke/MZGDRS +poker/M +pokey/MS +poky/TR +pol/SGMD +polar +polarity/SM +polarization/CM +polarize/CDSG +pole/MS +poleaxe/GDS +polecat/MS +polemic/MS +polemical/Y +polemicist/SM +polemics/M +polestar/SM +police/DSMG +policeman/M +policemen +policewoman/M +policewomen +policy/SM +policyholder/MS +policymaker/S +polio/MS +poliomyelitis/M +polish/ZGMDRS +polished/U +polisher/M +politburo/MS +polite/RYTP +politeness/M +politesse/M +politic/S +political/Y +politician/SM +politicization/M +politicize/CDSG +politicking/M +politico/SM +politics/M +polity/SM +polka/MDSG +poll/GMDNS +pollack/MS +pollard/S +pollen/M +pollinate/GNDS +pollination/M +pollinator/SM +polling/M +polliwog/SM +pollock/M +pollster/SM +pollutant/MS +pollute/ZGNDRS +polluted/U +polluter/M +pollution/M +pollywog/MS +polo/M +polonaise/SM +polonium/M +poltergeist/MS +poltroon/SM +poly +polyacrylamide +polyamory/S +polyandrous +polyandry/M +polyclinic/SM +polyester/MS +polyethylene/M +polygamist/MS +polygamous +polygamy/M +polyglot/SM +polygon/SM +polygonal +polygraph/GMD +polygraphs +polyhedral +polyhedron/SM +polymath/M +polymaths +polymer/SM +polymeric +polymerization/M +polymerize/GDS +polymorphic +polymorphous +polynomial/MS +polynucleotide/SM +polyp/MS +polypeptide's +polyphonic +polyphony/M +polypropylene/M +polys +polysemous +polystyrene/M +polysyllabic +polysyllable/MS +polytechnic/MS +polytheism/M +polytheist/SM +polytheistic +polythene +polyunsaturate/DS +polyurethane/MS +polyvinyl +pom/S +pomade/DSMG +pomander/SM +pomegranate/MS +pommel/SGMD +pommy/S +pomp/M +pompadour/SMD +pompano/MS +pompom/SM +pomposity/M +pompous/YP +pompousness/M +ponce/GDS +poncho/SM +poncy +pond/MS +ponder/SZGDR +ponderer/M +ponderous/YP +ponderousness/M +pone/MS +pong/GDS +pongee/M +poniard/MS +pontiff/SM +pontifical/Y +pontificate/DSMG +pontoon/SM +pony/GDSM +ponytail/MS +poo/SGD +pooch/MDSG +poodle/SM +poof/MS +poofter/S +pooh/GMD +poohs +pool/GMDS +poolroom/MS +poolside/S +poop/GMDS +poor/TRYP +poorboy/M +poorhouse/SM +poorness/M +pop/SM +popcorn/M +pope/MS +popgun/SM +popinjay/MS +poplar/SM +poplin/M +popover/SM +poppa/MS +poppadom/S +popped +popper/SM +poppet/S +popping +poppy/SM +poppycock/M +populace/MS +popular/Y +popularity/UM +popularization/M +popularize/DSG +populate/ACGDS +population/CM +populations +populism/M +populist/MS +populous/P +populousness/M +popup/MS +porcelain/SM +porch/MS +porcine +porcupine/SM +pore/MGDS +porgy/SM +pork/ZMR +porker/M +porky/RSMT +porn/M +porno/M +pornographer/MS +pornographic +pornographically +pornography/M +porosity/M +porous/P +porousness/M +porphyritic +porphyry/M +porpoise/MGDS +porridge/M +porringer/SM +port's/A +port/CAEGDS +portability/M +portable/MS +portage/DSMG +portal/SM +portcullis/MS +portend/SGD +portent/SM +portentous/YP +porter/ASM +porterhouse/SM +portfolio/MS +porthole/MS +portico/M +porticoes +portiere/MS +portion/KSGMD +portire/MS +portliness/M +portly/RPT +portmanteau/MS +portrait/MS +portraitist/SM +portraiture/M +portray/SGD +portrayal/MS +portulaca/M +pose's/A +pose/CAKEGDS +poser/EKSM +poseur/SM +posh/TR +posit/DSGV +position/CKEMS +positional/K +positioned/K +positioning/K +positive/MYPS +positiveness/M +positivism +positivist/S +positron/MS +poss +posse/MS +possess/AEVGSD +possession/ASM +possessive/SMYP +possessiveness/M +possessor/SM +possibility/SM +possible/SM +possibly +possum/SM +post/ZGMDRSJ +postage/M +postal +postbag/S +postbox/S +postcard/SM +postcode/S +postcolonial +postconsonantal +postdate/DSG +postdoc/MS +postdoctoral +poster/M +posterior/SM +posterity/M +postgraduate/SM +posthaste +posthumous/Y +posthypnotic +postie/S +postilion/SM +postillion/MS +postindustrial +posting/M +postlude/SM +postman/M +postmark/SMDG +postmaster/MS +postmen +postmenopausal +postmeridian +postmistress/MS +postmodern +postmodernism/M +postmodernist/MS +postmortem/SM +postnasal +postnatal +postoperative +postpaid +postpartum +postpone/DSGL +postponement/SM +postprandial +postscript/SM +postseason/SM +postsynaptic +postulate/XDSMGN +postulation/M +postural +posture/MGJDS +posturing/M +postwar +postwoman +postwomen +posy/SM +pot/CSM +potability/M +potable/SM +potash/M +potassium/M +potato/M +potatoes +potbelly/DSM +potboiler/SM +potency/M +potent/Y +potentate/MS +potential/MYS +potentiality/SM +potentiate/GDS +potful/SM +pothead/SM +pother/SMDG +potherb/SM +potholder/MS +pothole/DRSMZG +pothook/SM +potion/SM +potluck/MS +potpie/SM +potpourri/SM +potsherd/SM +potshot/MS +pottage/M +potted +potter/GSMD +pottery/SM +potting +potty/PRSMT +pouch/MDSG +pouf/S +pouffe/S +poulterer/MS +poultice/DSMG +poultry/M +pounce/DSMG +pound's +pound/KDSG +poundage/M +pounding/SM +pour/GDSJ +pout/ZGMDRS +pouter/M +poutine/S +poverty/M +pow +powder/GSMD +powdery +power/MDSG +powerboat/MS +powerful/Y +powerhouse/SM +powerless/PY +powerlessness/M +powwow/SGMD +pox/MS +pp +ppm +ppr +pr +practicability/M +practicably +practical/SMY +practicality/SM +practice/DSMGB +practiced/U +practicum/SM +practitioner/SM +praetor/SM +praetorian +pragmatic/MS +pragmatical/Y +pragmatism/M +pragmatist/MS +prairie/SM +praise/EDSMG +praiseworthiness/M +praiseworthy/P +praline/SM +pram/MS +prance/DRSMZG +prancer/M +prancing/Y +prang/DSG +prank/MS +prankster/SM +praseodymium/M +prat/S +prate/MZGDRS +prater/M +pratfall/SM +prattle/DRSMZG +prattler/M +prawn/MDSG +pray/ZGDRS +prayer/M +prayerful/Y +preach/DRSZGL +preacher/M +preachment/M +preachy/RT +preadolescence/SM +preamble/MGDS +prearrange/LGDS +prearrangement/M +preassigned +precancel/SMDG +precancerous +precarious/PY +precariousness/M +precast +precaution/MS +precautionary +precede/DSG +precedence/M +precedent/SM +precept/SM +preceptor/SM +precinct/MS +preciosity/M +precious/YP +preciousness/M +precipice/SM +precipitant/MS +precipitate/XMYGNDS +precipitation/M +precipitous/Y +precis/M +precise/DRSYTGNP +preciseness/M +precision/M +preclude/GDS +preclusion/M +precocious/YP +precociousness/M +precocity/M +precognition/M +precognitive +precolonial +preconceive/GDS +preconception/SM +precondition/MDGS +precook/GSD +precursor/SM +precursory +predate/DSG +predator/MS +predatory +predawn +predecease/GDS +predecessor/SM +predefined +predesignate/GDS +predestination/M +predestine/DSG +predetermination/M +predetermine/ZGDRS +predeterminer/M +predicable +predicament/MS +predicate/MGNVDS +predication/M +predicative/Y +predict/BGVSD +predictability/UM +predictable/U +predictably/U +prediction/SM +predictor/MS +predigest/GDS +predilection/SM +predispose/GDS +predisposition/MS +predominance/M +predominant/Y +predominate/YGDS +preemie/SM +preeminence/M +preeminent/Y +preempt/GVSD +preemption/M +preemptive/Y +preen/DSG +preexist/DGS +preexistence/M +pref +prefab/SM +prefabbed +prefabbing +prefabricate/DSGN +prefabrication/M +preface/DSMG +prefatory +prefect/SM +prefecture/MS +prefer/SBL +preferably +preference/MS +preferential/Y +preferment/M +preferred +preferring +prefigure/GDS +prefix/MDSG +preform/GSD +prefrontal +pregame/SM +pregnancy/SM +pregnant +preheat/GSD +prehensile +prehistorian/S +prehistoric +prehistorical/Y +prehistory/M +prehuman +prejudge/LGDS +prejudgement/MS +prejudgment/SM +prejudice/MGDS +prejudiced/U +prejudicial +prekindergarten/SM +prelacy/M +prelate/SM +prelim/SM +preliminarily +preliminary/SM +preliterate +prelude/MS +premarital +premature/Y +premed/SM +premedical +premeditate/DSGN +premeditated/U +premeditation/M +premenstrual +premier/SGMD +premiere/MS +premiership/MS +premise/DSMG +premium/SM +premix/GDS +premolar/SM +premonition/MS +premonitory +prenatal/Y +prenup/SM +prenuptial +preoccupation/SM +preoccupy/DSG +preoperative +preordain/GDS +prep/MS +prepackage/DSG +prepacked +prepaid +preparation/SM +preparatory +prepare/GDS +prepared/UP +preparedness/UM +prepay/GSL +prepayment/MS +preponderance/SM +preponderant/Y +preponderate/GDS +preposition/SM +prepositional/Y +prepossess/GDS +prepossessing/U +prepossession/SM +preposterous/Y +prepped +preppie/M +prepping +preppy/TRSM +prepubescence/M +prepubescent/SM +prepuce/MS +prequel/MS +prerecord/GSD +preregister/SGD +preregistration/M +prerequisite/MS +prerogative/SM +pres +presage/MGDS +presbyopia/M +presbyter/SM +presbytery/SM +preschool/SZMR +preschooler/M +prescience/M +prescient/Y +prescribe/DSG +prescript/SVM +prescription/SM +prescriptive/Y +preseason/SM +presence/SM +present/LMDRYZGSB +presentably +presentation/ASM +presenter/M +presentiment/SM +presentment/SM +preservation/M +preservationist/SM +preservative/SM +preserve/BDRSMZG +preserver/M +preset/S +presetting +preshrank +preshrink/GS +preshrunk +preside/GDS +presidency/SM +president/MS +presidential +presidia +presidium/M +presort/DGS +press's +press/ACGSD +pressed/U +presser/MS +pressie/S +pressing/SMY +pressman/M +pressmen +pressure/DSMG +pressurization/M +pressurize/CGDS +pressurizer/SM +prestidigitation/M +prestige/M +prestigious +presto/SM +presumably +presume/GDSB +presumption/SM +presumptive +presumptuous/YP +presumptuousness/M +presuppose/DSG +presupposition/MS +pretax +preteen/MS +pretend/DRZGS +pretender/M +pretense/SXMN +pretension/M +pretentious/UY +pretentiousness/M +preterit/SM +preterite/MS +preterm +preternatural/Y +pretest/DGS +pretext/MS +pretrial/S +prettify/GDS +prettily +prettiness/M +pretty/TGDRSMP +pretzel/MS +prevail/DGS +prevalence/M +prevalent +prevaricate/DSGNX +prevarication/M +prevaricator/SM +prevent/DBSGV +preventable/U +preventative/MS +prevention/M +preventive/SM +preview/MDRSZG +previous/Y +prevision/MS +prewar +prey/GMDS +prezzie/S +priapic +price's +price/AGDS +priceless +pricey +pricier +priciest +prick/MDRYSZG +pricker/M +prickle/MGDS +prickliness/M +prickly/PRT +pride/MGDS +prideful/Y +prier/M +priest/SMY +priestess/MS +priesthood/SM +priestliness/M +priestly/RTP +prig/MS +priggish/P +priggishness/M +prim/ZGDRYP +primacy/M +primal +primarily +primary/SM +primate/MS +prime/MS +primer/M +primeval +priming/M +primitive/SPMY +primitiveness/M +primmer +primmest +primness/M +primogenitor/SM +primogeniture/M +primordial/Y +primp/DSG +primrose/SM +primula/S +prince/SMY +princedom/SM +princeliness/M +princely/PRT +princess/MS +principal/SMY +principality/SM +principle/DSM +principled/U +print/AMDSG +printable/U +printer/MS +printing/SM +printmaking +printout/SM +prion/S +prior/MS +prioress/MS +prioritization +prioritize/DSG +priority/SM +priory/SM +prism/MS +prismatic +prison/SZMR +prisoner/M +prissily +prissiness/M +prissy/PTR +pristine +prithee +privacy/M +private/XMYTNRS +privateer/SM +privation/CSM +privatization/SM +privatize/DSG +privet/SM +privilege/DSMG +privileged/U +privily +privy/RSMT +prize/MGDS +prized/A +prizefight/ZGSMR +prizefighter/M +prizefighting/M +prizewinner/MS +prizewinning +pro/SM +proactive/Y +probabilistic +probability/SM +probable/SM +probably +probate/MN +probation/ZMR +probational +probationary +probationer/M +probe/MGDSBJ +probity/M +problem/MS +problematic +problematical/Y +probosces +proboscis/MS +procaine/M +procedural +procedure/SM +proceed/GJDS +proceeding/M +proceeds/M +process's +process/AGDS +processed/U +procession/GD +processional/MS +processor/SM +proclamation/MS +proclivity/SM +procrastinate/DSGN +procrastination/M +procrastinator/MS +procreate/V +proctor/GMDS +procurement/M +prod/MS +prodigal/MYS +prodigality/M +prodigious/Y +prodigy/SM +produce's +produce/AZGDRS +producer/AM +producible/A +production/ASM +productive/UY +productiveness/M +productivity/M +prof/MS +profanation/MS +profane/PYGDS +profaneness/M +profanity/SM +professed/Y +profession/SM +professional/MYS +professionalism/M +professionalization +professionalize/DSG +professor/SM +professorial/Y +professorship/SM +proffer/GMDS +proficiency/M +proficient/MYS +profit/BGD +profitability/M +profitable/U +profitably/U +profiteer/MDGS +profiteering/M +profiterole/SM +profitless +profligacy/M +profligate/SMY +profound/RYTP +profoundness/M +profundity/SM +profuse/PY +profuseness/M +progenitor/SM +progeny/M +progesterone/M +progestin/S +prognathous +prognoses +prognosis/M +prognostic/MS +prognosticate/XGNDS +prognostication/M +prognosticator/MS +program/CAS +programed +programing +programmable/MS +programmatic +programmed/AC +programmer/MS +programming/SM +progress/MDSGV +progression/MS +progressive/PMYS +progressiveness/M +prohibit/DGVS +prohibition/SM +prohibitionist/MS +prohibitive/Y +prohibitory +project/GMDS +projectile/SM +projection/SM +projectionist/SM +projector/MS +prokaryotic +prole/S +proletarian/MS +proletariat/M +proliferate/DSGN +proliferation/M +prolific +prolifically +prolix/Y +prolixity/M +prologue/SM +prolongation/SM +prom/M +promenade/MGDS +promethium/M +prominence/M +prominent/Y +promiscuity/M +promiscuous/Y +promise/DSMG +promising/Y +promissory +promo/M +promontory/SM +promote/DRZG +promoter/M +promotional +prompt/JPSMDRYZTG +prompted/U +prompter/M +prompting/M +promptitude/M +promptness/M +promulgate/GNDS +promulgation/M +promulgator/MS +pronate/DSGN +pronator/SM +prone/P +proneness/M +prong/MDS +pronghorn/MS +pronominal/M +pronounce/DSLG +pronounceable/U +pronouncement/SM +pronto +pronunciation/MS +proof/ADGSM +proofread/SRZG +proofreader/M +prop/MS +propaganda/M +propagandist/MS +propagandize/GDS +propagate/DSGN +propagation/M +propagator/SM +propel/S +propellant/MS +propelled +propeller/SM +propelling +propensity/SM +proper/MRYT +property/DSM +prophecy/SM +prophesier/M +prophesy/DRSMZG +prophet/SM +prophetess/MS +prophetic +prophetical/Y +prophylactic/SM +prophylaxes +prophylaxis/M +propinquity/M +propitiate/DSGN +propitiation/M +propitiatory +propitious/Y +proponent/SM +proportion/ESM +proportional/YS +proportionality +proportionate/EY +proposal/MS +propped +propping +proprietary/SM +proprieties/M +proprietor/SM +proprietorial/Y +proprietorship/SM +proprietress/MS +propriety/SM +propulsion/M +propulsive +propyl +prorate/DSG +prorogation/M +prorogue/GD +prosaic +prosaically +proscenium/SM +prosciutto/M +proscribe/DG +proscription/MS +prose/M +prosecute/DSXGN +prosecution/M +prosecutor/MS +proselyte/DSMG +proselytism/M +proselytize/DRSZG +proselytizer/M +prosody/SM +prospect/MDGVS +prospective/Y +prospector/SM +prospectus/MS +prosper/GSD +prosperity/M +prosperous/Y +prostate/MS +prostheses +prosthesis/M +prosthetic +prostitute/MGNDS +prostitution/M +prostrate/GNXDS +prostration/M +prosy/RT +protactinium/M +protagonist/SM +protean +protect/GVSD +protected/U +protection/SM +protectionism/M +protectionist/MS +protective/PY +protectiveness/M +protector/MS +protectorate/MS +protege/SM +protegee/S +protein/SM +protestant/S +protestation/MS +protestor/MS +protocol/MS +proton/SM +protoplasm/M +protoplasmic +prototype/MGS +prototypical +protozoa +protozoan/MS +protozoic +protract/GD +protrude/GDS +protrusile +protrusion/MS +protuberance/MS +protuberant +protg/MS +protge/S +proud/RYT +prov/NB +provability/M +provably +prove/EAGDS +proved/U +proven/U +provenance/SM +provender/M +provenience/M +proverbial/Y +provide/DRSZG +provided/U +providence/M +provident/Y +providential/Y +provider/M +province/MS +provincial/SMY +provincialism/M +provisional/Y +proviso/SM +provocateur/S +provocative/PY +provocativeness/M +provoke/DRSZG +provoked/U +provoker/M +provoking/Y +provolone/M +provost/SM +prow/MS +prowess/M +prowl/MDRSZG +prowler/M +proximal +proximate +proximity/M +proxy/SM +prude/MS +prudence/M +prudent/Y +prudential/Y +prudery/M +prudish/YP +prudishness/M +prune/MZGDRS +pruner/M +prurience/M +prurient/Y +pry/ZTGDRSM +prcis/MDG +psalm/MS +psalmist/SM +psaltery/SM +psephologist/S +psephology +pseud/S +pseudo/S +pseudonym/SM +pseudonymous +pseudorandom/Y +pseudoscience/MS +pseudy +pshaw/MS +psi/SM +psittacosis/M +psoriasis/M +psst +psych/MDSG +psyche/M +psychedelia +psychedelic/SM +psychedelically +psychiatric +psychiatrist/SM +psychiatry/M +psychic/MS +psychical/Y +psycho/SM +psychoactive +psychoanalyses +psychoanalysis/M +psychoanalyst/SM +psychoanalytic +psychoanalytical/Y +psychoanalyze/DSG +psychobabble/M +psychodrama/MS +psychogenic +psychokinesis +psychokinetic +psychological/Y +psychologist/MS +psychology/SM +psychometric +psychoneuroses +psychoneurosis/M +psychopath/M +psychopathic +psychopathology +psychopaths +psychopathy/M +psychopharmacology +psychos/S +psychosis/M +psychosomatic +psychotherapist/MS +psychotherapy/SM +psychotic/SM +psychotically +psychotropic/MS +psychs +pt/C +ptarmigan/MS +pterodactyl/MS +ptomaine/SM +pub/SM +pubertal +puberty/M +pubes/M +pubescence/M +pubescent +pubic +pubis/M +public/AM +publican/AMS +publication/ASM +publicist/MS +publicity/M +publicize/GDS +publicly +publish/AGDS +publishable +published/U +publisher/MS +publishing/M +puce/M +puck/ZMRS +pucker/MDG +puckish/YP +puckishness/M +pud/S +pudding/SM +puddle/DSMG +puddling/M +pudenda +pudendum/M +pudginess/M +pudgy/PRT +pueblo/SM +puerile +puerility/M +puerperal +puff/ZGMDRS +puffball/SM +puffer/M +puffin/SM +puffiness/M +puffy/PRT +pug/SM +pugilism/M +pugilist/SM +pugilistic +pugnacious/YP +pugnaciousness/M +pugnacity/M +puke/MGDS +pukka +pulchritude/M +pulchritudinous +pule/GDS +pull/ZGMDRS +pullback/MS +puller/M +pullet/SM +pulley/SM +pullout/MS +pullover/SM +pulmonary +pulp/GMDS +pulpiness/M +pulpit/SM +pulpwood/M +pulpy/RPT +pulsar/SM +pulsate/XGNDS +pulsation/M +pulse/AMGDS +pulverization/M +pulverize/DSG +puma/MS +pumice/SM +pummel/SGD +pump/ZGMDRS +pumper/M +pumpernickel/M +pumpkin/MS +pun/SM +punch/MDRSZG +punchbag/S +puncheon/MS +puncher/M +punchline/S +punchy/TR +punctilio/M +punctilious/PY +punctiliousness/M +punctual/Y +punctuality/M +punctuate/GNDS +punctuation/M +puncture/DSMG +pundit/SM +punditry/M +pungency/M +pungent/Y +puniness/M +punish/BLGDS +punished/U +punishing/Y +punishment/MS +punitive/Y +punk/TMRS +punned +punnet/S +punning +punster/SM +punt/ZGMDRS +punter/M +puny/TRP +pup/SM +pupa/M +pupae +pupal +pupate/DSG +pupil/MS +pupped +puppet/MS +puppeteer/SM +puppetry/M +pupping +puppy/SM +purblind +purchase/DRSMZGB +purchaser/M +purdah/M +pure/PYTR +purebred/SM +puree/MDS +pureeing +pureness/M +purgative/SM +purgatorial +purgatory/SM +purge/MZGDRS +purger/M +purification/M +purifier/M +purify/NDRSZG +purine/MS +purism/M +purist/MS +puristic +puritan/SM +puritanical/Y +puritanism/M +purity/M +purl/GMDS +purlieu/SM +purloin/SGD +purple/MTRS +purplish +purport/SMDG +purported/Y +purpose/DSMYG +purposeful/YP +purposefulness/M +purposeless/PY +purr/GMDS +purse/MZGDRS +purser/M +pursuance/M +pursuant +pursue/ZGDRS +pursuer/M +pursuit/SM +purulence/M +purulent +purvey/DSG +purveyance/M +purveyor/SM +purview/M +pus/M +push/ZGMDRS +pushbike/S +pushcart/SM +pushchair/S +pusher/M +pushily +pushiness/M +pushover/MS +pushpin/S +pushup/MS +pushy/TRP +pusillanimity/M +pusillanimous/Y +puss/MS +pussy/TRSM +pussycat/MS +pussyfoot/DSG +pustular +pustule/SM +put/ISM +putative +putdown/SM +putout/MS +putrefaction/M +putrefactive +putrefy/GDS +putrescence/M +putrescent +putrid +putsch/MS +putt/ZGMDRS +putted/I +puttee/MS +putter/MDRZG +putterer/M +putting/I +putty/GDSM +putz/S +puzzle/MZGDRSL +puzzlement/M +puzzler/M +pvt +pwn/SGD +pyelonephritis +pygmy/SM +pylon/SM +pylori +pyloric +pylorus/M +pyorrhea/M +pyramid/GSMD +pyramidal +pyre/MS +pyrimidine/MS +pyrite/SM +pyrites/M +pyromania/M +pyromaniac/SM +pyrotechnic/S +pyrotechnical +pyrotechnics/M +pyruvate +python/SM +pyx/MS +pzazz +q +qr +qt/S +qty +qua +quack/GMDS +quackery/M +quad/MS +quadrangle/SM +quadrangular +quadrant/MS +quadraphonic +quadratic/MS +quadrature +quadrennial +quadrennium/MS +quadriceps/MS +quadrilateral/SM +quadrille/XMNS +quadrillion/M +quadriplegia/M +quadriplegic/SM +quadrivium/M +quadruped/MS +quadrupedal +quadruple/MGDS +quadruplet/MS +quadruplicate/MGNDS +quadruplication/M +quaff/GMDS +quagmire/SM +quahog/MS +quail/GMDS +quaint/PRYT +quaintness/M +quake/MGDS +quaky +qualification/EM +qualified/U +qualifier/SM +qualify/EGXNDS +qualitative/Y +quality/SM +qualm/MS +qualmish +quandary/SM +quango/S +quanta +quantifiable +quantification/M +quantifier/M +quantify/NDRSZG +quantitative/Y +quantity/SM +quantum/M +quarantine/MGDS +quark/MS +quarrel/SZGMDR +quarreler/M +quarrelsome/P +quarrelsomeness/M +quarry/DSMG +quart/MS +quarter/SGMDY +quarterback/GMDS +quarterdeck/MS +quarterfinal/SM +quarterly/SM +quartermaster/MS +quarterstaff/M +quarterstaves +quartet/SM +quarto/MS +quartz/M +quasar/MS +quash/GDS +quasi +quatrain/MS +quaver/MDSG +quavery +quay/MS +quayside/S +queasily +queasiness/M +queasy/TPR +queen/GMDYS +queenly/RT +queer/PTGMDRYS +queerness/M +quell/GDS +quench/ZGDRSB +quenchable/U +quencher/M +quenchless +querulous/YP +querulousness/M +query/DSMG +ques +quesadilla/MS +quest/IFAMS +quested +questing +question/SMDRZGBJ +questionable/U +questionably/U +questioned/U +questioner/M +questioning/MY +questionnaire/SM +queue's +queue/CDSG +quibble/DRSMZG +quibbler/M +quiche/SM +quick/MNRYXTP +quicken/DG +quickfire +quickie/SM +quicklime/M +quickness/M +quicksand/MS +quicksilver/M +quickstep/MS +quid/MS +quiescence/M +quiescent/Y +quiet/SMDNRYXTGP +quieten/DG +quietism +quietness/M +quietude/IEM +quietus/MS +quiff/S +quill/SM +quilt/SMDRZG +quilter/M +quilting/M +quin/S +quince/SM +quine/S +quinine/M +quinoa +quinsy/M +quint/SM +quintessence/SM +quintessential/Y +quintet/SM +quintuple/MGDS +quintuplet/MS +quip/MS +quipped +quipping +quipster/SM +quire's +quire/IAS +quirk/SMDG +quirkiness/M +quirky/RTP +quirt/SM +quisling/SM +quit/S +quitclaim/MS +quite +quittance/M +quitter/SM +quitting +quiver/SMDG +quivery +quixotic +quixotically +quiz/M +quizzed +quizzer/SM +quizzes +quizzical/Y +quizzing +quo/H +quoin/SM +quoit/SMDG +quondam +quorate/I +quorum/SM +quot/B +quota/SM +quotability/M +quotation/SM +quote's +quote/UDSG +quotidian +quotient/SM +qwerty +r/S +rabbet/GMDS +rabbi/SM +rabbinate/M +rabbinic +rabbinical +rabbit/GMDS +rabble/MS +rabid/PY +rabidness/M +rabies/M +raccoon/MS +race/MZGDRS +racecourse/SM +racegoer/S +racehorse/MS +raceme/MS +racer/M +racetrack/MS +raceway/MS +racial/Y +racialism/M +racialist/MS +racily +raciness/M +racing/M +racism/M +racist/SM +rack/GMDS +racket/SMDG +racketeer/SMDG +racketeering/M +raconteur/SM +racoon +racquet/SM +racquetball/SM +racy/PRT +rad/SM +radar/SM +radarscope/SM +raddled +radial/SMY +radiance/M +radiant/Y +radiate/DSGNX +radiation/M +radiator/SM +radical/SMY +radicalism/M +radicalization/M +radicalize/DSG +radicchio/M +radii +radio/MDGS +radioactive/Y +radioactivity/M +radiocarbon/M +radiogram/MS +radiographer/SM +radiography/M +radioisotope/MS +radiologist/SM +radiology/M +radioman/M +radiomen +radiometer/MS +radiometric +radiometry/M +radiophone/SM +radioscopy/M +radiosonde/SM +radiosurgery +radiotelegraph/M +radiotelegraphs +radiotelegraphy/M +radiotelephone/MS +radiotherapist/MS +radiotherapy/M +radish/MS +radium/M +radius/M +radon/M +raffia/M +raffish/YP +raffishness/M +raffle/DSMG +raft/ZGMDRS +rafter/M +rafting/M +rag/SGMD +raga/MS +ragamuffin/MS +ragbag/M +rage/MS +ragga +ragged/RYTP +raggedness/M +raggedy/RT +ragging +raging/Y +raglan/SM +ragout/SM +ragtag/S +ragtime/M +ragweed/M +ragwort +rah +raid/ZGMDRS +raider/M +rail's +rail/CGDS +railcard/S +railing/SM +raillery/SM +railroad/SZGMDR +railroader/M +railroading/M +railway/SM +railwayman +railwaymen +raiment/M +rain/GMDS +rainbow/SM +raincoat/SM +raindrop/SM +rainfall/SM +rainmaker/SM +rainmaking/M +rainproof +rainstorm/MS +rainwater/M +rainy/RT +raise/MZGDRS +raiser/M +raisin/SM +raja/MS +rajah/M +rajahs +rake/MGDS +rakish/YP +rakishness/M +rally/DSMG +ram/SM +ramble/DRSMZGJ +rambler/M +rambunctious/PY +rambunctiousness/M +ramekin/SM +ramie/M +ramification/M +ramify/DSXNG +ramjet/SM +rammed +ramming +ramp/GMS +rampage/DSMG +rampancy/M +rampant/Y +rampart/SM +ramrod/SM +ramrodded +ramrodding +ramshackle +ran/A +ranch/MDRSZG +rancher/M +ranching/M +rancid/P +rancidity/M +rancidness/M +rancor/M +rancorous/Y +rand/M +randiness/M +random/PSY +randomization/M +randomize/DSG +randomness/MS +randy/RTP +ranee/MS +rang/ZR +range's +range/CGDS +rangefinder/S +ranger/M +ranginess/M +rangy/RTP +rani/MS +rank/TGJPMDRYS +ranking/M +rankle/DSG +rankness/M +ransack/SGD +ransom/SZGMDR +ransomer/M +ransomware +rant/ZGMDJRS +ranter/M +rap/SZGMDR +rapacious/PY +rapaciousness/M +rapacity/M +rape/MS +raper/M +rapeseed/M +rapid/PMRYTS +rapidity/M +rapidness/M +rapier/SM +rapine/M +rapist/SM +rapped +rappel/SM +rappelled +rappelling +rapper/SM +rapping +rapport/MS +rapporteur/S +rapprochement/SM +rapscallion/MS +rapt/YP +raptness/M +raptor/S +rapture/MS +rapturous/Y +rare/YTGPDRS +rarebit/MS +rarefaction/M +rarefy/GDS +rareness/M +rarity/SM +rascal/SMY +rash/ZTMRSYP +rasher/M +rashness/M +rasp/GMDS +raspberry/SM +raspy/RT +raster +rasterization/M +rasterize/DRSG +rat/SM +ratatouille/M +ratbag/S +ratchet/GMDS +rate/JXMZGNDRS +rated/U +ratepayer/S +rater/M +rather +rathskeller/SM +ratification/M +ratifier/M +ratify/NDRSZG +rating/M +ratio/MS +ratiocinate/GNDS +ratiocination/M +ration/MDG +rational/SMY +rationale/MS +rationalism/M +rationalist/SM +rationalistic +rationality/M +rationalization/MS +rationalize/DSG +ratlike +ratline/SM +rattan/SM +ratted +ratter/SM +ratting +rattle/DRSMZGJ +rattlebrain/SMD +rattler/M +rattlesnake/SM +rattletrap/SM +rattly +rattrap/SM +ratty/RT +raucous/YP +raucousness/M +raunchily +raunchiness/M +raunchy/TRP +ravage/DRSMZG +ravager/M +ravages/M +rave/JMZGDRS +ravel's +ravel/UDSG +raveling/S +raven/MDSG +ravenous/Y +ravine/SM +raving/M +ravioli/SM +ravish/DRSZGL +ravisher/M +ravishing/Y +ravishment/M +raw/PTMR +rawboned +rawhide/M +rawness/M +ray/SM +rayon/M +raze/GDS +razor/MS +razorback/MS +razz/GMDS +razzmatazz/M +rcpt +rd +re/DSMYTGVJ +reach/MDSGB +reachable/U +reacquire/DSG +react/V +reactant/SM +reactionary/SM +reactivity/M +read/ZGMRBJS +readability/SM +reader/M +readership/SM +readily +readiness/M +reading/M +readmitted +readout/SM +ready/DRSTGP +reafforestation +real/TMRYPS +realism/M +realist/SM +realistic/U +realistically/U +realities +reality/UM +realization/MS +realize/DSBG +realized/U +realm/MS +realness/M +realpolitik/M +realtor/SM +realty/M +ream/ZGMDRS +reamer/M +reap/ZGDRS +reaper/M +rear/GMDS +rearguard/MS +rearmost +rearward/S +reason/SMDRZGB +reasonable/UP +reasonableness/UM +reasonably/U +reasoner/M +reasoning/M +reassemble/DSG +reassuring/Y +rebate/M +rebel/MS +rebellion/MS +rebellious/YP +rebelliousness/M +rebid/S +rebidding +rebirth/M +reboil/SDG +rebuild/SG +rebuke/DSMG +rebuking/Y +rebuttal/MS +rec'd +rec/M +recalcitrance/M +recalcitrant +recant/SDG +recantation/SM +recap/MS +recapitalization +recce/S +recd +receipt/SMDG +receivables/M +receive/DRSZGB +receiver/M +receivership/M +recency +recent/RYTP +recentness/M +receptacle/SM +reception/MS +receptionist/SM +receptive/PY +receptiveness/M +receptivity/M +receptor/SM +recess/MDSGV +recessional/SM +recessionary +recessive/SM +recherche +recherch +recidivism/M +recidivist/SM +recipe/SM +recipient/SM +reciprocal/SMY +reciprocate/GNDS +reciprocation/M +reciprocity/M +recital/SM +recitalist/MS +recitative/MS +reciter/SM +reckless/YP +recklessness/M +reckon/SJDG +reckoning/M +reclamation/M +recline/DRSZG +recliner/M +recluse/SMV +recognizable/U +recognizably +recognize/DRSGB +recognized/U +recombination +recompense/DSMG +recompile/GD +recon/S +reconcile/GDSB +reconciliation/S +recondite +reconfiguration +reconfigure/D +reconnaissance/MS +reconnoiter/DGS +reconstruct/V +reconstructed/U +recorded/U +recorder/MS +recording/MS +recoup/DG +recourse/M +recoverable/U +recovery/SM +recreant/MS +recreational +recriminate/DSGNX +recrimination/M +recriminatory +recrudesce/GDS +recrudescence/M +recrudescent +recruit/LSMDRZG +recruiter/M +recruitment/M +rectal/Y +rectangle/MS +rectangular +rectifiable +rectification/M +rectifier/M +rectify/XNDRSZG +rectilinear +rectitude/M +recto/MS +rector/SM +rectory/SM +rectum/SM +recumbent +recuperate/GNVDS +recuperation/M +recur/S +recurred +recurrence/SM +recurrent/Y +recurring +recurse/XNV +recuse/DSG +recyclable/SM +recycling/M +red/PSM +redact/SDG +redaction/M +redactor/SM +redbird/SM +redbreast/MS +redbrick +redcap/SM +redcoat/SM +redcurrant/S +redden/SDG +redder +reddest +reddish +redeem/RZB +redeemer/M +redemption/M +redemptive +redesign/DSG +redhead/SMD +redirection +redistrict/GD +redivide/GDS +redlining/M +redneck/SM +redness/M +redo/G +redolence/M +redolent +redoubt/SBM +redoubtably +redound/SDG +redraw/SG +redskin/SM +reduce/DRSZG +reducer/M +reducible +reductase/M +reduction/SM +reductionist +reductive +redundancy/SM +redundant/Y +redwood/SM +redye/DS +reediness/M +reedy/RTP +reef/ZGMDRS +reefer/M +reek/GMDS +reel's +reel/UGDS +reeve/G +reexport/SDG +ref/SZM +refashion/DGS +refection/M +refectory/SM +refer/B +referee/DSM +refereeing +reference/MGDS +referendum/MS +referent/SM +referential +referral/SM +referred +referrer/SM +referring +reffed +reffing +refile/DSG +refill/BM +refined/U +refinement/SM +refiner/SM +refinery/S +refitting +reflate/XDSGN +reflationary +reflect/GVSD +reflection/MS +reflective/Y +reflector/MS +reflexive/SMY +reflexology +reforge/DSG +reform/MZ +reformat/V +reformatory/SM +reformatting +reformed/U +reformist/S +refortify/GDS +refract/SGVD +refraction/M +refractory/SM +refrain/SGMD +refresh/ZGLDRS +refresher/M +refreshing/Y +refreshment/SM +refreshments/M +refrigerant/SM +refrigerate/DSGN +refrigeration/M +refrigerator/MS +refuge/SM +refugee/SM +refulgence/M +refulgent +refund/B +refurbishment/MS +refusal/MS +refutation/MS +refute/BDRSZG +refuter/M +reg +regal/DYG +regalement/M +regalia/M +regard/ESMDG +regardless +regards/M +regather/DGS +regatta/SM +regency/SM +regeneracy/M +regenerate/V +regex/M +regexp/S +reggae/M +regicide/MS +regime/SM +regimen/SM +regiment/MDGS +regimental +regimentation/M +region/SM +regional/Y +regionalism/MS +register/GMDS +registered/U +registrant/MS +registrar/MS +registration/SM +registry/SM +regnant +regress/MDSGV +regression/MS +regret/SM +regretful/Y +regrettable +regrettably +regretted +regretting +regrind/GS +reground +regroup/DGS +regular/MYS +regularity/SM +regularization/M +regularize/DSG +regulate/CDSGNV +regulated/U +regulation/CM +regulations +regulator/MS +regulatory +regurgitate/DSGN +regurgitation/M +rehab/MS +rehabbed +rehabbing +rehabilitate/GNVDS +rehabilitation/M +rehang/SDG +rehears/GD +rehearsal/MS +rehearsed/U +rehi +rehung +reign/MDSG +reimburse/BDSGL +reimbursement/MS +rein/GD +reindeer/M +reinforce/LGDS +reinforcement/SM +reinitialize +reinstall/DG +reinstatement/M +reinsurance +reiterate/V +reject/GSMD +rejection/SM +rejoice/JGDS +rejoicing/M +rejoinder/SM +rejuvenate/DSGN +rejuvenation/M +rel +relate/DRSXZGNV +relatedness/M +relater/M +relation/M +relational +relationship/MS +relative/MYS +relativism/M +relativist/S +relativistic +relativity/M +relax/DRSZG +relaxant/MS +relaxation/SM +relaxer/M +relay/D +release/B +released/U +relegate/GNDS +relent/SGD +relentless/PY +relentlessness/M +relevance/M +relevancy/M +relevant/Y +reliability/UM +reliable/U +reliably/U +reliance/M +reliant +relic/MS +relief/SM +relieve/ZGDRS +reliever/M +religion/SM +religiosity +religious/MYP +religiousness/M +reline/DSG +relinquish/LDSG +relinquishment/M +reliquary/SM +relish/GMDS +relist/SGD +relocate/B +reluctance/M +reluctant/Y +rely/GDS +rem/M +remain/SGD +remainder/GMDS +remand/SGD +remapping +remark/B +remarkableness/M +remarkably +remarked/U +remediable +remedy/GDSM +remember/DG +remembered/U +remembrance/MS +reminder/M +reminisce/GDS +reminiscence/MS +reminiscent/Y +remiss/PY +remissness/M +remit/S +remittance/SM +remitted +remitting/U +remix/DSG +remnant/MS +remodel/GDS +remold/SGD +remonstrant/SM +remonstrate/DSG +remorse/M +remorseful/Y +remorseless/PY +remorselessness/M +remote/RSMYTP +remoteness/M +removal/SM +remunerate/GNVXDS +remuneration/M +renaissance/MS +renal +renascence/S +rend/GS +render/SGMDJ +rendering/M +rendezvous/GMDS +rendition/MS +renegade/DSMG +renege/DRSZG +reneger/M +renew/DSBG +renewal/MS +rennet/M +rennin/M +renounce/LDSG +renouncement/M +renovate/DSXGN +renovation/M +renovator/MS +renown/MD +rent/ZGMDRS +rental/SM +renter/M +renunciation/SM +reopen/SDG +reorg/MDSG +rep/SM +repaint/GDS +repair/BZR +repairer/M +repairman/M +repairmen +reparable +reparation/MS +reparations/M +repartee/M +repatriate/XDSMGN +repatriation/M +repeat/SMDRZGB +repeatable/U +repeatably +repeated/Y +repeater/M +repeating/M +repel/S +repelled +repellent/SM +repelling +repent/SDG +repentance/M +repentant/Y +repercussion/S +repertoire/MS +repertory/SM +repetition/MS +repetitious/YP +repetitiousness/M +repetitive/YP +repetitiveness/M +rephotograph/DG +replaceable +replant/GSD +replenish/LGDS +replenishment/M +replete/PDSGN +repleteness/M +repletion/M +replica/SM +replicate/DSGNX +replication/M +replicator/S +reportage/M +reported/Y +reportorial +reposeful +repository/SM +reprehend/DGS +reprehensibility/M +reprehensible +reprehensibly +reprehension/M +represent/GDS +representational +representative/MS +represented/U +repression/MS +repressive/PY +reprieve/DSMG +reprimand/GSMD +reprisal/SM +reprise/SMG +reproach/GMDSB +reproachful/Y +reprobate/MS +reproductive +reprogramming +reproving/Y +reptile/SM +reptilian/MS +republic/S +republicanism/M +repudiate/XGNDS +repudiation/M +repudiator/MS +repugnance/M +repugnant +repulsion/M +repulsive/YP +repulsiveness/M +repurchase/GDS +reputability/M +reputably/E +reputation/MS +repute/DSMGB +reputed/Y +request/GDR +requiem/SM +require/LDG +requirement/MS +requisite/XMNS +requisition/GMD +requital/M +requite/DRSZG +requited/U +requiter/M +reread/SG +rerecord/GDS +rerunning +resat +rescind/SDG +rescission/M +rescue/DRSMZG +rescuer/M +reseal/B +resell/SG +resemble/DSG +resend +resent/LSDG +resentful/YP +resentfulness/M +resentment/MS +reserpine/M +reservation/MS +reserved/UY +reservedness/M +reservist/SM +reservoir/SM +resetting +reshipping +residence/SM +residency/SM +resident/MS +residential +residua +residual/MS +residue/SM +residuum/M +resignation/SM +resigned/Y +resilience/M +resiliency/M +resilient/Y +resinous +resist/SMDRZG +resistance/SM +resistant/U +resistible +resistless +resistor/MS +resit/S +resitting +resold +resole/DSG +resolute/PY +resoluteness/M +resolve/RBM +resolved/U +resonance/SM +resonant/Y +resonate/GDS +resonator/SM +resorption/M +resound/SGD +resounding/Y +resourceful/YP +resourcefulness/M +resp +respect/ESGVMD +respectability/M +respectable +respectably +respectful/EY +respectfulness/M +respective/Y +respell/SGD +respiration/M +respirator/SM +respiratory +respire/DG +resplendence/M +resplendent/Y +respond/SGD +respondent/SM +response/MS +responsibility/SM +responsible +responsibly +responsive/UYP +responsiveness/UM +rest/GVMDS +restate/GDS +restaurant/SM +restaurateur/MS +restful/YP +restfuller +restfullest +restfulness/M +restitution/M +restive/YP +restiveness/M +restless/PY +restlessness/M +restoration/SM +restorative/SM +restorer/SM +restrained/U +restraint/MS +restrict/SDGV +restricted/U +restriction/MS +restrictive/YP +restrictiveness/M +restring/SG +restroom/SM +restructuring/SM +result/GSMD +resultant/SM +resume/DSMG +resumption/MS +resupply/DSG +resurgence/MS +resurgent +resurrect/GSD +resurrection/MS +resuscitate/GNDS +resuscitation/M +resuscitator/SM +retailer/MS +retain/SDRZG +retainer/M +retake/G +retaliate/DSGNVX +retaliation/M +retaliatory +retard/SMDRZG +retardant/SM +retardation/M +retarder/M +retch/DSG +reteach/GS +retention/M +retentive/YP +retentiveness/M +rethink/SGM +rethought +reticence/M +reticent/Y +reticulated +reticulation/MS +retina/SM +retinal +retinue/SM +retiree/SM +retirement/MS +retort/GMD +retrace/GDS +retract/DBG +retractile +retraction/S +retrain/DGS +retread/D +retrenchment/MS +retribution/MS +retributive +retrieval/SM +retrieve/DRSMZGB +retriever/M +retro/MS +retroactive/Y +retrofire/GDS +retrofit/SM +retrofitted +retrofitting +retrograde/DSG +retrogress/GVDS +retrogression/M +retrorocket/MS +retrospect/MDSGV +retrospection/M +retrospective/MYS +retrovirus/MS +retsina/M +returnable/SM +returnee/SM +rev/ZVM +revamping/M +reveal/GJSD +revealed/U +revealing/Y +reveille/M +revel/JMDRSZG +revelation/SM +reveler/M +revelry/SM +revenge/MGDS +revenuer/SM +reverb +reverberate/DSGNX +reverberation/M +revere/DSG +reverence/DSMG +reverend/SM +reverent/Y +reverential/Y +reverie/MS +revers/M +reversal/SM +reverse/Y +reversibility +reversible +reversibly +revert/GSD +revertible +revetment/SM +revile/DRSLZG +revilement/M +reviler/M +reviser/MS +revision/SM +revisionism/M +revisionist/SM +revival/MS +revivalism/M +revivalist/SM +revive/DSG +revivification/M +revocable +revoke/DSG +revolt/GD +revolting/Y +revolution/SM +revolutionary/SM +revolutionist/SM +revolutionize/DSG +revolve/BZGDRS +revolver/M +revue/MS +revulsion/M +revved +revving +rewarded/U +rewarding/U +rewarm/GSD +rewash/GDS +reweave/GS +rewedding +rewind/MB +rewound +rewrite/MGS +rhapsodic +rhapsodical +rhapsodize/GDS +rhapsody/SM +rhea/MS +rhenium/M +rheostat/SM +rhesus/MS +rhetoric/M +rhetorical/Y +rhetorician/SM +rheum/M +rheumatic/MS +rheumatically +rheumatism/M +rheumatoid +rheumatological +rheumatologist/MS +rheumatology/M +rheumy +rhinestone/SM +rhinitis/M +rhino/MS +rhinoceros/MS +rhinoplasty +rhinovirus/MS +rhizome/MS +rho/SM +rhodium/M +rhododendron/SM +rhomboid/SM +rhomboidal +rhombus/MS +rhubarb/MS +rhyme/MZGDRS +rhymer/M +rhymester/MS +rhythm/SM +rhythmic +rhythmical/Y +rial/MS +rib/SM +ribald +ribaldry/M +ribbed +ribber/SM +ribbing +ribbon/SM +riboflavin/M +rice/MZGDRS +ricer/M +rich/TMRSYP +richness/M +rick/GMDS +rickets/M +rickety/RT +rickrack/M +rickshaw/MS +ricochet/GMDS +ricotta/M +rid/S +riddance/M +ridden +ridding +riddle/DSMG +ride/MZGRS +rider/M +riderless +ridership/M +ridge/MGDS +ridgepole/SM +ridgy +ridicule/MGDS +ridiculous/YP +ridiculousness/M +riding/M +rife/TR +riff/GMDS +riffle/DSMG +riffraff/M +rifle/MZGDRS +rifleman/M +riflemen +rifler/M +rifling/M +rift/GMDS +rig/SM +rigamarole/SM +rigatoni/M +rigged +rigger/SM +rigging/M +right/MDRYSPTG +righteous/UP +righteously +righteousness/UM +rightful/PY +rightfulness/M +rightism/M +rightist/SM +rightmost +rightness/M +righto +rightsize/DSG +rightward/S +rigid/YP +rigidity/M +rigidness/M +rigmarole/MS +rigor/MS +rigorous/YP +rigorousness/M +rile/GDS +rill/MS +rim/SGMD +rime/MS +rimless +rimmed +rimming +rind/MS +ring/ZGMDRJ +ringer/M +ringgit/MS +ringleader/MS +ringlet/MS +ringlike +ringmaster/MS +ringside/M +ringtone/SM +ringworm/M +rink/MS +rinse/MGDS +riot/ZGMDRS +rioter/M +rioting/M +riotous/PY +rip/SXTMNR +riparian +ripcord/MS +ripe/YP +ripen/DG +ripened/U +ripeness/M +ripoff/SM +riposte/MGDS +ripped +ripper/SM +ripping +ripple/DSMG +ripply +ripsaw/SM +riptide/MS +rise/JMZGRS +risen +riser/M +risibility/M +risible +rising/M +risk/GMDS +riskily +riskiness/M +risky/RPT +risotto/MS +risque +risqu +rissole/S +rite/MS +ritual/SMY +ritualism/M +ritualistic +ritualistically +ritualized +ritzy/RT +riv/ZNR +rival/MDSG +rivaled/U +rivalry/SM +rive/CGDS +river/M +riverbank/SM +riverbed/MS +riverboat/SM +riverfront +riverside/MS +rivet/MDRSZG +riveter/M +riviera/S +rivulet/MS +riyal/MS +rm +roach/GMDS +road/IMS +roadbed/SM +roadblock/MDSG +roadhouse/SM +roadie/MS +roadkill/M +roadrunner/SM +roadshow/SM +roadside/SM +roadster/SM +roadway/SM +roadwork/SM +roadworthy +roam/ZGDRS +roamer/M +roaming/M +roan/MS +roar/ZGMDRS +roarer/M +roaring/M +roast/ZGMDRSJ +roaster/M +roasting/M +rob/S +robbed +robber/MS +robbery/SM +robbing +robe's +robe/EGDS +robin/MS +robocall/SGMD +robot/MS +robotic/S +robotics/M +robotize/GDS +robust/RYPT +robustness/M +rock/ZGMDRS +rockabilly/M +rockbound +rocker/M +rockery/S +rocket/MDSG +rocketry/M +rockfall/SM +rockiness/M +rocky/TRP +rococo/M +rod/SM +rode +rodent/MS +rodeo/MS +roe/SM +roebuck/SM +roentgen/MS +roger/GDS +rogue's +rogue/KS +roguery/M +roguish/YP +roguishness/M +roil/GDS +roister/ZGDRS +roisterer/M +role/MS +roll/MDRZGJS +rollback/SM +roller/M +rollerblading +rollerskating/M +rollick/SDG +rollicking/M +rollmop/S +rollover/SM +romaine/MS +roman/M +romance/MZGDRS +romancer/M +romantic/MS +romantically +romanticism/M +romanticist/SM +romanticize/DSG +romeo/MS +romp/MDRZGS +romper/M +rondo/SM +rood/MS +roof/MDRZGS +roofer/M +roofing/M +roofless +rooftop/SM +rook/MDGS +rookery/SM +rookie/SM +room/MDRZGS +roomer/M +roomette/SM +roomful/SM +roominess/M +roommate/SM +roomy/RTP +roost/SMDRZG +rooster/M +root/MDRZGS +rooter/M +rootkit/SM +rootless/P +rootlet/SM +rope/MZGDRS +roper/M +ropy/RT +rosary/SM +rose/MS +roseate +rosebud/SM +rosebush/MS +rosemary/M +rosette/SM +rosewater/M +rosewood/MS +rosily +rosin/SMDG +rosiness/M +roster/SM +rostrum/MS +rosy/RTP +rot/SM +rota/S +rotary/SM +rotatably +rotate/DSGNX +rotation/M +rotational +rotatory +rote/M +rotgut/M +rotisserie/SM +rotogravure/MS +rotor/SM +rototiller/MS +rotted +rotten/TPRY +rottenness/M +rotter/S +rotting +rottweiler/S +rotund/P +rotunda/MS +rotundity/M +rotundness/M +roue/MS +rouge/DSMG +rough/MDNRYXTGP +roughage/M +roughcast +roughen/GD +roughhouse/MGDS +roughneck/GMDS +roughness/M +roughs +roughshod +roulette/M +round/PSMDRYZTG +roundabout/SM +roundel/S +roundelay/MS +roundhouse/SM +roundish +roundness/M +roundup/MS +roundworm/SM +rouse/DSG +roust/SDG +roustabout/SM +rout/MRZS +route's +route/ADSG +routeing +router/M +routine/MYS +routinize/GDS +roux +rou/MS +rove/ZGDRS +rover/M +row/SZGMDR +rowan/S +rowboat/MS +rowdily +rowdiness/M +rowdy/PRSMT +rowdyism/M +rowel/SMDG +rower/M +rowing/M +rowlock/S +royal/SMY +royalist/SM +royalties/M +royalty/SM +rpm +rps +rt +rte +rub/SM +rubato/SM +rubbed +rubber/SM +rubberize/GDS +rubberneck/MDRSZG +rubbernecker/M +rubbery +rubbing/S +rubbish/MDSG +rubbishy +rubble/M +rubdown/SM +rube/MS +rubella/M +rubicund +rubidium/M +ruble/SM +rubric/SM +ruby/RSMT +ruched +ruck/DGS +rucksack/MS +ruckus/MS +ructions +rudder/SM +rudderless +ruddiness/M +ruddy/RTP +rude/YTRP +rudeness/M +rudiment/SM +rudimentary +rue/DSMG +rueful/PY +ruefulness/M +ruff/MDYGS +ruffian/MYS +ruffle/DSMG +ruffled/U +rug/SM +rugby/M +rugged/PTRY +ruggedness/M +rugger +rugrat/SM +ruin/MDGS +ruination/M +ruinous/Y +rule/MZGJDRS +ruler/M +ruling/M +rum/SM +rumba/SMDG +rumble/DSJMG +rumbling/M +rumbustious +ruminant/MS +ruminate/XGNVDS +rumination/M +ruminative/Y +rummage/DSMG +rummer +rummest +rummy/M +rumor/SMDG +rumormonger/SM +rump/MYS +rumple/DSMG +rumpus/MS +run/ASM +runabout/MS +runaround/SM +runaway/MS +rundown/SM +rune/MS +rung/MS +runic +runlet/SM +runnel/SM +runner/SM +running/M +runny/RT +runoff/SM +runt/MS +runty/RT +runway/SM +rupee/SM +rupiah/M +rupiahs +rupture/MGDS +rural +ruse/MS +rush/MDRSZG +rusher/M +rushy +rusk/MS +russet/SM +rust/MDGS +rustic/SM +rustically +rusticate/GDS +rustication/M +rusticity/M +rustiness/M +rustle/DRSJMZG +rustler/M +rustproof/SDG +rusty/RPNT +rut/SM +rutabaga/SM +ruthenium/M +rutherfordium/M +ruthless/YP +ruthlessness/M +rutted +rutting +rutty/RT +rye/M +s/NYXB +sabbath/M +sabbaths +sabbatical/SM +saber/MS +sable/MS +sabot/MS +sabotage/DSMG +saboteur/SM +sabra/MS +sabre/MS +sac/SM +saccharin/M +saccharine +sacerdotal +sachem/SM +sachet/SM +sack/ZGMDRJS +sackcloth/M +sacker/M +sackful/MS +sacking/M +sacra +sacrament/MS +sacramental +sacred/YP +sacredness/M +sacrifice/DSMG +sacrificial/Y +sacrilege/MS +sacrilegious/Y +sacristan/MS +sacristy/SM +sacroiliac/MS +sacrosanct/P +sacrosanctness/M +sacrum/M +sad/PY +sadden/SDG +sadder +saddest +saddle's +saddle/UDSG +saddlebag/MS +saddler/S +saddlery +sades +sadhu/S +sadism/M +sadist/SM +sadistic +sadistically +sadness/M +sadomasochism/M +sadomasochist/MS +sadomasochistic +safari/SGMD +safe/MYTPRS +safeguard/SMDG +safekeeping/M +safeness/M +safety/SM +safflower/MS +saffron/MS +sag/SM +saga/MS +sagacious/Y +sagacity/M +sage/MYTRS +sagebrush/M +sagged +sagging +saggy/RT +sago/M +saguaro/MS +sahib/MS +said/U +sail/GMDSJ +sailboard/MRZGS +sailboarder/M +sailboarding/M +sailboat/MS +sailcloth/M +sailfish/MS +sailing/M +sailor/SM +sailplane/MS +saint/MDYS +sainthood/M +saintlike +saintliness/M +saintly/PRT +saith +sake/M +saki/M +salaam/SMDG +salable/U +salacious/PY +salaciousness/M +salacity/M +salad/MS +salamander/SM +salami/SM +salary/DSM +sale/ABMS +saleable/U +saleroom/S +salesclerk/SM +salesgirl/SM +saleslady/SM +salesman/M +salesmanship/M +salesmen +salespeople/M +salesperson/MS +salesroom/S +saleswoman/M +saleswomen +salience/M +salient/SMY +saline/SM +salinity/M +saliva/M +salivary +salivate/GNDS +salivation/M +sallow/RTP +sallowness/M +sally/DSMG +salmon/SM +salmonella/M +salmonellae +salon/MS +saloon/SM +salsa/MS +salt's +salt/CTGDS +saltbox/MS +saltcellar/SM +salted/U +salter +saltine/SM +saltiness/M +saltpeter/M +saltshaker/SM +saltwater/M +salty/RTP +salubrious/I +salutary +salutation/MS +salutatorian/MS +salutatory +salute/DSMG +salvage/DSMG +salvageable +salvation/M +salve/MZGDRS +salver/M +salvo/MS +samarium/M +samba/MDSG +same/SP +sameness/M +samey +samizdat/S +samosa/S +samovar/SM +sampan/SM +sample/DRSMZGJ +sampler/M +sampling/M +samurai/SM +sanatorium/SM +sanctification/M +sanctify/GDSN +sanctimonious/YP +sanctimoniousness/M +sanctimony/M +sanction/GSMD +sanctioned/U +sanctity/M +sanctuary/SM +sanctum/SM +sand/ZGMDRS +sandal/SM +sandalwood/M +sandbag/SM +sandbagged +sandbagger/SM +sandbagging +sandbank/MS +sandbar/SM +sandblast/ZGMDRS +sandblaster/M +sandbox/MS +sandcastle/MS +sander/M +sandhog/SM +sandiness/M +sandlot/SM +sandlotter/MS +sandman/M +sandmen +sandpaper/GMDS +sandpiper/MS +sandpit/S +sandstone/M +sandstorm/SM +sandwich/MDSG +sandy/RTP +sane/IYTR +saneness/M +sang/S +sangfroid/M +sangria/M +sanguinary +sanguine/Y +sanitarian/SM +sanitarium/SM +sanitary/IU +sanitation/M +sanitize/GDS +sanity/IM +sank +sans +sanserif +sap/SM +sapience/M +sapiens +sapient +sapless +sapling/MS +sapped +sapper/S +sapphire/SM +sappiness/M +sapping +sappy/PRT +saprophyte/SM +saprophytic +sapsucker/SM +sapwood/M +saran/M +sarcasm/MS +sarcastic +sarcastically +sarcoma/MS +sarcophagi +sarcophagus/M +sardine/MS +sardonic +sardonically +sarge/MS +sari/MS +sarky +sarnie/S +sarong/SM +sarsaparilla/MS +sartorial/Y +sash/MS +sashay/SGMD +sass/GMDS +sassafras/MS +sassy/RT +sat +satanic +satanical/Y +satanism/M +satanist/MS +satay +satchel/MS +sate/GDS +sateen/M +satellite/DSMG +satiable/I +satiate/GNDS +satiation/M +satiety/M +satin/M +satinwood/SM +satiny +satire/SM +satiric +satirical/Y +satirist/SM +satirize/DSG +satisfaction/EM +satisfactions +satisfactorily/U +satisfactory/U +satisfied/U +satisfy/EDSG +satisfying/U +satisfyingly +sativa +satori/M +satrap/SM +satsuma/S +saturate/DSGN +saturated/U +saturation/M +saturnine +satyr/MS +satyriasis/M +satyric +sauce/MZGDRS +saucepan/SM +saucer/M +saucily +sauciness/M +saucy/RPT +sauerkraut/M +sauna/MDSG +saunter/MDGS +saurian +sauropod/SM +sausage/MS +saute/MS +sauteed +sauteing +sauternes/M +saut/MDSG +savage/DRSMYTGP +savageness/M +savagery/SM +savanna/MS +savant/SM +save/BJMZGDRS +saveable +saved/U +saver/M +saving/M +savings/M +savior/SM +savoir +savor/MDSG +savoriness/M +savory/PTRSM +savoy/MS +savvy/DRSMTG +saw/SGMD +sawbones/M +sawbuck/MS +sawdust/M +sawfly/SM +sawhorse/SM +sawmill/MS +sawyer/SM +sax/MS +saxifrage/SM +saxophone/MS +saxophonist/SM +say's +say/USG +saying/SM +scab/MS +scabbard/MS +scabbed +scabbiness/M +scabbing +scabby/PTR +scabies/M +scabrous +scad/MS +scaffold/SMG +scaffolding/M +scag/S +scagged +scalar/S +scalawag/MS +scald/MDSG +scale's +scale/CGDS +scaleless +scalene +scaliness/M +scallion/MS +scallop/GSMD +scallywag/MS +scalp/MDRSZG +scalpel/SM +scalper/M +scaly/RTP +scam/MS +scammed +scammer/S +scamming +scamp/MRSZ +scamper/GMD +scampi/M +scan/MS +scandal/SM +scandalize/DSG +scandalmonger/SM +scandalous/Y +scandium/M +scanned +scanner/SM +scanning +scansion/M +scant/CDSTG +scanter +scantily +scantiness/M +scantly +scantness/M +scanty/RSPT +scapegoat/SGMD +scapegrace/MS +scapula/M +scapulae +scapular/SM +scar/GMDS +scarab/SM +scarce/RYTP +scarceness/M +scarcity/SM +scare/MS +scarecrow/MS +scaremonger/SMG +scarf/MDSG +scarification/M +scarify/NDSG +scarily +scariness/M +scarlatina/M +scarlet/M +scarp/MDRSZG +scarper/DG +scarred +scarring +scarves +scary/RTP +scat/MS +scathing/Y +scatological +scatology/M +scatted +scatter/GJSMD +scatterbrain/SMD +scattering/M +scattershot +scatting +scatty +scavenge/ZGDRS +scavenger/M +scenario/MS +scenarist/MS +scene/MS +scenery/M +scenic +scenically +scent/CMS +scented/U +scenting +scentless +scepter/MS +sch +schadenfreude +schedule's +schedule/ADSG +scheduled/U +scheduler/S +schema +schemata +schematic/SM +schematically +schematize/GDS +scheme/DRSMZG +schemer/M +scherzo/MS +schilling/MS +schism/SM +schismatic/SM +schist/M +schizo/SM +schizoid/MS +schizophrenia/M +schizophrenic/SM +schlemiel/SM +schlep/SM +schlepp/GMDS +schlock/M +schlocky +schmaltz/M +schmaltzy/TR +schmo/M +schmoe/SM +schmooze/DRSZG +schmuck/MS +schnapps/M +schnaps +schnauzer/SM +schnitzel/SM +schnook/MS +schnoz/MS +schnozzle/SM +scholar/MYS +scholarship/MS +scholastic +scholastically +scholasticism +school/SGMD +schoolbag/MS +schoolbook/SM +schoolboy/MS +schoolchild/M +schoolchildren/M +schooldays +schooled/U +schoolfellow/SM +schoolgirl/SM +schoolhouse/SM +schooling/M +schoolkid/S +schoolmarm/SM +schoolmarmish +schoolmaster/MS +schoolmate/SM +schoolmistress/MS +schoolroom/SM +schoolteacher/MS +schoolwork/M +schoolyard/SM +schooner/SM +schrod/S +schuss/GMDS +schussboomer/MS +schwa/MS +sci +sciatic +sciatica/M +science/FMS +scientific/U +scientifically/U +scientist/SM +scimitar/SM +scintilla/MS +scintillate/DSGN +scintillation/M +scion/MS +scissor/GDS +scleroses +sclerosis/M +sclerotic +scoff/MDRSZG +scoffer/M +scofflaw/MS +scold/MDSGJ +scolding/M +scoliosis/M +sconce/SM +scone/MS +scoop/MDSG +scoopful/MS +scoot/DRSZG +scooter/M +scope/MGDS +scorbutic +scorch/MDRSZG +scorcher/M +score/MZGDRS +scoreboard/SM +scorecard/MS +scorekeeper/MS +scoreless +scoreline/S +scorer/M +scorn/MDRSZG +scorner/M +scornful/Y +scorpion/MS +scot-free +scotch/MDSG +scotchs +scoundrel/MS +scour/DRSZG +scourer/M +scourge/DSMG +scout/MDRSZG +scouting/M +scoutmaster/MS +scow/MS +scowl/MDSG +scrabble/MZGDRS +scrabbler/M +scrag/MS +scraggly/RT +scraggy/TR +scram/S +scramble's +scramble/UGDS +scrambler/MS +scrammed +scramming +scrap/MDRSZGJ +scrapbook/SM +scrape/SM +scraper/M +scrapheap/SM +scrapie +scrapped +scrapper/MS +scrapping +scrappy/TR +scrapyard/SM +scratch/GMDS +scratchcard/S +scratched/U +scratchily +scratchiness/M +scratchpad/S +scratchy/PRT +scrawl/SMDG +scrawly +scrawniness/M +scrawny/PTR +scream/SMDRZG +screamer/M +screaming/Y +scree/MDS +screech/GMDS +screechy/TR +screed/S +screen/SJMDG +screening/M +screenplay/SM +screensaver/SM +screenshot/SM +screenwriter/SM +screenwriting/M +screw's +screw/UDSG +screwball/MS +screwdriver/MS +screwiness/M +screwworm/SM +screwy/PRT +scribal +scribble/MZGDRS +scribbler/M +scribe's +scribe/CKIS +scrim/MS +scrimmage/MGDS +scrimp/SDG +scrimshaw/MDGS +scrip/MS +script/FSMDG +scripted/U +scriptural +scripture/MS +scriptwriter/SM +scrivener/SM +scrod/M +scrofula/M +scrofulous +scrog/S +scroll/GSMD +scrooge/MS +scrota +scrotal +scrotum/M +scrounge/DRSZG +scrounger/M +scroungy/TR +scrub/MS +scrubbed +scrubber/SM +scrubbing +scrubby/RT +scruff/SM +scruffily +scruffiness/M +scruffy/RPT +scrum/S +scrumhalf +scrumhalves +scrummage/S +scrummed +scrumming +scrump/SGD +scrumptious/Y +scrumpy +scrunch/MDSG +scrunchie/M +scrunchy/SM +scruple/MGDS +scrupulosity/M +scrupulous/UPY +scrupulousness/UM +scrutineer/S +scrutinize/GDS +scrutiny/M +scuba/MDSG +scud/MS +scudded +scudding +scuff/MDSG +scuffle/MGDS +scull/MDRSZG +sculler/M +scullery/SM +scullion/SM +sculpt/SGD +sculptor/SM +sculptress/MS +sculptural +sculpture/DSMG +scum/MS +scumbag/MS +scummed +scumming +scummy/TR +scupper/MDGS +scurf/M +scurfy +scurrility/M +scurrilous/PY +scurrilousness/M +scurry/GDSM +scurvily +scurvy/TRM +scutcheon/SM +scuttle/MGDS +scuttlebutt/M +scuzzy/TR +scythe/DSMG +sea/SM +seabed/SM +seabird/MS +seaboard/SM +seaborne +seacoast/SM +seafarer/SM +seafaring/M +seafloor/SM +seafood/M +seafront/SM +seagoing +seagull/MS +seahorse/MS +seal's +seal/AUSDG +sealant/MS +sealer/SM +sealskin/M +seam/GMDNS +seaman/M +seamanship/M +seamless/Y +seamount/MS +seamstress/MS +seamy/RT +seance/SM +seaplane/SM +seaport/MS +sear/GMDS +search/AZGMDRS +searchable/U +searcher/AM +searching/Y +searchlight/MS +searing/Y +seascape/SM +seashell/SM +seashore/SM +seasick/P +seasickness/M +seaside/MS +season/SGMDBJ +seasonable/U +seasonably/U +seasonal/Y +seasonality +seasoned/U +seasoning/M +seat's +seat/UGDS +seating/M +seatmate/SM +seawall/MS +seaward/MS +seawater/M +seaway/SM +seaweed/MS +seaworthiness/M +seaworthy/P +sebaceous +seborrhea/M +sebum +sec'y +sec/SM +secant/SM +secateurs +secede/DSG +secession/M +secessionist/MS +seclude/GDS +seclusion/M +seclusive +second/SLZGMDRY +secondarily +secondary/SM +seconder/M +secondhand +secondment/S +secrecy/M +secret/SGVMDY +secretarial +secretariat/MS +secretary/SM +secretaryship/M +secrete/XNS +secretion/M +secretive/PY +secretiveness/M +secretory +sect/IMS +sectarian/MS +sectarianism/M +sectary/SM +section/AESM +sectional/MS +sectionalism/M +sectioned +sectioning +sector/ESM +secular +secularism/M +secularist/SM +secularization/M +secularize/DSG +secure/DRSYTG +secured/U +security/ISM +secy +sedan/MS +sedate/DRSYTGNVP +sedateness/M +sedation/M +sedative/SM +sedentary +sedge/M +sedgy +sediment/MS +sedimentary +sedimentation/M +sedition/M +seditious +seduce/DRSZG +seducer/M +seduction/SM +seductive/YP +seductiveness/M +seductress/MS +sedulous/Y +see/RSMZ +seed's +seed/AGDS +seedbed/MS +seedcase/MS +seeded/U +seeder/SM +seediness/M +seedless +seedling/MS +seedpod/MS +seedy/RPT +seeing/S +seek/ZGRS +seeker/M +seem/GDS +seeming/Y +seemliness/UM +seemly/URTP +seen/U +seep/GDS +seepage/M +seer/M +seersucker/M +seesaw/SMDG +seethe/DSG +segfault/S +segment/GSMD +segmentation/M +segmented/U +segregate/CDSGN +segregated/U +segregation/CM +segregationist/MS +segue/MGDS +segueing +seigneur/SM +seignior/SM +seigniorial +seine/MZGDRS +seiner/M +seismic +seismically +seismograph/ZMR +seismographer/M +seismographic +seismographs +seismography/M +seismologic +seismological +seismologist/MS +seismology/M +seize/GDS +seizure/MS +seldom +select/CSGVD +selection/SM +selective/Y +selectivity/M +selectman/M +selectmen +selectness/M +selector/MS +selenium/M +selenographer/MS +selenography/M +self/GM +selfie/SM +selfish/UYP +selfishness/UM +selfism +selfist/S +selfless/PY +selflessness/M +selfsame +sell/ZGMRS +seller/M +selloff/MS +sellotape/DSG +sellout/MS +seltzer/MS +selvage/MS +selvedge/MS +selves +semantic/S +semantically +semanticist/MS +semantics/M +semaphore/DSMG +semblance/ASM +semen/M +semester/SM +semi/MS +semiannual/Y +semiarid +semiautomatic/MS +semibreve/S +semicircle/SM +semicircular +semicolon/MS +semiconducting +semiconductor/MS +semiconscious +semidarkness/M +semidetached +semifinal/SM +semifinalist/MS +semigloss/S +semimonthly/SM +seminal +seminar/MS +seminarian/SM +seminary/SM +semiofficial +semiotic/S +semiotics/M +semipermeable +semiprecious +semiprivate +semipro/S +semiprofessional/SM +semiquaver/S +semiretired +semiskilled +semisolid +semisweet +semitone/SM +semitrailer/MS +semitransparent +semitropical +semivowel/SM +semiweekly/SM +semiyearly +semolina/M +sempstress/MS +senate/SM +senator/MS +senatorial +send/ZGRS +sender/M +sendoff/MS +senescence/M +senescent +senile +senility/M +senior/SM +seniority/M +senna/M +senor/MS +senora/SM +senorita/SM +sensation/MS +sensational/Y +sensationalism/M +sensationalist/MS +sensationalize/GDS +sense/MGDS +senseless/PY +senselessness/M +sensibilities +sensibility/IM +sensible/P +sensibleness/M +sensibly/I +sensitive/SMYP +sensitiveness/M +sensitivities +sensitivity/IM +sensitization/CM +sensitize/CDSG +sensor/SM +sensory +sensual/Y +sensualist/SM +sensuality/M +sensuous/YP +sensuousness/M +sent/FAU +sentence/MGDS +sententious/Y +sentience/IM +sentient/I +sentiment/SM +sentimental/Y +sentimentalism/M +sentimentalist/MS +sentimentality/M +sentimentalization/M +sentimentalize/GDS +sentinel/MS +sentry/SM +sepal/MS +separability/IM +separable +separably/I +separate/XMYGNVDSP +separateness/M +separation/M +separatism/M +separatist/MS +separator/MS +sepia/M +sepsis/M +septa +septal +septet/SM +septic +septicemia/M +septicemic +septuagenarian/MS +septum/M +sepulcher/GMDS +sepulchral +seq +sequel/SM +sequence/MZGDRS +sequencing/M +sequential/FY +sequester/SDG +sequestrate/XGNDS +sequestration/M +sequin/SMD +sequinned +sequitur +sequoia/MS +seraglio/MS +serape/SM +seraph/M +seraphic +seraphim +seraphs +sere/TR +serenade/MGDS +serendipitous +serendipity/M +serene/RPYT +sereneness/M +serenity/M +serf/MS +serfdom/M +serge/M +sergeant/MS +serial/SMY +serialization/SM +serialize/GDS +series/M +serif/MS +serigraph/M +serigraphs +serine +serious/PY +seriousness/M +sermon/SM +sermonize/GDS +serology/M +serotonin +serous +serpent/MS +serpentine/M +serrate/XND +serration/M +serried +serum/MS +servant/MS +serve's/AF +serve/FACGDS +server/SM +servery/S +service/EMS +serviceability/M +serviceable +serviced +serviceman/M +servicemen +servicewoman/M +servicewomen +servicing +serviette/MS +servile +servility/M +serving's +servings +servitor/MS +servitude/M +servo/MS +servomechanism/SM +servomotor/MS +sesame/SM +sesquicentennial/MS +session/MS +set/AISM +setback/MS +setscrew/SM +setsquare/S +sett/BJZGRS +settee/MS +setter/M +setting/M +settle's +settle/AUGDS +settlement/AM +settlements +settler/SM +setup/MS +seven/MHS +seventeen/SMH +seventeenth/M +seventeenths +seventh/M +sevenths +seventieth/M +seventieths +seventy/SMH +sever/ETGDS +several/MY +severance/SM +severe/YPR +severeness/M +severity/M +sew/ASGD +sewage/M +sewer/MS +sewerage/M +sewing/M +sewn/A +sex/GMDS +sexagenarian/SM +sexily +sexiness/M +sexism/M +sexist/MS +sexless +sexologist/SM +sexology/M +sexpot/MS +sextant/SM +sextet/MS +sexting +sexton/MS +sextuplet/SM +sexual/Y +sexuality/M +sexy/PTR +sf +sh +shabbily +shabbiness/M +shabby/PTR +shack/MDSG +shackle's +shackle/UGDS +shad/GMDSJ +shade/MS +shadily +shadiness/M +shading/M +shadow/SGMD +shadowbox/GDS +shadowy/RT +shady/RPT +shaft/MDSG +shag/MS +shagged +shagginess/M +shagging +shaggy/TPR +shah/M +shahs +shake/MZGRS +shakedown/SM +shaken/U +shakeout/MS +shaker/M +shakeup/MS +shakily +shakiness/M +shaky/RPT +shale/M +shall +shallot/MS +shallow/TPMRYS +shallowness/M +shalom +shalt +sham/GMDS +shaman/SM +shamanic +shamanism +shamanistic +shamble/MGDS +shambles/M +shambolic +shame/MS +shamefaced/Y +shameful/PY +shamefulness/M +shameless/YP +shamelessness/M +shammed +shammies +shamming +shampoo/ZGMDRS +shampooer/M +shamrock/MS +shan't +shandy/S +shanghai/DSG +shank/MS +shantung/M +shanty/SM +shantytown/SM +shape's +shape/AGDS +shaped/U +shapeless/YP +shapelessness/M +shapeliness/M +shapely/PTR +shard/MS +share/MZGDRSB +shareable +sharecrop/S +sharecropped +sharecropper/MS +sharecropping +shareholder/SM +shareholding/S +sharer/M +shareware/M +sharia/M +shariah +shark/MDSG +sharkskin/M +sharp/MDNRYSPXZTG +sharpen/ADGS +sharpener/MS +sharper/M +sharpie/M +sharpish +sharpness/M +sharpshooter/SM +sharpshooting/M +sharpy/SM +shat +shatter/GMDS +shatterproof +shave/MZGDRSJ +shaven/U +shaver/M +shaving/M +shawl/MS +shay/MS +she'd +she'll +she/DSM +sheaf/M +shear/MDRSZG +shearer/M +sheath/JM +sheathe/UGDS +sheathing/M +sheaths +sheave/DSMG +shebang/MS +shebeen/S +shed/MS +shedding +sheen/M +sheeny/TR +sheep/M +sheepdog/MS +sheepfold/SM +sheepherder/MS +sheepish/YP +sheepishness/M +sheepskin/MS +sheer/MDRSPTG +sheerness/M +sheet/MSG +sheeting/M +sheetlike +sheik/MS +sheikdom/MS +sheikh/M +sheikhdom/MS +sheikhs +sheila/S +shekel/SM +shelf/M +shell/MDRSG +shellac/MS +shellacked +shellacking/MS +shellfire/M +shellfish/MS +shelter/GMDS +shelve/GDS +shelving/M +shemale/MS +shenanigan/SM +shepherd/SMDG +shepherdess/MS +sherbet/SM +sherd/MS +sheriff/SM +sherry/SM +shew/GDS +shewn +shh +shiatsu/M +shibboleth/M +shibboleths +shield/MDGS +shift/GMDS +shiftily +shiftiness/M +shiftless/PY +shiftlessness/M +shifty/RPT +shiitake/SM +shill/GMDSJ +shillelagh/M +shillelaghs +shilling/M +shim/MS +shimmed +shimmer/SMDG +shimmery +shimming +shimmy/DSMG +shin/ZGMDRS +shinbone/SM +shindig/SM +shine/MS +shiner/M +shingle/DSMG +shinguard/M +shininess/M +shinned +shinning +shinny/DSG +shinsplints/M +shiny/TRP +ship's +ship/ALS +shipboard/MS +shipbuilder/SM +shipbuilding/M +shipload/SM +shipmate/SM +shipment/AM +shipments +shipowner/MS +shipped/A +shipper/SM +shipping/M +shipshape +shipwreck/GMDS +shipwright/MS +shipyard/SM +shire/MS +shirk/ZGDRS +shirker/M +shirr/GMDSJ +shirring/M +shirt/GMDS +shirtfront/SM +shirting/M +shirtless +shirtsleeve/SM +shirttail/SM +shirtwaist/MS +shirty +shit/SM! +shitfaced/! +shithead/MS! +shitload's +shitload/! +shitloads +shitted/! +shitting/! +shitty/RT! +shiv/ZMRS +shiver/MDG +shivery +shoal/GMDS +shoat/MS +shock/ZGMDRS +shocker/M +shocking/Y +shockproof +shod/U +shoddily +shoddiness/M +shoddy/PRMT +shoe/MS +shoehorn/GMDS +shoeing +shoelace/MS +shoemaker/SM +shoeshine/SM +shoestring/SM +shoetree/MS +shogun/MS +shogunate/M +shone +shoo/GDS +shook +shoot/ZGMRSJ +shooter/M +shooting/M +shootout/MS +shop/MS +shopaholic/MS +shopfitter/S +shopfitting +shopfront/S +shopkeeper/MS +shoplift/DRZGS +shoplifter/M +shoplifting/M +shoppe/MZGDRS +shopper/M +shopping/M +shoptalk/M +shopworn +shore/MGDS +shorebird/SM +shoreline/MS +shoring/M +short/XTGMDNRYSP +shortage/MS +shortbread/M +shortcake/MS +shortchange/DSG +shortcoming/MS +shortcrust +shortcut/MS +shorten/JGD +shortening/M +shortfall/MS +shorthand/MD +shorthorn/MS +shortie/M +shortish +shortlist/DGS +shortness/M +shortsighted/PY +shortsightedness/M +shortstop/MS +shortwave/MS +shorty/SM +shot/MS +shotgun/SM +shotgunned +shotgunning +should +should've +shoulder/MDGS +shouldn't +shout/ZGMDRS +shouter/M +shove/MGDS +shovel/MDSG +shovelful/SM +show/JZGMDRS +showbiz/M +showboat/MDGS +showcase/MGDS +showdown/MS +shower/MDG +showerproof +showery +showgirl/MS +showground/S +showily +showiness/M +showing/M +showjumping +showman/M +showmanship/M +showmen +shown +showoff/SM +showpiece/SM +showplace/SM +showroom/MS +showstopper/MS +showstopping +showtime/MS +showy/TRP +shpt +shrank +shrapnel/M +shred/MS +shredded +shredder/MS +shredding +shrew/MS +shrewd/RYPT +shrewdness/M +shrewish +shriek/MDSG +shrift/M +shrike/MS +shrill/DRSPTG +shrillness/M +shrilly +shrimp/MDRSZG +shrine/MS +shrink/MSBG +shrinkage/M +shrive/GDS +shrivel/SGD +shriven +shroud/GMDS +shrub/MS +shrubbery/SM +shrubby/RT +shrug/MS +shrugged +shrugging +shrunk/N +shtick/MS +shuck/GMDS +shucks/S +shudder/MDSG +shuffle/AMGDS +shuffleboard/SM +shuffler/SM +shun/S +shunned +shunning +shunt/MSDG +shush/DSG +shut/S +shutdown/SM +shuteye/M +shutoff/SM +shutout/SM +shutter/SMDG +shutterbug/MS +shutting +shuttle/DSMG +shuttlecock/GMDS +shy/TGDRSMY +shyer +shyest +shyness/M +shyster/SM +sibilant/SM +sibling/SM +sibyl/MS +sibylline +sic/S +sicced +siccing +sick/PXTGDNRYS +sickbay/S +sickbed/SM +sicken/DG +sickening/Y +sickie/MS +sickish +sickle/MS +sickly/RT +sickness/MS +sicko/MS +sickout/SM +sickroom/MS +side's +side/AGDS +sidearm/SM +sidebar/SM +sideboard/SM +sideburns/M +sidecar/SM +sidekick/SM +sidelight/MS +sideline/DSMG +sidelong +sideman/M +sidemen +sidepiece/MS +sidereal +sidesaddle/MS +sideshow/MS +sidesplitting +sidestep/MS +sidestepped +sidestepping +sidestroke/DSMG +sideswipe/DSMG +sidetrack/SMDG +sidewalk/MS +sidewall/MS +sideways +sidewinder/SM +siding/MS +sidle/MGDS +siege/MS +sienna/M +sierra/MS +siesta/MS +sieve/MGDS +sift/ZGDRS +sifted/U +sifter/M +sigh/GMD +sighs +sight/GMDYSJ +sighting/M +sightless +sightly/UTR +sightread +sightseeing/M +sightseer/MS +sigma/MS +sign's/C +sign/AFCGDS +signage/M +signal/MDRYSZG +signaler/M +signalization/M +signalize/GDS +signalling +signalman/M +signalmen +signatory/SM +signature/MS +signboard/MS +signed/U +signer/CMS +signet/MS +significance/IM +significant/IY +signification/M +signify/XDSNG +signing/CSM +signor/FMS +signora/SM +signore +signori +signorina/MS +signorine +signpost/GSMD +signup/MS +silage/M +silence/DRSMZG +silencer/M +silent/MRYST +silhouette/DSMG +silica/M +silicate/MS +siliceous +silicon/SM +silicone/M +silicosis/M +silk/MNS +silkily +silkiness/M +silkscreen/SM +silkworm/MS +silky/TRP +sill/MS +silliness/M +silly/TRSMP +silo/MS +silt/GMDS +silty/TR +silvan +silver/GMDS +silverfish/MS +silversmith/M +silversmiths +silverware/M +silvery +sim/SM +simian/MS +similar/Y +similarity/ESM +simile/MS +similitude/EM +simmer/GMDS +simonize/DSG +simony/M +simpatico +simper/GMDS +simpering/Y +simple/TRP +simpleminded +simpleness/M +simpleton/SM +simplex +simplicity/M +simplification/M +simplify/DSXNG +simplistic +simplistically +simply +simulacra +simulacrum/S +simulate/EDSGN +simulation/EM +simulations +simulator/EMS +simulcast/GMDS +simultaneity/M +simultaneous/Y +sin/ASM +since +sincere/IYT +sincerer +sincerity/IM +sine/MS +sinecure/MS +sinew/MS +sinewy +sinful/PY +sinfulness/M +sing/BZGMDRYS +singalong/S +singe/MS +singeing +singer/M +singing/M +single/PMGDS +singleness/M +singles/M +singlet/S +singleton/SM +singletree/SM +singsong/SMDG +singular/SMY +singularity/SM +sinister +sink/BZGMRS +sinkable/U +sinker/M +sinkhole/SM +sinless +sinned +sinner/MS +sinning +sinology +sinuosity/M +sinuous/Y +sinus/MS +sinusitis/M +sinusoidal +sip/SM +siphon/GMDS +sipped +sipper/SM +sipping +sir/SXMN +sire/CMGDS +siree/M +siren/M +sirloin/SM +sirocco/SM +sirrah +sirree/M +sis/MS +sisal/M +sissified +sissy/RSMT +sister/ASM +sisterhood/MS +sisterliness/M +sisterly/P +sit/S +sitar/SM +sitarist/MS +sitcom/SM +site/MGDS +sitemap/SM +sitter/SM +sitting/SM +situate/DSXGN +situation/M +situational +six/MSH +sixfold +sixpence/MS +sixshooter/M +sixteen/SMH +sixteenth/M +sixteenths +sixth/M +sixths +sixtieth/M +sixtieths +sixty/SMH +size's +size/AGBDRS +sizeable +sizing/M +sizzle/DRSMZG +ska/M +skate/MZGDRS +skateboard/MDRSZG +skateboarder/M +skateboarding/M +skater/M +skating/M +skedaddle/MGDS +skeet/ZMR +skein/MS +skeletal +skeleton/SM +skeptic/SM +skeptical/Y +skepticism/M +sketch/MDRSZG +sketchbook/S +sketcher/M +sketchily +sketchiness/M +sketchpad/S +sketchy/RTP +skew/MDRZGS +skewbald/S +skewer/MDG +ski/SZGMDR +skibob/S +skid/MS +skidded +skidding +skidpan/S +skier/M +skiff/SM +skiffle +skiing/M +skill's +skill/CSD +skilled/U +skillet/SM +skillful/UY +skillfulness/M +skim/MS +skimmed +skimmer/SM +skimming +skimp/SDG +skimpily +skimpiness/M +skimpy/RTP +skin/MS +skincare/M +skinflick/MS +skinflint/MS +skinful +skinhead/MS +skinless +skinned +skinniness/M +skinning +skinny/RMTP +skint +skintight +skip/MS +skipped +skipper/SMDG +skipping +skirmish/ZGMDRS +skirt/SMDG +skit/MS +skitter/GSD +skittish/YP +skittishness/M +skittle/S +skive/DRSZG +skivvy/DSMG +skoal/SM +skua/S +skulduggery/M +skulk/SDRZG +skulker/M +skull/SM +skullcap/MS +skullduggery/M +skunk/SMDG +sky/GSM +skycap/SM +skydive/DRSZG +skydiver/M +skydiving/M +skyjack/JZGSDR +skyjacker/M +skyjacking/M +skylark/SGMD +skylight/MS +skyline/SM +skyrocket/GSMD +skyscraper/SM +skyward/S +skywriter/SM +skywriting/M +slab/MS +slabbed +slabbing +slack/PXZTGMDNRYS +slacken/DG +slacker/M +slackness/M +slacks/M +slag/MS +slagged +slagging +slagheap/S +slain +slake/GDS +slalom/MSDG +slam/MS +slammed +slammer/SM +slamming +slander/MZGDRS +slanderer/M +slanderous +slang/M +slangy/RT +slant/MSDG +slanting/Y +slantwise +slap/MS +slapdash +slaphappy +slapped +slapper/S +slapping +slapstick/M +slash/MDRSZG +slasher/M +slat/MDGS +slate/SM +slather/SDG +slatted +slattern/SMY +slaughter/MDRZGS +slaughterer/M +slaughterhouse/MS +slave/DRSMZG +slaveholder/MS +slaver/MDG +slavery/M +slavish/PY +slavishness/M +slaw/M +slay/DRZGJS +slayer/M +slaying/M +sleaze/SM +sleazebag/S +sleazeball/S +sleazily +sleaziness/M +sleazy/PRT +sled/MS +sledded +sledder/SM +sledding +sledge/DSMG +sledgehammer/GSMD +sleek/SDRYTGP +sleekness/M +sleep/SMRZG +sleeper/M +sleepily +sleepiness/M +sleepless/PY +sleeplessness/M +sleepover/SM +sleepwalk/ZGSDR +sleepwalker/M +sleepwalking/M +sleepwear/M +sleepy/RPT +sleepyhead/MS +sleet/SMDG +sleety +sleeve/DSM +sleeveless +sleigh/MDG +sleighs +sleight/SM +slender/PRT +slenderize/DSG +slenderness/M +slept +sleuth/MG +sleuths +slew/MDGS +slice/DRSMZG +slicer/M +slick/SMDRYZTGP +slicker/M +slickness/M +slid +slide/RSMZG +slider/M +slideshow/MS +slight/SMDRYTGP +slightness/M +slim/PS +slime/M +sliminess/M +slimline +slimmed +slimmer/S +slimmest +slimming/M +slimness/M +slimy/RTP +sling/SMG +slingback/S +slingshot/SM +slink/SG +slinky/RT +slip/MS +slipcase/MS +slipcover/MS +slipknot/MS +slippage/MS +slipped +slipper/SM +slipperiness/M +slippery/PRT +slipping +slippy +slipshod +slipstream/SM +slipway/SM +slit/MS +slither/SGMD +slithery +slitter +slitting +sliver/GSMD +slob/MS +slobbed +slobber/MDSG +slobbery +slobbing +sloe/MS +slog/MS +slogan/SM +sloganeering +slogged +slogging +sloop/SM +slop/MDGS +slope/SM +slopped +sloppily +sloppiness/M +slopping +sloppy/PTR +slops/M +slosh/DSG +slot/MS +sloth/M +slothful/YP +slothfulness/M +sloths +slotted +slotting +slouch/ZGMDRS +sloucher/M +slouchy/TR +slough/GMD +sloughs +sloven/SMY +slovenliness/M +slovenly/PTR +slow/DRYTGSP +slowcoach/S +slowdown/SM +slowness/M +slowpoke/SM +sludge/M +sludgy/RT +slue/MGDS +slug/MS +sluggard/MS +slugged +slugger/SM +slugging +sluggish/PY +sluggishness/M +sluice/DSMG +slum/MS +slumber/GSMD +slumberous +slumbrous +slumdog/SM +slumlord/MS +slummed +slummer +slumming +slummy/RT +slump/SMDG +slung +slunk +slur/MS +slurp/SMDG +slurred +slurring +slurry/M +slush/M +slushiness/M +slushy/RPT +slut/MS +sluttish +slutty/RT +sly/TRY +slyer +slyest +slyness/M +smack/SMDRZG +smacker/M +small/SMRTP +smallholder/S +smallholding/S +smallish +smallness/M +smallpox/M +smarmy/RT +smart/SMDNRYXTGP +smarten/DG +smartness/M +smartphone/SM +smarts/M +smartwatch/MS +smarty/SM +smartypants/M +smash/MDRSZG +smasher/M +smashup/SM +smattering/MS +smear/SMDG +smeary/RT +smell/SMDG +smelliness/M +smelly/RPT +smelt/SMDRZG +smelter/M +smidgen/MS +smilax/M +smile/DSMG +smiley/SM +smiling/Y +smirch/GMDS +smirk/SMDG +smite/SG +smith/M +smithereens/M +smiths +smithy/SM +smitten +smock/SMDG +smocking/M +smog/MS +smoggy/RT +smoke/DRSMZG +smokehouse/MS +smokeless +smoker/M +smokescreen/SM +smokestack/SM +smokey +smokiness/M +smoking/M +smoky/RTP +smolder/SGMD +smooch/MDSG +smoochy +smooth/PDRYTG +smoothie/M +smoothness/M +smooths +smoothy/SM +smorgasbord/SM +smote +smother/GSMD +smoulder/GMDS +smudge/DSMG +smudgy/TR +smug/YP +smugger +smuggest +smuggle/ZGDRS +smuggler/M +smuggling/M +smugness/M +smurf/S +smut/MS +smuttiness/M +smutty/TRP +smrgsbord/MS +snack/SMDG +snaffle/DSMG +snafu/SM +snag/MS +snagged +snagging +snail/SMDG +snake/DSMG +snakebite/MS +snakelike +snakeskin +snaky/RT +snap's +snap/US +snapdragon/SM +snapped/U +snapper/MS +snappily +snappiness/M +snapping/U +snappish/YP +snappishness/M +snappy/TRP +snapshot/SM +snare/DSMG +snarf/SDG +snark/S +snarkily +snarky/TR +snarl's +snarl/USDG +snarling/Y +snarly/TR +snatch/ZGMDRS +snatcher/M +snazzily +snazzy/TR +sneak/SMDRZG +sneaker/M +sneakily +sneakiness/M +sneaking/Y +sneaky/TRP +sneer/SJMDG +sneering/Y +sneeze/DSMG +snick/SDRZG +snicker/MDG +snide/RYT +sniff/SMDRZG +sniffer/M +sniffle/DSMG +sniffy/RT +snifter/SM +snigger/SMDG +snip/MDRZGS +snipe/SM +sniper/M +snipped +snippet/SM +snipping +snippy/RT +snips/M +snit/MS +snitch/MDSG +snivel/SMDRZG +sniveler/M +snob/MS +snobbery/M +snobbish/PY +snobbishness/M +snobby/RT +snog/S +snogged +snogging +snood/SM +snooker/MDSG +snoop/SMDRZG +snooper/M +snoopy/TR +snoot/SM +snootily +snootiness/M +snooty/PTR +snooze/DSMG +snore/DRSMZG +snorer/M +snorkel/ZGMDRS +snorkeler/M +snorkeling/M +snort/SMDRZG +snorter/M +snot/MS +snottily +snottiness/M +snotty/TPR +snout/SM +snow/MDGS +snowball/GSMD +snowbank/SM +snowbird/SM +snowblower/MS +snowboard/ZGMDRS +snowboarder/M +snowboarding/M +snowbound +snowdrift/SM +snowdrop/SM +snowfall/SM +snowfield/SM +snowflake/SM +snowiness/M +snowline +snowman/M +snowmen +snowmobile/DSMG +snowplow/SGMD +snowshed +snowshoe/SM +snowshoeing +snowstorm/SM +snowsuit/SM +snowy/PRT +snub/MS +snubbed +snubbing +snuff/SMDRYZG +snuffbox/MS +snuffer/M +snuffle/MGDS +snug/MYSP +snugged +snugger +snuggest +snugging +snuggle/MGDS +snugness/M +so +soak/MDGSJ +soaking/M +soap/MDGS +soapbox/MS +soapiness/M +soapstone/M +soapsuds/M +soapy/RPT +soar/MDGS +sob/SM +sobbed +sobbing/Y +sober/SDRYPTG +soberness/M +sobriety/IM +sobriquet/SM +soc +soccer/M +sociability/M +sociable/SM +sociably +social/SMY +socialism/M +socialist/SM +socialistic +socialite/SM +socialization/M +socialize/DSG +societal +society/SM +socioeconomic +socioeconomically +sociological/Y +sociologist/SM +sociology/M +sociopath/M +sociopaths +sociopolitical +sock/MDGS +socket/SM +sockeye/SM +sod/SM +soda/MS +sodded +sodden/Y +sodding +sodium/M +sodomite/MS +sodomize/GDS +sodomy/M +soever +sofa/MS +soft/NRYXTP +softback +softball/MS +softbound +softcover +soften/DRZG +softener/M +softhearted +softie/M +softness/M +software/M +softwood/SM +softy/SM +soggily +sogginess/M +soggy/RTP +soigne +soignee +soign +soigne +soil/MDGS +soiled/U +soiree/SM +soire/SM +sojourn/ZGMDRS +sojourner/M +sol/SM +solace/DSMG +solar +solaria +solarium/M +sold +solder/ZGSMDR +solderer/M +soldier/MDYSG +soldiery/M +sole/FSDGM +solecism/SM +solely +solemn/PTRY +solemness/M +solemnify/DSG +solemnity/SM +solemnization/M +solemnize/DSG +solemnness/M +solenoid/MS +solicit/GDS +solicitation/SM +solicited/U +solicitor/SM +solicitous/PY +solicitousness/M +solicitude/M +solid/PSMRYT +solidarity/M +solidi +solidification/M +solidify/DSNG +solidity/M +solidness/M +solidus/M +soliloquies +soliloquize/DSG +soliloquy/M +solipsism/M +solipsistic +solitaire/MS +solitariness/M +solitary/SMP +solitude/M +solo/MDGS +soloist/MS +solstice/MS +solubility/IM +soluble/MS +solute's +solute/AXN +solutes +solution's/AE +solvable/IU +solve/EADSG +solved/U +solvency/IM +solvent/IMS +solver/SM +somatic +somber/PY +somberness/M +sombre/PY +sombreness/M +sombrero/MS +some +somebody/SM +someday +somehow +someone/MS +someplace +somersault/MDGS +somerset/SM +somersetted +somersetting +something/SM +sometime/S +someway/S +somewhat/S +somewhere +sommelier/MS +somnambulism/M +somnambulist/SM +somnolence/M +somnolent +son/SM +sonar/SM +sonata/SM +sonatina/SM +song/MS +songbird/SM +songbook/SM +songfest/SM +songster/MS +songstress/MS +songwriter/SM +songwriting +sonic +sonnet/SM +sonny/SM +sonogram/SM +sonority/M +sonorous/YP +sonorousness/M +sonsofbitches +soon/RT +soot/M +sooth/MDRSZG +soothe +soother/M +soothing/Y +soothsayer/MS +soothsaying/M +sooty/RT +sop/SM +soph +sophism/M +sophist/MS +sophistic +sophistical +sophisticate/DSMGN +sophisticated/U +sophistication/M +sophistry/SM +sophomore/MS +sophomoric +soporific/MS +soporifically +sopped +sopping +soppy/RT +soprano/MS +sorbet/SM +sorcerer/MS +sorceress/MS +sorcery/M +sordid/PY +sordidness/M +sore/MYTRSP +sorehead/MS +soreness/M +sorghum/M +sorority/SM +sorrel/SM +sorrily +sorriness/M +sorrow/SMDG +sorrowful/YP +sorrowfulness/M +sorry/RTP +sort/FASGDM +sorta +sorted/U +sorter/SM +sortie/DSM +sortieing +sot/SM +sottish +sou'wester +sou/SMH +souffle/SM +souffl/SM +sough/MDG +soughs +sought/U +souk/S +soul/MS +soulful/YP +soulfulness/M +soulless/YP +soulmate/SM +sound/JPSMDRYZTG +soundalike/S +soundbar/S +soundbite/S +soundboard/MS +soundcheck/S +sounder/M +sounding/M +soundless/Y +soundness/UM +soundproof/GDS +soundproofing/M +soundscape/S +soundtrack/SM +soup/MDGS +soupcon/MS +soupy/RT +soupon/MS +sour/MDRYTGSP +source/ADSMG +sourdough/M +sourdoughs +sourish +sourness/M +sourpuss/MS +sousaphone/MS +souse/DSMG +south/M +southbound +southeast/ZMR +southeaster/MY +southeastern +southeastward/S +southerly/SM +southern/SZMR +southerner/M +southernmost +southpaw/SM +southward/MS +southwest/ZMR +southwester/MY +southwestern +southwestward/S +souvenir/SM +sovereign/SM +sovereignty/M +soviet/SM +sow's +sow/ASGD +sower/SM +sown/A +soy/M +soybean/MS +sozzled +spa/SM +space/DRSMZG +spacecraft/MS +spaceflight/MS +spaceman/M +spacemen +spaceport/SM +spacer/M +spaceship/SM +spacesuit/SM +spacewalk/SGMD +spacewoman/M +spacewomen +spacey +spacial +spacier +spaciest +spaciness/M +spacing/M +spacious/YP +spaciousness/M +spade/DSMG +spadeful/MS +spadework/M +spadices +spadix/M +spaghetti/M +spake +spam/MS +spammed +spammer/SM +spamming +span/MS +spandex/M +spangle/DSMG +spangly +spaniel/SM +spank/SMDGJ +spanking/M +spanned +spanner/SM +spanning +spar/MS +spare/DRSMYTGP +spareness/M +spareribs/M +sparing/UY +spark/SMDYG +sparkle/DRSMZG +sparkler/M +sparky/RT +sparred +sparring +sparrow/SM +sparrowhawk/S +sparse/RYTP +sparseness/M +sparsity/M +spartan +spasm/SM +spasmodic +spasmodically +spastic/SM +spat/MS +spate/SM +spathe/SM +spatial/Y +spatted +spatter/SGMD +spatting +spatula/SM +spavin/MD +spawn/SMDG +spay/DGS +speak/SRZGJ +speakeasy/SM +speaker/M +speakerphone/S +spear/SMDG +spearfish/GMDS +speargun +spearhead/GMDS +spearmint/M +spec/MS +special/SMY +specialism/S +specialist/MS +specialization/MS +specialize/GDS +specialty/SM +specie/SM +species/M +specif +specifiable +specific/MS +specifically +specification/M +specificity/M +specified/U +specify/XNZDRSG +specimen/SM +specious/YP +speciousness/M +speck/SMDG +speckle/MGDS +specs/M +spectacle/SM +spectacles/M +spectacular/MYS +spectate/DSG +spectator/SM +specter/AMS +spectra +spectral +spectrometer/MS +spectroscope/MS +spectroscopic +spectroscopy/M +spectrum/M +speculate/DSXGNV +speculation/M +speculative/Y +speculator/MS +sped +speech/MS +speechify/DSG +speechless/YP +speechlessness/M +speechwriter/S +speed/SMRZG +speedboat/SM +speeder/M +speedily +speediness/M +speeding/M +speedometer/MS +speedster/SM +speedup/MS +speedway/SM +speedwell/M +speedy/TPR +speleological +speleologist/MS +speleology/M +spell/JSMDRZG +spellbind/ZGRS +spellbinder/M +spellbound +spellcheck/MDRZGS +spellchecker/M +spelldown/SM +speller/M +spelling/M +spelt +spelunker/MS +spelunking/M +spend/BSRZG +spender/M +spending/M +spendthrift/MS +spent/U +sperm/SM +spermatozoa +spermatozoon/M +spermicidal +spermicide/MS +spew/MDRZGS +spewer/M +sphagnum/MS +sphere/SM +spherical/Y +spheroid/SM +spheroidal +sphincter/MS +sphinx/MS +spic/S +spice/DSMG +spicily +spiciness/M +spick/S +spicule/MS +spicy/PRT +spider/SM +spiderweb/MS +spidery +spiel/SMDG +spiff/SDG +spiffy/TR +spigot/SM +spike/DSMG +spikiness/M +spiky/RPT +spill/SMDG +spillage/MS +spillover/SM +spillway/MS +spin/MS +spinach/M +spinal/SMY +spindle/MGDS +spindly/TR +spine/SM +spineless/YP +spinet/SM +spinnaker/SM +spinner/MS +spinneret/SM +spinney/S +spinning/M +spinoff/MS +spinster/SM +spinsterhood/M +spinsterish +spiny/RT +spiracle/SM +spiraea/MS +spiral/SGMDY +spire's +spire/IFAS +spirea/SM +spirit's +spirit/ISGD +spirited/Y +spiritless +spiritual/MYS +spiritualism/M +spiritualist/MS +spiritualistic +spirituality/M +spirituous +spirochete/SM +spiry +spit/MDGS +spitball/SM +spite/ASM +spiteful/PY +spitefuller +spitefullest +spitefulness/M +spitfire/SM +spitted +spitting +spittle/M +spittoon/MS +spiv/S +splash/GMDS +splashdown/MS +splashily +splashiness/M +splashy/RTP +splat/SM +splatted +splatter/GSMD +splatting +splay/SMDG +splayfeet +splayfoot/MD +spleen/SM +splendid/RYT +splendor/MS +splendorous +splenectomy +splenetic +splice/DRSMZG +splicer/M +spliff/S +spline/S +splint/SZGMDR +splinter/MDG +splintery +split/SM +splitting/MS +splodge/S +splosh/DSG +splotch/MDSG +splotchy/TR +splurge/DSMG +splutter/GMDS +spoil's +spoil/CSDRZG +spoilage/M +spoiled/U +spoiler/CM +spoilsport/MS +spoke/SM +spoken/U +spokesman/M +spokesmen +spokespeople +spokesperson/MS +spokeswoman/M +spokeswomen +spoliation/CM +sponge/DRSMZG +spongecake/M +sponger/M +sponginess/M +spongy/RPT +sponsor/MDGS +sponsorship/M +spontaneity/M +spontaneous/Y +spoof/SMDG +spook/SMDG +spookiness/M +spooky/RPT +spool/SMDG +spoon/SMDG +spoonbill/MS +spoonerism/MS +spoonful/SM +spoor/SMDG +sporadic +sporadically +spore/DSMG +sporran/S +sport/SMDGV +sportiness/M +sporting/Y +sportive/Y +sportscast/MRZGS +sportscaster/M +sportsman/M +sportsmanlike/U +sportsmanship/M +sportsmen +sportspeople +sportsperson +sportswear/M +sportswoman/M +sportswomen +sportswriter/SM +sporty/TPR +spot/CMS +spotless/PY +spotlessness/M +spotlight/GSMD +spotlit +spotted +spotter/MS +spottily +spottiness/M +spotting +spotty/TPR +spousal/MS +spouse/SM +spout/SMDG +sprain/GSMD +sprang +sprat/SM +sprawl/GSMD +spray's +spray/ASDG +sprayer/MS +spread/ZGBSMR +spreadeagled +spreader/M +spreadsheet/MS +spree/DSM +spreeing +sprig/SM +sprigged +sprightliness/M +sprightly/RTP +spring/GSM +springboard/MS +springbok/MS +springily +springiness/M +springlike +springtime/M +springy/RPT +sprinkle/DRSJMZG +sprinkler/M +sprinkling/M +sprint/ZGSMDR +sprinter/M +sprite/SM +spritz/ZGMDRS +spritzer/M +sprocket/MS +sprog/S +sprout/GSMD +spruce/DRSPMYTG +spruceness/M +sprung +spry/RYT +spryness/M +spud/MS +spume/DSMG +spumoni/M +spumy +spun +spunk/SM +spunky/TR +spur/MS +spurge/M +spurious/PY +spuriousness/M +spurn/SDG +spurred +spurring +spurt/SMDG +sputa +sputnik/MS +sputter/MDGS +sputum/M +spy/GDSM +spyglass/MS +spymaster/S +spyware/MS +sq +sqq +squab/SM +squabble/MZGDRS +squabbler/M +squad/SM +squadron/MS +squalid/PTRY +squalidness/M +squall/SGMD +squally +squalor/M +squamous +squander/GDS +square/PDRSMYTG +squareness/M +squarish +squash/GMDS +squashy/TR +squat/SMP +squatness/M +squatted +squatter/MS +squattest +squatting +squaw/SM +squawk/SZGMDR +squawker/M +squeak/SZGMDR +squeaker/M +squeakily +squeakiness/M +squeaky/TRP +squeal/SZGMDR +squealer/M +squeamish/PY +squeamishness/M +squeegee/MDS +squeegeeing +squeeze/BMZGDRS +squeezebox/S +squeezer/M +squelch/GMDS +squelchy +squib/SM +squid/SM +squidgy +squiffy +squiggle/DSMG +squiggly +squint/STGMDR +squire/DSMG +squirm/SGMD +squirmy/RT +squirrel/SGMD +squirt/SGMD +squish/GMDS +squishy/RT +sriracha +ssh +st +stab/MYS +stabbed +stabber/MS +stabbing/MS +stability/IM +stabilization/CM +stabilize/CDSG +stabilizer/MS +stable/DRSMTG +stableman/M +stablemate/S +stablemen +stably/U +staccato/MS +stack/SMDG +stadium/MS +staff's +staff/ASDG +staffer/MS +staffing/M +stag/MDGSJ +stage/SM +stagecoach/MS +stagecraft/M +stagehand/MS +stagestruck +stagey +stagflation/M +stagger/MDGS +staggering/Y +staging/M +stagnancy/M +stagnant/Y +stagnate/DSGN +stagnation/M +stagy/RT +staid/PRYT +staidness/M +stain/SMDG +stained/U +stainless/M +stair/SM +staircase/MS +stairway/MS +stairwell/SM +stake/DSMG +stakeholder/MS +stakeout/SM +stalactite/MS +stalagmite/MS +stale/DRSTGP +stalemate/DSMG +staleness/M +stalk/SMDRJZG +stalker/M +stalking/M +stall's +stall/ISDG +stallholder/S +stallion/MS +stalwart/MYS +stamen/SM +stamina/M +stammer/ZGMDRS +stammerer/M +stammering/Y +stamp/SMDRZG +stampede/MGDS +stamper/M +stance/ISM +stanch/TGDRS +stanchion/SM +stand/SMRJZG +standalone +standard/MS +standardization/M +standardize/DSG +standby/M +standbys +standee/MS +stander/M +standing/M +standoff/MS +standoffish +standout/MS +standpipe/SM +standpoint/MS +standstill/MS +standup/M +stank +stanza/SM +staph/M +staphylococcal +staphylococci +staphylococcus/M +staple/DRSMZG +stapler/M +star/MDRZGS +starboard/M +starburst/S +starch/GMDS +starchily +starchiness/M +starchy/PTR +stardom/M +stardust/M +stare/SM +starer/M +starfish/MS +starfruit +stargaze/DRSZG +stargazer/M +stark/RYPZT +starkness/M +starless +starlet/MS +starlight/M +starling/SM +starlit +starred +starring +starry/TR +starstruck +start/ASMDG +starter/MS +startle/GDS +startling/Y +startup/MS +starvation/M +starve/DSJG +starveling/MS +stash/MDSG +stasis +stat/MS +state/DRSMYGNLX +statecraft/M +stated/U +statehood/M +statehouse/MS +stateless/P +statelessness/M +stateliness/M +stately/PRT +statement/AMS +statemented +statementing +stateroom/MS +stateside +statesman/M +statesmanlike +statesmanship/M +statesmen +stateswoman/M +stateswomen +statewide +static/SM +statically +station/MDRZG +stationary +stationer/M +stationery/M +stationmaster/S +statistic/MS +statistical/Y +statistician/SM +statuary/M +statue/SM +statuesque +statuette/MS +stature/MS +status/MS +statute/MS +statutorily +statutory +staunch/PDRSYTG +staunchness/M +stave/DSMG +stay/MDRZGS +std +stdio +stead/SM +steadfast/YP +steadfastness/M +steadily/U +steadiness/UM +steady/TGPDRSM +steak/SM +steakhouse/SM +steal/SMHG +stealth/M +stealthily +stealthiness/M +stealthy/TPR +steam/SMDRZG +steamboat/MS +steamer/M +steamfitter/SM +steamfitting/M +steaminess/M +steampunk +steamroll/ZGDRS +steamroller/MDG +steamship/MS +steamy/TPR +steed/SM +steel/SMDG +steeliness/M +steelmaker/S +steelworker/SM +steelworks/M +steely/PTR +steelyard/SM +steep/SMDNRYPXTG +steepen/GD +steeple/MS +steeplechase/MS +steeplejack/SM +steepness/M +steer/SMDBG +steerage/M +steering/M +steersman/M +steersmen +stegosauri +stegosaurus/MS +stein/SM +stellar +stem/MS +stemless +stemmed +stemming +stemware/M +stench/MS +stencil/GMDS +steno/SM +stenographer/SM +stenographic +stenography/M +stenosis +stent/SM +stentorian +step/IMS +stepbrother/SM +stepchild/M +stepchildren/M +stepdad/MS +stepdaughter/SM +stepfather/SM +stepladder/MS +stepmom/MS +stepmother/SM +stepparent/SM +steppe/DRSMZG +stepper/M +steppingstone/SM +stepsister/MS +stepson/MS +stereo/SM +stereophonic +stereoscope/MS +stereoscopic +stereotype/DSMG +stereotypical +sterile +sterility/M +sterilization/SM +sterilize/DRSZG +sterilizer/M +sterling/M +stern/SMRYPT +sternness/M +sternum/MS +steroid/MS +steroidal +stertorous +stet/S +stethoscope/MS +stetson/MS +stetted +stetting +stevedore/SM +stew/MDGS +steward/GMDS +stewardess/MS +stewardship/M +stick/SMRZG +sticker/M +stickily +stickiness/M +stickleback/SM +stickler/MS +stickpin/MS +stickup/MS +sticky/PTRSM +stiff/SMDNRYPXTG +stiffen/ZGDR +stiffener/M +stiffening/M +stiffness/M +stifle/DSJG +stifling/Y +stigma/SM +stigmata +stigmatic +stigmatization/M +stigmatize/GDS +stile/SM +stiletto/SM +still's +still/ITGSD +stillbirth/M +stillbirths +stillborn +stiller +stillness/M +stilt/SMD +stilted/Y +stimulant/SM +stimulate/DSGNV +stimulation/M +stimuli +stimulus/M +sting/ZGSMR +stinger/M +stingily +stinginess/M +stingray/SM +stingy/RTP +stink/ZGSMR +stinkbug/SM +stinker/M +stinky/RT +stint/GSMD +stipend/SM +stipendiary/S +stipple/DSMG +stippling/M +stipulate/XDSGN +stipulation/M +stir/MS +stirred +stirrer/SM +stirring/SY +stirrup/SM +stitch's +stitch/ADSG +stitchery/M +stitching/M +stoat/SM +stochastic +stock's +stock/AGSD +stockade/DSMG +stockbreeder/MS +stockbroker/SM +stockbroking/M +stockholder/SM +stockily +stockiness/M +stockinet/M +stockinette/M +stocking/SM +stockist/S +stockpile/MGDS +stockpot/SM +stockroom/MS +stocktaking/M +stocky/RTP +stockyard/MS +stodge +stodgily +stodginess/M +stodgy/RTP +stogie/M +stogy/SM +stoic/SM +stoical/Y +stoicism/M +stoke/DRSZG +stoker/M +stole/SM +stolen +stolid/RYTP +stolidity/M +stolidness/M +stolon/MS +stomach/MDRZG +stomachache/SM +stomacher/M +stomachs +stomp/GSMD +stone/DRSMZG +stonemason/MS +stoner/M +stonewall/GSD +stoneware/M +stonewashed +stonework/M +stonily +stoniness/M +stonkered +stonking +stony/TRP +stood +stooge/MS +stool/SM +stoop/GSMD +stop's +stop/US +stopcock/SM +stopgap/SM +stoplight/MS +stopover/MS +stoppable/U +stoppage/MS +stopped/U +stopper/GSMD +stopping/U +stopple/DSMG +stopwatch/MS +storage/M +store's +store/ADSG +storefront/MS +storehouse/MS +storekeeper/SM +storeroom/SM +stork/SM +storm/GSMD +stormily +storminess/M +stormy/RPT +story/DSM +storyboard/MS +storybook/SM +storyteller/MS +storytelling/M +stoup/SM +stout/TSMRYP +stouthearted +stoutness/M +stove/SM +stovepipe/SM +stow/DGS +stowage/M +stowaway/MS +straddle/DRSMZG +straddler/M +strafe/MGDS +straggle/DRSZG +straggler/M +straggly/TR +straight/SPXTMNRY +straightaway/SM +straightedge/SM +straighten/ZGDR +straightener/M +straightforward/YPS +straightforwardness/M +straightness/M +straightway +strain's +strain/FADSG +strainer/ASM +strait/MNSX +straiten/GD +straitjacket/SGMD +straitlaced +strand/MDSG +strange/PRYZT +strangeness/M +stranger/M +strangle/ZGDRS +stranglehold/SM +strangler/M +strangulate/GNDS +strangulation/M +strap's +strap/US +strapless/MS +strapped/U +strapping/M +strata +stratagem/SM +strategic/S +strategical/Y +strategics/M +strategist/SM +strategy/SM +strati +stratification/M +stratify/DSGN +stratosphere/SM +stratospheric +stratum/M +stratus/M +straw/GSMD +strawberry/SM +stray/GSMD +streak/MDRSZG +streaker/M +streaky/TR +stream/MDRSZG +streamer/M +streamline/DSG +street/MS +streetcar/MS +streetlamp/S +streetlight/SM +streetwalker/SM +streetwise +strength/M +strengthen/AGDS +strengthener/MS +strengths +strenuous/PY +strenuousness/M +strep/M +streptococcal +streptococci +streptococcus/M +streptomycin/M +stress/MDSG +stressed/U +stressful +stretch/BZGMDRS +stretcher/MDG +stretchmarks +stretchy/TR +strew/GSDH +strewn +stria/M +striae +striated +striation/MS +stricken +strict/RYPT +strictness/M +stricture/SM +stridden +stride/MGS +stridency/M +strident/Y +strife/M +strike/MZGRSJ +strikebound +strikebreaker/SM +strikebreaking +strikeout/MS +striker/M +striking/Y +string/MDRSZG +stringency/M +stringent/Y +stringer/M +stringiness/M +stringy/PTR +strip/GSMD +stripe/MS +stripey +stripling/MS +stripped +stripper/MS +stripping +striptease/MZGDRS +stripteaser/M +stripy +strive/GS +striven +strobe/MS +stroboscope/MS +stroboscopic +strode +stroke/MGDS +stroll/MDRSZG +stroller/M +strong/RYT +strongbox/MS +stronghold/MS +strongman/M +strongmen +strongroom/S +strontium/M +strop/SM +strophe/SM +strophic +stropped +stroppily +stropping +stroppy/TRP +strove +struck +structural/Y +structuralism +structuralist/S +structure's +structure/AGDS +structured/U +strudel/SM +struggle/MGDS +strum/SM +strummed +strumming +strumpet/MS +strung/UA +strut/SM +strutted +strutting +strychnine/M +stub/MS +stubbed +stubbing +stubble/M +stubbly +stubborn/RYPT +stubbornness/M +stubby/RT +stucco/MDG +stuccoes +stuck/U +stud/MYS +studbook/MS +studded +studding/M +student/SM +studentship/S +studied/U +studiedly +studio/MS +studious/PY +studiousness/M +studly/RT +study's +study/AGDS +stuff/GSMDJ +stuffily +stuffiness/M +stuffing/M +stuffy/RPT +stultification/M +stultify/DSNG +stumble/DRSMZG +stumbler/M +stump/GSMD +stumpy/TR +stun/S +stung +stunk +stunned +stunner/S +stunning/Y +stunt/GSMD +stuntman +stuntmen +stupefaction/M +stupefy/DSG +stupendous/Y +stupid/TMRYS +stupidity/SM +stupor/MS +sturdily +sturdiness/M +sturdy/TRP +sturgeon/SM +stutter/MDRSZG +stutterer/M +sty/SM +stye/MS +style's +style/ADSG +styli +stylish/PY +stylishness/M +stylist/SM +stylistic/S +stylistically +stylize/DSG +stylus/MS +stymie/MDS +stymieing +styptic/SM +suasion/EM +suave/RYTP +suaveness/M +suavity/M +sub/SM +subaltern/MS +subaqua +subarctic +subarea/MS +subatomic +subbasement/SM +subbed +subbing +subbranch/MS +subcategory/SM +subclass +subcommittee/SM +subcompact/SM +subconscious/PMY +subconsciousness/M +subcontinent/SM +subcontinental +subcontract/MDSG +subcontractor/MS +subculture/MS +subcutaneous/Y +subdivide/GDS +subdivision/SM +subdominant +subdue/DSG +subeditor/S +subfamily/SM +subfreezing +subgroup/MS +subhead/GJMS +subheading/M +subhuman/MS +subj +subject/GVMDS +subjection/M +subjective/Y +subjectivity/M +subjoin/GDS +subjugate/GNDS +subjugation/M +subjunctive/SM +sublease/MGDS +sublet/SM +subletting +sublieutenant/S +sublimate/GNDS +sublimation/M +sublime/YTGDRS +subliminal/Y +sublimity/M +sublingual +submarginal +submarine/MZRS +submariner/M +submerge/GDS +submergence/M +submerse/GNDS +submersible/MS +submersion/M +submicroscopic +submission's/A +submission/MS +submissive/PY +submissiveness/M +submit/AS +submitted/A +submitter +submitting/A +subnormal +suborbital +suborder/MS +subordinate/DSMGN +subordination/IM +suborn/SGD +subornation/M +subparagraph +subplot/MS +subpoena/GMDS +subprime +subprofessional/SM +subprogram/S +subroutine/SM +subscribe/UASDG +subscriber/MS +subscript/MS +subscription/MS +subsection/MS +subsequent/Y +subservience/M +subservient/Y +subset/SM +subside/GDS +subsidence/M +subsidiarity +subsidiary/SM +subsidization/M +subsidize/ZGDRS +subsidizer/M +subsidy/SM +subsist/SDG +subsistence/M +subsoil/M +subsonic +subspace +subspecies/M +substance/SM +substandard +substantial/IY +substantiate/GNDSX +substantiated/U +substantiation/FM +substantive/SMY +substation/MS +substituent/MS +substitute/XMGNDS +substitution/M +substrata +substrate/MS +substratum/M +substructure/SM +subsume/DSG +subsumption/S +subsurface/M +subsystem/SM +subteen/SM +subtenancy/M +subtenant/SM +subtend/SDG +subterfuge/SM +subterranean +subtext/SM +subtitle/DSMG +subtle/TR +subtlety/SM +subtly +subtopic/SM +subtotal/SGMD +subtract/GSD +subtraction/SM +subtrahend/SM +subtropic/S +subtropical +subtropics/M +suburb/MS +suburban/SM +suburbanite/SM +suburbia/M +subvention/SM +subversion/M +subversive/SPMY +subversiveness/M +subvert/SDG +subway/MS +subzero +succeed/GDS +success/VMS +successful/UY +succession/SM +successive/Y +successor/SM +succinct/RYTP +succinctness/M +succor/SGMD +succotash/M +succubi +succubus +succulence/M +succulency/M +succulent/SM +succumb/GDS +such +suchlike +suck/MDRZGS +sucker/GMD +suckle/DSJG +suckling/M +sucrose/M +suction/SMDG +sudden/PY +suddenness/M +suds/M +sudsy/TR +sue/DSG +suede/M +suet/M +suety +suffer/DRZGSJ +sufferance/M +sufferer/M +suffering/M +suffice/DSG +sufficiency/IM +sufficient/IY +suffix/MDSG +suffixation/M +suffocate/GNDS +suffocation/M +suffragan/MS +suffrage/M +suffragette/SM +suffragist/MS +suffuse/DSGN +suffusion/M +sugar/GSMD +sugarcane/M +sugarcoat/GDS +sugarless +sugarplum/MS +sugary/RT +suggest/GVSDR +suggestibility/M +suggestible +suggestion/SM +suggestive/YP +suggestiveness/M +suicidal +suicide/SM +suit/BMDGS +suitability/UM +suitableness/M +suitably/U +suitcase/SM +suite/SM +suited/U +suiting/M +suitor/MS +sukiyaki/M +sulfa/M +sulfate/SM +sulfide/SM +sulfonamides +sulfur/MDSG +sulfuric +sulfurous +sulk/MDGS +sulkily +sulkiness/M +sulky/TRSMP +sullen/RYPT +sullenness/M +sullied/U +sully/GDS +sultan/MS +sultana/SM +sultanate/MS +sultrily +sultriness/M +sultry/RPT +sum/SM +sumac/M +summarily +summarize/GDS +summary/SM +summat +summation/FMS +summed +summer/MDSG +summerhouse/SM +summertime/M +summery +summing +summit/MS +summitry/M +summon/DRSZG +summoner/M +summons/GMDS +sumo/M +sump/MS +sumptuous/PY +sumptuousness/M +sun/SM +sunbath/ZGMDRS +sunbathe +sunbather/M +sunbathing/M +sunbaths +sunbeam/SM +sunbed/S +sunbelt/SM +sunblock/MS +sunbonnet/SM +sunburn/SGMD +sunburst/MS +sundae/MS +sundeck/S +sunder/DSG +sundial/SM +sundown/SM +sundress/S +sundries/M +sundry/S +sunfish/MS +sunflower/MS +sung/U +sunglasses/M +sunhat/S +sunk/N +sunlamp/SM +sunless +sunlight/M +sunlit +sunned +sunniness/M +sunning +sunny/TRP +sunrise/SM +sunroof/SM +sunscreen/MS +sunset/MS +sunshade/MS +sunshine/M +sunshiny +sunspot/SM +sunstroke/M +suntan/MS +suntanned +suntanning +suntrap/S +sunup/M +sup/SZMR +super/M +superabundance/MS +superabundant +superannuate/GNDS +superannuation/M +superb/RYT +supercargo/M +supercargoes +supercharge/ZGDRS +supercharger/M +supercilious/PY +superciliousness/M +supercity/SM +supercomputer/MS +superconducting +superconductive +superconductivity/M +superconductor/SM +superego/MS +supererogation/M +supererogatory +superficial/Y +superficiality/M +superfine +superfluity/M +superfluous/YP +superfluousness/M +superglue +supergrass/S +superhero/MS +superheroes +superhighway/SM +superhuman +superimpose/GDS +superimposition/M +superintend/DSG +superintendence/M +superintendency/M +superintendent/SM +superior/MS +superiority/M +superlative/SMY +superman/M +supermarket/SM +supermen +supermodel/SM +supermom/MS +supernal +supernatural/SY +supernova/MS +supernovae +supernumerary/SM +superpose/GDS +superposition/M +superpower/SM +supersaturate/GNDS +supersaturation/M +superscribe/GDS +superscript/MS +superscription/M +supersede/GDS +supersize/GDS +supersonic +superstar/MS +superstate/S +superstition/MS +superstitious/Y +superstore/MS +superstructure/MS +supertanker/MS +superuser/S +supervene/GDS +supervention/M +supervise/XGNDS +supervised/U +supervision/M +supervisor/MS +supervisory +superwoman/M +superwomen +supine/Y +supp/DRZG +supper/M +suppertime +suppl +supplant/SDG +supple/TLPR +supplement/MDGS +supplemental +supplementary +supplementation/M +suppleness/M +suppliant/SM +supplicant/MS +supplicate/GDS +supplication/M +supplier/M +supply/ZGDRSMXN +support/MDRSBZGV +supportable/UI +supported/U +supporter/M +suppose/GDS +supposed/Y +supposition/MS +suppository/SM +suppress/GDS +suppressant/MS +suppressible +suppression/M +suppressor/SM +suppurate/DSGN +suppuration/M +supra +supranational +supremacist/MS +supremacy/M +supreme/Y +supremo/S +supt +surcease/DSMG +surcharge/DSMG +surcingle/SM +sure/PYTR +surefire +surefooted +sureness/M +surety/SM +surf/MDRZGS +surface's +surface/AGDS +surfboard/MDSG +surfeit/MDSG +surfer/M +surfing/M +surge/DSMG +surgeon/MS +surgery/SM +surgical/Y +surliness/M +surly/PTR +surmise/MGDS +surmount/DGSB +surmountable/I +surname/MS +surpass/GDS +surpassed/U +surplice/MS +surplus/MS +surplussed +surplussing +surprise/DSMGJ +surprising/UY +surreal +surrealism/M +surrealist/SM +surrealistic +surrealistically +surrender/MDSG +surreptitious/PY +surreptitiousness/M +surrey/MS +surrogacy/M +surrogate/SM +surround/GSDJ +surrounding/M +surroundings/M +surtax/MDSG +surtitle/S +surveillance/M +survey's +survey/ADGS +surveying/M +surveyor/SM +survival/SM +survivalist/SM +survive/DSGB +survivor/SM +susceptibility/SM +susceptible/I +sushi/M +suspect/SMDG +suspected/U +suspend/SDRZG +suspender/M +suspense/XMN +suspenseful +suspension/M +suspicion/SM +suspicious/Y +suss/DSG +sustain/SDBG +sustainability +sustainable/U +sustenance/M +sutler/MS +suttee +suture/MGDS +suzerain/MS +suzerainty/M +svelte/TR +swab/MS +swabbed +swabbing +swaddle/DSG +swag/MS +swagged +swagger/SMDRG +swagging +swain/SM +swallow/GSMD +swallowtail/MS +swam +swami/SM +swamp/GSMD +swampland/M +swampy/RT +swan/MS +swank/TGSMDR +swankily +swankiness/M +swanky/RPT +swanned +swanning +swansdown/M +swansong/S +swap/MS +swapped +swapping +sward/SM +swarm/GSMD +swarthy/TR +swash/GMDS +swashbuckler/SM +swashbuckling/M +swastika/SM +swat/MS +swatch/MS +swath/GMDS +swathe/M +swaths +swatted +swatter/SMDG +swatting +sway/MDGS +swayback/MD +swayed/U +swear/ZGSR +swearer/M +swearword/MS +sweat/ZGSMDR +sweatband/MS +sweater/M +sweatpants/M +sweats/M +sweatshirt/SM +sweatshop/MS +sweatsuit/S +sweaty/RT +swede/SM +sweep/ZGSMRJ +sweeper/M +sweeping/MY +sweepings/M +sweepstakes/M +sweet/XTSMNRYP +sweetbread/SM +sweetbriar/SM +sweetbrier/SM +sweetcorn +sweetened/U +sweetener/MS +sweetening/M +sweetheart/SM +sweetie/SM +sweetish +sweetmeat/MS +sweetness/M +swell/TGSMDRJ +swellhead/MDS +swelling/M +swelter/SGMD +swept +sweptback +swerve/MGDS +swerving/U +swift/PTSMRY +swiftness/M +swig/MS +swigged +swigging +swill/GSMD +swim/MS +swimmer/SM +swimming/MY +swimsuit/SM +swimwear +swindle/DRSMZG +swindler/M +swine/SM +swineherd/SM +swing/ZGSMR +swingeing +swinger/M +swinish +swipe/DSMG +swirl/GSMD +swirly +swish/TGMDRS +switch/MDRSZGB +switchback/MS +switchblade/SM +switchboard/SM +switcher/M +swivel/MDGS +swiz +swizz +swizzle/DSG +swollen +swoon/SGMD +swoop/SGMD +swoosh/MDSG +sword/SM +swordfish/MS +swordplay/M +swordsman/M +swordsmanship/M +swordsmen +swore +sworn +swot/S +swotted +swotting +swum +swung +sybarite/SM +sybaritic +sycamore/MS +sycophancy/M +sycophant/SM +sycophantic +syllabi +syllabic +syllabicate/GNDS +syllabication/M +syllabification/M +syllabify/DSNG +syllable/MS +syllabub/S +syllabus/MS +syllogism/MS +syllogistic +sylph/M +sylphic +sylphlike +sylphs +sylvan +symbioses +symbiosis/M +symbiotic +symbiotically +symbol/MS +symbolic +symbolical/Y +symbolism/M +symbolization/M +symbolize/DSG +symmetric/Y +symmetrical/Y +symmetry/SM +sympathetic/U +sympathetically/U +sympathies/M +sympathize/ZGDRS +sympathizer/M +sympathy/SM +symphonic +symphony/SM +symposium/MS +symptom/MS +symptomatic +symptomatically +syn/H +synagogal +synagogue/SM +synapse/MS +synaptic +sync/MDSG +synches +synchronicity +synchronization/SM +synchronize/GDS +synchronous/Y +syncopate/DSGN +syncopation/M +syncope/M +syndicalism +syndicalist/S +syndicate/DSMGN +syndication/M +syndrome/SM +synergism/M +synergistic +synergy/SM +synesthesia +synesthete/S +synesthetic +synfuel/MS +synod/SM +synonym/SM +synonymous +synonymy/M +synopses +synopsis/M +synoptic +synovial +syntactic +syntactical/Y +syntax/M +synthase/SM +syntheses +synthesis/M +synthesize/ZGDRS +synthesizer/M +synthetic/SM +synthetically +synths +syphilis/M +syphilitic/SM +syringe/DSMG +syrup/SM +syrupy +sysadmin/MS +sysop/SM +system/SM +systematic/U +systematical/Y +systematization/M +systematize/GDS +systemic/MS +systemically +systole/SM +systolic +sance/SM +t/SDNXGBJ +tRNA/M +ta +tab/SM +tabbed +tabbing +tabbouleh/M +tabby/SM +tabernacle/SM +tabla/MS +table/MGDS +tableau/M +tableaux +tablecloth/M +tablecloths +tableland/SM +tablespoon/SM +tablespoonful/SM +tablet/SM +tabletop/MS +tableware/M +tabloid/SM +taboo/MDSG +tabor/MS +tabular +tabulate/DSGNX +tabulation/M +tabulator/SM +tachograph +tachographs +tachometer/SM +tachycardia/M +tachyon +tacit/PY +tacitness/M +taciturn/Y +taciturnity/M +tack/ZGMDRS +tacker/M +tackiness/M +tackle/DRSMZG +tackler/M +tacky/RTP +taco/MS +tact/FM +tactful/YP +tactfulness/M +tactic/SM +tactical/Y +tactician/MS +tactile +tactility/M +tactless/PY +tactlessness/M +tad/SM +tadpole/MS +taffeta/M +taffrail/SM +taffy/SM +tag/SM +tagged +tagger/SM +tagging +tagliatelle +tagline/MS +taiga/MS +tail/ACSDMG +tailback/MS +tailboard/S +tailbone/S +tailcoat/MS +tailgate/MZGDRS +tailgater/M +tailless +taillight/MS +tailor/SGMD +tailoring/M +tailpiece/S +tailpipe/SM +tailspin/SM +tailwind/SM +taint/MDSG +tainted/U +take/AIMS +takeaway/S +taken/A +takeoff/MS +takeout/MS +takeover/SM +taker/MS +taking/SM +takings/M +talc/M +talcum/M +tale/MS +talebearer/MS +talent/SMD +talented/U +tali +talisman/MS +talk/ZGMDRS +talkative/PY +talkativeness/M +talker/M +talkie/RSMT +talky +tall/TRP +tallboy/MS +tallier/M +tallish +tallness/M +tallow/M +tallowy +tally/DRSMZG +tallyho/MDGS +talon/MS +talus/MS +tam/SM +tamale/SM +tamarack/MS +tamarind/MS +tambourine/MS +tame/BYZTGDRSP +tameable +tamed/U +tameness/M +tamer/M +tamoxifen +tamp/ZGDRS +tamper/ZGDR +tamperer/M +tampon/SM +tan/SM +tanager/MS +tanbark/M +tandem/SM +tandoori/M +tang/MS +tangelo/MS +tangent/MS +tangential/Y +tangerine/MS +tangibility/IM +tangible/IMS +tangibleness/M +tangibly/I +tangle's +tangle/UDSG +tango/MDSG +tangy/RT +tank/ZGMDRS +tankard/MS +tanker/M +tankful/MS +tanned/U +tanner/SM +tannery/SM +tannest +tannin/M +tanning/M +tansy/M +tantalization/M +tantalize/ZGDRS +tantalizer/M +tantalizing/Y +tantalum/M +tantamount +tantra/M +tantrum/SM +tap/SZGMDR +tapas +tape/MS +tapeline/MS +taper/MDG +tapestry/SM +tapeworm/MS +tapioca/M +tapir/MS +tapped/U +tapper/MS +tappet/MS +tapping +taproom/SM +taproot/SM +tar/SGMD +taramasalata +tarantella/MS +tarantula/SM +tarball/S +tardily +tardiness/M +tardy/TPR +tare/MS +target/MDGS +tariff/MS +tarmac/MS +tarmacadam +tarmacked +tarmacking +tarn/MS +tarnish/GMDS +tarnished/U +taro/MS +tarot/MS +tarp/MS +tarpaulin/MS +tarpon/MS +tarragon/SM +tarred +tarring +tarry/TGDRS +tarsal/MS +tarsi +tarsus/M +tart/PTGMDRYS +tartan/MS +tartar/MS +tartaric +tartness/M +tarty/T +taser/GMDS +task/GMDS +taskmaster/MS +taskmistress/MS +tassel/MDSG +taste/JMZGDRS +tasted/U +tasteful/EPY +tastefulness/EM +tasteless/PY +tastelessness/M +taster/M +tastily +tastiness/M +tasting/M +tasty/TRP +tat/SZR +tatami/MS +tater/M +tatted +tatter/MDSG +tatterdemalion/MS +tattie +tatting/M +tattle/MZGDRS +tattler/M +tattletale/MS +tattoo/MDRSZG +tattooer/M +tattooist/SM +tatty/TRS +tau/SM +taught/UA +taunt/ZGMDRS +taunter/M +taunting/Y +taupe/M +taut/PXTNRY +tauten/DG +tautness/M +tautological/Y +tautologous +tautology/SM +tavern/MS +tawdrily +tawdriness/M +tawdry/RTP +tawny/TRM +tax/BZGMDRS +taxa +taxation/M +taxer/M +taxi/GMDS +taxicab/SM +taxidermist/SM +taxidermy/M +taximeter/MS +taxiway/S +taxman +taxmen +taxon +taxonomic +taxonomical +taxonomist/MS +taxonomy/SM +taxpayer/MS +taxpaying +tb/S +tbsp +tea/SM +teabag/S +teacake/SM +teach/ZGRSBJ +teachable/U +teacher/M +teaching/M +teacup/MS +teacupful/MS +teak/MS +teakettle/SM +teal/MS +tealight/MS +team/GMDS +teammate/MS +teamster/MS +teamwork/M +teapot/MS +tear/GMDS +tearaway/S +teardrop/SM +tearful/Y +teargas/MS +teargassed +teargassing +tearjerker/MS +tearoom/SM +teary/TR +tease/MZGDRS +teasel/MS +teaser/M +teasing/Y +teaspoon/SM +teaspoonful/SM +teat/MS +teatime/S +tech/M +techie/S +technetium/M +technical/Y +technicality/SM +technician/SM +technicolor +technique/SM +techno +technobabble +technocracy/SM +technocrat/MS +technocratic +technological/Y +technologist/MS +technology/SM +technophobe/S +techs +tectonic/S +tectonics/M +ted/S +teddy/S +tedious/PY +tediousness/M +tedium/M +tee/DSMH +teeing +teem/GDS +teen/MS +teenage/RZ +teenager/M +teeny/TR +teenybopper/MS +teepee/MS +teeter/MDSG +teethe/GDS +teething/M +teetotal/RZ +teetotaler/M +teetotalism/M +tektite/SM +tel +telecast/SZGMR +telecaster/M +telecom/M +telecommunication/MS +telecommunications/M +telecommute/ZGDRS +telecommuter/M +telecommuting/M +teleconference/MGDS +teleconferencing/M +telegenic +telegram/MS +telegraph/MDRZG +telegrapher/M +telegraphese +telegraphic +telegraphically +telegraphist/SM +telegraphs +telegraphy/M +telekinesis/M +telekinetic +telemarketer/SM +telemarketing/M +telemeter/SM +telemetry/SM +teleological +teleology +telepathic +telepathically +telepathy/M +telephone/DRSMZG +telephoner/M +telephonic +telephonist/S +telephony/M +telephoto/SM +telephotography/M +teleplay/MS +teleport/DSG +teleportation +teleprinter/MS +teleprocessing/M +teleprompter/SM +telesales +telescope/DSMG +telescopic +telescopically +teletext/MS +telethon/MS +teletype/S +teletypewriter/MS +televangelism/M +televangelist/MS +televise/XGNDS +television/M +teleworker/S +teleworking +telex/MDSG +tell/AGS +teller/SM +telling/Y +telltale/SM +tellurium/M +telly/SM +telnet +temblor/MS +temerity/M +temp/MDRZTGS +temper/MDG +tempera/LSM +temperament/MS +temperamental/Y +temperance/IM +temperate/IY +temperateness/M +temperature/SM +tempest/SM +tempestuous/YP +tempestuousness/M +tempi +template's +template/S +temple/SM +tempo/SM +temporal/Y +temporarily +temporariness/M +temporary/FSM +temporize/ZGDRS +temporizer/M +tempt/SDRZG +temptation/MS +tempter/M +tempting/Y +temptress/MS +tempura/M +ten/BMH +tenability/M +tenable/U +tenably +tenacious/YP +tenaciousness/M +tenacity/M +tenancy/SM +tenant/SMDG +tenanted/U +tenantry/M +tench +tend/IFEDGS +tended/U +tendency/SM +tendentious/YP +tendentiousness/M +tender/SMDRYTGP +tenderfoot/MS +tenderhearted/P +tenderheartedness/M +tenderize/ZGDRS +tenderizer/M +tenderloin/SM +tenderness/M +tendinitis/M +tendon/SM +tendonitis/M +tendril/SM +tenement/SM +tenet/SM +tenfold +tenner/S +tennis/M +tenon/SMDG +tenor/SM +tenpin/SM +tenpins/M +tense/DRSMYTGNXP +tenseness/M +tensile +tension/ESM +tensity/IM +tensor/S +tent/DGSM +tentacle/DSM +tentative/PY +tentativeness/M +tenterhook/MS +tenth/MY +tenths +tenuity/M +tenuous/PY +tenuousness/M +tenure/DSMG +tepee/SM +tepid/YP +tepidity/M +tepidness/M +tequila/SM +terabit/SM +terabyte/MS +terahertz/M +terapixel/MS +terbium/M +tercentenary/SM +tercentennial/SM +teriyaki +term/MDYGS +termagant/MS +terminable/IC +terminal/MYS +terminate/DSGNX +termination/CSM +terminator/S +termini +terminological/Y +terminology/SM +terminus/M +termite/SM +tern/IMS +ternary/SM +terr +terrace/DSMG +terracotta/M +terrain/SM +terrapin/MS +terrarium/SM +terrazzo/MS +terrestrial/SMY +terrible/P +terribleness/M +terribly +terrier/M +terrific +terrifically +terrify/GDS +terrifying/Y +terrine/S +territorial/MS +territoriality +territory/SM +terror/SM +terrorism/M +terrorist/SM +terrorize/DSG +terry/RMZ +terrycloth/M +terse/RYTP +terseness/M +tertiary +tessellate/DSXGN +tessellation/M +test's/AFK +test/AKFCDGS +testable/CF +testament/MS +testamentary +testate/S +testator/MS +testatrices +testatrix/M +testcase/MS +tested/U +tester/KSM +testes +testicle/MS +testicular +testifier/M +testify/ZGDRS +testily +testimonial/MS +testimony/SM +testiness/M +testings +testis/M +testosterone/M +testsuite/SM +testy/PRT +tetanus/M +tetchily +tetchy/PRT +tether/SMDG +tetra/SM +tetracycline/M +tetrahedral +tetrahedron/MS +tetrameter/SM +text/FMS +textbook/SM +textbox/MS +texted +textile/MS +texting +textual/FY +textural +texture/MGDS +thalami +thalamus/M +thaliana +thalidomide/M +thallium/M +than +thane/SM +thank/SDG +thankful/YP +thankfulness/M +thankless/PY +thanklessness/M +thanksgiving/SM +that'd +that'll +that/M +thatch/MDRSZG +thatcher/M +thatching/M +thaw/MDGS +the/JG +theater/SM +theatergoer/SM +theatrical/YS +theatricality/M +theatricals/M +theatrics/M +thee/S +theft/SM +their/S +theism/M +theist/SM +theistic +them +thematic +thematically +theme/DSM +themselves +then/M +thence +thenceforth +thenceforward +theocracy/SM +theocratic +theodolite/S +theologian/SM +theological/Y +theology/SM +theorem/MS +theoretic +theoretical/Y +theoretician/SM +theorist/SM +theorize/DSG +theory/SM +theosophic +theosophical +theosophist/SM +theosophy/M +therapeutic/S +therapeutically +therapeutics/M +therapist/SM +therapy/SM +there/M +thereabout/S +thereafter +thereat +therebetween +thereby +therefor +therefore +therefrom +therein +theremin/SM +thereof +thereon +thereto +theretofore +thereunto +thereupon +therewith +therm/SM +thermal/MYS +thermionic +thermodynamic/S +thermodynamics/M +thermometer/MS +thermometric +thermonuclear +thermoplastic/SM +thermos/MS +thermostat/MS +thermostatic +thermostatically +thesauri +thesaurus/MS +these/S +thesis/M +thespian/SM +theta/SM +thew/MS +they +they'd +they'll +they're +they've +thiamine/M +thick/PMNRYXT +thicken/DRJZG +thickener/M +thickening/M +thicket/MS +thickheaded/M +thickness/MS +thicko/S +thickset +thief/M +thieve/DSG +thievery/M +thieving/M +thievish +thigh/M +thighbone/MS +thighs +thimble/MS +thimbleful/SM +thin/YSP +thine +thing/M +thingamabob/SM +thingamajig/SM +thingumabob/S +thingummy/S +thingy/S +think/SRBZG +thinkable/U +thinker/M +thinking's +thinned +thinner/MS +thinness/M +thinnest +thinning +third/SMY +thirst/SGMD +thirstily +thirstiness/M +thirsty/TPR +thirteen/SMH +thirteenth/M +thirteenths +thirtieth/M +thirtieths +thirty/HSM +this +thistle/MS +thistledown/M +thither +tho +thole/SM +thong/SM +thoracic +thorax/MS +thorium/M +thorn/SM +thorniness/M +thorny/PRT +thorough/RYPT +thoroughbred/MS +thoroughfare/MS +thoroughgoing +thoroughness/M +those +thou/MS +though +thought/SM +thoughtful/YP +thoughtfulness/M +thoughtless/PY +thoughtlessness/M +thousand/MHS +thousandfold +thousandth/M +thousandths +thraldom/M +thrall/SMDG +thralldom/M +thrash/JMDRSZG +thrasher/M +thrashing/M +thread/SMDRZG +threadbare +threader/M +threadlike +thready/TR +threat/SMNX +threaten/DG +threatening/Y +three/SM +threefold +threepence/M +threescore/MS +threesome/SM +threnody/SM +thresh/MDRSZG +thresher/M +threshold/SM +threw +thrice +thrift/SM +thriftily +thriftiness/M +thriftless +thrifty/PTR +thrill/SMDRZG +thriller/M +thrilling/Y +thrive/DSG +throat/SM +throatily +throatiness/M +throaty/RTP +throb/SM +throbbed +throbbing +throe/SM +thrombi +thrombolytic +thromboses +thrombosis/M +thrombotic +thrombus/M +throne's +throne/S +throng/GSMD +throttle/DRSMZG +throttler/M +through +throughout +throughput/M +throughway/MS +throw/SMRZG +throwaway/SM +throwback/SM +thrower/M +thrown +thru +thrum/SM +thrummed +thrumming +thrush/MS +thrust/GSM +thruway/MS +thud/MS +thudded +thudding +thug/MS +thuggery/M +thuggish +thulium/M +thumb/SMDG +thumbnail/SM +thumbprint/SM +thumbscrew/SM +thumbtack/SM +thump/SMDG +thumping/M +thunder/ZGMDRS +thunderbolt/SM +thunderclap/SM +thundercloud/MS +thunderer/M +thunderhead/SM +thunderous/Y +thundershower/SM +thunderstorm/SM +thunderstruck +thundery +thunk/S +thus +thwack/ZGSMDR +thwacker/M +thwart/GSMD +thy +thyme/M +thymine/M +thymus/MS +thyroid/MS +thyroidal +thyself +ti/MRZ +tiara/SM +tibia/M +tibiae +tibial +tic/SM +tick/MDRZGS +ticker/M +ticket/GSMD +ticking/M +tickle/DRSMZG +tickler/M +ticklish/YP +ticklishness/M +ticktacktoe/M +ticktock/MS +tidal/Y +tidbit/SM +tiddler/S +tiddly +tiddlywink/S +tiddlywinks/M +tide/MGJDS +tideland/SM +tidemark/S +tidewater/MS +tideway/MS +tidily/U +tidiness/UM +tidings/M +tidy/DRSMTGP +tie's +tie/AUSD +tieback/MS +tiebreak/RSZ +tiebreaker/M +tiepin/S +tier/MD +tiff/MDGS +tiger/SM +tigerish +tight/SNRYPXT +tighten/ZGDR +tightener/M +tightfisted +tightness/M +tightrope/MS +tights/M +tightwad/MS +tigress/MS +til +tilapia +tilde/SM +tile/MZGDRS +tiler/M +tiling/M +till's +till/EDRZGS +tillable +tillage/M +tiller/EM +tilt/MDGS +timber/SMDG +timberland/M +timberline/MS +timbre/SM +timbrel/SM +time/MYZGJDRS +timekeeper/MS +timekeeping/M +timeless/PY +timelessness/M +timeline/MS +timeliness/UM +timely/UPRT +timeout/SM +timepiece/MS +timer/M +timescale/S +timeserver/SM +timeserving/M +timeshare/S +timestamp/SMD +timetable/DSMG +timeworn +timezone +timid/RYTP +timidity/M +timidness/M +timing/M +timorous/PY +timorousness/M +timothy/M +timpani/M +timpanist/SM +tin/SM +tincture/MGDS +tinder/M +tinderbox/MS +tine/MS +tinfoil/M +ting/MDYG +tinge/SM +tingeing +tingle/DSMGJ +tingling/M +tininess/M +tinker/ZGSMDR +tinkerer/M +tinkle/DSMG +tinned +tinniness/M +tinning +tinnitus/M +tinny/PRT +tinplate/M +tinpot +tinsel/GSMD +tinsmith/M +tinsmiths +tint/MDGS +tintinnabulation/MS +tintype/MS +tinware/M +tiny/RTP +tip/SM +tipped +tipper/SM +tippet/SM +tippex/GDS +tipping +tipple/DRSMZG +tippler/M +tipsily +tipsiness/M +tipster/MS +tipsy/RPT +tiptoe/DSM +tiptoeing +tiptop/SM +tirade/SM +tiramisu/MS +tire's +tire/AGDS +tired/PRYT +tiredness/M +tireless/YP +tirelessness/M +tiresome/PY +tiresomeness/M +tissue/SM +tit/SM +titan/SM +titanic +titanium/M +titch/S +titchy +tithe/DRSMZG +tither/M +titian/M +titillate/DSGN +titillating/Y +titillation/M +titivate/DSGN +titivation/M +title/DSMG +titled/U +titleholder/MS +titlist/MS +titmice +titmouse/M +titter/SGMD +tittivate/DSGN +tittivation/M +tittle/SM +titty/S +titular +tizz +tizzy/SM +tn +tnpk +to/IU +toad/MS +toadstool/MS +toady/DSMG +toadyism/M +toast/SMDRZG +toaster/M +toastmaster/SM +toastmistress/MS +toasty/TRS +tobacco/MS +tobacconist/SM +toboggan/ZGSMDR +tobogganer/M +tobogganing/M +toccata/S +tocsin/SM +today/M +toddle/DRSMZG +toddler/M +toddy/SM +toe/DSM +toecap/SM +toehold/MS +toeing +toenail/MS +toerag/S +toff/S +toffee/SM +tofu/M +tog/SM +toga/MDS +together/P +togetherness/M +togged +togging +toggle/DSMG +togs/M +toil/MDRZGS +toiler/M +toilet/MDGS +toiletry/SM +toilette/M +toilsome +toke/MGDS +token/SM +tokenism/M +told/AU +tole/M +tolerable/I +tolerably/I +tolerance/IM +tolerances +tolerant/IY +tolerate/GNDS +toleration/M +toll/MDGS +tollbooth/M +tollbooths +tollgate/SM +tollway/SM +toluene/M +tom/SM +tomahawk/SGMD +tomato/M +tomatoes +tomb/MDGS +tombola/S +tomboy/MS +tomboyish +tombstone/MS +tomcat/MS +tome/MS +tomfoolery/SM +tomographic +tomography/M +tomorrow/MS +tomtit/MS +ton/SM +tonal/Y +tonality/SM +tone's +tone/IZGDRS +tonearm/SM +toneless/Y +toner/IM +tong/MDGS +tongue/MGDS +tongueless +tonic/SM +tonight/M +tonnage/SM +tonne/SM +tonsil/MS +tonsillectomy/SM +tonsillitis/M +tonsorial +tonsure/DSMG +tony/RT +too +took/A +tool's +tool/ADGS +toolbar/SM +toolbox/MS +toolkit +toolmaker/MS +toot/MDRZGS +tooter/M +tooth/MD +toothache/MS +toothbrush/MS +toothily +toothless +toothpaste/SM +toothpick/SM +toothsome +toothy/RT +tootle/GDS +tootsie/S +top/SM +topaz/MS +topcoat/SM +topdressing/SM +topee/S +topflight +topi/S +topiary/M +topic/SM +topical/Y +topicality/M +topknot/SM +topless +topmast/SM +topmost +topnotch +topographer/SM +topographic +topographical/Y +topography/SM +topological/Y +topology +topped +topper/MS +topping/SM +topple/GDS +topsail/SM +topside/SM +topsoil/M +topspin/M +toque/SM +tor/SM +torah/M +torahs +torch/GMDS +torchbearer/MS +torchlight/M +tore +toreador/MS +torment/SMDG +tormenting/Y +tormentor/MS +torn +tornado/M +tornadoes +torpedo/GMD +torpedoes +torpid/Y +torpidity/M +torpor/M +torque/MGDS +torrent/SM +torrential +torrid/YP +torridity/M +torridness/M +torsion/M +torsional +torso/SM +tort's +tort/EFAS +torte/SM +tortellini/M +tortilla/MS +tortoise/MS +tortoiseshell/SM +tortoni/M +tortuous/PY +tortuousness/M +torture/DRSMZG +torturer/M +torturous +torus +tosh +toss/MDRSZG +tossup/MS +tot/SGMD +total/GSMDY +totalitarian/SM +totalitarianism/M +totality/SM +totalizator/SM +tote/MS +totem/SM +totemic +totted +totter/ZGMDRS +totterer/M +totting +toucan/MS +touch/AGMDS +touchdown/SM +touche/BJ +touched/U +touchily +touchiness/M +touching/Y +touchline/S +touchpaper/S +touchscreen/MS +touchstone/MS +touchy/RPT +touch +tough/XTGMDNRYP +toughen/ZGDR +toughener/M +toughie/SM +toughness/M +toughs +toupee/MS +tour/CFSGDM +tourism/M +tourist/MS +touristic +touristy +tourmaline/M +tournament/SM +tourney/MS +tourniquet/MS +tousle/GDS +tout/MDGS +tow/SZGMDR +toward/S +towboat/MS +towel/JGSMD +towelette/SM +toweling/M +tower/GMD +towhead/MDS +towhee/MS +towline/MS +town/MS +townee/S +townhouse/MS +townie/MS +townsfolk/M +township/MS +townsman/M +townsmen +townspeople/M +townswoman/M +townswomen +towpath/M +towpaths +towrope/SM +toxemia/M +toxic +toxicity/SM +toxicological +toxicologist/SM +toxicology/M +toxin/SM +toy/SGMD +toyboy/S +tr +trabecula +trabecular +trabecule +trace/JDRSMZG +traceable/U +tracer/M +tracery/SM +traceur/SM +trachea/M +tracheae +tracheal +tracheotomy/SM +tracing/M +track/ZGSMDR +trackback/SM +trackball/SM +tracker/M +trackless +tracksuit/S +tract's +tract/CEKFAS +tractability/IM +tractable/I +tractably/I +traction/FEACKM +tractor/FCKMS +trad +trade/JDRSMZG +trademark/SGMD +trader/M +tradesman/M +tradesmen +tradespeople/M +tradeswoman/M +tradeswomen +trading/M +tradition/MS +traditional/Y +traditionalism/M +traditionalist/SM +traduce/DRSZG +traducer/M +traffic/SM +trafficked +trafficker/SM +trafficking/M +tragedian/SM +tragedienne/MS +tragedy/SM +tragic +tragically +tragicomedy/SM +tragicomic +trail/ZGSMDR +trailblazer/MS +trailblazing/M +trailer/M +train/ZGSMDRB +trained/U +trainee/SM +trainer/M +training/M +trainload/MS +trainman/M +trainmen +trainspotter/S +trainspotting +traipse/DSMG +trait/SM +traitor/SM +traitorous/Y +trajectory/SM +tram/MS +tramcar/S +tramlines +trammed +trammel/SGMD +trammeled/U +tramming +tramp/ZGSMDR +tramper/M +trample/DRSMZG +trampler/M +trampoline/MGDS +tramway/S +trance/MS +tranche/S +tranquil/RYT +tranquility/M +tranquilize/ZGDRS +tranquilizer/M +tranquillity/M +trans/I +transact/DGS +transaction/SM +transactor/MS +transatlantic +transceiver/SM +transcend/GSD +transcendence/M +transcendent +transcendental/Y +transcendentalism/M +transcendentalist/SM +transcontinental +transcribe/ZGDRS +transcriber/M +transcript/MS +transcription/SM +transducer/MS +transect/DSG +transept/MS +transfect/SGD +transfer/MBS +transferal/MS +transference/M +transferred +transferring +transfiguration/M +transfigure/GDS +transfinite +transfix/DSG +transform/BSZGMDR +transformation/SM +transformer/M +transfuse/DSXGN +transfusion/M +transgender/SD +transgenderism +transgene/S +transgenic +transgress/GDS +transgression/SM +transgressor/SM +transience/M +transiency/M +transient/SMY +transistor/SM +transistorize/DSG +transit/SGMD +transition/GSMD +transitional/Y +transitive/ISMY +transitiveness/M +transitivity/M +transitory +transl +translatable/U +translate/DSGNBX +translated/U +translation/M +translator/SM +transliterate/DSGNX +transliteration/M +translocation +translucence/M +translucency/M +translucent/Y +transmigrate/GNDS +transmigration/M +transmissible +transmission's/A +transmission/MS +transmit/S +transmittable +transmittal/M +transmittance/M +transmitted +transmitter/SM +transmitting +transmogrification/M +transmogrify/DSNG +transmutation/SM +transmute/BDSG +transnational/MS +transoceanic +transom/SM +transpacific +transparency/SM +transparent/Y +transpiration/M +transpire/DSG +transplant/MDGS +transplantation/M +transpolar +transponder/SM +transport/BSZGMDR +transportation/M +transporter/M +transpose/DSG +transposition/MS +transsexual/SM +transsexualism/M +transship/SL +transshipment/M +transshipped +transshipping +transubstantiation/M +transverse/MYS +transvestism/M +transvestite/MS +trap/MS +trapdoor/MS +trapeze/SM +trapezium/SM +trapezoid/SM +trapezoidal +trappable +trapped +trapper/SM +trapping/S +trappings/M +trapshooting/M +trash/GMDS +trashcan/MS +trashiness/M +trashy/RPT +trauma/MS +traumatic +traumatically +traumatize/GDS +travail/SGMD +travel/MDRSZGJ +traveled/U +traveler/M +traveling/M +travelog/SM +travelogue/MS +traversal/SM +traverse/DSMG +travesty/GDSM +trawl/ZGSMDR +trawler/M +tray/MS +treacherous/PY +treacherousness/M +treachery/SM +treacle/M +treacly +tread/AGSM +treadle/DSMG +treadmill/MS +treas +treason/BM +treasonous +treasure/DRSMZG +treasurer/M +treasury/SM +treat/AGSMD +treatable +treated/U +treatise/SM +treatment/MS +treaty/SM +treble/MGDS +tree/MDS +treeing +treeless +treelike +treeline +treetop/SM +trefoil/SM +trek/MS +trekked +trekker/SM +trekking +trellis/GMDS +trematode/MS +tremble/DSMG +tremendous/Y +tremolo/SM +tremor/MS +tremulous/PY +tremulousness/M +trench's +trench/ADSG +trenchancy/M +trenchant/Y +trencher/MS +trencherman/M +trenchermen +trend/GSMD +trendily +trendiness/M +trendsetter/S +trendsetting +trendy/RSMPT +trepidation/M +trespass/MDRSZG +trespasser/M +tress/EMS +trestle/MS +trews +trey/MS +triad/SM +triage/MGS +trial/ASM +trialed +trialing +triangle/SM +triangular/Y +triangulate/GNDS +triangulation/M +triathlete/S +triathlon/SM +tribal +tribalism/M +tribe/SM +tribesman/M +tribesmen +tribeswoman/M +tribeswomen +tribulation/SM +tribunal/SM +tribune/MS +tributary/SM +tribute's +tribute/FS +trice/M +tricentennial/MS +triceps/MS +triceratops/M +trichina/M +trichinae +trichinosis/M +trick/GSMD +trickery/M +trickily +trickiness/M +trickle/MGDS +trickster/SM +tricky/TRP +tricolor/SM +tricycle/SM +trident/MS +tried/U +triennial/MYS +trier/SM +trifecta/SM +trifle/MZGDRS +trifler/M +trifocals/M +trig/M +trigger/MDSG +triglyceride/MS +trigonometric +trigonometrical +trigonometry/M +trike/SM +trilateral/S +trilby/SM +trill/GSMD +trillion/SMH +trillionth/M +trillionths +trillium/M +trilobite/SM +trilogy/SM +trim/PMYS +trimaran/MS +trimester/SM +trimmed/U +trimmer/SM +trimmest +trimming/SM +trimmings/M +trimness/M +trimonthly +trinitrotoluene/M +trinity/SM +trinket/SM +trio/MS +trip/MYS +tripartite +tripe/M +triple/MGDS +triplet/SM +triplex/MS +triplicate/MGDS +tripod/MS +tripodal +tripos +tripped +tripper/SM +tripping +triptych/M +triptychs +tripwire/S +trireme/SM +trisect/SDG +trisection/M +trite/FPYT +triteness/FM +triter +tritium/M +triumph/GMD +triumphal +triumphalism +triumphalist +triumphant/Y +triumphs +triumvir/MS +triumvirate/SM +trivalent +trivet/MS +trivia/M +trivial/Y +triviality/SM +trivialization/M +trivialize/GDS +trivium/M +trochaic +trochee/SM +trod/AU +trodden/A +troglodyte/SM +troika/MS +troll/SGMD +trolley/SM +trolleybus/MS +trollop/SM +trombone/MS +trombonist/MS +tromp/SGD +tron/S +troop/SZGMDR +trooper/M +troopship/MS +trope/SM +trophy/SM +tropic/MS +tropical/Y +tropics/M +tropism/SM +troposphere/SM +trot/MS +troth/M +trotted +trotter/SM +trotting +troubadour/MS +trouble/DSMG +troubled/U +troublemaker/MS +troubleshoot/DRZGS +troubleshooter/M +troubleshooting/M +troubleshot +troublesome/Y +trough/M +troughs +trounce/DRSZG +trouncer/M +troupe/MZGDRS +trouper/M +trouser/SM +trousers/M +trousseau/M +trousseaux +trout/SM +trove/SM +trow/DSG +trowel/MDSG +troy/S +truancy/M +truant/GMDS +truce/SM +truck/SZGMDR +trucker/M +trucking/M +truckle/MGDS +truckload/SM +truculence/M +truculent/Y +trudge/MGDS +true/MTGDRS +truelove/SM +truffle/MS +trug/S +truism/MS +truly/U +trump/SGMD +trumpery/M +trumpet/ZGMDRS +trumpeter/M +truncate/GNDS +truncation/M +truncheon/SM +trundle/MZGDRS +trundler/M +trunk/SGM +truss/GMDS +trust/ESGMD +trustee/MS +trusteeship/SM +trustful/EY +trustfulness/M +trusting/Y +trustworthiness/M +trustworthy/TPR +trusty/TRSM +truth/ZMR +truther/M +truthful/UYP +truthfulness/UM +truthiness +truths/U +try's +try/AGDS +trying/Y +tryout/SM +tryptophan +tryst/SMDG +tsarists +tsetse/MS +tsp +tsunami/SM +ttys +tub/SZGMDR +tuba/MS +tubal +tubby/TR +tube/MS +tubeless/M +tuber/M +tubercle/SM +tubercular +tuberculin/M +tuberculosis/M +tuberculous +tuberose/M +tuberous +tubful/MS +tubing/M +tubular +tubule/MS +tuck/MDRSZG +tucker/MDG +tuft/MDRSZG +tufter/M +tug/SM +tugboat/MS +tugged +tugging +tuition/IM +tularemia/M +tulip/SM +tulle/M +tum/S +tumble/DRSMZG +tumbledown +tumbler/M +tumbleweed/SM +tumbling/M +tumbrel/SM +tumbril/SM +tumescence/M +tumescent +tumid +tumidity/M +tummy/SM +tumor/SM +tumorous +tumult/SM +tumultuous/Y +tun/SZGMDR +tuna/MS +tundra/SM +tune/MS +tuneful/YP +tunefulness/M +tuneless/Y +tuner/M +tuneup/SM +tungsten/M +tunic/SM +tunnel/JSMDRZG +tunneler/M +tunny/SM +tuple/S +tuppence +tuppenny +tuque/SM +turban/SMD +turbid +turbidity/M +turbine/SM +turbo/SM +turbocharge/ZGDRS +turbocharger/M +turbofan/SM +turbojet/SM +turboprop/SM +turbot/SM +turbulence/M +turbulent/Y +turd/MS +turducken/SM +tureen/SM +turf/MDSG +turfy +turgid/Y +turgidity/M +turkey/SM +turmeric/SM +turmoil/MS +turn/AMDRSZG +turnabout/SM +turnaround/SM +turnbuckle/SM +turncoat/SM +turner/AM +turning/MS +turnip/SM +turnkey/MS +turnoff/MS +turnout/MS +turnover/MS +turnpike/MS +turnstile/SM +turntable/SM +turpentine/M +turpitude/M +turps +turquoise/SM +turret/SMD +turtle/SM +turtledove/SM +turtleneck/SMD +tush/MS +tusk/MDS +tussle/DSMG +tussock/MS +tussocky +tut/SM +tutelage/M +tutelary +tutor/SMDG +tutored/U +tutorial/SM +tutorship/M +tutted +tutti/SM +tutting +tutu/MS +tux/MS +tuxedo/SM +twaddle/MZGDRS +twaddler/M +twain/M +twang/SMDG +twangy/RT +twas +twat/S +tweak/SMDG +twee +tweed/SM +tweeds/M +tweedy/RT +tween +tweep/S +tweet's +tweet/ASDG +tweeter/SM +tweezers/M +twelfth/M +twelfths +twelve/SM +twelvemonth/M +twelvemonths +twentieth/M +twentieths +twenty/SMH +twerk/SDG +twerp/SM +twice +twiddle/MGDS +twiddly +twig/MS +twigged +twigging +twiggy/TR +twilight/M +twilit +twill/MD +twin/MDRSZG +twine/SM +twiner/M +twinge/DSMG +twinight +twink/SY +twinkle/MGJDS +twinkling/M +twinned +twinning +twinset/S +twirl/SMDRZG +twirler/M +twirly +twist's +twist/USDG +twister/MS +twisty/TR +twit/MS +twitch/GMDS +twitchy/RT +twitted +twitter/MDSG +twittery +twitting +twixt +two/SM +twofer/SM +twofold +twopence/SM +twopenny +twosome/SM +twp +tycoon/SM +tying/AU +tyke/MS +tympani/M +tympanic +tympanist/MS +tympanum/SM +type's +type/AGDS +typecast/GS +typeface/MS +typescript/MS +typeset/S +typesetter/MS +typesetting/M +typewrite/RSZG +typewriter/M +typewriting/M +typewritten +typewrote +typhoid/M +typhoon/MS +typhus/M +typical/UY +typicality/M +typification/M +typify/NGDS +typing/M +typist/SM +typo/MS +typographer/SM +typographic +typographical/Y +typography/M +typology/SM +tyrannic +tyrannical/Y +tyrannize/GDS +tyrannosaur/MS +tyrannosaurus/MS +tyrannous +tyranny/SM +tyrant/SM +tyro/MS +u/S +ubiquitous/Y +ubiquity/M +udder/SM +ufologist/SM +ufology/M +ugh +ugliness/M +ugly/RTP +uh +uhf +ukase/SM +ukulele/SM +ulcer/SM +ulcerate/XDSGN +ulceration/M +ulcerous +ulna/M +ulnae +ulnar +ulster/MS +ult +ulterior +ultimate/MY +ultimatum/MS +ultimo +ultra/SM +ultraconservative/SM +ultrahigh +ultralight/SM +ultramarine/M +ultramodern +ultrasonic +ultrasonically +ultrasound/MS +ultraviolet/M +ululate/DSGNX +ululation/M +um +umbel/SM +umber/M +umbilical +umbilici +umbilicus/M +umbra/SM +umbrage/M +umbrella/SM +umiak/SM +umlaut/MS +ump/SGMD +umpire/MGDS +umpteen/H +unabridged/MS +unacceptability +unacceptable +unaccommodating +unaccountably +unadventurous +unaesthetic +unalterably +unambitious +unanimity/M +unanimous/Y +unapparent +unappetizing +unappreciative +unassertive +unassuming/Y +unavailing/Y +unaware/S +unbeknown +unbeknownst +unbend/SG +unbent +unbid +unblinking/Y +unblushing/Y +unbosom/DG +unbound/D +unbreakable +unbroken +uncanny/T +uncap/S +uncaring +unceasing/Y +unchangeable +uncharacteristic +uncharitable +unchaste/RT +uncial/M +uncle/SM +unclean/DRPT +uncleanly/T +unclear/DRT +uncomfortable +uncommon/T +uncomplaining/Y +uncomplicated +uncomprehending/Y +uncompromising/Y +unconditional/Y +uncongenial +unconscionable +unconscionably +unconscious/M +unconstitutional/Y +uncontrollably +uncontroversial +uncool +uncooperative +uncouth/Y +uncrushable +unction/SM +unctuous/YP +unctuousness/M +uncut +undaunted/Y +undecided/SM +undemonstrative/Y +undeniably +under +underachieve/LZGDRS +underachiever/M +underact/SDG +underage +underappreciated +underarm/SM +underbelly/SM +underbid/S +underbidding +underbrush/M +undercarriage/MS +undercharge/MGDS +underclass/MS +underclassman/M +underclassmen +underclothes/M +underclothing/M +undercoat/GJSMD +undercoating/M +undercover +undercurrent/SM +undercut/SM +undercutting +underdeveloped +underdevelopment/M +underdog/SM +underdone +underemployed +underemployment/M +underestimate/DSMGNX +underestimation/M +underexpose/GDS +underexposure/MS +underfed +underfeed/GS +underfloor +underflow +underfoot +underfunded +underfur/M +undergarment/SM +undergo/G +undergoes +undergone +undergrad/S +undergraduate/SM +underground/MS +undergrowth/M +underhand +underhanded/PY +underhandedness/M +underlain +underlay/SM +underlie/S +underline/MGDS +underling/MS +underlip/SM +underlying +undermanned +undermentioned +undermine/GDS +undermost +underneath/M +underneaths +undernourished +undernourishment/M +underpaid +underpants/M +underpart/MS +underpass/MS +underpay/GSL +underpayment/SM +underpin/S +underpinned +underpinning/MS +underplay/DGS +underpopulated +underprivileged +underproduction/M +underrate/GDS +underrepresented +underscore/DSMG +undersea/S +undersecretary/SM +undersell/GS +undersexed +undershirt/SM +undershoot/SG +undershorts/M +undershot +underside/MS +undersign/DGS +undersigned/M +undersized +underskirt/SM +undersold +understaffed +understand/SGBJ +understandably +understanding/MY +understate/DSLG +understatement/SM +understood +understudy/GDSM +undertake/ZGJRS +undertaken +undertaker/M +undertaking/M +underthings/M +undertone/MS +undertook +undertow/SM +underused +underutilized +undervaluation/M +undervalue/DSG +underwater +underway +underwear/M +underweight/M +underwent +underwhelm/DGS +underwire/DS +underworld/MS +underwrite/ZGRS +underwriter/M +underwritten +underwrote +undesirable/MS +undies/M +undo +undoubted/Y +undramatic +undreamt +undue +undulant +undulate/DSXGN +undulation/M +undying +unearthliness/M +unease/M +uneasy/T +uneatable +uneconomic +unemployed/M +unending +unenterprising +unequal/DY +unerring/Y +unessential +uneven/Y +unexceptionably +unexcited +unexciting +unexpected/YP +unexpectedness/M +unfailing/Y +unfair/PTRY +unfaltering +unfamiliar +unfathomably +unfed +unfeeling/Y +unfeminine +unfit/S +unfitting +unfix/GDS +unflagging/Y +unflappability/M +unflappable +unflappably +unflattering +unflinching/Y +unforgettably +unforgivably +unfortunate/MS +unfriendly/T +unfrock/DG +unfruitful +unfunny +ungainliness/M +ungainly/RPT +ungenerous +ungentle +ungodly/T +ungraceful/Y +ungrudging +unguarded +unguent/SM +ungulate/MS +unhandy/T +unhappy/T +unhealthful +unhealthy/T +unhistorical +unholy/T +unhurt +unicameral +unicellular +unicorn/SM +unicycle/SM +unidirectional +unification/AM +uniform/SMDYG +uniformity/M +unify/AGDSN +unilateral/Y +unilateralism +unimportant +unimpressive +uninformative +uninhibited/Y +uninstall/BSZGDR +uninsured +unintelligent +unintended +uninteresting +uninterrupted/Y +uninviting +union/ASM +unionism/M +unionist/MS +unique/YTRP +uniqueness/M +unisex/M +unison/M +unitary +unite/AEGSD +unitedly +unities +unitize/DSG +unity/EM +univalent +univalve/SM +universal/MYS +universality/M +universalize/DSG +universe/SM +university/SM +unjust/Y +unkempt +unkind/T +unkindly/T +unknowable/M +unknown/SM +unleaded/M +unless +unlike/PB +unlikely/T +unlit +unlock/DSG +unlovable +unlovely/TR +unloving +unlucky/T +unman/S +unmanly/T +unmarried +unmeaning +unmentionable/MS +unmentionables/M +unmet +unmindful +unmissable +unmistakably +unmoral +unmovable +unmusical +unnecessary +unnerving/Y +unobservant +unoffensive +unofficial/Y +unoriginal +unpeople +unperceptive +unpersuasive +unpick/GDS +unpin/S +unpleasing +unpolitical +unpopular +unpractical +unprecedented/Y +unprofessional/Y +unpromising +unpropitious +unquestioning/Y +unquiet/TR +unread/B +unready +unreal +unreasoning +unregenerate +unrelated +unrelenting/Y +unrelieved/Y +unremarkable +unremitting/Y +unrepentant +unreported +unrepresentative +unrest/M +unripe/TR +unroll/GDS +unromantic +unruliness/M +unruly/RTP +unsafe/YTR +unsavory +unscathed +unseeing/Y +unseemly/T +unseen/M +unsentimental +unset +unshakable +unshakably +unshakeable +unshapely +unshockable +unshorn +unsightliness/M +unsightly/PT +unsmiling +unsociable +unsocial +unsold +unsound/PRYT +unspeakable +unspeakably +unspecific +unspectacular +unsporting +unstable +unsteady/TRP +unstinting/Y +unstrapping +unsubstantial +unsubtle +unsuitable +unsure +unsuspecting/Y +unsymmetrical +untactful +unthinkably +unthinking/Y +untidy/PTR +until +untimely/T +untiring/Y +untouchable/MS +untoward +untrue/RT +untrustworthy +untruth/M +unutterable +unutterably +unwarrantable +unwary/T +unwavering +unwed +unwelcome/G +unwell +unwieldiness/M +unwieldy/TRP +unwise/RYT +unworried +unworthy/T +unwound +unwrapping +unyielding +up/S +upbeat/MS +upbraid/SGD +upbringing/MS +upchuck/SGD +upcoming +upcountry/M +update/MGDRS +updraft/MS +upend/SGD +upfront +upgrade/MGDS +upheaval/MS +upheld +uphill/MS +uphold/ZGRS +upholder/M +upholster/ASGD +upholsterer/MS +upholstery/M +upkeep/M +upland/MS +uplift/JSMDG +upload/SDG +upmarket +upmost +upon +upped +upper/SM +uppercase/M +upperclassman/M +upperclassmen +upperclasswoman +upperclasswomen +uppercut/MS +uppercutting +uppermost +upping +uppish +uppity +upraise/DSG +uprear/GSD +upright/MYPS +uprightness/M +uprising/SM +upriver +uproar/SM +uproarious/Y +uproot/GSD +upscale +upset/SM +upsetting +upshot/SM +upside/SM +upsilon/MS +upstage/GDS +upstairs +upstanding +upstart/MDSG +upstate/M +upstream +upstroke/SM +upsurge/MGDS +upswing/MS +uptake/SM +uptempo +upthrust/GSM +uptick/SM +uptight +uptown/M +uptrend +upturn/GSMD +upward/SY +upwind +uracil/M +uranium/M +urban +urbane/RYT +urbanity/M +urbanization/M +urbanize/DSG +urbanologist/MS +urbanology/M +urchin/SM +urea/M +uremia/M +uremic +ureter/SM +urethane/M +urethra/M +urethrae +urethral +urge/MGDS +urgency/M +urgent/Y +uric +urinal/SM +urinalyses +urinalysis/M +urinary +urinate/GNDS +urination/M +urine/M +urn/SM +urogenital +urological +urologist/MS +urology/M +ursine +urticaria/M +usability/M +usable/UA +usage/SM +use/AEDSMG +used/U +useful/PY +usefulness/M +useless/YP +uselessness/M +user/MS +username/MS +usher/SMDG +usherette/SM +usu +usual's +usual/UY +usurer/SM +usurious +usurp/SDRZG +usurpation/M +usurper/M +usury/M +utensil/SM +uteri +uterine +uterus/M +utilitarian/MS +utilitarianism/M +utility/SM +utilization/M +utilize/GBDS +utmost/M +utopia/SM +utopian/MS +utter/SDYG +utterance/SM +uttermost/M +uveitis +uvula/SM +uvular/MS +uxorious +v/AS +vac/S +vacancy/SM +vacant/Y +vacate/DSG +vacation/ZGMDRS +vacationer/M +vacationist/SM +vaccinate/GNDSX +vaccination/M +vaccine/SM +vacillate/XGNDS +vacillation/M +vacuity/M +vacuole/MS +vacuous/YP +vacuousness/M +vacuum/GSMD +vagabond/SMDG +vagabondage/M +vagarious +vagary/SM +vagina/SM +vaginae +vaginal/Y +vagrancy/M +vagrant/MS +vague/RYTP +vagueness/M +vagus +vain/RYT +vainglorious/Y +vainglory/M +val +valance/MS +vale/MS +valediction/MS +valedictorian/SM +valedictory/SM +valence/MS +valency/SM +valentine/SM +valet/SMDG +valetudinarian/MS +valetudinarianism/M +valiance/M +valiant/Y +valid/Y +validate/IGNDS +validation/IM +validations +validator/S +validity/IM +validness/M +valise/SM +valley/SM +valor/M +valorous/Y +valuable/MS +valuate/DSG +valuation/CAMS +value's +value/CAGSD +valueless +valuer/SM +valve/DSMG +valveless +valvular +vamoose/DSG +vamp/AMDGS +vampire/SM +van/SM +vanadium/M +vandal/SM +vandalism/M +vandalize/DSG +vane/MS +vanguard/MS +vanilla/SM +vanish/JDSG +vanity/SM +vanned +vanning +vanquish/ZGDRS +vanquisher/M +vantage/SM +vape/GDS +vapid/YP +vapidity/M +vapidness/M +vapor/SM +vaporization/M +vaporize/DRSZG +vaporizer/M +vaporous +vaporware +vapory +vaquero/MS +var/S +variability/IM +variable/ISM +variably/I +variance/SM +variant/MS +variate/NX +variation/M +varicolored +varicose +varied/U +variegate/DSGN +variegation/M +varietal/SM +variety/SM +various/Y +varlet/SM +varmint/MS +varnish/GMDS +varnished/U +varsity/SM +vary/DSG +varying/U +vascular +vase/MS +vasectomy/SM +vasoconstriction +vasomotor +vassal/SM +vassalage/M +vast/MRYTSP +vastness/M +vat/SM +vatted +vatting +vaudeville/M +vaudevillian/MS +vault/SMDRZG +vaulter/M +vaulting/M +vaunt/SMDG +vb +veal/M +vector/SGMD +veejay/SM +veep/MS +veer/MDGS +veg/SM +vegan/SM +veganism +vegeburger/S +veges +vegetable/SM +vegetarian/SM +vegetarianism/M +vegetate/GNVDS +vegetation/M +vegged +vegges +veggie/SM +veggieburger/S +vegging +vehemence/M +vehemency/M +vehement/Y +vehicle/MS +vehicular +veil's +veil/UDGS +vein/MDGS +vela +velar/SM +veld/MS +vellum/M +velocipede/MS +velocity/SM +velodrome/S +velour/MS +velum/M +velvet/M +velveteen/M +velvety +venal/Y +venality/M +venation/M +vend/DGS +vendetta/SM +vendible +vendor/MS +veneer/MDGS +venerability/M +venerable +venerate/DSGN +veneration/M +venereal +vengeance/M +vengeful/AY +venial +venireman/M +veniremen +venison/M +venom/M +venomous/Y +venous +vent's +vent/DGS +ventilate/GNDS +ventilation/M +ventilator/SM +ventral +ventricle/SM +ventricular +ventriloquism/M +ventriloquist/SM +ventriloquy/M +venture/DSMG +venturesome/PY +venturesomeness/M +venturous/PY +venturousness/M +venue/ASM +veracious/Y +veracity/M +veranda/SM +verandah/M +verandahs +verb/KMS +verbal/MYS +verbalization/M +verbalize/GDS +verbatim +verbena/SM +verbiage/MS +verbose/Y +verbosity/M +verboten +verdant/Y +verdict/SM +verdigris/GMDS +verdure/M +verge's +verge/FDSG +verger/MS +verifiable/U +verification/M +verified/U +verify/DSNG +verily +verisimilitude/M +veritable +veritably +verity/SM +vermicelli/M +vermiculite/M +vermiform +vermilion/M +vermin/M +verminous +vermouth/M +vernacular/MS +vernal +vernier/SM +veronica/M +verruca/SM +verrucae +versa +versatile +versatility/M +verse/AFNGMSDX +versed/U +versification/M +versifier/M +versify/ZGNDRS +version/AFIMS +versioned +versioning +verso/SM +versus +vert/A +vertebra/M +vertebrae +vertebral +vertebrata +vertebrate/IMS +vertex/MS +vertical/MYS +vertices +vertiginous +vertigo/M +verve/M +very/RT +vesicle/SM +vesicular +vesiculate +vesper/MS +vessel/MS +vest's +vest/ILDGS +vestal/MS +vestibule/MS +vestige/SM +vestigial/Y +vesting/M +vestment/IMS +vestry/SM +vestryman/M +vestrymen +vet/SM +vetch/MS +veteran/SM +veterinarian/MS +veterinary/SM +veto/MDG +vetoes +vetted +vetting +vex/GDS +vexation/SM +vexatious/Y +vhf +vi +via +viability/M +viable +viably +viaduct/SM +vial/MS +viand/SM +vibe/MS +vibes/M +vibraharp/SM +vibrancy/M +vibrant/Y +vibraphone/MS +vibraphonist/MS +vibrate/GNDSX +vibration/M +vibrato/MS +vibrator/SM +vibratory +viburnum/SM +vicar/SM +vicarage/SM +vicarious/YP +vicariousness/M +vice/CMS +viced +vicegerent/SM +vicennial +viceregal +viceroy/MS +vichyssoise/M +vicing +vicinity/M +vicious/YP +viciousness/M +vicissitude/SM +victim/MS +victimization/M +victimize/GDS +victor/MS +victorious/Y +victory/SM +victual/SMDG +vicuna/MS +vicua/MS +videlicet +video/GSMD +videocassette/SM +videoconferencing +videodisc/MS +videophone/MS +videotape/DSMG +videotex +vie/DS +view/AMDRSZG +viewer/AM +viewership/M +viewfinder/SM +viewing/SM +viewpoint/MS +vigesimal +vigil/SM +vigilance/M +vigilant/Y +vigilante/SM +vigilantism/M +vigilantist/M +vignette/DSMG +vignettist/MS +vigor/M +vigorous/Y +vii +viii +viking/MS +vile/YTPR +vileness/M +vilification/M +vilify/DSNG +villa/SM +village/RSMZ +villager/M +villain/SM +villainous +villainy/SM +villein/SM +villeinage/M +villi +villus/M +vim/M +vinaigrette/M +vincible/I +vindicate/XDSGN +vindication/M +vindicator/MS +vindictive/PY +vindictiveness/M +vine/MS +vinegar/M +vinegary +vineyard/MS +vino/M +vinous +vintage/MS +vintner/MS +vinyl/SM +viol/MBS +viola/SM +violable/I +violate/GNDSX +violation/M +violator/SM +violence/M +violent/Y +violet/MS +violin/MS +violincello/S +violinist/SM +violist/MS +violoncellist/SM +violoncello/MS +viper/SM +viperous +virago/M +viragoes +viral +vireo/SM +virgin/MS +virginal/SM +virginity/M +virgule/MS +virile +virility/M +virologist/SM +virology/M +virtual/Y +virtualization +virtue/SM +virtuosity/M +virtuoso/SM +virtuous/YP +virtuousness/M +virulence/M +virulent/Y +virus/MS +visa/MDSG +visage/MS +viscera +visceral/Y +viscid +viscose/M +viscosity/M +viscount/SM +viscountcy/SM +viscountess/MS +viscous +viscus/M +vise/ACMGDS +visibility/IM +visible/I +visibly/I +vision/KGDSM +visionary/SM +visit's +visit/ASGD +visitant/MS +visitation/MS +visitor/MS +visor/SM +vista/SM +visual/SMY +visualization/SM +visualize/DRSZG +visualizer/M +vita/M +vitae +vital/SY +vitality/M +vitalization/AM +vitalize/CAGSD +vitals/M +vitamin/MS +vitiate/GNDS +vitiation/M +viticulture/M +viticulturist/MS +vitreous +vitrifaction/M +vitrification/M +vitrify/GNDS +vitrine/SM +vitriol/M +vitriolic +vitriolically +vittles/M +vituperate/GNVDS +vituperation/M +viva/MS +vivace +vivacious/PY +vivaciousness/M +vivacity/M +vivaria +vivarium/SM +vivid/RYTP +vividness/M +vivify/ADSG +viviparous +vivisect/DGS +vivisection/M +vivisectional +vivisectionist/SM +vixen/SM +vixenish/Y +viz +vizier/SM +vlf +vocab +vocable/MS +vocabulary/SM +vocal/SMY +vocalic +vocalist/SM +vocalization/MS +vocalize/DSG +vocation/FIKASM +vocational/Y +vocative/MS +vociferate/DSGN +vociferation/M +vociferous/YP +vociferousness/M +vodka/SM +vogue/SM +voguish +voice/IDSMG +voiced/U +voiceless/PY +voicelessness/M +voicemail/SM +void/MDSGB +voila +voile/M +voil +vol/S +volatile +volatility/M +volatilize/DSG +volcanic +volcano/M +volcanoes +volcanological +volcanologist/MS +volcanology/M +vole/MS +volition/M +volitional +volley/GSMD +volleyball/MS +volt/AMS +voltage/MS +voltaic +voltmeter/SM +volubility/M +voluble +volubly +volume/SM +voluminous/YP +voluminousness/M +voluntarily/I +voluntarism/M +voluntary/SM +volunteer/SGMD +volunteerism/M +voluptuary/SM +voluptuous/PY +voluptuousness/M +volute/SM +vomit/SMDG +voodoo/GSMD +voodooism/M +voracious/PY +voraciousness/M +voracity/M +vortex/MS +votary/SM +vote's +vote/CGVDS +voter/SM +vouch/DRSZG +voucher/M +vouchsafe/DSG +vow/SGMD +vowel/SM +voyage/MZGDRS +voyager/M +voyageur/SM +voyeur/MS +voyeurism/M +voyeuristic +vulcanization/M +vulcanize/GDS +vulgar/RYT +vulgarian/MS +vulgarism/MS +vulgarity/SM +vulgarization/M +vulgarize/ZGDRS +vulgarizer/M +vulnerabilities +vulnerability/IM +vulnerable/I +vulnerably/I +vulpine +vulture/SM +vulturous +vulva/M +vulvae +vuvuzela/MS +vying +w/DNXTGVJ +wabbit/S +wack/MRTS +wackiness/M +wacko/SM +wacky/RPT +wad/SZGMDR +wadded +wadding/M +waddle/DSMG +wade/MS +wader/M +waders/M +wadge/S +wadi/MS +wafer/SM +waffle/MZGDRS +waffler/M +waft/MDGS +wag/SZGMDR +wage/MS +waged/U +wager/ZGMDR +wagerer/M +wagged +waggery/SM +wagging +waggish/YP +waggishness/M +waggle/MGDS +wagon/ZSMR +wagoner/M +wagtail/SM +waif/MS +wail/MDRZGS +wailer/M +wailing/M +wain/MS +wainscot/SJMDG +wainscoting/M +wainscotted +wainscotting/MS +wainwright/MS +waist/SM +waistband/MS +waistcoat/MS +waistline/MS +wait/MDRZGS +waiter/M +waiting/M +waitperson/MS +waitress/MS +waitstaff/M +waive/DRSZG +waiver/M +wake/MGJDS +wakeful/PY +wakefulness/M +waken/GSD +waldo/S +waldoes +wale/MGDS +walk/MDRZGS +walkabout/S +walkaway/MS +walker/M +walkies +walking/M +walkout/SM +walkover/MS +walkway/SM +wall/MDGS +wallaby/SM +wallah +wallahs +wallboard/M +wallet/MS +walleye/DSM +wallflower/MS +wallop/MDSJG +walloping/M +wallow/MDSG +wallpaper/SMDG +wally/S +walnut/MS +walrus/MS +waltz/ZGMDRS +waltzer/M +wampum/M +wan/GPDY +wand/MS +wander/DRSJZG +wanderer/M +wanderings/M +wanderlust/SM +wane/MS +wangle/MZGDRS +wangler/M +wank/DRZGS +wanna +wannabe/SM +wannabee/S +wanner +wanness/M +wannest +want/MDGS +wanted/U +wanton/MDYSPG +wantonness/M +wapiti/MS +war/SM +warble/MZGDRS +warbler/M +warbonnet/SM +ward/AMDGS +warden/MS +warder/MS +wardress/S +wardrobe/SM +wardroom/SM +ware/MS +warehouse/DSMG +warez +warfare/M +warhead/MS +warhorse/SM +warily/U +wariness/UM +warlike +warlock/MS +warlord/MS +warm/PDRYHZTGS +warmblooded +warmer/M +warmhearted/P +warmheartedness/M +warmish +warmness/M +warmonger/SMG +warmongering/M +warmth/M +warmup/MS +warn/JDGS +warning/M +warp/MDGS +warpaint +warpath/M +warpaths +warplane/MS +warrant/GMDS +warranted/U +warranty/DSMG +warred +warren/MS +warring +warrior/SM +warship/SM +wart/MS +warthog/SM +wartime/M +warty/TR +wary/UPRT +was +wasabi +wash/BJMDRSZG +washable/SM +washbasin/SM +washboard/SM +washbowl/SM +washcloth/M +washcloths +washed/U +washer/M +washerwoman/M +washerwomen +washing/M +washout/MS +washrag/MS +washroom/MS +washstand/SM +washtub/MS +washy/TR +wasn't +wasp/MS +waspish/YP +waspishness/M +wassail/SMDG +wast +wastage/M +waste/DRSMZG +wastebasket/MS +wasteful/PY +wastefulness/M +wasteland/SM +wastepaper/M +waster/M +wastewater +wastrel/SM +watch/BZGMDRS +watchable/U +watchband/MS +watchdog/SM +watcher/M +watchful/YP +watchfulness/M +watchmaker/MS +watchmaking/M +watchman/M +watchmen +watchstrap/S +watchtower/SM +watchword/MS +water/GSMD +waterbed/MS +waterbird/SM +waterboard/MDJSG +waterboarding/M +waterborne +watercolor/MS +watercourse/SM +watercraft/M +watercress/M +waterfall/SM +waterfowl/SM +waterfront/MS +waterhole/SM +wateriness/M +waterlily/SM +waterline/MS +waterlogged +watermark/MDGS +watermelon/SM +watermill/MS +waterpower/M +waterproof/SMDG +waterproofing/M +waters/M +watershed/MS +waterside/MS +waterspout/SM +watertight +waterway/MS +waterwheel/SM +waterworks/M +watery/PTR +watt/MS +wattage/M +wattle/MGDS +wave/MZGDRS +waveband/S +waveform +wavelength/M +wavelengths +wavelet/SM +wavelike +waver/ZGMDR +waverer/M +wavering/Y +waviness/M +wavy/PRT +wax/GMDNS +waxiness/M +waxwing/SM +waxwork/SM +waxy/RPT +way/SM +waybill/SM +wayfarer/MS +wayfaring/SM +waylaid +waylay/RSZG +waylayer/M +wayside/SM +wayward/PY +waywardness/M +wazoo/S +we +we'd +we'll +we're +we've +weak/PNRYXT +weaken/DRZG +weakener/M +weakfish/MS +weakish +weakling/SM +weakness/MS +weal/MHS +wealth/M +wealthiness/M +wealthy/TRP +wean/DGS +weapon/MS +weaponize/GDS +weaponless +weaponry/M +wear/MRBJSZG +wearable/U +wearer/M +wearied/U +wearily +weariness/M +wearisome/Y +weary/TGDRSP +weasel/MDYSG +weather/SMDG +weatherboard/SG +weathercock/MS +weathering/M +weatherization/M +weatherize/DSG +weatherman/M +weathermen +weatherperson/MS +weatherproof/GSD +weatherstrip/S +weatherstripped +weatherstripping/M +weave/DRSMZG +weaver/M +weaving/M +web/SM +webbed +webbing/M +webcam/MS +webcast/SMG +webdesign/MS +webfeet +webfoot/M +webinar/SM +webisode/MS +weblog/MS +webmaster/SM +webmistress/MS +website/SM +wed/AS +wedded/A +wedder +wedding/SM +wedge/DSMG +wedgie/MS +wedlock/M +wee/RSMT +weed/MDRSZG +weeder/M +weedkiller/S +weedless +weedy/TR +weeing +week/MYS +weekday/SM +weekend/SZGMDR +weekly/SM +weeknight/SM +ween/DSG +weenie/MTRS +weensy/RT +weeny +weep/MRJSZG +weeper/M +weepie +weepy/TRSM +weevil/MS +weft/MS +weigh's +weigh/AGD +weighbridge/S +weighs/A +weight/MDSJG +weighted/U +weightily +weightiness/M +weightless/YP +weightlessness/M +weightlifter/MS +weightlifting/M +weighty/PTR +weir/MS +weird/PTRY +weirdie/MS +weirdness/M +weirdo/MS +welcome/MGDS +weld/MDRBSZG +welder/M +welfare/M +welkin/M +well/MDPSG +wellhead/SM +wellie +wellington/MS +wellness/M +wellspring/MS +welly/S +welsh/ZGDRS +welsher/M +welt/MDRSZG +welter/GMD +welterweight/SM +wen/M +wench/MS +wend/DSG +went +wept +were +weren't +werewolf/M +werewolves +west/M +westbound +westerly/SM +western/SZMR +westerner/M +westernization/M +westernize/GDS +westernmost +westward/S +wet/SMYP +wetback/SM +wetland/SM +wetness/M +wetter/SM +wettest +wetting +wetware/S +whack/SJZGMDR +whacker/M +whale/DRSMZG +whaleboat/MS +whalebone/M +whaler/M +whaling/M +wham/MS +whammed +whamming +whammy/SM +wharf/M +wharves +what/MS +whatchamacallit/MS +whatever +whatnot/M +whatshername +whatshisname +whatsit/S +whatsoever +wheal/SM +wheat/MN +wheatgerm +wheatmeal +whee +wheedle/DRSZG +wheedler/M +wheel/SMDRG +wheelbarrow/SM +wheelbase/SM +wheelchair/SM +wheelhouse/MS +wheelie/SM +wheelwright/MS +wheeze/DSMG +wheezily +wheeziness/M +wheezy/PRT +whelk/SMD +whelm/SDG +whelp/SMDG +when/MS +whence +whenever +whensoever +where/SM +whereabouts/M +whereas +whereat +whereby +wherefore/MS +wherein +whereof +whereon +wheresoever +whereto +whereupon +wherever +wherewith +wherewithal/M +wherry/SM +whet/S +whether +whetstone/SM +whetted +whetting +whew +whey/M +which +whichever +whiff/SMDG +whiffletree/MS +while/DSMG +whilom +whilst +whim/MS +whimper/MDGS +whimsical/Y +whimsicality/M +whimsy/SM +whine/DRSMZG +whiner/M +whinge/DRSZG +whingeing +whinny/GDSM +whiny/RT +whip/MS +whipcord/M +whiplash/MS +whipped +whipper/MS +whippersnapper/MS +whippet/MS +whipping/SM +whippletree/SM +whippoorwill/MS +whipsaw/MDGS +whir/MS +whirl/SMDG +whirligig/MS +whirlpool/MS +whirlwind/MS +whirlybird/SM +whirred +whirring +whisk/SMDRZG +whisker/MD +whiskery +whiskey/MS +whisky/SM +whiskys +whisper/MDRSZG +whisperer/M +whist/M +whistle/MZGDRS +whistler/M +whit/MDNRSXTGJ +white/SPM +whitebait +whiteboard/S +whitecap/SM +whitefish/MS +whitehead/MS +whiten/ZGDRJ +whitener/M +whiteness/M +whitening/M +whiteout/SM +whitepaper/MS +whitetail/MS +whitewall/SM +whitewash/MDSG +whitewater/M +whitey/SM +whither +whiting/M +whitish +whittle/ZGDRS +whittler/M +whiz/M +whizkid/M +whizz/MDSG +whizzbang/MS +who'd +who'll +who're +who've +who/M +whoa +whodunit/MS +whoever +whole/SMP +wholefood/S +wholegrain +wholehearted/YP +wholeheartedness/M +wholemeal +wholeness/M +wholesale/MZGDRS +wholesaler/M +wholesome/UP +wholesomely +wholesomeness/UM +wholewheat +wholly +whom +whomever +whomsoever +whoop/SMDRZG +whoopee/S +whooper/M +whoosh/MDSG +whop/S +whopped +whopper/SM +whopping +whore/SMG +whorehouse/MS +whoreish +whorish +whorl/SMD +whose +whoso +whosoever +whup/S +whupped +whupping +why'd +why/M +whys +wick/MDRSZ +wicked/TPRY +wickedness/M +wicker/M +wickerwork/M +wicket/SM +wide/YTRP +widemouthed +widen/SDRZG +widener/M +wideness/M +widescreen/MS +widespread +widgeon/MS +widget/S +widow/SMDRZG +widower/M +widowhood/M +width/M +widths +wield/SDRZG +wielder/M +wiener/SM +wienie/SM +wife/MY +wifeless +wig/SM +wigeon/SM +wigged +wigging +wiggle/DRSMZG +wiggler/M +wiggly/TR +wight/SM +wiglet/SM +wigwag/SM +wigwagged +wigwagging +wigwam/SM +wiki/MS +wild/MRYSTP +wildcard/MS +wildcat/MS +wildcatted +wildcatter/MS +wildcatting +wildebeest/MS +wilderness/MS +wildfire/MS +wildflower/SM +wildfowl/M +wildlife/M +wildness/M +wilds/M +wile/MGDS +wilful/P +wilfulness/M +wiliness/M +will/MDS +willful/PY +willfulness/M +willies/M +willing/UPY +willingness/UM +williwaw/MS +willow/SM +willowy +willpower/M +willy/S +wilt/MDSG +wily/RTP +wimp/MDSG +wimpish +wimple/DSMG +wimpy/RT +win/SGMD +wince/DSMG +winch/MDSG +wind's +wind/UASG +windbag/SM +windblown +windbreak/SZMR +windbreaker/M +windburn/MD +windcheater/S +windchill/M +winded +winder/SM +windfall/MS +windflower/MS +windily +windiness/M +winding's +windjammer/SM +windlass/MS +windless +windmill/MDGS +window/SMDG +windowless +windowpane/SM +windowsill/SM +windpipe/MS +windproof +windrow/SM +windscreen/SM +windshield/SM +windsock/MS +windstorm/MS +windsurf/ZGDRS +windsurfer/M +windsurfing/M +windswept +windup/SM +windward/M +windy/RTP +wine/MS +wineglass/MS +winegrower/MS +winemaker/MS +winery/SM +wing/MDRZG +wingding/MS +wingless +winglike +wingnut/SM +wingspan/MS +wingspread/SM +wingtip/SM +wink/MDRSZG +winker/M +winkle/DSMG +winnable/U +winner/SM +winning/MYS +winnow/ZGSDR +winnower/M +wino/MS +winsome/YTRP +winsomeness/M +winter/GSMD +wintergreen/M +winterize/GDS +wintertime/M +wintry/TR +winy/RT +wipe/MZGDRS +wiper/M +wire's +wire/AGDS +wired/S +wirehair/MS +wireless/MS +wiretap/MS +wiretapped +wiretapper/SM +wiretapping/M +wiriness/M +wiring/M +wiry/RTP +wisdom/M +wise/MYTGDRS +wiseacre/SM +wisecrack/MDSG +wiseguy/S +wish/MDRSZG +wishbone/SM +wisher/M +wishful/Y +wishlist's +wisp/MS +wispy/RT +wist +wisteria/SM +wistful/YP +wistfulness/M +wit/SM +witch/MDSG +witchcraft/M +witchery/M +with +withal +withdraw/SG +withdrawal/MS +withdrawn +withdrew +withe/DRSMZG +wither/JGD +withering/Y +withers/M +withheld +withhold/SG +withholding/M +within/M +without +withstand/GS +withstood +witless/PY +witlessness/M +witness/MDSG +wits/M +witted +witter/SGD +witticism/SM +wittily +wittiness/M +witting/UY +witty/RPT +wive/GDS +wiz/S +wizard/SMY +wizardry/M +wizened +wk/Y +woad/M +wobble/MGDS +wobbliness/M +wobbly/RTP +wodge/S +woe/SM +woebegone +woeful/YP +woefuller +woefullest +woefulness/M +wog/S +wok/SMN +woke +wold/MS +wolf/MDSG +wolfhound/SM +wolfish +wolfram/M +wolverine/SM +wolves +woman/M +womanhood/M +womanish +womanize/DRSZG +womanizer/M +womankind/M +womanlike/M +womanliness/M +womanly/RPT +womb/MS +wombat/MS +womble/S +women/M +womenfolk/SM +womenfolks/M +won't +won/M +wonder/MDGLS +wonderful/YP +wonderfulness/M +wondering/Y +wonderland/MS +wonderment/M +wondrous/Y +wonk/MS +wonky/TR +wont/MD +wonted/U +woo/SZGDR +wood/MDNSG +woodbine/M +woodblock/MS +woodcarver/MS +woodcarving/SM +woodchuck/MS +woodcock/SM +woodcraft/M +woodcut/SM +woodcutter/SM +woodcutting/M +wooden/RYTP +woodenness/M +woodiness/M +woodland/SM +woodlice +woodlot/SM +woodlouse +woodman/M +woodmen +woodpecker/MS +woodpile/SM +woods/M +woodshed/SM +woodsiness/M +woodsman/M +woodsmen +woodsy/RTP +woodwind/MS +woodwork/MRZG +woodworker/M +woodworking/M +woodworm/S +woody/TPRSM +wooer/M +woof/MDRSZG +woofer/M +wool/MNX +woolen/M +woolgathering/M +wooliness +woolliness/M +woolly/RSMPT +woozily +wooziness/M +woozy/TRP +wop/MS! +word's +word/ADSG +wordage/M +wordbook/SM +wordily +wordiness/M +wording/SM +wordless/Y +wordplay/M +wordsmith +wordsmiths +wordy/TPR +wore +work's +work/ADJSG +workable/U +workaday +workaholic/SM +workaround/S +workbasket/S +workbench/MS +workbook/MS +workday/SM +worker/MS +workfare/M +workflow/MS +workforce/M +workhorse/SM +workhouse/SM +working's +workingman/M +workingmen +workings/M +workingwoman/M +workingwomen +workload/MS +workman/M +workmanlike +workmanship/M +workmate/S +workmen +workout/SM +workplace/MS +workroom/MS +works/M +worksheet/MS +workshop/MS +workshy +workstation/MS +worktable/MS +worktop/S +workup/MS +workweek/SM +world/SM +worldlier +worldliness/UM +worldly/UTP +worldview/SM +worldwide +worm/MDSG +wormhole/MS +wormwood/M +wormy/TR +worn/U +worried/Y +worrier/M +worriment/M +worrisome +worry/ZGDRSMJ +worrying/Y +worrywart/SM +worse/M +worsen/DSG +worship/ZGSMDR +worshiper/M +worshipful +worst/SGMD +worsted/M +wort/M +worth/M +worthies +worthily/U +worthiness/UM +worthless/PY +worthlessness/M +worthwhile +worthy's +worthy/UPRT +wot +wotcha +would've +would/S +wouldn't +wouldst +wound/SGMDR +wove/A +woven/AU +wow/SGMD +wpm +wrack/GSMD +wraith/M +wraiths +wrangle/DRSMZGJ +wrangler/M +wrap's +wrap/US +wraparound/SM +wrapped/U +wrapper/SM +wrapping/MS +wrasse/MS +wrath/M +wrathful/Y +wreak/SGD +wreath/MDSG +wreathe +wreaths +wreck/SZGMDR +wreckage/M +wrecker/M +wren/MS +wrench/MDSG +wrest/SGMD +wrestle/MZGDRS +wrestler/M +wrestling/M +wretch/MS +wretched/TPRY +wretchedness/M +wriggle/MZGDRS +wriggler/M +wriggly +wright/MS +wring/SZGMR +wringer/M +wrinkle/MGDS +wrinkled/U +wrinkly/TRSM +wrist/SM +wristband/MS +wristwatch/MS +writ/MRBJSZG +write/S +writer/M +writhe/MGDS +writing/M +written/AU +wrong/STGMPDRY +wrongdoer/SM +wrongdoing/SM +wrongful/PY +wrongfulness/M +wrongheaded/YP +wrongheadedness/M +wrongness/M +wrote/A +wroth +wrought +wrung +wry/Y +wryer +wryest +wryness/M +wt +wunderkind/S +wurst/SM +wuss/MS +wussy/RSMT +x +xci +xcii +xciv +xcix +xcvi +xcvii +xenon/M +xenophobe/MS +xenophobia/M +xenophobic +xerographic +xerography/M +xerox/MDSG +xi/SM +xii +xiii +xiv +xix +xor +xref/S +xterm/M +xv +xvi +xvii +xviii +xx +xxi +xxii +xxiii +xxiv +xxix +xxv +xxvi +xxvii +xxviii +xxx +xxxi +xxxii +xxxiii +xxxiv +xxxix +xxxv +xxxvi +xxxvii +xxxviii +xylem/M +xylene +xylophone/SM +xylophonist/MS +y +y'all +ya +yacht/SMDG +yachting/M +yachtsman/M +yachtsmen +yachtswoman/M +yachtswomen +yahoo/SM +yak/SM +yakked +yakking +yam/SM +yammer/SZGMDR +yammerer/M +yang/M +yank/MDSG +yap/SM +yapped +yapping +yard/MS +yardage/MS +yardarm/MS +yardman/M +yardmaster/MS +yardmen +yardstick/MS +yarmulke/SM +yarn/MS +yarrow/M +yashmak/S +yaw/SGMD +yawl/MS +yawn/MDRSZG +yawner/M +yaws/M +yd +ye/RST +yea/SM +yeah/M +yeahs +year/MYS +yearbook/MS +yearling/MS +yearlong +yearly/SM +yearn/GSJD +yearning/M +yeast/SM +yeasty/RT +yegg/MS +yell/MDSG +yellow/MDRTGPS +yellowhammer/S +yellowish +yellowness/M +yellowy +yelp/MDSG +yen/SM +yeoman/M +yeomanry/M +yeomen +yep/SM +yes/MS +yeshiva/SM +yeshivot +yessed +yessing +yesterday/MS +yesteryear/M +yet +yeti/MS +yew/SM +yid/S +yield/JSGMD +yikes +yin/M +yip/SM +yipe +yipped +yippee +yipping +yo +yob/S +yobbo/S +yodel/SMDRZG +yodeler/M +yoga/M +yogi/MS +yogic +yogurt/SM +yoke's +yoke/UGDS +yokel/SM +yolk/MDS +yon +yonder +yonks +yore/M +you'd +you'll +you're +you've +you/SMH +young/TMR +youngish +youngster/MS +your/S +yourself +yourselves +youth/M +youthful/YP +youthfulness/M +youths +yow +yowl/MDSG +yr/S +ytterbium/M +yttrium/M +yuan/M +yucca/SM +yuck/MDSG +yucky/TR +yuk/SM +yukked +yukking +yukky +yule/M +yuletide/M +yum +yummy/TR +yup/SM +yuppie/MS +yuppify/GDS +yurt/MS +z/DNXTGJ +zaniness/M +zany/RSMPT +zap/SM +zapped +zapper/MS +zapping +zappy +zeal/M +zealot/MS +zealotry/M +zealous/YP +zealousness/M +zebra/SM +zebu/MS +zed/SM +zeitgeist/SM +zenith/M +zeniths +zenned +zeolite/S +zephyr/MS +zeppelin/MS +zero/MDHSG +zeroes +zest/MS +zestful/YP +zestfulness/M +zesty/RT +zeta/MS +zigzag/SM +zigzagged +zigzagging +zilch/M +zillion/MS +zinc/MS +zincked +zincking +zine/S +zinfandel/M +zing/MDRZG +zinger/M +zingy/RT +zinnia/MS +zip's +zip/US +zipped/U +zipper/MDGS +zipping/U +zippy/TR +zircon/MS +zirconium/M +zit/SM +zither/MS +zloty/SM +zlotys +zodiac/MS +zodiacal +zombie/MS +zonal/Y +zone's +zone/AGDS +zoning/M +zonked +zoo/SM +zookeeper/SM +zoological/Y +zoologist/SM +zoology/M +zoom/MDSG +zoophyte/SM +zoophytic +zooplankton +zorch +zoster +zounds +zucchini/MS +zwieback/M +zydeco/M +zygote/SM +zygotic +zymurgy/M +ngstrm/M +clair/SM +clat/M +lan/M +migr/SM +pe/MS +tude/SM diff --git a/extensions/spellcheck/locales/moz.build b/extensions/spellcheck/locales/moz.build new file mode 100644 index 000000000..28919c271 --- /dev/null +++ b/extensions/spellcheck/locales/moz.build @@ -0,0 +1,6 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + diff --git a/extensions/spellcheck/moz.build b/extensions/spellcheck/moz.build new file mode 100644 index 000000000..957aa0e7d --- /dev/null +++ b/extensions/spellcheck/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['idl', 'locales', 'hunspell', 'src'] + +MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini'] +MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini'] diff --git a/extensions/spellcheck/src/moz.build b/extensions/spellcheck/src/moz.build new file mode 100644 index 000000000..8d6cef588 --- /dev/null +++ b/extensions/spellcheck/src/moz.build @@ -0,0 +1,34 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include('/ipc/chromium/chromium-config.mozbuild') +SOURCES += [ + 'mozEnglishWordUtils.cpp', + 'mozInlineSpellChecker.cpp', + 'mozInlineSpellWordUtil.cpp', + 'mozPersonalDictionary.cpp', + 'mozSpellChecker.cpp', + 'mozSpellCheckerFactory.cpp', + 'mozSpellI18NManager.cpp', +] + +FINAL_LIBRARY = 'xul' + +if CONFIG['MOZ_SYSTEM_HUNSPELL']: + CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS'] +else: + LOCAL_INCLUDES += ['../hunspell/src'] + +LOCAL_INCLUDES += [ + '../hunspell/glue', + '/dom/base', +] +EXPORTS.mozilla += [ + 'mozSpellChecker.h', +] + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/extensions/spellcheck/src/mozEnglishWordUtils.cpp b/extensions/spellcheck/src/mozEnglishWordUtils.cpp new file mode 100644 index 000000000..5033b247b --- /dev/null +++ b/extensions/spellcheck/src/mozEnglishWordUtils.cpp @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozEnglishWordUtils.h" +#include "nsReadableUtils.h" +#include "nsIServiceManager.h" +#include "nsUnicharUtils.h" +#include "nsUnicharUtilCIID.h" +#include "nsUnicodeProperties.h" +#include "nsCRT.h" +#include "mozilla/Likely.h" + +NS_IMPL_CYCLE_COLLECTING_ADDREF(mozEnglishWordUtils) +NS_IMPL_CYCLE_COLLECTING_RELEASE(mozEnglishWordUtils) + +NS_INTERFACE_MAP_BEGIN(mozEnglishWordUtils) + NS_INTERFACE_MAP_ENTRY(mozISpellI18NUtil) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellI18NUtil) + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozEnglishWordUtils) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION(mozEnglishWordUtils, + mURLDetector) + +mozEnglishWordUtils::mozEnglishWordUtils() +{ + mLanguage.AssignLiteral("en"); + + nsresult rv; + mURLDetector = do_CreateInstance(MOZ_TXTTOHTMLCONV_CONTRACTID, &rv); +} + +mozEnglishWordUtils::~mozEnglishWordUtils() +{ +} + +NS_IMETHODIMP mozEnglishWordUtils::GetLanguage(char16_t * *aLanguage) +{ + NS_ENSURE_ARG_POINTER(aLanguage); + + *aLanguage = ToNewUnicode(mLanguage); + if (!*aLanguage) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +// return the possible root forms of aWord. +NS_IMETHODIMP mozEnglishWordUtils::GetRootForm(const char16_t *aWord, uint32_t type, char16_t ***words, uint32_t *count) +{ + nsAutoString word(aWord); + char16_t **tmpPtr; + int32_t length = word.Length(); + + *count = 0; + + mozEnglishWordUtils::myspCapitalization ct = captype(word); + switch (ct) + { + case HuhCap: + case NoCap: + tmpPtr = (char16_t **)moz_xmalloc(sizeof(char16_t *)); + if (!tmpPtr) + return NS_ERROR_OUT_OF_MEMORY; + tmpPtr[0] = ToNewUnicode(word); + if (!tmpPtr[0]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(0, tmpPtr); + return NS_ERROR_OUT_OF_MEMORY; + } + *words = tmpPtr; + *count = 1; + break; + + + case AllCap: + tmpPtr = (char16_t **)moz_xmalloc(sizeof(char16_t *) * 3); + if (!tmpPtr) + return NS_ERROR_OUT_OF_MEMORY; + tmpPtr[0] = ToNewUnicode(word); + if (!tmpPtr[0]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(0, tmpPtr); + return NS_ERROR_OUT_OF_MEMORY; + } + ToLowerCase(tmpPtr[0], tmpPtr[0], length); + + tmpPtr[1] = ToNewUnicode(word); + if (!tmpPtr[1]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(1, tmpPtr); + return NS_ERROR_OUT_OF_MEMORY; + } + ToLowerCase(tmpPtr[1], tmpPtr[1], length); + ToUpperCase(tmpPtr[1], tmpPtr[1], 1); + + tmpPtr[2] = ToNewUnicode(word); + if (!tmpPtr[2]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(2, tmpPtr); + return NS_ERROR_OUT_OF_MEMORY; + } + + *words = tmpPtr; + *count = 3; + break; + + case InitCap: + tmpPtr = (char16_t **)moz_xmalloc(sizeof(char16_t *) * 2); + if (!tmpPtr) + return NS_ERROR_OUT_OF_MEMORY; + + tmpPtr[0] = ToNewUnicode(word); + if (!tmpPtr[0]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(0, tmpPtr); + return NS_ERROR_OUT_OF_MEMORY; + } + ToLowerCase(tmpPtr[0], tmpPtr[0], length); + + tmpPtr[1] = ToNewUnicode(word); + if (!tmpPtr[1]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(1, tmpPtr); + return NS_ERROR_OUT_OF_MEMORY; + } + + *words = tmpPtr; + *count = 2; + break; + default: + return NS_ERROR_FAILURE; // should never get here; + } + return NS_OK; +} + +// This needs vast improvement +bool mozEnglishWordUtils::ucIsAlpha(char16_t aChar) +{ + // XXX we have to fix callers to handle the full Unicode range + return nsIUGenCategory::kLetter == mozilla::unicode::GetGenCategory(aChar); +} + +NS_IMETHODIMP mozEnglishWordUtils::FindNextWord(const char16_t *word, uint32_t length, uint32_t offset, int32_t *begin, int32_t *end) +{ + const char16_t *p = word + offset; + const char16_t *endbuf = word + length; + const char16_t *startWord=p; + if(p 0 && ucIsAlpha(*(p-1))) { + while (p < endbuf && ucIsAlpha(*p)) + p++; + } + while((p < endbuf) && (!ucIsAlpha(*p))) + { + p++; + } + startWord=p; + while((p < endbuf) && ((ucIsAlpha(*p))||(*p=='\''))) + { + p++; + } + + // we could be trying to break down a url, we don't want to break a url into parts, + // instead we want to find out if it really is a url and if so, skip it, advancing startWord + // to a point after the url. + + // before we spend more time looking to see if the word is a url, look for a url identifer + // and make sure that identifer isn't the last character in the word fragment. + if ( (*p == ':' || *p == '@' || *p == '.') && p < endbuf - 1) { + + // ok, we have a possible url...do more research to find out if we really have one + // and determine the length of the url so we can skip over it. + + if (mURLDetector) + { + int32_t startPos = -1; + int32_t endPos = -1; + + mURLDetector->FindURLInPlaintext(startWord, endbuf - startWord, p - startWord, &startPos, &endPos); + + // ok, if we got a url, adjust the array bounds, skip the current url text and find the next word again + if (startPos != -1 && endPos != -1) { + startWord = p + endPos + 1; // skip over the url + p = startWord; // reset p + + // now recursively call FindNextWord to search for the next word now that we have skipped the url + return FindNextWord(word, length, startWord - word, begin, end); + } + } + } + + while((p > startWord)&&(*(p-1) == '\'')){ // trim trailing apostrophes + p--; + } + } + else{ + startWord = endbuf; + } + if(startWord == endbuf){ + *begin = -1; + *end = -1; + } + else{ + *begin = startWord-word; + *end = p-word; + } + return NS_OK; +} + +mozEnglishWordUtils::myspCapitalization +mozEnglishWordUtils::captype(const nsString &word) +{ + char16_t* lword=ToNewUnicode(word); + ToUpperCase(lword,lword,word.Length()); + if(word.Equals(lword)){ + free(lword); + return AllCap; + } + + ToLowerCase(lword,lword,word.Length()); + if(word.Equals(lword)){ + free(lword); + return NoCap; + } + int32_t length=word.Length(); + if(Substring(word,1,length-1).Equals(lword+1)){ + free(lword); + return InitCap; + } + free(lword); + return HuhCap; +} + +// Convert the list of words in iwords to the same capitalization aWord and +// return them in owords. +NS_IMETHODIMP mozEnglishWordUtils::FromRootForm(const char16_t *aWord, const char16_t **iwords, uint32_t icount, char16_t ***owords, uint32_t *ocount) +{ + nsAutoString word(aWord); + nsresult rv = NS_OK; + + int32_t length; + char16_t **tmpPtr = (char16_t **)moz_xmalloc(sizeof(char16_t *)*icount); + if (!tmpPtr) + return NS_ERROR_OUT_OF_MEMORY; + + mozEnglishWordUtils::myspCapitalization ct = captype(word); + for(uint32_t i = 0; i < icount; ++i) { + length = NS_strlen(iwords[i]); + tmpPtr[i] = (char16_t *) moz_xmalloc(sizeof(char16_t) * (length + 1)); + if (MOZ_UNLIKELY(!tmpPtr[i])) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, tmpPtr); + return NS_ERROR_OUT_OF_MEMORY; + } + memcpy(tmpPtr[i], iwords[i], (length + 1) * sizeof(char16_t)); + + nsAutoString capTest(tmpPtr[i]); + mozEnglishWordUtils::myspCapitalization newCt=captype(capTest); + if(newCt == NoCap){ + switch(ct) + { + case HuhCap: + case NoCap: + break; + case AllCap: + ToUpperCase(tmpPtr[i],tmpPtr[i],length); + rv = NS_OK; + break; + case InitCap: + ToUpperCase(tmpPtr[i],tmpPtr[i],1); + rv = NS_OK; + break; + default: + rv = NS_ERROR_FAILURE; // should never get here; + break; + + } + } + } + if (NS_SUCCEEDED(rv)){ + *owords = tmpPtr; + *ocount = icount; + } + return rv; +} + diff --git a/extensions/spellcheck/src/mozEnglishWordUtils.h b/extensions/spellcheck/src/mozEnglishWordUtils.h new file mode 100644 index 000000000..0bc3ddfba --- /dev/null +++ b/extensions/spellcheck/src/mozEnglishWordUtils.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozEnglishWordUtils_h__ +#define mozEnglishWordUtils_h__ + +#include "nsCOMPtr.h" +#include "mozISpellI18NUtil.h" +#include "nsIUnicodeEncoder.h" +#include "nsIUnicodeDecoder.h" +#include "nsString.h" + +#include "mozITXTToHTMLConv.h" +#include "nsCycleCollectionParticipant.h" + +class mozEnglishWordUtils : public mozISpellI18NUtil +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_MOZISPELLI18NUTIL + NS_DECL_CYCLE_COLLECTION_CLASS(mozEnglishWordUtils) + + mozEnglishWordUtils(); + /* additional members */ + enum myspCapitalization{ + NoCap,InitCap,AllCap,HuhCap + }; + +protected: + virtual ~mozEnglishWordUtils(); + + mozEnglishWordUtils::myspCapitalization captype(const nsString &word); + bool ucIsAlpha(char16_t aChar); + + nsString mLanguage; + nsString mCharset; + nsCOMPtr mURLDetector; // used to detect urls so the spell checker can skip them. +}; + +#endif diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp new file mode 100644 index 000000000..96011a37e --- /dev/null +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -0,0 +1,2043 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=2 sts=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This class is called by the editor to handle spellchecking after various + * events. The main entrypoint is SpellCheckAfterEditorChange, which is called + * when the text is changed. + * + * It is VERY IMPORTANT that we do NOT do any operations that might cause DOM + * notifications to be flushed when we are called from the editor. This is + * because the call might originate from a frame, and flushing the + * notifications might cause that frame to be deleted. + * + * Using the WordUtil class to find words causes DOM notifications to be + * flushed because it asks for style information. As a result, we post an event + * and do all of the spellchecking in that event handler, which occurs later. + * We store all DOM pointers in ranges because they are kept up-to-date with + * DOM changes that may have happened while the event was on the queue. + * + * We also allow the spellcheck to be suspended and resumed later. This makes + * large pastes or initializations with a lot of text not hang the browser UI. + * + * An optimization is the mNeedsCheckAfterNavigation flag. This is set to + * true when we get any change, and false once there is no possibility + * something changed that we need to check on navigation. Navigation events + * tend to be a little tricky because we want to check the current word on + * exit if something has changed. If we navigate inside the word, we don't want + * to do anything. As a result, this flag is cleared in FinishNavigationEvent + * when we know that we are checking as a result of navigation. + */ + +#include "mozilla/EditorBase.h" +#include "mozilla/EditorUtils.h" +#include "mozilla/Services.h" +#include "mozilla/dom/Selection.h" +#include "mozInlineSpellChecker.h" +#include "mozInlineSpellWordUtil.h" +#include "mozISpellI18NManager.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "nsIDOMNode.h" +#include "nsIDOMDocument.h" +#include "nsIDOMElement.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMMouseEvent.h" +#include "nsIDOMKeyEvent.h" +#include "nsIDOMNode.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMEvent.h" +#include "nsGenericHTMLElement.h" +#include "nsRange.h" +#include "nsIPlaintextEditor.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsIRunnable.h" +#include "nsISelection.h" +#include "nsISelectionPrivate.h" +#include "nsISelectionController.h" +#include "nsIServiceManager.h" +#include "nsITextServicesFilter.h" +#include "nsString.h" +#include "nsThreadUtils.h" +#include "nsUnicharUtils.h" +#include "nsIContent.h" +#include "nsRange.h" +#include "nsContentUtils.h" +#include "nsIObserverService.h" +#include "nsITextControlElement.h" +#include "prtime.h" + +using namespace mozilla; +using namespace mozilla::dom; + +// Set to spew messages to the console about what is happening. +//#define DEBUG_INLINESPELL + +// the number of milliseconds that we will take at once to do spellchecking +#define INLINESPELL_CHECK_TIMEOUT 50 + +// The number of words to check before we look at the time to see if +// INLINESPELL_CHECK_TIMEOUT ms have elapsed. This prevents us from spending +// too much time checking the clock. Note that misspelled words count for +// more than one word in this calculation. +#define INLINESPELL_TIMEOUT_CHECK_FREQUENCY 50 + +// This number is the number of checked words a misspelled word counts for +// when we're checking the time to see if the alloted time is up for +// spellchecking. Misspelled words take longer to process since we have to +// create a range, so they count more. The exact number isn't very important +// since this just controls how often we check the current time. +#define MISSPELLED_WORD_COUNT_PENALTY 4 + +// These notifications are broadcast when spell check starts and ends. STARTED +// must always be followed by ENDED. +#define INLINESPELL_STARTED_TOPIC "inlineSpellChecker-spellCheck-started" +#define INLINESPELL_ENDED_TOPIC "inlineSpellChecker-spellCheck-ended" + +static bool ContentIsDescendantOf(nsINode* aPossibleDescendant, + nsINode* aPossibleAncestor); + +static const char kMaxSpellCheckSelectionSize[] = "extensions.spellcheck.inline.max-misspellings"; + +mozInlineSpellStatus::mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker) + : mSpellChecker(aSpellChecker), mWordCount(0) +{ +} + +// mozInlineSpellStatus::InitForEditorChange +// +// This is the most complicated case. For changes, we need to compute the +// range of stuff that changed based on the old and new caret positions, +// as well as use a range possibly provided by the editor (start and end, +// which are usually nullptr) to get a range with the union of these. + +nsresult +mozInlineSpellStatus::InitForEditorChange( + EditAction aAction, + nsIDOMNode* aAnchorNode, int32_t aAnchorOffset, + nsIDOMNode* aPreviousNode, int32_t aPreviousOffset, + nsIDOMNode* aStartNode, int32_t aStartOffset, + nsIDOMNode* aEndNode, int32_t aEndOffset) +{ + nsresult rv; + + nsCOMPtr doc; + rv = GetDocument(getter_AddRefs(doc)); + NS_ENSURE_SUCCESS(rv, rv); + + // save the anchor point as a range so we can find the current word later + rv = PositionToCollapsedRange(doc, aAnchorNode, aAnchorOffset, + getter_AddRefs(mAnchorRange)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr prevNode = do_QueryInterface(aPreviousNode); + NS_ENSURE_STATE(prevNode); + + bool deleted = aAction == EditAction::deleteSelection; + if (aAction == EditAction::insertIMEText) { + // IME may remove the previous node if it cancels composition when + // there is no text around the composition. + deleted = !prevNode->IsInComposedDoc(); + } + + if (deleted) { + // Deletes are easy, the range is just the current anchor. We set the range + // to check to be empty, FinishInitOnEvent will fill in the range to be + // the current word. + mOp = eOpChangeDelete; + mRange = nullptr; + return NS_OK; + } + + mOp = eOpChange; + + // range to check + mRange = new nsRange(prevNode); + + // ...we need to put the start and end in the correct order + int16_t cmpResult; + rv = mAnchorRange->ComparePoint(aPreviousNode, aPreviousOffset, &cmpResult); + NS_ENSURE_SUCCESS(rv, rv); + if (cmpResult < 0) { + // previous anchor node is before the current anchor + rv = mRange->SetStart(aPreviousNode, aPreviousOffset); + NS_ENSURE_SUCCESS(rv, rv); + rv = mRange->SetEnd(aAnchorNode, aAnchorOffset); + } else { + // previous anchor node is after (or the same as) the current anchor + rv = mRange->SetStart(aAnchorNode, aAnchorOffset); + NS_ENSURE_SUCCESS(rv, rv); + rv = mRange->SetEnd(aPreviousNode, aPreviousOffset); + } + NS_ENSURE_SUCCESS(rv, rv); + + // On insert save this range: DoSpellCheck optimizes things in this range. + // Otherwise, just leave this nullptr. + if (aAction == EditAction::insertText) + mCreatedRange = mRange; + + // if we were given a range, we need to expand our range to encompass it + if (aStartNode && aEndNode) { + rv = mRange->ComparePoint(aStartNode, aStartOffset, &cmpResult); + NS_ENSURE_SUCCESS(rv, rv); + if (cmpResult < 0) { // given range starts before + rv = mRange->SetStart(aStartNode, aStartOffset); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = mRange->ComparePoint(aEndNode, aEndOffset, &cmpResult); + NS_ENSURE_SUCCESS(rv, rv); + if (cmpResult > 0) { // given range ends after + rv = mRange->SetEnd(aEndNode, aEndOffset); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + return NS_OK; +} + +// mozInlineSpellStatis::InitForNavigation +// +// For navigation events, we just need to store the new and old positions. +// +// In some cases, we detect that we shouldn't check. If this event should +// not be processed, *aContinue will be false. + +nsresult +mozInlineSpellStatus::InitForNavigation( + bool aForceCheck, int32_t aNewPositionOffset, + nsIDOMNode* aOldAnchorNode, int32_t aOldAnchorOffset, + nsIDOMNode* aNewAnchorNode, int32_t aNewAnchorOffset, + bool* aContinue) +{ + nsresult rv; + mOp = eOpNavigation; + + mForceNavigationWordCheck = aForceCheck; + mNewNavigationPositionOffset = aNewPositionOffset; + + // get the root node for checking + nsCOMPtr editor = do_QueryReferent(mSpellChecker->mEditor, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr rootElt; + rv = editor->GetRootElement(getter_AddRefs(rootElt)); + NS_ENSURE_SUCCESS(rv, rv); + + // the anchor node might not be in the DOM anymore, check + nsCOMPtr root = do_QueryInterface(rootElt, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr currentAnchor = do_QueryInterface(aOldAnchorNode, &rv); + NS_ENSURE_SUCCESS(rv, rv); + if (root && currentAnchor && ! ContentIsDescendantOf(currentAnchor, root)) { + *aContinue = false; + return NS_OK; + } + + nsCOMPtr doc; + rv = GetDocument(getter_AddRefs(doc)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = PositionToCollapsedRange(doc, aOldAnchorNode, aOldAnchorOffset, + getter_AddRefs(mOldNavigationAnchorRange)); + NS_ENSURE_SUCCESS(rv, rv); + rv = PositionToCollapsedRange(doc, aNewAnchorNode, aNewAnchorOffset, + getter_AddRefs(mAnchorRange)); + NS_ENSURE_SUCCESS(rv, rv); + + *aContinue = true; + return NS_OK; +} + +// mozInlineSpellStatus::InitForSelection +// +// It is easy for selections since we always re-check the spellcheck +// selection. + +nsresult +mozInlineSpellStatus::InitForSelection() +{ + mOp = eOpSelection; + return NS_OK; +} + +// mozInlineSpellStatus::InitForRange +// +// Called to cause the spellcheck of the given range. This will look like +// a change operation over the given range. + +nsresult +mozInlineSpellStatus::InitForRange(nsRange* aRange) +{ + mOp = eOpChange; + mRange = aRange; + return NS_OK; +} + +// mozInlineSpellStatus::FinishInitOnEvent +// +// Called when the event is triggered to complete initialization that +// might require the WordUtil. This calls to the operation-specific +// initializer, and also sets the range to be the entire element if it +// is nullptr. +// +// Watch out: the range might still be nullptr if there is nothing to do, +// the caller will have to check for this. + +nsresult +mozInlineSpellStatus::FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil) +{ + nsresult rv; + if (! mRange) { + rv = mSpellChecker->MakeSpellCheckRange(nullptr, 0, nullptr, 0, + getter_AddRefs(mRange)); + NS_ENSURE_SUCCESS(rv, rv); + } + + switch (mOp) { + case eOpChange: + if (mAnchorRange) + return FillNoCheckRangeFromAnchor(aWordUtil); + break; + case eOpChangeDelete: + if (mAnchorRange) { + rv = FillNoCheckRangeFromAnchor(aWordUtil); + NS_ENSURE_SUCCESS(rv, rv); + } + // Delete events will have no range for the changed text (because it was + // deleted), and InitForEditorChange will set it to nullptr. Here, we select + // the entire word to cause any underlining to be removed. + mRange = mNoCheckRange; + break; + case eOpNavigation: + return FinishNavigationEvent(aWordUtil); + case eOpSelection: + // this gets special handling in ResumeCheck + break; + case eOpResume: + // everything should be initialized already in this case + break; + default: + NS_NOTREACHED("Bad operation"); + return NS_ERROR_NOT_INITIALIZED; + } + return NS_OK; +} + +// mozInlineSpellStatus::FinishNavigationEvent +// +// This verifies that we need to check the word at the previous caret +// position. Now that we have the word util, we can find the word belonging +// to the previous caret position. If the new position is inside that word, +// we don't want to do anything. In this case, we'll nullptr out mRange so +// that the caller will know not to continue. +// +// Notice that we don't set mNoCheckRange. We check here whether the cursor +// is in the word that needs checking, so it isn't necessary. Plus, the +// spellchecker isn't guaranteed to only check the given word, and it could +// remove the underline from the new word under the cursor. + +nsresult +mozInlineSpellStatus::FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil) +{ + nsCOMPtr editor = do_QueryReferent(mSpellChecker->mEditor); + if (! editor) + return NS_ERROR_FAILURE; // editor is gone + + NS_ASSERTION(mAnchorRange, "No anchor for navigation!"); + nsCOMPtr newAnchorNode, oldAnchorNode; + int32_t newAnchorOffset, oldAnchorOffset; + + // get the DOM position of the old caret, the range should be collapsed + nsresult rv = mOldNavigationAnchorRange->GetStartContainer( + getter_AddRefs(oldAnchorNode)); + NS_ENSURE_SUCCESS(rv, rv); + rv = mOldNavigationAnchorRange->GetStartOffset(&oldAnchorOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // find the word on the old caret position, this is the one that we MAY need + // to check + RefPtr oldWord; + rv = aWordUtil.GetRangeForWord(oldAnchorNode, oldAnchorOffset, + getter_AddRefs(oldWord)); + NS_ENSURE_SUCCESS(rv, rv); + + // aWordUtil.GetRangeForWord flushes pending notifications, check editor again. + editor = do_QueryReferent(mSpellChecker->mEditor); + if (! editor) + return NS_ERROR_FAILURE; // editor is gone + + // get the DOM position of the new caret, the range should be collapsed + rv = mAnchorRange->GetStartContainer(getter_AddRefs(newAnchorNode)); + NS_ENSURE_SUCCESS(rv, rv); + rv = mAnchorRange->GetStartOffset(&newAnchorOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // see if the new cursor position is in the word of the old cursor position + bool isInRange = false; + if (! mForceNavigationWordCheck) { + rv = oldWord->IsPointInRange(newAnchorNode, + newAnchorOffset + mNewNavigationPositionOffset, + &isInRange); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (isInRange) { + // caller should give up + mRange = nullptr; + } else { + // check the old word + mRange = oldWord; + + // Once we've spellchecked the current word, we don't need to spellcheck + // for any more navigation events. + mSpellChecker->mNeedsCheckAfterNavigation = false; + } + return NS_OK; +} + +// mozInlineSpellStatus::FillNoCheckRangeFromAnchor +// +// Given the mAnchorRange object, computes the range of the word it is on +// (if any) and fills that range into mNoCheckRange. This is used for +// change and navigation events to know which word we should skip spell +// checking on + +nsresult +mozInlineSpellStatus::FillNoCheckRangeFromAnchor( + mozInlineSpellWordUtil& aWordUtil) +{ + nsCOMPtr anchorNode; + nsresult rv = mAnchorRange->GetStartContainer(getter_AddRefs(anchorNode)); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t anchorOffset; + rv = mAnchorRange->GetStartOffset(&anchorOffset); + NS_ENSURE_SUCCESS(rv, rv); + + return aWordUtil.GetRangeForWord(anchorNode, anchorOffset, + getter_AddRefs(mNoCheckRange)); +} + +// mozInlineSpellStatus::GetDocument +// +// Returns the nsIDOMDocument object for the document for the +// current spellchecker. + +nsresult +mozInlineSpellStatus::GetDocument(nsIDOMDocument** aDocument) +{ + nsresult rv; + *aDocument = nullptr; + if (! mSpellChecker->mEditor) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr editor = do_QueryReferent(mSpellChecker->mEditor, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr domDoc; + rv = editor->GetDocument(getter_AddRefs(domDoc)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(domDoc, NS_ERROR_NULL_POINTER); + domDoc.forget(aDocument); + return NS_OK; +} + +// mozInlineSpellStatus::PositionToCollapsedRange +// +// Converts a given DOM position to a collapsed range covering that +// position. We use ranges to store DOM positions becuase they stay +// updated as the DOM is changed. + +nsresult +mozInlineSpellStatus::PositionToCollapsedRange(nsIDOMDocument* aDocument, + nsIDOMNode* aNode, int32_t aOffset, nsIDOMRange** aRange) +{ + *aRange = nullptr; + nsCOMPtr range; + nsresult rv = aDocument->CreateRange(getter_AddRefs(range)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = range->SetStart(aNode, aOffset); + NS_ENSURE_SUCCESS(rv, rv); + rv = range->SetEnd(aNode, aOffset); + NS_ENSURE_SUCCESS(rv, rv); + + range.swap(*aRange); + return NS_OK; +} + +// mozInlineSpellResume + +class mozInlineSpellResume : public Runnable +{ +public: + mozInlineSpellResume(const mozInlineSpellStatus& aStatus, + uint32_t aDisabledAsyncToken) + : mDisabledAsyncToken(aDisabledAsyncToken), mStatus(aStatus) {} + + nsresult Post() + { + return NS_DispatchToMainThread(this); + } + + NS_IMETHOD Run() override + { + // Discard the resumption if the spell checker was disabled after the + // resumption was scheduled. + if (mDisabledAsyncToken == mStatus.mSpellChecker->mDisabledAsyncToken) { + mStatus.mSpellChecker->ResumeCheck(&mStatus); + } + return NS_OK; + } + +private: + uint32_t mDisabledAsyncToken; + mozInlineSpellStatus mStatus; +}; + +// Used as the nsIEditorSpellCheck::InitSpellChecker callback. +class InitEditorSpellCheckCallback final : public nsIEditorSpellCheckCallback +{ + ~InitEditorSpellCheckCallback() {} +public: + NS_DECL_ISUPPORTS + + explicit InitEditorSpellCheckCallback(mozInlineSpellChecker* aSpellChecker) + : mSpellChecker(aSpellChecker) {} + + NS_IMETHOD EditorSpellCheckDone() override + { + return mSpellChecker ? mSpellChecker->EditorSpellCheckInited() : NS_OK; + } + + void Cancel() + { + mSpellChecker = nullptr; + } + +private: + RefPtr mSpellChecker; +}; +NS_IMPL_ISUPPORTS(InitEditorSpellCheckCallback, nsIEditorSpellCheckCallback) + + +NS_INTERFACE_MAP_BEGIN(mozInlineSpellChecker) + NS_INTERFACE_MAP_ENTRY(nsIInlineSpellChecker) + NS_INTERFACE_MAP_ENTRY(nsIEditActionListener) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener) + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozInlineSpellChecker) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(mozInlineSpellChecker) +NS_IMPL_CYCLE_COLLECTING_RELEASE(mozInlineSpellChecker) + +NS_IMPL_CYCLE_COLLECTION(mozInlineSpellChecker, + mSpellCheck, + mTreeWalker, + mCurrentSelectionAnchorNode) + +mozInlineSpellChecker::SpellCheckingState + mozInlineSpellChecker::gCanEnableSpellChecking = + mozInlineSpellChecker::SpellCheck_Uninitialized; + +mozInlineSpellChecker::mozInlineSpellChecker() : + mNumWordsInSpellSelection(0), + mMaxNumWordsInSpellSelection(250), + mNumPendingSpellChecks(0), + mNumPendingUpdateCurrentDictionary(0), + mDisabledAsyncToken(0), + mNeedsCheckAfterNavigation(false), + mFullSpellCheckScheduled(false) +{ + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) + prefs->GetIntPref(kMaxSpellCheckSelectionSize, &mMaxNumWordsInSpellSelection); + mMaxMisspellingsPerCheck = mMaxNumWordsInSpellSelection * 3 / 4; +} + +mozInlineSpellChecker::~mozInlineSpellChecker() +{ +} + +NS_IMETHODIMP +mozInlineSpellChecker::GetSpellChecker(nsIEditorSpellCheck **aSpellCheck) +{ + *aSpellCheck = mSpellCheck; + NS_IF_ADDREF(*aSpellCheck); + return NS_OK; +} + +NS_IMETHODIMP +mozInlineSpellChecker::Init(nsIEditor *aEditor) +{ + mEditor = do_GetWeakReference(aEditor); + return NS_OK; +} + +// mozInlineSpellChecker::Cleanup +// +// Called by the editor when the editor is going away. This is important +// because we remove listeners. We do NOT clean up anything else in this +// function, because it can get called while DoSpellCheck is running! +// +// Getting the style information there can cause DOM notifications to be +// flushed, which can cause editors to go away which will bring us here. +// We can not do anything that will cause DoSpellCheck to freak out. + +nsresult mozInlineSpellChecker::Cleanup(bool aDestroyingFrames) +{ + mNumWordsInSpellSelection = 0; + nsCOMPtr spellCheckSelection; + nsresult rv = GetSpellCheckSelection(getter_AddRefs(spellCheckSelection)); + if (NS_FAILED(rv)) { + // Ensure we still unregister event listeners (but return a failure code) + UnregisterEventListeners(); + } else { + if (!aDestroyingFrames) { + spellCheckSelection->RemoveAllRanges(); + } + + rv = UnregisterEventListeners(); + } + + // Notify ENDED observers now. If we wait to notify as we normally do when + // these async operations finish, then in the meantime the editor may create + // another inline spell checker and cause more STARTED and ENDED + // notifications to be broadcast. Interleaved notifications for the same + // editor but different inline spell checkers could easily confuse + // observers. They may receive two consecutive STARTED notifications for + // example, which we guarantee will not happen. + + nsCOMPtr editor = do_QueryReferent(mEditor); + if (mPendingSpellCheck) { + // Cancel the pending editor spell checker initialization. + mPendingSpellCheck = nullptr; + mPendingInitEditorSpellCheckCallback->Cancel(); + mPendingInitEditorSpellCheckCallback = nullptr; + ChangeNumPendingSpellChecks(-1, editor); + } + + // Increment this token so that pending UpdateCurrentDictionary calls and + // scheduled spell checks are discarded when they finish. + mDisabledAsyncToken++; + + if (mNumPendingUpdateCurrentDictionary > 0) { + // Account for pending UpdateCurrentDictionary calls. + ChangeNumPendingSpellChecks(-mNumPendingUpdateCurrentDictionary, editor); + mNumPendingUpdateCurrentDictionary = 0; + } + if (mNumPendingSpellChecks > 0) { + // If mNumPendingSpellChecks is still > 0 at this point, the remainder is + // pending scheduled spell checks. + ChangeNumPendingSpellChecks(-mNumPendingSpellChecks, editor); + } + + mEditor = nullptr; + mFullSpellCheckScheduled = false; + + return rv; +} + +// mozInlineSpellChecker::CanEnableInlineSpellChecking +// +// This function can be called to see if it seems likely that we can enable +// spellchecking before actually creating the InlineSpellChecking objects. +// +// The problem is that we can't get the dictionary list without actually +// creating a whole bunch of spellchecking objects. This function tries to +// do that and caches the result so we don't have to keep allocating those +// objects if there are no dictionaries or spellchecking. +// +// Whenever dictionaries are added or removed at runtime, this value must be +// updated before an observer notification is sent out about the change, to +// avoid editors getting a wrong cached result. + +bool // static +mozInlineSpellChecker::CanEnableInlineSpellChecking() +{ + nsresult rv; + if (gCanEnableSpellChecking == SpellCheck_Uninitialized) { + gCanEnableSpellChecking = SpellCheck_NotAvailable; + + nsCOMPtr spellchecker = + do_CreateInstance("@mozilla.org/editor/editorspellchecker;1", &rv); + NS_ENSURE_SUCCESS(rv, false); + + bool canSpellCheck = false; + rv = spellchecker->CanSpellCheck(&canSpellCheck); + NS_ENSURE_SUCCESS(rv, false); + + if (canSpellCheck) + gCanEnableSpellChecking = SpellCheck_Available; + } + return (gCanEnableSpellChecking == SpellCheck_Available); +} + +void // static +mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking() +{ + gCanEnableSpellChecking = SpellCheck_Uninitialized; +} + +// mozInlineSpellChecker::RegisterEventListeners +// +// The inline spell checker listens to mouse events and keyboard navigation+ // events. + +nsresult +mozInlineSpellChecker::RegisterEventListeners() +{ + nsCOMPtr editor (do_QueryReferent(mEditor)); + NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER); + + editor->AddEditActionListener(this); + + nsCOMPtr doc; + nsresult rv = editor->GetDocument(getter_AddRefs(doc)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr piTarget = do_QueryInterface(doc, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + piTarget->AddEventListener(NS_LITERAL_STRING("blur"), this, + true, false); + piTarget->AddEventListener(NS_LITERAL_STRING("click"), this, + false, false); + piTarget->AddEventListener(NS_LITERAL_STRING("keypress"), this, + false, false); + return NS_OK; +} + +// mozInlineSpellChecker::UnregisterEventListeners + +nsresult +mozInlineSpellChecker::UnregisterEventListeners() +{ + nsCOMPtr editor (do_QueryReferent(mEditor)); + NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER); + + editor->RemoveEditActionListener(this); + + nsCOMPtr doc; + editor->GetDocument(getter_AddRefs(doc)); + NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER); + + nsCOMPtr piTarget = do_QueryInterface(doc); + NS_ENSURE_TRUE(piTarget, NS_ERROR_NULL_POINTER); + + piTarget->RemoveEventListener(NS_LITERAL_STRING("blur"), this, true); + piTarget->RemoveEventListener(NS_LITERAL_STRING("click"), this, false); + piTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, false); + return NS_OK; +} + +// mozInlineSpellChecker::GetEnableRealTimeSpell + +NS_IMETHODIMP +mozInlineSpellChecker::GetEnableRealTimeSpell(bool* aEnabled) +{ + NS_ENSURE_ARG_POINTER(aEnabled); + *aEnabled = mSpellCheck != nullptr || mPendingSpellCheck != nullptr; + return NS_OK; +} + +// mozInlineSpellChecker::SetEnableRealTimeSpell + +NS_IMETHODIMP +mozInlineSpellChecker::SetEnableRealTimeSpell(bool aEnabled) +{ + if (!aEnabled) { + mSpellCheck = nullptr; + return Cleanup(false); + } + + if (mSpellCheck) { + // spellcheck the current contents. SpellCheckRange doesn't supply a created + // range to DoSpellCheck, which in our case is the entire range. But this + // optimization doesn't matter because there is nothing in the spellcheck + // selection when starting, which triggers a better optimization. + return SpellCheckRange(nullptr); + } + + if (mPendingSpellCheck) { + // The editor spell checker is already being initialized. + return NS_OK; + } + + mPendingSpellCheck = + do_CreateInstance("@mozilla.org/editor/editorspellchecker;1"); + NS_ENSURE_STATE(mPendingSpellCheck); + + nsCOMPtr filter = + do_CreateInstance("@mozilla.org/editor/txtsrvfiltermail;1"); + if (!filter) { + mPendingSpellCheck = nullptr; + NS_ENSURE_STATE(filter); + } + mPendingSpellCheck->SetFilter(filter); + + mPendingInitEditorSpellCheckCallback = new InitEditorSpellCheckCallback(this); + if (!mPendingInitEditorSpellCheckCallback) { + mPendingSpellCheck = nullptr; + NS_ENSURE_STATE(mPendingInitEditorSpellCheckCallback); + } + + nsCOMPtr editor = do_QueryReferent(mEditor); + nsresult rv = mPendingSpellCheck->InitSpellChecker( + editor, false, mPendingInitEditorSpellCheckCallback); + if (NS_FAILED(rv)) { + mPendingSpellCheck = nullptr; + mPendingInitEditorSpellCheckCallback = nullptr; + NS_ENSURE_SUCCESS(rv, rv); + } + + ChangeNumPendingSpellChecks(1); + + return NS_OK; +} + +// Called when nsIEditorSpellCheck::InitSpellChecker completes. +nsresult +mozInlineSpellChecker::EditorSpellCheckInited() +{ + NS_ASSERTION(mPendingSpellCheck, "Spell check should be pending!"); + + // spell checking is enabled, register our event listeners to track navigation + RegisterEventListeners(); + + mSpellCheck = mPendingSpellCheck; + mPendingSpellCheck = nullptr; + mPendingInitEditorSpellCheckCallback = nullptr; + ChangeNumPendingSpellChecks(-1); + + // spellcheck the current contents. SpellCheckRange doesn't supply a created + // range to DoSpellCheck, which in our case is the entire range. But this + // optimization doesn't matter because there is nothing in the spellcheck + // selection when starting, which triggers a better optimization. + return SpellCheckRange(nullptr); +} + +// Changes the number of pending spell checks by the given delta. If the number +// becomes zero or nonzero, observers are notified. See NotifyObservers for +// info on the aEditor parameter. +void +mozInlineSpellChecker::ChangeNumPendingSpellChecks(int32_t aDelta, + nsIEditor* aEditor) +{ + int8_t oldNumPending = mNumPendingSpellChecks; + mNumPendingSpellChecks += aDelta; + NS_ASSERTION(mNumPendingSpellChecks >= 0, + "Unbalanced ChangeNumPendingSpellChecks calls!"); + if (oldNumPending == 0 && mNumPendingSpellChecks > 0) { + NotifyObservers(INLINESPELL_STARTED_TOPIC, aEditor); + } else if (oldNumPending > 0 && mNumPendingSpellChecks == 0) { + NotifyObservers(INLINESPELL_ENDED_TOPIC, aEditor); + } +} + +// Broadcasts the given topic to observers. aEditor is passed to observers if +// nonnull; otherwise mEditor is passed. +void +mozInlineSpellChecker::NotifyObservers(const char* aTopic, nsIEditor* aEditor) +{ + nsCOMPtr os = mozilla::services::GetObserverService(); + if (!os) + return; + nsCOMPtr editor = aEditor; + if (!editor) { + editor = do_QueryReferent(mEditor); + } + os->NotifyObservers(editor, aTopic, nullptr); +} + +// mozInlineSpellChecker::SpellCheckAfterEditorChange +// +// Called by the editor when nearly anything happens to change the content. +// +// The start and end positions specify a range for the thing that happened, +// but these are usually nullptr, even when you'd think they would be useful +// because you want the range (for example, pasting). We ignore them in +// this case. + +NS_IMETHODIMP +mozInlineSpellChecker::SpellCheckAfterEditorChange( + int32_t aAction, nsISelection *aSelection, + nsIDOMNode *aPreviousSelectedNode, int32_t aPreviousSelectedOffset, + nsIDOMNode *aStartNode, int32_t aStartOffset, + nsIDOMNode *aEndNode, int32_t aEndOffset) +{ + nsresult rv; + NS_ENSURE_ARG_POINTER(aSelection); + if (!mSpellCheck) + return NS_OK; // disabling spell checking is not an error + + // this means something has changed, and we never check the current word, + // therefore, we should spellcheck for subsequent caret navigations + mNeedsCheckAfterNavigation = true; + + // the anchor node is the position of the caret + nsCOMPtr anchorNode; + rv = aSelection->GetAnchorNode(getter_AddRefs(anchorNode)); + NS_ENSURE_SUCCESS(rv, rv); + int32_t anchorOffset; + rv = aSelection->GetAnchorOffset(&anchorOffset); + NS_ENSURE_SUCCESS(rv, rv); + + mozInlineSpellStatus status(this); + rv = status.InitForEditorChange((EditAction)aAction, + anchorNode, anchorOffset, + aPreviousSelectedNode, aPreviousSelectedOffset, + aStartNode, aStartOffset, + aEndNode, aEndOffset); + NS_ENSURE_SUCCESS(rv, rv); + rv = ScheduleSpellCheck(status); + NS_ENSURE_SUCCESS(rv, rv); + + // remember the current caret position after every change + SaveCurrentSelectionPosition(); + return NS_OK; +} + +// mozInlineSpellChecker::SpellCheckRange +// +// Spellchecks all the words in the given range. +// Supply a nullptr range and this will check the entire editor. + +nsresult +mozInlineSpellChecker::SpellCheckRange(nsIDOMRange* aRange) +{ + if (!mSpellCheck) { + NS_WARNING_ASSERTION( + mPendingSpellCheck, + "Trying to spellcheck, but checking seems to be disabled"); + return NS_ERROR_NOT_INITIALIZED; + } + + mozInlineSpellStatus status(this); + nsRange* range = static_cast(aRange); + nsresult rv = status.InitForRange(range); + NS_ENSURE_SUCCESS(rv, rv); + return ScheduleSpellCheck(status); +} + +// mozInlineSpellChecker::GetMisspelledWord + +NS_IMETHODIMP +mozInlineSpellChecker::GetMisspelledWord(nsIDOMNode *aNode, int32_t aOffset, + nsIDOMRange **newword) +{ + NS_ENSURE_ARG_POINTER(aNode); + nsCOMPtr spellCheckSelection; + nsresult res = GetSpellCheckSelection(getter_AddRefs(spellCheckSelection)); + NS_ENSURE_SUCCESS(res, res); + + return IsPointInSelection(spellCheckSelection, aNode, aOffset, newword); +} + +// mozInlineSpellChecker::ReplaceWord + +NS_IMETHODIMP +mozInlineSpellChecker::ReplaceWord(nsIDOMNode *aNode, int32_t aOffset, + const nsAString &newword) +{ + nsCOMPtr editor (do_QueryReferent(mEditor)); + NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER); + NS_ENSURE_TRUE(newword.Length() != 0, NS_ERROR_FAILURE); + + nsCOMPtr range; + nsresult res = GetMisspelledWord(aNode, aOffset, getter_AddRefs(range)); + NS_ENSURE_SUCCESS(res, res); + + if (range) + { + // This range was retrieved from the spellchecker selection. As + // ranges cannot be shared between selections, we must clone it + // before adding it to the editor's selection. + nsCOMPtr editorRange; + res = range->CloneRange(getter_AddRefs(editorRange)); + NS_ENSURE_SUCCESS(res, res); + + AutoPlaceHolderBatch phb(editor, nullptr); + + nsCOMPtr selection; + res = editor->GetSelection(getter_AddRefs(selection)); + NS_ENSURE_SUCCESS(res, res); + selection->RemoveAllRanges(); + selection->AddRange(editorRange); + editor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip); + + nsCOMPtr textEditor(do_QueryReferent(mEditor)); + if (textEditor) + textEditor->InsertText(newword); + } + + return NS_OK; +} + +// mozInlineSpellChecker::AddWordToDictionary + +NS_IMETHODIMP +mozInlineSpellChecker::AddWordToDictionary(const nsAString &word) +{ + NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED); + + nsAutoString wordstr(word); + nsresult rv = mSpellCheck->AddWordToDictionary(wordstr.get()); + NS_ENSURE_SUCCESS(rv, rv); + + mozInlineSpellStatus status(this); + rv = status.InitForSelection(); + NS_ENSURE_SUCCESS(rv, rv); + return ScheduleSpellCheck(status); +} + +// mozInlineSpellChecker::RemoveWordFromDictionary + +NS_IMETHODIMP +mozInlineSpellChecker::RemoveWordFromDictionary(const nsAString &word) +{ + NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED); + + nsAutoString wordstr(word); + nsresult rv = mSpellCheck->RemoveWordFromDictionary(wordstr.get()); + NS_ENSURE_SUCCESS(rv, rv); + + mozInlineSpellStatus status(this); + rv = status.InitForRange(nullptr); + NS_ENSURE_SUCCESS(rv, rv); + return ScheduleSpellCheck(status); +} + +// mozInlineSpellChecker::IgnoreWord + +NS_IMETHODIMP +mozInlineSpellChecker::IgnoreWord(const nsAString &word) +{ + NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED); + + nsAutoString wordstr(word); + nsresult rv = mSpellCheck->IgnoreWordAllOccurrences(wordstr.get()); + NS_ENSURE_SUCCESS(rv, rv); + + mozInlineSpellStatus status(this); + rv = status.InitForSelection(); + NS_ENSURE_SUCCESS(rv, rv); + return ScheduleSpellCheck(status); +} + +// mozInlineSpellChecker::IgnoreWords + +NS_IMETHODIMP +mozInlineSpellChecker::IgnoreWords(const char16_t **aWordsToIgnore, + uint32_t aCount) +{ + NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED); + + // add each word to the ignore list and then recheck the document + for (uint32_t index = 0; index < aCount; index++) + mSpellCheck->IgnoreWordAllOccurrences(aWordsToIgnore[index]); + + mozInlineSpellStatus status(this); + nsresult rv = status.InitForSelection(); + NS_ENSURE_SUCCESS(rv, rv); + return ScheduleSpellCheck(status); +} + +NS_IMETHODIMP mozInlineSpellChecker::WillCreateNode(const nsAString & aTag, nsIDOMNode *aParent, int32_t aPosition) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::DidCreateNode(const nsAString & aTag, nsIDOMNode *aNode, nsIDOMNode *aParent, + int32_t aPosition, nsresult aResult) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::WillInsertNode(nsIDOMNode *aNode, nsIDOMNode *aParent, + int32_t aPosition) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::DidInsertNode(nsIDOMNode *aNode, nsIDOMNode *aParent, + int32_t aPosition, nsresult aResult) +{ + + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::WillDeleteNode(nsIDOMNode *aChild) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::DidDeleteNode(nsIDOMNode *aChild, nsresult aResult) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::WillSplitNode(nsIDOMNode *aExistingRightNode, int32_t aOffset) +{ + return NS_OK; +} + +NS_IMETHODIMP +mozInlineSpellChecker::DidSplitNode(nsIDOMNode *aExistingRightNode, + int32_t aOffset, + nsIDOMNode *aNewLeftNode, nsresult aResult) +{ + return SpellCheckBetweenNodes(aNewLeftNode, 0, aNewLeftNode, 0); +} + +NS_IMETHODIMP mozInlineSpellChecker::WillJoinNodes(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, nsIDOMNode *aParent) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::DidJoinNodes(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, + nsIDOMNode *aParent, nsresult aResult) +{ + return SpellCheckBetweenNodes(aRightNode, 0, aRightNode, 0); +} + +NS_IMETHODIMP mozInlineSpellChecker::WillInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, const nsAString & aString) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::DidInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, + const nsAString & aString, nsresult aResult) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::WillDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::DidDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength, nsresult aResult) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::WillDeleteSelection(nsISelection *aSelection) +{ + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::DidDeleteSelection(nsISelection *aSelection) +{ + return NS_OK; +} + +// mozInlineSpellChecker::MakeSpellCheckRange +// +// Given begin and end positions, this function constructs a range as +// required for ScheduleSpellCheck. If the start and end nodes are nullptr, +// then the entire range will be selected, and you can supply -1 as the +// offset to the end range to select all of that node. +// +// If the resulting range would be empty, nullptr is put into *aRange and the +// function succeeds. + +nsresult +mozInlineSpellChecker::MakeSpellCheckRange( + nsIDOMNode* aStartNode, int32_t aStartOffset, + nsIDOMNode* aEndNode, int32_t aEndOffset, + nsRange** aRange) +{ + nsresult rv; + *aRange = nullptr; + + nsCOMPtr editor (do_QueryReferent(mEditor)); + NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER); + + nsCOMPtr doc; + rv = editor->GetDocument(getter_AddRefs(doc)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + nsCOMPtr range; + rv = doc->CreateRange(getter_AddRefs(range)); + NS_ENSURE_SUCCESS(rv, rv); + + // possibly use full range of the editor + nsCOMPtr rootElem; + if (! aStartNode || ! aEndNode) { + rv = editor->GetRootElement(getter_AddRefs(rootElem)); + NS_ENSURE_SUCCESS(rv, rv); + + aStartNode = rootElem; + aStartOffset = 0; + + aEndNode = rootElem; + aEndOffset = -1; + } + + if (aEndOffset == -1) { + nsCOMPtr childNodes; + rv = aEndNode->GetChildNodes(getter_AddRefs(childNodes)); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t childCount; + rv = childNodes->GetLength(&childCount); + NS_ENSURE_SUCCESS(rv, rv); + + aEndOffset = childCount; + } + + // sometimes we are are requested to check an empty range (possibly an empty + // document). This will result in assertions later. + if (aStartNode == aEndNode && aStartOffset == aEndOffset) + return NS_OK; + + rv = range->SetStart(aStartNode, aStartOffset); + NS_ENSURE_SUCCESS(rv, rv); + if (aEndOffset) + rv = range->SetEnd(aEndNode, aEndOffset); + else + rv = range->SetEndAfter(aEndNode); + NS_ENSURE_SUCCESS(rv, rv); + + *aRange = static_cast(range.forget().take()); + return NS_OK; +} + +nsresult +mozInlineSpellChecker::SpellCheckBetweenNodes(nsIDOMNode *aStartNode, + int32_t aStartOffset, + nsIDOMNode *aEndNode, + int32_t aEndOffset) +{ + RefPtr range; + nsresult rv = MakeSpellCheckRange(aStartNode, aStartOffset, + aEndNode, aEndOffset, + getter_AddRefs(range)); + NS_ENSURE_SUCCESS(rv, rv); + + if (! range) + return NS_OK; // range is empty: nothing to do + + mozInlineSpellStatus status(this); + rv = status.InitForRange(range); + NS_ENSURE_SUCCESS(rv, rv); + return ScheduleSpellCheck(status); +} + +// mozInlineSpellChecker::ShouldSpellCheckNode +// +// There are certain conditions when we don't want to spell check a node. In +// particular quotations, moz signatures, etc. This routine returns false +// for these cases. + +bool +mozInlineSpellChecker::ShouldSpellCheckNode(nsIEditor* aEditor, + nsINode *aNode) +{ + MOZ_ASSERT(aNode); + if (!aNode->IsContent()) + return true; + + nsIContent *content = aNode->AsContent(); + + uint32_t flags; + aEditor->GetFlags(&flags); + if (flags & nsIPlaintextEditor::eEditorMailMask) { + nsIContent *parent = content->GetParent(); + while (parent) { + if (parent->IsHTMLElement(nsGkAtoms::blockquote) && + parent->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::type, + nsGkAtoms::cite, + eIgnoreCase)) { + return false; + } + if (parent->IsHTMLElement(nsGkAtoms::pre) && + parent->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::_class, + nsGkAtoms::mozsignature, + eIgnoreCase)) { + return false; + } + + parent = parent->GetParent(); + } + } else { + // Check spelling only if the node is editable, and GetSpellcheck() is true + // on the nearest HTMLElement ancestor. + if (!content->IsEditable()) { + return false; + } + + // Make sure that we can always turn on spell checking for inputs/textareas. + // Note that because of the previous check, at this point we know that the + // node is editable. + if (content->IsInAnonymousSubtree()) { + nsIContent *node = content->GetParent(); + while (node && node->IsInNativeAnonymousSubtree()) { + node = node->GetParent(); + } + nsCOMPtr textControl = do_QueryInterface(node); + if (textControl) { + return true; + } + } + + // Get HTML element ancestor (might be aNode itself, although probably that + // has to be a text node in real life here) + nsIContent *parent = content; + while (!parent->IsHTMLElement()) { + parent = parent->GetParent(); + if (!parent) { + return true; + } + } + + // See if it's spellcheckable + return static_cast(parent)->Spellcheck(); + } + + return true; +} + +// mozInlineSpellChecker::ScheduleSpellCheck +// +// This is called by code to do the actual spellchecking. We will set up +// the proper structures for calls to DoSpellCheck. + +nsresult +mozInlineSpellChecker::ScheduleSpellCheck(const mozInlineSpellStatus& aStatus) +{ + if (mFullSpellCheckScheduled) { + // Just ignore this; we're going to spell-check everything anyway + return NS_OK; + } + + RefPtr resume = + new mozInlineSpellResume(aStatus, mDisabledAsyncToken); + NS_ENSURE_TRUE(resume, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = resume->Post(); + if (NS_SUCCEEDED(rv)) { + if (aStatus.IsFullSpellCheck()) { + // We're going to check everything. Suppress further spell-check attempts + // until that happens. + mFullSpellCheckScheduled = true; + } + ChangeNumPendingSpellChecks(1); + } + return rv; +} + +// mozInlineSpellChecker::DoSpellCheckSelection +// +// Called to re-check all misspelled words. We iterate over all ranges in +// the selection and call DoSpellCheck on them. This is used when a word +// is ignored or added to the dictionary: all instances of that word should +// be removed from the selection. +// +// FIXME-PERFORMANCE: This takes as long as it takes and is not resumable. +// Typically, checking this small amount of text is relatively fast, but +// for large numbers of words, a lag may be noticeable. + +nsresult +mozInlineSpellChecker::DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil, + Selection* aSpellCheckSelection, + mozInlineSpellStatus* aStatus) +{ + nsresult rv; + + // clear out mNumWordsInSpellSelection since we'll be rebuilding the ranges. + mNumWordsInSpellSelection = 0; + + // Since we could be modifying the ranges for the spellCheckSelection while + // looping on the spell check selection, keep a separate array of range + // elements inside the selection + nsTArray> ranges; + + int32_t count = aSpellCheckSelection->RangeCount(); + + for (int32_t idx = 0; idx < count; idx++) { + nsRange *range = aSpellCheckSelection->GetRangeAt(idx); + if (range) { + ranges.AppendElement(range); + } + } + + // We have saved the ranges above. Clearing the spellcheck selection here + // isn't necessary (rechecking each word will modify it as necessary) but + // provides better performance. By ensuring that no ranges need to be + // removed in DoSpellCheck, we can save checking range inclusion which is + // slow. + aSpellCheckSelection->RemoveAllRanges(); + + // We use this state object for all calls, and just update its range. Note + // that we don't need to call FinishInit since we will be filling in the + // necessary information. + mozInlineSpellStatus status(this); + rv = status.InitForRange(nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + bool doneChecking; + for (int32_t idx = 0; idx < count; idx++) { + // We can consider this word as "added" since we know it has no spell + // check range over it that needs to be deleted. All the old ranges + // were cleared above. We also need to clear the word count so that we + // check all words instead of stopping early. + status.mRange = ranges[idx]; + rv = DoSpellCheck(aWordUtil, aSpellCheckSelection, &status, + &doneChecking); + NS_ENSURE_SUCCESS(rv, rv); + MOZ_ASSERT(doneChecking, + "We gave the spellchecker one word, but it didn't finish checking?!?!"); + + status.mWordCount = 0; + } + + return NS_OK; +} + +// mozInlineSpellChecker::DoSpellCheck +// +// This function checks words intersecting the given range, excluding those +// inside mStatus->mNoCheckRange (can be nullptr). Words inside aNoCheckRange +// will have any spell selection removed (this is used to hide the +// underlining for the word that the caret is in). aNoCheckRange should be +// on word boundaries. +// +// mResume->mCreatedRange is a possibly nullptr range of new text that was +// inserted. Inside this range, we don't bother to check whether things are +// inside the spellcheck selection, which speeds up large paste operations +// considerably. +// +// Normal case when editing text by typing +// h e l l o w o r k d h o w a r e y o u +// ^ caret +// [-------] mRange +// [-------] mNoCheckRange +// -> does nothing (range is the same as the no check range) +// +// Case when pasting: +// [---------- pasted text ----------] +// h e l l o w o r k d h o w a r e y o u +// ^ caret +// [---] aNoCheckRange +// -> recheck all words in range except those in aNoCheckRange +// +// If checking is complete, *aDoneChecking will be set. If there is more +// but we ran out of time, this will be false and the range will be +// updated with the stuff that still needs checking. + +nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil, + Selection *aSpellCheckSelection, + mozInlineSpellStatus* aStatus, + bool* aDoneChecking) +{ + *aDoneChecking = true; + + NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED); + + // get the editor for ShouldSpellCheckNode, this may fail in reasonable + // circumstances since the editor could have gone away + nsCOMPtr editor (do_QueryReferent(mEditor)); + if (! editor) + return NS_ERROR_FAILURE; + + if (aStatus->mRange->Collapsed()) + return NS_OK; + + // see if the selection has any ranges, if not, then we can optimize checking + // range inclusion later (we have no ranges when we are initially checking or + // when there are no misspelled words yet). + int32_t originalRangeCount = aSpellCheckSelection->RangeCount(); + + // set the starting DOM position to be the beginning of our range + { + // Scope for the node/offset pairs here so they don't get + // accidentally used later + nsINode* beginNode = aStatus->mRange->GetStartParent(); + int32_t beginOffset = aStatus->mRange->StartOffset(); + nsINode* endNode = aStatus->mRange->GetEndParent(); + int32_t endOffset = aStatus->mRange->EndOffset(); + + // Now check that we're still looking at a range that's under + // aWordUtil.GetRootNode() + nsINode* rootNode = aWordUtil.GetRootNode(); + if (!nsContentUtils::ContentIsDescendantOf(beginNode, rootNode) || + !nsContentUtils::ContentIsDescendantOf(endNode, rootNode)) { + // Just bail out and don't try to spell-check this + return NS_OK; + } + + aWordUtil.SetEnd(endNode, endOffset); + aWordUtil.SetPosition(beginNode, beginOffset); + } + + // aWordUtil.SetPosition flushes pending notifications, check editor again. + // XXX Uhhh, *we're* holding a strong ref to the editor. + editor = do_QueryReferent(mEditor); + if (! editor) + return NS_ERROR_FAILURE; + + int32_t wordsSinceTimeCheck = 0; + PRTime beginTime = PR_Now(); + + nsAutoString wordText; + RefPtr wordRange; + bool dontCheckWord; + while (NS_SUCCEEDED(aWordUtil.GetNextWord(wordText, + getter_AddRefs(wordRange), + &dontCheckWord)) && + wordRange) { + wordsSinceTimeCheck++; + + // get the range for the current word. + nsINode *beginNode; + nsINode *endNode; + int32_t beginOffset, endOffset; + + ErrorResult erv; + beginNode = wordRange->GetStartContainer(erv); + endNode = wordRange->GetEndContainer(erv); + beginOffset = wordRange->GetStartOffset(erv); + endOffset = wordRange->GetEndOffset(erv); + +#ifdef DEBUG_INLINESPELL + printf("->Got word \"%s\"", NS_ConvertUTF16toUTF8(wordText).get()); + if (dontCheckWord) + printf(" (not checking)"); + printf("\n"); +#endif + + // see if there is a spellcheck range that already intersects the word + // and remove it. We only need to remove old ranges, so don't bother if + // there were no ranges when we started out. + if (originalRangeCount > 0) { + // likewise, if this word is inside new text, we won't bother testing + if (!aStatus->mCreatedRange || + !aStatus->mCreatedRange->IsPointInRange(*beginNode, beginOffset, erv)) { + nsTArray> ranges; + aSpellCheckSelection->GetRangesForInterval(*beginNode, beginOffset, + *endNode, endOffset, + true, ranges, erv); + ENSURE_SUCCESS(erv, erv.StealNSResult()); + for (uint32_t i = 0; i < ranges.Length(); i++) + RemoveRange(aSpellCheckSelection, ranges[i]); + } + } + + // some words are special and don't need checking + if (dontCheckWord) + continue; + + // some nodes we don't spellcheck + if (!ShouldSpellCheckNode(editor, beginNode)) + continue; + + // Don't check spelling if we're inside the noCheckRange. This needs to + // be done after we clear any old selection because the excluded word + // might have been previously marked. + // + // We do a simple check to see if the beginning of our word is in the + // exclusion range. Because the exclusion range is a multiple of a word, + // this is sufficient. + if (aStatus->mNoCheckRange && + aStatus->mNoCheckRange->IsPointInRange(*beginNode, beginOffset, erv)) { + continue; + } + + // check spelling and add to selection if misspelled + bool isMisspelled; + aWordUtil.NormalizeWord(wordText); + nsresult rv = mSpellCheck->CheckCurrentWordNoSuggest(wordText.get(), &isMisspelled); + if (NS_FAILED(rv)) + continue; + + if (isMisspelled) { + // misspelled words count extra toward the max + wordsSinceTimeCheck += MISSPELLED_WORD_COUNT_PENALTY; + AddRange(aSpellCheckSelection, wordRange); + + aStatus->mWordCount ++; + if (aStatus->mWordCount >= mMaxMisspellingsPerCheck || + SpellCheckSelectionIsFull()) + break; + } + + // see if we've run out of time, only check every N words for perf + if (wordsSinceTimeCheck >= INLINESPELL_TIMEOUT_CHECK_FREQUENCY) { + wordsSinceTimeCheck = 0; + if (PR_Now() > PRTime(beginTime + INLINESPELL_CHECK_TIMEOUT * PR_USEC_PER_MSEC)) { + // stop checking, our time limit has been exceeded + + // move the range to encompass the stuff that needs checking + rv = aStatus->mRange->SetStart(endNode, endOffset); + if (NS_FAILED(rv)) { + // The range might be unhappy because the beginning is after the + // end. This is possible when the requested end was in the middle + // of a word, just ignore this situation and assume we're done. + return NS_OK; + } + *aDoneChecking = false; + return NS_OK; + } + } + } + + return NS_OK; +} + +// An RAII helper that calls ChangeNumPendingSpellChecks on destruction. +class AutoChangeNumPendingSpellChecks +{ +public: + AutoChangeNumPendingSpellChecks(mozInlineSpellChecker* aSpellChecker, + int32_t aDelta) + : mSpellChecker(aSpellChecker), mDelta(aDelta) {} + + ~AutoChangeNumPendingSpellChecks() + { + mSpellChecker->ChangeNumPendingSpellChecks(mDelta); + } + +private: + RefPtr mSpellChecker; + int32_t mDelta; +}; + +// mozInlineSpellChecker::ResumeCheck +// +// Called by the resume event when it fires. We will try to pick up where +// the last resume left off. + +nsresult +mozInlineSpellChecker::ResumeCheck(mozInlineSpellStatus* aStatus) +{ + // Observers should be notified that spell check has ended only after spell + // check is done below, but since there are many early returns in this method + // and the number of pending spell checks must be decremented regardless of + // whether the spell check actually happens, use this RAII object. + AutoChangeNumPendingSpellChecks autoChangeNumPending(this, -1); + + if (aStatus->IsFullSpellCheck()) { + // Allow posting new spellcheck resume events from inside + // ResumeCheck, now that we're actually firing. + NS_ASSERTION(mFullSpellCheckScheduled, + "How could this be false? The full spell check is " + "calling us!!"); + mFullSpellCheckScheduled = false; + } + + if (! mSpellCheck) + return NS_OK; // spell checking has been turned off + + nsCOMPtr editor = do_QueryReferent(mEditor); + if (! editor) + return NS_OK; // editor is gone + + mozInlineSpellWordUtil wordUtil; + nsresult rv = wordUtil.Init(mEditor); + if (NS_FAILED(rv)) + return NS_OK; // editor doesn't like us, don't assert + + nsCOMPtr spellCheckSelectionRef; + rv = GetSpellCheckSelection(getter_AddRefs(spellCheckSelectionRef)); + NS_ENSURE_SUCCESS(rv, rv); + + auto spellCheckSelection = + static_cast(spellCheckSelectionRef.get()); + + nsAutoString currentDictionary; + rv = mSpellCheck->GetCurrentDictionary(currentDictionary); + if (NS_FAILED(rv)) { + // no active dictionary + int32_t count = spellCheckSelection->RangeCount(); + for (int32_t index = count - 1; index >= 0; index--) { + nsRange *checkRange = spellCheckSelection->GetRangeAt(index); + if (checkRange) { + RemoveRange(spellCheckSelection, checkRange); + } + } + return NS_OK; + } + + CleanupRangesInSelection(spellCheckSelection); + + rv = aStatus->FinishInitOnEvent(wordUtil); + NS_ENSURE_SUCCESS(rv, rv); + if (! aStatus->mRange) + return NS_OK; // empty range, nothing to do + + bool doneChecking = true; + if (aStatus->mOp == mozInlineSpellStatus::eOpSelection) + rv = DoSpellCheckSelection(wordUtil, spellCheckSelection, aStatus); + else + rv = DoSpellCheck(wordUtil, spellCheckSelection, aStatus, &doneChecking); + NS_ENSURE_SUCCESS(rv, rv); + + if (! doneChecking) + rv = ScheduleSpellCheck(*aStatus); + return rv; +} + +// mozInlineSpellChecker::IsPointInSelection +// +// Determines if a given (node,offset) point is inside the given +// selection. If so, the specific range of the selection that +// intersects is places in *aRange. (There may be multiple disjoint +// ranges in a selection.) +// +// If there is no intersection, *aRange will be nullptr. + +nsresult +mozInlineSpellChecker::IsPointInSelection(nsISelection *aSelection, + nsIDOMNode *aNode, + int32_t aOffset, + nsIDOMRange **aRange) +{ + *aRange = nullptr; + + nsCOMPtr privSel(do_QueryInterface(aSelection)); + + nsTArray ranges; + nsCOMPtr node = do_QueryInterface(aNode); + nsresult rv = privSel->GetRangesForIntervalArray(node, aOffset, node, aOffset, + true, &ranges); + NS_ENSURE_SUCCESS(rv, rv); + + if (ranges.Length() == 0) + return NS_OK; // no matches + + // there may be more than one range returned, and we don't know what do + // do with that, so just get the first one + NS_ADDREF(*aRange = ranges[0]); + return NS_OK; +} + +nsresult +mozInlineSpellChecker::CleanupRangesInSelection(Selection *aSelection) +{ + // integrity check - remove ranges that have collapsed to nothing. This + // can happen if the node containing a highlighted word was removed. + if (!aSelection) + return NS_ERROR_FAILURE; + + int32_t count = aSelection->RangeCount(); + + for (int32_t index = 0; index < count; index++) + { + nsRange *checkRange = aSelection->GetRangeAt(index); + if (checkRange) + { + if (checkRange->Collapsed()) + { + RemoveRange(aSelection, checkRange); + index--; + count--; + } + } + } + + return NS_OK; +} + + +// mozInlineSpellChecker::RemoveRange +// +// For performance reasons, we have an upper bound on the number of word +// ranges in the spell check selection. When removing a range from the +// selection, we need to decrement mNumWordsInSpellSelection + +nsresult +mozInlineSpellChecker::RemoveRange(Selection *aSpellCheckSelection, + nsRange *aRange) +{ + NS_ENSURE_ARG_POINTER(aSpellCheckSelection); + NS_ENSURE_ARG_POINTER(aRange); + + ErrorResult rv; + aSpellCheckSelection->RemoveRange(*aRange, rv); + if (!rv.Failed() && mNumWordsInSpellSelection) + mNumWordsInSpellSelection--; + + return rv.StealNSResult(); +} + + +// mozInlineSpellChecker::AddRange +// +// For performance reasons, we have an upper bound on the number of word +// ranges we'll add to the spell check selection. Once we reach that upper +// bound, stop adding the ranges + +nsresult +mozInlineSpellChecker::AddRange(nsISelection* aSpellCheckSelection, + nsIDOMRange* aRange) +{ + NS_ENSURE_ARG_POINTER(aSpellCheckSelection); + NS_ENSURE_ARG_POINTER(aRange); + + nsresult rv = NS_OK; + + if (!SpellCheckSelectionIsFull()) + { + rv = aSpellCheckSelection->AddRange(aRange); + if (NS_SUCCEEDED(rv)) + mNumWordsInSpellSelection++; + } + + return rv; +} + +nsresult mozInlineSpellChecker::GetSpellCheckSelection(nsISelection ** aSpellCheckSelection) +{ + nsCOMPtr editor (do_QueryReferent(mEditor)); + NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER); + + nsCOMPtr selcon; + nsresult rv = editor->GetSelectionController(getter_AddRefs(selcon)); + NS_ENSURE_SUCCESS(rv, rv); + + return selcon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK, aSpellCheckSelection); +} + +nsresult mozInlineSpellChecker::SaveCurrentSelectionPosition() +{ + nsCOMPtr editor (do_QueryReferent(mEditor)); + NS_ENSURE_TRUE(editor, NS_OK); + + // figure out the old caret position based on the current selection + nsCOMPtr selection; + nsresult rv = editor->GetSelection(getter_AddRefs(selection)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = selection->GetFocusNode(getter_AddRefs(mCurrentSelectionAnchorNode)); + NS_ENSURE_SUCCESS(rv, rv); + + selection->GetFocusOffset(&mCurrentSelectionOffset); + + return NS_OK; +} + +// This is a copy of nsContentUtils::ContentIsDescendantOf. Another crime +// for XPCOM's rap sheet +bool // static +ContentIsDescendantOf(nsINode* aPossibleDescendant, + nsINode* aPossibleAncestor) +{ + NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!"); + NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!"); + + do { + if (aPossibleDescendant == aPossibleAncestor) + return true; + aPossibleDescendant = aPossibleDescendant->GetParentNode(); + } while (aPossibleDescendant); + + return false; +} + +// mozInlineSpellChecker::HandleNavigationEvent +// +// Acts upon mouse clicks and keyboard navigation changes, spell checking +// the previous word if the new navigation location moves us to another +// word. +// +// This is complicated by the fact that our mouse events are happening after +// selection has been changed to account for the mouse click. But keyboard +// events are happening before the caret selection has changed. Working +// around this by letting keyboard events setting forceWordSpellCheck to +// true. aNewPositionOffset also tries to work around this for the +// DOM_VK_RIGHT and DOM_VK_LEFT cases. + +nsresult +mozInlineSpellChecker::HandleNavigationEvent(bool aForceWordSpellCheck, + int32_t aNewPositionOffset) +{ + nsresult rv; + + // If we already handled the navigation event and there is no possibility + // anything has changed since then, we don't have to do anything. This + // optimization makes a noticeable difference when you hold down a navigation + // key like Page Down. + if (! mNeedsCheckAfterNavigation) + return NS_OK; + + nsCOMPtr currentAnchorNode = mCurrentSelectionAnchorNode; + int32_t currentAnchorOffset = mCurrentSelectionOffset; + + // now remember the new focus position resulting from the event + rv = SaveCurrentSelectionPosition(); + NS_ENSURE_SUCCESS(rv, rv); + + bool shouldPost; + mozInlineSpellStatus status(this); + rv = status.InitForNavigation(aForceWordSpellCheck, aNewPositionOffset, + currentAnchorNode, currentAnchorOffset, + mCurrentSelectionAnchorNode, mCurrentSelectionOffset, + &shouldPost); + NS_ENSURE_SUCCESS(rv, rv); + if (shouldPost) { + rv = ScheduleSpellCheck(status); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + +NS_IMETHODIMP mozInlineSpellChecker::HandleEvent(nsIDOMEvent* aEvent) +{ + nsAutoString eventType; + aEvent->GetType(eventType); + + if (eventType.EqualsLiteral("blur")) { + return Blur(aEvent); + } + if (eventType.EqualsLiteral("click")) { + return MouseClick(aEvent); + } + if (eventType.EqualsLiteral("keypress")) { + return KeyPress(aEvent); + } + + return NS_OK; +} + +nsresult mozInlineSpellChecker::Blur(nsIDOMEvent* aEvent) +{ + // force spellcheck on blur, for instance when tabbing out of a textbox + HandleNavigationEvent(true); + return NS_OK; +} + +nsresult mozInlineSpellChecker::MouseClick(nsIDOMEvent *aMouseEvent) +{ + nsCOMPtrmouseEvent = do_QueryInterface(aMouseEvent); + NS_ENSURE_TRUE(mouseEvent, NS_OK); + + // ignore any errors from HandleNavigationEvent as we don't want to prevent + // anyone else from seeing this event. + int16_t button; + mouseEvent->GetButton(&button); + HandleNavigationEvent(button != 0); + return NS_OK; +} + +nsresult mozInlineSpellChecker::KeyPress(nsIDOMEvent* aKeyEvent) +{ + nsCOMPtrkeyEvent = do_QueryInterface(aKeyEvent); + NS_ENSURE_TRUE(keyEvent, NS_OK); + + uint32_t keyCode; + keyEvent->GetKeyCode(&keyCode); + + // we only care about navigation keys that moved selection + switch (keyCode) + { + case nsIDOMKeyEvent::DOM_VK_RIGHT: + case nsIDOMKeyEvent::DOM_VK_LEFT: + HandleNavigationEvent(false, keyCode == nsIDOMKeyEvent::DOM_VK_RIGHT ? 1 : -1); + break; + case nsIDOMKeyEvent::DOM_VK_UP: + case nsIDOMKeyEvent::DOM_VK_DOWN: + case nsIDOMKeyEvent::DOM_VK_HOME: + case nsIDOMKeyEvent::DOM_VK_END: + case nsIDOMKeyEvent::DOM_VK_PAGE_UP: + case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN: + HandleNavigationEvent(true /* force a spelling correction */); + break; + } + + return NS_OK; +} + +// Used as the nsIEditorSpellCheck::UpdateCurrentDictionary callback. +class UpdateCurrentDictionaryCallback final : public nsIEditorSpellCheckCallback +{ +public: + NS_DECL_ISUPPORTS + + explicit UpdateCurrentDictionaryCallback(mozInlineSpellChecker* aSpellChecker, + uint32_t aDisabledAsyncToken) + : mSpellChecker(aSpellChecker), mDisabledAsyncToken(aDisabledAsyncToken) {} + + NS_IMETHOD EditorSpellCheckDone() override + { + // Ignore this callback if SetEnableRealTimeSpell(false) was called after + // the UpdateCurrentDictionary call that triggered it. + return mSpellChecker->mDisabledAsyncToken > mDisabledAsyncToken ? + NS_OK : + mSpellChecker->CurrentDictionaryUpdated(); + } + +private: + ~UpdateCurrentDictionaryCallback() {} + + RefPtr mSpellChecker; + uint32_t mDisabledAsyncToken; +}; +NS_IMPL_ISUPPORTS(UpdateCurrentDictionaryCallback, nsIEditorSpellCheckCallback) + +NS_IMETHODIMP mozInlineSpellChecker::UpdateCurrentDictionary() +{ + // mSpellCheck is null and mPendingSpellCheck is nonnull while the spell + // checker is being initialized. Calling UpdateCurrentDictionary on + // mPendingSpellCheck simply queues the dictionary update after the init. + nsCOMPtr spellCheck = mSpellCheck ? mSpellCheck : + mPendingSpellCheck; + if (!spellCheck) { + return NS_OK; + } + + if (NS_FAILED(spellCheck->GetCurrentDictionary(mPreviousDictionary))) { + mPreviousDictionary.Truncate(); + } + + RefPtr cb = + new UpdateCurrentDictionaryCallback(this, mDisabledAsyncToken); + NS_ENSURE_STATE(cb); + nsresult rv = spellCheck->UpdateCurrentDictionary(cb); + if (NS_FAILED(rv)) { + cb = nullptr; + return rv; + } + mNumPendingUpdateCurrentDictionary++; + ChangeNumPendingSpellChecks(1); + + return NS_OK; +} + +// Called when nsIEditorSpellCheck::UpdateCurrentDictionary completes. +nsresult mozInlineSpellChecker::CurrentDictionaryUpdated() +{ + mNumPendingUpdateCurrentDictionary--; + NS_ASSERTION(mNumPendingUpdateCurrentDictionary >= 0, + "CurrentDictionaryUpdated called without corresponding " + "UpdateCurrentDictionary call!"); + ChangeNumPendingSpellChecks(-1); + + nsAutoString currentDictionary; + if (!mSpellCheck || + NS_FAILED(mSpellCheck->GetCurrentDictionary(currentDictionary))) { + currentDictionary.Truncate(); + } + + nsresult rv = SpellCheckRange(nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +NS_IMETHODIMP +mozInlineSpellChecker::GetSpellCheckPending(bool* aPending) +{ + *aPending = mNumPendingSpellChecks > 0; + return NS_OK; +} diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.h b/extensions/spellcheck/src/mozInlineSpellChecker.h new file mode 100644 index 000000000..86d91c2c0 --- /dev/null +++ b/extensions/spellcheck/src/mozInlineSpellChecker.h @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __mozinlinespellchecker_h__ +#define __mozinlinespellchecker_h__ + +#include "mozilla/EditorBase.h" +#include "nsRange.h" +#include "nsIEditorSpellCheck.h" +#include "nsIEditActionListener.h" +#include "nsIInlineSpellChecker.h" +#include "nsIDOMTreeWalker.h" +#include "nsWeakReference.h" +#include "nsIDOMEventListener.h" +#include "nsWeakReference.h" +#include "mozISpellI18NUtil.h" +#include "nsCycleCollectionParticipant.h" + +// X.h defines KeyPress +#ifdef KeyPress +#undef KeyPress +#endif + +class mozInlineSpellWordUtil; +class mozInlineSpellChecker; +class mozInlineSpellResume; +class InitEditorSpellCheckCallback; +class UpdateCurrentDictionaryCallback; +class mozInlineSpellResume; + +class mozInlineSpellStatus +{ +public: + explicit mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker); + + nsresult InitForEditorChange(EditAction aAction, + nsIDOMNode* aAnchorNode, int32_t aAnchorOffset, + nsIDOMNode* aPreviousNode, int32_t aPreviousOffset, + nsIDOMNode* aStartNode, int32_t aStartOffset, + nsIDOMNode* aEndNode, int32_t aEndOffset); + nsresult InitForNavigation(bool aForceCheck, int32_t aNewPositionOffset, + nsIDOMNode* aOldAnchorNode, int32_t aOldAnchorOffset, + nsIDOMNode* aNewAnchorNode, int32_t aNewAnchorOffset, + bool* aContinue); + nsresult InitForSelection(); + nsresult InitForRange(nsRange* aRange); + + nsresult FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil); + + // Return true if we plan to spell-check everything + bool IsFullSpellCheck() const { + return mOp == eOpChange && !mRange; + } + + RefPtr mSpellChecker; + + // The total number of words checked in this sequence, using this tally tells + // us when to stop. This count is preserved as we continue checking in new + // messages. + int32_t mWordCount; + + // what happened? + enum Operation { eOpChange, // for SpellCheckAfterChange except deleteSelection + eOpChangeDelete, // for SpellCheckAfterChange deleteSelection + eOpNavigation, // for HandleNavigationEvent + eOpSelection, // re-check all misspelled words + eOpResume }; // for resuming a previously started check + Operation mOp; + + // Used for events where we have already computed the range to use. It can + // also be nullptr in these cases where we need to check the entire range. + RefPtr mRange; + + // If we happen to know something was inserted, this is that range. + // Can be nullptr (this only allows an optimization, so not setting doesn't hurt) + RefPtr mCreatedRange; + + // Contains the range computed for the current word. Can be nullptr. + RefPtr mNoCheckRange; + + // Indicates the position of the cursor for the event (so we can compute + // mNoCheckRange). It can be nullptr if we don't care about the cursor position + // (such as for the intial check of everything). + // + // For mOp == eOpNavigation, this is the NEW position of the cursor + nsCOMPtr mAnchorRange; + + // ----- + // The following members are only for navigation events and are only + // stored for FinishNavigationEvent to initialize the other members. + // ----- + + // this is the OLD position of the cursor + nsCOMPtr mOldNavigationAnchorRange; + + // Set when we should force checking the current word. See + // mozInlineSpellChecker::HandleNavigationEvent for a description of why we + // have this. + bool mForceNavigationWordCheck; + + // Contains the offset passed in to HandleNavigationEvent + int32_t mNewNavigationPositionOffset; + +protected: + nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil); + + nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil); + + nsresult GetDocument(nsIDOMDocument** aDocument); + nsresult PositionToCollapsedRange(nsIDOMDocument* aDocument, + nsIDOMNode* aNode, int32_t aOffset, + nsIDOMRange** aRange); +}; + +class mozInlineSpellChecker final : public nsIInlineSpellChecker, + public nsIEditActionListener, + public nsIDOMEventListener, + public nsSupportsWeakReference +{ +private: + friend class mozInlineSpellStatus; + friend class InitEditorSpellCheckCallback; + friend class UpdateCurrentDictionaryCallback; + friend class AutoChangeNumPendingSpellChecks; + friend class mozInlineSpellResume; + + // Access with CanEnableInlineSpellChecking + enum SpellCheckingState { SpellCheck_Uninitialized = -1, + SpellCheck_NotAvailable = 0, + SpellCheck_Available = 1}; + static SpellCheckingState gCanEnableSpellChecking; + + nsWeakPtr mEditor; + nsCOMPtr mSpellCheck; + nsCOMPtr mPendingSpellCheck; + nsCOMPtr mTreeWalker; + nsCOMPtr mConverter; + + int32_t mNumWordsInSpellSelection; + int32_t mMaxNumWordsInSpellSelection; + + // How many misspellings we can add at once. This is often less than the max + // total number of misspellings. When you have a large textarea prepopulated + // with text with many misspellings, we can hit this limit. By making it + // lower than the total number of misspelled words, new text typed by the + // user can also have spellchecking in it. + int32_t mMaxMisspellingsPerCheck; + + // we need to keep track of the current text position in the document + // so we can spell check the old word when the user clicks around the document. + nsCOMPtr mCurrentSelectionAnchorNode; + int32_t mCurrentSelectionOffset; + + // Tracks the number of pending spell checks *and* async operations that may + // lead to spell checks, like updating the current dictionary. This is + // necessary so that observers can know when to wait for spell check to + // complete. + int32_t mNumPendingSpellChecks; + + // The number of calls to UpdateCurrentDictionary that haven't finished yet. + int32_t mNumPendingUpdateCurrentDictionary; + + // This number is incremented each time the spell checker is disabled so that + // pending scheduled spell checks and UpdateCurrentDictionary calls can be + // ignored when they finish. + uint32_t mDisabledAsyncToken; + + // When mPendingSpellCheck is non-null, this is the callback passed when + // it was initialized. + RefPtr mPendingInitEditorSpellCheckCallback; + + // Set when we have spellchecked after the last edit operation. See the + // commment at the top of the .cpp file for more info. + bool mNeedsCheckAfterNavigation; + + // Set when we have a pending mozInlineSpellResume which will check + // the whole document. + bool mFullSpellCheckScheduled; + + // Maintains state during the asynchronous UpdateCurrentDictionary call. + nsString mPreviousDictionary; + +public: + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_NSIEDITACTIONLISTENER + NS_DECL_NSIINLINESPELLCHECKER + NS_DECL_NSIDOMEVENTLISTENER + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker, nsIDOMEventListener) + + // returns true if there are any spell checking dictionaries available + static bool CanEnableInlineSpellChecking(); + // update the cached value whenever the list of available dictionaries changes + static void UpdateCanEnableInlineSpellChecking(); + + nsresult Blur(nsIDOMEvent* aEvent); + nsresult MouseClick(nsIDOMEvent* aMouseEvent); + nsresult KeyPress(nsIDOMEvent* aKeyEvent); + + mozInlineSpellChecker(); + + // spell checks all of the words between two nodes + nsresult SpellCheckBetweenNodes(nsIDOMNode *aStartNode, + int32_t aStartOffset, + nsIDOMNode *aEndNode, + int32_t aEndOffset); + + // examines the dom node in question and returns true if the inline spell + // checker should skip the node (i.e. the text is inside of a block quote + // or an e-mail signature...) + bool ShouldSpellCheckNode(nsIEditor* aEditor, nsINode *aNode); + + nsresult SpellCheckAfterChange(nsIDOMNode* aCursorNode, int32_t aCursorOffset, + nsIDOMNode* aPreviousNode, int32_t aPreviousOffset, + nsISelection* aSpellCheckSelection); + + // spell check the text contained within aRange, potentially scheduling + // another check in the future if the time threshold is reached + nsresult ScheduleSpellCheck(const mozInlineSpellStatus& aStatus); + + nsresult DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil, + mozilla::dom::Selection* aSpellCheckSelection, + mozInlineSpellStatus* aStatus); + nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil, + mozilla::dom::Selection *aSpellCheckSelection, + mozInlineSpellStatus* aStatus, + bool* aDoneChecking); + + // helper routine to determine if a point is inside of the passed in selection. + nsresult IsPointInSelection(nsISelection *aSelection, + nsIDOMNode *aNode, + int32_t aOffset, + nsIDOMRange **aRange); + + nsresult CleanupRangesInSelection(mozilla::dom::Selection *aSelection); + + nsresult RemoveRange(mozilla::dom::Selection *aSpellCheckSelection, + nsRange *aRange); + nsresult AddRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange); + bool SpellCheckSelectionIsFull() { return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection; } + + nsresult MakeSpellCheckRange(nsIDOMNode* aStartNode, int32_t aStartOffset, + nsIDOMNode* aEndNode, int32_t aEndOffset, + nsRange** aRange); + + // DOM and editor event registration helper routines + nsresult RegisterEventListeners(); + nsresult UnregisterEventListeners(); + nsresult HandleNavigationEvent(bool aForceWordSpellCheck, int32_t aNewPositionOffset = 0); + + nsresult GetSpellCheckSelection(nsISelection ** aSpellCheckSelection); + nsresult SaveCurrentSelectionPosition(); + + nsresult ResumeCheck(mozInlineSpellStatus* aStatus); + +protected: + virtual ~mozInlineSpellChecker(); + + // called when async nsIEditorSpellCheck methods complete + nsresult EditorSpellCheckInited(); + nsresult CurrentDictionaryUpdated(); + + // track the number of pending spell checks and async operations that may lead + // to spell checks, notifying observers accordingly + void ChangeNumPendingSpellChecks(int32_t aDelta, + nsIEditor* aEditor = nullptr); + void NotifyObservers(const char* aTopic, nsIEditor* aEditor); +}; + +#endif /* __mozinlinespellchecker_h__ */ diff --git a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp new file mode 100644 index 000000000..3aef1533d --- /dev/null +++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp @@ -0,0 +1,1085 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozInlineSpellWordUtil.h" +#include "nsDebug.h" +#include "nsIAtom.h" +#include "nsComponentManagerUtils.h" +#include "nsIDOMCSSStyleDeclaration.h" +#include "nsIDOMElement.h" +#include "nsIDOMRange.h" +#include "nsIEditor.h" +#include "nsIDOMNode.h" +#include "nsUnicharUtilCIID.h" +#include "nsUnicodeProperties.h" +#include "nsServiceManagerUtils.h" +#include "nsIContent.h" +#include "nsTextFragment.h" +#include "mozilla/dom/Element.h" +#include "nsRange.h" +#include "nsContentUtils.h" +#include "nsIFrame.h" +#include +#include "mozilla/BinarySearch.h" + +using namespace mozilla; + +// IsIgnorableCharacter +// +// These characters are ones that we should ignore in input. + +inline bool IsIgnorableCharacter(char16_t ch) +{ + return (ch == 0xAD || // SOFT HYPHEN + ch == 0x1806); // MONGOLIAN TODO SOFT HYPHEN +} + +// IsConditionalPunctuation +// +// Some characters (like apostrophes) require characters on each side to be +// part of a word, and are otherwise punctuation. + +inline bool IsConditionalPunctuation(char16_t ch) +{ + return (ch == '\'' || + ch == 0x2019 || // RIGHT SINGLE QUOTATION MARK + ch == 0x00B7); // MIDDLE DOT +} + +// mozInlineSpellWordUtil::Init + +nsresult +mozInlineSpellWordUtil::Init(nsWeakPtr aWeakEditor) +{ + nsresult rv; + + // getting the editor can fail commonly because the editor was detached, so + // don't assert + nsCOMPtr editor = do_QueryReferent(aWeakEditor, &rv); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr domDoc; + rv = editor->GetDocument(getter_AddRefs(domDoc)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(domDoc, NS_ERROR_NULL_POINTER); + + mDOMDocument = domDoc; + mDocument = do_QueryInterface(domDoc); + + // Find the root node for the editor. For contenteditable we'll need something + // cleverer here. + nsCOMPtr rootElt; + rv = editor->GetRootElement(getter_AddRefs(rootElt)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr rootNode = do_QueryInterface(rootElt); + mRootNode = rootNode; + NS_ASSERTION(mRootNode, "GetRootElement returned null *and* claimed to suceed!"); + return NS_OK; +} + +static inline bool +IsTextNode(nsINode* aNode) +{ + return aNode->IsNodeOfType(nsINode::eTEXT); +} + +typedef void (* OnLeaveNodeFunPtr)(nsINode* aNode, void* aClosure); + +// Find the next node in the DOM tree in preorder. +// Calls OnLeaveNodeFunPtr when the traversal leaves a node, which is +// why we can't just use GetNextNode here, sadly. +static nsINode* +FindNextNode(nsINode* aNode, nsINode* aRoot, + OnLeaveNodeFunPtr aOnLeaveNode, void* aClosure) +{ + NS_PRECONDITION(aNode, "Null starting node?"); + + nsINode* next = aNode->GetFirstChild(); + if (next) + return next; + + // Don't look at siblings or otherwise outside of aRoot + if (aNode == aRoot) + return nullptr; + + next = aNode->GetNextSibling(); + if (next) + return next; + + // Go up + for (;;) { + if (aOnLeaveNode) { + aOnLeaveNode(aNode, aClosure); + } + + next = aNode->GetParent(); + if (next == aRoot || ! next) + return nullptr; + aNode = next; + + next = aNode->GetNextSibling(); + if (next) + return next; + } +} + +// aNode is not a text node. Find the first text node starting at aNode/aOffset +// in a preorder DOM traversal. +static nsINode* +FindNextTextNode(nsINode* aNode, int32_t aOffset, nsINode* aRoot) +{ + NS_PRECONDITION(aNode, "Null starting node?"); + NS_ASSERTION(!IsTextNode(aNode), "FindNextTextNode should start with a non-text node"); + + nsINode* checkNode; + // Need to start at the aOffset'th child + nsIContent* child = aNode->GetChildAt(aOffset); + + if (child) { + checkNode = child; + } else { + // aOffset was beyond the end of the child list. + // goto next node after the last descendant of aNode in + // a preorder DOM traversal. + checkNode = aNode->GetNextNonChildNode(aRoot); + } + + while (checkNode && !IsTextNode(checkNode)) { + checkNode = checkNode->GetNextNode(aRoot); + } + return checkNode; +} + +// mozInlineSpellWordUtil::SetEnd +// +// We have two ranges "hard" and "soft". The hard boundary is simply +// the scope of the root node. The soft boundary is that which is set +// by the caller of this class by calling this function. If this function is +// not called, the soft boundary is the same as the hard boundary. +// +// When we reach the soft boundary (mSoftEnd), we keep +// going until we reach the end of a word. This allows the caller to set the +// end of the range to anything, and we will always check whole multiples of +// words. When we reach the hard boundary we stop no matter what. +// +// There is no beginning soft boundary. This is because we only go to the +// previous node once, when finding the previous word boundary in +// SetPosition(). You might think of the soft boundary as being this initial +// position. + +nsresult +mozInlineSpellWordUtil::SetEnd(nsINode* aEndNode, int32_t aEndOffset) +{ + NS_PRECONDITION(aEndNode, "Null end node?"); + + NS_ASSERTION(mRootNode, "Not initialized"); + + InvalidateWords(); + + if (!IsTextNode(aEndNode)) { + // End at the start of the first text node after aEndNode/aEndOffset. + aEndNode = FindNextTextNode(aEndNode, aEndOffset, mRootNode); + aEndOffset = 0; + } + mSoftEnd = NodeOffset(aEndNode, aEndOffset); + return NS_OK; +} + +nsresult +mozInlineSpellWordUtil::SetPosition(nsINode* aNode, int32_t aOffset) +{ + InvalidateWords(); + + if (!IsTextNode(aNode)) { + // Start at the start of the first text node after aNode/aOffset. + aNode = FindNextTextNode(aNode, aOffset, mRootNode); + aOffset = 0; + } + mSoftBegin = NodeOffset(aNode, aOffset); + + nsresult rv = EnsureWords(); + if (NS_FAILED(rv)) { + return rv; + } + + int32_t textOffset = MapDOMPositionToSoftTextOffset(mSoftBegin); + if (textOffset < 0) + return NS_OK; + mNextWordIndex = FindRealWordContaining(textOffset, HINT_END, true); + return NS_OK; +} + +nsresult +mozInlineSpellWordUtil::EnsureWords() +{ + if (mSoftTextValid) + return NS_OK; + BuildSoftText(); + nsresult rv = BuildRealWords(); + if (NS_FAILED(rv)) { + mRealWords.Clear(); + return rv; + } + mSoftTextValid = true; + return NS_OK; +} + +nsresult +mozInlineSpellWordUtil::MakeRangeForWord(const RealWord& aWord, nsRange** aRange) +{ + NodeOffset begin = MapSoftTextOffsetToDOMPosition(aWord.mSoftTextOffset, HINT_BEGIN); + NodeOffset end = MapSoftTextOffsetToDOMPosition(aWord.EndOffset(), HINT_END); + return MakeRange(begin, end, aRange); +} + +// mozInlineSpellWordUtil::GetRangeForWord + +nsresult +mozInlineSpellWordUtil::GetRangeForWord(nsIDOMNode* aWordNode, + int32_t aWordOffset, + nsRange** aRange) +{ + // Set our soft end and start + nsCOMPtr wordNode = do_QueryInterface(aWordNode); + NodeOffset pt = NodeOffset(wordNode, aWordOffset); + + if (!mSoftTextValid || pt != mSoftBegin || pt != mSoftEnd) { + InvalidateWords(); + mSoftBegin = mSoftEnd = pt; + nsresult rv = EnsureWords(); + if (NS_FAILED(rv)) { + return rv; + } + } + + int32_t offset = MapDOMPositionToSoftTextOffset(pt); + if (offset < 0) + return MakeRange(pt, pt, aRange); + int32_t wordIndex = FindRealWordContaining(offset, HINT_BEGIN, false); + if (wordIndex < 0) + return MakeRange(pt, pt, aRange); + return MakeRangeForWord(mRealWords[wordIndex], aRange); +} + +// This is to fix characters that the spellchecker may not like +static void +NormalizeWord(const nsSubstring& aInput, int32_t aPos, int32_t aLen, nsAString& aOutput) +{ + aOutput.Truncate(); + for (int32_t i = 0; i < aLen; i++) { + char16_t ch = aInput.CharAt(i + aPos); + + // remove ignorable characters from the word + if (IsIgnorableCharacter(ch)) + continue; + + // the spellchecker doesn't handle curly apostrophes in all languages + if (ch == 0x2019) { // RIGHT SINGLE QUOTATION MARK + ch = '\''; + } + + aOutput.Append(ch); + } +} + +// mozInlineSpellWordUtil::GetNextWord +// +// FIXME-optimization: we shouldn't have to generate a range every single +// time. It would be better if the inline spellchecker didn't require a +// range unless the word was misspelled. This may or may not be possible. + +nsresult +mozInlineSpellWordUtil::GetNextWord(nsAString& aText, nsRange** aRange, + bool* aSkipChecking) +{ +#ifdef DEBUG_SPELLCHECK + printf("GetNextWord called; mNextWordIndex=%d\n", mNextWordIndex); +#endif + + if (mNextWordIndex < 0 || + mNextWordIndex >= int32_t(mRealWords.Length())) { + mNextWordIndex = -1; + *aRange = nullptr; + *aSkipChecking = true; + return NS_OK; + } + + const RealWord& word = mRealWords[mNextWordIndex]; + nsresult rv = MakeRangeForWord(word, aRange); + NS_ENSURE_SUCCESS(rv, rv); + ++mNextWordIndex; + *aSkipChecking = !word.mCheckableWord; + ::NormalizeWord(mSoftText, word.mSoftTextOffset, word.mLength, aText); + +#ifdef DEBUG_SPELLCHECK + printf("GetNextWord returning: %s (skip=%d)\n", + NS_ConvertUTF16toUTF8(aText).get(), *aSkipChecking); +#endif + + return NS_OK; +} + +// mozInlineSpellWordUtil::MakeRange +// +// Convenience function for creating a range over the current document. + +nsresult +mozInlineSpellWordUtil::MakeRange(NodeOffset aBegin, NodeOffset aEnd, + nsRange** aRange) +{ + NS_ENSURE_ARG_POINTER(aBegin.mNode); + if (!mDOMDocument) + return NS_ERROR_NOT_INITIALIZED; + + RefPtr range = new nsRange(aBegin.mNode); + nsresult rv = range->Set(aBegin.mNode, aBegin.mOffset, + aEnd.mNode, aEnd.mOffset); + NS_ENSURE_SUCCESS(rv, rv); + range.forget(aRange); + + return NS_OK; +} + +/*********** DOM text extraction ************/ + +// IsDOMWordSeparator +// +// Determines if the given character should be considered as a DOM Word +// separator. Basically, this is whitespace, although it could also have +// certain punctuation that we know ALWAYS breaks words. This is important. +// For example, we can't have any punctuation that could appear in a URL +// or email address in this, because those need to always fit into a single +// DOM word. + +static bool +IsDOMWordSeparator(char16_t ch) +{ + // simple spaces + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + return true; + + // complex spaces - check only if char isn't ASCII (uncommon) + if (ch >= 0xA0 && + (ch == 0x00A0 || // NO-BREAK SPACE + ch == 0x2002 || // EN SPACE + ch == 0x2003 || // EM SPACE + ch == 0x2009 || // THIN SPACE + ch == 0x3000)) // IDEOGRAPHIC SPACE + return true; + + // otherwise not a space + return false; +} + +static inline bool +IsBRElement(nsINode* aNode) +{ + return aNode->IsHTMLElement(nsGkAtoms::br); +} + +/** + * Given a TextNode, checks to see if there's a DOM word separator before + * aBeforeOffset within it. This function does not modify aSeparatorOffset when + * it returns false. + * + * @param aNode the TextNode to check. + * @param aBeforeOffset the offset in the TextNode before which we will search + * for the DOM separator. You can pass INT32_MAX to search the entire + * length of the string. + * @param aSeparatorOffset will be set to the offset of the first separator it + * encounters. Will not be written to if no separator is found. + * @returns True if it found a separator. + */ +static bool +TextNodeContainsDOMWordSeparator(nsINode* aNode, + int32_t aBeforeOffset, + int32_t* aSeparatorOffset) +{ + // aNode is actually an nsIContent, since it's eTEXT + nsIContent* content = static_cast(aNode); + const nsTextFragment* textFragment = content->GetText(); + NS_ASSERTION(textFragment, "Where is our text?"); + for (int32_t i = std::min(aBeforeOffset, int32_t(textFragment->GetLength())) - 1; i >= 0; --i) { + if (IsDOMWordSeparator(textFragment->CharAt(i))) { + // Be greedy, find as many separators as we can + for (int32_t j = i - 1; j >= 0; --j) { + if (IsDOMWordSeparator(textFragment->CharAt(j))) { + i = j; + } else { + break; + } + } + *aSeparatorOffset = i; + return true; + } + } + return false; +} + +/** + * Check if there's a DOM word separator before aBeforeOffset in this node. + * Always returns true if it's a BR element. + * aSeparatorOffset is set to the index of the first character in the last + * separator if any is found (0 for BR elements). + * + * This function does not modify aSeparatorOffset when it returns false. + */ +static bool +ContainsDOMWordSeparator(nsINode* aNode, int32_t aBeforeOffset, + int32_t* aSeparatorOffset) +{ + if (IsBRElement(aNode)) { + *aSeparatorOffset = 0; + return true; + } + + if (!IsTextNode(aNode)) + return false; + + return TextNodeContainsDOMWordSeparator(aNode, aBeforeOffset, + aSeparatorOffset); +} + +static bool +IsBreakElement(nsINode* aNode) +{ + if (!aNode->IsElement()) { + return false; + } + + dom::Element *element = aNode->AsElement(); + + if (element->IsHTMLElement(nsGkAtoms::br)) + return true; + + // If we don't have a frame, we don't consider ourselves a break + // element. In particular, words can span us. + if (!element->GetPrimaryFrame()) + return false; + + // Anything that's not an inline element is a break element. + // XXXbz should replaced inlines be break elements, though? + return element->GetPrimaryFrame()->StyleDisplay()->mDisplay != + StyleDisplay::Inline; +} + +struct CheckLeavingBreakElementClosure { + bool mLeftBreakElement; +}; + +static void +CheckLeavingBreakElement(nsINode* aNode, void* aClosure) +{ + CheckLeavingBreakElementClosure* cl = + static_cast(aClosure); + if (!cl->mLeftBreakElement && IsBreakElement(aNode)) { + cl->mLeftBreakElement = true; + } +} + +void +mozInlineSpellWordUtil::NormalizeWord(nsSubstring& aWord) +{ + nsAutoString result; + ::NormalizeWord(aWord, 0, aWord.Length(), result); + aWord = result; +} + +void +mozInlineSpellWordUtil::BuildSoftText() +{ + // First we have to work backwards from mSoftStart to find a text node + // containing a DOM word separator, a non-inline-element + // boundary, or the hard start node. That's where we'll start building the + // soft string from. + nsINode* node = mSoftBegin.mNode; + int32_t firstOffsetInNode = 0; + int32_t checkBeforeOffset = mSoftBegin.mOffset; + while (node) { + if (ContainsDOMWordSeparator(node, checkBeforeOffset, &firstOffsetInNode)) { + if (node == mSoftBegin.mNode) { + // If we find a word separator on the first node, look at the preceding + // word on the text node as well. + int32_t newOffset = 0; + if (firstOffsetInNode > 0) { + // Try to find the previous word boundary in the current node. If + // we can't find one, start checking previous sibling nodes (if any + // adjacent ones exist) to see if we can find any text nodes with + // DOM word separators. We bail out as soon as we see a node that is + // not a text node, or we run out of previous sibling nodes. In the + // event that we simply cannot find any preceding word separator, the + // offset is set to 0, and the soft text beginning node is set to the + // "most previous" text node before the original starting node, or + // kept at the original starting node if no previous text nodes exist. + if (!ContainsDOMWordSeparator(node, firstOffsetInNode - 1, + &newOffset)) { + nsINode* prevNode = node->GetPreviousSibling(); + while (prevNode && IsTextNode(prevNode)) { + mSoftBegin.mNode = prevNode; + if (TextNodeContainsDOMWordSeparator(prevNode, INT32_MAX, + &newOffset)) { + break; + } + prevNode = prevNode->GetPreviousSibling(); + } + } + } + firstOffsetInNode = newOffset; + mSoftBegin.mOffset = newOffset; + } + break; + } + checkBeforeOffset = INT32_MAX; + if (IsBreakElement(node)) { + // Since GetPreviousContent follows tree *preorder*, we're about to traverse + // up out of 'node'. Since node induces breaks (e.g., it's a block), + // don't bother trying to look outside it, just stop now. + break; + } + // GetPreviousContent below expects mRootNode to be an ancestor of node. + if (!nsContentUtils::ContentIsDescendantOf(node, mRootNode)) { + break; + } + node = node->GetPreviousContent(mRootNode); + } + + // Now build up the string moving forward through the DOM until we reach + // the soft end and *then* see a DOM word separator, a non-inline-element + // boundary, or the hard end node. + mSoftText.Truncate(); + mSoftTextDOMMapping.Clear(); + bool seenSoftEnd = false; + // Leave this outside the loop so large heap string allocations can be reused + // across iterations + while (node) { + if (node == mSoftEnd.mNode) { + seenSoftEnd = true; + } + + bool exit = false; + if (IsTextNode(node)) { + nsIContent* content = static_cast(node); + NS_ASSERTION(content, "Where is our content?"); + const nsTextFragment* textFragment = content->GetText(); + NS_ASSERTION(textFragment, "Where is our text?"); + int32_t lastOffsetInNode = textFragment->GetLength(); + + if (seenSoftEnd) { + // check whether we can stop after this + for (int32_t i = node == mSoftEnd.mNode ? mSoftEnd.mOffset : 0; + i < int32_t(textFragment->GetLength()); ++i) { + if (IsDOMWordSeparator(textFragment->CharAt(i))) { + exit = true; + // stop at the first separator after the soft end point + lastOffsetInNode = i; + break; + } + } + } + + if (firstOffsetInNode < lastOffsetInNode) { + int32_t len = lastOffsetInNode - firstOffsetInNode; + mSoftTextDOMMapping.AppendElement( + DOMTextMapping(NodeOffset(node, firstOffsetInNode), mSoftText.Length(), len)); + + bool ok = textFragment->AppendTo(mSoftText, firstOffsetInNode, len, + mozilla::fallible); + if (!ok) { + // probably out of memory, remove from mSoftTextDOMMapping + mSoftTextDOMMapping.RemoveElementAt(mSoftTextDOMMapping.Length() - 1); + exit = true; + } + } + + firstOffsetInNode = 0; + } + + if (exit) + break; + + CheckLeavingBreakElementClosure closure = { false }; + node = FindNextNode(node, mRootNode, CheckLeavingBreakElement, &closure); + if (closure.mLeftBreakElement || (node && IsBreakElement(node))) { + // We left, or are entering, a break element (e.g., block). Maybe we can + // stop now. + if (seenSoftEnd) + break; + // Record the break + mSoftText.Append(' '); + } + } + +#ifdef DEBUG_SPELLCHECK + printf("Got DOM string: %s\n", NS_ConvertUTF16toUTF8(mSoftText).get()); +#endif +} + +nsresult +mozInlineSpellWordUtil::BuildRealWords() +{ + // This is pretty simple. We just have to walk mSoftText, tokenizing it + // into "real words". + // We do an outer traversal of words delimited by IsDOMWordSeparator, calling + // SplitDOMWord on each of those DOM words + int32_t wordStart = -1; + mRealWords.Clear(); + for (int32_t i = 0; i < int32_t(mSoftText.Length()); ++i) { + if (IsDOMWordSeparator(mSoftText.CharAt(i))) { + if (wordStart >= 0) { + nsresult rv = SplitDOMWord(wordStart, i); + if (NS_FAILED(rv)) { + return rv; + } + wordStart = -1; + } + } else { + if (wordStart < 0) { + wordStart = i; + } + } + } + if (wordStart >= 0) { + nsresult rv = SplitDOMWord(wordStart, mSoftText.Length()); + if (NS_FAILED(rv)) { + return rv; + } + } + + return NS_OK; +} + +/*********** DOM/realwords<->mSoftText mapping functions ************/ + +int32_t +mozInlineSpellWordUtil::MapDOMPositionToSoftTextOffset(NodeOffset aNodeOffset) +{ + if (!mSoftTextValid) { + NS_ERROR("Soft text must be valid if we're to map into it"); + return -1; + } + + for (int32_t i = 0; i < int32_t(mSoftTextDOMMapping.Length()); ++i) { + const DOMTextMapping& map = mSoftTextDOMMapping[i]; + if (map.mNodeOffset.mNode == aNodeOffset.mNode) { + // Allow offsets at either end of the string, in particular, allow the + // offset that's at the end of the contributed string + int32_t offsetInContributedString = + aNodeOffset.mOffset - map.mNodeOffset.mOffset; + if (offsetInContributedString >= 0 && + offsetInContributedString <= map.mLength) + return map.mSoftTextOffset + offsetInContributedString; + return -1; + } + } + return -1; +} + +namespace { + +template +class FirstLargerOffset +{ + int32_t mSoftTextOffset; + +public: + explicit FirstLargerOffset(int32_t aSoftTextOffset) : mSoftTextOffset(aSoftTextOffset) {} + int operator()(const T& t) const { + // We want the first larger offset, so never return 0 (which would + // short-circuit evaluation before finding the last such offset). + return mSoftTextOffset < t.mSoftTextOffset ? -1 : 1; + } +}; + +template +bool +FindLastNongreaterOffset(const nsTArray& aContainer, int32_t aSoftTextOffset, size_t* aIndex) +{ + if (aContainer.Length() == 0) { + return false; + } + + BinarySearchIf(aContainer, 0, aContainer.Length(), + FirstLargerOffset(aSoftTextOffset), aIndex); + if (*aIndex > 0) { + // There was at least one mapping with offset <= aSoftTextOffset. Step back + // to find the last element with |mSoftTextOffset <= aSoftTextOffset|. + *aIndex -= 1; + } else { + // Every mapping had offset greater than aSoftTextOffset. + MOZ_ASSERT(aContainer[*aIndex].mSoftTextOffset > aSoftTextOffset); + } + return true; +} + +} // namespace + +mozInlineSpellWordUtil::NodeOffset +mozInlineSpellWordUtil::MapSoftTextOffsetToDOMPosition(int32_t aSoftTextOffset, + DOMMapHint aHint) +{ + NS_ASSERTION(mSoftTextValid, "Soft text must be valid if we're to map out of it"); + if (!mSoftTextValid) + return NodeOffset(nullptr, -1); + + // Find the last mapping, if any, such that mSoftTextOffset <= aSoftTextOffset + size_t index; + bool found = FindLastNongreaterOffset(mSoftTextDOMMapping, aSoftTextOffset, &index); + if (!found) { + return NodeOffset(nullptr, -1); + } + + // 'index' is now the last mapping, if any, such that + // mSoftTextOffset <= aSoftTextOffset. + // If we're doing HINT_END, then we may want to return the end of the + // the previous mapping instead of the start of this mapping + if (aHint == HINT_END && index > 0) { + const DOMTextMapping& map = mSoftTextDOMMapping[index - 1]; + if (map.mSoftTextOffset + map.mLength == aSoftTextOffset) + return NodeOffset(map.mNodeOffset.mNode, map.mNodeOffset.mOffset + map.mLength); + } + + // We allow ourselves to return the end of this mapping even if we're + // doing HINT_START. This will only happen if there is no mapping which this + // point is the start of. I'm not 100% sure this is OK... + const DOMTextMapping& map = mSoftTextDOMMapping[index]; + int32_t offset = aSoftTextOffset - map.mSoftTextOffset; + if (offset >= 0 && offset <= map.mLength) + return NodeOffset(map.mNodeOffset.mNode, map.mNodeOffset.mOffset + offset); + + return NodeOffset(nullptr, -1); +} + +int32_t +mozInlineSpellWordUtil::FindRealWordContaining(int32_t aSoftTextOffset, + DOMMapHint aHint, bool aSearchForward) +{ + NS_ASSERTION(mSoftTextValid, "Soft text must be valid if we're to map out of it"); + if (!mSoftTextValid) + return -1; + + // Find the last word, if any, such that mSoftTextOffset <= aSoftTextOffset + size_t index; + bool found = FindLastNongreaterOffset(mRealWords, aSoftTextOffset, &index); + if (!found) { + return -1; + } + + // 'index' is now the last word, if any, such that + // mSoftTextOffset <= aSoftTextOffset. + // If we're doing HINT_END, then we may want to return the end of the + // the previous word instead of the start of this word + if (aHint == HINT_END && index > 0) { + const RealWord& word = mRealWords[index - 1]; + if (word.mSoftTextOffset + word.mLength == aSoftTextOffset) + return index - 1; + } + + // We allow ourselves to return the end of this word even if we're + // doing HINT_START. This will only happen if there is no word which this + // point is the start of. I'm not 100% sure this is OK... + const RealWord& word = mRealWords[index]; + int32_t offset = aSoftTextOffset - word.mSoftTextOffset; + if (offset >= 0 && offset <= static_cast(word.mLength)) + return index; + + if (aSearchForward) { + if (mRealWords[0].mSoftTextOffset > aSoftTextOffset) { + // All words have mSoftTextOffset > aSoftTextOffset + return 0; + } + // 'index' is the last word such that mSoftTextOffset <= aSoftTextOffset. + // Word index+1, if it exists, will be the first with + // mSoftTextOffset > aSoftTextOffset. + if (index + 1 < mRealWords.Length()) + return index + 1; + } + + return -1; +} + +/*********** Word Splitting ************/ + +// classifies a given character in the DOM word +enum CharClass { + CHAR_CLASS_WORD, + CHAR_CLASS_SEPARATOR, + CHAR_CLASS_END_OF_INPUT }; + +// Encapsulates DOM-word to real-word splitting +struct MOZ_STACK_CLASS WordSplitState +{ + mozInlineSpellWordUtil* mWordUtil; + const nsDependentSubstring mDOMWordText; + int32_t mDOMWordOffset; + CharClass mCurCharClass; + + WordSplitState(mozInlineSpellWordUtil* aWordUtil, + const nsString& aString, int32_t aStart, int32_t aLen) + : mWordUtil(aWordUtil), mDOMWordText(aString, aStart, aLen), + mDOMWordOffset(0), mCurCharClass(CHAR_CLASS_END_OF_INPUT) {} + + CharClass ClassifyCharacter(int32_t aIndex, bool aRecurse) const; + void Advance(); + void AdvanceThroughSeparators(); + void AdvanceThroughWord(); + + // Finds special words like email addresses and URLs that may start at the + // current position, and returns their length, or 0 if not found. This allows + // arbitrary word breaking rules to be used for these special entities, as + // long as they can not contain whitespace. + bool IsSpecialWord(); + + // Similar to IsSpecialWord except that this takes a split word as + // input. This checks for things that do not require special word-breaking + // rules. + bool ShouldSkipWord(int32_t aStart, int32_t aLength); +}; + +// WordSplitState::ClassifyCharacter + +CharClass +WordSplitState::ClassifyCharacter(int32_t aIndex, bool aRecurse) const +{ + NS_ASSERTION(aIndex >= 0 && aIndex <= int32_t(mDOMWordText.Length()), + "Index out of range"); + if (aIndex == int32_t(mDOMWordText.Length())) + return CHAR_CLASS_SEPARATOR; + + // this will classify the character, we want to treat "ignorable" characters + // such as soft hyphens, and also ZWJ and ZWNJ as word characters. + nsIUGenCategory::nsUGenCategory + charCategory = mozilla::unicode::GetGenCategory(mDOMWordText[aIndex]); + if (charCategory == nsIUGenCategory::kLetter || + IsIgnorableCharacter(mDOMWordText[aIndex]) || + mDOMWordText[aIndex] == 0x200C /* ZWNJ */ || + mDOMWordText[aIndex] == 0x200D /* ZWJ */) + return CHAR_CLASS_WORD; + + // If conditional punctuation is surrounded immediately on both sides by word + // characters it also counts as a word character. + if (IsConditionalPunctuation(mDOMWordText[aIndex])) { + if (!aRecurse) { + // not allowed to look around, this punctuation counts like a separator + return CHAR_CLASS_SEPARATOR; + } + + // check the left-hand character + if (aIndex == 0) + return CHAR_CLASS_SEPARATOR; + if (ClassifyCharacter(aIndex - 1, false) != CHAR_CLASS_WORD) + return CHAR_CLASS_SEPARATOR; + // If the previous charatcer is a word-char, make sure that it's not a + // special dot character. + if (mDOMWordText[aIndex - 1] == '.') + return CHAR_CLASS_SEPARATOR; + + // now we know left char is a word-char, check the right-hand character + if (aIndex == int32_t(mDOMWordText.Length()) - 1) + return CHAR_CLASS_SEPARATOR; + if (ClassifyCharacter(aIndex + 1, false) != CHAR_CLASS_WORD) + return CHAR_CLASS_SEPARATOR; + // If the next charatcer is a word-char, make sure that it's not a + // special dot character. + if (mDOMWordText[aIndex + 1] == '.') + return CHAR_CLASS_SEPARATOR; + + // char on either side is a word, this counts as a word + return CHAR_CLASS_WORD; + } + + // The dot character, if appearing at the end of a word, should + // be considered part of that word. Example: "etc.", or + // abbreviations + if (aIndex > 0 && + mDOMWordText[aIndex] == '.' && + mDOMWordText[aIndex - 1] != '.' && + ClassifyCharacter(aIndex - 1, false) != CHAR_CLASS_WORD) { + return CHAR_CLASS_WORD; + } + + // all other punctuation + if (charCategory == nsIUGenCategory::kSeparator || + charCategory == nsIUGenCategory::kOther || + charCategory == nsIUGenCategory::kPunctuation || + charCategory == nsIUGenCategory::kSymbol) { + // Don't break on hyphens, as hunspell handles them on its own. + if (aIndex > 0 && + mDOMWordText[aIndex] == '-' && + mDOMWordText[aIndex - 1] != '-' && + ClassifyCharacter(aIndex - 1, false) == CHAR_CLASS_WORD) { + // A hyphen is only meaningful as a separator inside a word + // if the previous and next characters are a word character. + if (aIndex == int32_t(mDOMWordText.Length()) - 1) + return CHAR_CLASS_SEPARATOR; + if (mDOMWordText[aIndex + 1] != '.' && + ClassifyCharacter(aIndex + 1, false) == CHAR_CLASS_WORD) + return CHAR_CLASS_WORD; + } + return CHAR_CLASS_SEPARATOR; + } + + // any other character counts as a word + return CHAR_CLASS_WORD; +} + + +// WordSplitState::Advance + +void +WordSplitState::Advance() +{ + NS_ASSERTION(mDOMWordOffset >= 0, "Negative word index"); + NS_ASSERTION(mDOMWordOffset < (int32_t)mDOMWordText.Length(), + "Length beyond end"); + + mDOMWordOffset ++; + if (mDOMWordOffset >= (int32_t)mDOMWordText.Length()) + mCurCharClass = CHAR_CLASS_END_OF_INPUT; + else + mCurCharClass = ClassifyCharacter(mDOMWordOffset, true); +} + + +// WordSplitState::AdvanceThroughSeparators + +void +WordSplitState::AdvanceThroughSeparators() +{ + while (mCurCharClass == CHAR_CLASS_SEPARATOR) + Advance(); +} + +// WordSplitState::AdvanceThroughWord + +void +WordSplitState::AdvanceThroughWord() +{ + while (mCurCharClass == CHAR_CLASS_WORD) + Advance(); +} + + +// WordSplitState::IsSpecialWord + +bool +WordSplitState::IsSpecialWord() +{ + // Search for email addresses. We simply define these as any sequence of + // characters with an '@' character in the middle. The DOM word is already + // split on whitepace, so we know that everything to the end is the address + int32_t firstColon = -1; + for (int32_t i = mDOMWordOffset; + i < int32_t(mDOMWordText.Length()); i ++) { + if (mDOMWordText[i] == '@') { + // only accept this if there are unambiguous word characters (don't bother + // recursing to disambiguate apostrophes) on each side. This prevents + // classifying, e.g. "@home" as an email address + + // Use this condition to only accept words with '@' in the middle of + // them. It works, but the inlinespellcker doesn't like this. The problem + // is that you type "fhsgfh@" that's a misspelled word followed by a + // symbol, but when you type another letter "fhsgfh@g" that first word + // need to be unmarked misspelled. It doesn't do this. it only checks the + // current position for potentially removing a spelling range. + if (i > 0 && ClassifyCharacter(i - 1, false) == CHAR_CLASS_WORD && + i < (int32_t)mDOMWordText.Length() - 1 && + ClassifyCharacter(i + 1, false) == CHAR_CLASS_WORD) { + return true; + } + } else if (mDOMWordText[i] == ':' && firstColon < 0) { + firstColon = i; + + // If the first colon is followed by a slash, consider it a URL + // This will catch things like asdf://foo.com + if (firstColon < (int32_t)mDOMWordText.Length() - 1 && + mDOMWordText[firstColon + 1] == '/') { + return true; + } + } + } + + // Check the text before the first colon against some known protocols. It + // is impossible to check against all protocols, especially since you can + // plug in new protocols. We also don't want to waste time here checking + // against a lot of obscure protocols. + if (firstColon > mDOMWordOffset) { + nsString protocol(Substring(mDOMWordText, mDOMWordOffset, + firstColon - mDOMWordOffset)); + if (protocol.EqualsIgnoreCase("http") || + protocol.EqualsIgnoreCase("https") || + protocol.EqualsIgnoreCase("news") || + protocol.EqualsIgnoreCase("file") || + protocol.EqualsIgnoreCase("javascript") || + protocol.EqualsIgnoreCase("data") || + protocol.EqualsIgnoreCase("ftp")) { + return true; + } + } + + // not anything special + return false; +} + +// WordSplitState::ShouldSkipWord + +bool +WordSplitState::ShouldSkipWord(int32_t aStart, int32_t aLength) +{ + int32_t last = aStart + aLength; + + // check to see if the word contains a digit + for (int32_t i = aStart; i < last; i ++) { + if (unicode::GetGenCategory(mDOMWordText[i]) == nsIUGenCategory::kNumber) { + return true; + } + } + + // not special + return false; +} + +// mozInlineSpellWordUtil::SplitDOMWord + +nsresult +mozInlineSpellWordUtil::SplitDOMWord(int32_t aStart, int32_t aEnd) +{ + WordSplitState state(this, mSoftText, aStart, aEnd - aStart); + state.mCurCharClass = state.ClassifyCharacter(0, true); + + state.AdvanceThroughSeparators(); + if (state.mCurCharClass != CHAR_CLASS_END_OF_INPUT && + state.IsSpecialWord()) { + int32_t specialWordLength = state.mDOMWordText.Length() - state.mDOMWordOffset; + if (!mRealWords.AppendElement( + RealWord(aStart + state.mDOMWordOffset, specialWordLength, false), + fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; + } + + while (state.mCurCharClass != CHAR_CLASS_END_OF_INPUT) { + state.AdvanceThroughSeparators(); + if (state.mCurCharClass == CHAR_CLASS_END_OF_INPUT) + break; + + // save the beginning of the word + int32_t wordOffset = state.mDOMWordOffset; + + // find the end of the word + state.AdvanceThroughWord(); + int32_t wordLen = state.mDOMWordOffset - wordOffset; + if (!mRealWords.AppendElement( + RealWord(aStart + wordOffset, wordLen, + !state.ShouldSkipWord(wordOffset, wordLen)), fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + return NS_OK; +} diff --git a/extensions/spellcheck/src/mozInlineSpellWordUtil.h b/extensions/spellcheck/src/mozInlineSpellWordUtil.h new file mode 100644 index 000000000..b28d24ae5 --- /dev/null +++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.h @@ -0,0 +1,179 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozInlineSpellWordUtil_h +#define mozInlineSpellWordUtil_h + +#include "nsCOMPtr.h" +#include "nsIDOMDocument.h" +#include "nsIDocument.h" +#include "nsString.h" +#include "nsTArray.h" + +//#define DEBUG_SPELLCHECK + +class nsRange; +class nsINode; + +/** + * This class extracts text from the DOM and builds it into a single string. + * The string includes whitespace breaks whereever non-inline elements begin + * and end. This string is broken into "real words", following somewhat + * complex rules; for example substrings that look like URLs or + * email addresses are treated as single words, but otherwise many kinds of + * punctuation are treated as word separators. GetNextWord provides a way + * to iterate over these "real words". + * + * The basic operation is: + * + * 1. Call Init with the weak pointer to the editor that you're using. + * 2. Call SetEnd to set where you want to stop spellchecking. We'll stop + * at the word boundary after that. If SetEnd is not called, we'll stop + * at the end of the document's root element. + * 3. Call SetPosition to initialize the current position inside the + * previously given range. + * 4. Call GetNextWord over and over until it returns false. + */ + +class mozInlineSpellWordUtil +{ +public: + struct NodeOffset { + nsINode* mNode; + int32_t mOffset; + + NodeOffset(nsINode* aNode, int32_t aOffset) : + mNode(aNode), mOffset(aOffset) {} + + bool operator==(const NodeOffset& aOther) const { + return mNode == aOther.mNode && mOffset == aOther.mOffset; + } + + bool operator!=(const NodeOffset& aOther) const { + return !(*this == aOther); + } + }; + + mozInlineSpellWordUtil() + : mRootNode(nullptr), + mSoftBegin(nullptr, 0), mSoftEnd(nullptr, 0), + mNextWordIndex(-1), mSoftTextValid(false) {} + + nsresult Init(nsWeakPtr aWeakEditor); + + nsresult SetEnd(nsINode* aEndNode, int32_t aEndOffset); + + // sets the current position, this should be inside the range. If we are in + // the middle of a word, we'll move to its start. + nsresult SetPosition(nsINode* aNode, int32_t aOffset); + + // Given a point inside or immediately following a word, this returns the + // DOM range that exactly encloses that word's characters. The current + // position will be at the end of the word. This will find the previous + // word if the current position is space, so if you care that the point is + // inside the word, you should check the range. + // + // THIS CHANGES THE CURRENT POSITION AND RANGE. It is designed to be called + // before you actually generate the range you are interested in and iterate + // the words in it. + nsresult GetRangeForWord(nsIDOMNode* aWordNode, int32_t aWordOffset, + nsRange** aRange); + + // Moves to the the next word in the range, and retrieves it's text and range. + // An empty word and a nullptr range are returned when we are done checking. + // aSkipChecking will be set if the word is "special" and shouldn't be + // checked (e.g., an email address). + nsresult GetNextWord(nsAString& aText, nsRange** aRange, + bool* aSkipChecking); + + // Call to normalize some punctuation. This function takes an autostring + // so we can access characters directly. + static void NormalizeWord(nsSubstring& aWord); + + nsIDOMDocument* GetDOMDocument() const { return mDOMDocument; } + nsIDocument* GetDocument() const { return mDocument; } + nsINode* GetRootNode() { return mRootNode; } + +private: + + // cached stuff for the editor, set by Init + nsCOMPtr mDOMDocument; + nsCOMPtr mDocument; + + // range to check, see SetPosition and SetEnd + nsINode* mRootNode; + NodeOffset mSoftBegin; + NodeOffset mSoftEnd; + + // DOM text covering the soft range, with newlines added at block boundaries + nsString mSoftText; + // A list of where we extracted text from, ordered by mSoftTextOffset. A given + // DOM node appears at most once in this list. + struct DOMTextMapping { + NodeOffset mNodeOffset; + int32_t mSoftTextOffset; + int32_t mLength; + + DOMTextMapping(NodeOffset aNodeOffset, int32_t aSoftTextOffset, int32_t aLength) + : mNodeOffset(aNodeOffset), mSoftTextOffset(aSoftTextOffset), + mLength(aLength) {} + }; + nsTArray mSoftTextDOMMapping; + + // A list of the "real words" in mSoftText, ordered by mSoftTextOffset + struct RealWord { + int32_t mSoftTextOffset; + uint32_t mLength : 31; + uint32_t mCheckableWord : 1; + + RealWord(int32_t aOffset, uint32_t aLength, bool aCheckable) + : mSoftTextOffset(aOffset), mLength(aLength), mCheckableWord(aCheckable) + { + static_assert(sizeof(RealWord) == 8, "RealWord should be limited to 8 bytes"); + MOZ_ASSERT(aLength < INT32_MAX, "Word length is too large to fit in the bitfield"); + } + + int32_t EndOffset() const { return mSoftTextOffset + mLength; } + }; + nsTArray mRealWords; + int32_t mNextWordIndex; + + bool mSoftTextValid; + + void InvalidateWords() { mSoftTextValid = false; } + nsresult EnsureWords(); + + int32_t MapDOMPositionToSoftTextOffset(NodeOffset aNodeOffset); + // Map an offset into mSoftText to a DOM position. Note that two DOM positions + // can map to the same mSoftText offset, e.g. given nodes A=aaaa and B=bbbb + // forming aaaabbbb, (A,4) and (B,0) give the same string offset. So, + // aHintBefore controls which position we return ... if aHint is eEnd + // then the position indicates the END of a range so we return (A,4). Otherwise + // the position indicates the START of a range so we return (B,0). + enum DOMMapHint { HINT_BEGIN, HINT_END }; + NodeOffset MapSoftTextOffsetToDOMPosition(int32_t aSoftTextOffset, + DOMMapHint aHint); + // Finds the index of the real word containing aSoftTextOffset, or -1 if none + // If it's exactly between two words, then if aHint is HINT_BEGIN, return the + // later word (favouring the assumption that it's the BEGINning of a word), + // otherwise return the earlier word (assuming it's the END of a word). + // If aSearchForward is true, then if we don't find a word at the given + // position, search forward until we do find a word and return that (if found). + int32_t FindRealWordContaining(int32_t aSoftTextOffset, DOMMapHint aHint, + bool aSearchForward); + + // build mSoftText and mSoftTextDOMMapping + void BuildSoftText(); + // Build mRealWords array + nsresult BuildRealWords(); + + nsresult SplitDOMWord(int32_t aStart, int32_t aEnd); + + // Convenience functions, object must be initialized + nsresult MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsRange** aRange); + nsresult MakeRangeForWord(const RealWord& aWord, nsRange** aRange); +}; + +#endif diff --git a/extensions/spellcheck/src/mozPersonalDictionary.cpp b/extensions/spellcheck/src/mozPersonalDictionary.cpp new file mode 100644 index 000000000..efaf14356 --- /dev/null +++ b/extensions/spellcheck/src/mozPersonalDictionary.cpp @@ -0,0 +1,471 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozPersonalDictionary.h" +#include "nsIUnicharInputStream.h" +#include "nsReadableUtils.h" +#include "nsIFile.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsIObserverService.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIWeakReference.h" +#include "nsCRT.h" +#include "nsNetUtil.h" +#include "nsNetCID.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsISafeOutputStream.h" +#include "nsTArray.h" +#include "nsStringEnumerator.h" +#include "nsUnicharInputStream.h" +#include "nsIRunnable.h" +#include "nsThreadUtils.h" +#include "nsProxyRelease.h" +#include "prio.h" +#include "mozilla/Move.h" + +#define MOZ_PERSONAL_DICT_NAME "persdict.dat" + +/** + * This is the most braindead implementation of a personal dictionary possible. + * There is not much complexity needed, though. It could be made much faster, + * and probably should, but I don't see much need for more in terms of interface. + * + * Allowing personal words to be associated with only certain dictionaries maybe. + * + * TODO: + * Implement the suggestion record. + */ + +NS_IMPL_CYCLE_COLLECTING_ADDREF(mozPersonalDictionary) +NS_IMPL_CYCLE_COLLECTING_RELEASE(mozPersonalDictionary) + +NS_INTERFACE_MAP_BEGIN(mozPersonalDictionary) + NS_INTERFACE_MAP_ENTRY(mozIPersonalDictionary) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIPersonalDictionary) + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozPersonalDictionary) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION(mozPersonalDictionary, mEncoder) + +class mozPersonalDictionaryLoader final : public mozilla::Runnable +{ +public: + explicit mozPersonalDictionaryLoader(mozPersonalDictionary *dict) : mDict(dict) + { + } + + NS_IMETHOD Run() override + { + mDict->SyncLoad(); + + // Release the dictionary on the main thread + NS_ReleaseOnMainThread(mDict.forget()); + + return NS_OK; + } + +private: + RefPtr mDict; +}; + +class mozPersonalDictionarySave final : public mozilla::Runnable +{ +public: + explicit mozPersonalDictionarySave(mozPersonalDictionary *aDict, + nsCOMPtr aFile, + nsTArray &&aDictWords) + : mDictWords(aDictWords), + mFile(aFile), + mDict(aDict) + { + } + + NS_IMETHOD Run() override + { + nsresult res; + + MOZ_ASSERT(!NS_IsMainThread()); + + { + mozilla::MonitorAutoLock mon(mDict->mMonitorSave); + + nsCOMPtr outStream; + NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStream), mFile, + PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, + 0664); + + // Get a buffered output stream 4096 bytes big, to optimize writes. + nsCOMPtr bufferedOutputStream; + res = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), + outStream, 4096); + if (NS_FAILED(res)) { + return res; + } + + uint32_t bytesWritten; + nsAutoCString utf8Key; + for (uint32_t i = 0; i < mDictWords.Length(); ++i) { + CopyUTF16toUTF8(mDictWords[i], utf8Key); + + bufferedOutputStream->Write(utf8Key.get(), utf8Key.Length(), + &bytesWritten); + bufferedOutputStream->Write("\n", 1, &bytesWritten); + } + nsCOMPtr safeStream = + do_QueryInterface(bufferedOutputStream); + NS_ASSERTION(safeStream, "expected a safe output stream!"); + if (safeStream) { + res = safeStream->Finish(); + if (NS_FAILED(res)) { + NS_WARNING("failed to save personal dictionary file! possible data loss"); + } + } + + // Save is done, reset the state variable and notify those who are waiting. + mDict->mSavePending = false; + mon.Notify(); + + // Leaving the block where 'mon' was declared will call the destructor + // and unlock. + } + + // Release the dictionary on the main thread. + NS_ReleaseOnMainThread(mDict.forget()); + + return NS_OK; + } + +private: + nsTArray mDictWords; + nsCOMPtr mFile; + RefPtr mDict; +}; + +mozPersonalDictionary::mozPersonalDictionary() + : mIsLoaded(false), + mSavePending(false), + mMonitor("mozPersonalDictionary::mMonitor"), + mMonitorSave("mozPersonalDictionary::mMonitorSave") +{ +} + +mozPersonalDictionary::~mozPersonalDictionary() +{ +} + +nsresult mozPersonalDictionary::Init() +{ + nsCOMPtr svc = + do_GetService("@mozilla.org/observer-service;1"); + + NS_ENSURE_STATE(svc); + // we want to reload the dictionary if the profile switches + nsresult rv = svc->AddObserver(this, "profile-do-change", true); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = svc->AddObserver(this, "profile-before-change", true); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + Load(); + + return NS_OK; +} + +void mozPersonalDictionary::WaitForLoad() +{ + // If the dictionary is already loaded, we return straight away. + if (mIsLoaded) { + return; + } + + // If the dictionary hasn't been loaded, we try to lock the same monitor + // that the thread uses that does the load. This way the main thread will + // be suspended until the monitor becomes available. + mozilla::MonitorAutoLock mon(mMonitor); + + // The monitor has become available. This can have two reasons: + // 1: The thread that does the load has finished. + // 2: The thread that does the load hasn't even started. + // In this case we need to wait. + if (!mIsLoaded) { + mon.Wait(); + } +} + +nsresult mozPersonalDictionary::LoadInternal() +{ + nsresult rv; + mozilla::MonitorAutoLock mon(mMonitor); + + if (mIsLoaded) { + return NS_OK; + } + + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mFile)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!mFile) { + return NS_ERROR_FAILURE; + } + + rv = mFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr runnable = new mozPersonalDictionaryLoader(this); + rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP mozPersonalDictionary::Load() +{ + nsresult rv = LoadInternal(); + + if (NS_FAILED(rv)) { + mIsLoaded = true; + } + + return rv; +} + +void mozPersonalDictionary::SyncLoad() +{ + MOZ_ASSERT(!NS_IsMainThread()); + + mozilla::MonitorAutoLock mon(mMonitor); + + if (mIsLoaded) { + return; + } + + SyncLoadInternal(); + mIsLoaded = true; + mon.Notify(); +} + +void mozPersonalDictionary::SyncLoadInternal() +{ + MOZ_ASSERT(!NS_IsMainThread()); + + //FIXME Deinst -- get dictionary name from prefs; + nsresult rv; + bool dictExists; + + rv = mFile->Exists(&dictExists); + if (NS_FAILED(rv)) { + return; + } + + if (!dictExists) { + // Nothing is really wrong... + return; + } + + nsCOMPtr inStream; + NS_NewLocalFileInputStream(getter_AddRefs(inStream), mFile); + + nsCOMPtr convStream; + rv = NS_NewUnicharInputStream(inStream, getter_AddRefs(convStream)); + if (NS_FAILED(rv)) { + return; + } + + // we're rereading to get rid of the old data -- we shouldn't have any, but... + mDictionaryTable.Clear(); + + char16_t c; + uint32_t nRead; + bool done = false; + do{ // read each line of text into the string array. + if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) break; + while(!done && ((c == '\n') || (c == '\r'))){ + if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) done = true; + } + if (!done){ + nsAutoString word; + while((c != '\n') && (c != '\r') && !done){ + word.Append(c); + if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) done = true; + } + mDictionaryTable.PutEntry(word.get()); + } + } while(!done); +} + +void mozPersonalDictionary::WaitForSave() +{ + // If no save is pending, we return straight away. + if (!mSavePending) { + return; + } + + // If a save is pending, we try to lock the same monitor that the thread uses + // that does the save. This way the main thread will be suspended until the + // monitor becomes available. + mozilla::MonitorAutoLock mon(mMonitorSave); + + // The monitor has become available. This can have two reasons: + // 1: The thread that does the save has finished. + // 2: The thread that does the save hasn't even started. + // In this case we need to wait. + if (mSavePending) { + mon.Wait(); + } +} + +NS_IMETHODIMP mozPersonalDictionary::Save() +{ + nsCOMPtr theFile; + nsresult res; + + WaitForSave(); + + mSavePending = true; + + //FIXME Deinst -- get dictionary name from prefs; + res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile)); + if(NS_FAILED(res)) return res; + if(!theFile)return NS_ERROR_FAILURE; + res = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME)); + if(NS_FAILED(res)) return res; + + nsCOMPtr target = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &res); + if (NS_WARN_IF(NS_FAILED(res))) { + return res; + } + + nsTArray array; + nsString* elems = array.AppendElements(mDictionaryTable.Count()); + for (auto iter = mDictionaryTable.Iter(); !iter.Done(); iter.Next()) { + elems->Assign(iter.Get()->GetKey()); + elems++; + } + + nsCOMPtr runnable = + new mozPersonalDictionarySave(this, theFile, mozilla::Move(array)); + res = target->Dispatch(runnable, NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(res))) { + return res; + } + return res; +} + +NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords) +{ + NS_ENSURE_ARG_POINTER(aWords); + *aWords = nullptr; + + WaitForLoad(); + + nsTArray *array = new nsTArray(); + nsString* elems = array->AppendElements(mDictionaryTable.Count()); + for (auto iter = mDictionaryTable.Iter(); !iter.Done(); iter.Next()) { + elems->Assign(iter.Get()->GetKey()); + elems++; + } + + array->Sort(); + + return NS_NewAdoptingStringEnumerator(aWords, array); +} + +NS_IMETHODIMP mozPersonalDictionary::Check(const char16_t *aWord, const char16_t *aLanguage, bool *aResult) +{ + NS_ENSURE_ARG_POINTER(aWord); + NS_ENSURE_ARG_POINTER(aResult); + + WaitForLoad(); + + *aResult = (mDictionaryTable.GetEntry(aWord) || mIgnoreTable.GetEntry(aWord)); + return NS_OK; +} + +NS_IMETHODIMP mozPersonalDictionary::AddWord(const char16_t *aWord, const char16_t *aLang) +{ + nsresult res; + WaitForLoad(); + + mDictionaryTable.PutEntry(aWord); + res = Save(); + return res; +} + +NS_IMETHODIMP mozPersonalDictionary::RemoveWord(const char16_t *aWord, const char16_t *aLang) +{ + nsresult res; + WaitForLoad(); + + mDictionaryTable.RemoveEntry(aWord); + res = Save(); + return res; +} + +NS_IMETHODIMP mozPersonalDictionary::IgnoreWord(const char16_t *aWord) +{ + // avoid adding duplicate words to the ignore list + if (aWord && !mIgnoreTable.GetEntry(aWord)) + mIgnoreTable.PutEntry(aWord); + return NS_OK; +} + +NS_IMETHODIMP mozPersonalDictionary::EndSession() +{ + WaitForLoad(); + + WaitForSave(); + mIgnoreTable.Clear(); + return NS_OK; +} + +NS_IMETHODIMP mozPersonalDictionary::AddCorrection(const char16_t *word, const char16_t *correction, const char16_t *lang) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP mozPersonalDictionary::RemoveCorrection(const char16_t *word, const char16_t *correction, const char16_t *lang) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP mozPersonalDictionary::GetCorrection(const char16_t *word, char16_t ***words, uint32_t *count) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP mozPersonalDictionary::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) +{ + if (!nsCRT::strcmp(aTopic, "profile-do-change")) { + // The observer is registered in Init() which calls Load and in turn + // LoadInternal(); i.e. Observe() can't be called before Load(). + WaitForLoad(); + mIsLoaded = false; + Load(); // load automatically clears out the existing dictionary table + } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) { + WaitForSave(); + } + + return NS_OK; +} diff --git a/extensions/spellcheck/src/mozPersonalDictionary.h b/extensions/spellcheck/src/mozPersonalDictionary.h new file mode 100644 index 000000000..1a9f082d0 --- /dev/null +++ b/extensions/spellcheck/src/mozPersonalDictionary.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozPersonalDictionary_h__ +#define mozPersonalDictionary_h__ + +#include "nsCOMPtr.h" +#include "nsString.h" +#include "mozIPersonalDictionary.h" +#include "nsIUnicodeEncoder.h" +#include "nsIObserver.h" +#include "nsWeakReference.h" +#include "nsTHashtable.h" +#include "nsCRT.h" +#include "nsCycleCollectionParticipant.h" +#include "nsHashKeys.h" +#include + +#define MOZ_PERSONALDICTIONARY_CONTRACTID "@mozilla.org/spellchecker/personaldictionary;1" +#define MOZ_PERSONALDICTIONARY_CID \ +{ /* 7EF52EAF-B7E1-462B-87E2-5D1DBACA9048 */ \ +0X7EF52EAF, 0XB7E1, 0X462B, \ + { 0X87, 0XE2, 0X5D, 0X1D, 0XBA, 0XCA, 0X90, 0X48 } } + +class mozPersonalDictionaryLoader; +class mozPersonalDictionarySave; + +class mozPersonalDictionary final : public mozIPersonalDictionary, + public nsIObserver, + public nsSupportsWeakReference +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_MOZIPERSONALDICTIONARY + NS_DECL_NSIOBSERVER + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozPersonalDictionary, mozIPersonalDictionary) + + mozPersonalDictionary(); + + nsresult Init(); + +protected: + virtual ~mozPersonalDictionary(); + + /* true if the dictionary has been loaded from disk */ + bool mIsLoaded; + + /* true if a dictionary save is pending */ + bool mSavePending; + + nsCOMPtr mFile; + mozilla::Monitor mMonitor; + mozilla::Monitor mMonitorSave; + nsTHashtable mDictionaryTable; + nsTHashtable mIgnoreTable; + + /*Encoder to use to compare with spellchecker word */ + nsCOMPtr mEncoder; + +private: + /* wait for the asynchronous load of the dictionary to be completed */ + void WaitForLoad(); + + /* enter the monitor before starting a synchronous load off the main-thread */ + void SyncLoad(); + + /* launch an asynchrounous load of the dictionary from the main-thread + * after successfully initializing mFile with the path of the dictionary */ + nsresult LoadInternal(); + + /* perform a synchronous load of the dictionary from disk */ + void SyncLoadInternal(); + + /* wait for the asynchronous save of the dictionary to be completed */ + void WaitForSave(); + + friend class mozPersonalDictionaryLoader; + friend class mozPersonalDictionarySave; +}; + +#endif diff --git a/extensions/spellcheck/src/mozSpellChecker.cpp b/extensions/spellcheck/src/mozSpellChecker.cpp new file mode 100644 index 000000000..771006be3 --- /dev/null +++ b/extensions/spellcheck/src/mozSpellChecker.cpp @@ -0,0 +1,565 @@ +/* vim: set ts=2 sts=2 sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "mozSpellChecker.h" +#include "nsIServiceManager.h" +#include "mozISpellI18NManager.h" +#include "nsIStringEnumerator.h" +#include "nsICategoryManager.h" +#include "nsISupportsPrimitives.h" +#include "nsISimpleEnumerator.h" +#include "mozilla/PRemoteSpellcheckEngineChild.h" +#include "mozilla/dom/ContentChild.h" +#include "nsXULAppAPI.h" + +using mozilla::dom::ContentChild; +using mozilla::PRemoteSpellcheckEngineChild; +using mozilla::RemoteSpellcheckEngineChild; + +#define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1" + +NS_IMPL_CYCLE_COLLECTING_ADDREF(mozSpellChecker) +NS_IMPL_CYCLE_COLLECTING_RELEASE(mozSpellChecker) + +NS_INTERFACE_MAP_BEGIN(mozSpellChecker) + NS_INTERFACE_MAP_ENTRY(nsISpellChecker) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpellChecker) + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozSpellChecker) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION(mozSpellChecker, + mTsDoc, + mPersonalDictionary) + +mozSpellChecker::mozSpellChecker() + : mEngine(nullptr) +{ +} + +mozSpellChecker::~mozSpellChecker() +{ + if (mPersonalDictionary) { + // mPersonalDictionary->Save(); + mPersonalDictionary->EndSession(); + } + mSpellCheckingEngine = nullptr; + mPersonalDictionary = nullptr; + + if (mEngine) { + MOZ_ASSERT(XRE_IsContentProcess()); + mEngine->Send__delete__(mEngine); + MOZ_ASSERT(!mEngine); + } +} + +nsresult +mozSpellChecker::Init() +{ + mSpellCheckingEngine = nullptr; + if (XRE_IsContentProcess()) { + mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton(); + MOZ_ASSERT(contentChild); + mEngine = new RemoteSpellcheckEngineChild(this); + contentChild->SendPRemoteSpellcheckEngineConstructor(mEngine); + } else { + mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1"); + } + + return NS_OK; +} + +NS_IMETHODIMP +mozSpellChecker::SetDocument(nsITextServicesDocument *aDoc, bool aFromStartofDoc) +{ + mTsDoc = aDoc; + mFromStart = aFromStartofDoc; + return NS_OK; +} + + +NS_IMETHODIMP +mozSpellChecker::NextMisspelledWord(nsAString &aWord, nsTArray *aSuggestions) +{ + if(!aSuggestions||!mConverter) + return NS_ERROR_NULL_POINTER; + + int32_t selOffset; + int32_t begin,end; + nsresult result; + result = SetupDoc(&selOffset); + bool isMisspelled,done; + if (NS_FAILED(result)) + return result; + + while( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done ) + { + nsString str; + result = mTsDoc->GetCurrentTextBlock(&str); + + if (NS_FAILED(result)) + return result; + do{ + result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end); + if(NS_SUCCEEDED(result)&&(begin != -1)){ + const nsAString &currWord = Substring(str, begin, end - begin); + result = CheckWord(currWord, &isMisspelled, aSuggestions); + if(isMisspelled){ + aWord = currWord; + mTsDoc->SetSelection(begin, end-begin); + // After ScrollSelectionIntoView(), the pending notifications might + // be flushed and PresShell/PresContext/Frames may be dead. + // See bug 418470. + mTsDoc->ScrollSelectionIntoView(); + return NS_OK; + } + } + selOffset = end; + }while(end != -1); + mTsDoc->NextBlock(); + selOffset=0; + } + return NS_OK; +} + +NS_IMETHODIMP +mozSpellChecker::CheckWord(const nsAString &aWord, bool *aIsMisspelled, nsTArray *aSuggestions) +{ + nsresult result; + bool correct; + + if (XRE_IsContentProcess()) { + nsString wordwrapped = nsString(aWord); + bool rv; + if (aSuggestions) { + rv = mEngine->SendCheckAndSuggest(wordwrapped, aIsMisspelled, aSuggestions); + } else { + rv = mEngine->SendCheck(wordwrapped, aIsMisspelled); + } + return rv ? NS_OK : NS_ERROR_NOT_AVAILABLE; + } + + if(!mSpellCheckingEngine) { + return NS_ERROR_NULL_POINTER; + } + *aIsMisspelled = false; + result = mSpellCheckingEngine->Check(PromiseFlatString(aWord).get(), &correct); + NS_ENSURE_SUCCESS(result, result); + if(!correct){ + if(aSuggestions){ + uint32_t count,i; + char16_t **words; + + result = mSpellCheckingEngine->Suggest(PromiseFlatString(aWord).get(), &words, &count); + NS_ENSURE_SUCCESS(result, result); + nsString* suggestions = aSuggestions->AppendElements(count); + for(i=0;iFirstBlock(); + currOffset=0; + currentBlock = 0; + while( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done ) + { + result = mTsDoc->GetCurrentTextBlock(&str); + do{ + result = mConverter->FindNextWord(str.get(),str.Length(),currOffset,&begin,&end); + if(NS_SUCCEEDED(result)&&(begin != -1)){ + if (aOldWord.Equals(Substring(str, begin, end-begin))) { + // if we are before the current selection point but in the same block + // move the selection point forwards + if((currentBlock == startBlock)&&(begin < selOffset)){ + selOffset += + int32_t(aNewWord.Length()) - int32_t(aOldWord.Length()); + if(selOffset < begin) selOffset=begin; + } + mTsDoc->SetSelection(begin, end-begin); + mTsDoc->InsertText(&newWord); + mTsDoc->GetCurrentTextBlock(&str); + end += (aNewWord.Length() - aOldWord.Length()); // recursion was cute in GEB, not here. + } + } + currOffset = end; + }while(currOffset != -1); + mTsDoc->NextBlock(); + currentBlock++; + currOffset=0; + } + + // We are done replacing. Put the selection point back where we found it (or equivalent); + result = mTsDoc->FirstBlock(); + currentBlock = 0; + while(( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done ) &&(currentBlock < startBlock)){ + mTsDoc->NextBlock(); + } + +//After we have moved to the block where the first occurrence of replace was done, put the +//selection to the next word following it. In case there is no word following it i.e if it happens +//to be the last word in that block, then move to the next block and put the selection to the +//first word in that block, otherwise when the Setupdoc() is called, it queries the LastSelectedBlock() +//and the selection offset of the last occurrence of the replaced word is taken instead of the first +//occurrence and things get messed up as reported in the bug 244969 + + if( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done ){ + nsString str; + result = mTsDoc->GetCurrentTextBlock(&str); + result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end); + if(end == -1) + { + mTsDoc->NextBlock(); + selOffset=0; + result = mTsDoc->GetCurrentTextBlock(&str); + result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end); + mTsDoc->SetSelection(begin, 0); + } + else + mTsDoc->SetSelection(begin, 0); + } + } + else{ + mTsDoc->InsertText(&newWord); + } + return NS_OK; +} + +NS_IMETHODIMP +mozSpellChecker::IgnoreAll(const nsAString &aWord) +{ + if(mPersonalDictionary){ + mPersonalDictionary->IgnoreWord(PromiseFlatString(aWord).get()); + } + return NS_OK; +} + +NS_IMETHODIMP +mozSpellChecker::AddWordToPersonalDictionary(const nsAString &aWord) +{ + nsresult res; + char16_t empty=0; + if (!mPersonalDictionary) + return NS_ERROR_NULL_POINTER; + res = mPersonalDictionary->AddWord(PromiseFlatString(aWord).get(),&empty); + return res; +} + +NS_IMETHODIMP +mozSpellChecker::RemoveWordFromPersonalDictionary(const nsAString &aWord) +{ + nsresult res; + char16_t empty=0; + if (!mPersonalDictionary) + return NS_ERROR_NULL_POINTER; + res = mPersonalDictionary->RemoveWord(PromiseFlatString(aWord).get(),&empty); + return res; +} + +NS_IMETHODIMP +mozSpellChecker::GetPersonalDictionary(nsTArray *aWordList) +{ + if(!aWordList || !mPersonalDictionary) + return NS_ERROR_NULL_POINTER; + + nsCOMPtr words; + mPersonalDictionary->GetWordList(getter_AddRefs(words)); + + bool hasMore; + nsAutoString word; + while (NS_SUCCEEDED(words->HasMore(&hasMore)) && hasMore) { + words->GetNext(word); + aWordList->AppendElement(word); + } + return NS_OK; +} + +NS_IMETHODIMP +mozSpellChecker::GetDictionaryList(nsTArray *aDictionaryList) +{ + if (XRE_IsContentProcess()) { + ContentChild *child = ContentChild::GetSingleton(); + child->GetAvailableDictionaries(*aDictionaryList); + return NS_OK; + } + + nsresult rv; + + // For catching duplicates + nsTHashtable dictionaries; + + nsCOMArray spellCheckingEngines; + rv = GetEngineList(&spellCheckingEngines); + NS_ENSURE_SUCCESS(rv, rv); + + for (int32_t i = 0; i < spellCheckingEngines.Count(); i++) { + nsCOMPtr engine = spellCheckingEngines[i]; + + uint32_t count = 0; + char16_t **words = nullptr; + engine->GetDictionaryList(&words, &count); + for (uint32_t k = 0; k < count; k++) { + nsAutoString dictName; + + dictName.Assign(words[k]); + + // Skip duplicate dictionaries. Only take the first one + // for each name. + if (dictionaries.Contains(dictName)) + continue; + + dictionaries.PutEntry(dictName); + + if (!aDictionaryList->AppendElement(dictName)) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words); + return NS_ERROR_OUT_OF_MEMORY; + } + } + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words); + } + + return NS_OK; +} + +NS_IMETHODIMP +mozSpellChecker::GetCurrentDictionary(nsAString &aDictionary) +{ + if (XRE_IsContentProcess()) { + aDictionary = mCurrentDictionary; + return NS_OK; + } + + if (!mSpellCheckingEngine) { + aDictionary.Truncate(); + return NS_OK; + } + + nsXPIDLString dictname; + mSpellCheckingEngine->GetDictionary(getter_Copies(dictname)); + aDictionary = dictname; + return NS_OK; +} + +NS_IMETHODIMP +mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary) +{ + if (XRE_IsContentProcess()) { + nsString wrappedDict = nsString(aDictionary); + bool isSuccess; + mEngine->SendSetDictionary(wrappedDict, &isSuccess); + if (!isSuccess) { + mCurrentDictionary.Truncate(); + return NS_ERROR_NOT_AVAILABLE; + } + + mCurrentDictionary = wrappedDict; + return NS_OK; + } + + // Calls to mozISpellCheckingEngine::SetDictionary might destroy us + RefPtr kungFuDeathGrip = this; + + mSpellCheckingEngine = nullptr; + + if (aDictionary.IsEmpty()) { + return NS_OK; + } + + nsresult rv; + nsCOMArray spellCheckingEngines; + rv = GetEngineList(&spellCheckingEngines); + NS_ENSURE_SUCCESS(rv, rv); + + for (int32_t i = 0; i < spellCheckingEngines.Count(); i++) { + // We must set mSpellCheckingEngine before we call SetDictionary, since + // SetDictionary calls back to this spell checker to check if the + // dictionary was set + mSpellCheckingEngine = spellCheckingEngines[i]; + + rv = mSpellCheckingEngine->SetDictionary(PromiseFlatString(aDictionary).get()); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr personalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1"); + mSpellCheckingEngine->SetPersonalDictionary(personalDictionary.get()); + + nsXPIDLString language; + nsCOMPtr serv(do_GetService("@mozilla.org/spellchecker/i18nmanager;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + return serv->GetUtil(language.get(),getter_AddRefs(mConverter)); + } + } + + mSpellCheckingEngine = nullptr; + + // We could not find any engine with the requested dictionary + return NS_ERROR_NOT_AVAILABLE; +} + +nsresult +mozSpellChecker::SetupDoc(int32_t *outBlockOffset) +{ + nsresult rv; + + nsITextServicesDocument::TSDBlockSelectionStatus blockStatus; + int32_t selOffset; + int32_t selLength; + *outBlockOffset = 0; + + if (!mFromStart) + { + rv = mTsDoc->LastSelectedBlock(&blockStatus, &selOffset, &selLength); + if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound)) + { + switch (blockStatus) + { + case nsITextServicesDocument::eBlockOutside: // No TB in S, but found one before/after S. + case nsITextServicesDocument::eBlockPartial: // S begins or ends in TB but extends outside of TB. + // the TS doc points to the block we want. + *outBlockOffset = selOffset + selLength; + break; + + case nsITextServicesDocument::eBlockInside: // S extends beyond the start and end of TB. + // we want the block after this one. + rv = mTsDoc->NextBlock(); + *outBlockOffset = 0; + break; + + case nsITextServicesDocument::eBlockContains: // TB contains entire S. + *outBlockOffset = selOffset + selLength; + break; + + case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S). + default: + NS_NOTREACHED("Shouldn't ever get this status"); + } + } + else //failed to get last sel block. Just start at beginning + { + rv = mTsDoc->FirstBlock(); + *outBlockOffset = 0; + } + + } + else // we want the first block + { + rv = mTsDoc->FirstBlock(); + mFromStart = false; + } + return rv; +} + + +// utility method to discover which block we're in. The TSDoc interface doesn't give +// us this, because it can't assume a read-only document. +// shamelessly stolen from nsTextServicesDocument +nsresult +mozSpellChecker::GetCurrentBlockIndex(nsITextServicesDocument *aDoc, int32_t *outBlockIndex) +{ + int32_t blockIndex = 0; + bool isDone = false; + nsresult result = NS_OK; + + do + { + aDoc->PrevBlock(); + + result = aDoc->IsDone(&isDone); + + if (!isDone) + blockIndex ++; + + } while (NS_SUCCEEDED(result) && !isDone); + + *outBlockIndex = blockIndex; + + return result; +} + +nsresult +mozSpellChecker::GetEngineList(nsCOMArray* aSpellCheckingEngines) +{ + MOZ_ASSERT(!XRE_IsContentProcess()); + + nsresult rv; + bool hasMoreEngines; + + nsCOMPtr catMgr = do_GetService(NS_CATEGORYMANAGER_CONTRACTID); + if (!catMgr) + return NS_ERROR_NULL_POINTER; + + nsCOMPtr catEntries; + + // Get contract IDs of registrated external spell-check engines and + // append one of HunSpell at the end. + rv = catMgr->EnumerateCategory("spell-check-engine", getter_AddRefs(catEntries)); + if (NS_FAILED(rv)) + return rv; + + while (catEntries->HasMoreElements(&hasMoreEngines), hasMoreEngines){ + nsCOMPtr elem; + rv = catEntries->GetNext(getter_AddRefs(elem)); + + nsCOMPtr entry = do_QueryInterface(elem, &rv); + if (NS_FAILED(rv)) + return rv; + + nsCString contractId; + rv = entry->GetData(contractId); + if (NS_FAILED(rv)) + return rv; + + // Try to load spellchecker engine. Ignore errors silently + // except for the last one (HunSpell). + nsCOMPtr engine = + do_GetService(contractId.get(), &rv); + if (NS_SUCCEEDED(rv)) { + aSpellCheckingEngines->AppendObject(engine); + } + } + + // Try to load HunSpell spellchecker engine. + nsCOMPtr engine = + do_GetService(DEFAULT_SPELL_CHECKER, &rv); + if (NS_FAILED(rv)) { + // Fail if not succeeded to load HunSpell. Ignore errors + // for external spellcheck engines. + return rv; + } + aSpellCheckingEngines->AppendObject(engine); + + return NS_OK; +} diff --git a/extensions/spellcheck/src/mozSpellChecker.h b/extensions/spellcheck/src/mozSpellChecker.h new file mode 100644 index 000000000..883dee38d --- /dev/null +++ b/extensions/spellcheck/src/mozSpellChecker.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozSpellChecker_h__ +#define mozSpellChecker_h__ + +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsISpellChecker.h" +#include "nsString.h" +#include "nsITextServicesDocument.h" +#include "mozIPersonalDictionary.h" +#include "mozISpellCheckingEngine.h" +#include "nsClassHashtable.h" +#include "nsTArray.h" +#include "mozISpellI18NUtil.h" +#include "nsCycleCollectionParticipant.h" +#include "RemoteSpellCheckEngineChild.h" + +namespace mozilla { +class PRemoteSpellcheckEngineChild; +class RemoteSpellcheckEngineChild; +} // namespace mozilla + +class mozSpellChecker : public nsISpellChecker +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(mozSpellChecker) + + mozSpellChecker(); + + nsresult Init(); + + // nsISpellChecker + NS_IMETHOD SetDocument(nsITextServicesDocument *aDoc, bool aFromStartofDoc) override; + NS_IMETHOD NextMisspelledWord(nsAString &aWord, nsTArray *aSuggestions) override; + NS_IMETHOD CheckWord(const nsAString &aWord, bool *aIsMisspelled, nsTArray *aSuggestions) override; + NS_IMETHOD Replace(const nsAString &aOldWord, const nsAString &aNewWord, bool aAllOccurrences) override; + NS_IMETHOD IgnoreAll(const nsAString &aWord) override; + + NS_IMETHOD AddWordToPersonalDictionary(const nsAString &aWord) override; + NS_IMETHOD RemoveWordFromPersonalDictionary(const nsAString &aWord) override; + NS_IMETHOD GetPersonalDictionary(nsTArray *aWordList) override; + + NS_IMETHOD GetDictionaryList(nsTArray *aDictionaryList) override; + NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary) override; + NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) override; + + void DeleteRemoteEngine() { + mEngine = nullptr; + } + +protected: + virtual ~mozSpellChecker(); + + nsCOMPtr mConverter; + nsCOMPtr mTsDoc; + nsCOMPtr mPersonalDictionary; + + nsCOMPtr mSpellCheckingEngine; + bool mFromStart; + + nsString mCurrentDictionary; + + nsresult SetupDoc(int32_t *outBlockOffset); + + nsresult GetCurrentBlockIndex(nsITextServicesDocument *aDoc, int32_t *outBlockIndex); + + nsresult GetEngineList(nsCOMArray *aDictionaryList); + + mozilla::PRemoteSpellcheckEngineChild *mEngine; +}; +#endif // mozSpellChecker_h__ diff --git a/extensions/spellcheck/src/mozSpellCheckerFactory.cpp b/extensions/spellcheck/src/mozSpellCheckerFactory.cpp new file mode 100644 index 000000000..301f5d284 --- /dev/null +++ b/extensions/spellcheck/src/mozSpellCheckerFactory.cpp @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "mozilla/ModuleUtils.h" +#include "mozHunspell.h" +#include "mozHunspellDirProvider.h" +#include "mozSpellChecker.h" +#include "mozInlineSpellChecker.h" +#include "nsTextServicesCID.h" +#include "mozPersonalDictionary.h" +#include "mozSpellI18NManager.h" +#include "nsIFile.h" + +#define NS_SPELLCHECKER_CID \ +{ /* 8227f019-afc7-461e-b030-9f185d7a0e29 */ \ +0x8227F019, 0xAFC7, 0x461e, \ +{ 0xB0, 0x30, 0x9F, 0x18, 0x5D, 0x7A, 0x0E, 0x29} } + +#define MOZ_INLINESPELLCHECKER_CID \ +{ /* 9FE5D975-09BD-44aa-A01A-66402EA28657 */ \ +0x9fe5d975, 0x9bd, 0x44aa, \ +{ 0xa0, 0x1a, 0x66, 0x40, 0x2e, 0xa2, 0x86, 0x57} } + +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozHunspell, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(mozHunspellDirProvider) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozSpellChecker, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozPersonalDictionary, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(mozSpellI18NManager) +NS_GENERIC_FACTORY_CONSTRUCTOR(mozInlineSpellChecker) + +NS_DEFINE_NAMED_CID(MOZ_HUNSPELL_CID); +NS_DEFINE_NAMED_CID(HUNSPELLDIRPROVIDER_CID); +NS_DEFINE_NAMED_CID(NS_SPELLCHECKER_CID); +NS_DEFINE_NAMED_CID(MOZ_PERSONALDICTIONARY_CID); +NS_DEFINE_NAMED_CID(MOZ_SPELLI18NMANAGER_CID); +NS_DEFINE_NAMED_CID(MOZ_INLINESPELLCHECKER_CID); + +static const mozilla::Module::CIDEntry kSpellcheckCIDs[] = { + { &kMOZ_HUNSPELL_CID, false, nullptr, mozHunspellConstructor }, + { &kHUNSPELLDIRPROVIDER_CID, false, nullptr, mozHunspellDirProviderConstructor }, + { &kNS_SPELLCHECKER_CID, false, nullptr, mozSpellCheckerConstructor }, + { &kMOZ_PERSONALDICTIONARY_CID, false, nullptr, mozPersonalDictionaryConstructor }, + { &kMOZ_SPELLI18NMANAGER_CID, false, nullptr, mozSpellI18NManagerConstructor }, + { &kMOZ_INLINESPELLCHECKER_CID, false, nullptr, mozInlineSpellCheckerConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kSpellcheckContracts[] = { + { MOZ_HUNSPELL_CONTRACTID, &kMOZ_HUNSPELL_CID }, + { mozHunspellDirProvider::kContractID, &kHUNSPELLDIRPROVIDER_CID }, + { NS_SPELLCHECKER_CONTRACTID, &kNS_SPELLCHECKER_CID }, + { MOZ_PERSONALDICTIONARY_CONTRACTID, &kMOZ_PERSONALDICTIONARY_CID }, + { MOZ_SPELLI18NMANAGER_CONTRACTID, &kMOZ_SPELLI18NMANAGER_CID }, + { MOZ_INLINESPELLCHECKER_CONTRACTID, &kMOZ_INLINESPELLCHECKER_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kSpellcheckCategories[] = { + { XPCOM_DIRECTORY_PROVIDER_CATEGORY, "spellcheck-directory-provider", mozHunspellDirProvider::kContractID }, + { nullptr } +}; + +const mozilla::Module kSpellcheckModule = { + mozilla::Module::kVersion, + kSpellcheckCIDs, + kSpellcheckContracts, + kSpellcheckCategories +}; + +NSMODULE_DEFN(mozSpellCheckerModule) = &kSpellcheckModule; diff --git a/extensions/spellcheck/src/mozSpellI18NManager.cpp b/extensions/spellcheck/src/mozSpellI18NManager.cpp new file mode 100644 index 000000000..7b77e707e --- /dev/null +++ b/extensions/spellcheck/src/mozSpellI18NManager.cpp @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozSpellI18NManager.h" +#include "mozEnglishWordUtils.h" +#include "nsString.h" +#include "mozilla/RefPtr.h" + +NS_IMPL_ISUPPORTS(mozSpellI18NManager, mozISpellI18NManager) + +mozSpellI18NManager::mozSpellI18NManager() +{ +} + +mozSpellI18NManager::~mozSpellI18NManager() +{ +} + +NS_IMETHODIMP mozSpellI18NManager::GetUtil(const char16_t *aLanguage, mozISpellI18NUtil **_retval) +{ + if (!_retval) { + return NS_ERROR_NULL_POINTER; + } + + // XXX TODO Actually handle multiple languages. + RefPtr utils = new mozEnglishWordUtils; + utils.forget(_retval); + + return NS_OK; +} diff --git a/extensions/spellcheck/src/mozSpellI18NManager.h b/extensions/spellcheck/src/mozSpellI18NManager.h new file mode 100644 index 000000000..3f075f69c --- /dev/null +++ b/extensions/spellcheck/src/mozSpellI18NManager.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozSpellI18NManager_h__ +#define mozSpellI18NManager_h__ + +#include "nsCOMPtr.h" +#include "mozISpellI18NManager.h" +#include "nsCycleCollectionParticipant.h" + +#define MOZ_SPELLI18NMANAGER_CONTRACTID "@mozilla.org/spellchecker/i18nmanager;1" +#define MOZ_SPELLI18NMANAGER_CID \ +{ /* {AEB8936F-219C-4D3C-8385-D9382DAA551A} */ \ +0xaeb8936f, 0x219c, 0x4d3c, \ + { 0x83, 0x85, 0xd9, 0x38, 0x2d, 0xaa, 0x55, 0x1a } } + +class mozSpellI18NManager : public mozISpellI18NManager +{ +protected: + virtual ~mozSpellI18NManager(); +public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISPELLI18NMANAGER + + mozSpellI18NManager(); +}; +#endif + diff --git a/extensions/spellcheck/tests/chrome/base/base_utf.aff b/extensions/spellcheck/tests/chrome/base/base_utf.aff new file mode 100644 index 000000000..493157b30 --- /dev/null +++ b/extensions/spellcheck/tests/chrome/base/base_utf.aff @@ -0,0 +1,198 @@ +# OpenOffice.org’s en_US.aff file +# with Unicode apostrophe: ’ + +SET UTF-8 +TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' + +MAXNGRAMSUGS 1 +WORDCHARS .'’ + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 88 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion +McDonalds’sá/w +McDonald’sszá/g3) st:McDonald’s po:noun_prs is:TRANS +McDonald’sszal/g4) st:McDonald’s po:noun_prs is:INSTR +McDonald’ssal/w diff --git a/extensions/spellcheck/tests/chrome/base/base_utf.dic b/extensions/spellcheck/tests/chrome/base/base_utf.dic new file mode 100644 index 000000000..b2b536d28 --- /dev/null +++ b/extensions/spellcheck/tests/chrome/base/base_utf.dic @@ -0,0 +1,29 @@ +28 +created/U +create/XKVNGADS +imply/GNSDX +natural/PUY +like/USPBY +convey/BDGS +look/GZRDS +text +hello +said +sawyer +NASA +rotten +day +tomorrow +seven +FAQ/SM +can’t +doesn’t +etc +won’t +lip +text +horrifying +speech +suggest +uncreate/V +Hunspell diff --git a/extensions/spellcheck/tests/chrome/chrome.ini b/extensions/spellcheck/tests/chrome/chrome.ini new file mode 100644 index 000000000..cdd20b9cd --- /dev/null +++ b/extensions/spellcheck/tests/chrome/chrome.ini @@ -0,0 +1,9 @@ +[DEFAULT] +skip-if = os == 'android' + +[test_add_remove_dictionaries.xul] +support-files = + base/base_utf.dic + base/base_utf.aff + map/maputf.dic + map/maputf.aff diff --git a/extensions/spellcheck/tests/chrome/map/maputf.aff b/extensions/spellcheck/tests/chrome/map/maputf.aff new file mode 100644 index 000000000..30edb2a78 --- /dev/null +++ b/extensions/spellcheck/tests/chrome/map/maputf.aff @@ -0,0 +1,11 @@ +# With MAP suggestion, Hunspell can add missing accents to a word. + +SET UTF-8 + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +MAP 3 +MAP uúü +MAP öóo +MAP ß(ss) diff --git a/extensions/spellcheck/tests/chrome/map/maputf.dic b/extensions/spellcheck/tests/chrome/map/maputf.dic new file mode 100644 index 000000000..1c6fa8d05 --- /dev/null +++ b/extensions/spellcheck/tests/chrome/map/maputf.dic @@ -0,0 +1,4 @@ +3 +Frühstück +tükörfúró +groß diff --git a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul new file mode 100644 index 000000000..661eaccff --- /dev/null +++ b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul @@ -0,0 +1,129 @@ + + + + + + + + diff --git a/extensions/spellcheck/tests/mochitest/helper_bug1170484.js b/extensions/spellcheck/tests/mochitest/helper_bug1170484.js new file mode 100644 index 000000000..0a26448ee --- /dev/null +++ b/extensions/spellcheck/tests/mochitest/helper_bug1170484.js @@ -0,0 +1,15 @@ +var Cu = Components.utils; +var Ci = Components.interfaces; + +Cu.import("resource://gre/modules/Services.jsm"); + +// Chrome scripts are run with synchronous messages, so make sure we're completely +// decoupled from the content process before doing this work. +Cu.dispatch(function() { + let chromeWin = Services.ww.activeWindow.QueryInterface(Ci.nsIDOMChromeWindow); + contextMenu = chromeWin.document.getElementById("contentAreaContextMenu"); + var suggestion = contextMenu.querySelector(".spell-suggestion"); + suggestion.doCommand(); + contextMenu.hidePopup(); + sendAsyncMessage("spellingCorrected"); +}); diff --git a/extensions/spellcheck/tests/mochitest/mochitest.ini b/extensions/spellcheck/tests/mochitest/mochitest.ini new file mode 100644 index 000000000..4bf02b253 --- /dev/null +++ b/extensions/spellcheck/tests/mochitest/mochitest.ini @@ -0,0 +1,6 @@ +[DEFAULT] +skip-if = os == 'android' + +[test_bug1170484.html] +support-files = helper_bug1170484.js +skip-if = os == 'linux' #Bug 1202570 diff --git a/extensions/spellcheck/tests/mochitest/test_bug1170484.html b/extensions/spellcheck/tests/mochitest/test_bug1170484.html new file mode 100644 index 000000000..bdfb39f18 --- /dev/null +++ b/extensions/spellcheck/tests/mochitest/test_bug1170484.html @@ -0,0 +1,56 @@ + + + + + + Test for Bug 1170484 + + + + + + +Mozilla Bug 1170484 +

+ +
+  
testing spellechek
+
+ + diff --git a/extensions/universalchardet/moz.build b/extensions/universalchardet/moz.build new file mode 100644 index 000000000..318d6b92d --- /dev/null +++ b/extensions/universalchardet/moz.build @@ -0,0 +1,9 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['src'] +TEST_DIRS += ['tests'] + diff --git a/extensions/universalchardet/src/base/CharDistribution.cpp b/extensions/universalchardet/src/base/CharDistribution.cpp new file mode 100644 index 000000000..7030bd85e --- /dev/null +++ b/extensions/universalchardet/src/base/CharDistribution.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CharDistribution.h" + +#include "JISFreq.tab" +#include "mozilla/ArrayUtils.h" + +#define SURE_YES 0.99f +#define SURE_NO 0.01f + +//return confidence base on received data +float CharDistributionAnalysis::GetConfidence(void) +{ + //if we didn't receive any character in our consideration range, or the + // number of frequent characters is below the minimum threshold, return + // negative answer + if (mTotalChars <= 0 || mFreqChars <= mDataThreshold) + return SURE_NO; + + if (mTotalChars != mFreqChars) { + float r = mFreqChars / ((mTotalChars - mFreqChars) * mTypicalDistributionRatio); + + if (r < SURE_YES) + return r; + } + //normalize confidence, (we don't want to be 100% sure) + return SURE_YES; +} + +SJISDistributionAnalysis::SJISDistributionAnalysis() +{ + mCharToFreqOrder = JISCharToFreqOrder; + mTableSize = mozilla::ArrayLength(JISCharToFreqOrder); + mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO; +} + +EUCJPDistributionAnalysis::EUCJPDistributionAnalysis() +{ + mCharToFreqOrder = JISCharToFreqOrder; + mTableSize = mozilla::ArrayLength(JISCharToFreqOrder); + mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO; +} + diff --git a/extensions/universalchardet/src/base/CharDistribution.h b/extensions/universalchardet/src/base/CharDistribution.h new file mode 100644 index 000000000..bd5143b8e --- /dev/null +++ b/extensions/universalchardet/src/base/CharDistribution.h @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CharDistribution_h__ +#define CharDistribution_h__ + +#include "nscore.h" + +#define ENOUGH_DATA_THRESHOLD 1024 + +class CharDistributionAnalysis +{ +public: + CharDistributionAnalysis() {Reset();} + + //feed a block of data and do distribution analysis + void HandleData(const char* aBuf, uint32_t aLen) {} + + //Feed a character with known length + void HandleOneChar(const char* aStr, uint32_t aCharLen) + { + int32_t order; + + //we only care about 2-bytes character in our distribution analysis + order = (aCharLen == 2) ? GetOrder(aStr) : -1; + + if (order >= 0) + { + mTotalChars++; + //order is valid + if ((uint32_t)order < mTableSize) + { + if (512 > mCharToFreqOrder[order]) + mFreqChars++; + } + } + } + + //return confidence base on existing data + float GetConfidence(void); + + //Reset analyser, clear any state + void Reset() + { + mDone = false; + mTotalChars = 0; + mFreqChars = 0; + mDataThreshold = 0; + } + + //It is not necessary to receive all data to draw conclusion. For charset detection, + // certain amount of data is enough + bool GotEnoughData() {return mTotalChars > ENOUGH_DATA_THRESHOLD;} + +protected: + //we do not handle character base on its original encoding string, but + //convert this encoding string to a number, here called order. + //This allow multiple encoding of a language to share one frequency table + virtual int32_t GetOrder(const char* str) {return -1;} + + //If this flag is set to true, detection is done and conclusion has been made + bool mDone; + + //The number of characters whose frequency order is less than 512 + uint32_t mFreqChars; + + //Total character encounted. + uint32_t mTotalChars; + + //Number of hi-byte characters needed to trigger detection + uint32_t mDataThreshold; + + //Mapping table to get frequency order from char order (get from GetOrder()) + const int16_t *mCharToFreqOrder; + + //Size of above table + uint32_t mTableSize; + + //This is a constant value varies from language to language, it is used in + //calculating confidence. See my paper for further detail. + float mTypicalDistributionRatio; +}; + + +class EUCTWDistributionAnalysis: public CharDistributionAnalysis +{ +public: + EUCTWDistributionAnalysis(); +protected: + + //for euc-TW encoding, we are interested + // first byte range: 0xc4 -- 0xfe + // second byte range: 0xa1 -- 0xfe + //no validation needed here. State machine has done that + int32_t GetOrder(const char* str) + { if ((unsigned char)*str >= (unsigned char)0xc4) + return 94*((unsigned char)str[0]-(unsigned char)0xc4) + (unsigned char)str[1] - (unsigned char)0xa1; + else + return -1; + } +}; + + +class EUCKRDistributionAnalysis : public CharDistributionAnalysis +{ +public: + EUCKRDistributionAnalysis(); +protected: + //for euc-KR encoding, we are interested + // first byte range: 0xb0 -- 0xfe + // second byte range: 0xa1 -- 0xfe + //no validation needed here. State machine has done that + int32_t GetOrder(const char* str) + { if ((unsigned char)*str >= (unsigned char)0xb0) + return 94*((unsigned char)str[0]-(unsigned char)0xb0) + (unsigned char)str[1] - (unsigned char)0xa1; + else + return -1; + } +}; + +class GB2312DistributionAnalysis : public CharDistributionAnalysis +{ +public: + GB2312DistributionAnalysis(); +protected: + //for GB2312 encoding, we are interested + // first byte range: 0xb0 -- 0xfe + // second byte range: 0xa1 -- 0xfe + //no validation needed here. State machine has done that + int32_t GetOrder(const char* str) + { if ((unsigned char)*str >= (unsigned char)0xb0 && (unsigned char)str[1] >= (unsigned char)0xa1) + return 94*((unsigned char)str[0]-(unsigned char)0xb0) + (unsigned char)str[1] - (unsigned char)0xa1; + else + return -1; + } +}; + + +class Big5DistributionAnalysis : public CharDistributionAnalysis +{ +public: + Big5DistributionAnalysis(); +protected: + //for big5 encoding, we are interested + // first byte range: 0xa4 -- 0xfe + // second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe + //no validation needed here. State machine has done that + int32_t GetOrder(const char* str) + { if ((unsigned char)*str >= (unsigned char)0xa4) + if ((unsigned char)str[1] >= (unsigned char)0xa1) + return 157*((unsigned char)str[0]-(unsigned char)0xa4) + (unsigned char)str[1] - (unsigned char)0xa1 +63; + else + return 157*((unsigned char)str[0]-(unsigned char)0xa4) + (unsigned char)str[1] - (unsigned char)0x40; + else + return -1; + } +}; + +class SJISDistributionAnalysis : public CharDistributionAnalysis +{ +public: + SJISDistributionAnalysis(); +protected: + //for sjis encoding, we are interested + // first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe + // second byte range: 0x40 -- 0x7e, 0x81 -- oxfe + //no validation needed here. State machine has done that + int32_t GetOrder(const char* str) + { + int32_t order; + if ((unsigned char)*str >= (unsigned char)0x81 && (unsigned char)*str <= (unsigned char)0x9f) + order = 188 * ((unsigned char)str[0]-(unsigned char)0x81); + else if ((unsigned char)*str >= (unsigned char)0xe0 && (unsigned char)*str <= (unsigned char)0xef) + order = 188 * ((unsigned char)str[0]-(unsigned char)0xe0 + 31); + else + return -1; + order += (unsigned char)*(str+1) - 0x40; + if ((unsigned char)str[1] > (unsigned char)0x7f) + order--; + return order; + } +}; + +class EUCJPDistributionAnalysis : public CharDistributionAnalysis +{ +public: + EUCJPDistributionAnalysis(); +protected: + //for euc-JP encoding, we are interested + // first byte range: 0xa0 -- 0xfe + // second byte range: 0xa1 -- 0xfe + //no validation needed here. State machine has done that + int32_t GetOrder(const char* str) + { if ((unsigned char)*str >= (unsigned char)0xa0) + return 94*((unsigned char)str[0]-(unsigned char)0xa1) + (unsigned char)str[1] - (unsigned char)0xa1; + else + return -1; + } +}; + +#endif //CharDistribution_h__ + diff --git a/extensions/universalchardet/src/base/JISFreq.tab b/extensions/universalchardet/src/base/JISFreq.tab new file mode 100644 index 000000000..d3815caa4 --- /dev/null +++ b/extensions/universalchardet/src/base/JISFreq.tab @@ -0,0 +1,554 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//Sampling from about 20M text materials include literature and computer technology + +// Japanese frequency table, applied to both S-JIS and EUC-JP +//They are sorted in order. + +/****************************************************************************** + * 128 --> 0.77094 + * 256 --> 0.85710 + * 512 --> 0.92635 + * 1024 --> 0.97130 + * 2048 --> 0.99431 + * + * Idea Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 + * Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 + * + * Typical Distribution Ratio, 25% of IDR + *****************************************************************************/ + +#define JIS_TYPICAL_DISTRIBUTION_RATIO (float) 3.0 + +// Char to FreqOrder table +static const int16_t JISCharToFreqOrder[] = +{ + 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, // 16 +3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, // 32 +1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, // 48 +2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, // 64 +2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, // 80 +5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, // 96 +1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, // 112 +5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, // 128 +5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, // 144 +5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, // 160 +5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, // 176 +5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, // 192 +5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, // 208 +1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, // 224 +1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, // 240 +1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, // 256 +2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, // 272 +3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, // 288 +3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, // 304 + 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, // 320 + 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, // 336 +1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, // 352 + 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, // 368 +5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, // 384 + 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, // 400 + 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, // 416 + 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, // 432 + 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, // 448 + 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, // 464 +5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, // 480 +5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, // 496 +5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, // 512 +4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, // 528 +5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, // 544 +5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, // 560 +5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, // 576 +5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, // 592 +5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, // 608 +5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, // 624 +5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, // 640 +5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, // 656 +5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, // 672 +3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, // 688 +5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, // 704 +5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, // 720 +5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, // 736 +5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, // 752 +5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, // 768 +5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, // 784 +5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, // 800 +5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, // 816 +5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, // 832 +5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, // 848 +5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, // 864 +5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, // 880 +5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, // 896 +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, // 912 +5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, // 928 +5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, // 944 +5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, // 960 +5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, // 976 +5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, // 992 +5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, // 1008 +5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, // 1024 +5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, // 1040 +5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, // 1056 +5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, // 1072 +5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, // 1088 +5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, // 1104 +5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, // 1120 +5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, // 1136 +5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, // 1152 +5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, // 1168 +5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, // 1184 +5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, // 1200 +5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, // 1216 +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, // 1232 +5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, // 1248 +5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, // 1264 +5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, // 1280 +5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, // 1296 +6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, // 1312 +6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, // 1328 +6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, // 1344 +6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, // 1360 +6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, // 1376 +6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, // 1392 +6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, // 1408 +6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, // 1424 +4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, // 1440 + 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, // 1456 + 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, // 1472 +1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, // 1488 +1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, // 1504 + 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, // 1520 +3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, // 1536 +3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, // 1552 + 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, // 1568 +3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, // 1584 +3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, // 1600 + 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, // 1616 +2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, // 1632 + 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, // 1648 +3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, // 1664 +1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, // 1680 + 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, // 1696 +1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, // 1712 + 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, // 1728 +2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, // 1744 +2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, // 1760 +2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, // 1776 +2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, // 1792 +1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, // 1808 +1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, // 1824 +1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, // 1840 +1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, // 1856 +2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, // 1872 +1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, // 1888 +2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, // 1904 +1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, // 1920 +1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, // 1936 +1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, // 1952 +1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, // 1968 +1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, // 1984 +1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, // 2000 + 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, // 2016 + 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, // 2032 +1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, // 2048 +2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, // 2064 +2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, // 2080 +2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, // 2096 +3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, // 2112 +3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, // 2128 + 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, // 2144 +3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, // 2160 +1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, // 2176 + 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, // 2192 +2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, // 2208 +1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, // 2224 + 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, // 2240 +3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, // 2256 +4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, // 2272 +2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, // 2288 +1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, // 2304 +2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, // 2320 +1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, // 2336 + 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, // 2352 + 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, // 2368 +1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, // 2384 +2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, // 2400 +2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, // 2416 +2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, // 2432 +3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, // 2448 +1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, // 2464 +2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, // 2480 + 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, // 2496 + 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, // 2512 + 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, // 2528 +1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, // 2544 +2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, // 2560 + 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, // 2576 +1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, // 2592 +1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, // 2608 + 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, // 2624 +1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, // 2640 +1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, // 2656 +1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, // 2672 + 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, // 2688 +2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, // 2704 + 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, // 2720 +2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, // 2736 +3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, // 2752 +2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, // 2768 +1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, // 2784 +6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, // 2800 +1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, // 2816 +2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, // 2832 +1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, // 2848 + 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, // 2864 + 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, // 2880 +3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, // 2896 +3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, // 2912 +1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, // 2928 +1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, // 2944 +1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, // 2960 +1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, // 2976 + 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, // 2992 + 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, // 3008 +2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, // 3024 + 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, // 3040 +3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, // 3056 +2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, // 3072 + 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, // 3088 +1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, // 3104 +2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, // 3120 + 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, // 3136 +1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, // 3152 + 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, // 3168 +4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, // 3184 +2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, // 3200 +1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, // 3216 + 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, // 3232 +1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, // 3248 +2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, // 3264 + 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, // 3280 +6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, // 3296 +1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, // 3312 +1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, // 3328 +2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, // 3344 +3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, // 3360 + 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, // 3376 +3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, // 3392 +1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, // 3408 + 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, // 3424 +1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, // 3440 + 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, // 3456 +3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, // 3472 + 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, // 3488 +2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, // 3504 + 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, // 3520 +4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, // 3536 +2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, // 3552 +1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, // 3568 +1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, // 3584 +1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, // 3600 + 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, // 3616 +1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, // 3632 +3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, // 3648 +1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, // 3664 +3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, // 3680 + 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, // 3696 + 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, // 3712 + 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, // 3728 +2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, // 3744 +1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, // 3760 + 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, // 3776 +1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, // 3792 + 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, // 3808 +1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, // 3824 + 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, // 3840 + 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, // 3856 + 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, // 3872 +1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, // 3888 +1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, // 3904 +2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, // 3920 +4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, // 3936 + 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, // 3952 +1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, // 3968 + 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, // 3984 +1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, // 4000 +3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, // 4016 +1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, // 4032 +2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, // 4048 +2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, // 4064 +1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, // 4080 +1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, // 4096 +2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, // 4112 + 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, // 4128 +2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, // 4144 +1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, // 4160 +1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, // 4176 +1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, // 4192 +1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, // 4208 +3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, // 4224 +2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, // 4240 +2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, // 4256 + 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, // 4272 +3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, // 4288 +3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, // 4304 +1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, // 4320 +2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, // 4336 +1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, // 4352 +2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, // 4368 //last 512 + +/*************************************************************************************** + *Everything below is of no interest for detection purpose * + *************************************************************************************** + +2138,2122,3730,2888,1995,1820,1044,6190,6191,6192,6193,6194,6195,6196,6197,6198, // 4384 +6199,6200,6201,6202,6203,6204,6205,4670,6206,6207,6208,6209,6210,6211,6212,6213, // 4400 +6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229, // 4416 +6230,6231,6232,6233,6234,6235,6236,6237,3187,6238,6239,3969,6240,6241,6242,6243, // 4432 +6244,4671,6245,6246,4672,6247,6248,4133,6249,6250,4364,6251,2923,2556,2613,4673, // 4448 +4365,3970,6252,6253,6254,6255,4674,6256,6257,6258,2768,2353,4366,4675,4676,3188, // 4464 +4367,3463,6259,4134,4677,4678,6260,2267,6261,3842,3332,4368,3543,6262,6263,6264, // 4480 +3013,1954,1928,4135,4679,6265,6266,2478,3091,6267,4680,4369,6268,6269,1699,6270, // 4496 +3544,4136,4681,6271,4137,6272,4370,2804,6273,6274,2593,3971,3972,4682,6275,2236, // 4512 +4683,6276,6277,4684,6278,6279,4138,3973,4685,6280,6281,3258,6282,6283,6284,6285, // 4528 +3974,4686,2841,3975,6286,6287,3545,6288,6289,4139,4687,4140,6290,4141,6291,4142, // 4544 +6292,6293,3333,6294,6295,6296,4371,6297,3399,6298,6299,4372,3976,6300,6301,6302, // 4560 +4373,6303,6304,3843,3731,6305,4688,4374,6306,6307,3259,2294,6308,3732,2530,4143, // 4576 +6309,4689,6310,6311,6312,3048,6313,6314,4690,3733,2237,6315,6316,2282,3334,6317, // 4592 +6318,3844,6319,6320,4691,6321,3400,4692,6322,4693,6323,3049,6324,4375,6325,3977, // 4608 +6326,6327,6328,3546,6329,4694,3335,6330,4695,4696,6331,6332,6333,6334,4376,3978, // 4624 +6335,4697,3979,4144,6336,3980,4698,6337,6338,6339,6340,6341,4699,4700,4701,6342, // 4640 +6343,4702,6344,6345,4703,6346,6347,4704,6348,4705,4706,3135,6349,4707,6350,4708, // 4656 +6351,4377,6352,4709,3734,4145,6353,2506,4710,3189,6354,3050,4711,3981,6355,3547, // 4672 +3014,4146,4378,3735,2651,3845,3260,3136,2224,1986,6356,3401,6357,4712,2594,3627, // 4688 +3137,2573,3736,3982,4713,3628,4714,4715,2682,3629,4716,6358,3630,4379,3631,6359, // 4704 +6360,6361,3983,6362,6363,6364,6365,4147,3846,4717,6366,6367,3737,2842,6368,4718, // 4720 +2628,6369,3261,6370,2386,6371,6372,3738,3984,4719,3464,4720,3402,6373,2924,3336, // 4736 +4148,2866,6374,2805,3262,4380,2704,2069,2531,3138,2806,2984,6375,2769,6376,4721, // 4752 +4722,3403,6377,6378,3548,6379,6380,2705,3092,1979,4149,2629,3337,2889,6381,3338, // 4768 +4150,2557,3339,4381,6382,3190,3263,3739,6383,4151,4723,4152,2558,2574,3404,3191, // 4784 +6384,6385,4153,6386,4724,4382,6387,6388,4383,6389,6390,4154,6391,4725,3985,6392, // 4800 +3847,4155,6393,6394,6395,6396,6397,3465,6398,4384,6399,6400,6401,6402,6403,6404, // 4816 +4156,6405,6406,6407,6408,2123,6409,6410,2326,3192,4726,6411,6412,6413,6414,4385, // 4832 +4157,6415,6416,4158,6417,3093,3848,6418,3986,6419,6420,3849,6421,6422,6423,4159, // 4848 +6424,6425,4160,6426,3740,6427,6428,6429,6430,3987,6431,4727,6432,2238,6433,6434, // 4864 +4386,3988,6435,6436,3632,6437,6438,2843,6439,6440,6441,6442,3633,6443,2958,6444, // 4880 +6445,3466,6446,2364,4387,3850,6447,4388,2959,3340,6448,3851,6449,4728,6450,6451, // 4896 +3264,4729,6452,3193,6453,4389,4390,2706,3341,4730,6454,3139,6455,3194,6456,3051, // 4912 +2124,3852,1602,4391,4161,3853,1158,3854,4162,3989,4392,3990,4731,4732,4393,2040, // 4928 +4163,4394,3265,6457,2807,3467,3855,6458,6459,6460,3991,3468,4733,4734,6461,3140, // 4944 +2960,6462,4735,6463,6464,6465,6466,4736,4737,4738,4739,6467,6468,4164,2403,3856, // 4960 +6469,6470,2770,2844,6471,4740,6472,6473,6474,6475,6476,6477,6478,3195,6479,4741, // 4976 +4395,6480,2867,6481,4742,2808,6482,2493,4165,6483,6484,6485,6486,2295,4743,6487, // 4992 +6488,6489,3634,6490,6491,6492,6493,6494,6495,6496,2985,4744,6497,6498,4745,6499, // 5008 +6500,2925,3141,4166,6501,6502,4746,6503,6504,4747,6505,6506,6507,2890,6508,6509, // 5024 +6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,3469,4167,6520,6521,6522,4748, // 5040 +4396,3741,4397,4749,4398,3342,2125,4750,6523,4751,4752,4753,3052,6524,2961,4168, // 5056 +6525,4754,6526,4755,4399,2926,4169,6527,3857,6528,4400,4170,6529,4171,6530,6531, // 5072 +2595,6532,6533,6534,6535,3635,6536,6537,6538,6539,6540,6541,6542,4756,6543,6544, // 5088 +6545,6546,6547,6548,4401,6549,6550,6551,6552,4402,3405,4757,4403,6553,6554,6555, // 5104 +4172,3742,6556,6557,6558,3992,3636,6559,6560,3053,2726,6561,3549,4173,3054,4404, // 5120 +6562,6563,3993,4405,3266,3550,2809,4406,6564,6565,6566,4758,4759,6567,3743,6568, // 5136 +4760,3744,4761,3470,6569,6570,6571,4407,6572,3745,4174,6573,4175,2810,4176,3196, // 5152 +4762,6574,4177,6575,6576,2494,2891,3551,6577,6578,3471,6579,4408,6580,3015,3197, // 5168 +6581,3343,2532,3994,3858,6582,3094,3406,4409,6583,2892,4178,4763,4410,3016,4411, // 5184 +6584,3995,3142,3017,2683,6585,4179,6586,6587,4764,4412,6588,6589,4413,6590,2986, // 5200 +6591,2962,3552,6592,2963,3472,6593,6594,4180,4765,6595,6596,2225,3267,4414,6597, // 5216 +3407,3637,4766,6598,6599,3198,6600,4415,6601,3859,3199,6602,3473,4767,2811,4416, // 5232 +1856,3268,3200,2575,3996,3997,3201,4417,6603,3095,2927,6604,3143,6605,2268,6606, // 5248 +3998,3860,3096,2771,6607,6608,3638,2495,4768,6609,3861,6610,3269,2745,4769,4181, // 5264 +3553,6611,2845,3270,6612,6613,6614,3862,6615,6616,4770,4771,6617,3474,3999,4418, // 5280 +4419,6618,3639,3344,6619,4772,4182,6620,2126,6621,6622,6623,4420,4773,6624,3018, // 5296 +6625,4774,3554,6626,4183,2025,3746,6627,4184,2707,6628,4421,4422,3097,1775,4185, // 5312 +3555,6629,6630,2868,6631,6632,4423,6633,6634,4424,2414,2533,2928,6635,4186,2387, // 5328 +6636,4775,6637,4187,6638,1891,4425,3202,3203,6639,6640,4776,6641,3345,6642,6643, // 5344 +3640,6644,3475,3346,3641,4000,6645,3144,6646,3098,2812,4188,3642,3204,6647,3863, // 5360 +3476,6648,3864,6649,4426,4001,6650,6651,6652,2576,6653,4189,4777,6654,6655,6656, // 5376 +2846,6657,3477,3205,4002,6658,4003,6659,3347,2252,6660,6661,6662,4778,6663,6664, // 5392 +6665,6666,6667,6668,6669,4779,4780,2048,6670,3478,3099,6671,3556,3747,4004,6672, // 5408 +6673,6674,3145,4005,3748,6675,6676,6677,6678,6679,3408,6680,6681,6682,6683,3206, // 5424 +3207,6684,6685,4781,4427,6686,4782,4783,4784,6687,6688,6689,4190,6690,6691,3479, // 5440 +6692,2746,6693,4428,6694,6695,6696,6697,6698,6699,4785,6700,6701,3208,2727,6702, // 5456 +3146,6703,6704,3409,2196,6705,4429,6706,6707,6708,2534,1996,6709,6710,6711,2747, // 5472 +6712,6713,6714,4786,3643,6715,4430,4431,6716,3557,6717,4432,4433,6718,6719,6720, // 5488 +6721,3749,6722,4006,4787,6723,6724,3644,4788,4434,6725,6726,4789,2772,6727,6728, // 5504 +6729,6730,6731,2708,3865,2813,4435,6732,6733,4790,4791,3480,6734,6735,6736,6737, // 5520 +4436,3348,6738,3410,4007,6739,6740,4008,6741,6742,4792,3411,4191,6743,6744,6745, // 5536 +6746,6747,3866,6748,3750,6749,6750,6751,6752,6753,6754,6755,3867,6756,4009,6757, // 5552 +4793,4794,6758,2814,2987,6759,6760,6761,4437,6762,6763,6764,6765,3645,6766,6767, // 5568 +3481,4192,6768,3751,6769,6770,2174,6771,3868,3752,6772,6773,6774,4193,4795,4438, // 5584 +3558,4796,4439,6775,4797,6776,6777,4798,6778,4799,3559,4800,6779,6780,6781,3482, // 5600 +6782,2893,6783,6784,4194,4801,4010,6785,6786,4440,6787,4011,6788,6789,6790,6791, // 5616 +6792,6793,4802,6794,6795,6796,4012,6797,6798,6799,6800,3349,4803,3483,6801,4804, // 5632 +4195,6802,4013,6803,6804,4196,6805,4014,4015,6806,2847,3271,2848,6807,3484,6808, // 5648 +6809,6810,4441,6811,4442,4197,4443,3272,4805,6812,3412,4016,1579,6813,6814,4017, // 5664 +6815,3869,6816,2964,6817,4806,6818,6819,4018,3646,6820,6821,4807,4019,4020,6822, // 5680 +6823,3560,6824,6825,4021,4444,6826,4198,6827,6828,4445,6829,6830,4199,4808,6831, // 5696 +6832,6833,3870,3019,2458,6834,3753,3413,3350,6835,4809,3871,4810,3561,4446,6836, // 5712 +6837,4447,4811,4812,6838,2459,4448,6839,4449,6840,6841,4022,3872,6842,4813,4814, // 5728 +6843,6844,4815,4200,4201,4202,6845,4023,6846,6847,4450,3562,3873,6848,6849,4816, // 5744 +4817,6850,4451,4818,2139,6851,3563,6852,6853,3351,6854,6855,3352,4024,2709,3414, // 5760 +4203,4452,6856,4204,6857,6858,3874,3875,6859,6860,4819,6861,6862,6863,6864,4453, // 5776 +3647,6865,6866,4820,6867,6868,6869,6870,4454,6871,2869,6872,6873,4821,6874,3754, // 5792 +6875,4822,4205,6876,6877,6878,3648,4206,4455,6879,4823,6880,4824,3876,6881,3055, // 5808 +4207,6882,3415,6883,6884,6885,4208,4209,6886,4210,3353,6887,3354,3564,3209,3485, // 5824 +2652,6888,2728,6889,3210,3755,6890,4025,4456,6891,4825,6892,6893,6894,6895,4211, // 5840 +6896,6897,6898,4826,6899,6900,4212,6901,4827,6902,2773,3565,6903,4828,6904,6905, // 5856 +6906,6907,3649,3650,6908,2849,3566,6909,3567,3100,6910,6911,6912,6913,6914,6915, // 5872 +4026,6916,3355,4829,3056,4457,3756,6917,3651,6918,4213,3652,2870,6919,4458,6920, // 5888 +2438,6921,6922,3757,2774,4830,6923,3356,4831,4832,6924,4833,4459,3653,2507,6925, // 5904 +4834,2535,6926,6927,3273,4027,3147,6928,3568,6929,6930,6931,4460,6932,3877,4461, // 5920 +2729,3654,6933,6934,6935,6936,2175,4835,2630,4214,4028,4462,4836,4215,6937,3148, // 5936 +4216,4463,4837,4838,4217,6938,6939,2850,4839,6940,4464,6941,6942,6943,4840,6944, // 5952 +4218,3274,4465,6945,6946,2710,6947,4841,4466,6948,6949,2894,6950,6951,4842,6952, // 5968 +4219,3057,2871,6953,6954,6955,6956,4467,6957,2711,6958,6959,6960,3275,3101,4843, // 5984 +6961,3357,3569,6962,4844,6963,6964,4468,4845,3570,6965,3102,4846,3758,6966,4847, // 6000 +3878,4848,4849,4029,6967,2929,3879,4850,4851,6968,6969,1733,6970,4220,6971,6972, // 6016 +6973,6974,6975,6976,4852,6977,6978,6979,6980,6981,6982,3759,6983,6984,6985,3486, // 6032 +3487,6986,3488,3416,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,4853, // 6048 +6998,6999,4030,7000,7001,3211,7002,7003,4221,7004,7005,3571,4031,7006,3572,7007, // 6064 +2614,4854,2577,7008,7009,2965,3655,3656,4855,2775,3489,3880,4222,4856,3881,4032, // 6080 +3882,3657,2730,3490,4857,7010,3149,7011,4469,4858,2496,3491,4859,2283,7012,7013, // 6096 +7014,2365,4860,4470,7015,7016,3760,7017,7018,4223,1917,7019,7020,7021,4471,7022, // 6112 +2776,4472,7023,7024,7025,7026,4033,7027,3573,4224,4861,4034,4862,7028,7029,1929, // 6128 +3883,4035,7030,4473,3058,7031,2536,3761,3884,7032,4036,7033,2966,2895,1968,4474, // 6144 +3276,4225,3417,3492,4226,2105,7034,7035,1754,2596,3762,4227,4863,4475,3763,4864, // 6160 +3764,2615,2777,3103,3765,3658,3418,4865,2296,3766,2815,7036,7037,7038,3574,2872, // 6176 +3277,4476,7039,4037,4477,7040,7041,4038,7042,7043,7044,7045,7046,7047,2537,7048, // 6192 +7049,7050,7051,7052,7053,7054,4478,7055,7056,3767,3659,4228,3575,7057,7058,4229, // 6208 +7059,7060,7061,3660,7062,3212,7063,3885,4039,2460,7064,7065,7066,7067,7068,7069, // 6224 +7070,7071,7072,7073,7074,4866,3768,4867,7075,7076,7077,7078,4868,3358,3278,2653, // 6240 +7079,7080,4479,3886,7081,7082,4869,7083,7084,7085,7086,7087,7088,2538,7089,7090, // 6256 +7091,4040,3150,3769,4870,4041,2896,3359,4230,2930,7092,3279,7093,2967,4480,3213, // 6272 +4481,3661,7094,7095,7096,7097,7098,7099,7100,7101,7102,2461,3770,7103,7104,4231, // 6288 +3151,7105,7106,7107,4042,3662,7108,7109,4871,3663,4872,4043,3059,7110,7111,7112, // 6304 +3493,2988,7113,4873,7114,7115,7116,3771,4874,7117,7118,4232,4875,7119,3576,2336, // 6320 +4876,7120,4233,3419,4044,4877,4878,4482,4483,4879,4484,4234,7121,3772,4880,1045, // 6336 +3280,3664,4881,4882,7122,7123,7124,7125,4883,7126,2778,7127,4485,4486,7128,4884, // 6352 +3214,3887,7129,7130,3215,7131,4885,4045,7132,7133,4046,7134,7135,7136,7137,7138, // 6368 +7139,7140,7141,7142,7143,4235,7144,4886,7145,7146,7147,4887,7148,7149,7150,4487, // 6384 +4047,4488,7151,7152,4888,4048,2989,3888,7153,3665,7154,4049,7155,7156,7157,7158, // 6400 +7159,7160,2931,4889,4890,4489,7161,2631,3889,4236,2779,7162,7163,4891,7164,3060, // 6416 +7165,1672,4892,7166,4893,4237,3281,4894,7167,7168,3666,7169,3494,7170,7171,4050, // 6432 +7172,7173,3104,3360,3420,4490,4051,2684,4052,7174,4053,7175,7176,7177,2253,4054, // 6448 +7178,7179,4895,7180,3152,3890,3153,4491,3216,7181,7182,7183,2968,4238,4492,4055, // 6464 +7184,2990,7185,2479,7186,7187,4493,7188,7189,7190,7191,7192,4896,7193,4897,2969, // 6480 +4494,4898,7194,3495,7195,7196,4899,4495,7197,3105,2731,7198,4900,7199,7200,7201, // 6496 +4056,7202,3361,7203,7204,4496,4901,4902,7205,4497,7206,7207,2315,4903,7208,4904, // 6512 +7209,4905,2851,7210,7211,3577,7212,3578,4906,7213,4057,3667,4907,7214,4058,2354, // 6528 +3891,2376,3217,3773,7215,7216,7217,7218,7219,4498,7220,4908,3282,2685,7221,3496, // 6544 +4909,2632,3154,4910,7222,2337,7223,4911,7224,7225,7226,4912,4913,3283,4239,4499, // 6560 +7227,2816,7228,7229,7230,7231,7232,7233,7234,4914,4500,4501,7235,7236,7237,2686, // 6576 +7238,4915,7239,2897,4502,7240,4503,7241,2516,7242,4504,3362,3218,7243,7244,7245, // 6592 +4916,7246,7247,4505,3363,7248,7249,7250,7251,3774,4506,7252,7253,4917,7254,7255, // 6608 +3284,2991,4918,4919,3219,3892,4920,3106,3497,4921,7256,7257,7258,4922,7259,4923, // 6624 +3364,4507,4508,4059,7260,4240,3498,7261,7262,4924,7263,2992,3893,4060,3220,7264, // 6640 +7265,7266,7267,7268,7269,4509,3775,7270,2817,7271,4061,4925,4510,3776,7272,4241, // 6656 +4511,3285,7273,7274,3499,7275,7276,7277,4062,4512,4926,7278,3107,3894,7279,7280, // 6672 +4927,7281,4513,7282,7283,3668,7284,7285,4242,4514,4243,7286,2058,4515,4928,4929, // 6688 +4516,7287,3286,4244,7288,4517,7289,7290,7291,3669,7292,7293,4930,4931,4932,2355, // 6704 +4933,7294,2633,4518,7295,4245,7296,7297,4519,7298,7299,4520,4521,4934,7300,4246, // 6720 +4522,7301,7302,7303,3579,7304,4247,4935,7305,4936,7306,7307,7308,7309,3777,7310, // 6736 +4523,7311,7312,7313,4248,3580,7314,4524,3778,4249,7315,3581,7316,3287,7317,3221, // 6752 +7318,4937,7319,7320,7321,7322,7323,7324,4938,4939,7325,4525,7326,7327,7328,4063, // 6768 +7329,7330,4940,7331,7332,4941,7333,4526,7334,3500,2780,1741,4942,2026,1742,7335, // 6784 +7336,3582,4527,2388,7337,7338,7339,4528,7340,4250,4943,7341,7342,7343,4944,7344, // 6800 +7345,7346,3020,7347,4945,7348,7349,7350,7351,3895,7352,3896,4064,3897,7353,7354, // 6816 +7355,4251,7356,7357,3898,7358,3779,7359,3780,3288,7360,7361,4529,7362,4946,4530, // 6832 +2027,7363,3899,4531,4947,3222,3583,7364,4948,7365,7366,7367,7368,4949,3501,4950, // 6848 +3781,4951,4532,7369,2517,4952,4252,4953,3155,7370,4954,4955,4253,2518,4533,7371, // 6864 +7372,2712,4254,7373,7374,7375,3670,4956,3671,7376,2389,3502,4065,7377,2338,7378, // 6880 +7379,7380,7381,3061,7382,4957,7383,7384,7385,7386,4958,4534,7387,7388,2993,7389, // 6896 +3062,7390,4959,7391,7392,7393,4960,3108,4961,7394,4535,7395,4962,3421,4536,7396, // 6912 +4963,7397,4964,1857,7398,4965,7399,7400,2176,3584,4966,7401,7402,3422,4537,3900, // 6928 +3585,7403,3782,7404,2852,7405,7406,7407,4538,3783,2654,3423,4967,4539,7408,3784, // 6944 +3586,2853,4540,4541,7409,3901,7410,3902,7411,7412,3785,3109,2327,3903,7413,7414, // 6960 +2970,4066,2932,7415,7416,7417,3904,3672,3424,7418,4542,4543,4544,7419,4968,7420, // 6976 +7421,4255,7422,7423,7424,7425,7426,4067,7427,3673,3365,4545,7428,3110,2559,3674, // 6992 +7429,7430,3156,7431,7432,3503,7433,3425,4546,7434,3063,2873,7435,3223,4969,4547, // 7008 +4548,2898,4256,4068,7436,4069,3587,3786,2933,3787,4257,4970,4971,3788,7437,4972, // 7024 +3064,7438,4549,7439,7440,7441,7442,7443,4973,3905,7444,2874,7445,7446,7447,7448, // 7040 +3021,7449,4550,3906,3588,4974,7450,7451,3789,3675,7452,2578,7453,4070,7454,7455, // 7056 +7456,4258,3676,7457,4975,7458,4976,4259,3790,3504,2634,4977,3677,4551,4260,7459, // 7072 +7460,7461,7462,3907,4261,4978,7463,7464,7465,7466,4979,4980,7467,7468,2213,4262, // 7088 +7469,7470,7471,3678,4981,7472,2439,7473,4263,3224,3289,7474,3908,2415,4982,7475, // 7104 +4264,7476,4983,2655,7477,7478,2732,4552,2854,2875,7479,7480,4265,7481,4553,4984, // 7120 +7482,7483,4266,7484,3679,3366,3680,2818,2781,2782,3367,3589,4554,3065,7485,4071, // 7136 +2899,7486,7487,3157,2462,4072,4555,4073,4985,4986,3111,4267,2687,3368,4556,4074, // 7152 +3791,4268,7488,3909,2783,7489,2656,1962,3158,4557,4987,1963,3159,3160,7490,3112, // 7168 +4988,4989,3022,4990,4991,3792,2855,7491,7492,2971,4558,7493,7494,4992,7495,7496, // 7184 +7497,7498,4993,7499,3426,4559,4994,7500,3681,4560,4269,4270,3910,7501,4075,4995, // 7200 +4271,7502,7503,4076,7504,4996,7505,3225,4997,4272,4077,2819,3023,7506,7507,2733, // 7216 +4561,7508,4562,7509,3369,3793,7510,3590,2508,7511,7512,4273,3113,2994,2616,7513, // 7232 +7514,7515,7516,7517,7518,2820,3911,4078,2748,7519,7520,4563,4998,7521,7522,7523, // 7248 +7524,4999,4274,7525,4564,3682,2239,4079,4565,7526,7527,7528,7529,5000,7530,7531, // 7264 +5001,4275,3794,7532,7533,7534,3066,5002,4566,3161,7535,7536,4080,7537,3162,7538, // 7280 +7539,4567,7540,7541,7542,7543,7544,7545,5003,7546,4568,7547,7548,7549,7550,7551, // 7296 +7552,7553,7554,7555,7556,5004,7557,7558,7559,5005,7560,3795,7561,4569,7562,7563, // 7312 +7564,2821,3796,4276,4277,4081,7565,2876,7566,5006,7567,7568,2900,7569,3797,3912, // 7328 +7570,7571,7572,4278,7573,7574,7575,5007,7576,7577,5008,7578,7579,4279,2934,7580, // 7344 +7581,5009,7582,4570,7583,4280,7584,7585,7586,4571,4572,3913,7587,4573,3505,7588, // 7360 +5010,7589,7590,7591,7592,3798,4574,7593,7594,5011,7595,4281,7596,7597,7598,4282, // 7376 +5012,7599,7600,5013,3163,7601,5014,7602,3914,7603,7604,2734,4575,4576,4577,7605, // 7392 +7606,7607,7608,7609,3506,5015,4578,7610,4082,7611,2822,2901,2579,3683,3024,4579, // 7408 +3507,7612,4580,7613,3226,3799,5016,7614,7615,7616,7617,7618,7619,7620,2995,3290, // 7424 +7621,4083,7622,5017,7623,7624,7625,7626,7627,4581,3915,7628,3291,7629,5018,7630, // 7440 +7631,7632,7633,4084,7634,7635,3427,3800,7636,7637,4582,7638,5019,4583,5020,7639, // 7456 +3916,7640,3801,5021,4584,4283,7641,7642,3428,3591,2269,7643,2617,7644,4585,3592, // 7472 +7645,4586,2902,7646,7647,3227,5022,7648,4587,7649,4284,7650,7651,7652,4588,2284, // 7488 +7653,5023,7654,7655,7656,4589,5024,3802,7657,7658,5025,3508,4590,7659,7660,7661, // 7504 +1969,5026,7662,7663,3684,1821,2688,7664,2028,2509,4285,7665,2823,1841,7666,2689, // 7520 +3114,7667,3917,4085,2160,5027,5028,2972,7668,5029,7669,7670,7671,3593,4086,7672, // 7536 +4591,4087,5030,3803,7673,7674,7675,7676,7677,7678,7679,4286,2366,4592,4593,3067, // 7552 +2328,7680,7681,4594,3594,3918,2029,4287,7682,5031,3919,3370,4288,4595,2856,7683, // 7568 +3509,7684,7685,5032,5033,7686,7687,3804,2784,7688,7689,7690,7691,3371,7692,7693, // 7584 +2877,5034,7694,7695,3920,4289,4088,7696,7697,7698,5035,7699,5036,4290,5037,5038, // 7600 +5039,7700,7701,7702,5040,5041,3228,7703,1760,7704,5042,3229,4596,2106,4089,7705, // 7616 +4597,2824,5043,2107,3372,7706,4291,4090,5044,7707,4091,7708,5045,3025,3805,4598, // 7632 +4292,4293,4294,3373,7709,4599,7710,5046,7711,7712,5047,5048,3806,7713,7714,7715, // 7648 +5049,7716,7717,7718,7719,4600,5050,7720,7721,7722,5051,7723,4295,3429,7724,7725, // 7664 +7726,7727,3921,7728,3292,5052,4092,7729,7730,7731,7732,7733,7734,7735,5053,5054, // 7680 +7736,7737,7738,7739,3922,3685,7740,7741,7742,7743,2635,5055,7744,5056,4601,7745, // 7696 +7746,2560,7747,7748,7749,7750,3923,7751,7752,7753,7754,7755,4296,2903,7756,7757, // 7712 +7758,7759,7760,3924,7761,5057,4297,7762,7763,5058,4298,7764,4093,7765,7766,5059, // 7728 +3925,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,3595,7777,4299,5060,4094, // 7744 +7778,3293,5061,7779,7780,4300,7781,7782,4602,7783,3596,7784,7785,3430,2367,7786, // 7760 +3164,5062,5063,4301,7787,7788,4095,5064,5065,7789,3374,3115,7790,7791,7792,7793, // 7776 +7794,7795,7796,3597,4603,7797,7798,3686,3116,3807,5066,7799,7800,5067,7801,7802, // 7792 +4604,4302,5068,4303,4096,7803,7804,3294,7805,7806,5069,4605,2690,7807,3026,7808, // 7808 +7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824, // 7824 +7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, // 7840 +7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855,7856, // 7856 +7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871,7872, // 7872 +7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888, // 7888 +7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903,7904, // 7904 +7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920, // 7920 +7921,7922,7923,7924,3926,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, // 7936 +7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, // 7952 +7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, // 7968 +7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, // 7984 +7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, // 8000 +8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, // 8016 +8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, // 8032 +8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, // 8048 +8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, // 8064 +8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, // 8080 +8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, // 8096 +8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, // 8112 +8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, // 8128 +8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, // 8144 +8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, // 8160 +8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, // 8176 +8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, // 8192 +8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, // 8208 +8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, // 8224 +8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, // 8240 +8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, // 8256 +8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271, // 8272 +****************************************************************************************/ + +}; + diff --git a/extensions/universalchardet/src/base/JpCntx.cpp b/extensions/universalchardet/src/base/JpCntx.cpp new file mode 100644 index 000000000..28ab64336 --- /dev/null +++ b/extensions/universalchardet/src/base/JpCntx.cpp @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nscore.h" +#include "JpCntx.h" + +//This is hiragana 2-char sequence table, the number in each cell represents its frequency category +const uint8_t jp2CharContext[83][83] = +{ +{ 0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,}, +{ 2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4,}, +{ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,}, +{ 0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4,}, +{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{ 0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4,}, +{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{ 0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3,}, +{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{ 0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4,}, +{ 1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4,}, +{ 0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3,}, +{ 0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3,}, +{ 0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3,}, +{ 0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4,}, +{ 0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3,}, +{ 2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4,}, +{ 0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3,}, +{ 0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5,}, +{ 0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3,}, +{ 2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5,}, +{ 0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4,}, +{ 1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4,}, +{ 0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3,}, +{ 0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3,}, +{ 0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3,}, +{ 0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5,}, +{ 0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4,}, +{ 0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5,}, +{ 0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3,}, +{ 0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4,}, +{ 0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4,}, +{ 0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4,}, +{ 0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1,}, +{ 0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,}, +{ 1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3,}, +{ 0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0,}, +{ 0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3,}, +{ 0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3,}, +{ 0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5,}, +{ 0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4,}, +{ 2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5,}, +{ 0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3,}, +{ 0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3,}, +{ 0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3,}, +{ 0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3,}, +{ 0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4,}, +{ 0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4,}, +{ 0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2,}, +{ 0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3,}, +{ 0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3,}, +{ 0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3,}, +{ 0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3,}, +{ 0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4,}, +{ 0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3,}, +{ 0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4,}, +{ 0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3,}, +{ 0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3,}, +{ 0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4,}, +{ 0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4,}, +{ 0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3,}, +{ 2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4,}, +{ 0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4,}, +{ 0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3,}, +{ 0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4,}, +{ 0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4,}, +{ 1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4,}, +{ 0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3,}, +{ 0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2,}, +{ 0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2,}, +{ 0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3,}, +{ 0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3,}, +{ 0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5,}, +{ 0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3,}, +{ 0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4,}, +{ 1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4,}, +{ 0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4,}, +{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{ 0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3,}, +{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1,}, +{ 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2,}, +{ 0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3,}, +{ 0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1,}, +}; + +#define MINIMUM_DATA_THRESHOLD 4 + +void JapaneseContextAnalysis::HandleData(const char* aBuf, uint32_t aLen) +{ + uint32_t charLen; + int32_t order; + uint32_t i; + + if (mDone) + return; + + //The buffer we got is byte oriented, and a character may span in more than one + //buffers. In case the last one or two byte in last buffer is not complete, we + //record how many byte needed to complete that character and skip these bytes here. + //We can choose to record those bytes as well and analyse the character once it + //is complete, but since a character will not make much difference, by simply skipping + //this character will simply our logic and improve performance. + for (i = mNeedToSkipCharNum; i < aLen; ) + { + order = GetOrder(aBuf+i, &charLen); + i+= charLen; + if (i > aLen){ + mNeedToSkipCharNum = i - aLen; + mLastCharOrder = -1; + } + else + { + if (order != -1 && mLastCharOrder != -1) + { + mTotalRel ++; + if (mTotalRel > MAX_REL_THRESHOLD) + { + mDone = true; + break; + } + mRelSample[jp2CharContext[mLastCharOrder][order]]++; + } + mLastCharOrder = order; + } + } + + return; +} + +void JapaneseContextAnalysis::Reset() +{ + mTotalRel = 0; + for (uint32_t i = 0; i < NUM_OF_CATEGORY; i++) + mRelSample[i] = 0; + mNeedToSkipCharNum = 0; + mLastCharOrder = -1; + mDone = false; + mDataThreshold = 0; +} +#define DONT_KNOW (float)-1 + +float JapaneseContextAnalysis::GetConfidence(void) +{ + //This is just one way to calculate confidence. It works well for me. + if (mTotalRel > mDataThreshold) + return ((float)(mTotalRel - mRelSample[0]))/mTotalRel; + else + return (float)DONT_KNOW; +} + + +int32_t SJISContextAnalysis::GetOrder(const char* str, uint32_t *charLen) +{ + //find out current char's byte length + if (((unsigned char)*str >= (unsigned char)0x81 && (unsigned char)*str <= (unsigned char)0x9f) || + ((unsigned char)*str >= (unsigned char)0xe0 && (unsigned char)*str <= (unsigned char)0xfc) ) + *charLen = 2; + else + *charLen = 1; + + //return its order if it is hiragana + if (*str == '\202' && + (unsigned char)*(str+1) >= (unsigned char)0x9f && + (unsigned char)*(str+1) <= (unsigned char)0xf1) + return (unsigned char)*(str+1) - (unsigned char)0x9f; + return -1; +} + +int32_t EUCJPContextAnalysis::GetOrder(const char* str, uint32_t *charLen) +{ + //find out current char's byte length + if ((unsigned char)*str == (unsigned char)0x8e || + ((unsigned char)*str >= (unsigned char)0xa1 && + (unsigned char)*str <= (unsigned char)0xfe)) + *charLen = 2; + else if ((unsigned char)*str == (unsigned char)0x8f) + *charLen = 3; + else + *charLen = 1; + + //return its order if it is hiragana + if ((unsigned char)*str == (unsigned char)0xa4 && + (unsigned char)*(str+1) >= (unsigned char)0xa1 && + (unsigned char)*(str+1) <= (unsigned char)0xf3) + return (unsigned char)*(str+1) - (unsigned char)0xa1; + return -1; +} diff --git a/extensions/universalchardet/src/base/JpCntx.h b/extensions/universalchardet/src/base/JpCntx.h new file mode 100644 index 000000000..88e096432 --- /dev/null +++ b/extensions/universalchardet/src/base/JpCntx.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __JPCNTX_H__ +#define __JPCNTX_H__ + +#define NUM_OF_CATEGORY 6 + +#include "nscore.h" + +#define ENOUGH_REL_THRESHOLD 100 +#define MAX_REL_THRESHOLD 1000 + +//hiragana frequency category table +extern const uint8_t jp2CharContext[83][83]; + +class JapaneseContextAnalysis +{ +public: + JapaneseContextAnalysis() {Reset();} + + void HandleData(const char* aBuf, uint32_t aLen); + + void HandleOneChar(const char* aStr, uint32_t aCharLen) + { + int32_t order; + + //if we received enough data, stop here + if (mTotalRel > MAX_REL_THRESHOLD) mDone = true; + if (mDone) return; + + //Only 2-bytes characters are of our interest + order = (aCharLen == 2) ? GetOrder(aStr) : -1; + if (order != -1 && mLastCharOrder != -1) + { + mTotalRel++; + //count this sequence to its category counter + mRelSample[jp2CharContext[mLastCharOrder][order]]++; + } + mLastCharOrder = order; + } + + float GetConfidence(void); + void Reset(); + bool GotEnoughData() {return mTotalRel > ENOUGH_REL_THRESHOLD;} + +protected: + virtual int32_t GetOrder(const char* str, uint32_t *charLen) = 0; + virtual int32_t GetOrder(const char* str) = 0; + + //category counters, each integer counts sequences in its category + uint32_t mRelSample[NUM_OF_CATEGORY]; + + //total sequence received + uint32_t mTotalRel; + + //Number of sequences needed to trigger detection + uint32_t mDataThreshold; + + //The order of previous char + int32_t mLastCharOrder; + + //if last byte in current buffer is not the last byte of a character, we + //need to know how many byte to skip in next buffer. + uint32_t mNeedToSkipCharNum; + + //If this flag is set to true, detection is done and conclusion has been made + bool mDone; +}; + + +class SJISContextAnalysis : public JapaneseContextAnalysis +{ + //SJISContextAnalysis(){}; +protected: + int32_t GetOrder(const char* str, uint32_t *charLen); + + int32_t GetOrder(const char* str) + { + //We only interested in Hiragana, so first byte is '\202' + if (*str == '\202' && + (unsigned char)*(str+1) >= (unsigned char)0x9f && + (unsigned char)*(str+1) <= (unsigned char)0xf1) + return (unsigned char)*(str+1) - (unsigned char)0x9f; + return -1; + } +}; + +class EUCJPContextAnalysis : public JapaneseContextAnalysis +{ +protected: + int32_t GetOrder(const char* str, uint32_t *charLen); + int32_t GetOrder(const char* str) + //We only interested in Hiragana, so first byte is '\244' + { + if (*str == '\244' && + (unsigned char)*(str+1) >= (unsigned char)0xa1 && + (unsigned char)*(str+1) <= (unsigned char)0xf3) + return (unsigned char)*(str+1) - (unsigned char)0xa1; + return -1; + } +}; + +#endif /* __JPCNTX_H__ */ + diff --git a/extensions/universalchardet/src/base/moz.build b/extensions/universalchardet/src/base/moz.build new file mode 100644 index 000000000..442579d4a --- /dev/null +++ b/extensions/universalchardet/src/base/moz.build @@ -0,0 +1,22 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'CharDistribution.cpp', + 'JpCntx.cpp', + 'nsCharSetProber.cpp', + 'nsEscCharsetProber.cpp', + 'nsEscSM.cpp', + 'nsEUCJPProber.cpp', + 'nsLatin1Prober.cpp', + 'nsMBCSGroupProber.cpp', + 'nsMBCSSM.cpp', + 'nsSJISProber.cpp', + 'nsUniversalDetector.cpp', + 'nsUTF8Prober.cpp', +] + +FINAL_LIBRARY = 'xul' diff --git a/extensions/universalchardet/src/base/nsCharSetProber.cpp b/extensions/universalchardet/src/base/nsCharSetProber.cpp new file mode 100644 index 000000000..cd15a10c3 --- /dev/null +++ b/extensions/universalchardet/src/base/nsCharSetProber.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCharSetProber.h" +#include "prmem.h" + +//This filter applies to all scripts which do not use English characters +bool nsCharSetProber::FilterWithoutEnglishLetters(const char* aBuf, uint32_t aLen, char** newBuf, uint32_t& newLen) +{ + char *newptr; + char *prevPtr, *curPtr; + + bool meetMSB = false; + newptr = *newBuf = (char*)PR_Malloc(aLen); + if (!newptr) + return false; + + for (curPtr = prevPtr = (char*)aBuf; curPtr < aBuf+aLen; curPtr++) + { + if (*curPtr & 0x80) + { + meetMSB = true; + } + else if (*curPtr < 'A' || (*curPtr > 'Z' && *curPtr < 'a') || *curPtr > 'z') + { + //current char is a symbol, most likely a punctuation. we treat it as segment delimiter + if (meetMSB && curPtr > prevPtr) + //this segment contains more than single symbol, and it has upper ASCII, we need to keep it + { + while (prevPtr < curPtr) *newptr++ = *prevPtr++; + prevPtr++; + *newptr++ = ' '; + meetMSB = false; + } + else //ignore current segment. (either because it is just a symbol or just an English word) + prevPtr = curPtr+1; + } + } + if (meetMSB && curPtr > prevPtr) + while (prevPtr < curPtr) *newptr++ = *prevPtr++; + + newLen = newptr - *newBuf; + + return true; +} + +//This filter applies to all scripts which contain both English characters and upper ASCII characters. +bool nsCharSetProber::FilterWithEnglishLetters(const char* aBuf, uint32_t aLen, char** newBuf, uint32_t& newLen) +{ + //do filtering to reduce load to probers + char *newptr; + char *prevPtr, *curPtr; + bool isInTag = false; + + newptr = *newBuf = (char*)PR_Malloc(aLen); + if (!newptr) + return false; + + for (curPtr = prevPtr = (char*)aBuf; curPtr < aBuf+aLen; curPtr++) + { + if (*curPtr == '>') + isInTag = false; + else if (*curPtr == '<') + isInTag = true; + + if (!(*curPtr & 0x80) && + (*curPtr < 'A' || (*curPtr > 'Z' && *curPtr < 'a') || *curPtr > 'z') ) + { + if (curPtr > prevPtr && !isInTag) // Current segment contains more than just a symbol + // and it is not inside a tag, keep it. + { + while (prevPtr < curPtr) *newptr++ = *prevPtr++; + prevPtr++; + *newptr++ = ' '; + } + else + prevPtr = curPtr+1; + } + } + + // If the current segment contains more than just a symbol + // and it is not inside a tag then keep it. + if (!isInTag) + while (prevPtr < curPtr) + *newptr++ = *prevPtr++; + + newLen = newptr - *newBuf; + + return true; +} diff --git a/extensions/universalchardet/src/base/nsCharSetProber.h b/extensions/universalchardet/src/base/nsCharSetProber.h new file mode 100644 index 000000000..4cb12794f --- /dev/null +++ b/extensions/universalchardet/src/base/nsCharSetProber.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef nsCharSetProber_h__ +#define nsCharSetProber_h__ + +#include "nscore.h" + +//#define DEBUG_chardet // Uncomment this for debug dump. + +typedef enum { + eDetecting = 0, //We are still detecting, no sure answer yet, but caller can ask for confidence. + eFoundIt = 1, //That's a positive answer + eNotMe = 2 //Negative answer +} nsProbingState; + +#define SHORTCUT_THRESHOLD (float)0.95 + +class nsCharSetProber { +public: + virtual ~nsCharSetProber() {} + virtual const char* GetCharSetName() = 0; + virtual nsProbingState HandleData(const char* aBuf, uint32_t aLen) = 0; + virtual nsProbingState GetState(void) = 0; + virtual void Reset(void) = 0; + virtual float GetConfidence(void) = 0; + +#ifdef DEBUG_chardet + virtual void DumpStatus() {}; +#endif + + // Helper functions used in the Latin1 and Group probers. + // both functions Allocate a new buffer for newBuf. This buffer should be + // freed by the caller using PR_FREEIF. + // Both functions return false in case of memory allocation failure. + static bool FilterWithoutEnglishLetters(const char* aBuf, uint32_t aLen, char** newBuf, uint32_t& newLen); + static bool FilterWithEnglishLetters(const char* aBuf, uint32_t aLen, char** newBuf, uint32_t& newLen); + +}; + +#endif /* nsCharSetProber_h__ */ diff --git a/extensions/universalchardet/src/base/nsCodingStateMachine.h b/extensions/universalchardet/src/base/nsCodingStateMachine.h new file mode 100644 index 000000000..53779959c --- /dev/null +++ b/extensions/universalchardet/src/base/nsCodingStateMachine.h @@ -0,0 +1,85 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef nsCodingStateMachine_h__ +#define nsCodingStateMachine_h__ + +#include "mozilla/ArrayUtils.h" + +#include "nsPkgInt.h" + +typedef enum { + eStart = 0, + eError = 1, + eItsMe = 2 +} nsSMState; + +#define GETCLASS(c) GETFROMPCK(((unsigned char)(c)), mModel->classTable) + +//state machine model +typedef struct +{ + nsPkgInt classTable; + uint32_t classFactor; + nsPkgInt stateTable; + const uint32_t* charLenTable; +#ifdef DEBUG + const size_t charLenTableLength; +#endif + const char* name; +} SMModel; + +class nsCodingStateMachine { +public: + explicit nsCodingStateMachine(const SMModel* sm) : mModel(sm) { mCurrentState = eStart; } + nsSMState NextState(char c){ + //for each byte we get its class , if it is first byte, we also get byte length + uint32_t byteCls = GETCLASS(c); + if (mCurrentState == eStart) + { + mCurrentBytePos = 0; + MOZ_ASSERT(byteCls < mModel->charLenTableLength); + mCurrentCharLen = mModel->charLenTable[byteCls]; + } + //from byte's class and stateTable, we get its next state + mCurrentState=(nsSMState)GETFROMPCK(mCurrentState*(mModel->classFactor)+byteCls, + mModel->stateTable); + mCurrentBytePos++; + return mCurrentState; + } + uint32_t GetCurrentCharLen(void) {return mCurrentCharLen;} + void Reset(void) {mCurrentState = eStart;} + const char * GetCodingStateMachine() {return mModel->name;} + +protected: + nsSMState mCurrentState; + uint32_t mCurrentCharLen; + uint32_t mCurrentBytePos; + + const SMModel *mModel; +}; + +extern const SMModel UTF8SMModel; +extern const SMModel Big5SMModel; +extern const SMModel EUCJPSMModel; +extern const SMModel EUCKRSMModel; +extern const SMModel EUCTWSMModel; +extern const SMModel GB18030SMModel; +extern const SMModel SJISSMModel; + + +extern const SMModel HZSMModel; +extern const SMModel ISO2022CNSMModel; +extern const SMModel ISO2022JPSMModel; +extern const SMModel ISO2022KRSMModel; + +#undef CHAR_LEN_TABLE +#ifdef DEBUG +#define CHAR_LEN_TABLE(x) x, mozilla::ArrayLength(x) +#else +#define CHAR_LEN_TABLE(x) x +#endif + +#endif /* nsCodingStateMachine_h__ */ + diff --git a/extensions/universalchardet/src/base/nsEUCJPProber.cpp b/extensions/universalchardet/src/base/nsEUCJPProber.cpp new file mode 100644 index 000000000..663421f03 --- /dev/null +++ b/extensions/universalchardet/src/base/nsEUCJPProber.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// for japanese encoding, obeserve characteristic: +// 1, kana character (or hankaku?) often have hight frequency of appereance +// 2, kana character often exist in group +// 3, certain combination of kana is never used in japanese language + +#include "nsEUCJPProber.h" +#include "nsDebug.h" + +void nsEUCJPProber::Reset(void) +{ + mCodingSM->Reset(); + mState = eDetecting; + mContextAnalyser.Reset(); + mDistributionAnalyser.Reset(); +} + +nsProbingState nsEUCJPProber::HandleData(const char* aBuf, uint32_t aLen) +{ + NS_ASSERTION(aLen, "HandleData called with empty buffer"); + nsSMState codingState; + + for (uint32_t i = 0; i < aLen; i++) + { + codingState = mCodingSM->NextState(aBuf[i]); + if (codingState == eItsMe) + { + mState = eFoundIt; + break; + } + if (codingState == eStart) + { + uint32_t charLen = mCodingSM->GetCurrentCharLen(); + + if (i == 0) + { + mLastChar[1] = aBuf[0]; + mContextAnalyser.HandleOneChar(mLastChar, charLen); + mDistributionAnalyser.HandleOneChar(mLastChar, charLen); + } + else + { + mContextAnalyser.HandleOneChar(aBuf+i-1, charLen); + mDistributionAnalyser.HandleOneChar(aBuf+i-1, charLen); + } + } + } + + mLastChar[0] = aBuf[aLen-1]; + + if (mState == eDetecting) + if (mContextAnalyser.GotEnoughData() && GetConfidence() > SHORTCUT_THRESHOLD) + mState = eFoundIt; + + return mState; +} + +float nsEUCJPProber::GetConfidence(void) +{ + float contxtCf = mContextAnalyser.GetConfidence(); + float distribCf = mDistributionAnalyser.GetConfidence(); + + return (contxtCf > distribCf ? contxtCf : distribCf); +} + diff --git a/extensions/universalchardet/src/base/nsEUCJPProber.h b/extensions/universalchardet/src/base/nsEUCJPProber.h new file mode 100644 index 000000000..4880151e5 --- /dev/null +++ b/extensions/universalchardet/src/base/nsEUCJPProber.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// for S-JIS encoding, obeserve characteristic: +// 1, kana character (or hankaku?) often have hight frequency of appereance +// 2, kana character often exist in group +// 3, certain combination of kana is never used in japanese language + +#ifndef nsEUCJPProber_h__ +#define nsEUCJPProber_h__ + +#include "nsCharSetProber.h" +#include "nsCodingStateMachine.h" +#include "JpCntx.h" +#include "CharDistribution.h" + +class nsEUCJPProber: public nsCharSetProber { +public: + nsEUCJPProber() + {mCodingSM = new nsCodingStateMachine(&EUCJPSMModel); + Reset();} + virtual ~nsEUCJPProber(void){delete mCodingSM;} + nsProbingState HandleData(const char* aBuf, uint32_t aLen); + const char* GetCharSetName() {return "EUC-JP";} + nsProbingState GetState(void) {return mState;} + void Reset(void); + float GetConfidence(void); + +protected: + nsCodingStateMachine* mCodingSM; + nsProbingState mState; + + EUCJPContextAnalysis mContextAnalyser; + EUCJPDistributionAnalysis mDistributionAnalyser; + + char mLastChar[2]; +}; + + +#endif /* nsEUCJPProber_h__ */ + diff --git a/extensions/universalchardet/src/base/nsEscCharsetProber.cpp b/extensions/universalchardet/src/base/nsEscCharsetProber.cpp new file mode 100644 index 000000000..b4fbfeb00 --- /dev/null +++ b/extensions/universalchardet/src/base/nsEscCharsetProber.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "nsEscCharsetProber.h" +#include "nsUniversalDetector.h" + +nsEscCharSetProber::nsEscCharSetProber() +{ + mCodingSM = new nsCodingStateMachine(&ISO2022JPSMModel); + mState = eDetecting; + mDetectedCharset = nullptr; +} + +nsEscCharSetProber::~nsEscCharSetProber(void) +{ +} + +void nsEscCharSetProber::Reset(void) +{ + mState = eDetecting; + mCodingSM->Reset(); + mDetectedCharset = nullptr; +} + +nsProbingState nsEscCharSetProber::HandleData(const char* aBuf, uint32_t aLen) +{ + nsSMState codingState; + uint32_t i; + + for ( i = 0; i < aLen && mState == eDetecting; i++) + { + codingState = mCodingSM->NextState(aBuf[i]); + if (codingState == eItsMe) + { + mState = eFoundIt; + mDetectedCharset = mCodingSM->GetCodingStateMachine(); + return mState; + } + } + + return mState; +} + diff --git a/extensions/universalchardet/src/base/nsEscCharsetProber.h b/extensions/universalchardet/src/base/nsEscCharsetProber.h new file mode 100644 index 000000000..4507972d0 --- /dev/null +++ b/extensions/universalchardet/src/base/nsEscCharsetProber.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsEscCharSetProber_h__ +#define nsEscCharSetProber_h__ + +#include "nsCharSetProber.h" +#include "nsCodingStateMachine.h" +#include "nsAutoPtr.h" + +class nsEscCharSetProber: public nsCharSetProber { +public: + nsEscCharSetProber(); + virtual ~nsEscCharSetProber(void); + nsProbingState HandleData(const char* aBuf, uint32_t aLen); + const char* GetCharSetName() {return mDetectedCharset;} + nsProbingState GetState(void) {return mState;} + void Reset(void); + float GetConfidence(void){return (float)0.99;} + +protected: + void GetDistribution(uint32_t aCharLen, const char* aStr); + + nsAutoPtr mCodingSM; + nsProbingState mState; + const char * mDetectedCharset; +}; + +#endif /* nsEscCharSetProber_h__ */ + diff --git a/extensions/universalchardet/src/base/nsEscSM.cpp b/extensions/universalchardet/src/base/nsEscSM.cpp new file mode 100644 index 000000000..77a223fec --- /dev/null +++ b/extensions/universalchardet/src/base/nsEscSM.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsCodingStateMachine.h" + +static const uint32_t ISO2022JP_cls [ 256 / 8 ] = { +PCK4BITS(2,0,0,0,0,0,0,0), // 00 - 07 +PCK4BITS(0,0,0,0,0,0,2,2), // 08 - 0f +PCK4BITS(0,0,0,0,0,0,0,0), // 10 - 17 +PCK4BITS(0,0,0,1,0,0,0,0), // 18 - 1f +PCK4BITS(0,0,0,0,7,0,0,0), // 20 - 27 +PCK4BITS(3,0,0,0,0,0,0,0), // 28 - 2f +PCK4BITS(0,0,0,0,0,0,0,0), // 30 - 37 +PCK4BITS(0,0,0,0,0,0,0,0), // 38 - 3f +PCK4BITS(6,0,4,0,8,0,0,0), // 40 - 47 +PCK4BITS(0,9,5,0,0,0,0,0), // 48 - 4f +PCK4BITS(0,0,0,0,0,0,0,0), // 50 - 57 +PCK4BITS(0,0,0,0,0,0,0,0), // 58 - 5f +PCK4BITS(0,0,0,0,0,0,0,0), // 60 - 67 +PCK4BITS(0,0,0,0,0,0,0,0), // 68 - 6f +PCK4BITS(0,0,0,0,0,0,0,0), // 70 - 77 +PCK4BITS(0,0,0,0,0,0,0,0), // 78 - 7f +PCK4BITS(2,2,2,2,2,2,2,2), // 80 - 87 +PCK4BITS(2,2,2,2,2,2,2,2), // 88 - 8f +PCK4BITS(2,2,2,2,2,2,2,2), // 90 - 97 +PCK4BITS(2,2,2,2,2,2,2,2), // 98 - 9f +PCK4BITS(2,2,2,2,2,2,2,2), // a0 - a7 +PCK4BITS(2,2,2,2,2,2,2,2), // a8 - af +PCK4BITS(2,2,2,2,2,2,2,2), // b0 - b7 +PCK4BITS(2,2,2,2,2,2,2,2), // b8 - bf +PCK4BITS(2,2,2,2,2,2,2,2), // c0 - c7 +PCK4BITS(2,2,2,2,2,2,2,2), // c8 - cf +PCK4BITS(2,2,2,2,2,2,2,2), // d0 - d7 +PCK4BITS(2,2,2,2,2,2,2,2), // d8 - df +PCK4BITS(2,2,2,2,2,2,2,2), // e0 - e7 +PCK4BITS(2,2,2,2,2,2,2,2), // e8 - ef +PCK4BITS(2,2,2,2,2,2,2,2), // f0 - f7 +PCK4BITS(2,2,2,2,2,2,2,2) // f8 - ff +}; + + +static const uint32_t ISO2022JP_st [ 9] = { +PCK4BITS(eStart, 3,eError,eStart,eStart,eStart,eStart,eStart),//00-07 +PCK4BITS(eStart,eStart,eError,eError,eError,eError,eError,eError),//08-0f +PCK4BITS(eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe),//10-17 +PCK4BITS(eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError),//18-1f +PCK4BITS(eError, 5,eError,eError,eError, 4,eError,eError),//20-27 +PCK4BITS(eError,eError,eError, 6,eItsMe,eError,eItsMe,eError),//28-2f +PCK4BITS(eError,eError,eError,eError,eError,eError,eItsMe,eItsMe),//30-37 +PCK4BITS(eError,eError,eError,eItsMe,eError,eError,eError,eError),//38-3f +PCK4BITS(eError,eError,eError,eError,eItsMe,eError,eStart,eStart) //40-47 +}; + +static const uint32_t ISO2022JPCharLenTable[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +const SMModel ISO2022JPSMModel = { + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022JP_cls }, + 10, + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022JP_st }, + CHAR_LEN_TABLE(ISO2022JPCharLenTable), + "ISO-2022-JP", +}; diff --git a/extensions/universalchardet/src/base/nsLatin1Prober.cpp b/extensions/universalchardet/src/base/nsLatin1Prober.cpp new file mode 100644 index 000000000..e2769486e --- /dev/null +++ b/extensions/universalchardet/src/base/nsLatin1Prober.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsLatin1Prober.h" +#include "prmem.h" +#include + +#define UDF 0 // undefined +#define OTH 1 //other +#define ASC 2 // ascii capital letter +#define ASS 3 // ascii small letter +#define ACV 4 // accent capital vowel +#define ACO 5 // accent capital other +#define ASV 6 // accent small vowel +#define ASO 7 // accent small other +#define CLASS_NUM 8 // total classes + +static const unsigned char Latin1_CharToClass[] = +{ + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, // 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, // 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, // 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, // 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, // 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, // 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, // 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, // 78 - 7F + OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, // 80 - 87 + OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, // 88 - 8F + UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // 90 - 97 + OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, // 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // A0 - A7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, // B8 - BF + ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, // C0 - C7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, // C8 - CF + ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, // D0 - D7 + ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, // D8 - DF + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, // E0 - E7 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, // E8 - EF + ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, // F0 - F7 + ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, // F8 - FF +}; + + +/* 0 : illegal + 1 : very unlikely + 2 : normal + 3 : very likely +*/ +static const unsigned char Latin1ClassModel[] = +{ +/* UDF OTH ASC ASS ACV ACO ASV ASO */ +/*UDF*/ 0, 0, 0, 0, 0, 0, 0, 0, +/*OTH*/ 0, 3, 3, 3, 3, 3, 3, 3, +/*ASC*/ 0, 3, 3, 3, 3, 3, 3, 3, +/*ASS*/ 0, 3, 3, 3, 1, 1, 3, 3, +/*ACV*/ 0, 3, 3, 3, 1, 2, 1, 2, +/*ACO*/ 0, 3, 3, 3, 3, 3, 3, 3, +/*ASV*/ 0, 3, 1, 3, 1, 1, 1, 3, +/*ASO*/ 0, 3, 1, 3, 1, 1, 3, 3, +}; + +void nsLatin1Prober::Reset(void) +{ + mState = eDetecting; + mLastCharClass = OTH; + for (int i = 0; i < FREQ_CAT_NUM; i++) + mFreqCounter[i] = 0; +} + + +nsProbingState nsLatin1Prober::HandleData(const char* aBuf, uint32_t aLen) +{ + char *newBuf1 = 0; + uint32_t newLen1 = 0; + + if (!FilterWithEnglishLetters(aBuf, aLen, &newBuf1, newLen1)) { + newBuf1 = (char*)aBuf; + newLen1 = aLen; + } + + unsigned char charClass; + unsigned char freq; + for (uint32_t i = 0; i < newLen1; i++) + { + charClass = Latin1_CharToClass[(unsigned char)newBuf1[i]]; + freq = Latin1ClassModel[mLastCharClass*CLASS_NUM + charClass]; + if (freq == 0) { + mState = eNotMe; + break; + } + mFreqCounter[freq]++; + mLastCharClass = charClass; + } + + if (newBuf1 != aBuf) + PR_FREEIF(newBuf1); + + return mState; +} + +float nsLatin1Prober::GetConfidence(void) +{ + if (mState == eNotMe) + return 0.01f; + + float confidence; + uint32_t total = 0; + for (int32_t i = 0; i < FREQ_CAT_NUM; i++) + total += mFreqCounter[i]; + + if(!total) + confidence = 0.0f; + else + { + confidence = mFreqCounter[3]*1.0f / total; + confidence -= mFreqCounter[1]*20.0f/total; + } + + if (confidence < 0.0f) + confidence = 0.0f; + + // lower the confidence of latin1 so that other more accurate detector + // can take priority. + confidence *= 0.50f; + + return confidence; +} + +#ifdef DEBUG_chardet +void nsLatin1Prober::DumpStatus() +{ + printf(" Latin1Prober: %1.3f [%s]\r\n", GetConfidence(), GetCharSetName()); +} +#endif + + diff --git a/extensions/universalchardet/src/base/nsLatin1Prober.h b/extensions/universalchardet/src/base/nsLatin1Prober.h new file mode 100644 index 000000000..df25d083b --- /dev/null +++ b/extensions/universalchardet/src/base/nsLatin1Prober.h @@ -0,0 +1,36 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsLatin1Prober_h__ +#define nsLatin1Prober_h__ + +#include "nsCharSetProber.h" + +#define FREQ_CAT_NUM 4 + +class nsLatin1Prober: public nsCharSetProber { +public: + nsLatin1Prober(void){Reset();} + virtual ~nsLatin1Prober(void){} + nsProbingState HandleData(const char* aBuf, uint32_t aLen); + const char* GetCharSetName() {return "windows-1252";} + nsProbingState GetState(void) {return mState;} + void Reset(void); + float GetConfidence(void); + +#ifdef DEBUG_chardet + virtual void DumpStatus(); +#endif + +protected: + + nsProbingState mState; + char mLastCharClass; + uint32_t mFreqCounter[FREQ_CAT_NUM]; +}; + + +#endif /* nsLatin1Prober_h__ */ + diff --git a/extensions/universalchardet/src/base/nsMBCSGroupProber.cpp b/extensions/universalchardet/src/base/nsMBCSGroupProber.cpp new file mode 100644 index 000000000..b47691443 --- /dev/null +++ b/extensions/universalchardet/src/base/nsMBCSGroupProber.cpp @@ -0,0 +1,177 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + +#include "nsMBCSGroupProber.h" +#include "nsUniversalDetector.h" + +#if defined(DEBUG_chardet) || defined(DEBUG_jgmyers) +const char *ProberName[] = +{ + "UTF8", + "SJIS", + "EUCJP", +}; + +#endif + +nsMBCSGroupProber::nsMBCSGroupProber() +{ + mProbers[0] = new nsUTF8Prober(); + mProbers[1] = new nsSJISProber(); + mProbers[2] = new nsEUCJPProber(); + Reset(); +} + +nsMBCSGroupProber::~nsMBCSGroupProber() +{ + for (uint32_t i = 0; i < NUM_OF_PROBERS; i++) + { + delete mProbers[i]; + } +} + +const char* nsMBCSGroupProber::GetCharSetName() +{ + if (mBestGuess == -1) + { + GetConfidence(); + if (mBestGuess == -1) + mBestGuess = 0; + } + return mProbers[mBestGuess]->GetCharSetName(); +} + +void nsMBCSGroupProber::Reset(void) +{ + mActiveNum = 0; + for (uint32_t i = 0; i < NUM_OF_PROBERS; i++) + { + if (mProbers[i]) + { + mProbers[i]->Reset(); + mIsActive[i] = true; + ++mActiveNum; + } + else + mIsActive[i] = false; + } + mBestGuess = -1; + mState = eDetecting; + mKeepNext = 0; +} + +nsProbingState nsMBCSGroupProber::HandleData(const char* aBuf, uint32_t aLen) +{ + nsProbingState st; + uint32_t start = 0; + uint32_t keepNext = mKeepNext; + + //do filtering to reduce load to probers + for (uint32_t pos = 0; pos < aLen; ++pos) + { + if (aBuf[pos] & 0x80) + { + if (!keepNext) + start = pos; + keepNext = 2; + } + else if (keepNext) + { + if (--keepNext == 0) + { + for (uint32_t i = 0; i < NUM_OF_PROBERS; i++) + { + if (!mIsActive[i]) + continue; + st = mProbers[i]->HandleData(aBuf + start, pos + 1 - start); + if (st == eFoundIt) + { + mBestGuess = i; + mState = eFoundIt; + return mState; + } + } + } + } + } + + if (keepNext) { + for (uint32_t i = 0; i < NUM_OF_PROBERS; i++) + { + if (!mIsActive[i]) + continue; + st = mProbers[i]->HandleData(aBuf + start, aLen - start); + if (st == eFoundIt) + { + mBestGuess = i; + mState = eFoundIt; + return mState; + } + } + } + mKeepNext = keepNext; + + return mState; +} + +float nsMBCSGroupProber::GetConfidence(void) +{ + uint32_t i; + float bestConf = 0.0, cf; + + switch (mState) + { + case eFoundIt: + return (float)0.99; + case eNotMe: + return (float)0.01; + default: + for (i = 0; i < NUM_OF_PROBERS; i++) + { + if (!mIsActive[i]) + continue; + cf = mProbers[i]->GetConfidence(); + if (bestConf < cf) + { + bestConf = cf; + mBestGuess = i; + } + } + } + return bestConf; +} + +#ifdef DEBUG_chardet +void nsMBCSGroupProber::DumpStatus() +{ + uint32_t i; + float cf; + + GetConfidence(); + for (i = 0; i < NUM_OF_PROBERS; i++) + { + if (!mIsActive[i]) + printf(" MBCS inactive: [%s] (confidence is too low).\r\n", ProberName[i]); + else + { + cf = mProbers[i]->GetConfidence(); + printf(" MBCS %1.3f: [%s]\r\n", cf, ProberName[i]); + } + } +} +#endif + +#ifdef DEBUG_jgmyers +void nsMBCSGroupProber::GetDetectorState(nsUniversalDetector::DetectorState (&states)[nsUniversalDetector::NumDetectors], uint32_t &offset) +{ + for (uint32_t i = 0; i < NUM_OF_PROBERS; ++i) { + states[offset].name = ProberName[i]; + states[offset].isActive = mIsActive[i]; + states[offset].confidence = mIsActive[i] ? mProbers[i]->GetConfidence() : 0.0; + ++offset; + } +} +#endif /* DEBUG_jgmyers */ diff --git a/extensions/universalchardet/src/base/nsMBCSGroupProber.h b/extensions/universalchardet/src/base/nsMBCSGroupProber.h new file mode 100644 index 000000000..444b31d09 --- /dev/null +++ b/extensions/universalchardet/src/base/nsMBCSGroupProber.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsMBCSGroupProber_h__ +#define nsMBCSGroupProber_h__ + +#include "nsSJISProber.h" +#include "nsUTF8Prober.h" +#include "nsEUCJPProber.h" + +#define NUM_OF_PROBERS 3 + +class nsMBCSGroupProber: public nsCharSetProber { +public: + nsMBCSGroupProber(); + virtual ~nsMBCSGroupProber(); + nsProbingState HandleData(const char* aBuf, uint32_t aLen); + const char* GetCharSetName(); + nsProbingState GetState(void) {return mState;} + void Reset(void); + float GetConfidence(void); + +#ifdef DEBUG_chardet + void DumpStatus(); +#endif +#ifdef DEBUG_jgmyers + void GetDetectorState(nsUniversalDetector::DetectorState (&states)[nsUniversalDetector::NumDetectors], uint32_t &offset); +#endif + +protected: + nsProbingState mState; + nsCharSetProber* mProbers[NUM_OF_PROBERS]; + bool mIsActive[NUM_OF_PROBERS]; + int32_t mBestGuess; + uint32_t mActiveNum; + uint32_t mKeepNext; +}; + +#endif /* nsMBCSGroupProber_h__ */ + diff --git a/extensions/universalchardet/src/base/nsMBCSSM.cpp b/extensions/universalchardet/src/base/nsMBCSSM.cpp new file mode 100644 index 000000000..6a1adbf86 --- /dev/null +++ b/extensions/universalchardet/src/base/nsMBCSSM.cpp @@ -0,0 +1,188 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsCodingStateMachine.h" + +/* +Modification from frank tang's original work: +. 0x00 is allowed as a legal character. Since some web pages contains this char in + text stream. +*/ + +static const uint32_t EUCJP_cls [ 256 / 8 ] = { +//PCK4BITS(5,4,4,4,4,4,4,4), // 00 - 07 +PCK4BITS(4,4,4,4,4,4,4,4), // 00 - 07 +PCK4BITS(4,4,4,4,4,4,5,5), // 08 - 0f +PCK4BITS(4,4,4,4,4,4,4,4), // 10 - 17 +PCK4BITS(4,4,4,5,4,4,4,4), // 18 - 1f +PCK4BITS(4,4,4,4,4,4,4,4), // 20 - 27 +PCK4BITS(4,4,4,4,4,4,4,4), // 28 - 2f +PCK4BITS(4,4,4,4,4,4,4,4), // 30 - 37 +PCK4BITS(4,4,4,4,4,4,4,4), // 38 - 3f +PCK4BITS(4,4,4,4,4,4,4,4), // 40 - 47 +PCK4BITS(4,4,4,4,4,4,4,4), // 48 - 4f +PCK4BITS(4,4,4,4,4,4,4,4), // 50 - 57 +PCK4BITS(4,4,4,4,4,4,4,4), // 58 - 5f +PCK4BITS(4,4,4,4,4,4,4,4), // 60 - 67 +PCK4BITS(4,4,4,4,4,4,4,4), // 68 - 6f +PCK4BITS(4,4,4,4,4,4,4,4), // 70 - 77 +PCK4BITS(4,4,4,4,4,4,4,4), // 78 - 7f +PCK4BITS(5,5,5,5,5,5,5,5), // 80 - 87 +PCK4BITS(5,5,5,5,5,5,1,3), // 88 - 8f +PCK4BITS(5,5,5,5,5,5,5,5), // 90 - 97 +PCK4BITS(5,5,5,5,5,5,5,5), // 98 - 9f +PCK4BITS(5,2,2,2,2,2,2,2), // a0 - a7 +PCK4BITS(2,2,2,2,2,2,2,2), // a8 - af +PCK4BITS(2,2,2,2,2,2,2,2), // b0 - b7 +PCK4BITS(2,2,2,2,2,2,2,2), // b8 - bf +PCK4BITS(2,2,2,2,2,2,2,2), // c0 - c7 +PCK4BITS(2,2,2,2,2,2,2,2), // c8 - cf +PCK4BITS(2,2,2,2,2,2,2,2), // d0 - d7 +PCK4BITS(2,2,2,2,2,2,2,2), // d8 - df +PCK4BITS(0,0,0,0,0,0,0,0), // e0 - e7 +PCK4BITS(0,0,0,0,0,0,0,0), // e8 - ef +PCK4BITS(0,0,0,0,0,0,0,0), // f0 - f7 +PCK4BITS(0,0,0,0,0,0,0,5) // f8 - ff +}; + + +static const uint32_t EUCJP_st [ 5] = { +PCK4BITS( 3, 4, 3, 5,eStart,eError,eError,eError),//00-07 +PCK4BITS(eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe),//08-0f +PCK4BITS(eItsMe,eItsMe,eStart,eError,eStart,eError,eError,eError),//10-17 +PCK4BITS(eError,eError,eStart,eError,eError,eError, 3,eError),//18-1f +PCK4BITS( 3,eError,eError,eError,eStart,eStart,eStart,eStart) //20-27 +}; + +static const uint32_t EUCJPCharLenTable[] = {2, 2, 2, 3, 1, 0}; + +const SMModel EUCJPSMModel = { + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCJP_cls }, + 6, + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCJP_st }, + CHAR_LEN_TABLE(EUCJPCharLenTable), + "EUC-JP", +}; + +// sjis + +static const uint32_t SJIS_cls [ 256 / 8 ] = { +//PCK4BITS(0,1,1,1,1,1,1,1), // 00 - 07 +PCK4BITS(1,1,1,1,1,1,1,1), // 00 - 07 +PCK4BITS(1,1,1,1,1,1,0,0), // 08 - 0f +PCK4BITS(1,1,1,1,1,1,1,1), // 10 - 17 +PCK4BITS(1,1,1,0,1,1,1,1), // 18 - 1f +PCK4BITS(1,1,1,1,1,1,1,1), // 20 - 27 +PCK4BITS(1,1,1,1,1,1,1,1), // 28 - 2f +PCK4BITS(1,1,1,1,1,1,1,1), // 30 - 37 +PCK4BITS(1,1,1,1,1,1,1,1), // 38 - 3f +PCK4BITS(2,2,2,2,2,2,2,2), // 40 - 47 +PCK4BITS(2,2,2,2,2,2,2,2), // 48 - 4f +PCK4BITS(2,2,2,2,2,2,2,2), // 50 - 57 +PCK4BITS(2,2,2,2,2,2,2,2), // 58 - 5f +PCK4BITS(2,2,2,2,2,2,2,2), // 60 - 67 +PCK4BITS(2,2,2,2,2,2,2,2), // 68 - 6f +PCK4BITS(2,2,2,2,2,2,2,2), // 70 - 77 +PCK4BITS(2,2,2,2,2,2,2,1), // 78 - 7f +PCK4BITS(3,3,3,3,3,3,3,3), // 80 - 87 +PCK4BITS(3,3,3,3,3,3,3,3), // 88 - 8f +PCK4BITS(3,3,3,3,3,3,3,3), // 90 - 97 +PCK4BITS(3,3,3,3,3,3,3,3), // 98 - 9f +//0xa0 is illegal in sjis encoding, but some pages does +//contain such byte. We need to be more error forgiven. +PCK4BITS(2,2,2,2,2,2,2,2), // a0 - a7 +PCK4BITS(2,2,2,2,2,2,2,2), // a8 - af +PCK4BITS(2,2,2,2,2,2,2,2), // b0 - b7 +PCK4BITS(2,2,2,2,2,2,2,2), // b8 - bf +PCK4BITS(2,2,2,2,2,2,2,2), // c0 - c7 +PCK4BITS(2,2,2,2,2,2,2,2), // c8 - cf +PCK4BITS(2,2,2,2,2,2,2,2), // d0 - d7 +PCK4BITS(2,2,2,2,2,2,2,2), // d8 - df +PCK4BITS(3,3,3,3,3,3,3,3), // e0 - e7 +PCK4BITS(3,3,3,3,3,4,4,4), // e8 - ef +PCK4BITS(4,4,4,4,4,4,4,4), // f0 - f7 +PCK4BITS(4,4,4,4,4,0,0,0) // f8 - ff +}; + + +static const uint32_t SJIS_st [ 3] = { +PCK4BITS(eError,eStart,eStart, 3,eError,eError,eError,eError),//00-07 +PCK4BITS(eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe),//08-0f +PCK4BITS(eItsMe,eItsMe,eError,eError,eStart,eStart,eStart,eStart) //10-17 +}; + +static const uint32_t SJISCharLenTable[] = {0, 1, 1, 2, 0, 0}; + +const SMModel SJISSMModel = { + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, SJIS_cls }, + 6, + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, SJIS_st }, + CHAR_LEN_TABLE(SJISCharLenTable), + "Shift_JIS", +}; + + +static const uint32_t UTF8_cls [ 256 / 8 ] = { +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 00 - 07 +PCK4BITS( 1, 1, 1, 1, 1, 1, 0, 0), // 08 - 0f +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 10 - 17 +PCK4BITS( 1, 1, 1, 0, 1, 1, 1, 1), // 18 - 1f +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 20 - 27 +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 28 - 2f +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 30 - 37 +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 38 - 3f +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 40 - 47 +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 48 - 4f +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 50 - 57 +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 58 - 5f +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 60 - 67 +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 68 - 6f +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 70 - 77 +PCK4BITS( 1, 1, 1, 1, 1, 1, 1, 1), // 78 - 7f +PCK4BITS( 2, 2, 2, 2, 2, 2, 2, 2), // 80 - 87 +PCK4BITS( 2, 2, 2, 2, 2, 2, 2, 2), // 88 - 8f +PCK4BITS( 3, 3, 3, 3, 3, 3, 3, 3), // 90 - 97 +PCK4BITS( 3, 3, 3, 3, 3, 3, 3, 3), // 98 - 9f +PCK4BITS( 4, 4, 4, 4, 4, 4, 4, 4), // a0 - a7 +PCK4BITS( 4, 4, 4, 4, 4, 4, 4, 4), // a8 - af +PCK4BITS( 4, 4, 4, 4, 4, 4, 4, 4), // b0 - b7 +PCK4BITS( 4, 4, 4, 4, 4, 4, 4, 4), // b8 - bf +PCK4BITS( 0, 0, 5, 5, 5, 5, 5, 5), // c0 - c7 +PCK4BITS( 5, 5, 5, 5, 5, 5, 5, 5), // c8 - cf +PCK4BITS( 5, 5, 5, 5, 5, 5, 5, 5), // d0 - d7 +PCK4BITS( 5, 5, 5, 5, 5, 5, 5, 5), // d8 - df +PCK4BITS( 6, 7, 7, 7, 7, 7, 7, 7), // e0 - e7 +PCK4BITS( 7, 7, 7, 7, 7, 8, 7, 7), // e8 - ef +PCK4BITS( 9,10,10,10,11, 0, 0, 0), // f0 - f7 +PCK4BITS( 0, 0, 0, 0, 0, 0, 0, 0) // f8 - ff +}; + + +static const uint32_t UTF8_st [ 15] = { +PCK4BITS(eError,eStart,eError,eError,eError, 3, 4, 5), // 00 - 07 +PCK4BITS( 6, 7, 8, 9,eError,eError,eError,eError), // 08 - 0f +PCK4BITS(eError,eError,eError,eError,eError,eError,eError,eError), // 10 - 17 +PCK4BITS(eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe), // 18 - 1f +PCK4BITS(eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,eStart,eStart), // 20 - 27 +PCK4BITS(eStart,eError,eError,eError,eError,eError,eError,eError), // 28 - 2f +PCK4BITS(eError,eError,eError,eError, 3,eError,eError,eError), // 30 - 37 +PCK4BITS(eError,eError,eError,eError,eError,eError, 3, 3), // 38 - 3f +PCK4BITS( 3,eError,eError,eError,eError,eError,eError,eError), // 40 - 47 +PCK4BITS(eError,eError, 3, 3,eError,eError,eError,eError), // 48 - 4f +PCK4BITS(eError,eError,eError,eError,eError,eError, 5, 5), // 50 - 57 +PCK4BITS(eError,eError,eError,eError,eError,eError,eError,eError), // 58 - 5f +PCK4BITS(eError,eError, 5, 5, 5,eError,eError,eError), // 60 - 67 +PCK4BITS(eError,eError,eError,eError,eError,eError, 5,eError), // 68 - 6f +PCK4BITS(eError,eError,eError,eError,eError,eError,eError,eError) // 70 - 77 +}; + +static const uint32_t UTF8CharLenTable[] = {0, 1, 0, 0, 0, 2, 3, 3, 3, 4, 4, 4}; + +const SMModel UTF8SMModel = { + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, UTF8_cls }, + 12, + {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, UTF8_st }, + CHAR_LEN_TABLE(UTF8CharLenTable), + "UTF-8", +}; diff --git a/extensions/universalchardet/src/base/nsPkgInt.h b/extensions/universalchardet/src/base/nsPkgInt.h new file mode 100644 index 000000000..488b2389d --- /dev/null +++ b/extensions/universalchardet/src/base/nsPkgInt.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsPkgInt_h__ +#define nsPkgInt_h__ +#include "nscore.h" + +typedef enum { + eIdxSft4bits = 3, + eIdxSft8bits = 2, + eIdxSft16bits = 1 +} nsIdxSft; + +typedef enum { + eSftMsk4bits = 7, + eSftMsk8bits = 3, + eSftMsk16bits = 1 +} nsSftMsk; + +typedef enum { + eBitSft4bits = 2, + eBitSft8bits = 3, + eBitSft16bits = 4 +} nsBitSft; + +typedef enum { + eUnitMsk4bits = 0x0000000FL, + eUnitMsk8bits = 0x000000FFL, + eUnitMsk16bits = 0x0000FFFFL +} nsUnitMsk; + +typedef struct nsPkgInt { + nsIdxSft idxsft; + nsSftMsk sftmsk; + nsBitSft bitsft; + nsUnitMsk unitmsk; + const uint32_t* const data; +} nsPkgInt; + + +#define PCK16BITS(a,b) ((uint32_t)(((b) << 16) | (a))) + +#define PCK8BITS(a,b,c,d) PCK16BITS( ((uint32_t)(((b) << 8) | (a))), \ + ((uint32_t)(((d) << 8) | (c)))) + +#define PCK4BITS(a,b,c,d,e,f,g,h) PCK8BITS( ((uint32_t)(((b) << 4) | (a))), \ + ((uint32_t)(((d) << 4) | (c))), \ + ((uint32_t)(((f) << 4) | (e))), \ + ((uint32_t)(((h) << 4) | (g))) ) + +#define GETFROMPCK(i, c) \ + (((((c).data)[(i)>>(c).idxsft])>>(((i)&(c).sftmsk)<<(c).bitsft))&(c).unitmsk) + +#endif /* nsPkgInt_h__ */ + diff --git a/extensions/universalchardet/src/base/nsSJISProber.cpp b/extensions/universalchardet/src/base/nsSJISProber.cpp new file mode 100644 index 000000000..73d615bd9 --- /dev/null +++ b/extensions/universalchardet/src/base/nsSJISProber.cpp @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// for S-JIS encoding, obeserve characteristic: +// 1, kana character (or hankaku?) often have hight frequency of appereance +// 2, kana character often exist in group +// 3, certain combination of kana is never used in japanese language + +#include "nsSJISProber.h" +#include "nsDebug.h" + +void nsSJISProber::Reset(void) +{ + mCodingSM->Reset(); + mState = eDetecting; + mContextAnalyser.Reset(); + mDistributionAnalyser.Reset(); +} + +nsProbingState nsSJISProber::HandleData(const char* aBuf, uint32_t aLen) +{ + NS_ASSERTION(aLen, "HandleData called with empty buffer"); + nsSMState codingState; + + for (uint32_t i = 0; i < aLen; i++) + { + codingState = mCodingSM->NextState(aBuf[i]); + if (codingState == eItsMe) + { + mState = eFoundIt; + break; + } + if (codingState == eStart) + { + uint32_t charLen = mCodingSM->GetCurrentCharLen(); + if (i == 0) + { + mLastChar[1] = aBuf[0]; + mContextAnalyser.HandleOneChar(mLastChar+2-charLen, charLen); + mDistributionAnalyser.HandleOneChar(mLastChar, charLen); + } + else + { + mContextAnalyser.HandleOneChar(aBuf+i+1-charLen, charLen); + mDistributionAnalyser.HandleOneChar(aBuf+i-1, charLen); + } + } + } + + mLastChar[0] = aBuf[aLen-1]; + + if (mState == eDetecting) + if (mContextAnalyser.GotEnoughData() && GetConfidence() > SHORTCUT_THRESHOLD) + mState = eFoundIt; + + return mState; +} + +float nsSJISProber::GetConfidence(void) +{ + float contxtCf = mContextAnalyser.GetConfidence(); + float distribCf = mDistributionAnalyser.GetConfidence(); + + return (contxtCf > distribCf ? contxtCf : distribCf); +} + diff --git a/extensions/universalchardet/src/base/nsSJISProber.h b/extensions/universalchardet/src/base/nsSJISProber.h new file mode 100644 index 000000000..6044fae87 --- /dev/null +++ b/extensions/universalchardet/src/base/nsSJISProber.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// for S-JIS encoding, obeserve characteristic: +// 1, kana character (or hankaku?) often have hight frequency of appereance +// 2, kana character often exist in group +// 3, certain combination of kana is never used in japanese language + +#ifndef nsSJISProber_h__ +#define nsSJISProber_h__ + +#include "nsCharSetProber.h" +#include "nsCodingStateMachine.h" +#include "JpCntx.h" +#include "CharDistribution.h" + + +class nsSJISProber: public nsCharSetProber { +public: + nsSJISProber() + {mCodingSM = new nsCodingStateMachine(&SJISSMModel); + Reset();} + virtual ~nsSJISProber(void){delete mCodingSM;} + nsProbingState HandleData(const char* aBuf, uint32_t aLen); + const char* GetCharSetName() {return "Shift_JIS";} + nsProbingState GetState(void) {return mState;} + void Reset(void); + float GetConfidence(void); + +protected: + nsCodingStateMachine* mCodingSM; + nsProbingState mState; + + SJISContextAnalysis mContextAnalyser; + SJISDistributionAnalysis mDistributionAnalyser; + + char mLastChar[2]; +}; + + +#endif /* nsSJISProber_h__ */ + diff --git a/extensions/universalchardet/src/base/nsUTF8Prober.cpp b/extensions/universalchardet/src/base/nsUTF8Prober.cpp new file mode 100644 index 000000000..1cba4f3cb --- /dev/null +++ b/extensions/universalchardet/src/base/nsUTF8Prober.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsUTF8Prober.h" + +void nsUTF8Prober::Reset(void) +{ + mCodingSM->Reset(); + mNumOfMBChar = 0; + mState = eDetecting; +} + +nsProbingState nsUTF8Prober::HandleData(const char* aBuf, uint32_t aLen) +{ + nsSMState codingState; + + for (uint32_t i = 0; i < aLen; i++) + { + codingState = mCodingSM->NextState(aBuf[i]); + if (codingState == eItsMe) + { + mState = eFoundIt; + break; + } + if (codingState == eStart) + { + if (mCodingSM->GetCurrentCharLen() >= 2) + mNumOfMBChar++; + } + } + + if (mState == eDetecting) + if (GetConfidence() > SHORTCUT_THRESHOLD) + mState = eFoundIt; + return mState; +} + +#define ONE_CHAR_PROB (float)0.50 + +float nsUTF8Prober::GetConfidence(void) +{ + float unlike = (float)0.99; + + if (mNumOfMBChar < 6) + { + for (uint32_t i = 0; i < mNumOfMBChar; i++) + unlike *= ONE_CHAR_PROB; + return (float)1.0 - unlike; + } + else + return (float)0.99; +} + diff --git a/extensions/universalchardet/src/base/nsUTF8Prober.h b/extensions/universalchardet/src/base/nsUTF8Prober.h new file mode 100644 index 000000000..077d3dd74 --- /dev/null +++ b/extensions/universalchardet/src/base/nsUTF8Prober.h @@ -0,0 +1,31 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsUTF8Prober_h__ +#define nsUTF8Prober_h__ + +#include "nsCharSetProber.h" +#include "nsCodingStateMachine.h" + +class nsUTF8Prober: public nsCharSetProber { +public: + nsUTF8Prober(){mNumOfMBChar = 0; + mCodingSM = new nsCodingStateMachine(&UTF8SMModel); + Reset(); } + virtual ~nsUTF8Prober(){delete mCodingSM;} + nsProbingState HandleData(const char* aBuf, uint32_t aLen); + const char* GetCharSetName() {return "UTF-8";} + nsProbingState GetState(void) {return mState;} + void Reset(void); + float GetConfidence(void); + +protected: + nsCodingStateMachine* mCodingSM; + nsProbingState mState; + uint32_t mNumOfMBChar; +}; + +#endif /* nsUTF8Prober_h__ */ + diff --git a/extensions/universalchardet/src/base/nsUniversalDetector.cpp b/extensions/universalchardet/src/base/nsUniversalDetector.cpp new file mode 100644 index 000000000..d272827b8 --- /dev/null +++ b/extensions/universalchardet/src/base/nsUniversalDetector.cpp @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nscore.h" + +#include "nsUniversalDetector.h" + +#include "nsMBCSGroupProber.h" +#include "nsEscCharsetProber.h" +#include "nsLatin1Prober.h" + +nsUniversalDetector::nsUniversalDetector() +{ + mDone = false; + mBestGuess = -1; //illegal value as signal + mInTag = false; + mEscCharSetProber = nullptr; + + mStart = true; + mDetectedCharset = nullptr; + mGotData = false; + mInputState = ePureAscii; + mLastChar = '\0'; + + uint32_t i; + for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++) + mCharSetProbers[i] = nullptr; +} + +nsUniversalDetector::~nsUniversalDetector() +{ + for (int32_t i = 0; i < NUM_OF_CHARSET_PROBERS; i++) + delete mCharSetProbers[i]; + + delete mEscCharSetProber; +} + +void +nsUniversalDetector::Reset() +{ + mDone = false; + mBestGuess = -1; //illegal value as signal + mInTag = false; + + mStart = true; + mDetectedCharset = nullptr; + mGotData = false; + mInputState = ePureAscii; + mLastChar = '\0'; + + if (mEscCharSetProber) + mEscCharSetProber->Reset(); + + uint32_t i; + for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++) + if (mCharSetProbers[i]) + mCharSetProbers[i]->Reset(); +} + +//--------------------------------------------------------------------- +#define SHORTCUT_THRESHOLD (float)0.95 +#define MINIMUM_THRESHOLD (float)0.20 + +nsresult nsUniversalDetector::HandleData(const char* aBuf, uint32_t aLen) +{ + if(mDone) + return NS_OK; + + if (aLen > 0) + mGotData = true; + + //If the data starts with BOM, we know it is UTF + if (mStart) + { + mStart = false; + if (aLen >= 2) { + switch (aBuf[0]) { + case '\xEF': + if ((aLen > 2) && ('\xBB' == aBuf[1]) && ('\xBF' == aBuf[2])) { + // EF BB BF UTF-8 encoded BOM + mDetectedCharset = "UTF-8"; + } + break; + case '\xFE': + if ('\xFF' == aBuf[1]) { + // FE FF UTF-16, big endian BOM + mDetectedCharset = "UTF-16BE"; + } + break; + case '\xFF': + if ('\xFE' == aBuf[1]) { + // FF FE UTF-16, little endian BOM + mDetectedCharset = "UTF-16LE"; + } + break; + } // switch + } + + if (mDetectedCharset) + { + mDone = true; + return NS_OK; + } + } + + uint32_t i; + for (i = 0; i < aLen; i++) + { + //other than 0xa0, if every othe character is ascii, the page is ascii + if (aBuf[i] & '\x80' && aBuf[i] != '\xA0') //Since many Ascii only page contains NBSP + { + //we got a non-ascii byte (high-byte) + if (mInputState != eHighbyte) + { + //adjust state + mInputState = eHighbyte; + + //kill mEscCharSetProber if it is active + if (mEscCharSetProber) { + delete mEscCharSetProber; + mEscCharSetProber = nullptr; + } + + //start multibyte and singlebyte charset prober + if (nullptr == mCharSetProbers[0]) + { + mCharSetProbers[0] = new nsMBCSGroupProber(); + if (nullptr == mCharSetProbers[0]) + return NS_ERROR_OUT_OF_MEMORY; + } + if (nullptr == mCharSetProbers[2]) + { + mCharSetProbers[2] = new nsLatin1Prober; + if (nullptr == mCharSetProbers[2]) + return NS_ERROR_OUT_OF_MEMORY; + } + } + } + else + { + //ok, just pure ascii so far + if ((ePureAscii == mInputState) && (aBuf[i] == '\033')) + { + //found escape character + mInputState = eEscAscii; + } + mLastChar = aBuf[i]; + } + } + + nsProbingState st; + switch (mInputState) + { + case eEscAscii: + if (nullptr == mEscCharSetProber) { + mEscCharSetProber = new nsEscCharSetProber(); + if (nullptr == mEscCharSetProber) + return NS_ERROR_OUT_OF_MEMORY; + } + st = mEscCharSetProber->HandleData(aBuf, aLen); + if (st == eFoundIt) + { + mDone = true; + mDetectedCharset = mEscCharSetProber->GetCharSetName(); + } + break; + case eHighbyte: + for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++) + { + if (mCharSetProbers[i]) + { + st = mCharSetProbers[i]->HandleData(aBuf, aLen); + if (st == eFoundIt) + { + mDone = true; + mDetectedCharset = mCharSetProbers[i]->GetCharSetName(); + return NS_OK; + } + } + } + break; + + default: //pure ascii + ;//do nothing here + } + return NS_OK; +} + + +//--------------------------------------------------------------------- +void nsUniversalDetector::DataEnd() +{ + if (!mGotData) + { + // we haven't got any data yet, return immediately + // caller program sometimes call DataEnd before anything has been sent to detector + return; + } + + if (mDetectedCharset) + { + mDone = true; + Report(mDetectedCharset); + return; + } + + switch (mInputState) + { + case eHighbyte: + { + float proberConfidence; + float maxProberConfidence = (float)0.0; + int32_t maxProber = 0; + + for (int32_t i = 0; i < NUM_OF_CHARSET_PROBERS; i++) + { + if (mCharSetProbers[i]) + { + proberConfidence = mCharSetProbers[i]->GetConfidence(); + if (proberConfidence > maxProberConfidence) + { + maxProberConfidence = proberConfidence; + maxProber = i; + } + } + } + //do not report anything because we are not confident of it, that's in fact a negative answer + if (maxProberConfidence > MINIMUM_THRESHOLD) + Report(mCharSetProbers[maxProber]->GetCharSetName()); + } + break; + case eEscAscii: + break; + default: + ; + } + return; +} diff --git a/extensions/universalchardet/src/base/nsUniversalDetector.h b/extensions/universalchardet/src/base/nsUniversalDetector.h new file mode 100644 index 000000000..345e74f9f --- /dev/null +++ b/extensions/universalchardet/src/base/nsUniversalDetector.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsUniversalDetector_h__ +#define nsUniversalDetector_h__ + +class nsCharSetProber; + +#define NUM_OF_CHARSET_PROBERS 3 + +typedef enum { + ePureAscii = 0, + eEscAscii = 1, + eHighbyte = 2 +} nsInputState; + +class nsUniversalDetector { +public: + nsUniversalDetector(); + virtual ~nsUniversalDetector(); + virtual nsresult HandleData(const char* aBuf, uint32_t aLen); + virtual void DataEnd(void); + +protected: + virtual void Report(const char* aCharset) = 0; + virtual void Reset(); + nsInputState mInputState; + bool mDone; + bool mInTag; + bool mStart; + bool mGotData; + char mLastChar; + const char * mDetectedCharset; + int32_t mBestGuess; + uint32_t mLanguageFilter; + + nsCharSetProber *mCharSetProbers[NUM_OF_CHARSET_PROBERS]; + nsCharSetProber *mEscCharSetProber; +}; + +#endif + diff --git a/extensions/universalchardet/src/moz.build b/extensions/universalchardet/src/moz.build new file mode 100644 index 000000000..db5b3ff62 --- /dev/null +++ b/extensions/universalchardet/src/moz.build @@ -0,0 +1,8 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['base', 'xpcom'] + diff --git a/extensions/universalchardet/src/xpcom/moz.build b/extensions/universalchardet/src/xpcom/moz.build new file mode 100644 index 000000000..5a24a5771 --- /dev/null +++ b/extensions/universalchardet/src/xpcom/moz.build @@ -0,0 +1,16 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'nsUdetXPCOMWrapper.cpp', + 'nsUniversalCharDetModule.cpp', +] + +FINAL_LIBRARY = 'xul' + +LOCAL_INCLUDES += [ + '../base', +] diff --git a/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.cpp b/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.cpp new file mode 100644 index 000000000..750b1fd07 --- /dev/null +++ b/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.cpp @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nscore.h" + +#include "nsUniversalDetector.h" +#include "nsUdetXPCOMWrapper.h" +#include "nsCharSetProber.h" // for DumpStatus + +#include "nsUniversalCharDetDll.h" +//---- for XPCOM +#include "nsIFactory.h" +#include "nsISupports.h" +#include "nsCOMPtr.h" + +//--------------------------------------------------------------------- +nsXPCOMDetector:: nsXPCOMDetector() + : nsUniversalDetector() +{ +} +//--------------------------------------------------------------------- +nsXPCOMDetector::~nsXPCOMDetector() +{ +} +//--------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS(nsXPCOMDetector, nsICharsetDetector) + +//--------------------------------------------------------------------- +NS_IMETHODIMP nsXPCOMDetector::Init( + nsICharsetDetectionObserver* aObserver) +{ + NS_ASSERTION(mObserver == nullptr , "Init twice"); + if(nullptr == aObserver) + return NS_ERROR_ILLEGAL_VALUE; + + mObserver = aObserver; + return NS_OK; +} +//---------------------------------------------------------- +NS_IMETHODIMP nsXPCOMDetector::DoIt(const char* aBuf, + uint32_t aLen, bool* oDontFeedMe) +{ + NS_ASSERTION(mObserver != nullptr , "have not init yet"); + + if((nullptr == aBuf) || (nullptr == oDontFeedMe)) + return NS_ERROR_ILLEGAL_VALUE; + + this->Reset(); + nsresult rv = this->HandleData(aBuf, aLen); + if (NS_FAILED(rv)) + return rv; + + if (mDone) + { + if (mDetectedCharset) + Report(mDetectedCharset); + + *oDontFeedMe = true; + } + *oDontFeedMe = false; + return NS_OK; +} +//---------------------------------------------------------- +NS_IMETHODIMP nsXPCOMDetector::Done() +{ + NS_ASSERTION(mObserver != nullptr , "have not init yet"); +#ifdef DEBUG_chardet + for (int32_t i = 0; i < NUM_OF_CHARSET_PROBERS; i++) + { + // If no data was received the array might stay filled with nulls + // the way it was initialized in the constructor. + if (mCharSetProbers[i]) + mCharSetProbers[i]->DumpStatus(); + } +#endif + + this->DataEnd(); + return NS_OK; +} +//---------------------------------------------------------- +void nsXPCOMDetector::Report(const char* aCharset) +{ + NS_ASSERTION(mObserver != nullptr , "have not init yet"); +#ifdef DEBUG_chardet + printf("Universal Charset Detector report charset %s . \r\n", aCharset); +#endif + mObserver->Notify(aCharset, eBestAnswer); +} + + +//--------------------------------------------------------------------- +nsXPCOMStringDetector:: nsXPCOMStringDetector() + : nsUniversalDetector() +{ +} +//--------------------------------------------------------------------- +nsXPCOMStringDetector::~nsXPCOMStringDetector() +{ +} +//--------------------------------------------------------------------- +NS_IMPL_ISUPPORTS(nsXPCOMStringDetector, nsIStringCharsetDetector) +//--------------------------------------------------------------------- +void nsXPCOMStringDetector::Report(const char *aCharset) +{ + mResult = aCharset; +#ifdef DEBUG_chardet + printf("New Charset Prober report charset %s . \r\n", aCharset); +#endif +} +//--------------------------------------------------------------------- +NS_IMETHODIMP nsXPCOMStringDetector::DoIt(const char* aBuf, + uint32_t aLen, const char** oCharset, + nsDetectionConfident &oConf) +{ + mResult = nullptr; + this->Reset(); + nsresult rv = this->HandleData(aBuf, aLen); + if (NS_FAILED(rv)) + return rv; + this->DataEnd(); + if (mResult) + { + *oCharset=mResult; + oConf = eBestAnswer; + } + return NS_OK; +} diff --git a/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.h b/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.h new file mode 100644 index 000000000..11a0bd10a --- /dev/null +++ b/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.h @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _nsUdetXPCOMWrapper_h__ +#define _nsUdetXPCOMWrapper_h__ +#include "nsISupports.h" +#include "nsICharsetDetector.h" +#include "nsIStringCharsetDetector.h" +#include "nsICharsetDetectionObserver.h" +#include "nsCOMPtr.h" + +#include "nsIFactory.h" + +// {12BB8F1B-2389-11d3-B3BF-00805F8A6670} +#define NS_JA_PSMDETECTOR_CID \ +{ 0x12bb8f1b, 0x2389, 0x11d3, { 0xb3, 0xbf, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70 } } + +// {12BB8F1C-2389-11d3-B3BF-00805F8A6670} +#define NS_JA_STRING_PSMDETECTOR_CID \ +{ 0x12bb8f1c, 0x2389, 0x11d3, { 0xb3, 0xbf, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70 } } + +//===================================================================== +class nsXPCOMDetector : + public nsUniversalDetector, + public nsICharsetDetector +{ + NS_DECL_ISUPPORTS + public: + nsXPCOMDetector(); + NS_IMETHOD Init(nsICharsetDetectionObserver* aObserver) override; + NS_IMETHOD DoIt(const char* aBuf, uint32_t aLen, bool *oDontFeedMe) override; + NS_IMETHOD Done() override; + protected: + virtual ~nsXPCOMDetector(); + virtual void Report(const char* aCharset) override; + private: + nsCOMPtr mObserver; +}; + + +//===================================================================== +class nsXPCOMStringDetector : + public nsUniversalDetector, + public nsIStringCharsetDetector +{ + NS_DECL_ISUPPORTS + public: + nsXPCOMStringDetector(); + NS_IMETHOD DoIt(const char* aBuf, uint32_t aLen, + const char** oCharset, nsDetectionConfident &oConf) override; + protected: + virtual ~nsXPCOMStringDetector(); + virtual void Report(const char* aCharset) override; + private: + nsCOMPtr mObserver; + const char* mResult; +}; + +//===================================================================== + +class nsJAPSMDetector : public nsXPCOMDetector +{ +public: + nsJAPSMDetector() + : nsXPCOMDetector() {} +}; + +class nsJAStringPSMDetector : public nsXPCOMStringDetector +{ +public: + nsJAStringPSMDetector() + : nsXPCOMStringDetector() {} +}; + +#endif //_nsUdetXPCOMWrapper_h__ diff --git a/extensions/universalchardet/src/xpcom/nsUniversalCharDetDll.h b/extensions/universalchardet/src/xpcom/nsUniversalCharDetDll.h new file mode 100644 index 000000000..404cb4518 --- /dev/null +++ b/extensions/universalchardet/src/xpcom/nsUniversalCharDetDll.h @@ -0,0 +1,11 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsCharDetDll_h__ +#define nsCharDetDll_h__ + +#include "prtypes.h" + +#endif /* nsCharDetDll_h__ */ diff --git a/extensions/universalchardet/src/xpcom/nsUniversalCharDetModule.cpp b/extensions/universalchardet/src/xpcom/nsUniversalCharDetModule.cpp new file mode 100644 index 000000000..38e2e60bd --- /dev/null +++ b/extensions/universalchardet/src/xpcom/nsUniversalCharDetModule.cpp @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ModuleUtils.h" + +#include "nsCOMPtr.h" + +#include "nspr.h" +#include "nsString.h" +#include "nsUniversalCharDetDll.h" +#include "nsISupports.h" +#include "nsICategoryManager.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsICharsetDetector.h" +#include "nsIStringCharsetDetector.h" + +#include "nsUniversalDetector.h" +#include "nsUdetXPCOMWrapper.h" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsJAPSMDetector) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsJAStringPSMDetector) +NS_DEFINE_NAMED_CID(NS_JA_PSMDETECTOR_CID); +NS_DEFINE_NAMED_CID(NS_JA_STRING_PSMDETECTOR_CID); + +static const mozilla::Module::CIDEntry kChardetCIDs[] = { + { &kNS_JA_PSMDETECTOR_CID, false, nullptr, nsJAPSMDetectorConstructor }, + { &kNS_JA_STRING_PSMDETECTOR_CID, false, nullptr, nsJAStringPSMDetectorConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kChardetContracts[] = { + { NS_CHARSET_DETECTOR_CONTRACTID_BASE "ja_parallel_state_machine", &kNS_JA_PSMDETECTOR_CID }, + { NS_STRCDETECTOR_CONTRACTID_BASE "ja_parallel_state_machine", &kNS_JA_STRING_PSMDETECTOR_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kChardetCategories[] = { + { NS_CHARSET_DETECTOR_CATEGORY, "ja_parallel_state_machine", NS_CHARSET_DETECTOR_CONTRACTID_BASE "ja_parallel_state_machine" }, + { nullptr } +}; + +static const mozilla::Module kChardetModule = { + mozilla::Module::kVersion, + kChardetCIDs, + kChardetContracts, + kChardetCategories +}; + +NSMODULE_DEFN(nsUniversalCharDetModule) = &kChardetModule; diff --git a/extensions/universalchardet/tests/CharsetDetectionTests.js b/extensions/universalchardet/tests/CharsetDetectionTests.js new file mode 100644 index 000000000..6ccc9c3f1 --- /dev/null +++ b/extensions/universalchardet/tests/CharsetDetectionTests.js @@ -0,0 +1,94 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ +/* vim: set ts=8 et sw=4 tw=80: */ +var gExpectedCharset; +var gOldPref; +var gDetectorList; +var gTestIndex; +var gLocalDir; +var Cc = Components.classes; +var Ci = Components.interfaces; + +function CharsetDetectionTests(aTestFile, aExpectedCharset, aDetectorList) +{ + gExpectedCharset = aExpectedCharset; + gDetectorList = aDetectorList; + + InitDetectorTests(); + + var fileURI = gLocalDir + aTestFile; + $("testframe").src = fileURI; + + SimpleTest.waitForExplicitFinish(); +} + +function InitDetectorTests() +{ + var prefService = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefBranch); + var str = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader); + var ioService = Cc['@mozilla.org/network/io-service;1'] + .getService(Ci.nsIIOService); + loader.loadSubScript("chrome://mochikit/content/chrome-harness.js"); + + try { + gOldPref = prefService + .getComplexValue("intl.charset.detector", + Ci.nsIPrefLocalizedString).data; + } catch (e) { + gOldPref = ""; + } + SetDetectorPref(gDetectorList[0]); + gTestIndex = 0; + $("testframe").onload = DoDetectionTest; + + if (gExpectedCharset == "default") { + // No point trying to be generic here, because we have plenty of other + // unit tests that fail if run using a non-windows-1252 locale. + gExpectedCharset = "windows-1252"; + } + + // Get the local directory. This needs to be a file: URI because chrome: + // URIs are always UTF-8 (bug 617339) and we are testing decoding from other + // charsets. + var jar = getJar(getRootDirectory(window.location.href)); + var dir = jar ? + extractJarToTmp(jar) : + getChromeDir(getResolvedURI(window.location.href)); + gLocalDir = ioService.newFileURI(dir).spec; +} + +function SetDetectorPref(aPrefValue) +{ + var prefService = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefBranch); + var str = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + str.data = aPrefValue; + prefService.setComplexValue("intl.charset.detector", + Ci.nsISupportsString, str); + gCurrentDetector = aPrefValue; +} + +function DoDetectionTest() { + var iframeDoc = $("testframe").contentDocument; + var charset = iframeDoc.characterSet; + + is(charset, gExpectedCharset, + "decoded as " + gExpectedCharset + " by " + gDetectorList[gTestIndex]); + + if (++gTestIndex < gDetectorList.length) { + SetDetectorPref(gDetectorList[gTestIndex]); + iframeDoc.location.reload(); + } else { + CleanUpDetectionTests(); + } +} + +function CleanUpDetectionTests() { + SetDetectorPref(gOldPref); + SimpleTest.finish(); +} + diff --git a/extensions/universalchardet/tests/bug306272_text.html b/extensions/universalchardet/tests/bug306272_text.html new file mode 100644 index 000000000..4a0c61283 --- /dev/null +++ b/extensions/universalchardet/tests/bug306272_text.html @@ -0,0 +1,9 @@ + + + + 306272 + + + +Antti Näyhä <Antti.Nayha@somewhere.fi> + \ No newline at end of file diff --git a/extensions/universalchardet/tests/bug421271_text.html b/extensions/universalchardet/tests/bug421271_text.html new file mode 100644 index 000000000..dfffc3363 --- /dev/null +++ b/extensions/universalchardet/tests/bug421271_text.html @@ -0,0 +1,5 @@ + + +BBC - 606 - A Forum Conversation + +

posted 5 Weeks Ago

if rangers draw and marseille and benfica win i stand to lift 825. not bad for a 2 bet.
50p on 3 homes
Man Utd/Marseille/Benfica
50p on 3 Draws
Rangers/Halifax/Bristol City
50p on 3 Aways
Doncaster/Stranraer/Rushden & Diamonds
and 50p on all nine results.
GET IN THERE.

\ No newline at end of file diff --git a/extensions/universalchardet/tests/bug426271_text-euc-jp.html b/extensions/universalchardet/tests/bug426271_text-euc-jp.html new file mode 100644 index 000000000..467d69c73 --- /dev/null +++ b/extensions/universalchardet/tests/bug426271_text-euc-jp.html @@ -0,0 +1,11 @@ + + + +ܸ쥨󥳡ɥƥ + + +EUC-JPǤΡ˻ҶΤʤϷؤǤ̤򤷤Ƥȡ礭ή褿Τǡ줵ȿ٤褦Ȼäͤ椫ˤλҤޤ줿ΤǡϺפ̾դ˰Ƥ + +ĹϺϡε͡줷Ƥ뤳ȤΤꡢ༣դ롣ξƤĻҤ̤㤤ƻˤʬͿƥ̡롢˽롣ǵ襤˾ᡢåäƤäꡢ줵󡦤̤θ֤ꡢ餷Ȥŵ: ե꡼ɴʻŵإڥǥWikipediaˡ + + diff --git a/extensions/universalchardet/tests/bug426271_text-utf-8.html b/extensions/universalchardet/tests/bug426271_text-utf-8.html new file mode 100644 index 000000000..7e38c27c3 --- /dev/null +++ b/extensions/universalchardet/tests/bug426271_text-utf-8.html @@ -0,0 +1,11 @@ + + + +日本語エンコードテスト + + +これはUTF-8です昔々、ある所に子供のいない老夫婦が住んでいた。ある日、お婆さんが川で洗濯をしていると、大きな桃が流れて来たので、お爺さんと食べようと持ち帰った。二人で桃を割ると中から男の子が生まれたので、「桃太郎」と名付けて大事に育てた。 + +成長した桃太郎は、鬼ヶ島の鬼が人々を苦しめていることを知り、鬼退治を決意する。両親から黍団子を餞別に貰い、道中にそれを分け与えてイヌ、サル、キジを家来に従える。鬼ヶ島で鬼と戦い、見事に勝利を収め、鬼が方々から奪っていった財宝を持ち帰り、お爺さん・お婆さんの元に返り、幸せに暮らしたという。出典: フリー百科事典『ウィキペディア(Wikipedia)』 + + diff --git a/extensions/universalchardet/tests/bug431054_text.html b/extensions/universalchardet/tests/bug431054_text.html new file mode 100644 index 000000000..aa88a4e1d --- /dev/null +++ b/extensions/universalchardet/tests/bug431054_text.html @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/universalchardet/tests/bug547487_text.html b/extensions/universalchardet/tests/bug547487_text.html new file mode 100644 index 000000000..2fe6575e7 --- /dev/null +++ b/extensions/universalchardet/tests/bug547487_text.html @@ -0,0 +1 @@ +The quick brown fox jumps over the lazy dog. diff --git a/extensions/universalchardet/tests/bug620106_text.html b/extensions/universalchardet/tests/bug620106_text.html new file mode 100644 index 000000000..b7ca0aca3 --- /dev/null +++ b/extensions/universalchardet/tests/bug620106_text.html @@ -0,0 +1,1045 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ƥȤΥ󥳡ǥ󥰤򸡽С⤦٥ƥȡޤ󥳡ɤθФƥȤޤ줬ФƤޤ + diff --git a/extensions/universalchardet/tests/bug631751be_text.html b/extensions/universalchardet/tests/bug631751be_text.html new file mode 100644 index 000000000..104d50399 Binary files /dev/null and b/extensions/universalchardet/tests/bug631751be_text.html differ diff --git a/extensions/universalchardet/tests/bug631751le_text.html b/extensions/universalchardet/tests/bug631751le_text.html new file mode 100644 index 000000000..a1e5f6bfb Binary files /dev/null and b/extensions/universalchardet/tests/bug631751le_text.html differ diff --git a/extensions/universalchardet/tests/bug638318_text.html b/extensions/universalchardet/tests/bug638318_text.html new file mode 100644 index 000000000..3f2ff4421 Binary files /dev/null and b/extensions/universalchardet/tests/bug638318_text.html differ diff --git a/extensions/universalchardet/tests/bug811363-1.text b/extensions/universalchardet/tests/bug811363-1.text new file mode 100644 index 000000000..a2952d62f --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-1.text @@ -0,0 +1 @@ +Two-byte UTF-8 including the first and last characters in the range: €Шерлок߿ diff --git a/extensions/universalchardet/tests/bug811363-2.text b/extensions/universalchardet/tests/bug811363-2.text new file mode 100644 index 000000000..b3b672635 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-2.text @@ -0,0 +1,3 @@ +Three byte UTF-8, first byte 0xE0, including first and last characters +in the range: ࠀशर्लक࿿ + diff --git a/extensions/universalchardet/tests/bug811363-3.text b/extensions/universalchardet/tests/bug811363-3.text new file mode 100644 index 000000000..29b6d4c58 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-3.text @@ -0,0 +1,3 @@ +Three byte UTF-8, first byte 0xE1-EC, including first and last characters +in the range: ကシャーロック쿿 + diff --git a/extensions/universalchardet/tests/bug811363-4.text b/extensions/universalchardet/tests/bug811363-4.text new file mode 100644 index 000000000..f337d2e43 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-4.text @@ -0,0 +1,3 @@ +Three byte UTF-8, first byte 0xED, including first and last characters +in the range: 퀀홈하홈탐퟿ + diff --git a/extensions/universalchardet/tests/bug811363-5.text b/extensions/universalchardet/tests/bug811363-5.text new file mode 100644 index 000000000..2827c8030 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-5.text @@ -0,0 +1,3 @@ +Three byte UTF-8, first byte 0xEE-EF, including first and last characters +in the range: ﴍﻟﻮﻙ￿ + diff --git a/extensions/universalchardet/tests/bug811363-6.text b/extensions/universalchardet/tests/bug811363-6.text new file mode 100644 index 000000000..c23e0077c --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-6.text @@ -0,0 +1,3 @@ +Four byte UTF-8, first byte 0xF0, including first and last characters +in the range: 𐀀𐌲𐌿𐍄𐌹𐍃𐌺 𿿿 + diff --git a/extensions/universalchardet/tests/bug811363-7.text b/extensions/universalchardet/tests/bug811363-7.text new file mode 100644 index 000000000..8a2c209f1 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-7.text @@ -0,0 +1,3 @@ +Four byte UTF-8, first byte 0xF1-F3, including first and last characters +in the range: 񀀀񠀀 񠀁 񠀂󿿿 + diff --git a/extensions/universalchardet/tests/bug811363-8.text b/extensions/universalchardet/tests/bug811363-8.text new file mode 100644 index 000000000..b82f3da40 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-8.text @@ -0,0 +1,3 @@ +Four byte UTF-8, first byte 0xF4, including first and last characters +in the range:􀀀􈀀 􈀁 􈀂􏿿 + diff --git a/extensions/universalchardet/tests/bug811363-9.text b/extensions/universalchardet/tests/bug811363-9.text new file mode 100644 index 000000000..50b232eaf --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-9.text @@ -0,0 +1,2 @@ +Four byte UTF-8, first byte 0xF0, including BMP only:𐤔𐤓𐤋𐤅𐤒 + diff --git a/extensions/universalchardet/tests/bug811363-invalid-1.text b/extensions/universalchardet/tests/bug811363-invalid-1.text new file mode 100644 index 000000000..8718c36d7 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-invalid-1.text @@ -0,0 +1,4 @@ +Orphaned continuation bytes: + + + diff --git a/extensions/universalchardet/tests/bug811363-invalid-2.text b/extensions/universalchardet/tests/bug811363-invalid-2.text new file mode 100644 index 000000000..d38980fad --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-invalid-2.text @@ -0,0 +1,3 @@ +First bytes of 2-byte sequences (0xc0-0xdf), each followed by a space character: +First bytes of 3-byte sequences (0xe0-0xef), each followed by a space character: +First bytes of 4-byte sequences (0xf0-0xf4), each followed by a space character: diff --git a/extensions/universalchardet/tests/bug811363-invalid-3.text b/extensions/universalchardet/tests/bug811363-invalid-3.text new file mode 100644 index 000000000..1c438d70a --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-invalid-3.text @@ -0,0 +1,2 @@ +3-byte sequence with last byte missing (U+0000): +4-byte sequence with last b0te missing (U+0000): diff --git a/extensions/universalchardet/tests/bug811363-invalid-4.text b/extensions/universalchardet/tests/bug811363-invalid-4.text new file mode 100644 index 000000000..8a943dca3 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-invalid-4.text @@ -0,0 +1 @@ +Overlong encodings: diff --git a/extensions/universalchardet/tests/bug811363-invalid-5.text b/extensions/universalchardet/tests/bug811363-invalid-5.text new file mode 100644 index 000000000..fa76449c2 --- /dev/null +++ b/extensions/universalchardet/tests/bug811363-invalid-5.text @@ -0,0 +1,3 @@ +Isolated surrogates: +Surrogate pairs: + diff --git a/extensions/universalchardet/tests/chrome.ini b/extensions/universalchardet/tests/chrome.ini new file mode 100644 index 000000000..995ff043f --- /dev/null +++ b/extensions/universalchardet/tests/chrome.ini @@ -0,0 +1,52 @@ +[DEFAULT] +support-files = + CharsetDetectionTests.js + bug306272_text.html + bug421271_text.html + bug426271_text-euc-jp.html + bug426271_text-utf-8.html + bug431054_text.html + bug547487_text.html + bug631751be_text.html + bug631751le_text.html + bug638318_text.html + bug811363-1.text + bug811363-2.text + bug811363-3.text + bug811363-4.text + bug811363-5.text + bug811363-6.text + bug811363-7.text + bug811363-8.text + bug811363-9.text + bug811363-invalid-1.text + bug811363-invalid-2.text + bug811363-invalid-3.text + bug811363-invalid-4.text + bug811363-invalid-5.text + +[test_bug306272.html] +[test_bug421271.html] +[test_bug426271-euc-jp.html] +[test_bug426271-utf-8.html] +[test_bug431054-japanese.html] +[test_bug431054.html] +[test_bug547487.html] +[test_bug631751be.html] +[test_bug631751le.html] +[test_bug638318.html] +[test_bug811363-1-1.html] +[test_bug811363-1-2.html] +[test_bug811363-1-3.html] +[test_bug811363-1-4.html] +[test_bug811363-1-5.html] +[test_bug811363-2-1.html] +[test_bug811363-2-2.html] +[test_bug811363-2-3.html] +[test_bug811363-2-4.html] +[test_bug811363-2-5.html] +[test_bug811363-2-6.html] +[test_bug811363-2-7.html] +[test_bug811363-2-8.html] +[test_bug811363-2-9.html] + diff --git a/extensions/universalchardet/tests/moz.build b/extensions/universalchardet/tests/moz.build new file mode 100644 index 000000000..47f2ae432 --- /dev/null +++ b/extensions/universalchardet/tests/moz.build @@ -0,0 +1,8 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] + diff --git a/extensions/universalchardet/tests/test_bug306272.html b/extensions/universalchardet/tests/test_bug306272.html new file mode 100644 index 000000000..d797b45af --- /dev/null +++ b/extensions/universalchardet/tests/test_bug306272.html @@ -0,0 +1,31 @@ + + + + + Test for Bug 306272 + + + + + +Mozilla Bug 306272 +

+ + +
+
+
+ + + diff --git a/extensions/universalchardet/tests/test_bug421271.html b/extensions/universalchardet/tests/test_bug421271.html new file mode 100644 index 000000000..2e6cd29e7 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug421271.html @@ -0,0 +1,37 @@ + + + + + Test for Bug 421271 + + + + + +Mozilla Bug 421271 +

+ + +
+
+
+ + + diff --git a/extensions/universalchardet/tests/test_bug426271-euc-jp.html b/extensions/universalchardet/tests/test_bug426271-euc-jp.html new file mode 100644 index 000000000..4eeca8282 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug426271-euc-jp.html @@ -0,0 +1,31 @@ + + + + + Test for Bug 426271 + + + + + +Mozilla Bug 426271 +

+ + +
+
+
+ + + diff --git a/extensions/universalchardet/tests/test_bug426271-utf-8.html b/extensions/universalchardet/tests/test_bug426271-utf-8.html new file mode 100644 index 000000000..a393e624e --- /dev/null +++ b/extensions/universalchardet/tests/test_bug426271-utf-8.html @@ -0,0 +1,32 @@ + + + + + Test for Bug 426271 + + + + + +Mozilla Bug 426271 +

+ + +
+
+
+ + + diff --git a/extensions/universalchardet/tests/test_bug431054-japanese.html b/extensions/universalchardet/tests/test_bug431054-japanese.html new file mode 100644 index 000000000..64b806663 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug431054-japanese.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 431054 + + + + + +Mozilla Bug 431054 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug431054.html b/extensions/universalchardet/tests/test_bug431054.html new file mode 100644 index 000000000..a33fa2569 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug431054.html @@ -0,0 +1,34 @@ + + + + + Test for Bug 431054 + + + + + +Mozilla Bug 431054 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug547487.html b/extensions/universalchardet/tests/test_bug547487.html new file mode 100644 index 000000000..37c4708d9 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug547487.html @@ -0,0 +1,36 @@ + + + + + Test for Bug 547487 + + + + + +Mozilla Bug 547487 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug631751be.html b/extensions/universalchardet/tests/test_bug631751be.html new file mode 100644 index 000000000..de965cbf2 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug631751be.html @@ -0,0 +1,31 @@ + + + + + Test for Bug 631751 + + + + + +Mozilla Bug 631751 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug631751le.html b/extensions/universalchardet/tests/test_bug631751le.html new file mode 100644 index 000000000..ef19537b8 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug631751le.html @@ -0,0 +1,31 @@ + + + + + Test for Bug 631751 + + + + + +Mozilla Bug 631751 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug638318.html b/extensions/universalchardet/tests/test_bug638318.html new file mode 100644 index 000000000..62e78052b --- /dev/null +++ b/extensions/universalchardet/tests/test_bug638318.html @@ -0,0 +1,31 @@ + + + + + Test for Bug 638318 + + + + + +Mozilla Bug 638318 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-1-1.html b/extensions/universalchardet/tests/test_bug811363-1-1.html new file mode 100644 index 000000000..6583d39b4 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-1-1.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-1-2.html b/extensions/universalchardet/tests/test_bug811363-1-2.html new file mode 100644 index 000000000..86d00828d --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-1-2.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-1-3.html b/extensions/universalchardet/tests/test_bug811363-1-3.html new file mode 100644 index 000000000..782fba274 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-1-3.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-1-4.html b/extensions/universalchardet/tests/test_bug811363-1-4.html new file mode 100644 index 000000000..590f221b1 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-1-4.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-1-5.html b/extensions/universalchardet/tests/test_bug811363-1-5.html new file mode 100644 index 000000000..11233dc24 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-1-5.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-1.html b/extensions/universalchardet/tests/test_bug811363-2-1.html new file mode 100644 index 000000000..e380f7269 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-1.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-2.html b/extensions/universalchardet/tests/test_bug811363-2-2.html new file mode 100644 index 000000000..0a4e41f3c --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-2.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-3.html b/extensions/universalchardet/tests/test_bug811363-2-3.html new file mode 100644 index 000000000..713a191f1 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-3.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-4.html b/extensions/universalchardet/tests/test_bug811363-2-4.html new file mode 100644 index 000000000..725e1b7f4 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-4.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-5.html b/extensions/universalchardet/tests/test_bug811363-2-5.html new file mode 100644 index 000000000..8bdd8b8ce --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-5.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-6.html b/extensions/universalchardet/tests/test_bug811363-2-6.html new file mode 100644 index 000000000..6208f7389 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-6.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-7.html b/extensions/universalchardet/tests/test_bug811363-2-7.html new file mode 100644 index 000000000..694ff73b3 --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-7.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-8.html b/extensions/universalchardet/tests/test_bug811363-2-8.html new file mode 100644 index 000000000..49d094d7b --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-8.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + diff --git a/extensions/universalchardet/tests/test_bug811363-2-9.html b/extensions/universalchardet/tests/test_bug811363-2-9.html new file mode 100644 index 000000000..5f2312cdf --- /dev/null +++ b/extensions/universalchardet/tests/test_bug811363-2-9.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 811363 + + + + + +Mozilla Bug 811363 +

+ + +
+
+
+ + -- cgit v1.2.3